mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-28 23:08:36 +08:00
NavMenuPopup menu item style completed
This commit is contained in:
+13
-4
@@ -370,12 +370,20 @@ namespace AtomUI.Theme.Styling
|
||||
|
||||
public static class NavMenuTokenResourceKey
|
||||
{
|
||||
public static readonly TokenResourceKey PopupMinWidth = new TokenResourceKey("NavMenu.PopupMinWidth", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey MenuPopupBorderRadius = new TokenResourceKey("NavMenu.MenuPopupBorderRadius", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey MenuPopupBoxShadows = new TokenResourceKey("NavMenu.MenuPopupBoxShadows", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey MenuPopupContentPadding = new TokenResourceKey("NavMenu.MenuPopupContentPadding", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey MenuPopupMinWidth = new TokenResourceKey("NavMenu.MenuPopupMinWidth", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey MenuPopupMaxWidth = new TokenResourceKey("NavMenu.MenuPopupMaxWidth", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey MenuPopupMinHeight = new TokenResourceKey("NavMenu.MenuPopupMinHeight", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey MenuPopupMaxHeight = new TokenResourceKey("NavMenu.MenuPopupMaxHeight", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey TopLevelItemPopupMarginToAnchor = new TokenResourceKey("NavMenu.TopLevelItemPopupMarginToAnchor", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey GroupTitleColor = new TokenResourceKey("NavMenu.GroupTitleColor", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey GroupTitleLineHeight = new TokenResourceKey("NavMenu.GroupTitleLineHeight", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey GroupTitleFontSize = new TokenResourceKey("NavMenu.GroupTitleFontSize", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey ItemBorderRadius = new TokenResourceKey("NavMenu.ItemBorderRadius", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey SubMenuItemBorderRadius = new TokenResourceKey("NavMenu.SubMenuItemBorderRadius", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey KeyGestureColor = new TokenResourceKey("NavMenu.KeyGestureColor", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey ItemColor = new TokenResourceKey("NavMenu.ItemColor", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey ItemHoverColor = new TokenResourceKey("NavMenu.ItemHoverColor", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey HorizontalItemHoverColor = new TokenResourceKey("NavMenu.HorizontalItemHoverColor", "AtomUI.Token");
|
||||
@@ -396,19 +404,20 @@ namespace AtomUI.Theme.Styling
|
||||
public static readonly TokenResourceKey HorizontalItemSelectedBg = new TokenResourceKey("NavMenu.HorizontalItemSelectedBg", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey ActiveBarWidth = new TokenResourceKey("NavMenu.ActiveBarWidth", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey ActiveBarHeight = new TokenResourceKey("NavMenu.ActiveBarHeight", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey ItemContentMargin = new TokenResourceKey("NavMenu.ItemContentMargin", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey ItemContentPadding = new TokenResourceKey("NavMenu.ItemContentPadding", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey ItemMargin = new TokenResourceKey("NavMenu.ItemMargin", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey HorizontalItemMargin = new TokenResourceKey("NavMenu.HorizontalItemMargin", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey ItemPadding = new TokenResourceKey("NavMenu.ItemPadding", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey HorizontalItemHoverBg = new TokenResourceKey("NavMenu.HorizontalItemHoverBg", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey HorizontalItemBorderRadius = new TokenResourceKey("NavMenu.HorizontalItemBorderRadius", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey ItemHeight = new TokenResourceKey("NavMenu.ItemHeight", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey CollapsedWidth = new TokenResourceKey("NavMenu.CollapsedWidth", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey PopupBg = new TokenResourceKey("NavMenu.PopupBg", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey MenuPopupBg = new TokenResourceKey("NavMenu.MenuPopupBg", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey HorizontalLineHeight = new TokenResourceKey("NavMenu.HorizontalLineHeight", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey IconMargin = new TokenResourceKey("NavMenu.IconMargin", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey IconSize = new TokenResourceKey("NavMenu.IconSize", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey CollapsedIconSize = new TokenResourceKey("NavMenu.CollapsedIconSize", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey DarkPopupBg = new TokenResourceKey("NavMenu.DarkPopupBg", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey DarkMenuPopupBg = new TokenResourceKey("NavMenu.DarkMenuPopupBg", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey DarkItemColor = new TokenResourceKey("NavMenu.DarkItemColor", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey DarkDangerItemColor = new TokenResourceKey("NavMenu.DarkDangerItemColor", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey DarkItemBg = new TokenResourceKey("NavMenu.DarkItemBg", "AtomUI.Token");
|
||||
|
||||
@@ -4,6 +4,7 @@ using AtomUI.Theme.Styling;
|
||||
using AtomUI.Utils;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Converters;
|
||||
using Avalonia.Controls.Metadata;
|
||||
using Avalonia.Controls.Mixins;
|
||||
using Avalonia.Controls.Primitives;
|
||||
@@ -353,6 +354,8 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
||||
private EventHandler CanExecuteChangedHandler => _canExecuteChangeHandler ??= new(CanExecuteChanged);
|
||||
|
||||
#endregion
|
||||
|
||||
internal static PlatformKeyGestureConverter KeyGestureConverter = new();
|
||||
|
||||
/// <summary>
|
||||
/// The default value for the <see cref="ItemsControl.ItemsPanel"/> property.
|
||||
@@ -563,7 +566,8 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
||||
}
|
||||
|
||||
_horizontalFrame = e.NameScope.Find<Border>(TopLevelHorizontalNavMenuItemTheme.FramePart);
|
||||
TokenResourceBinder.CreateTokenBinding(this, PopupMinWidthProperty, NavMenuTokenResourceKey.PopupMinWidth);
|
||||
TokenResourceBinder.CreateTokenBinding(this, PopupMinWidthProperty, NavMenuTokenResourceKey.MenuPopupMinWidth);
|
||||
SetupItemIcon();
|
||||
}
|
||||
|
||||
protected override void UpdateDataValidation(
|
||||
@@ -712,6 +716,10 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
||||
{
|
||||
SetupHorizontalEffectiveIndicatorWidth();
|
||||
}
|
||||
else if (change.Property == IconProperty)
|
||||
{
|
||||
SetupItemIcon();
|
||||
}
|
||||
|
||||
if (change.Property == BoundsProperty ||
|
||||
change.Property == PopupMinWidthProperty)
|
||||
@@ -720,6 +728,14 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupItemIcon()
|
||||
{
|
||||
if (Icon is not null && Icon is PathIcon menuItemIcon)
|
||||
{
|
||||
menuItemIcon.Name = ThemeConstants.ItemIconPart;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupHorizontalEffectiveIndicatorWidth()
|
||||
{
|
||||
var width = Bounds.Width;
|
||||
|
||||
@@ -1,21 +1,298 @@
|
||||
using AtomUI.Theme;
|
||||
using AtomUI.Icon;
|
||||
using AtomUI.Media;
|
||||
using AtomUI.Theme;
|
||||
using AtomUI.Theme.Styling;
|
||||
using AtomUI.Theme.Utils;
|
||||
using AtomUI.Utils;
|
||||
using Avalonia;
|
||||
using Avalonia.Animation;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Presenters;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Data;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Styling;
|
||||
|
||||
namespace AtomUI.Controls;
|
||||
|
||||
[ControlThemeProvider]
|
||||
internal class NavMenuItemTheme : BaseControlTheme
|
||||
{
|
||||
public const string ItemDecoratorPart = "PART_ItemDecorator";
|
||||
public const string MainContainerPart = "PART_MainContainer";
|
||||
public const string ItemIconPresenterPart = "PART_ItemIconPresenter";
|
||||
public const string ItemTextPresenterPart = "PART_ItemTextPresenter";
|
||||
public const string InputGestureTextPart = "PART_InputGestureText";
|
||||
public const string MenuIndicatorIconPart = "PART_MenuIndicatorIcon";
|
||||
public const string PopupPart = "PART_Popup";
|
||||
public const string ItemsPresenterPart = "PART_ItemsPresenter";
|
||||
|
||||
public NavMenuItemTheme()
|
||||
: base(typeof(NavMenuItem))
|
||||
{
|
||||
}
|
||||
|
||||
protected override IControlTemplate BuildControlTemplate()
|
||||
{
|
||||
return new FuncControlTemplate<NavMenuItem>((item, scope) =>
|
||||
{
|
||||
BuildInstanceStyles(item);
|
||||
// 仅仅为了把 Popup 包进来,没有其他什么作用
|
||||
var layoutWrapper = new Panel();
|
||||
var container = new Border
|
||||
{
|
||||
Name = ItemDecoratorPart
|
||||
};
|
||||
|
||||
var transitions = new Transitions();
|
||||
transitions.Add(AnimationUtils.CreateTransition<SolidColorBrushTransition>(Border.BackgroundProperty));
|
||||
container.Transitions = transitions;
|
||||
|
||||
var layout = new Grid
|
||||
{
|
||||
Name = MainContainerPart,
|
||||
ColumnDefinitions =
|
||||
{
|
||||
new ColumnDefinition(GridLength.Auto)
|
||||
{
|
||||
SharedSizeGroup = ThemeConstants.IconPresenterSizeGroup
|
||||
},
|
||||
new ColumnDefinition(GridLength.Star),
|
||||
new ColumnDefinition(GridLength.Auto)
|
||||
{
|
||||
SharedSizeGroup = ThemeConstants.InputGestureTextSizeGroup
|
||||
},
|
||||
new ColumnDefinition(GridLength.Auto)
|
||||
{
|
||||
SharedSizeGroup = ThemeConstants.MenuIndicatorIconSizeGroup
|
||||
}
|
||||
}
|
||||
};
|
||||
layout.RegisterInNameScope(scope);
|
||||
|
||||
var iconPresenter = new Viewbox
|
||||
{
|
||||
Name = ItemIconPresenterPart,
|
||||
HorizontalAlignment = HorizontalAlignment.Center,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
Stretch = Stretch.Uniform
|
||||
};
|
||||
|
||||
Grid.SetColumn(iconPresenter, 0);
|
||||
iconPresenter.RegisterInNameScope(scope);
|
||||
CreateTemplateParentBinding(iconPresenter, Viewbox.ChildProperty, NavMenuItem.IconProperty);
|
||||
TokenResourceBinder.CreateTokenBinding(iconPresenter, Layoutable.MarginProperty,
|
||||
NavMenuTokenResourceKey.ItemMargin);
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(iconPresenter, Layoutable.WidthProperty,
|
||||
NavMenuTokenResourceKey.ItemIconSize);
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(iconPresenter, Layoutable.HeightProperty,
|
||||
NavMenuTokenResourceKey.ItemIconSize);
|
||||
|
||||
var itemTextPresenter = new ContentPresenter
|
||||
{
|
||||
Name = ItemTextPresenterPart,
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
RecognizesAccessKey = true,
|
||||
IsHitTestVisible = false
|
||||
};
|
||||
Grid.SetColumn(itemTextPresenter, 1);
|
||||
TokenResourceBinder.CreateTokenBinding(itemTextPresenter, Layoutable.MarginProperty,
|
||||
NavMenuTokenResourceKey.ItemMargin);
|
||||
CreateTemplateParentBinding(itemTextPresenter, ContentPresenter.ContentProperty,
|
||||
HeaderedSelectingItemsControl.HeaderProperty);
|
||||
CreateTemplateParentBinding(itemTextPresenter, ContentPresenter.ContentTemplateProperty,
|
||||
HeaderedSelectingItemsControl.HeaderTemplateProperty);
|
||||
|
||||
itemTextPresenter.RegisterInNameScope(scope);
|
||||
|
||||
var inputGestureText = new TextBlock
|
||||
{
|
||||
Name = InputGestureTextPart,
|
||||
HorizontalAlignment = HorizontalAlignment.Right,
|
||||
TextAlignment = TextAlignment.Right,
|
||||
VerticalAlignment = VerticalAlignment.Center
|
||||
};
|
||||
Grid.SetColumn(inputGestureText, 2);
|
||||
TokenResourceBinder.CreateTokenBinding(inputGestureText, Layoutable.MarginProperty,
|
||||
NavMenuTokenResourceKey.ItemMargin);
|
||||
CreateTemplateParentBinding(inputGestureText,
|
||||
TextBlock.TextProperty,
|
||||
NavMenuItem.InputGestureProperty,
|
||||
BindingMode.Default,
|
||||
NavMenuItem.KeyGestureConverter);
|
||||
|
||||
inputGestureText.RegisterInNameScope(scope);
|
||||
|
||||
var menuIndicatorIcon = new PathIcon
|
||||
{
|
||||
Name = MenuIndicatorIconPart,
|
||||
HorizontalAlignment = HorizontalAlignment.Right,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
Kind = "RightOutlined"
|
||||
};
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(menuIndicatorIcon, Layoutable.WidthProperty,
|
||||
GlobalTokenResourceKey.IconSizeXS);
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(menuIndicatorIcon, Layoutable.HeightProperty,
|
||||
GlobalTokenResourceKey.IconSizeXS);
|
||||
Grid.SetColumn(menuIndicatorIcon, 3);
|
||||
menuIndicatorIcon.RegisterInNameScope(scope);
|
||||
|
||||
var popup = CreateMenuPopup();
|
||||
popup.RegisterInNameScope(scope);
|
||||
|
||||
layout.Children.Add(iconPresenter);
|
||||
layout.Children.Add(itemTextPresenter);
|
||||
layout.Children.Add(inputGestureText);
|
||||
layout.Children.Add(menuIndicatorIcon);
|
||||
layout.Children.Add(popup);
|
||||
|
||||
container.Child = layout;
|
||||
layoutWrapper.Children.Add(container);
|
||||
return layoutWrapper;
|
||||
});
|
||||
}
|
||||
|
||||
private Popup CreateMenuPopup()
|
||||
{
|
||||
var popup = new Popup
|
||||
{
|
||||
Name = PopupPart,
|
||||
WindowManagerAddShadowHint = false,
|
||||
IsLightDismissEnabled = false,
|
||||
Placement = PlacementMode.RightEdgeAlignedTop
|
||||
};
|
||||
|
||||
var border = new Border();
|
||||
TokenResourceBinder.CreateTokenBinding(border, Border.BackgroundProperty,
|
||||
GlobalTokenResourceKey.ColorBgContainer);
|
||||
TokenResourceBinder.CreateTokenBinding(border, Border.CornerRadiusProperty,
|
||||
NavMenuTokenResourceKey.MenuPopupBorderRadius);
|
||||
TokenResourceBinder.CreateTokenBinding(border, Layoutable.MinWidthProperty,
|
||||
NavMenuTokenResourceKey.MenuPopupMinWidth);
|
||||
TokenResourceBinder.CreateTokenBinding(border, Layoutable.MaxWidthProperty,
|
||||
NavMenuTokenResourceKey.MenuPopupMaxWidth);
|
||||
TokenResourceBinder.CreateTokenBinding(border, Layoutable.MinHeightProperty,
|
||||
NavMenuTokenResourceKey.MenuPopupMinHeight);
|
||||
TokenResourceBinder.CreateTokenBinding(border, Layoutable.MaxHeightProperty,
|
||||
NavMenuTokenResourceKey.MenuPopupMaxHeight);
|
||||
TokenResourceBinder.CreateTokenBinding(border, Decorator.PaddingProperty,
|
||||
NavMenuTokenResourceKey.MenuPopupContentPadding);
|
||||
|
||||
var scrollViewer = new MenuScrollViewer();
|
||||
var itemsPresenter = new ItemsPresenter
|
||||
{
|
||||
Name = ItemsPresenterPart
|
||||
};
|
||||
CreateTemplateParentBinding(itemsPresenter, ItemsPresenter.ItemsPanelProperty, ItemsControl.ItemsPanelProperty);
|
||||
Grid.SetIsSharedSizeScope(itemsPresenter, true);
|
||||
scrollViewer.Content = itemsPresenter;
|
||||
border.Child = scrollViewer;
|
||||
|
||||
popup.Child = border;
|
||||
|
||||
TokenResourceBinder.CreateTokenBinding(popup, Popup.MarginToAnchorProperty,
|
||||
NavMenuTokenResourceKey.TopLevelItemPopupMarginToAnchor);
|
||||
TokenResourceBinder.CreateTokenBinding(popup, Popup.MaskShadowsProperty,
|
||||
NavMenuTokenResourceKey.MenuPopupBoxShadows);
|
||||
CreateTemplateParentBinding(popup, Avalonia.Controls.Primitives.Popup.IsOpenProperty,
|
||||
NavMenuItem.IsSubMenuOpenProperty, BindingMode.TwoWay);
|
||||
|
||||
return popup;
|
||||
}
|
||||
|
||||
protected override void BuildStyles()
|
||||
{
|
||||
BuildCommonStyle();
|
||||
BuildMenuIndicatorStyle();
|
||||
BuildMenuIconStyle();
|
||||
BuildDisabledStyle();
|
||||
}
|
||||
|
||||
private void BuildCommonStyle()
|
||||
{
|
||||
var commonStyle = new Style(selector => selector.Nesting());
|
||||
commonStyle.Add(TemplatedControl.ForegroundProperty, NavMenuTokenResourceKey.ItemColor);
|
||||
{
|
||||
var keyGestureStyle = new Style(selector => selector.Nesting().Template().Name(InputGestureTextPart));
|
||||
keyGestureStyle.Add(TextBlock.ForegroundProperty, NavMenuTokenResourceKey.KeyGestureColor);
|
||||
commonStyle.Add(keyGestureStyle);
|
||||
}
|
||||
{
|
||||
var borderStyle = new Style(selector => selector.Nesting().Template().Name(ItemDecoratorPart));
|
||||
borderStyle.Add(Layoutable.MinHeightProperty, NavMenuTokenResourceKey.ItemHeight);
|
||||
borderStyle.Add(Decorator.PaddingProperty, NavMenuTokenResourceKey.ItemContentPadding);
|
||||
borderStyle.Add(Border.BackgroundProperty, NavMenuTokenResourceKey.ItemBg);
|
||||
borderStyle.Add(Border.CornerRadiusProperty, NavMenuTokenResourceKey.ItemBorderRadius);
|
||||
commonStyle.Add(borderStyle);
|
||||
}
|
||||
|
||||
// Hover 状态
|
||||
var hoverStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.PointerOver));
|
||||
hoverStyle.Add(TemplatedControl.ForegroundProperty, NavMenuTokenResourceKey.ItemHoverColor);
|
||||
{
|
||||
var borderStyle = new Style(selector => selector.Nesting().Template().Name(ItemDecoratorPart));
|
||||
borderStyle.Add(Border.BackgroundProperty, NavMenuTokenResourceKey.ItemHoverBg);
|
||||
hoverStyle.Add(borderStyle);
|
||||
}
|
||||
commonStyle.Add(hoverStyle);
|
||||
Add(commonStyle);
|
||||
}
|
||||
|
||||
private void BuildMenuIndicatorStyle()
|
||||
{
|
||||
{
|
||||
var menuIndicatorStyle = new Style(selector => selector.Nesting().Template().Name(MenuIndicatorIconPart));
|
||||
menuIndicatorStyle.Add(Visual.IsVisibleProperty, true);
|
||||
Add(menuIndicatorStyle);
|
||||
}
|
||||
var hasSubMenuStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.Empty));
|
||||
{
|
||||
var menuIndicatorStyle = new Style(selector => selector.Nesting().Template().Name(MenuIndicatorIconPart));
|
||||
menuIndicatorStyle.Add(Visual.IsVisibleProperty, false);
|
||||
hasSubMenuStyle.Add(menuIndicatorStyle);
|
||||
}
|
||||
Add(hasSubMenuStyle);
|
||||
}
|
||||
|
||||
private void BuildMenuIconStyle()
|
||||
{
|
||||
{
|
||||
var iconViewBoxStyle = new Style(selector => selector.Nesting().Template().Name(ItemIconPresenterPart));
|
||||
iconViewBoxStyle.Add(Visual.IsVisibleProperty, false);
|
||||
Add(iconViewBoxStyle);
|
||||
}
|
||||
|
||||
var hasIconStyle = new Style(selector => selector.Nesting().Class(":icon"));
|
||||
{
|
||||
var iconViewBoxStyle = new Style(selector => selector.Nesting().Template().Name(ItemIconPresenterPart));
|
||||
iconViewBoxStyle.Add(Visual.IsVisibleProperty, true);
|
||||
hasIconStyle.Add(iconViewBoxStyle);
|
||||
}
|
||||
Add(hasIconStyle);
|
||||
}
|
||||
|
||||
private void BuildDisabledStyle()
|
||||
{
|
||||
var disabledStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.Disabled));
|
||||
disabledStyle.Add(TemplatedControl.ForegroundProperty, NavMenuTokenResourceKey.ItemDisabledColor);
|
||||
Add(disabledStyle);
|
||||
}
|
||||
|
||||
protected override void BuildInstanceStyles(Control control)
|
||||
{
|
||||
var iconStyle = new Style(selector => selector.Name(ThemeConstants.ItemIconPart));
|
||||
iconStyle.Add(PathIcon.WidthProperty, NavMenuTokenResourceKey.ItemIconSize);
|
||||
iconStyle.Add(PathIcon.HeightProperty, NavMenuTokenResourceKey.ItemIconSize);
|
||||
iconStyle.Add(PathIcon.NormalFilledBrushProperty, GlobalTokenResourceKey.ColorText);
|
||||
iconStyle.Add(PathIcon.DisabledFilledBrushProperty, NavMenuTokenResourceKey.ItemDisabledColor);
|
||||
iconStyle.Add(PathIcon.SelectedFilledBrushProperty, GlobalTokenResourceKey.ColorPrimary);
|
||||
control.Styles.Add(iconStyle);
|
||||
|
||||
var disabledIconStyle = new Style(selector => selector.OfType<PathIcon>().Class(StdPseudoClass.Disabled));
|
||||
disabledIconStyle.Add(PathIcon.IconModeProperty, IconMode.Disabled);
|
||||
control.Styles.Add(disabledIconStyle);
|
||||
}
|
||||
}
|
||||
@@ -11,9 +11,44 @@ internal class NavMenuToken : AbstractControlDesignToken
|
||||
public const string ID = "NavMenu";
|
||||
|
||||
/// <summary>
|
||||
/// 弹出菜单的宽度
|
||||
/// 菜单的圆角
|
||||
/// </summary>
|
||||
public double PopupMinWidth { get; set; }
|
||||
public CornerRadius MenuPopupBorderRadius { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 菜单 Popup 阴影
|
||||
/// </summary>
|
||||
public BoxShadows MenuPopupBoxShadows { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 菜单内容边距
|
||||
/// </summary>
|
||||
public Thickness MenuPopupContentPadding { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 菜单 Popup 最小宽度
|
||||
/// </summary>
|
||||
public double MenuPopupMinWidth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 菜单 Popup 最大宽度
|
||||
/// </summary>
|
||||
public double MenuPopupMaxWidth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 菜单 Popup 最小高度
|
||||
/// </summary>
|
||||
public double MenuPopupMinHeight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 菜单 Popup 最大高度
|
||||
/// </summary>
|
||||
public double MenuPopupMaxHeight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 顶层弹出菜单,距离顶层菜单项的边距
|
||||
/// </summary>
|
||||
public double TopLevelItemPopupMarginToAnchor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 分组标题文字颜色
|
||||
@@ -40,6 +75,11 @@ internal class NavMenuToken : AbstractControlDesignToken
|
||||
/// </summary>
|
||||
public CornerRadius SubMenuItemBorderRadius { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 快捷键颜色
|
||||
/// </summary>
|
||||
public Color KeyGestureColor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 菜单项文字颜色
|
||||
/// </summary>
|
||||
@@ -143,6 +183,16 @@ internal class NavMenuToken : AbstractControlDesignToken
|
||||
/// <summary>
|
||||
/// 菜单项外间距
|
||||
/// </summary>
|
||||
public Thickness ItemContentMargin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 菜单项横向内间距
|
||||
/// </summary>
|
||||
public Thickness ItemContentPadding { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 菜单项内部元素边距
|
||||
/// </summary>
|
||||
public Thickness ItemMargin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -150,11 +200,6 @@ internal class NavMenuToken : AbstractControlDesignToken
|
||||
/// </summary>
|
||||
public Thickness HorizontalItemMargin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 菜单项横向内间距
|
||||
/// </summary>
|
||||
public Thickness ItemPadding { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 横向菜单项横悬浮态背景色
|
||||
/// </summary>
|
||||
@@ -178,7 +223,7 @@ internal class NavMenuToken : AbstractControlDesignToken
|
||||
/// <summary>
|
||||
/// 弹出框背景色
|
||||
/// </summary>
|
||||
public Color PopupBg { get; set; }
|
||||
public Color MenuPopupBg { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 横向菜单行高
|
||||
@@ -204,7 +249,7 @@ internal class NavMenuToken : AbstractControlDesignToken
|
||||
/// <summary>
|
||||
/// 暗色模式下的浮层菜单的背景颜色
|
||||
/// </summary>
|
||||
public Color DarkPopupBg { get; set; }
|
||||
public Color DarkMenuPopupBg { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 暗色模式下的菜单项文字颜色
|
||||
@@ -315,15 +360,13 @@ internal class NavMenuToken : AbstractControlDesignToken
|
||||
var activeBarHeight = !double.IsNaN(ActiveBarHeight)
|
||||
? ActiveBarHeight
|
||||
: _globalToken.LineWidthBold;
|
||||
var itemMargin = ItemMargin != default ? ItemMargin : new Thickness(_globalToken.MarginXXS, _globalToken.MarginXXS);
|
||||
var itemContentMargin = ItemContentMargin != default ? ItemContentMargin : new Thickness(_globalToken.MarginXXS, _globalToken.MarginXXS);
|
||||
var colorTextDark = ColorUtils.FromRgbF(
|
||||
0.65d,
|
||||
colorTextLightSolid.GetRedF(),
|
||||
colorTextLightSolid.GetGreenF(),
|
||||
colorTextLightSolid.GetBlueF());
|
||||
|
||||
|
||||
PopupMinWidth = 160d;
|
||||
|
||||
ItemBorderRadius = _globalToken.BorderRadiusLG;
|
||||
SubMenuItemBorderRadius = _globalToken.BorderRadiusSM;
|
||||
ItemColor = _globalToken.ColorText;
|
||||
@@ -351,19 +394,18 @@ internal class NavMenuToken : AbstractControlDesignToken
|
||||
DangerItemActiveBg = _globalToken.ColorError;
|
||||
DangerItemSelectedBg = _globalToken.ColorError;
|
||||
|
||||
ItemMargin = itemMargin;
|
||||
HorizontalItemBorderRadius = new CornerRadius(0);
|
||||
HorizontalItemHoverBg = Colors.Transparent;
|
||||
ItemHeight = _globalToken.ControlHeightLG;
|
||||
GroupTitleLineHeight = _globalToken.ControlHeight;
|
||||
CollapsedWidth = _globalToken.ControlHeightLG * 2;
|
||||
PopupBg = _globalToken.ColorBgElevated;
|
||||
ItemPadding = new Thickness(_globalToken.Padding, 0);
|
||||
HorizontalLineHeight = _globalToken.ControlHeightLG * 1.15;
|
||||
IconSize = _globalToken.FontSize;
|
||||
IconMargin = new Thickness(0, 0, _globalToken.ControlHeightSM - _globalToken.FontSize, 0);
|
||||
CollapsedIconSize = _globalToken.FontSizeLG;
|
||||
GroupTitleFontSize = _globalToken.FontSize;
|
||||
KeyGestureColor = _globalToken.ColorTextSecondary;
|
||||
|
||||
ItemContentMargin = itemContentMargin;
|
||||
ItemContentPadding = new Thickness(_globalToken.Padding, _globalToken.PaddingXXS);
|
||||
ItemMargin = new Thickness(0, 0, _globalToken.MarginXXS, 0);
|
||||
ItemHeight = _globalToken.ControlHeight;
|
||||
GroupTitleLineHeight = _globalToken.ControlHeight;
|
||||
CollapsedWidth = _globalToken.ControlHeight * 2;
|
||||
IconSize = _globalToken.FontSize;
|
||||
IconMargin = new Thickness(0, 0, _globalToken.ControlHeightSM - _globalToken.FontSize, 0);
|
||||
CollapsedIconSize = _globalToken.FontSizeLG;
|
||||
GroupTitleFontSize = _globalToken.FontSize;
|
||||
|
||||
// Disabled
|
||||
DarkItemDisabledColor = ColorUtils.FromRgbF(0.25d,
|
||||
@@ -375,7 +417,7 @@ internal class NavMenuToken : AbstractControlDesignToken
|
||||
DarkItemColor = colorTextDark;
|
||||
DarkDangerItemColor = _globalToken.ColorError;
|
||||
DarkItemBg = Color.Parse("#001529");
|
||||
DarkPopupBg = Color.Parse("#001529");
|
||||
DarkMenuPopupBg = Color.Parse("#001529");
|
||||
DarkSubMenuItemBg = Color.Parse("#000c17");
|
||||
|
||||
DarkItemSelectedColor = colorTextLightSolid;
|
||||
@@ -388,13 +430,27 @@ internal class NavMenuToken : AbstractControlDesignToken
|
||||
DarkDangerItemSelectedColor = colorTextLightSolid;
|
||||
DarkDangerItemActiveBg = _globalToken.ColorError;
|
||||
|
||||
MenuHorizontalHeight = _globalToken.ControlHeightLG * 1.15;
|
||||
HorizontalItemMargin = new Thickness(_globalToken.Padding, 0);
|
||||
MenuHorizontalHeight = _globalToken.ControlHeightLG * 1.15;
|
||||
HorizontalItemMargin = new Thickness(_globalToken.Padding, 0);
|
||||
HorizontalLineHeight = _globalToken.ControlHeightLG * 1.15;
|
||||
HorizontalItemBorderRadius = new CornerRadius(0);
|
||||
HorizontalItemHoverBg = Colors.Transparent;
|
||||
|
||||
MenuArrowSize = _globalToken.FontSize / 7 * 5;
|
||||
MenuArrowOffset = MenuArrowSize * 0.25;
|
||||
MenuSubMenuBg = _globalToken.ColorBgElevated;
|
||||
|
||||
ItemIconSize = _globalToken.IconSize;
|
||||
|
||||
MenuPopupMinWidth = 160d;
|
||||
MenuPopupMaxWidth = 800d;
|
||||
MenuPopupMinHeight = ItemHeight * 3;
|
||||
MenuPopupMaxHeight = ItemHeight * 30;
|
||||
TopLevelItemPopupMarginToAnchor = _globalToken.MarginXXS;
|
||||
|
||||
MenuPopupBg = _globalToken.ColorBgElevated;
|
||||
MenuPopupBorderRadius = _globalToken.BorderRadiusLG;
|
||||
MenuPopupContentPadding = new Thickness(_globalToken.PaddingXXS, MenuPopupBorderRadius.TopLeft / 2);
|
||||
MenuPopupBoxShadows = _globalToken.BoxShadowsSecondary;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,4 +3,10 @@
|
||||
internal static class ThemeConstants
|
||||
{
|
||||
public const string PopupPart = "PART_Popup";
|
||||
public const string ItemIconPart = "PART_ItemIcon";
|
||||
|
||||
// 菜单项 SizeGridName
|
||||
public const string IconPresenterSizeGroup = "IconPresenter";
|
||||
public const string InputGestureTextSizeGroup = "InputGestureText";
|
||||
public const string MenuIndicatorIconSizeGroup = "MenuIndicatorIcon";
|
||||
}
|
||||
@@ -135,7 +135,7 @@ internal class TopLevelHorizontalNavMenuItemTheme : BaseControlTheme
|
||||
{
|
||||
Name = PopupPart,
|
||||
WindowManagerAddShadowHint = false,
|
||||
IsLightDismissEnabled = true,
|
||||
IsLightDismissEnabled = false,
|
||||
Placement = PlacementMode.BottomEdgeAlignedLeft
|
||||
};
|
||||
|
||||
@@ -229,7 +229,7 @@ internal class TopLevelHorizontalNavMenuItemTheme : BaseControlTheme
|
||||
|
||||
protected override void BuildInstanceStyles(Control control)
|
||||
{
|
||||
var iconStyle = new Style(selector => selector.OfType<PathIcon>());
|
||||
var iconStyle = new Style(selector => selector.Name(ThemeConstants.ItemIconPart));
|
||||
iconStyle.Add(PathIcon.WidthProperty, NavMenuTokenResourceKey.ItemIconSize);
|
||||
iconStyle.Add(PathIcon.HeightProperty, NavMenuTokenResourceKey.ItemIconSize);
|
||||
iconStyle.Add(PathIcon.NormalFilledBrushProperty, GlobalTokenResourceKey.ColorText);
|
||||
|
||||
@@ -6,8 +6,11 @@ using AtomUI.Theme.Styling;
|
||||
using AtomUI.Utils;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Diagnostics;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Controls.Primitives.PopupPositioning;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Input.Raw;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.LogicalTree;
|
||||
using Avalonia.Media;
|
||||
@@ -64,6 +67,7 @@ public class Popup : AvaloniaPopup
|
||||
|
||||
private PopupShadowLayer? _shadowLayer;
|
||||
private CompositeDisposable? _compositeDisposable;
|
||||
private IDisposable? _selfLightDismissDisposable;
|
||||
private bool _initialized;
|
||||
private ManagedPopupPositionerInfo? _managedPopupPositioner;
|
||||
protected bool _animating;
|
||||
@@ -77,13 +81,14 @@ public class Popup : AvaloniaPopup
|
||||
AffectsMeasure<Popup>(PlacementProperty);
|
||||
AffectsMeasure<Popup>(PlacementAnchorProperty);
|
||||
AffectsMeasure<Popup>(PlacementGravityProperty);
|
||||
|
||||
IsLightDismissEnabledProperty.OverrideDefaultValue<Popup>(false);
|
||||
}
|
||||
|
||||
public Popup()
|
||||
{
|
||||
IsLightDismissEnabled = false;
|
||||
Closed += HandleClosed;
|
||||
Opened += HandleOpened;
|
||||
Closed += HandleClosed;
|
||||
Opened += HandleOpened;
|
||||
}
|
||||
|
||||
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
|
||||
@@ -124,7 +129,9 @@ public class Popup : AvaloniaPopup
|
||||
VerticalOffset = offsetY;
|
||||
|
||||
_compositeDisposable?.Dispose();
|
||||
_shadowLayer = null;
|
||||
_selfLightDismissDisposable?.Dispose();
|
||||
_firstDetected = true;
|
||||
_shadowLayer = null;
|
||||
}
|
||||
|
||||
private void HandleOpened(object? sender, EventArgs? args)
|
||||
@@ -160,6 +167,41 @@ public class Popup : AvaloniaPopup
|
||||
{
|
||||
CreateShadowLayer();
|
||||
}
|
||||
|
||||
// 如果没有启动,我们使用自己的处理函数,一版是为了增加我们自己的动画效果
|
||||
if (!IsLightDismissEnabled)
|
||||
{
|
||||
var inputManager = AvaloniaLocator.Current.GetService<IInputManager>()!;
|
||||
_selfLightDismissDisposable = inputManager.Process.Subscribe(HandleMouseClick);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _firstDetected = true;
|
||||
|
||||
private void HandleMouseClick(RawInputEventArgs args)
|
||||
{
|
||||
if (!IsOpen)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (args is RawPointerEventArgs pointerEventArgs)
|
||||
{
|
||||
if (pointerEventArgs.Type == RawPointerEventType.LeftButtonUp)
|
||||
{
|
||||
if (_firstDetected)
|
||||
{
|
||||
_firstDetected = false;
|
||||
return;
|
||||
}
|
||||
if (this is IPopupHostProvider popupHostProvider)
|
||||
{
|
||||
if (popupHostProvider.PopupHost != pointerEventArgs.Root)
|
||||
{
|
||||
CloseAnimation();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,6 +312,7 @@ public class Popup : AvaloniaPopup
|
||||
?? new Rect(0, 0, double.MaxValue, double.MaxValue);
|
||||
}
|
||||
|
||||
// TODO review 后可能需要删除
|
||||
private static IReadOnlyList<ManagedPopupPositionerScreenInfo> GetScreenInfos(TopLevel topLevel)
|
||||
{
|
||||
if (topLevel is WindowBase window)
|
||||
@@ -280,10 +323,11 @@ public class Popup : AvaloniaPopup
|
||||
new ManagedPopupPositionerScreenInfo(s.Bounds.ToRect(1), s.WorkingArea.ToRect(1)))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
|
||||
return Array.Empty<ManagedPopupPositionerScreenInfo>();
|
||||
}
|
||||
|
||||
|
||||
// TODO review 后可能需要删除
|
||||
private static Rect GetParentClientAreaScreenGeometry(TopLevel topLevel)
|
||||
{
|
||||
// Popup positioner operates with abstract coordinates, but in our case they are pixel ones
|
||||
|
||||
Reference in New Issue
Block a user