feat: redesign IconButton.
This commit is contained in:
@@ -3,7 +3,16 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:converters="clr-namespace:Ursa.Themes.Semi.Converters"
|
xmlns:converters="clr-namespace:Ursa.Themes.Semi.Converters"
|
||||||
xmlns:u="https://irihi.tech/ursa">
|
xmlns:u="https://irihi.tech/ursa">
|
||||||
<!-- Add Resources Here -->
|
<Design.PreviewWith>
|
||||||
|
<StackPanel Margin="20">
|
||||||
|
<u:IconButton Icon="{StaticResource SemiIconGithubLogo}" />
|
||||||
|
<u:IconButton
|
||||||
|
Theme="{StaticResource SolidIconButton}"
|
||||||
|
Icon="{StaticResource SemiIconGithubLogo}"
|
||||||
|
Classes="Warning"
|
||||||
|
Content="GitHub" />
|
||||||
|
</StackPanel>
|
||||||
|
</Design.PreviewWith>
|
||||||
<converters:BooleansToOpacityConverter x:Key="OpacityConverter" />
|
<converters:BooleansToOpacityConverter x:Key="OpacityConverter" />
|
||||||
<ControlTheme x:Key="{x:Type u:IconButton}" TargetType="u:IconButton">
|
<ControlTheme x:Key="{x:Type u:IconButton}" TargetType="u:IconButton">
|
||||||
<Setter Property="Background" Value="{DynamicResource ButtonDefaultBackground}" />
|
<Setter Property="Background" Value="{DynamicResource ButtonDefaultBackground}" />
|
||||||
@@ -31,14 +40,13 @@
|
|||||||
TextElement.FontSize="{TemplateBinding FontSize}"
|
TextElement.FontSize="{TemplateBinding FontSize}"
|
||||||
TextElement.FontWeight="{TemplateBinding FontWeight}"
|
TextElement.FontWeight="{TemplateBinding FontWeight}"
|
||||||
UseLayoutRounding="False">
|
UseLayoutRounding="False">
|
||||||
<Grid
|
<ReversibleStackPanel
|
||||||
|
Name="{x:Static u:IconButton.PART_RootPanel}"
|
||||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||||
ColumnDefinitions="Auto, Auto"
|
Orientation="Horizontal"
|
||||||
RowDefinitions="Auto, Auto">
|
Spacing="{StaticResource IconButtonInnerSpacing}">
|
||||||
<Panel
|
<Panel Name="PART_IconRoot">
|
||||||
Name="PART_IconRoot"
|
|
||||||
Grid.Column="0">
|
|
||||||
<Panel.IsVisible>
|
<Panel.IsVisible>
|
||||||
<MultiBinding Converter="{x:Static BoolConverters.Or}">
|
<MultiBinding Converter="{x:Static BoolConverters.Or}">
|
||||||
<Binding Path="IsLoading" RelativeSource="{RelativeSource TemplatedParent}" />
|
<Binding Path="IsLoading" RelativeSource="{RelativeSource TemplatedParent}" />
|
||||||
@@ -51,7 +59,16 @@
|
|||||||
<ContentPresenter
|
<ContentPresenter
|
||||||
Content="{TemplateBinding Icon}"
|
Content="{TemplateBinding Icon}"
|
||||||
ContentTemplate="{TemplateBinding IconTemplate}"
|
ContentTemplate="{TemplateBinding IconTemplate}"
|
||||||
Opacity="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=!IsLoading, Converter={StaticResource OpacityConverter}}" />
|
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||||
|
Opacity="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=!IsLoading, Converter={StaticResource OpacityConverter}}">
|
||||||
|
<ContentPresenter.DataTemplates>
|
||||||
|
<DataTemplate DataType="Geometry">
|
||||||
|
<PathIcon
|
||||||
|
Theme="{StaticResource InnerPathIcon}"
|
||||||
|
Data="{Binding }" />
|
||||||
|
</DataTemplate>
|
||||||
|
</ContentPresenter.DataTemplates>
|
||||||
|
</ContentPresenter>
|
||||||
<u:LoadingIcon
|
<u:LoadingIcon
|
||||||
Classes="Small"
|
Classes="Small"
|
||||||
Foreground="{TemplateBinding Foreground}"
|
Foreground="{TemplateBinding Foreground}"
|
||||||
@@ -59,13 +76,11 @@
|
|||||||
</Panel>
|
</Panel>
|
||||||
<ContentPresenter
|
<ContentPresenter
|
||||||
Name="PART_ContentPresenter"
|
Name="PART_ContentPresenter"
|
||||||
Grid.Row="0" Grid.Column="1"
|
|
||||||
Margin="8 0 0 0"
|
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
IsVisible="{TemplateBinding Content, Converter={x:Static ObjectConverters.IsNotNull}}"
|
IsVisible="{TemplateBinding Content, Converter={x:Static ObjectConverters.IsNotNull}}"
|
||||||
Content="{TemplateBinding Content}" />
|
Content="{TemplateBinding Content}" />
|
||||||
</Grid>
|
</ReversibleStackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
</ControlTemplate>
|
</ControlTemplate>
|
||||||
</Setter>
|
</Setter>
|
||||||
@@ -108,66 +123,40 @@
|
|||||||
<Setter Property="Foreground" Value="{DynamicResource ButtonDefaultDisabledForeground}" />
|
<Setter Property="Foreground" Value="{DynamicResource ButtonDefaultDisabledForeground}" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style Selector="^:empty[IsLoading=False] /template/ ContentPresenter#PART_ContentPresenter">
|
<Style Selector="^:right /template/ ReversibleStackPanel#PART_RootPanel">
|
||||||
<Setter Property="Margin" Value="0" />
|
<Setter Property="Orientation" Value="Horizontal" />
|
||||||
|
<Setter Property="ReverseOrder" Value="True" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style Selector="^:right">
|
<Style Selector="^:left /template/ ReversibleStackPanel#PART_RootPanel">
|
||||||
<Style Selector="^ /template/ Panel#PART_IconRoot">
|
<Setter Property="Orientation" Value="Horizontal" />
|
||||||
<Setter Property="Grid.Column" Value="1" />
|
<Setter Property="ReverseOrder" Value="False" />
|
||||||
<Setter Property="Grid.Row" Value="0" />
|
|
||||||
</Style>
|
|
||||||
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
|
|
||||||
<Setter Property="Grid.Column" Value="0" />
|
|
||||||
<Setter Property="Grid.Row" Value="0" />
|
|
||||||
<Setter Property="Margin" Value="0 0 8 0" />
|
|
||||||
</Style>
|
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style Selector="^:left">
|
<Style Selector="^:top /template/ ReversibleStackPanel#PART_RootPanel">
|
||||||
<Style Selector="^ /template/ Panel#PART_IconRoot">
|
<Setter Property="Orientation" Value="Vertical" />
|
||||||
<Setter Property="Grid.Column" Value="0" />
|
<Setter Property="ReverseOrder" Value="False" />
|
||||||
<Setter Property="Grid.Row" Value="0" />
|
|
||||||
</Style>
|
|
||||||
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
|
|
||||||
<Setter Property="Grid.Column" Value="1" />
|
|
||||||
<Setter Property="Grid.Row" Value="0" />
|
|
||||||
<Setter Property="Margin" Value="8 0 0 0" />
|
|
||||||
</Style>
|
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style Selector="^:top">
|
<Style Selector="^:bottom /template/ ReversibleStackPanel#PART_RootPanel">
|
||||||
<Style Selector="^ /template/ Panel#PART_IconRoot">
|
<Setter Property="Orientation" Value="Vertical" />
|
||||||
<Setter Property="Grid.Column" Value="0" />
|
<Setter Property="ReverseOrder" Value="True" />
|
||||||
<Setter Property="Grid.Row" Value="0" />
|
|
||||||
</Style>
|
|
||||||
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
|
|
||||||
<Setter Property="Grid.Column" Value="0" />
|
|
||||||
<Setter Property="Grid.Row" Value="1" />
|
|
||||||
<Setter Property="Margin" Value="0 4 0 0" />
|
|
||||||
</Style>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style Selector="^:bottom">
|
|
||||||
<Style Selector="^ /template/ Panel#PART_IconRoot">
|
|
||||||
<Setter Property="Grid.Column" Value="0" />
|
|
||||||
<Setter Property="Grid.Row" Value="1" />
|
|
||||||
</Style>
|
|
||||||
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
|
|
||||||
<Setter Property="Grid.Column" Value="0" />
|
|
||||||
<Setter Property="Grid.Row" Value="0" />
|
|
||||||
<Setter Property="Margin" Value="0 0 0 4" />
|
|
||||||
</Style>
|
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style Selector="^.Large">
|
<Style Selector="^.Large">
|
||||||
<Setter Property="MinHeight" Value="{DynamicResource ButtonLargeHeight}" />
|
<Setter Property="MinHeight" Value="{DynamicResource ButtonLargeHeight}" />
|
||||||
<Setter Property="Padding" Value="{DynamicResource ButtonLargePadding}" />
|
<Setter Property="Padding" Value="{DynamicResource ButtonLargePadding}" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style Selector="^.Small">
|
<Style Selector="^.Small">
|
||||||
<Setter Property="MinHeight" Value="{DynamicResource ButtonSmallHeight}" />
|
<Setter Property="MinHeight" Value="{DynamicResource ButtonSmallHeight}" />
|
||||||
<Setter Property="Padding" Value="{DynamicResource ButtonSmallPadding}" />
|
<Setter Property="Padding" Value="{DynamicResource ButtonSmallPadding}" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="^:empty-content">
|
||||||
|
<Setter Property="MinWidth" Value="{Binding $self.MinHeight}" />
|
||||||
|
<Setter Property="Padding" Value="0" />
|
||||||
|
</Style>
|
||||||
</ControlTheme>
|
</ControlTheme>
|
||||||
|
|
||||||
<ControlTheme
|
<ControlTheme
|
||||||
@@ -284,7 +273,6 @@
|
|||||||
<Setter Property="Background" Value="{DynamicResource ButtonOutlineBackground}" />
|
<Setter Property="Background" Value="{DynamicResource ButtonOutlineBackground}" />
|
||||||
<Setter Property="Foreground" Value="{DynamicResource ButtonDefaultDisabledForeground}" />
|
<Setter Property="Foreground" Value="{DynamicResource ButtonDefaultDisabledForeground}" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
</ControlTheme>
|
</ControlTheme>
|
||||||
|
|
||||||
<ControlTheme
|
<ControlTheme
|
||||||
|
|||||||
3
src/Ursa.Themes.Semi/Themes/Shared/IconButton.axaml
Normal file
3
src/Ursa.Themes.Semi/Themes/Shared/IconButton.axaml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
<x:Double x:Key="IconButtonInnerSpacing">8</x:Double>
|
||||||
|
</ResourceDictionary>
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
<ResourceInclude Source="Divider.axaml" />
|
<ResourceInclude Source="Divider.axaml" />
|
||||||
<ResourceInclude Source="Drawer.axaml" />
|
<ResourceInclude Source="Drawer.axaml" />
|
||||||
<ResourceInclude Source="DualBadge.axaml" />
|
<ResourceInclude Source="DualBadge.axaml" />
|
||||||
|
<ResourceInclude Source="IconButton.axaml" />
|
||||||
<ResourceInclude Source="MessageBox.axaml" />
|
<ResourceInclude Source="MessageBox.axaml" />
|
||||||
<ResourceInclude Source="NavigationMenu.axaml" />
|
<ResourceInclude Source="NavigationMenu.axaml" />
|
||||||
<ResourceInclude Source="Notification.axaml" />
|
<ResourceInclude Source="Notification.axaml" />
|
||||||
|
|||||||
@@ -7,17 +7,22 @@ using Ursa.Common;
|
|||||||
|
|
||||||
namespace Ursa.Controls;
|
namespace Ursa.Controls;
|
||||||
|
|
||||||
[PseudoClasses(PC_Right, PC_Left, PC_Top, PC_Bottom, PC_Empty)]
|
[TemplatePart(PART_RootPanel, typeof(Panel))]
|
||||||
public class IconButton: Button
|
[PseudoClasses(PC_Right, PC_Left, PC_Top, PC_Bottom, PC_Empty, PC_EmptyContent)]
|
||||||
|
public class IconButton : Button
|
||||||
{
|
{
|
||||||
public const string PC_Right = ":right";
|
public const string PC_Right = ":right";
|
||||||
public const string PC_Left = ":left";
|
public const string PC_Left = ":left";
|
||||||
public const string PC_Top = ":top";
|
public const string PC_Top = ":top";
|
||||||
public const string PC_Bottom = ":bottom";
|
public const string PC_Bottom = ":bottom";
|
||||||
public const string PC_Empty = ":empty";
|
public const string PC_Empty = ":empty";
|
||||||
|
public const string PC_EmptyContent = ":empty-content";
|
||||||
|
public const string PART_RootPanel = "PART_RootPanel";
|
||||||
|
|
||||||
public static readonly StyledProperty<object?> IconProperty = AvaloniaProperty.Register<IconButton, object?>(
|
private Panel? _rootPanel;
|
||||||
nameof(Icon));
|
|
||||||
|
public static readonly StyledProperty<object?> IconProperty =
|
||||||
|
AvaloniaProperty.Register<IconButton, object?>(nameof(Icon));
|
||||||
|
|
||||||
public object? Icon
|
public object? Icon
|
||||||
{
|
{
|
||||||
@@ -25,8 +30,8 @@ public class IconButton: Button
|
|||||||
set => SetValue(IconProperty, value);
|
set => SetValue(IconProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static readonly StyledProperty<IDataTemplate?> IconTemplateProperty = AvaloniaProperty.Register<IconButton, IDataTemplate?>(
|
public static readonly StyledProperty<IDataTemplate?> IconTemplateProperty =
|
||||||
nameof(IconTemplate));
|
AvaloniaProperty.Register<IconButton, IDataTemplate?>(nameof(IconTemplate));
|
||||||
|
|
||||||
public IDataTemplate? IconTemplate
|
public IDataTemplate? IconTemplate
|
||||||
{
|
{
|
||||||
@@ -34,8 +39,8 @@ public class IconButton: Button
|
|||||||
set => SetValue(IconTemplateProperty, value);
|
set => SetValue(IconTemplateProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static readonly StyledProperty<bool> IsLoadingProperty = AvaloniaProperty.Register<IconButton, bool>(
|
public static readonly StyledProperty<bool> IsLoadingProperty =
|
||||||
nameof(IsLoading));
|
AvaloniaProperty.Register<IconButton, bool>(nameof(IsLoading));
|
||||||
|
|
||||||
public bool IsLoading
|
public bool IsLoading
|
||||||
{
|
{
|
||||||
@@ -43,8 +48,8 @@ public class IconButton: Button
|
|||||||
set => SetValue(IsLoadingProperty, value);
|
set => SetValue(IsLoadingProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static readonly StyledProperty<Position> IconPlacementProperty = AvaloniaProperty.Register<IconButton, Position>(
|
public static readonly StyledProperty<Position> IconPlacementProperty =
|
||||||
nameof(IconPlacement), defaultValue: Position.Left);
|
AvaloniaProperty.Register<IconButton, Position>(nameof(IconPlacement), defaultValue: Position.Left);
|
||||||
|
|
||||||
public Position IconPlacement
|
public Position IconPlacement
|
||||||
{
|
{
|
||||||
@@ -57,16 +62,27 @@ public class IconButton: Button
|
|||||||
IconPlacementProperty.Changed.AddClassHandler<IconButton, Position>((o, e) =>
|
IconPlacementProperty.Changed.AddClassHandler<IconButton, Position>((o, e) =>
|
||||||
{
|
{
|
||||||
o.SetPlacement(e.NewValue.Value, o.Icon);
|
o.SetPlacement(e.NewValue.Value, o.Icon);
|
||||||
|
o.InvalidateRootPanel();
|
||||||
});
|
});
|
||||||
IconProperty.Changed.AddClassHandler<IconButton, object?>((o, e) =>
|
IconProperty.Changed.AddClassHandler<IconButton, object?>((o, e) =>
|
||||||
{
|
{
|
||||||
o.SetPlacement(o.IconPlacement, e.NewValue.Value);
|
o.SetPlacement(o.IconPlacement, e.NewValue.Value);
|
||||||
});
|
});
|
||||||
|
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)
|
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||||
{
|
{
|
||||||
base.OnApplyTemplate(e);
|
base.OnApplyTemplate(e);
|
||||||
|
_rootPanel = e.NameScope.Find<Panel>(PART_RootPanel);
|
||||||
|
SetEmptyContent();
|
||||||
SetPlacement(IconPlacement, Icon);
|
SetPlacement(IconPlacement, Icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,6 +97,7 @@ public class IconButton: Button
|
|||||||
PseudoClasses.Set(PC_Bottom, false);
|
PseudoClasses.Set(PC_Bottom, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PseudoClasses.Set(PC_Empty, false);
|
PseudoClasses.Set(PC_Empty, false);
|
||||||
PseudoClasses.Set(PC_Left, placement == Position.Left);
|
PseudoClasses.Set(PC_Left, placement == Position.Left);
|
||||||
PseudoClasses.Set(PC_Right, placement == Position.Right);
|
PseudoClasses.Set(PC_Right, placement == Position.Right);
|
||||||
|
|||||||
Reference in New Issue
Block a user