diff --git a/.editorconfig b/.editorconfig
index 490397a..71d45df 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -2,13 +2,19 @@
root = true
[*]
-end_of_line = CRLF
+end_of_line = crlf
+indent_style = space
+max_line_length = 190
; 4-column tab indentation
-[*.{cs,csproj,xaml,xml,props,targets}]
-indent_style = space
+[*.{cs,csproj,xaml,xml,props,targets,nuspec}]
indent_size = 4
-[*.{md,yml}]
-indent_style = space
+[*.{yml,json}]
+indent_size = 2
+max_line_length = off
+
+[*.md]
indent_size = 2
+max_line_length = off
+trim_trailing_whitespace = false
diff --git a/src/AvaloniaApp/AvaloniaApp.csproj b/src/AvaloniaApp/AvaloniaApp.csproj
index 06e00f7..ba2ee52 100644
--- a/src/AvaloniaApp/AvaloniaApp.csproj
+++ b/src/AvaloniaApp/AvaloniaApp.csproj
@@ -1,24 +1,25 @@
-
- WinExe
- net8.0;net6.0
- enable
- true
- app.manifest
- true
-
-
-
-
-
-
-
-
-
+
+ WinExe
+ net8.0;net6.0
+ enable
+ true
+ app.manifest
+ true
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/AvaloniaApp/MainWindow.axaml b/src/AvaloniaApp/MainWindow.axaml
index c4653f7..b3e3485 100644
--- a/src/AvaloniaApp/MainWindow.axaml
+++ b/src/AvaloniaApp/MainWindow.axaml
@@ -2,8 +2,9 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:iconPacks="clr-namespace:MahApps.Metro.IconPacks;assembly=AvaloniaIconPacks"
xmlns:avaloniaApp="clr-namespace:AvaloniaApp"
+ xmlns:iconPacks="urn:iconpacks-avalonia"
+ xmlns:iconPacks1="clr-namespace:MahApps.Metro.IconPacks;assembly=AvaloniaIconPacks"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="AvaloniaApp.MainWindow"
Title="AvaloniaApp"
@@ -15,10 +16,10 @@
-
+
-
@@ -30,13 +31,13 @@
-
-
-
-
- net8.0;net6.0;netstandard2.0
- $(DefineConstants);AVALONIA
- latest
- disable
-
-
-
-
-
-
-
-
+
+
+ net8.0;net6.0;netstandard2.0
+ $(DefineConstants);AVALONIA
+ latest
+ disable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/AvaloniaIconPacks/BoxIcons.xaml b/src/AvaloniaIconPacks/BoxIcons.xaml
index 4258d6e..22f6ae8 100644
--- a/src/AvaloniaIconPacks/BoxIcons.xaml
+++ b/src/AvaloniaIconPacks/BoxIcons.xaml
@@ -1,11 +1,10 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/AvaloniaIconPacks/Core/PackIconBase.cs b/src/AvaloniaIconPacks/Core/PackIconBase.cs
deleted file mode 100644
index f44c400..0000000
--- a/src/AvaloniaIconPacks/Core/PackIconBase.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-#if (NETFX_CORE || WINDOWS_UWP)
-using Windows.UI.Xaml.Controls;
-#elif AVALONIA
-using Avalonia.Controls;
-
-#else
-using System.Windows.Controls;
-#endif
-
-namespace MahApps.Metro.IconPacks
-{
-#if AVALONIA
- public abstract class PackIconBase : PathIcon
-#else
- public abstract class PackIconBase : Control
-#endif
- {
- protected internal abstract void SetKind(TKind iconKind);
- protected abstract void UpdateData();
- }
-}
\ No newline at end of file
diff --git a/src/AvaloniaIconPacks/Core/PackIconControlBase.cs b/src/AvaloniaIconPacks/Core/PackIconControlBase.cs
deleted file mode 100644
index dfa9c89..0000000
--- a/src/AvaloniaIconPacks/Core/PackIconControlBase.cs
+++ /dev/null
@@ -1,639 +0,0 @@
-using System;
-
-#if NETFX_CORE || WINDOWS_UWP
-using System.Linq;
-using Windows.UI.Xaml;
-using Windows.UI.Xaml.Media;
-using Windows.UI.Xaml.Media.Animation;
-#elif AVALONIA
-using System.Reactive;
-using System.Reactive.Linq;
-using System.Threading.Tasks;
-using Avalonia;
-using Avalonia.Animation;
-using Avalonia.Animation.Easings;
-using Avalonia.Controls;
-using Avalonia.Controls.Primitives;
-using Avalonia.Data;
-using Avalonia.Media;
-using Avalonia.Styling;
-
-#else
-using System.ComponentModel;
-using System.Linq;
-using System.Windows;
-using System.Windows.Media;
-using System.Windows.Media.Animation;
-#endif
-
-namespace MahApps.Metro.IconPacks
-{
- ///
- /// Class PackIconControlBase which is the base class for any PackIcon control.
- ///
- public abstract class PackIconControlBase : PackIconBase
- {
-#if NETFX_CORE || WINDOWS_UWP
- private long _opacityRegisterToken;
- private long _visibilityRegisterToken;
-
- public PackIconControlBase()
- {
- this.Loaded += (sender, args) =>
- {
- this._opacityRegisterToken = this.RegisterPropertyChangedCallback(OpacityProperty, this.CoerceSpinProperty);
- this._visibilityRegisterToken = this.RegisterPropertyChangedCallback(VisibilityProperty, this.CoerceSpinProperty);
- };
- this.Unloaded += (sender, args) =>
- {
- this.UnregisterPropertyChangedCallback(OpacityProperty, this._opacityRegisterToken);
- this.UnregisterPropertyChangedCallback(VisibilityProperty, this._visibilityRegisterToken);
- };
- }
-
- private void CoerceSpinProperty(DependencyObject sender, DependencyProperty dp)
- {
- var packIcon = sender as PackIconControlBase;
- if (packIcon != null && (dp == OpacityProperty || dp == VisibilityProperty))
- {
- var spin = this.Spin && packIcon.Visibility == Visibility.Visible && packIcon.SpinDuration > 0 && packIcon.Opacity > 0;
- packIcon.ToggleSpinAnimation(spin);
- }
- }
-#elif AVALONIA
- public PackIconControlBase()
- {
- AffectsRender(SpinProperty);
- AffectsRender(SpinDurationProperty);
- AffectsRender(OpacityProperty);
- AffectsRender(SpinEasingFunctionProperty);
- AffectsRender(FlipProperty);
- AffectsRender(RotationAngleProperty);
-
- Observable.CombineLatest(
- this.GetObservable(SpinProperty).Select(_ => Unit.Default),
- this.GetObservable(IsVisibleProperty).Select(_ => Unit.Default),
- this.GetObservable(SpinDurationProperty).Select(_ => Unit.Default),
- this.GetObservable(OpacityProperty).Select(_ => Unit.Default),
- this.GetObservable(SpinEasingFunctionProperty).Select(_ => Unit.Default))
- .Select(_ => this.CanSpin())
- .Subscribe(spin =>
- {
- this.StopSpinAnimation();
- if (spin)
- {
- this.BeginSpinAnimation();
- }
- });
- }
-
- private bool CanSpin()
- {
- return this.Spin
- && this.IsVisible
- && this.SpinDuration > 0
- && this.Opacity > 0
- && this.SpinEasingFunction != null;
- }
-#else
- static PackIconControlBase()
- {
- OpacityProperty.OverrideMetadata(typeof(PackIconControlBase), new UIPropertyMetadata(1d, (d, e) => { d.CoerceValue(SpinProperty); }));
- VisibilityProperty.OverrideMetadata(typeof(PackIconControlBase), new UIPropertyMetadata(Visibility.Visible, (d, e) => { d.CoerceValue(SpinProperty); }));
- }
-#endif
-
-#if (NETFX_CORE || WINDOWS_UWP)
- protected static readonly DependencyProperty DataProperty
- = DependencyProperty.Register(nameof(Data), typeof(string), typeof(PackIconControlBase), new PropertyMetadata(""));
-#elif !AVALONIA
- private static readonly DependencyPropertyKey DataPropertyKey
- = DependencyProperty.RegisterReadOnly(nameof(Data), typeof(string), typeof(PackIconControlBase), new PropertyMetadata(""));
-
- // ReSharper disable once StaticMemberInGenericType
- public static readonly DependencyProperty DataProperty = DataPropertyKey.DependencyProperty;
-#endif
-
- ///
- /// Gets the path data for the current icon kind.
- ///
-#if !(NETFX_CORE || WINDOWS_UWP || AVALONIA)
- [TypeConverter(typeof(GeometryConverter))]
- public string Data
- {
- get { return (string)GetValue(DataProperty); }
- protected set { SetValue(DataPropertyKey, value); }
- }
-#endif
-
-#if NETFX_CORE || WINDOWS_UWP
- protected override void OnApplyTemplate()
- {
- base.OnApplyTemplate();
-
- this.UpdateData();
-
- this.CoerceSpinProperty(this, SpinProperty);
-
- if (this.Spin)
- {
- this.StopSpinAnimation();
- this.BeginSpinAnimation();
- }
- }
-#elif AVALONIA
- private Grid innerGrid;
-
- private ScaleTransform scaleTransform;
- private RotateTransform rotateTransform;
-
- ///
- protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
- {
- base.OnApplyTemplate(e);
-
- this.innerGrid = e.NameScope.Find("PART_InnerGrid");
-
- if (this.innerGrid != null)
- {
- var transformGroup = new TransformGroup();
- this.scaleTransform = new ScaleTransform();
- this.rotateTransform = new RotateTransform();
- transformGroup.Children.Add(scaleTransform);
- transformGroup.Children.Add(rotateTransform);
- this.innerGrid.RenderTransform = transformGroup;
- }
-
- this.UpdateScaleTransformation(this.Flip);
- this.UpdateRotateTransformation(this.RotationAngle);
- this.UpdateData();
-
- var spin = CanSpin();
- if (spin)
- {
- this.StopSpinAnimation();
- this.BeginSpinAnimation();
- }
- }
-
- protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
- {
- base.OnPropertyChanged(change);
-
- if (change.Property == FlipProperty)
- {
- if (change.NewValue != null && change.NewValue != change.OldValue)
- {
- this.UpdateScaleTransformation(change.GetNewValue());
- }
- }
- else if (change.Property == RotationAngleProperty)
- {
- if (change.NewValue != null && change.NewValue != change.OldValue)
- {
- this.UpdateRotateTransformation(change.GetNewValue());
- }
- }
- }
-
- private void UpdateScaleTransformation(PackIconFlipOrientation flipOrientation)
- {
- if (this.scaleTransform != null)
- {
- var scaleX = flipOrientation is PackIconFlipOrientation.Horizontal or PackIconFlipOrientation.Both
- ? -1
- : 1;
- var scaleY = flipOrientation is PackIconFlipOrientation.Vertical or PackIconFlipOrientation.Both
- ? -1
- : 1;
- this.scaleTransform.ScaleX = scaleX;
- this.scaleTransform.ScaleY = scaleY;
- }
- }
-
- private void UpdateRotateTransformation(double angle)
- {
- if (this.rotateTransform != null)
- {
- this.rotateTransform.Angle = angle;
- }
- }
-#else
- public override void OnApplyTemplate()
- {
- base.OnApplyTemplate();
-
- this.UpdateData();
-
- this.CoerceValue(SpinProperty);
-
- if (this.Spin)
- {
- this.StopSpinAnimation();
- this.BeginSpinAnimation();
- }
- }
-#endif
-
- ///
- /// Identifies the Flip dependency property.
- ///
-#if AVALONIA
- public static readonly StyledProperty FlipProperty
- = AvaloniaProperty.Register(nameof(Flip));
-#else
- public static readonly DependencyProperty FlipProperty
- = DependencyProperty.Register(
- nameof(Flip),
- typeof(PackIconFlipOrientation),
- typeof(PackIconControlBase),
- new PropertyMetadata(PackIconFlipOrientation.Normal));
-#endif
-
- ///
- /// Gets or sets the flip orientation.
- ///
- public PackIconFlipOrientation Flip
- {
- get { return (PackIconFlipOrientation)this.GetValue(FlipProperty); }
- set { this.SetValue(FlipProperty, value); }
- }
-
- ///
- /// Identifies the RotationAngle dependency property.
- ///
-#if NETFX_CORE || WINDOWS_UWP
- public static readonly DependencyProperty RotationAngleProperty
- = DependencyProperty.Register(
- nameof(RotationAngle),
- typeof(double),
- typeof(PackIconControlBase),
- new PropertyMetadata(0d));
-#elif AVALONIA
- public static readonly StyledProperty RotationAngleProperty
- = AvaloniaProperty.Register(
- nameof(RotationAngle),
- 0d,
- false,
- BindingMode.OneWay,
- null,
- (packIcon, value) =>
- {
- if (value < 0)
- {
- return 0d;
- }
-
- return value > 360 ? 360d : value;
- });
-#else
- public static readonly DependencyProperty RotationAngleProperty
- = DependencyProperty.Register(
- nameof(RotationAngle),
- typeof(double),
- typeof(PackIconControlBase),
- new PropertyMetadata(0d, null, (dependencyObject, value) =>
- {
- var val = (double)value;
- if (val < 0)
- {
- return 0d;
- }
-
- return val > 360 ? 360d : val;
- }));
-#endif
-
- ///
- /// Gets or sets the rotation (angle).
- ///
- /// The rotation.
- public double RotationAngle
- {
- get { return (double)this.GetValue(RotationAngleProperty); }
- set { this.SetValue(RotationAngleProperty, value); }
- }
-
- ///
- /// Identifies the Spin dependency property.
- ///
-#if NETFX_CORE || WINDOWS_UWP
- public static readonly DependencyProperty SpinProperty
- = DependencyProperty.Register(
- nameof(Spin),
- typeof(bool),
- typeof(PackIconControlBase),
- new PropertyMetadata(default(bool), SpinPropertyChangedCallback));
-
- private static void SpinPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
- {
- if (dependencyObject is PackIconControlBase packIcon && e.OldValue != e.NewValue && e.NewValue is bool)
- {
- packIcon.ToggleSpinAnimation((bool)e.NewValue);
- }
- }
-#elif AVALONIA
- public static readonly StyledProperty SpinProperty
- = AvaloniaProperty.Register(nameof(Spin));
-#else
- public static readonly DependencyProperty SpinProperty
- = DependencyProperty.Register(
- nameof(Spin),
- typeof(bool),
- typeof(PackIconControlBase),
- new PropertyMetadata(default(bool), SpinPropertyChangedCallback, SpinPropertyCoerceValueCallback));
-
- private static object SpinPropertyCoerceValueCallback(DependencyObject dependencyObject, object value)
- {
- if (dependencyObject is PackIconControlBase packIcon && (!packIcon.IsVisible || packIcon.Opacity <= 0 || packIcon.SpinDuration <= 0.0))
- {
- return false;
- }
- return value;
- }
-
- private static void SpinPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
- {
- if (dependencyObject is PackIconControlBase packIcon && e.OldValue != e.NewValue && e.NewValue is bool)
- {
- packIcon.ToggleSpinAnimation((bool)e.NewValue);
- }
- }
-#endif
-
- ///
- /// Gets or sets a value indicating whether the inner icon is spinning.
- ///
- /// true if spin; otherwise, false.
- public bool Spin
- {
- get { return (bool)this.GetValue(SpinProperty); }
- set { this.SetValue(SpinProperty, value); }
- }
-
-#if AVALONIA
- private Animation spinAnimation = null;
- private Task spinAnimationTask = null;
-
- private void BeginSpinAnimation()
- {
- if (this.innerGrid is null)
- {
- return;
- }
-
- var animation = spinAnimation ?? new Animation
- {
- Children =
- {
- new KeyFrame()
- {
- Cue = new Cue(0),
- Setters = { new Setter(RotateTransform.AngleProperty, 0d) }
- },
- new KeyFrame()
- {
- Cue = new Cue(1),
- Setters = { new Setter(RotateTransform.AngleProperty, 360d) }
- }
- }
- };
-
- animation.Duration = TimeSpan.FromSeconds(this.SpinDuration);
- animation.Easing = this.SpinEasingFunction;
- animation.IterationCount = IterationCount.Infinite;
- this.spinAnimation = animation;
- this.spinAnimationTask = animation.RunAsync(this.innerGrid);
- }
-
- private void StopSpinAnimation()
- {
- if (this.spinAnimation != null)
- {
- this.spinAnimation.IterationCount = new IterationCount(0);
- this.spinAnimationTask?.Dispose();
- this.spinAnimationTask = null;
- }
- }
-#else
- private void ToggleSpinAnimation(bool spin)
- {
- if (spin)
- {
- this.BeginSpinAnimation();
- }
- else
- {
- this.StopSpinAnimation();
- }
- }
-
- private Storyboard spinningStoryboard;
- private FrameworkElement _innerGrid;
- private FrameworkElement InnerGrid => this._innerGrid ?? (this._innerGrid =
- this.GetTemplateChild("PART_InnerGrid") as FrameworkElement);
-
- private void BeginSpinAnimation()
- {
- var element = this.InnerGrid;
- if (null == element)
- {
- return;
- }
- var transformGroup = element.RenderTransform as TransformGroup ?? new TransformGroup();
- var rotateTransform = transformGroup.Children.OfType().LastOrDefault();
-
- if (rotateTransform != null)
- {
- rotateTransform.Angle = 0;
- }
- else
- {
- transformGroup.Children.Add(new RotateTransform());
- element.RenderTransform = transformGroup;
- }
-
- var animation = new DoubleAnimation
- {
- From = 0,
- To = 360,
- AutoReverse = this.SpinAutoReverse,
- EasingFunction = this.SpinEasingFunction,
- RepeatBehavior = RepeatBehavior.Forever,
- Duration = new Duration(TimeSpan.FromSeconds(this.SpinDuration))
- };
-
- var storyboard = new Storyboard();
- storyboard.Children.Add(animation);
- Storyboard.SetTarget(animation, element);
-
-#if NETFX_CORE || WINDOWS_UWP
- Storyboard.SetTargetProperty(animation, $"(RenderTransform).(TransformGroup.Children)[{transformGroup.Children.Count - 1}].(Angle)");
-#else
- Storyboard.SetTargetProperty(animation, new PropertyPath($"(0).(1)[{transformGroup.Children.Count - 1}].(2)", RenderTransformProperty, TransformGroup.ChildrenProperty, RotateTransform.AngleProperty));
-#endif
-
- spinningStoryboard = storyboard;
- storyboard.Begin();
- }
-
- private void StopSpinAnimation()
- {
- var storyboard = spinningStoryboard;
- storyboard?.Stop();
- spinningStoryboard = null;
- }
-#endif
-
- ///
- /// Identifies the SpinDuration dependency property.
- ///
-#if NETFX_CORE || WINDOWS_UWP
- public static readonly DependencyProperty SpinDurationProperty
- = DependencyProperty.Register(
- nameof(SpinDuration),
- typeof(double),
- typeof(PackIconControlBase),
- new PropertyMetadata(1d, SpinDurationPropertyChangedCallback));
-#elif AVALONIA
- public static readonly StyledProperty SpinDurationProperty
- = AvaloniaProperty.Register(
- nameof(SpinDuration),
- 1d,
- false,
- BindingMode.OneWay,
- null,
- (iconPack, value) => value < 0 ? 0d : value);
-#else
- public static readonly DependencyProperty SpinDurationProperty
- = DependencyProperty.Register(
- nameof(SpinDuration),
- typeof(double),
- typeof(PackIconControlBase),
- new PropertyMetadata(1d, SpinDurationPropertyChangedCallback, (dependencyObject, value) =>
- {
- var val = (double)value;
- return val < 0 ? 0d : value;
- }));
-
- private static void SpinDurationPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
- {
- if (dependencyObject is PackIconControlBase packIcon && e.OldValue != e.NewValue && packIcon.Spin && e.NewValue is double)
- {
- packIcon.StopSpinAnimation();
- packIcon.BeginSpinAnimation();
- }
- }
-#endif
-
- ///
- /// Gets or sets the duration of the spinning animation (in seconds). This will also restart the spin animation.
- ///
- /// The duration of the spin in seconds.
- public double SpinDuration
- {
- get { return (double)this.GetValue(SpinDurationProperty); }
- set { this.SetValue(SpinDurationProperty, value); }
- }
-
- ///
- /// Identifies the SpinEasingFunction dependency property.
- ///
-#if NETFX_CORE || WINDOWS_UWP
- public static readonly DependencyProperty SpinEasingFunctionProperty
- = DependencyProperty.Register(
- nameof(SpinEasingFunction),
- typeof(EasingFunctionBase),
- typeof(PackIconControlBase),
- new PropertyMetadata(null, SpinEasingFunctionPropertyChangedCallback));
-
- private static void SpinEasingFunctionPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
- {
- if (dependencyObject is PackIconControlBase packIcon && e.OldValue != e.NewValue && packIcon.Spin)
- {
- packIcon.StopSpinAnimation();
- packIcon.BeginSpinAnimation();
- }
- }
-#elif AVALONIA
- public static readonly StyledProperty SpinEasingFunctionProperty
- = AvaloniaProperty.Register(
- nameof(SpinEasingFunction),
- new LinearEasing());
-#else
- public static readonly DependencyProperty SpinEasingFunctionProperty
- = DependencyProperty.Register(
- nameof(SpinEasingFunction),
- typeof(IEasingFunction),
- typeof(PackIconControlBase),
- new PropertyMetadata(null, SpinEasingFunctionPropertyChangedCallback));
-
- private static void SpinEasingFunctionPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
- {
- if (dependencyObject is PackIconControlBase packIcon && e.OldValue != e.NewValue && packIcon.Spin)
- {
- packIcon.StopSpinAnimation();
- packIcon.BeginSpinAnimation();
- }
- }
-#endif
-
- ///
- /// Gets or sets the EasingFunction of the spinning animation. This will also restart the spin animation.
- ///
- /// The spin easing function.
-#if NETFX_CORE || WINDOWS_UWP
- public EasingFunctionBase SpinEasingFunction
- {
- get { return (EasingFunctionBase)this.GetValue(SpinEasingFunctionProperty); }
- set { this.SetValue(SpinEasingFunctionProperty, value); }
- }
-#elif AVALONIA
- public Easing SpinEasingFunction
- {
- get { return (Easing)this.GetValue(SpinEasingFunctionProperty); }
- set { this.SetValue(SpinEasingFunctionProperty, value); }
- }
-#else
- public IEasingFunction SpinEasingFunction
- {
- get { return (IEasingFunction)this.GetValue(SpinEasingFunctionProperty); }
- set { this.SetValue(SpinEasingFunctionProperty, value); }
- }
-#endif
-
-#if AVALONIA
- public static readonly StyledProperty SpinAutoReverseProperty
- = AvaloniaProperty.Register(nameof(SpinAutoReverse));
-#else
- ///
- /// Identifies the SpinAutoReverse dependency property.
- ///
- public static readonly DependencyProperty SpinAutoReverseProperty
- = DependencyProperty.Register(
- nameof(SpinAutoReverse),
- typeof(bool),
- typeof(PackIconControlBase),
- new PropertyMetadata(default(bool), SpinAutoReversePropertyChangedCallback));
-
- private static void SpinAutoReversePropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
- {
- if (dependencyObject is PackIconControlBase packIcon && e.OldValue != e.NewValue && packIcon.Spin && e.NewValue is bool)
- {
- packIcon.StopSpinAnimation();
- packIcon.BeginSpinAnimation();
- }
- }
-#endif
-
- ///
- /// Gets or sets the AutoReverse of the spinning animation. This will also restart the spin animation.
- ///
- /// true if [spin automatic reverse]; otherwise, false.
- public bool SpinAutoReverse
- {
- get { return (bool)this.GetValue(SpinAutoReverseProperty); }
- set { this.SetValue(SpinAutoReverseProperty, value); }
- }
- }
-}
\ No newline at end of file
diff --git a/src/AvaloniaIconPacks/PackIconBoxIcons.cs b/src/AvaloniaIconPacks/PackIconBoxIcons.cs
index 8d3f17b..4280be4 100644
--- a/src/AvaloniaIconPacks/PackIconBoxIcons.cs
+++ b/src/AvaloniaIconPacks/PackIconBoxIcons.cs
@@ -1,13 +1,6 @@
-using System;
using Avalonia.Media;
-#if (NETFX_CORE || WINDOWS_UWP)
-using Windows.UI.Xaml;
-using Windows.UI.Xaml.Data;
-#elif AVALONIA
+using IconPacks.Avalonia;
using Avalonia;
-#else
-using System.Windows;
-#endif
namespace MahApps.Metro.IconPacks
{
@@ -17,73 +10,38 @@ namespace MahApps.Metro.IconPacks
///
public class PackIconBoxIcons : PackIconControlBase
{
-#if AVALONIA
public static readonly StyledProperty KindProperty
= AvaloniaProperty.Register(nameof(Kind));
-#else
- public static readonly DependencyProperty KindProperty
- = DependencyProperty.Register(
- nameof(Kind),
- typeof(PackIconBoxIconsKind),
- typeof(PackIconBoxIcons),
- new PropertyMetadata(default(PackIconBoxIconsKind), KindPropertyChangedCallback));
-
- private static void KindPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
- {
- if (e.NewValue != e.OldValue)
- {
- ((PackIconBoxIcons)dependencyObject).UpdateData();
- }
- }
-#endif
///
/// Gets or sets the icon to display.
///
public PackIconBoxIconsKind Kind
{
- get { return (PackIconBoxIconsKind) GetValue(KindProperty); }
+ get { return GetValue(KindProperty); }
set { SetValue(KindProperty, value); }
}
-#if NETFX_CORE || WINDOWS_UWP
- public PackIconBoxIcons()
- {
- this.DefaultStyleKey = typeof(PackIconBoxIcons);
- }
-#elif AVALONIA
// We override OnPropertyChanged of the base class. That way we can react on property changes
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
- // if the changed property is the NumberOfStarsProperty, we need to update the stars
+ // if the changed property is the KindProperty, we need to update the stars
if (change.Property == KindProperty)
{
UpdateData();
}
}
-#else
- static PackIconBoxIcons()
- {
- DefaultStyleKeyProperty.OverrideMetadata(typeof(PackIconBoxIcons), new FrameworkPropertyMetadata(typeof(PackIconBoxIcons)));
- }
-#endif
- protected internal override void SetKind(TKind iconKind)
+ protected override void SetKind(TKind iconKind)
{
-#if NETFX_CORE || WINDOWS_UWP
- BindingOperations.SetBinding(this, PackIconBoxIcons.KindProperty, new Binding() { Source = iconKind, Mode = BindingMode.OneTime });
-#elif AVALONIA
this.SetValue(KindProperty, iconKind);
-#else
- this.SetCurrentValue(KindProperty, iconKind);
-#endif
}
protected override void UpdateData()
{
- if (Kind != default(PackIconBoxIconsKind))
+ if (Kind != default)
{
string data = null;
PackIconBoxIconsDataFactory.DataIndex.Value?.TryGetValue(Kind, out data);
diff --git a/src/IconPacks.Avalonia.Core/Attributes/MetaDataAttribute.cs b/src/IconPacks.Avalonia.Core/Attributes/MetaDataAttribute.cs
new file mode 100644
index 0000000..4c1cee5
--- /dev/null
+++ b/src/IconPacks.Avalonia.Core/Attributes/MetaDataAttribute.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace IconPacks.Avalonia.Attributes
+{
+ ///
+ /// Specifies meta data for a class.
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
+ public sealed class MetaDataAttribute : Attribute
+ {
+ public MetaDataAttribute()
+ {
+ }
+
+ public MetaDataAttribute(string name, string projectUrl, string licenseUrl)
+ {
+ Name = name;
+ ProjectUrl = projectUrl;
+ LicenseUrl = licenseUrl;
+ }
+
+ public string Name { get; }
+
+ public string ProjectUrl { get; }
+
+ public string LicenseUrl { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/IconPacks.Avalonia.Core/Converter/DataTypeValueConverter.cs b/src/IconPacks.Avalonia.Core/Converter/DataTypeValueConverter.cs
new file mode 100644
index 0000000..b1bf660
--- /dev/null
+++ b/src/IconPacks.Avalonia.Core/Converter/DataTypeValueConverter.cs
@@ -0,0 +1,39 @@
+using Avalonia.Data;
+using System;
+using System.Globalization;
+
+namespace IconPacks.Avalonia.Converter
+{
+ public class DataTypeValueConverter : MarkupConverter
+ {
+ // Explicit static constructor to tell C# compiler
+ // not to mark type as beforefieldinit
+ static DataTypeValueConverter()
+ {
+ }
+
+ private DataTypeValueConverter()
+ {
+ }
+
+ public static DataTypeValueConverter Instance { get; } = new();
+
+ ///
+ public override object ProvideValue(IServiceProvider serviceProvider)
+ {
+ return Instance;
+ }
+
+ ///
+ protected override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ return value?.GetType();
+ }
+
+ ///
+ protected override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ return BindingNotification.UnsetValue;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/IconPacks.Avalonia.Core/Converter/FlipToScaleXValueConverter.cs b/src/IconPacks.Avalonia.Core/Converter/FlipToScaleXValueConverter.cs
new file mode 100644
index 0000000..0367bb2
--- /dev/null
+++ b/src/IconPacks.Avalonia.Core/Converter/FlipToScaleXValueConverter.cs
@@ -0,0 +1,49 @@
+using Avalonia.Data;
+using System;
+using System.Globalization;
+
+namespace IconPacks.Avalonia.Converter
+{
+ ///
+ /// ValueConverter which converts the PackIconFlipOrientation enumeration value to ScaleX value of a ScaleTransformation.
+ ///
+ public class FlipToScaleXValueConverter : MarkupConverter
+ {
+ // Explicit static constructor to tell C# compiler
+ // not to mark type as beforefieldinit
+ static FlipToScaleXValueConverter()
+ {
+ }
+
+ private FlipToScaleXValueConverter()
+ {
+ }
+
+ public static FlipToScaleXValueConverter Instance { get; } = new();
+
+ ///
+ public override object ProvideValue(IServiceProvider serviceProvider)
+ {
+ return Instance;
+ }
+
+ ///
+ protected override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ if (value is PackIconFlipOrientation flip)
+ {
+ return flip is PackIconFlipOrientation.Horizontal or PackIconFlipOrientation.Both
+ ? -1
+ : 1;
+ }
+
+ return 1;
+ }
+
+ ///
+ protected override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ return BindingNotification.UnsetValue;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/IconPacks.Avalonia.Core/Converter/FlipToScaleYValueConverter.cs b/src/IconPacks.Avalonia.Core/Converter/FlipToScaleYValueConverter.cs
new file mode 100644
index 0000000..710e167
--- /dev/null
+++ b/src/IconPacks.Avalonia.Core/Converter/FlipToScaleYValueConverter.cs
@@ -0,0 +1,48 @@
+using Avalonia.Data;
+using System;
+using System.Globalization;
+
+namespace IconPacks.Avalonia.Converter
+{
+ ///
+ /// ValueConverter which converts the PackIconFlipOrientation enumeration value to ScaleY value of a ScaleTransformation.
+ ///
+ public class FlipToScaleYValueConverter : MarkupConverter
+ {
+ // Explicit static constructor to tell C# compiler
+ // not to mark type as beforefieldinit
+ static FlipToScaleYValueConverter()
+ {
+ }
+
+ private FlipToScaleYValueConverter()
+ {
+ }
+
+ public static FlipToScaleYValueConverter Instance { get; } = new();
+
+ ///
+ public override object ProvideValue(IServiceProvider serviceProvider)
+ {
+ return Instance;
+ }
+
+ ///
+ protected override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ if (value is PackIconFlipOrientation flip)
+ {
+ var scaleY = flip == PackIconFlipOrientation.Vertical || flip == PackIconFlipOrientation.Both ? -1 : 1;
+ return scaleY;
+ }
+
+ return 1;
+ }
+
+ ///
+ protected override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ return BindingNotification.UnsetValue;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/IconPacks.Avalonia.Core/Converter/MarkupConverter.cs b/src/IconPacks.Avalonia.Core/Converter/MarkupConverter.cs
new file mode 100644
index 0000000..c2b7f12
--- /dev/null
+++ b/src/IconPacks.Avalonia.Core/Converter/MarkupConverter.cs
@@ -0,0 +1,76 @@
+using System;
+using Avalonia.Data.Converters;
+using Avalonia.Markup.Xaml;
+using System.Globalization;
+using Avalonia.Data;
+
+namespace IconPacks.Avalonia.Converter
+{
+ ///
+ /// MarkupConverter is a MarkupExtension which can be used for IValueConverter.
+ ///
+ public abstract class MarkupConverter : MarkupExtension, IValueConverter
+ {
+ ///
+ public override object ProvideValue(IServiceProvider serviceProvider)
+ {
+ return this;
+ }
+
+ ///
+ /// Converts a value.
+ ///
+ /// The value to convert.
+ /// The type of the target.
+ /// A user-defined parameter.
+ /// The culture to use.
+ /// The converted value.
+ ///
+ /// This method should not throw exceptions. If the value is not convertible, return
+ /// a in an error state. Any exceptions thrown will be
+ /// treated as an application exception.
+ ///
+ protected abstract object Convert(object value, Type targetType, object parameter, CultureInfo culture);
+
+ ///
+ /// Converts a value.
+ ///
+ /// The value to convert.
+ /// The type of the target.
+ /// A user-defined parameter.
+ /// The culture to use.
+ /// The converted value.
+ ///
+ /// This method should not throw exceptions. If the value is not convertible, return
+ /// a in an error state. Any exceptions thrown will be
+ /// treated as an application exception.
+ ///
+ protected abstract object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture);
+
+ ///
+ object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ try
+ {
+ return Convert(value, targetType, parameter, culture);
+ }
+ catch
+ {
+ return BindingNotification.UnsetValue;
+ }
+ }
+
+ ///
+ object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ try
+ {
+ return ConvertBack(value, targetType, parameter, culture);
+ }
+ catch
+ {
+ return BindingNotification.UnsetValue;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/IconPacks.Avalonia.Core/Converter/NullToUnsetValueConverter.cs b/src/IconPacks.Avalonia.Core/Converter/NullToUnsetValueConverter.cs
new file mode 100644
index 0000000..ae7d30e
--- /dev/null
+++ b/src/IconPacks.Avalonia.Core/Converter/NullToUnsetValueConverter.cs
@@ -0,0 +1,39 @@
+using Avalonia.Data;
+using System;
+using System.Globalization;
+
+namespace IconPacks.Avalonia.Converter
+{
+ public class NullToUnsetValueConverter : MarkupConverter
+ {
+ // Explicit static constructor to tell C# compiler
+ // not to mark type as beforefieldinit
+ static NullToUnsetValueConverter()
+ {
+ }
+
+ private NullToUnsetValueConverter()
+ {
+ }
+
+ public static NullToUnsetValueConverter Instance { get; } = new();
+
+ ///
+ public override object ProvideValue(IServiceProvider serviceProvider)
+ {
+ return Instance;
+ }
+
+ ///
+ protected override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ return value ?? BindingNotification.UnsetValue;
+ }
+
+ ///
+ protected override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ return BindingNotification.UnsetValue;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/IconPacks.Avalonia.Core/IconPacks.Avalonia.Core.csproj b/src/IconPacks.Avalonia.Core/IconPacks.Avalonia.Core.csproj
new file mode 100644
index 0000000..22834c3
--- /dev/null
+++ b/src/IconPacks.Avalonia.Core/IconPacks.Avalonia.Core.csproj
@@ -0,0 +1,27 @@
+
+
+
+ net8.0;net6.0;netstandard2.0
+ $(DefineConstants);AVALONIA
+ latest
+ disable
+ true
+
+
+
+ IconPacks.Avalonia.Core
+ IconPacks.Avalonia.Core
+ IconPacks.Avalonia
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/IconPacks.Avalonia.Core/PackIconBase.cs b/src/IconPacks.Avalonia.Core/PackIconBase.cs
new file mode 100644
index 0000000..526b5ec
--- /dev/null
+++ b/src/IconPacks.Avalonia.Core/PackIconBase.cs
@@ -0,0 +1,10 @@
+using Avalonia.Controls;
+
+namespace IconPacks.Avalonia
+{
+ public abstract class PackIconBase : PathIcon
+ {
+ protected internal abstract void SetKind(TKind iconKind);
+ protected abstract void UpdateData();
+ }
+}
\ No newline at end of file
diff --git a/src/IconPacks.Avalonia.Core/PackIconControlBase.cs b/src/IconPacks.Avalonia.Core/PackIconControlBase.cs
new file mode 100644
index 0000000..e58fb0f
--- /dev/null
+++ b/src/IconPacks.Avalonia.Core/PackIconControlBase.cs
@@ -0,0 +1,285 @@
+using System;
+using System.Reactive;
+using System.Reactive.Linq;
+using System.Threading.Tasks;
+using Avalonia;
+using Avalonia.Animation;
+using Avalonia.Animation.Easings;
+using Avalonia.Controls;
+using Avalonia.Controls.Primitives;
+using Avalonia.Data;
+using Avalonia.Media;
+using Avalonia.Styling;
+
+namespace IconPacks.Avalonia
+{
+ ///
+ /// Class PackIconControlBase which is the base class for any PackIcon control.
+ ///
+ public abstract class PackIconControlBase : PackIconBase
+ {
+ public PackIconControlBase()
+ {
+ AffectsRender(SpinProperty, SpinDurationProperty, OpacityProperty, SpinEasingFunctionProperty, FlipProperty, RotationAngleProperty);
+
+ Observable.CombineLatest(
+ this.GetObservable(SpinProperty).Select(_ => Unit.Default),
+ this.GetObservable(IsVisibleProperty).Select(_ => Unit.Default),
+ this.GetObservable(SpinDurationProperty).Select(_ => Unit.Default),
+ this.GetObservable(OpacityProperty).Select(_ => Unit.Default),
+ this.GetObservable(SpinEasingFunctionProperty).Select(_ => Unit.Default))
+ .Select(_ => this.CanSpin())
+ .Subscribe(spin =>
+ {
+ this.StopSpinAnimation();
+ if (spin)
+ {
+ this.BeginSpinAnimation();
+ }
+ });
+ }
+
+ private bool CanSpin()
+ {
+ return this.Spin
+ && this.IsVisible
+ && this.SpinDuration > 0
+ && this.Opacity > 0
+ && this.SpinEasingFunction != null;
+ }
+
+ private Grid innerGrid;
+ private ScaleTransform scaleTransform;
+ private RotateTransform rotateTransform;
+
+ ///
+ protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
+ {
+ base.OnApplyTemplate(e);
+
+ this.innerGrid = e.NameScope.Find("PART_InnerGrid");
+
+ if (this.innerGrid != null)
+ {
+ var transformGroup = new TransformGroup();
+ this.scaleTransform = new ScaleTransform();
+ this.rotateTransform = new RotateTransform();
+ transformGroup.Children.Add(scaleTransform);
+ transformGroup.Children.Add(rotateTransform);
+ this.innerGrid.RenderTransform = transformGroup;
+ }
+
+ this.UpdateScaleTransformation(this.Flip);
+ this.UpdateRotateTransformation(this.RotationAngle);
+ this.UpdateData();
+
+ var spin = CanSpin();
+ if (spin)
+ {
+ this.StopSpinAnimation();
+ this.BeginSpinAnimation();
+ }
+ }
+
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
+ {
+ base.OnPropertyChanged(change);
+
+ if (change.Property == FlipProperty)
+ {
+ if (change.NewValue != null && change.NewValue != change.OldValue)
+ {
+ this.UpdateScaleTransformation(change.GetNewValue());
+ }
+ }
+ else if (change.Property == RotationAngleProperty)
+ {
+ if (change.NewValue != null && change.NewValue != change.OldValue)
+ {
+ this.UpdateRotateTransformation(change.GetNewValue());
+ }
+ }
+ }
+
+ private void UpdateScaleTransformation(PackIconFlipOrientation flipOrientation)
+ {
+ if (this.scaleTransform != null)
+ {
+ var scaleX = flipOrientation is PackIconFlipOrientation.Horizontal or PackIconFlipOrientation.Both
+ ? -1
+ : 1;
+ var scaleY = flipOrientation is PackIconFlipOrientation.Vertical or PackIconFlipOrientation.Both
+ ? -1
+ : 1;
+ this.scaleTransform.ScaleX = scaleX;
+ this.scaleTransform.ScaleY = scaleY;
+ }
+ }
+
+ private void UpdateRotateTransformation(double angle)
+ {
+ if (this.rotateTransform != null)
+ {
+ this.rotateTransform.Angle = angle;
+ }
+ }
+
+ ///
+ /// Identifies the Flip dependency property.
+ ///
+ public static readonly StyledProperty FlipProperty
+ = AvaloniaProperty.Register(nameof(Flip));
+
+ ///
+ /// Gets or sets the flip orientation.
+ ///
+ public PackIconFlipOrientation Flip
+ {
+ get { return this.GetValue(FlipProperty); }
+ set { this.SetValue(FlipProperty, value); }
+ }
+
+ ///
+ /// Identifies the RotationAngle dependency property.
+ ///
+ public static readonly StyledProperty RotationAngleProperty
+ = AvaloniaProperty.Register(
+ nameof(RotationAngle),
+ 0d,
+ false,
+ BindingMode.OneWay,
+ null,
+ (packIcon, value) =>
+ {
+ if (value < 0)
+ {
+ return 0d;
+ }
+
+ return value > 360 ? 360d : value;
+ });
+
+ ///
+ /// Gets or sets the rotation (angle).
+ ///
+ /// The rotation.
+ public double RotationAngle
+ {
+ get { return this.GetValue(RotationAngleProperty); }
+ set { this.SetValue(RotationAngleProperty, value); }
+ }
+
+ ///
+ /// Identifies the Spin dependency property.
+ ///
+ public static readonly StyledProperty SpinProperty
+ = AvaloniaProperty.Register(nameof(Spin));
+
+ ///
+ /// Gets or sets a value indicating whether the inner icon is spinning.
+ ///
+ /// true if spin; otherwise, false.
+ public bool Spin
+ {
+ get { return this.GetValue(SpinProperty); }
+ set { this.SetValue(SpinProperty, value); }
+ }
+
+ private Animation spinAnimation = null;
+ private Task spinAnimationTask = null;
+
+ private void BeginSpinAnimation()
+ {
+ if (this.innerGrid is null)
+ {
+ return;
+ }
+
+ var animation = spinAnimation ?? new Animation
+ {
+ Children =
+ {
+ new KeyFrame()
+ {
+ Cue = new Cue(0),
+ Setters = { new Setter(RotateTransform.AngleProperty, 0d) }
+ },
+ new KeyFrame()
+ {
+ Cue = new Cue(1),
+ Setters = { new Setter(RotateTransform.AngleProperty, 360d) }
+ }
+ }
+ };
+
+ animation.Duration = TimeSpan.FromSeconds(this.SpinDuration);
+ animation.Easing = this.SpinEasingFunction;
+ animation.IterationCount = IterationCount.Infinite;
+ this.spinAnimation = animation;
+ this.spinAnimationTask = animation.RunAsync(this.innerGrid);
+ }
+
+ private void StopSpinAnimation()
+ {
+ if (this.spinAnimation != null)
+ {
+ this.spinAnimation.IterationCount = new IterationCount(0);
+ this.spinAnimationTask?.Dispose();
+ this.spinAnimationTask = null;
+ }
+ }
+
+ ///
+ /// Identifies the SpinDuration dependency property.
+ ///
+ public static readonly StyledProperty SpinDurationProperty
+ = AvaloniaProperty.Register(
+ nameof(SpinDuration),
+ 1d,
+ false,
+ BindingMode.OneWay,
+ null,
+ (iconPack, value) => value < 0 ? 0d : value);
+
+ ///
+ /// Gets or sets the duration of the spinning animation (in seconds). This will also restart the spin animation.
+ ///
+ /// The duration of the spin in seconds.
+ public double SpinDuration
+ {
+ get { return this.GetValue(SpinDurationProperty); }
+ set { this.SetValue(SpinDurationProperty, value); }
+ }
+
+ ///
+ /// Identifies the SpinEasingFunction dependency property.
+ ///
+ public static readonly StyledProperty SpinEasingFunctionProperty
+ = AvaloniaProperty.Register(
+ nameof(SpinEasingFunction),
+ new LinearEasing());
+
+ ///
+ /// Gets or sets the EasingFunction of the spinning animation. This will also restart the spin animation.
+ ///
+ /// The spin easing function.
+ public Easing SpinEasingFunction
+ {
+ get { return this.GetValue(SpinEasingFunctionProperty); }
+ set { this.SetValue(SpinEasingFunctionProperty, value); }
+ }
+
+ public static readonly StyledProperty SpinAutoReverseProperty
+ = AvaloniaProperty.Register(nameof(SpinAutoReverse));
+
+ ///
+ /// Gets or sets the AutoReverse of the spinning animation. This will also restart the spin animation.
+ ///
+ /// true if [spin automatic reverse]; otherwise, false.
+ public bool SpinAutoReverse
+ {
+ get { return this.GetValue(SpinAutoReverseProperty); }
+ set { this.SetValue(SpinAutoReverseProperty, value); }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/IconPacks.Avalonia.Core/PackIconDataFactory.cs b/src/IconPacks.Avalonia.Core/PackIconDataFactory.cs
new file mode 100644
index 0000000..8c70d1c
--- /dev/null
+++ b/src/IconPacks.Avalonia.Core/PackIconDataFactory.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using IconPacks.Avalonia.Utils;
+
+namespace IconPacks.Avalonia
+{
+ public static class PackIconDataFactory where TEnum : struct, Enum
+ {
+ public static Lazy> DataIndex { get; }
+
+ static PackIconDataFactory()
+ {
+ DataIndex = new Lazy>(Create);
+ }
+
+ public static IDictionary Create()
+ {
+ var json = System.Reflection.Assembly.GetAssembly(typeof(TEnum))?.ReadFile("Resources.Icons.json");
+ return string.IsNullOrEmpty(json)
+ ? new Dictionary()
+ : System.Text.Json.JsonSerializer.Deserialize>(json);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/IconPacks.Avalonia.Core/PackIconExtension.cs b/src/IconPacks.Avalonia.Core/PackIconExtension.cs
new file mode 100644
index 0000000..aded4cd
--- /dev/null
+++ b/src/IconPacks.Avalonia.Core/PackIconExtension.cs
@@ -0,0 +1,240 @@
+using Avalonia.Animation.Easings;
+using System;
+using Avalonia.Markup.Xaml;
+
+namespace IconPacks.Avalonia
+{
+ public interface IPackIconExtension
+ {
+ double Width { get; set; }
+ double Height { get; set; }
+ PackIconFlipOrientation Flip { get; set; }
+ double RotationAngle { get; set; }
+ bool Spin { get; set; }
+ bool SpinAutoReverse { get; set; }
+ Easing SpinEasingFunction { get; set; }
+ double SpinDuration { get; set; }
+ }
+
+ public static class PackIconExtensionHelper
+ {
+ public static PackIconControlBase GetPackIcon(this IPackIconExtension packIconExtension, TKind kind) where TPack : PackIconControlBase, new()
+ {
+ var packIcon = new TPack();
+ packIcon.SetKind(kind);
+
+ if (((BasePackIconExtension)packIconExtension).IsFieldChanged(BasePackIconExtension.ChangedFieldFlags.Width))
+ {
+ packIcon.Width = packIconExtension.Width;
+ }
+
+ if (((BasePackIconExtension)packIconExtension).IsFieldChanged(BasePackIconExtension.ChangedFieldFlags.Height))
+ {
+ packIcon.Height = packIconExtension.Height;
+ }
+
+ if (((BasePackIconExtension)packIconExtension).IsFieldChanged(BasePackIconExtension.ChangedFieldFlags.Flip))
+ {
+ packIcon.Flip = packIconExtension.Flip;
+ }
+
+ if (((BasePackIconExtension)packIconExtension).IsFieldChanged(BasePackIconExtension.ChangedFieldFlags.RotationAngle))
+ {
+ packIcon.RotationAngle = packIconExtension.RotationAngle;
+ }
+
+ if (((BasePackIconExtension)packIconExtension).IsFieldChanged(BasePackIconExtension.ChangedFieldFlags.Spin))
+ {
+ packIcon.Spin = packIconExtension.Spin;
+ }
+
+ if (((BasePackIconExtension)packIconExtension).IsFieldChanged(BasePackIconExtension.ChangedFieldFlags.SpinAutoReverse))
+ {
+ packIcon.SpinAutoReverse = packIconExtension.SpinAutoReverse;
+ }
+
+ if (((BasePackIconExtension)packIconExtension).IsFieldChanged(BasePackIconExtension.ChangedFieldFlags.SpinEasingFunction))
+ {
+ packIcon.SpinEasingFunction = packIconExtension.SpinEasingFunction;
+ }
+
+ if (((BasePackIconExtension)packIconExtension).IsFieldChanged(BasePackIconExtension.ChangedFieldFlags.SpinDuration))
+ {
+ packIcon.SpinDuration = packIconExtension.SpinDuration;
+ }
+
+ return packIcon;
+ }
+ }
+
+ public abstract class BasePackIconExtension : MarkupExtension, IPackIconExtension
+ {
+ private double _width = 20d;
+
+ public double Width
+ {
+ get => _width;
+ set
+ {
+ if (Equals(_width, value))
+ {
+ return;
+ }
+
+ _width = value;
+ WriteFieldChangedFlag(ChangedFieldFlags.Width, true);
+ }
+ }
+
+ private double _height = 20d;
+
+ public double Height
+ {
+ get => _height;
+ set
+ {
+ if (Equals(_height, value))
+ {
+ return;
+ }
+
+ _height = value;
+ WriteFieldChangedFlag(ChangedFieldFlags.Height, true);
+ }
+ }
+
+ private PackIconFlipOrientation _flip = PackIconFlipOrientation.Normal;
+
+ public PackIconFlipOrientation Flip
+ {
+ get => _flip;
+ set
+ {
+ if (Equals(_flip, value))
+ {
+ return;
+ }
+
+ _flip = value;
+ WriteFieldChangedFlag(ChangedFieldFlags.Flip, true);
+ }
+ }
+
+ private double _rotationAngle = 0d;
+
+ public double RotationAngle
+ {
+ get => _rotationAngle;
+ set
+ {
+ if (Equals(_rotationAngle, value))
+ {
+ return;
+ }
+
+ _rotationAngle = value;
+ WriteFieldChangedFlag(ChangedFieldFlags.RotationAngle, true);
+ }
+ }
+
+ private bool _spin;
+
+ public bool Spin
+ {
+ get => _spin;
+ set
+ {
+ if (Equals(_spin, value))
+ {
+ return;
+ }
+
+ _spin = value;
+ WriteFieldChangedFlag(ChangedFieldFlags.Spin, true);
+ }
+ }
+
+ private bool _spinAutoReverse;
+
+ public bool SpinAutoReverse
+ {
+ get => _spinAutoReverse;
+ set
+ {
+ if (Equals(_spinAutoReverse, value))
+ {
+ return;
+ }
+
+ _spinAutoReverse = value;
+ WriteFieldChangedFlag(ChangedFieldFlags.SpinAutoReverse, true);
+ }
+ }
+
+ private Easing _spinEasingFunction = null;
+
+ public Easing SpinEasingFunction
+ {
+ get => _spinEasingFunction;
+ set
+ {
+ if (Equals(_spinEasingFunction, value))
+ {
+ return;
+ }
+
+ _spinEasingFunction = value;
+ WriteFieldChangedFlag(ChangedFieldFlags.SpinEasingFunction, true);
+ }
+ }
+
+ private double _spinDuration = 1d;
+
+ public double SpinDuration
+ {
+ get => _spinDuration;
+ set
+ {
+ if (Equals(_spinDuration, value))
+ {
+ return;
+ }
+
+ _spinDuration = value;
+ WriteFieldChangedFlag(ChangedFieldFlags.SpinDuration, true);
+ }
+ }
+
+ internal ChangedFieldFlags changedField; // Cache changed field bits
+
+ internal bool IsFieldChanged(ChangedFieldFlags reqFlag)
+ {
+ return (changedField & reqFlag) != 0;
+ }
+
+ internal void WriteFieldChangedFlag(ChangedFieldFlags reqFlag, bool set)
+ {
+ if (set)
+ {
+ changedField |= reqFlag;
+ }
+ else
+ {
+ changedField &= (~reqFlag);
+ }
+ }
+
+ [Flags]
+ internal enum ChangedFieldFlags : ushort
+ {
+ Width = 0x0001,
+ Height = 0x0002,
+ Flip = 0x0004,
+ RotationAngle = 0x0008,
+ Spin = 0x0010,
+ SpinAutoReverse = 0x0020,
+ SpinEasingFunction = 0x0040,
+ SpinDuration = 0x0080
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/AvaloniaIconPacks/Core/PackIconFlipOrientation.cs b/src/IconPacks.Avalonia.Core/PackIconFlipOrientation.cs
similarity index 90%
rename from src/AvaloniaIconPacks/Core/PackIconFlipOrientation.cs
rename to src/IconPacks.Avalonia.Core/PackIconFlipOrientation.cs
index cae5cde..aa217db 100644
--- a/src/AvaloniaIconPacks/Core/PackIconFlipOrientation.cs
+++ b/src/IconPacks.Avalonia.Core/PackIconFlipOrientation.cs
@@ -1,28 +1,28 @@
-namespace MahApps.Metro.IconPacks
-{
- ///
- /// Enum PackIconFlipOrientation for the Flip property of any PackIcon control.
- ///
- public enum PackIconFlipOrientation
- {
- ///
- /// No flip
- ///
- Normal,
-
- ///
- /// Flip the icon horizontal
- ///
- Horizontal,
-
- ///
- /// Flip the icon vertical
- ///
- Vertical,
-
- ///
- /// Flip the icon vertical and horizontal
- ///
- Both
- }
+namespace IconPacks.Avalonia
+{
+ ///
+ /// Enum PackIconFlipOrientation for the Flip property of any PackIcon control.
+ ///
+ public enum PackIconFlipOrientation
+ {
+ ///
+ /// No flip
+ ///
+ Normal,
+
+ ///
+ /// Flip the icon horizontal
+ ///
+ Horizontal,
+
+ ///
+ /// Flip the icon vertical
+ ///
+ Vertical,
+
+ ///
+ /// Flip the icon vertical and horizontal
+ ///
+ Both
+ }
}
\ No newline at end of file
diff --git a/src/IconPacks.Avalonia.Core/PackIconImageExtension.cs b/src/IconPacks.Avalonia.Core/PackIconImageExtension.cs
new file mode 100644
index 0000000..20e199a
--- /dev/null
+++ b/src/IconPacks.Avalonia.Core/PackIconImageExtension.cs
@@ -0,0 +1,90 @@
+using Avalonia.Markup.Xaml;
+using Avalonia.Media;
+
+namespace IconPacks.Avalonia
+{
+ public abstract class BasePackIconImageExtension : MarkupExtension
+ {
+ ///
+ /// Gets or sets the brush to draw the icon.
+ ///
+ public IBrush Brush { get; set; } = Brushes.Black;
+
+ ///
+ /// Gets or sets the flip orientation for the icon.
+ ///
+ public PackIconFlipOrientation Flip { get; set; } = PackIconFlipOrientation.Normal;
+
+ ///
+ /// Gets or sets the rotation (angle) for the icon.
+ ///
+ public double RotationAngle { get; set; } = 0d;
+
+ ///
+ /// Gets the path data for the given kind.
+ ///
+ protected abstract string GetPathData(object iconKind);
+
+ ///
+ /// Gets the ScaleTransform for the given kind.
+ ///
+ /// The icon kind to draw.
+ protected virtual ScaleTransform GetScaleTransform(object iconKind)
+ {
+ return new ScaleTransform(1, 1);
+ }
+
+ ///
+ /// Gets the for the .
+ ///
+ /// The icon kind to draw.
+ protected Transform GetTransformGroup(object iconKind)
+ {
+ var transformGroup = new TransformGroup();
+ transformGroup.Children.Add(this.GetScaleTransform(iconKind)); // scale
+ transformGroup.Children.Add(new ScaleTransform(
+ this.Flip is PackIconFlipOrientation.Horizontal or PackIconFlipOrientation.Both ? -1 : 1,
+ this.Flip is PackIconFlipOrientation.Vertical or PackIconFlipOrientation.Both ? -1 : 1
+ )); // flip
+ transformGroup.Children.Add(new RotateTransform(this.RotationAngle)); // rotate
+
+ return transformGroup;
+ }
+
+ ///
+ /// Gets the object that will be used for the .
+ ///
+ protected virtual DrawingGroup GetDrawingGroup(object iconKind, Brush foregroundBrush, string path)
+ {
+ var geometryDrawing = new GeometryDrawing
+ {
+ Geometry = Geometry.Parse(path),
+ Brush = foregroundBrush
+ };
+
+ var drawingGroup = new DrawingGroup
+ {
+ Children = { geometryDrawing },
+ Transform = this.GetTransformGroup(iconKind)
+ };
+
+ return drawingGroup;
+ }
+
+ ///
+ /// Gets the ImageSource for the given kind.
+ ///
+ protected IImage CreateImageSource(object iconKind, Brush foregroundBrush)
+ {
+ var path = this.GetPathData(iconKind);
+
+ if (string.IsNullOrEmpty(path))
+ {
+ return null;
+ }
+
+ var drawingImage = new DrawingImage(GetDrawingGroup(iconKind, foregroundBrush, path));
+ return drawingImage;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/IconPacks.Avalonia.Core/Properties/AssemblyInfo.cs b/src/IconPacks.Avalonia.Core/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..fb305e5
--- /dev/null
+++ b/src/IconPacks.Avalonia.Core/Properties/AssemblyInfo.cs
@@ -0,0 +1,9 @@
+using System.Runtime.InteropServices;
+using Avalonia.Metadata;
+
+[assembly: XmlnsPrefix("urn:iconpacks-avalonia", "iconPacks")]
+[assembly: XmlnsDefinition("urn:iconpacks-avalonia", "IconPacks")]
+[assembly: XmlnsDefinition("urn:iconpacks-avalonia", "IconPacks.Avalonia")]
+[assembly: XmlnsDefinition("urn:iconpacks-avalonia", "IconPacks.Avalonia.Attributes")]
+
+[assembly: ComVisible(false)]
\ No newline at end of file
diff --git a/src/IconPacks.Avalonia.Core/Utils/AssemblyTextFileReader.cs b/src/IconPacks.Avalonia.Core/Utils/AssemblyTextFileReader.cs
new file mode 100644
index 0000000..e3a2691
--- /dev/null
+++ b/src/IconPacks.Avalonia.Core/Utils/AssemblyTextFileReader.cs
@@ -0,0 +1,62 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+using JetBrains.Annotations;
+
+namespace IconPacks.Avalonia.Utils
+{
+ public static class AssemblyTextFileReader
+ {
+ private static string GetManifestResourceName(this Assembly assembly, string fileName)
+ {
+ var name = assembly
+ .GetManifestResourceNames()
+ .SingleOrDefault(n => n.EndsWith(fileName, StringComparison.InvariantCultureIgnoreCase));
+
+ if (string.IsNullOrEmpty(name))
+ {
+ throw new FileNotFoundException($"Embedded file '{fileName}' could not be found in assembly '{assembly.FullName}'.", fileName);
+ }
+
+ return name;
+ }
+
+ public static async Task ReadFileAsync([NotNull] this Assembly assembly, string fileName)
+ {
+ if (assembly == null) throw new ArgumentNullException(nameof(assembly));
+
+ var resourceName = assembly.GetManifestResourceName(fileName);
+
+#if NET6_0_OR_GREATER
+ await using var stream = assembly.GetManifestResourceStream(resourceName);
+#else
+ using var stream = assembly.GetManifestResourceStream(resourceName);
+#endif
+ if (stream != null)
+ {
+ using var reader = new StreamReader(stream);
+ return await reader.ReadToEndAsync().ConfigureAwait(false);
+ }
+
+ return null;
+ }
+
+ public static string ReadFile([NotNull] this Assembly assembly, string fileName)
+ {
+ if (assembly == null) throw new ArgumentNullException(nameof(assembly));
+
+ var resourceName = assembly.GetManifestResourceName(fileName);
+
+ using var stream = assembly.GetManifestResourceStream(resourceName);
+ if (stream != null)
+ {
+ using var reader = new StreamReader(stream);
+ return reader.ReadToEnd();
+ }
+
+ return null;
+ }
+ }
+}
\ No newline at end of file