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  }