Tag.xaml.cs
1 // Copyright (c) Microsoft Corporation 2 // The Microsoft Corporation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using Microsoft.CmdPal.Core.ViewModels; 6 using Microsoft.CmdPal.UI.Helpers; 7 using Microsoft.CommandPalette.Extensions; 8 using Microsoft.UI.Xaml; 9 using Microsoft.UI.Xaml.Controls; 10 using Microsoft.UI.Xaml.Media; 11 12 namespace Microsoft.CmdPal.UI.Controls; 13 14 [TemplatePart(Name = TagIconBox, Type = typeof(IconBox))] 15 16 public partial class Tag : Control 17 { 18 internal const string TagIconBox = "PART_Icon"; 19 20 public OptionalColor? BackgroundColor 21 { 22 get => (OptionalColor?)GetValue(BackgroundColorProperty); 23 set => SetValue(BackgroundColorProperty, value); 24 } 25 26 public OptionalColor? ForegroundColor 27 { 28 get => (OptionalColor?)GetValue(ForegroundColorProperty); 29 set => SetValue(ForegroundColorProperty, value); 30 } 31 32 public bool HasIcon => Icon?.HasIcon(this.ActualTheme == ElementTheme.Light) ?? false; 33 34 public IconInfoViewModel? Icon 35 { 36 get => (IconInfoViewModel?)GetValue(IconProperty); 37 set => SetValue(IconProperty, value); 38 } 39 40 public string? Text 41 { 42 get => (string?)GetValue(TextProperty); 43 set => SetValue(TextProperty, value); 44 } 45 46 private static Brush? OriginalBg => Application.Current.Resources["TagBackground"] as Brush; 47 48 private static Brush? OriginalFg => Application.Current.Resources["TagForeground"] as Brush; 49 50 private static Brush? OriginalBorder => Application.Current.Resources["TagBorderBrush"] as Brush; 51 52 public static readonly DependencyProperty ForegroundColorProperty = 53 DependencyProperty.Register(nameof(ForegroundColor), typeof(OptionalColor), typeof(Tag), new PropertyMetadata(null, OnForegroundColorPropertyChanged)); 54 55 public static readonly DependencyProperty BackgroundColorProperty = 56 DependencyProperty.Register(nameof(BackgroundColor), typeof(OptionalColor), typeof(Tag), new PropertyMetadata(null, OnBackgroundColorPropertyChanged)); 57 58 public static readonly DependencyProperty IconProperty = 59 DependencyProperty.Register(nameof(Icon), typeof(IconInfoViewModel), typeof(Tag), new PropertyMetadata(null)); 60 61 public static readonly DependencyProperty TextProperty = 62 DependencyProperty.Register(nameof(Text), typeof(string), typeof(Tag), new PropertyMetadata(null)); 63 64 public Tag() 65 { 66 this.DefaultStyleKey = typeof(Tag); 67 } 68 69 protected override void OnApplyTemplate() 70 { 71 base.OnApplyTemplate(); 72 73 if (GetTemplateChild(TagIconBox) is IconBox iconBox) 74 { 75 iconBox.SourceRequested += IconCacheProvider.SourceRequested20; 76 iconBox.Visibility = HasIcon ? Visibility.Visible : Visibility.Collapsed; 77 } 78 } 79 80 private static void OnForegroundColorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 81 { 82 if (d is not Tag tag) 83 { 84 return; 85 } 86 87 if (tag.ForegroundColor is not null && 88 OptionalColorBrushCacheProvider.Convert(tag.ForegroundColor.Value) is SolidColorBrush brush) 89 { 90 tag.Foreground = brush; 91 92 // If we have a BG color, then don't apply a border. 93 if (tag.BackgroundColor is OptionalColor bg && bg.HasValue) 94 { 95 tag.BorderBrush = OriginalBorder; 96 } 97 else 98 { 99 // Otherwise (no background), use the FG as the border 100 tag.BorderBrush = brush; 101 } 102 } 103 else 104 { 105 tag.Foreground = OriginalFg; 106 tag.BorderBrush = OriginalBorder; 107 } 108 } 109 110 private static void OnBackgroundColorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 111 { 112 if (d is not Tag tag) 113 { 114 return; 115 } 116 117 if (tag.BackgroundColor is not null && 118 OptionalColorBrushCacheProvider.Convert(tag.BackgroundColor.Value) is SolidColorBrush brush) 119 { 120 tag.Background = brush; 121 122 // Since we have a BG here, we never want a border. 123 tag.BorderBrush = OriginalBorder; 124 125 // If we have a FG color, then don't apply a border. 126 if (tag.ForegroundColor is OptionalColor fg && fg.HasValue) 127 { 128 tag.BorderBrush = OriginalBorder; 129 } 130 else 131 { 132 // Otherwise (no foreground), use the FG as the border 133 tag.BorderBrush = brush; 134 } 135 } 136 else 137 { 138 // No BG color here. 139 tag.Background = OriginalBg; 140 141 // If we have a FG color, then don't apply a border. 142 if (tag.ForegroundColor is OptionalColor fg && fg.HasValue) 143 { 144 tag.BorderBrush = tag.Foreground; 145 } 146 else 147 { 148 // Otherwise (no foreground), use the FG as the border 149 tag.BorderBrush = OriginalBorder; 150 } 151 } 152 } 153 }