mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-22 17:35:30 +08:00
Refactor Segmented themes
This commit is contained in:
@@ -31,6 +31,7 @@
|
||||
<ResourceInclude Source="ProgressBar/Themes/ProgressBarThemes.axaml" />
|
||||
<ResourceInclude Source="RadioButton/Themes/RadioButtonTheme.axaml" />
|
||||
<ResourceInclude Source="ScrollBar/Themes/ScrollBarThemes.axaml" />
|
||||
<ResourceInclude Source="Segmented/Themes/SegmentedThemes.axaml" />
|
||||
<ResourceInclude Source="PopupConfirm/Themes/PopupConfirmContainerTheme.axaml" />
|
||||
<ResourceInclude Source="Tag/Themes/TagTheme.axaml" />
|
||||
<ResourceInclude Source="NumericUpDown/Themes/NumericUpDownTheme.axaml" />
|
||||
|
||||
@@ -192,7 +192,7 @@
|
||||
</Style>
|
||||
</Style>
|
||||
|
||||
<Style Selector="^:not(^:icononly)">
|
||||
<Style Selector="^:not(:icononly)">
|
||||
<Style Selector="^ /template/ atom|IconPresenter#PART_ButtonIcon, ^ /template/ atom|Icon#PART_LoadingIcon">
|
||||
<Setter Property="Margin" Value="{DynamicResource {x:Static atom:ButtonTokenKey.IconMargin}}" />
|
||||
</Style>
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorPrimary}}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="^:selected:not(^:inactive)">
|
||||
<Style Selector="^:selected:not(:inactive)">
|
||||
<Setter Property="Background" Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorPrimary}}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorWhite}}" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
<Setter Property="SpinnerHandleWidthToken" Value="{DynamicResource {x:Static atom:ButtonSpinnerTokenKey.HandleWidth}}"/>
|
||||
|
||||
<Style Selector="^[IsEnabled=True]">
|
||||
<Style Selector="^:not(^:filled)">
|
||||
<Style Selector="^:not(:filled)">
|
||||
<Style Selector="^ /template/ Border#PART_InnerBoxDecorator">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
</Style>
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorPrimary}}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="^:selected:not(^:inactive)">
|
||||
<Style Selector="^:selected:not(:inactive)">
|
||||
<Setter Property="Background" Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorPrimary}}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorWhite}}" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorPrimary}}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="^:selected:not(^:inactive)">
|
||||
<Style Selector="^:selected:not(:inactive)">
|
||||
<Setter Property="Background" Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorPrimary}}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorWhite}}" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
|
||||
-2
@@ -15,8 +15,6 @@ namespace AtomUI.Theme
|
||||
themes.Add(new AtomUI.Controls.CardTabStripItemTheme());
|
||||
themes.Add(new AtomUI.Controls.CardTabStripTheme());
|
||||
themes.Add(new AtomUI.Controls.HyperLinkTextBlockTheme());
|
||||
themes.Add(new AtomUI.Controls.SegmentedItemTheme());
|
||||
themes.Add(new AtomUI.Controls.SegmentedTheme());
|
||||
themes.Add(new AtomUI.Controls.SeparatorTheme());
|
||||
themes.Add(new AtomUI.Controls.SliderTheme());
|
||||
themes.Add(new AtomUI.Controls.SliderThumbTheme());
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
using System.Reactive.Disposables;
|
||||
using AtomUI.Controls.Themes;
|
||||
using AtomUI.Controls.Utils;
|
||||
using AtomUI.Data;
|
||||
using AtomUI.Theme;
|
||||
using AtomUI.Theme.Styling;
|
||||
using AtomUI.Theme.Utils;
|
||||
using Avalonia;
|
||||
using Avalonia.Animation;
|
||||
@@ -11,13 +10,12 @@ using Avalonia.Controls.Metadata;
|
||||
using Avalonia.Controls.Presenters;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.LogicalTree;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.VisualTree;
|
||||
|
||||
namespace AtomUI.Controls;
|
||||
|
||||
[TemplatePart(SegmentedTheme.ItemsPresenterPart, typeof(ItemsPresenter))]
|
||||
[TemplatePart(SegmentedThemeConstants.ItemsPresenterPart, typeof(ItemsPresenter))]
|
||||
public class Segmented : SelectingItemsControl,
|
||||
IMotionAwareControl,
|
||||
IControlSharedTokenResourcesHost
|
||||
@@ -112,9 +110,12 @@ public class Segmented : SelectingItemsControl,
|
||||
static Segmented()
|
||||
{
|
||||
AffectsMeasure<Segmented>(IsExpandingProperty, SizeTypeProperty);
|
||||
AffectsRender<Segmented>(SelectedThumbCornerRadiusProperty, SelectedThumbBgProperty,
|
||||
AffectsRender<Segmented>(
|
||||
SelectedThumbCornerRadiusProperty,
|
||||
SelectedThumbBgProperty,
|
||||
SelectedThumbBoxShadowsProperty,
|
||||
SelectedThumbSizeProperty, SelectedThumbPosProperty);
|
||||
SelectedThumbSizeProperty,
|
||||
SelectedThumbPosProperty);
|
||||
}
|
||||
|
||||
public Segmented()
|
||||
@@ -151,9 +152,18 @@ public class Segmented : SelectingItemsControl,
|
||||
|
||||
SetupSelectedThumbRect();
|
||||
}
|
||||
|
||||
|
||||
private void HandleSelectionChanged(object? sender, SelectionChangedEventArgs args)
|
||||
{
|
||||
if (this.IsAttachedToVisualTree())
|
||||
{
|
||||
SetupSelectedThumbRect();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnSizeChanged(SizeChangedEventArgs e)
|
||||
{
|
||||
base.OnSizeChanged(e);
|
||||
SetupSelectedThumbRect();
|
||||
}
|
||||
|
||||
@@ -194,18 +204,6 @@ public class Segmented : SelectingItemsControl,
|
||||
}
|
||||
}
|
||||
|
||||
protected override Size ArrangeOverride(Size finalSize)
|
||||
{
|
||||
base.ArrangeOverride(finalSize);
|
||||
if (Transitions is null)
|
||||
{
|
||||
SetupSelectedThumbRect();
|
||||
ConfigureTransitions();
|
||||
}
|
||||
|
||||
return finalSize;
|
||||
}
|
||||
|
||||
private void ConfigureTransitions()
|
||||
{
|
||||
if (IsMotionEnabled)
|
||||
@@ -213,8 +211,7 @@ public class Segmented : SelectingItemsControl,
|
||||
Transitions = new Transitions
|
||||
{
|
||||
TransitionUtils.CreateTransition<PointTransition>(SelectedThumbPosProperty),
|
||||
TransitionUtils.CreateTransition<SizeTransition>(SelectedThumbSizeProperty,
|
||||
SharedTokenKey.MotionDurationFast)
|
||||
TransitionUtils.CreateTransition<SizeTransition>(SelectedThumbSizeProperty)
|
||||
};
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
using System.Diagnostics;
|
||||
using System.Reactive.Disposables;
|
||||
using AtomUI.Animations;
|
||||
using AtomUI.Controls.Utils;
|
||||
using AtomUI.IconPkg;
|
||||
using AtomUI.Reflection;
|
||||
using AtomUI.Theme;
|
||||
using Avalonia;
|
||||
using Avalonia.Animation;
|
||||
using Avalonia.Controls;
|
||||
@@ -17,10 +14,8 @@ using Avalonia.VisualTree;
|
||||
|
||||
namespace AtomUI.Controls;
|
||||
|
||||
[PseudoClasses(StdPseudoClass.Pressed, StdPseudoClass.Selected)]
|
||||
public class SegmentedItem : ContentControl,
|
||||
ISelectable,
|
||||
IResourceBindingManager
|
||||
[PseudoClasses(StdPseudoClass.Pressed, StdPseudoClass.Selected, SegmentedPseudoClass.HasIcon)]
|
||||
public class SegmentedItem : ContentControl, ISelectable
|
||||
{
|
||||
#region 公共属性定义
|
||||
|
||||
@@ -64,11 +59,7 @@ public class SegmentedItem : ContentControl,
|
||||
set => SetValue(IsMotionEnabledProperty, value);
|
||||
}
|
||||
|
||||
CompositeDisposable? IResourceBindingManager.ResourceBindingsDisposable => _resourceBindingsDisposable;
|
||||
|
||||
#endregion
|
||||
|
||||
private CompositeDisposable? _resourceBindingsDisposable;
|
||||
|
||||
static SegmentedItem()
|
||||
{
|
||||
@@ -81,16 +72,9 @@ public class SegmentedItem : ContentControl,
|
||||
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
|
||||
{
|
||||
base.OnAttachedToLogicalTree(e);
|
||||
_resourceBindingsDisposable = new CompositeDisposable();
|
||||
Debug.Assert(Parent is Segmented, "SegmentedItem's Parent must be Segmented Control.");
|
||||
}
|
||||
|
||||
protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e)
|
||||
{
|
||||
base.OnDetachedFromLogicalTree(e);
|
||||
this.DisposeTokenBindings();
|
||||
}
|
||||
|
||||
protected override void OnPointerReleased(PointerReleasedEventArgs e)
|
||||
{
|
||||
base.OnPointerReleased(e);
|
||||
@@ -114,12 +98,18 @@ public class SegmentedItem : ContentControl,
|
||||
{
|
||||
base.OnApplyTemplate(e);
|
||||
ConfigureTransitions();
|
||||
UpdatePseudoClasses();
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
||||
{
|
||||
base.OnPropertyChanged(change);
|
||||
|
||||
if (change.Property == IconProperty)
|
||||
{
|
||||
UpdatePseudoClasses();
|
||||
}
|
||||
|
||||
if (this.IsAttachedToVisualTree())
|
||||
{
|
||||
if (change.Property == IsMotionEnabledProperty)
|
||||
@@ -127,19 +117,6 @@ public class SegmentedItem : ContentControl,
|
||||
ConfigureTransitions();
|
||||
}
|
||||
}
|
||||
|
||||
if (change.Property == IconProperty)
|
||||
{
|
||||
if (change.OldValue is Icon oldIcon)
|
||||
{
|
||||
oldIcon.SetTemplatedParent(null);
|
||||
}
|
||||
|
||||
if (change.NewValue is Icon newIcon)
|
||||
{
|
||||
newIcon.SetTemplatedParent(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ConfigureTransitions()
|
||||
@@ -156,4 +133,9 @@ public class SegmentedItem : ContentControl,
|
||||
Transitions = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePseudoClasses()
|
||||
{
|
||||
PseudoClasses.Set(SegmentedPseudoClass.HasIcon, Icon is not null);
|
||||
}
|
||||
}
|
||||
@@ -1,246 +0,0 @@
|
||||
using AtomUI.IconPkg;
|
||||
using AtomUI.Theme;
|
||||
using AtomUI.Theme.Styling;
|
||||
using AtomUI.Utils;
|
||||
using Avalonia;
|
||||
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;
|
||||
|
||||
[ControlThemeProvider]
|
||||
internal class SegmentedItemTheme : BaseControlTheme
|
||||
{
|
||||
public const string MainFramePart = "PART_MainFrame";
|
||||
public const string IconContentPart = "PART_IconContent";
|
||||
public const string ContentPart = "PART_Content";
|
||||
|
||||
public SegmentedItemTheme() : base(typeof(SegmentedItem))
|
||||
{
|
||||
}
|
||||
|
||||
protected override IControlTemplate BuildControlTemplate()
|
||||
{
|
||||
return new FuncControlTemplate<SegmentedItem>((segmentedItem, scope) =>
|
||||
{
|
||||
var mainFrame = new Border
|
||||
{
|
||||
Name = MainFramePart
|
||||
};
|
||||
CreateTemplateParentBinding(mainFrame, Border.BackgroundProperty, TemplatedControl.BackgroundProperty);
|
||||
CreateTemplateParentBinding(mainFrame, Border.CornerRadiusProperty, TemplatedControl.CornerRadiusProperty);
|
||||
CreateTemplateParentBinding(mainFrame, Decorator.PaddingProperty, TemplatedControl.PaddingProperty);
|
||||
|
||||
var contentLayout = new DockPanel
|
||||
{
|
||||
LastChildFill = true
|
||||
};
|
||||
|
||||
var iconContent = new ContentPresenter
|
||||
{
|
||||
Name = IconContentPart
|
||||
};
|
||||
iconContent.RegisterInNameScope(scope);
|
||||
CreateTemplateParentBinding(iconContent, ContentPresenter.ContentProperty, SegmentedItem.IconProperty);
|
||||
CreateTemplateParentBinding(iconContent, Visual.IsVisibleProperty, SegmentedItem.IconProperty,
|
||||
BindingMode.Default,
|
||||
ObjectConverters.IsNotNull);
|
||||
|
||||
contentLayout.Children.Add(iconContent);
|
||||
|
||||
var contentPresenter = new ContentPresenter
|
||||
{
|
||||
Name = ContentPart,
|
||||
HorizontalContentAlignment = HorizontalAlignment.Center,
|
||||
VerticalContentAlignment = VerticalAlignment.Center
|
||||
};
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.ContentProperty,
|
||||
ContentControl.ContentProperty,
|
||||
BindingMode.Default,
|
||||
new FuncValueConverter<object?, object?>(content =>
|
||||
{
|
||||
if (content is string text)
|
||||
{
|
||||
return new TextBlock()
|
||||
{
|
||||
Text = text,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
};
|
||||
}
|
||||
return content;
|
||||
}));
|
||||
CreateTemplateParentBinding(contentPresenter, Visual.IsVisibleProperty, ContentControl.ContentProperty,
|
||||
BindingMode.Default,
|
||||
ObjectConverters.IsNotNull);
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.ContentTemplateProperty,
|
||||
ContentControl.ContentTemplateProperty);
|
||||
contentLayout.Children.Add(contentPresenter);
|
||||
|
||||
mainFrame.Child = contentLayout;
|
||||
|
||||
return mainFrame;
|
||||
});
|
||||
}
|
||||
|
||||
protected override void BuildStyles()
|
||||
{
|
||||
var commonStyle = new Style(selector => selector.Nesting());
|
||||
|
||||
// 没有被选择的正常状态
|
||||
var enabledStyle =
|
||||
new Style(selector => selector.Nesting().PropertyEquals(InputElement.IsEnabledProperty, true));
|
||||
enabledStyle.Add(InputElement.CursorProperty, new SetterValueFactory<Cursor>(() => new Cursor(StandardCursorType.Hand)));
|
||||
|
||||
{
|
||||
var iconStyle = new Style(selector => selector.Nesting().Template().Name(IconContentPart).Child().OfType<Icon>());
|
||||
iconStyle.Add(Icon.IconModeProperty, IconMode.Normal);
|
||||
Add(iconStyle);
|
||||
}
|
||||
|
||||
// 选中状态
|
||||
var selectedStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.Selected));
|
||||
selectedStyle.Add(TemplatedControl.ForegroundProperty, SegmentedTokenKey.ItemSelectedColor);
|
||||
selectedStyle.Add(TemplatedControl.BackgroundProperty, SegmentedTokenKey.ItemSelectedBg);
|
||||
{
|
||||
var iconStyle = new Style(selector => selector.Nesting().Template().Name(IconContentPart).Child().OfType<Icon>());
|
||||
iconStyle.Add(Icon.IconModeProperty, IconMode.Selected);
|
||||
selectedStyle.Add(iconStyle);
|
||||
}
|
||||
enabledStyle.Add(selectedStyle);
|
||||
|
||||
// 没有被选中的状态
|
||||
var notSelectedStyle =
|
||||
new Style(selector => selector.Nesting().Not(x => x.Nesting().Class(StdPseudoClass.Selected)));
|
||||
notSelectedStyle.Add(TemplatedControl.BackgroundProperty, SharedTokenKey.ColorTransparent);
|
||||
notSelectedStyle.Add(TemplatedControl.ForegroundProperty, SegmentedTokenKey.ItemColor);
|
||||
|
||||
// Hover 状态
|
||||
var hoverStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.PointerOver));
|
||||
hoverStyle.Add(TemplatedControl.BackgroundProperty, SegmentedTokenKey.ItemHoverBg);
|
||||
hoverStyle.Add(TemplatedControl.ForegroundProperty, SegmentedTokenKey.ItemHoverColor);
|
||||
{
|
||||
var iconStyle = new Style(selector => selector.Nesting().Template().Name(IconContentPart).Child().OfType<Icon>());
|
||||
iconStyle.Add(Icon.IconModeProperty, IconMode.Active);
|
||||
hoverStyle.Add(iconStyle);
|
||||
}
|
||||
notSelectedStyle.Add(hoverStyle);
|
||||
|
||||
// Pressed 状态
|
||||
var pressedStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.Pressed));
|
||||
pressedStyle.Add(TemplatedControl.BackgroundProperty, SegmentedTokenKey.ItemActiveBg);
|
||||
notSelectedStyle.Add(pressedStyle);
|
||||
{
|
||||
var iconStyle = new Style(selector => selector.Nesting().Template().Name(IconContentPart).Child().OfType<Icon>());
|
||||
iconStyle.Add(Icon.IconModeProperty, IconMode.Selected);
|
||||
pressedStyle.Add(iconStyle);
|
||||
}
|
||||
|
||||
enabledStyle.Add(notSelectedStyle);
|
||||
commonStyle.Add(enabledStyle);
|
||||
Add(commonStyle);
|
||||
|
||||
BuildSizeTypeStyle();
|
||||
BuildIconStyle();
|
||||
BuildDisabledStyle();
|
||||
}
|
||||
|
||||
private void BuildSizeTypeStyle()
|
||||
{
|
||||
var largeSizeStyle =
|
||||
new Style(selector => selector.Nesting().PropertyEquals(SegmentedItem.SizeTypeProperty, SizeType.Large));
|
||||
largeSizeStyle.Add(TemplatedControl.CornerRadiusProperty, SharedTokenKey.BorderRadius);
|
||||
largeSizeStyle.Add(TemplatedControl.FontSizeProperty, SharedTokenKey.FontSizeLG);
|
||||
largeSizeStyle.Add(Layoutable.MinHeightProperty, SegmentedTokenKey.ItemMinHeightLG);
|
||||
largeSizeStyle.Add(TemplatedControl.PaddingProperty, SegmentedTokenKey.SegmentedItemPadding);
|
||||
Add(largeSizeStyle);
|
||||
|
||||
var middleSizeStyle =
|
||||
new Style(selector => selector.Nesting().PropertyEquals(SegmentedItem.SizeTypeProperty, SizeType.Middle));
|
||||
middleSizeStyle.Add(TemplatedControl.CornerRadiusProperty, SharedTokenKey.BorderRadiusSM);
|
||||
middleSizeStyle.Add(TemplatedControl.FontSizeProperty, SharedTokenKey.FontSize);
|
||||
middleSizeStyle.Add(Layoutable.MinHeightProperty, SegmentedTokenKey.ItemMinHeight);
|
||||
middleSizeStyle.Add(TemplatedControl.PaddingProperty, SegmentedTokenKey.SegmentedItemPadding);
|
||||
Add(middleSizeStyle);
|
||||
|
||||
var smallSizeStyle =
|
||||
new Style(selector => selector.Nesting().PropertyEquals(SegmentedItem.SizeTypeProperty, SizeType.Small));
|
||||
smallSizeStyle.Add(TemplatedControl.CornerRadiusProperty, SharedTokenKey.BorderRadiusXS);
|
||||
smallSizeStyle.Add(TemplatedControl.FontSizeProperty, SharedTokenKey.FontSize);
|
||||
smallSizeStyle.Add(Layoutable.MinHeightProperty, SegmentedTokenKey.ItemMinHeightSM);
|
||||
smallSizeStyle.Add(TemplatedControl.PaddingProperty, SegmentedTokenKey.SegmentedItemPaddingSM);
|
||||
|
||||
Add(smallSizeStyle);
|
||||
}
|
||||
|
||||
private void BuildIconStyle()
|
||||
{
|
||||
var hasIconStyle =
|
||||
new Style(selector => selector.Nesting()
|
||||
.Not(x => x.Nesting().PropertyEquals(SegmentedItem.IconProperty, null)));
|
||||
{
|
||||
var labelStyle = new Style(selector => selector.Nesting().Template().Name(ContentPart));
|
||||
labelStyle.Add(Layoutable.MarginProperty, SegmentedTokenKey.SegmentedItemContentMargin);
|
||||
hasIconStyle.Add(labelStyle);
|
||||
}
|
||||
|
||||
Add(hasIconStyle);
|
||||
|
||||
{
|
||||
var iconStyle = new Style(selector => selector.Nesting().Template().Name(IconContentPart).Child().OfType<Icon>());
|
||||
iconStyle.Add(Icon.NormalFilledBrushProperty, SegmentedTokenKey.ItemColor);
|
||||
iconStyle.Add(Icon.ActiveFilledBrushProperty, SegmentedTokenKey.ItemHoverColor);
|
||||
iconStyle.Add(Icon.SelectedFilledBrushProperty, SegmentedTokenKey.ItemSelectedColor);
|
||||
iconStyle.Add(Icon.DisabledFilledBrushProperty, SharedTokenKey.ColorTextDisabled);
|
||||
Add(iconStyle);
|
||||
}
|
||||
|
||||
var largeSizeStyle =
|
||||
new Style(selector => selector.Nesting().PropertyEquals(SegmentedItem.SizeTypeProperty, SizeType.Large));
|
||||
{
|
||||
var iconStyle = new Style(selector => selector.Nesting().Template().Name(IconContentPart).Child().OfType<Icon>());
|
||||
iconStyle.Add(Layoutable.WidthProperty, SharedTokenKey.IconSizeLG);
|
||||
iconStyle.Add(Layoutable.HeightProperty, SharedTokenKey.IconSizeLG);
|
||||
largeSizeStyle.Add(iconStyle);
|
||||
}
|
||||
Add(largeSizeStyle);
|
||||
|
||||
var middleSizeStyle =
|
||||
new Style(selector => selector.Nesting().PropertyEquals(SegmentedItem.SizeTypeProperty, SizeType.Middle));
|
||||
{
|
||||
var iconStyle = new Style(selector => selector.Nesting().Template().Name(IconContentPart).Child().OfType<Icon>());
|
||||
iconStyle.Add(Layoutable.WidthProperty, SharedTokenKey.IconSize);
|
||||
iconStyle.Add(Layoutable.HeightProperty, SharedTokenKey.IconSize);
|
||||
middleSizeStyle.Add(iconStyle);
|
||||
}
|
||||
Add(middleSizeStyle);
|
||||
|
||||
var smallSizeStyle =
|
||||
new Style(selector => selector.Nesting().PropertyEquals(SegmentedItem.SizeTypeProperty, SizeType.Small));
|
||||
{
|
||||
var iconStyle = new Style(selector => selector.Nesting().Template().Name(IconContentPart).Child().OfType<Icon>());
|
||||
iconStyle.Add(Layoutable.WidthProperty, SharedTokenKey.IconSizeSM);
|
||||
iconStyle.Add(Layoutable.HeightProperty, SharedTokenKey.IconSizeSM);
|
||||
smallSizeStyle.Add(iconStyle);
|
||||
}
|
||||
Add(smallSizeStyle);
|
||||
}
|
||||
|
||||
private void BuildDisabledStyle()
|
||||
{
|
||||
var disabledStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.Disabled));
|
||||
disabledStyle.Add(TemplatedControl.ForegroundProperty, SharedTokenKey.ColorTextDisabled);
|
||||
{
|
||||
var iconStyle = new Style(selector => selector.Nesting().Template().Name(IconContentPart).Child().OfType<Icon>());
|
||||
iconStyle.Add(Icon.IconModeProperty, IconMode.Disabled);
|
||||
disabledStyle.Add(iconStyle);
|
||||
}
|
||||
Add(disabledStyle);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace AtomUI.Controls;
|
||||
|
||||
public static class SegmentedPseudoClass
|
||||
{
|
||||
public const string HasIcon = ":has-icon";
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
using AtomUI.Data;
|
||||
using AtomUI.Theme;
|
||||
using AtomUI.Theme.Styling;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Presenters;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Styling;
|
||||
|
||||
namespace AtomUI.Controls;
|
||||
|
||||
[ControlThemeProvider]
|
||||
internal class SegmentedTheme : BaseControlTheme
|
||||
{
|
||||
public const string FramePart = "PART_Frame";
|
||||
public const string ItemsPresenterPart = "PART_ItemsPresenter";
|
||||
|
||||
public SegmentedTheme() : base(typeof(Segmented))
|
||||
{
|
||||
}
|
||||
|
||||
protected override IControlTemplate BuildControlTemplate()
|
||||
{
|
||||
return new FuncControlTemplate<Segmented>((segmented, scope) =>
|
||||
{
|
||||
var frame = new Border
|
||||
{
|
||||
Name = FramePart,
|
||||
ClipToBounds = true
|
||||
};
|
||||
var itemsPresenter = new ItemsPresenter
|
||||
{
|
||||
Name = ItemsPresenterPart,
|
||||
ItemsPanel = new FuncTemplate<Panel?>(() =>
|
||||
{
|
||||
var panel = new SegmentedStackPanel();
|
||||
BindUtils.RelayBind(segmented, Segmented.IsExpandingProperty, panel,
|
||||
SegmentedStackPanel.IsExpandingProperty);
|
||||
return panel;
|
||||
})
|
||||
};
|
||||
itemsPresenter.RegisterInNameScope(scope);
|
||||
frame.Child = itemsPresenter;
|
||||
|
||||
CreateTemplateParentBinding(frame, Border.CornerRadiusProperty,
|
||||
TemplatedControl.CornerRadiusProperty);
|
||||
CreateTemplateParentBinding(frame, Decorator.PaddingProperty, TemplatedControl.PaddingProperty);
|
||||
return frame;
|
||||
});
|
||||
}
|
||||
|
||||
protected override void BuildStyles()
|
||||
{
|
||||
var commonStyle = new Style(selector => selector.Nesting());
|
||||
commonStyle.Add(TemplatedControl.PaddingProperty, SegmentedTokenKey.TrackPadding);
|
||||
commonStyle.Add(TemplatedControl.BackgroundProperty, SegmentedTokenKey.TrackBg);
|
||||
commonStyle.Add(Layoutable.HorizontalAlignmentProperty, HorizontalAlignment.Left);
|
||||
commonStyle.Add(Segmented.SelectedThumbBgProperty, SegmentedTokenKey.ItemSelectedBg);
|
||||
commonStyle.Add(Segmented.SelectedThumbBoxShadowsProperty, SharedTokenKey.BoxShadowsTertiary);
|
||||
var expandingStyle =
|
||||
new Style(selector => selector.Nesting().PropertyEquals(Segmented.IsExpandingProperty, true));
|
||||
expandingStyle.Add(Layoutable.HorizontalAlignmentProperty, HorizontalAlignment.Stretch);
|
||||
commonStyle.Add(expandingStyle);
|
||||
Add(commonStyle);
|
||||
|
||||
BuildSizeTypeStyle();
|
||||
}
|
||||
|
||||
private void BuildSizeTypeStyle()
|
||||
{
|
||||
var largeSizeTypeStyle = new Style(selector =>
|
||||
selector.Nesting().PropertyEquals(Segmented.SizeTypeProperty, SizeType.Large));
|
||||
largeSizeTypeStyle.Add(TemplatedControl.CornerRadiusProperty, SharedTokenKey.BorderRadiusLG);
|
||||
largeSizeTypeStyle.Add(Segmented.SelectedThumbCornerRadiusProperty, SharedTokenKey.BorderRadius);
|
||||
Add(largeSizeTypeStyle);
|
||||
|
||||
var middleSizeTypeStyle = new Style(selector =>
|
||||
selector.Nesting().PropertyEquals(Segmented.SizeTypeProperty, SizeType.Middle));
|
||||
middleSizeTypeStyle.Add(TemplatedControl.CornerRadiusProperty, SharedTokenKey.BorderRadius);
|
||||
middleSizeTypeStyle.Add(Segmented.SelectedThumbCornerRadiusProperty, SharedTokenKey.BorderRadiusSM);
|
||||
Add(middleSizeTypeStyle);
|
||||
|
||||
var smallSizeTypeStyle = new Style(selector =>
|
||||
selector.Nesting().PropertyEquals(Segmented.SizeTypeProperty, SizeType.Small));
|
||||
smallSizeTypeStyle.Add(TemplatedControl.CornerRadiusProperty, SharedTokenKey.BorderRadiusSM);
|
||||
smallSizeTypeStyle.Add(Segmented.SelectedThumbCornerRadiusProperty, SharedTokenKey.BorderRadiusXS);
|
||||
Add(smallSizeTypeStyle);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
<ResourceDictionary
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:atom="https://atomui.net">
|
||||
<atom:StringToTextBlockConverter x:Key="StringToTextBlockConverter" VerticalAlignment="Center" />
|
||||
<ControlTheme x:Key="{x:Type atom:SegmentedItem}" TargetType="atom:SegmentedItem">
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate>
|
||||
<Border Name="{x:Static atom:SegmentedItemThemeConstants.MainFramePart}"
|
||||
Background="{TemplateBinding Background}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}"
|
||||
Padding="{TemplateBinding Padding}">
|
||||
<DockPanel LastChildFill="True">
|
||||
<atom:IconPresenter Name="{x:Static atom:SegmentedItemThemeConstants.IconPresenterPart}"
|
||||
Icon="{TemplateBinding Icon}"
|
||||
IsVisible="{TemplateBinding Icon, Converter={x:Static ObjectConverters.IsNotNull}}" />
|
||||
<ContentPresenter Name="{x:Static atom:SegmentedItemThemeConstants.ContentPart}"
|
||||
HorizontalContentAlignment="Center"
|
||||
VerticalContentAlignment="Center"
|
||||
Content="{TemplateBinding Content, Converter={StaticResource StringToTextBlockConverter}}"
|
||||
IsVisible="{TemplateBinding Content, Converter={x:Static ObjectConverters.IsNotNull}}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}" />
|
||||
</DockPanel>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
|
||||
<Style Selector="^[IsEnabled=True]">
|
||||
<Setter Property="Cursor" Value="Hand" />
|
||||
<Style Selector="^ /template/ atom|IconPresenter#PART_IconPresenter">
|
||||
<Setter Property="IconMode" Value="Normal" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="^:selected">
|
||||
<Setter Property="Foreground"
|
||||
Value="{DynamicResource {x:Static atom:SegmentedTokenKey.ItemSelectedColor}}" />
|
||||
<Setter Property="Background"
|
||||
Value="{DynamicResource {x:Static atom:SegmentedTokenKey.ItemSelectedBg}}" />
|
||||
|
||||
<Style Selector="^ /template/ atom|IconPresenter#PART_IconPresenter">
|
||||
<Setter Property="IconMode" Value="Selected" />
|
||||
</Style>
|
||||
</Style>
|
||||
|
||||
<Style Selector="^:not(^:selected)">
|
||||
<Setter Property="Foreground" Value="{DynamicResource {x:Static atom:SegmentedTokenKey.ItemColor}}" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
|
||||
<Style Selector="^:pointerover">
|
||||
<Setter Property="Foreground"
|
||||
Value="{DynamicResource {x:Static atom:SegmentedTokenKey.ItemHoverColor}}" />
|
||||
<Setter Property="Background"
|
||||
Value="{DynamicResource {x:Static atom:SegmentedTokenKey.ItemHoverBg}}" />
|
||||
<Style Selector="^ /template/ atom|IconPresenter#PART_IconPresenter">
|
||||
<Setter Property="IconMode" Value="Active" />
|
||||
</Style>
|
||||
</Style>
|
||||
|
||||
<Style Selector="^:pressed">
|
||||
<Setter Property="Background"
|
||||
Value="{DynamicResource {x:Static atom:SegmentedTokenKey.ItemActiveBg}}" />
|
||||
<Style Selector="^ /template/ atom|IconPresenter#PART_IconPresenter">
|
||||
<Setter Property="IconMode" Value="Selected" />
|
||||
</Style>
|
||||
</Style>
|
||||
</Style>
|
||||
</Style>
|
||||
|
||||
<Style Selector="^[SizeType=Large]">
|
||||
<Setter Property="CornerRadius"
|
||||
Value="{DynamicResource {x:Static atom:SharedTokenKey.BorderRadius}}" />
|
||||
<Setter Property="FontSize"
|
||||
Value="{DynamicResource {x:Static atom:SharedTokenKey.FontSizeLG}}" />
|
||||
<Setter Property="MinHeight"
|
||||
Value="{DynamicResource {x:Static atom:SegmentedTokenKey.ItemMinHeightLG}}" />
|
||||
<Setter Property="Padding"
|
||||
Value="{DynamicResource {x:Static atom:SegmentedTokenKey.SegmentedItemPadding}}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="^[SizeType=Middle]">
|
||||
<Setter Property="CornerRadius"
|
||||
Value="{DynamicResource {x:Static atom:SharedTokenKey.BorderRadiusSM}}" />
|
||||
<Setter Property="FontSize"
|
||||
Value="{DynamicResource {x:Static atom:SharedTokenKey.FontSize}}" />
|
||||
<Setter Property="MinHeight"
|
||||
Value="{DynamicResource {x:Static atom:SegmentedTokenKey.ItemMinHeight}}" />
|
||||
<Setter Property="Padding"
|
||||
Value="{DynamicResource {x:Static atom:SegmentedTokenKey.SegmentedItemPadding}}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="^[SizeType=Small]">
|
||||
<Setter Property="CornerRadius"
|
||||
Value="{DynamicResource {x:Static atom:SharedTokenKey.BorderRadiusXS}}" />
|
||||
<Setter Property="FontSize"
|
||||
Value="{DynamicResource {x:Static atom:SharedTokenKey.FontSize}}" />
|
||||
<Setter Property="MinHeight"
|
||||
Value="{DynamicResource {x:Static atom:SegmentedTokenKey.ItemMinHeightSM}}" />
|
||||
<Setter Property="Padding"
|
||||
Value="{DynamicResource {x:Static atom:SegmentedTokenKey.SegmentedItemPaddingSM}}" />
|
||||
</Style>
|
||||
|
||||
<!-- BuildIconStyle begin -->
|
||||
<Style Selector="^:has-icon">
|
||||
<Style Selector="^ /template/ ContentPresenter#PART_Content">
|
||||
<Setter Property="Margin"
|
||||
Value="{DynamicResource {x:Static atom:SegmentedTokenKey.SegmentedItemContentMargin}}" />
|
||||
</Style>
|
||||
</Style>
|
||||
|
||||
<Style Selector="^ /template/ atom|IconPresenter#PART_IconPresenter">
|
||||
<Setter Property="NormalFilledBrush"
|
||||
Value="{DynamicResource {x:Static atom:SegmentedTokenKey.ItemColor}}" />
|
||||
<Setter Property="ActiveFilledBrush"
|
||||
Value="{DynamicResource {x:Static atom:SegmentedTokenKey.ItemHoverColor}}" />
|
||||
<Setter Property="SelectedFilledBrush"
|
||||
Value="{DynamicResource {x:Static atom:SegmentedTokenKey.ItemSelectedColor}}" />
|
||||
<Setter Property="DisabledFilledBrush"
|
||||
Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorTextDisabled}}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="^[SizeType=Large]">
|
||||
<Style Selector="^ /template/ atom|IconPresenter#PART_IconPresenter">
|
||||
<Setter Property="IconWidth"
|
||||
Value="{DynamicResource {x:Static atom:SharedTokenKey.IconSizeLG}}" />
|
||||
<Setter Property="IconHeight"
|
||||
Value="{DynamicResource {x:Static atom:SharedTokenKey.IconSizeLG}}" />
|
||||
</Style>
|
||||
</Style>
|
||||
|
||||
<Style Selector="^[SizeType=Middle]">
|
||||
<Style Selector="^ /template/ atom|IconPresenter#PART_IconPresenter">
|
||||
<Setter Property="IconWidth"
|
||||
Value="{DynamicResource {x:Static atom:SharedTokenKey.IconSize}}" />
|
||||
<Setter Property="IconHeight"
|
||||
Value="{DynamicResource {x:Static atom:SharedTokenKey.IconSize}}" />
|
||||
</Style>
|
||||
</Style>
|
||||
|
||||
<Style Selector="^[SizeType=Small]">
|
||||
<Style Selector="^ /template/ atom|IconPresenter#PART_IconPresenter">
|
||||
<Setter Property="IconWidth"
|
||||
Value="{DynamicResource {x:Static atom:SharedTokenKey.IconSizeSM}}" />
|
||||
<Setter Property="IconHeight"
|
||||
Value="{DynamicResource {x:Static atom:SharedTokenKey.IconSizeSM}}" />
|
||||
</Style>
|
||||
</Style>
|
||||
<!-- BuildIconStyle end -->
|
||||
|
||||
<Style Selector="^:disabled">
|
||||
<Setter Property="Foreground"
|
||||
Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorTextDisabled}}" />
|
||||
<Style Selector="^ /template/ atom|IconPresenter#PART_IconPresenter">
|
||||
<Setter Property="IconMode" Value="Disabled"/>
|
||||
</Style>
|
||||
</Style>
|
||||
|
||||
</ControlTheme>
|
||||
</ResourceDictionary>
|
||||
@@ -0,0 +1,48 @@
|
||||
<ResourceDictionary
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:atom="https://atomui.net">
|
||||
<ControlTheme x:Key="{x:Type atom:Segmented}" TargetType="atom:Segmented">
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate>
|
||||
<Border Name="{x:Static atom:SegmentedThemeConstants.FramePart}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
ClipToBounds="True">
|
||||
<ItemsPresenter Name="{x:Static atom:SegmentedThemeConstants.ItemsPresenterPart}">
|
||||
<ItemsPresenter.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<atom:SegmentedStackPanel IsExpanding="{Binding IsExpanding, RelativeSource={RelativeSource AncestorType=atom:Segmented}}"/>
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsPresenter.ItemsPanel>
|
||||
</ItemsPresenter>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
|
||||
<Setter Property="Padding" Value="{DynamicResource {x:Static atom:SegmentedTokenKey.TrackPadding}}" />
|
||||
<Setter Property="Background" Value="{DynamicResource {x:Static atom:SegmentedTokenKey.TrackBg}}" />
|
||||
<Setter Property="HorizontalAlignment" Value="Left" />
|
||||
<Setter Property="SelectedThumbBg" Value="{DynamicResource {x:Static atom:SegmentedTokenKey.ItemSelectedBg}}" />
|
||||
<Setter Property="SelectedThumbBoxShadows" Value="{DynamicResource {x:Static atom:SharedTokenKey.BoxShadowsTertiary}}" />
|
||||
|
||||
<Style Selector="^[IsExpanding=True]">
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="^[SizeType=Large]">
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource {x:Static atom:SharedTokenKey.BorderRadiusLG}}" />
|
||||
<Setter Property="SelectedThumbCornerRadius" Value="{DynamicResource {x:Static atom:SharedTokenKey.BorderRadius}}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="^[SizeType=Middle]">
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource {x:Static atom:SharedTokenKey.BorderRadius}}" />
|
||||
<Setter Property="SelectedThumbCornerRadius" Value="{DynamicResource {x:Static atom:SharedTokenKey.BorderRadiusSM}}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="^[SizeType=Small]">
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource {x:Static atom:SharedTokenKey.BorderRadiusSM}}" />
|
||||
<Setter Property="SelectedThumbCornerRadius" Value="{DynamicResource {x:Static atom:SharedTokenKey.BorderRadiusXS}}" />
|
||||
</Style>
|
||||
</ControlTheme>
|
||||
</ResourceDictionary>
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace AtomUI.Controls.Themes;
|
||||
|
||||
internal static class SegmentedItemThemeConstants
|
||||
{
|
||||
public const string MainFramePart = "PART_MainFrame";
|
||||
public const string IconPresenterPart = "PART_IconPresenter";
|
||||
public const string ContentPart = "PART_Content";
|
||||
}
|
||||
|
||||
internal static class SegmentedThemeConstants
|
||||
{
|
||||
public const string FramePart = "PART_Frame";
|
||||
public const string ItemsPresenterPart = "PART_ItemsPresenter";
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<ResourceDictionary xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceInclude Source="SegmentedTheme.axaml"/>
|
||||
<ResourceInclude Source="SegmentedItemTheme.axaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
@@ -2,7 +2,6 @@ using AtomUI.Data;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Metadata;
|
||||
using Avalonia.Data;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Metadata;
|
||||
@@ -185,25 +184,25 @@ public class IconPresenter : Control
|
||||
|
||||
private void ConfigureIcon(Icon icon)
|
||||
{
|
||||
SetValue(LoadingAnimationProperty, icon.LoadingAnimation, BindingPriority.Template);
|
||||
SetValue(LoadingAnimationDurationProperty, icon.LoadingAnimationDuration, BindingPriority.Template);
|
||||
SetCurrentValue(LoadingAnimationProperty, icon.LoadingAnimation);
|
||||
SetCurrentValue(LoadingAnimationDurationProperty, icon.LoadingAnimationDuration);
|
||||
if (icon.ThemeType != IconThemeType.TwoTone)
|
||||
{
|
||||
if (icon.NormalFilledBrush != null)
|
||||
{
|
||||
SetValue(NormalFilledBrushProperty, icon.NormalFilledBrush, BindingPriority.Template);
|
||||
SetCurrentValue(NormalFilledBrushProperty, icon.NormalFilledBrush);
|
||||
}
|
||||
if (icon.ActiveFilledBrush != null)
|
||||
{
|
||||
SetValue(ActiveFilledBrushProperty, icon.ActiveFilledBrush, BindingPriority.Template);
|
||||
SetCurrentValue(ActiveFilledBrushProperty, icon.ActiveFilledBrush);
|
||||
}
|
||||
if (icon.SecondaryFilledBrush != null)
|
||||
{
|
||||
SetValue(SelectedFilledBrushProperty, icon.SecondaryFilledBrush, BindingPriority.Template);
|
||||
SetCurrentValue(SelectedFilledBrushProperty, icon.SecondaryFilledBrush);
|
||||
}
|
||||
if (icon.SecondaryFilledBrush != null)
|
||||
{
|
||||
SetValue(DisabledFilledBrushProperty, icon.DisabledFilledBrush, BindingPriority.Template);
|
||||
SetCurrentValue(DisabledFilledBrushProperty, icon.DisabledFilledBrush);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user