Added IconRepeatButton, IconDropDownButton, IconSplitButton, IconToggleButton, IconToggleSplitButton (#834)
* Added IconRepeatButton (#812) * Replaced control-specific PART_RootPanel workaround with AffectsArrange call fixing ReversibleStackPanel for the whole application. * Added IconToggleButton (#812) * Split IconRepeatButton into separate XAML file. * Added IconSplitButton (#812) * Added BindableClasses utility to allow propagating Classes property between controls. Avalonia currently doesn't support binding from Classes property, and binding to Classes property is heavily restricted. * Added IconToggleSplitButton (#812) * Fixed tab order in IconSplitButton and IconToggleSplitButton (DockPanel messes up tab order, TabIndex is global and makes it even worse, so just switched to Grid). * Added IconDropDownButton (#812) * Fixed IconPlacement inheritance. * Added redesigned IconButton demo section (#812) * Fixed spacing issues * Added redesigned demo sections for the newly added icon buttons (#812) * Replaced BindableClasses with ClassHelper. Fixed styling of default solid split icon buttons. (#812) * Replaced IIconButton with attached-like property getters and PseudolassesExtensions.Set(Classes); fixed arrow alignments in top/bottom split icon buttons (#812) * Applied fixes suggested by Copilot in code review (#812) * Fixed incorrect base type of IconDropDownButton (#812) * Fixed IconSplitButton and IconToggleSplitButton styles (#812) * Fixed secondary button color in checked state * Fixed applying of CornerRadius * Changed secondary button to square * Simplified template * Disabled demo of Colorful theme for IconSplitButton and IconToggleSplitButton
This commit is contained in:
committed by
GitHub
parent
a4906d5130
commit
6f7db1c20c
@@ -19,11 +19,12 @@ public class IconButton : Button
|
||||
public const string PC_EmptyContent = ":empty-content";
|
||||
public const string PART_RootPanel = "PART_RootPanel";
|
||||
|
||||
private Panel? _rootPanel;
|
||||
|
||||
public static readonly StyledProperty<object?> IconProperty =
|
||||
AvaloniaProperty.Register<IconButton, object?>(nameof(Icon));
|
||||
|
||||
public static object? GetIcon(ContentControl o) => o.GetValue(IconProperty);
|
||||
public static void SetIcon(ContentControl o, object? value) => o.SetValue(IconProperty, value);
|
||||
|
||||
public object? Icon
|
||||
{
|
||||
get => GetValue(IconProperty);
|
||||
@@ -33,6 +34,9 @@ public class IconButton : Button
|
||||
public static readonly StyledProperty<IDataTemplate?> IconTemplateProperty =
|
||||
AvaloniaProperty.Register<IconButton, IDataTemplate?>(nameof(IconTemplate));
|
||||
|
||||
public static IDataTemplate? GetIconTemplate(ContentControl o) => o.GetValue(IconTemplateProperty);
|
||||
public static void SetIconTemplate(ContentControl o, IDataTemplate? value) => o.SetValue(IconTemplateProperty, value);
|
||||
|
||||
public IDataTemplate? IconTemplate
|
||||
{
|
||||
get => GetValue(IconTemplateProperty);
|
||||
@@ -42,6 +46,9 @@ public class IconButton : Button
|
||||
public static readonly StyledProperty<bool> IsLoadingProperty =
|
||||
AvaloniaProperty.Register<IconButton, bool>(nameof(IsLoading));
|
||||
|
||||
public static bool GetIsLoading(ContentControl o) => o.GetValue(IsLoadingProperty);
|
||||
public static void SetIsLoading(ContentControl o, bool value) => o.SetValue(IsLoadingProperty, value);
|
||||
|
||||
public bool IsLoading
|
||||
{
|
||||
get => GetValue(IsLoadingProperty);
|
||||
@@ -51,6 +58,9 @@ public class IconButton : Button
|
||||
public static readonly StyledProperty<Position> IconPlacementProperty =
|
||||
AvaloniaProperty.Register<IconButton, Position>(nameof(IconPlacement), defaultValue: Position.Left);
|
||||
|
||||
public static Position GetIconPlacement(ContentControl o) => o.GetValue(IconPlacementProperty);
|
||||
public static void SetIconPlacement(ContentControl o, Position value) => o.SetValue(IconPlacementProperty, value);
|
||||
|
||||
public Position IconPlacement
|
||||
{
|
||||
get => GetValue(IconPlacementProperty);
|
||||
@@ -59,49 +69,48 @@ public class IconButton : Button
|
||||
|
||||
static IconButton()
|
||||
{
|
||||
IconPlacementProperty.Changed.AddClassHandler<IconButton, Position>((o, e) =>
|
||||
ReversibleStackPanelUtils.EnsureBugFixed();
|
||||
IconPlacementProperty.Changed.AddClassHandler<ContentControl, Position>((o, e) =>
|
||||
{
|
||||
o.SetPlacement(e.NewValue.Value, o.Icon);
|
||||
o.InvalidateRootPanel();
|
||||
UpdateIconPseudoClasses(o, e.NewValue.Value, GetIcon(o));
|
||||
});
|
||||
IconProperty.Changed.AddClassHandler<IconButton, object?>((o, e) =>
|
||||
IconProperty.Changed.AddClassHandler<ContentControl, object?>((o, e) =>
|
||||
{
|
||||
o.SetPlacement(o.IconPlacement, e.NewValue.Value);
|
||||
UpdateIconPseudoClasses(o, GetIconPlacement(o), e.NewValue.Value);
|
||||
});
|
||||
ContentProperty.Changed.AddClassHandler<ContentControl, object?>((o, _) =>
|
||||
{
|
||||
UpdateEmptyContentPseudoClass(o);
|
||||
});
|
||||
ContentProperty.Changed.AddClassHandler<IconButton>((o, e) => o.SetEmptyContent());
|
||||
}
|
||||
|
||||
private void InvalidateRootPanel() => _rootPanel?.InvalidateArrange();
|
||||
|
||||
private void SetEmptyContent()
|
||||
{
|
||||
PseudoClasses.Set(PC_EmptyContent, Presenter?.Content is null);
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
base.OnApplyTemplate(e);
|
||||
_rootPanel = e.NameScope.Find<Panel>(PART_RootPanel);
|
||||
SetEmptyContent();
|
||||
SetPlacement(IconPlacement, Icon);
|
||||
UpdateEmptyContentPseudoClass(this);
|
||||
UpdateIconPseudoClasses(this, IconPlacement, Icon);
|
||||
}
|
||||
|
||||
private void SetPlacement(Position placement, object? icon)
|
||||
internal static void UpdatePseudoClasses(ContentControl button)
|
||||
{
|
||||
if (icon is null)
|
||||
{
|
||||
PseudoClasses.Set(PC_Empty, true);
|
||||
PseudoClasses.Set(PC_Left, false);
|
||||
PseudoClasses.Set(PC_Right, false);
|
||||
PseudoClasses.Set(PC_Top, false);
|
||||
PseudoClasses.Set(PC_Bottom, false);
|
||||
return;
|
||||
}
|
||||
UpdateEmptyContentPseudoClass(button);
|
||||
UpdateIconPseudoClasses(button, GetIconPlacement(button), GetIcon(button));
|
||||
}
|
||||
|
||||
PseudoClasses.Set(PC_Empty, false);
|
||||
PseudoClasses.Set(PC_Left, placement == Position.Left);
|
||||
PseudoClasses.Set(PC_Right, placement == Position.Right);
|
||||
PseudoClasses.Set(PC_Top, placement == Position.Top);
|
||||
PseudoClasses.Set(PC_Bottom, placement == Position.Bottom);
|
||||
private static void UpdateEmptyContentPseudoClass(ContentControl button)
|
||||
{
|
||||
IPseudoClasses pseudo = button.Classes;
|
||||
pseudo.Set(PC_EmptyContent, button.Content is null);
|
||||
}
|
||||
|
||||
private static void UpdateIconPseudoClasses(ContentControl button, Position placement, object? icon)
|
||||
{
|
||||
IPseudoClasses pseudo = button.Classes;
|
||||
var hasIcon = icon is not null;
|
||||
pseudo.Set(PC_Empty, !hasIcon);
|
||||
pseudo.Set(PC_Left, hasIcon && placement == Position.Left);
|
||||
pseudo.Set(PC_Right, hasIcon && placement == Position.Right);
|
||||
pseudo.Set(PC_Top, hasIcon && placement == Position.Top);
|
||||
pseudo.Set(PC_Bottom, hasIcon && placement == Position.Bottom);
|
||||
}
|
||||
}
|
||||
57
src/Ursa/Controls/Buttons/IconDropDownButton.cs
Normal file
57
src/Ursa/Controls/Buttons/IconDropDownButton.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Ursa.Common;
|
||||
|
||||
namespace Ursa.Controls;
|
||||
|
||||
public class IconDropDownButton : DropDownButton
|
||||
{
|
||||
public static readonly StyledProperty<object?> IconProperty =
|
||||
IconButton.IconProperty.AddOwner<IconDropDownButton>();
|
||||
|
||||
public object? Icon
|
||||
{
|
||||
get => GetValue(IconProperty);
|
||||
set => SetValue(IconProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IDataTemplate?> IconTemplateProperty =
|
||||
IconButton.IconTemplateProperty.AddOwner<IconDropDownButton>();
|
||||
|
||||
public IDataTemplate? IconTemplate
|
||||
{
|
||||
get => GetValue(IconTemplateProperty);
|
||||
set => SetValue(IconTemplateProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<bool> IsLoadingProperty =
|
||||
IconButton.IsLoadingProperty.AddOwner<IconDropDownButton>();
|
||||
|
||||
public bool IsLoading
|
||||
{
|
||||
get => GetValue(IsLoadingProperty);
|
||||
set => SetValue(IsLoadingProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<Position> IconPlacementProperty =
|
||||
IconButton.IconPlacementProperty.AddOwner<IconDropDownButton>();
|
||||
|
||||
public Position IconPlacement
|
||||
{
|
||||
get => GetValue(IconPlacementProperty);
|
||||
set => SetValue(IconPlacementProperty, value);
|
||||
}
|
||||
|
||||
static IconDropDownButton()
|
||||
{
|
||||
ReversibleStackPanelUtils.EnsureBugFixed();
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
base.OnApplyTemplate(e);
|
||||
IconButton.UpdatePseudoClasses(this);
|
||||
}
|
||||
}
|
||||
57
src/Ursa/Controls/Buttons/IconRepeatButton.cs
Normal file
57
src/Ursa/Controls/Buttons/IconRepeatButton.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Ursa.Common;
|
||||
|
||||
namespace Ursa.Controls;
|
||||
|
||||
public class IconRepeatButton : RepeatButton
|
||||
{
|
||||
public static readonly StyledProperty<object?> IconProperty =
|
||||
IconButton.IconProperty.AddOwner<IconRepeatButton>();
|
||||
|
||||
public object? Icon
|
||||
{
|
||||
get => GetValue(IconProperty);
|
||||
set => SetValue(IconProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IDataTemplate?> IconTemplateProperty =
|
||||
IconButton.IconTemplateProperty.AddOwner<IconRepeatButton>();
|
||||
|
||||
public IDataTemplate? IconTemplate
|
||||
{
|
||||
get => GetValue(IconTemplateProperty);
|
||||
set => SetValue(IconTemplateProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<bool> IsLoadingProperty =
|
||||
IconButton.IsLoadingProperty.AddOwner<IconRepeatButton>();
|
||||
|
||||
public bool IsLoading
|
||||
{
|
||||
get => GetValue(IsLoadingProperty);
|
||||
set => SetValue(IsLoadingProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<Position> IconPlacementProperty =
|
||||
IconButton.IconPlacementProperty.AddOwner<IconRepeatButton>();
|
||||
|
||||
public Position IconPlacement
|
||||
{
|
||||
get => GetValue(IconPlacementProperty);
|
||||
set => SetValue(IconPlacementProperty, value);
|
||||
}
|
||||
|
||||
static IconRepeatButton()
|
||||
{
|
||||
ReversibleStackPanelUtils.EnsureBugFixed();
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
base.OnApplyTemplate(e);
|
||||
IconButton.UpdatePseudoClasses(this);
|
||||
}
|
||||
}
|
||||
57
src/Ursa/Controls/Buttons/IconSplitButton.cs
Normal file
57
src/Ursa/Controls/Buttons/IconSplitButton.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Ursa.Common;
|
||||
|
||||
namespace Ursa.Controls;
|
||||
|
||||
public class IconSplitButton : SplitButton
|
||||
{
|
||||
public static readonly StyledProperty<object?> IconProperty =
|
||||
IconButton.IconProperty.AddOwner<IconSplitButton>();
|
||||
|
||||
public object? Icon
|
||||
{
|
||||
get => GetValue(IconProperty);
|
||||
set => SetValue(IconProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IDataTemplate?> IconTemplateProperty =
|
||||
IconButton.IconTemplateProperty.AddOwner<IconSplitButton>();
|
||||
|
||||
public IDataTemplate? IconTemplate
|
||||
{
|
||||
get => GetValue(IconTemplateProperty);
|
||||
set => SetValue(IconTemplateProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<bool> IsLoadingProperty =
|
||||
IconButton.IsLoadingProperty.AddOwner<IconSplitButton>();
|
||||
|
||||
public bool IsLoading
|
||||
{
|
||||
get => GetValue(IsLoadingProperty);
|
||||
set => SetValue(IsLoadingProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<Position> IconPlacementProperty =
|
||||
IconButton.IconPlacementProperty.AddOwner<IconSplitButton>();
|
||||
|
||||
public Position IconPlacement
|
||||
{
|
||||
get => GetValue(IconPlacementProperty);
|
||||
set => SetValue(IconPlacementProperty, value);
|
||||
}
|
||||
|
||||
static IconSplitButton()
|
||||
{
|
||||
ReversibleStackPanelUtils.EnsureBugFixed();
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
base.OnApplyTemplate(e);
|
||||
IconButton.UpdatePseudoClasses(this);
|
||||
}
|
||||
}
|
||||
56
src/Ursa/Controls/Buttons/IconToggleButton.cs
Normal file
56
src/Ursa/Controls/Buttons/IconToggleButton.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Ursa.Common;
|
||||
|
||||
namespace Ursa.Controls;
|
||||
|
||||
public class IconToggleButton : ToggleButton
|
||||
{
|
||||
public static readonly StyledProperty<object?> IconProperty =
|
||||
IconButton.IconProperty.AddOwner<IconToggleButton>();
|
||||
|
||||
public object? Icon
|
||||
{
|
||||
get => GetValue(IconProperty);
|
||||
set => SetValue(IconProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IDataTemplate?> IconTemplateProperty =
|
||||
IconButton.IconTemplateProperty.AddOwner<IconToggleButton>();
|
||||
|
||||
public IDataTemplate? IconTemplate
|
||||
{
|
||||
get => GetValue(IconTemplateProperty);
|
||||
set => SetValue(IconTemplateProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<bool> IsLoadingProperty =
|
||||
IconButton.IsLoadingProperty.AddOwner<IconToggleButton>();
|
||||
|
||||
public bool IsLoading
|
||||
{
|
||||
get => GetValue(IsLoadingProperty);
|
||||
set => SetValue(IsLoadingProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<Position> IconPlacementProperty =
|
||||
IconButton.IconPlacementProperty.AddOwner<IconToggleButton>();
|
||||
|
||||
public Position IconPlacement
|
||||
{
|
||||
get => GetValue(IconPlacementProperty);
|
||||
set => SetValue(IconPlacementProperty, value);
|
||||
}
|
||||
|
||||
static IconToggleButton()
|
||||
{
|
||||
ReversibleStackPanelUtils.EnsureBugFixed();
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
base.OnApplyTemplate(e);
|
||||
IconButton.UpdatePseudoClasses(this);
|
||||
}
|
||||
}
|
||||
59
src/Ursa/Controls/Buttons/IconToggleSplitButton.cs
Normal file
59
src/Ursa/Controls/Buttons/IconToggleSplitButton.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Ursa.Common;
|
||||
|
||||
namespace Ursa.Controls;
|
||||
|
||||
public class IconToggleSplitButton : ToggleSplitButton
|
||||
{
|
||||
public static readonly StyledProperty<object?> IconProperty =
|
||||
IconButton.IconProperty.AddOwner<IconToggleSplitButton>();
|
||||
|
||||
public object? Icon
|
||||
{
|
||||
get => GetValue(IconProperty);
|
||||
set => SetValue(IconProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IDataTemplate?> IconTemplateProperty =
|
||||
IconButton.IconTemplateProperty.AddOwner<IconToggleSplitButton>();
|
||||
|
||||
public IDataTemplate? IconTemplate
|
||||
{
|
||||
get => GetValue(IconTemplateProperty);
|
||||
set => SetValue(IconTemplateProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<bool> IsLoadingProperty =
|
||||
IconButton.IsLoadingProperty.AddOwner<IconToggleSplitButton>();
|
||||
|
||||
public bool IsLoading
|
||||
{
|
||||
get => GetValue(IsLoadingProperty);
|
||||
set => SetValue(IsLoadingProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<Position> IconPlacementProperty =
|
||||
IconButton.IconPlacementProperty.AddOwner<IconToggleSplitButton>();
|
||||
|
||||
public Position IconPlacement
|
||||
{
|
||||
get => GetValue(IconPlacementProperty);
|
||||
set => SetValue(IconPlacementProperty, value);
|
||||
}
|
||||
|
||||
static IconToggleSplitButton()
|
||||
{
|
||||
ReversibleStackPanelUtils.EnsureBugFixed();
|
||||
}
|
||||
|
||||
protected override Type StyleKeyOverride => GetType();
|
||||
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
base.OnApplyTemplate(e);
|
||||
IconButton.UpdatePseudoClasses(this);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user