using System; using System.Text.RegularExpressions; using Avalonia; using Avalonia.Controls; using Avalonia.Layout; using Avalonia.LogicalTree; using Avalonia.Markup.Xaml; using Avalonia.Media; using Avalonia.Media.Imaging; using Avalonia.Visuals.Media.Imaging; using Material.Icons; using Material.Icons.Avalonia; namespace Artemis.UI.Shared; /// /// Represents a control that can display an arbitrary kind of icon. /// public class ArtemisIcon : UserControl { private static readonly Regex _imageRegex = new(@"[\/.](gif|jpg|jpeg|tiff|png)$", RegexOptions.Compiled); /// /// Creates a new instance of the class. /// public ArtemisIcon() { InitializeComponent(); DetachedFromLogicalTree += OnDetachedFromLogicalTree; LayoutUpdated += OnLayoutUpdated; } private static void IconChanging(IAvaloniaObject sender, bool before) { if (before) ((ArtemisIcon) sender).Update(); } private void Update() { try { // First look for an enum value instead of a string if (Icon is MaterialIconKind materialIcon) { Content = new MaterialIcon {Kind = materialIcon, Width = Bounds.Width, Height = Bounds.Height}; } // If it's a string there are several options else if (Icon is string iconString) { // An enum defined as a string if (Enum.TryParse(iconString, true, out MaterialIconKind parsedIcon)) { Content = new MaterialIcon {Kind = parsedIcon, Width = Bounds.Width, Height = Bounds.Height}; } // An URI pointing to an image else if (_imageRegex.IsMatch(iconString)) { if (!Fill) Content = new Image { Source = new Bitmap(iconString), VerticalAlignment = VerticalAlignment.Stretch, HorizontalAlignment = HorizontalAlignment.Stretch }; else Content = new Border { Background = TextBlock.GetForeground(this), VerticalAlignment = VerticalAlignment.Stretch, HorizontalAlignment = HorizontalAlignment.Stretch, OpacityMask = new ImageBrush(new Bitmap(iconString)) {BitmapInterpolationMode = BitmapInterpolationMode.MediumQuality} }; } else { Content = new MaterialIcon {Kind = MaterialIconKind.QuestionMark, Width = Bounds.Width, Height = Bounds.Height}; } } } catch { Content = new MaterialIcon {Kind = MaterialIconKind.QuestionMark, Width = Bounds.Width, Height = Bounds.Height}; } } private void OnLayoutUpdated(object? sender, EventArgs e) { if (Content is Control contentControl) { contentControl.Width = Bounds.Width; contentControl.Height = Bounds.Height; } } private void OnDetachedFromLogicalTree(object? sender, LogicalTreeAttachmentEventArgs e) { if (Content is Image image && image.Source is IDisposable disposable) disposable.Dispose(); } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); } #region Properties /// /// Gets or sets the currently displayed icon as either a or an /// pointing to an SVG /// public static readonly StyledProperty IconProperty = AvaloniaProperty.Register(nameof(Icon), notifying: IconChanging); /// /// Gets or sets the currently displayed icon as either a or an /// pointing to an SVG /// public object? Icon { get => GetValue(IconProperty); set => SetValue(IconProperty, value); } /// /// Gets or sets a boolean indicating whether or not the icon should be filled in with the primary text color of the /// theme /// public static readonly StyledProperty FillProperty = AvaloniaProperty.Register(nameof(Icon), false, notifying: IconChanging); /// /// Gets or sets a boolean indicating whether or not the icon should be filled in with the primary text color of the /// theme /// public bool Fill { get => GetValue(FillProperty); set => SetValue(FillProperty, value); } #endregion }