mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-22 00:46:48 +08:00
341 lines
16 KiB
C#
341 lines
16 KiB
C#
using AtomUI.Controls.Utils;
|
|
using AtomUI.IconPkg;
|
|
using AtomUI.IconPkg.AntDesign;
|
|
using AtomUI.Media;
|
|
using AtomUI.Theme;
|
|
using AtomUI.Theme.Styling;
|
|
using Avalonia;
|
|
using Avalonia.Animation;
|
|
using Avalonia.Controls;
|
|
using Avalonia.Controls.Presenters;
|
|
using Avalonia.Controls.Primitives;
|
|
using Avalonia.Controls.Templates;
|
|
using Avalonia.Data;
|
|
using Avalonia.Data.Converters;
|
|
using Avalonia.Input;
|
|
using Avalonia.Layout;
|
|
using Avalonia.Styling;
|
|
|
|
namespace AtomUI.Controls;
|
|
|
|
internal abstract class BaseButtonTheme : BaseControlTheme
|
|
{
|
|
public const string FramePart = "PART_Frame";
|
|
public const string LabelPart = "PART_Label";
|
|
public const string MainInfoLayoutPart = "PART_MainInfoLayout";
|
|
public const string RootLayoutPart = "PART_RootLayout";
|
|
public const string LoadingIconPart = "PART_LoadingIcon";
|
|
public const string ButtonIconPart = "PART_ButtonIcon";
|
|
public const string RightExtraContentPart = "PART_RightExtraContent";
|
|
public const string RightExtraLayoutPart = "PART_RightExtraLayout";
|
|
|
|
public BaseButtonTheme(Type targetType) : base(targetType)
|
|
{
|
|
}
|
|
|
|
protected override IControlTemplate BuildControlTemplate()
|
|
{
|
|
return new FuncControlTemplate<Button>((button, scope) =>
|
|
{
|
|
var loadingIcon = AntDesignIconPackage.LoadingOutlined();
|
|
loadingIcon.Name = LoadingIconPart;
|
|
|
|
loadingIcon.RegisterInNameScope(scope);
|
|
|
|
CreateTemplateParentBinding(loadingIcon, Layoutable.WidthProperty, Button.IconSizeProperty);
|
|
CreateTemplateParentBinding(loadingIcon, Layoutable.HeightProperty, Button.IconSizeProperty);
|
|
CreateTemplateParentBinding(loadingIcon, Layoutable.MarginProperty, Button.IconMarginProperty);
|
|
CreateTemplateParentBinding(loadingIcon, Icon.NormalFilledBrushProperty, Button.IconNormalColorProperty);
|
|
CreateTemplateParentBinding(loadingIcon, Icon.ActiveFilledBrushProperty, Button.IconHoverColorProperty);
|
|
CreateTemplateParentBinding(loadingIcon, Icon.SelectedFilledBrushProperty, Button.IconPressedColorProperty);
|
|
CreateTemplateParentBinding(loadingIcon, Icon.DisabledFilledBrushProperty, Button.IconDisabledColorProperty);
|
|
|
|
var iconPresenter = new ContentPresenter
|
|
{
|
|
Name = ButtonIconPart
|
|
};
|
|
CreateTemplateParentBinding(iconPresenter, ContentPresenter.ContentProperty, Button.IconProperty);
|
|
|
|
var labelText = new SingleLineText
|
|
{
|
|
Name = LabelPart,
|
|
VerticalAlignment = VerticalAlignment.Center
|
|
};
|
|
|
|
CreateTemplateParentBinding(labelText, SingleLineText.SizeTypeProperty, Button.SizeTypeProperty);
|
|
CreateTemplateParentBinding(labelText, SingleLineText.TextProperty, Button.TextProperty);
|
|
labelText.RegisterInNameScope(scope);
|
|
|
|
var mainInfoLayout = new StackPanel
|
|
{
|
|
Name = MainInfoLayoutPart,
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
HorizontalAlignment = HorizontalAlignment.Center,
|
|
Orientation = Orientation.Horizontal
|
|
};
|
|
|
|
mainInfoLayout.RegisterInNameScope(scope);
|
|
mainInfoLayout.Children.Add(loadingIcon);
|
|
mainInfoLayout.Children.Add(iconPresenter);
|
|
mainInfoLayout.Children.Add(labelText);
|
|
|
|
var extraContentLayout = new StackPanel()
|
|
{
|
|
Name = RightExtraLayoutPart,
|
|
Orientation = Orientation.Horizontal,
|
|
};
|
|
CreateTemplateParentBinding(extraContentLayout, StackPanel.IsVisibleProperty, Button.ExtraContainerVisibleProperty);
|
|
BuildExtraContainer(extraContentLayout, scope);
|
|
DockPanel.SetDock(extraContentLayout, Dock.Right);
|
|
|
|
var rootLayout = new DockPanel
|
|
{
|
|
Name = RootLayoutPart,
|
|
LastChildFill = true
|
|
};
|
|
|
|
rootLayout.Children.Add(extraContentLayout);
|
|
rootLayout.Children.Add(mainInfoLayout);
|
|
|
|
var frame = new Border()
|
|
{
|
|
Name = FramePart
|
|
};
|
|
|
|
CreateTemplateParentBinding(frame, Decorator.PaddingProperty, TemplatedControl.PaddingProperty);
|
|
CreateTemplateParentBinding(frame, Border.BorderThicknessProperty,
|
|
Button.EffectiveBorderThicknessProperty);
|
|
CreateTemplateParentBinding(frame, Border.BorderBrushProperty,
|
|
TemplatedControl.BorderBrushProperty);
|
|
CreateTemplateParentBinding(frame, Border.BackgroundSizingProperty,
|
|
TemplatedControl.BackgroundSizingProperty);
|
|
CreateTemplateParentBinding(frame, Border.CornerRadiusProperty,
|
|
TemplatedControl.CornerRadiusProperty);
|
|
|
|
frame.Child = rootLayout;
|
|
|
|
return frame;
|
|
});
|
|
}
|
|
|
|
protected virtual void BuildExtraContainer(StackPanel containerLayout, INameScope scope)
|
|
{
|
|
var extraContentPresenter = new ContentPresenter
|
|
{
|
|
Name = RightExtraContentPart,
|
|
HorizontalContentAlignment = HorizontalAlignment.Center,
|
|
VerticalContentAlignment = VerticalAlignment.Center,
|
|
HorizontalAlignment = HorizontalAlignment.Center,
|
|
VerticalAlignment = VerticalAlignment.Center
|
|
};
|
|
|
|
CreateTemplateParentBinding(extraContentPresenter, Visual.IsVisibleProperty,
|
|
Button.RightExtraContentProperty,
|
|
BindingMode.Default,
|
|
ObjectConverters.IsNotNull);
|
|
CreateTemplateParentBinding(extraContentPresenter, ContentPresenter.ContentProperty,
|
|
Button.RightExtraContentProperty);
|
|
|
|
containerLayout.Children.Add(extraContentPresenter);
|
|
}
|
|
|
|
protected override void BuildStyles()
|
|
{
|
|
this.Add(Layoutable.HorizontalAlignmentProperty, HorizontalAlignment.Left);
|
|
this.Add(Layoutable.VerticalAlignmentProperty, VerticalAlignment.Top);
|
|
this.Add(InputElement.CursorProperty, new SetterValueFactory<Cursor>(() => new Cursor(StandardCursorType.Hand)));
|
|
this.Add(Button.DefaultShadowProperty, ButtonTokenKey.DefaultShadow);
|
|
this.Add(Button.PrimaryShadowProperty, ButtonTokenKey.PrimaryShadow);
|
|
this.Add(Button.DangerShadowProperty, ButtonTokenKey.DangerShadow);
|
|
|
|
var extraLayoutStyle = new Style(selector => selector.Nesting().Template().Name(RightExtraLayoutPart));
|
|
extraLayoutStyle.Add(StackPanel.SpacingProperty, ButtonTokenKey.ExtraContentItemSpacing);
|
|
Add(extraLayoutStyle);
|
|
|
|
BuildSizeStyle();
|
|
BuildIconStyle();
|
|
BuildLoadingStyle();
|
|
|
|
// 动画设置
|
|
var isMotionEnabledStyle = new Style(selector => selector.Nesting().PropertyEquals(Button.IsMotionEnabledProperty, true));
|
|
var frameStyle = new Style(selector => selector.Nesting().Template().Name(FramePart));
|
|
frameStyle.Add(IconButton.TransitionsProperty, new SetterValueFactory<Transitions>(() => new Transitions()
|
|
{
|
|
AnimationUtils.CreateTransition<SolidColorBrushTransition>(TemplatedControl.BackgroundProperty)
|
|
}));
|
|
isMotionEnabledStyle.Add(frameStyle);
|
|
Add(isMotionEnabledStyle);
|
|
}
|
|
|
|
private void BuildSizeStyle()
|
|
{
|
|
var largeSizeStyle = new Style(selector =>
|
|
selector.Nesting().PropertyEquals(Button.SizeTypeProperty, SizeType.Large));
|
|
largeSizeStyle.Add(Button.ControlHeightTokenProperty, SharedTokenKey.ControlHeightLG);
|
|
largeSizeStyle.Add(TemplatedControl.FontSizeProperty, ButtonTokenKey.ContentFontSizeLG);
|
|
{
|
|
var notCircleTypeStyle = new Style(selector => selector.Nesting().Not(nest =>
|
|
nest.Nesting().PropertyEquals(Button.ButtonShapeProperty, ButtonShape.Circle)));
|
|
notCircleTypeStyle.Add(TemplatedControl.PaddingProperty, ButtonTokenKey.PaddingLG);
|
|
largeSizeStyle.Add(notCircleTypeStyle);
|
|
}
|
|
largeSizeStyle.Add(TemplatedControl.CornerRadiusProperty, SharedTokenKey.BorderRadiusLG);
|
|
{
|
|
var iconOnlyStyle = new Style(selector => selector.Nesting().Class(Button.IconOnlyPC));
|
|
iconOnlyStyle.Add(TemplatedControl.PaddingProperty, ButtonTokenKey.IconOnyPaddingLG);
|
|
largeSizeStyle.Add(iconOnlyStyle);
|
|
}
|
|
{
|
|
var extraContentStyle = new Style(selector => selector.Nesting().Template().Name(RightExtraLayoutPart));
|
|
extraContentStyle.Add(Layoutable.MarginProperty, ButtonTokenKey.ExtraContentMarginLG);
|
|
largeSizeStyle.Add(extraContentStyle);
|
|
}
|
|
Add(largeSizeStyle);
|
|
|
|
var middleSizeStyle = new Style(selector =>
|
|
selector.Nesting().PropertyEquals(Button.SizeTypeProperty, SizeType.Middle));
|
|
middleSizeStyle.Add(Button.ControlHeightTokenProperty, SharedTokenKey.ControlHeight);
|
|
middleSizeStyle.Add(TemplatedControl.FontSizeProperty, ButtonTokenKey.ContentFontSize);
|
|
middleSizeStyle.Add(TemplatedControl.CornerRadiusProperty, SharedTokenKey.BorderRadius);
|
|
{
|
|
var notCircleTypeStyle = new Style(selector => selector.Nesting().Not(nest =>
|
|
nest.Nesting().PropertyEquals(Button.ButtonShapeProperty, ButtonShape.Circle)));
|
|
notCircleTypeStyle.Add(TemplatedControl.PaddingProperty, ButtonTokenKey.Padding);
|
|
middleSizeStyle.Add(notCircleTypeStyle);
|
|
}
|
|
{
|
|
var iconOnlyStyle = new Style(selector => selector.Nesting().Class(Button.IconOnlyPC));
|
|
iconOnlyStyle.Add(TemplatedControl.PaddingProperty, ButtonTokenKey.IconOnyPadding);
|
|
middleSizeStyle.Add(iconOnlyStyle);
|
|
}
|
|
{
|
|
var extraContentStyle = new Style(selector => selector.Nesting().Template().Name(RightExtraLayoutPart));
|
|
extraContentStyle.Add(Layoutable.MarginProperty, ButtonTokenKey.ExtraContentMargin);
|
|
middleSizeStyle.Add(extraContentStyle);
|
|
}
|
|
Add(middleSizeStyle);
|
|
|
|
var smallSizeStyle = new Style(selector =>
|
|
selector.Nesting().PropertyEquals(Button.SizeTypeProperty, SizeType.Small));
|
|
smallSizeStyle.Add(Button.ControlHeightTokenProperty, SharedTokenKey.ControlHeightSM);
|
|
smallSizeStyle.Add(TemplatedControl.FontSizeProperty, ButtonTokenKey.ContentFontSizeSM);
|
|
smallSizeStyle.Add(TemplatedControl.CornerRadiusProperty, SharedTokenKey.BorderRadiusSM);
|
|
{
|
|
var notCircleTypeStyle = new Style(selector => selector.Nesting().Not(nest =>
|
|
nest.Nesting().PropertyEquals(Button.ButtonShapeProperty, ButtonShape.Circle)));
|
|
notCircleTypeStyle.Add(TemplatedControl.PaddingProperty, ButtonTokenKey.PaddingSM);
|
|
smallSizeStyle.Add(notCircleTypeStyle);
|
|
}
|
|
{
|
|
var iconOnlyStyle = new Style(selector => selector.Nesting().Class(Button.IconOnlyPC));
|
|
iconOnlyStyle.Add(TemplatedControl.PaddingProperty, ButtonTokenKey.IconOnyPaddingSM);
|
|
smallSizeStyle.Add(iconOnlyStyle);
|
|
}
|
|
{
|
|
var extraContentStyle = new Style(selector => selector.Nesting().Template().Name(RightExtraLayoutPart));
|
|
extraContentStyle.Add(Layoutable.MarginProperty, ButtonTokenKey.ExtraContentMarginSM);
|
|
smallSizeStyle.Add(extraContentStyle);
|
|
}
|
|
Add(smallSizeStyle);
|
|
}
|
|
|
|
private void BuildIconStyle()
|
|
{
|
|
{
|
|
var iconStyle = new Style(selector => selector.Nesting().Template().Name(ButtonIconPart).Descendant().OfType<Icon>());
|
|
iconStyle.Add(Icon.IconModeProperty, IconMode.Normal);
|
|
Add(iconStyle);
|
|
}
|
|
var hoverStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.PointerOver));
|
|
{
|
|
var iconStyle = new Style(selector => selector.Nesting().Template().Name(ButtonIconPart).Descendant().OfType<Icon>());
|
|
iconStyle.Add(Icon.IconModeProperty, IconMode.Active);
|
|
hoverStyle.Add(iconStyle);
|
|
}
|
|
Add(hoverStyle);
|
|
var pressedStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.Pressed));
|
|
{
|
|
var iconStyle = new Style(selector => selector.Nesting().Template().Name(ButtonIconPart).Descendant().OfType<Icon>());
|
|
iconStyle.Add(Icon.IconModeProperty, IconMode.Selected);
|
|
pressedStyle.Add(iconStyle);
|
|
}
|
|
Add(pressedStyle);
|
|
var disabledStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.Disabled));
|
|
{
|
|
var iconStyle = new Style(selector => selector.Nesting().Template().Name(ButtonIconPart).Descendant().OfType<Icon>());
|
|
iconStyle.Add(Icon.IconModeProperty, IconMode.Disabled);
|
|
disabledStyle.Add(iconStyle);
|
|
}
|
|
Add(disabledStyle);
|
|
// text 和 icon 都存在的情况
|
|
{
|
|
var largeSizeStyle = new Style(selector =>
|
|
selector.Nesting().PropertyEquals(Button.SizeTypeProperty, SizeType.Large));
|
|
largeSizeStyle.Add(Button.IconSizeProperty, SharedTokenKey.IconSizeLG);
|
|
Add(largeSizeStyle);
|
|
|
|
var middleSizeStyle = new Style(selector =>
|
|
selector.Nesting().PropertyEquals(Button.SizeTypeProperty, SizeType.Middle));
|
|
middleSizeStyle.Add(Button.IconSizeProperty, SharedTokenKey.IconSize);
|
|
Add(middleSizeStyle);
|
|
|
|
var smallSizeStyle = new Style(selector =>
|
|
selector.Nesting().PropertyEquals(Button.SizeTypeProperty, SizeType.Small));
|
|
smallSizeStyle.Add(Button.IconSizeProperty, SharedTokenKey.IconSizeSM);
|
|
Add(smallSizeStyle);
|
|
}
|
|
|
|
// icon only
|
|
var iconOnlyStyle = new Style(selector => selector.Nesting().Class(Button.IconOnlyPC));
|
|
iconOnlyStyle.Add(Button.IconMarginProperty, new Thickness());
|
|
{
|
|
var largeSizeStyle = new Style(selector =>
|
|
selector.Nesting().PropertyEquals(Button.SizeTypeProperty, SizeType.Large));
|
|
largeSizeStyle.Add(Button.IconSizeProperty, ButtonTokenKey.OnlyIconSizeLG);
|
|
iconOnlyStyle.Add(largeSizeStyle);
|
|
|
|
var middleSizeStyle = new Style(selector =>
|
|
selector.Nesting().PropertyEquals(Button.SizeTypeProperty, SizeType.Middle));
|
|
middleSizeStyle.Add(Button.IconSizeProperty, ButtonTokenKey.OnlyIconSize);
|
|
iconOnlyStyle.Add(middleSizeStyle);
|
|
|
|
var smallSizeStyle = new Style(selector =>
|
|
selector.Nesting().PropertyEquals(Button.SizeTypeProperty, SizeType.Small));
|
|
smallSizeStyle.Add(Button.IconSizeProperty, ButtonTokenKey.OnlyIconSizeSM);
|
|
iconOnlyStyle.Add(smallSizeStyle);
|
|
}
|
|
Add(iconOnlyStyle);
|
|
|
|
var notIconOnyStyle = new Style(selector => selector.Nesting().Not(x => x.Nesting().Class(Button.IconOnlyPC)));
|
|
notIconOnyStyle.Add(Button.IconMarginProperty, ButtonTokenKey.IconMargin);
|
|
Add(notIconOnyStyle);
|
|
}
|
|
|
|
private void BuildLoadingStyle()
|
|
{
|
|
// 正常状态
|
|
{
|
|
var buttonIconStyle = new Style(selector => selector.Nesting().Template().Name(ButtonIconPart));
|
|
buttonIconStyle.Add(Visual.IsVisibleProperty, true);
|
|
Add(buttonIconStyle);
|
|
|
|
var loadingIconStyle = new Style(selector => selector.Nesting().Template().Name(LoadingIconPart));
|
|
loadingIconStyle.Add(Visual.IsVisibleProperty, false);
|
|
Add(loadingIconStyle);
|
|
}
|
|
// loading 状态
|
|
var loadingStyle = new Style(selector => selector.Nesting().Class(Button.LoadingPC));
|
|
{
|
|
var buttonIconStyle = new Style(selector => selector.Nesting().Template().Name(ButtonIconPart));
|
|
buttonIconStyle.Add(Visual.IsVisibleProperty, false);
|
|
loadingStyle.Add(buttonIconStyle);
|
|
|
|
var loadingIconStyle = new Style(selector => selector.Nesting().Template().Name(LoadingIconPart));
|
|
loadingIconStyle.Add(Visual.IsVisibleProperty, true);
|
|
loadingIconStyle.Add(Icon.LoadingAnimationProperty, IconAnimation.Spin);
|
|
loadingStyle.Add(loadingIconStyle);
|
|
}
|
|
loadingStyle.Add(Visual.OpacityProperty, SharedTokenKey.OpacityLoading);
|
|
Add(loadingStyle);
|
|
}
|
|
} |