using WPFluent.Converters;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
// ReSharper disable once CheckNamespace
namespace WPFluent.Controls;
///
/// Represents the base class for an icon UI element.
///
[TypeConverter(typeof(IconElementConverter))]
public abstract class IconElement : FrameworkElement
{
///
/// Identifies the dependency property.
///
public static readonly DependencyProperty ForegroundProperty = TextElement.ForegroundProperty
.AddOwner(
typeof(IconElement),
new FrameworkPropertyMetadata(
SystemColors.ControlTextBrush,
FrameworkPropertyMetadataOptions.Inherits,
static(d, args) => ((IconElement)d).OnForegroundChanged(args)));
private Grid? _layoutRoot;
static IconElement()
{
FocusableProperty.OverrideMetadata(typeof(IconElement), new FrameworkPropertyMetadata(false));
KeyboardNavigation.IsTabStopProperty.OverrideMetadata(typeof(IconElement), new FrameworkPropertyMetadata(false));
}
private void EnsureLayoutRoot()
{
if(_layoutRoot != null)
{
return;
}
_layoutRoot = new Grid { Background = Brushes.Transparent, SnapsToDevicePixels = true };
_layoutRoot.Children.Add(InitializeChildren());
AddVisualChild(_layoutRoot);
}
protected override Size ArrangeOverride(Size finalSize)
{
EnsureLayoutRoot();
_layoutRoot!.Arrange(new Rect(default, finalSize));
return finalSize;
}
protected override Visual GetVisualChild(int index)
{
if(index != 0)
{
throw new ArgumentOutOfRangeException(nameof(index), "IconElement should have only 1 child");
}
EnsureLayoutRoot();
return _layoutRoot!;
}
protected abstract UIElement InitializeChildren();
protected override Size MeasureOverride(Size availableSize)
{
EnsureLayoutRoot();
_layoutRoot!.Measure(availableSize);
return _layoutRoot.DesiredSize;
}
protected virtual void OnForegroundChanged(DependencyPropertyChangedEventArgs args)
{
}
protected override int VisualChildrenCount => 1;
///
/// Coerces the value of an Icon dependency property, allowing the use of either IconElement or IconSourceElement.
///
/// The dependency object (unused).
/// The value to be coerced.
/// An IconElement, either directly or derived from an IconSourceElement.
public static object? Coerce(DependencyObject _, object? baseValue)
{
return baseValue switch
{
IconSourceElement iconSourceElement => iconSourceElement.CreateIconElement(),
IconElement or null => baseValue,
_ => throw new ArgumentException(
message: $"Expected either '{typeof(IconSourceElement)}' or '{typeof(IconElement)}' but got '{baseValue.GetType()}'.",
paramName: nameof(baseValue)),
};
}
///
[Bindable(true)]
[Category("Appearance")]
public Brush Foreground { get => (Brush)GetValue(ForegroundProperty); set => SetValue(ForegroundProperty, value); }
}