mirror of
https://gitee.com/chinware/atomui.git
synced 2024-12-02 03:47:52 +08:00
NavMenu dark mode completed
This commit is contained in:
parent
003cb21847
commit
8710ccbd48
@ -63,6 +63,7 @@ Welcome to communicate and give suggestions to AtomUI, thank you for giving the
|
|||||||
| Breadcrumb | TODO |
|
| Breadcrumb | TODO |
|
||||||
| Dropdown | Completed ✅ |
|
| Dropdown | Completed ✅ |
|
||||||
| Menu | Completed ✅ |
|
| Menu | Completed ✅ |
|
||||||
|
| NavMenu | Completed ✅ |
|
||||||
| Pagination | TODO |
|
| Pagination | TODO |
|
||||||
| Steps | TODO |
|
| Steps | TODO |
|
||||||
|
|
||||||
|
@ -90,7 +90,8 @@ PS: AtomUI 目前仅在 Windows 11 平台测试<br>
|
|||||||
|:---------------|:-------|
|
|:---------------|:-------|
|
||||||
| Breadcrumb 面包屑 | 未完成 |
|
| Breadcrumb 面包屑 | 未完成 |
|
||||||
| Dropdown 下拉菜单 | 已完成 ✅ |
|
| Dropdown 下拉菜单 | 已完成 ✅ |
|
||||||
| Menu 导航菜单 | 已完成 ✅ |
|
| Menu 菜单 | 已完成 ✅ |
|
||||||
|
| NavMenu 导航菜单 | 已完成 ✅ |
|
||||||
| Pagination 分页 | 进行中 💪 |
|
| Pagination 分页 | 进行中 💪 |
|
||||||
| Steps 步骤条 | 未完成 |
|
| Steps 步骤条 | 未完成 |
|
||||||
|
|
||||||
|
@ -251,5 +251,35 @@
|
|||||||
</atom:NavMenu>
|
</atom:NavMenu>
|
||||||
</desktop:ShowCaseItem>
|
</desktop:ShowCaseItem>
|
||||||
|
|
||||||
|
<desktop:ShowCaseItem
|
||||||
|
Title="Switch the menu type"
|
||||||
|
Description="Show the dynamic switching mode (between inline and vertical).">
|
||||||
|
<StackPanel Orientation="Vertical" Spacing="10">
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="5">
|
||||||
|
<atom:ToggleSwitch Name="ChangeModeSwitch"/>
|
||||||
|
<TextBlock>Change Mode</TextBlock>
|
||||||
|
<atom:ToggleSwitch Margin="10, 0, 0, 0" Name="ChangeStyleSwitch"/>
|
||||||
|
<TextBlock>Change Style</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
<atom:NavMenu Mode="{Binding Mode}" Width="256" Margin="0, 0, 0, 20" IsDarkStyle="{Binding IsDark}">
|
||||||
|
<atom:NavMenuItem Header="Navigation One" Icon="{atom:IconProvider Kind=MailOutlined}" />
|
||||||
|
<atom:NavMenuItem Header="Navigation Two" Icon="{atom:IconProvider Kind=AppstoreOutlined}" IsEnabled="False"/>
|
||||||
|
<atom:NavMenuItem Header="Navigation Three - Submenu" Icon="{atom:IconProvider Kind=SettingOutlined}">
|
||||||
|
<atom:NavMenuItem Header="Item 1">
|
||||||
|
<atom:NavMenuItem Header="Option 1" />
|
||||||
|
<atom:NavMenuItem Header="Option 2" />
|
||||||
|
</atom:NavMenuItem>
|
||||||
|
|
||||||
|
<atom:NavMenuItem Header="Item 2">
|
||||||
|
<atom:NavMenuItem Header="Option 3" />
|
||||||
|
<atom:NavMenuItem Header="Option 4" />
|
||||||
|
</atom:NavMenuItem>
|
||||||
|
</atom:NavMenuItem>
|
||||||
|
<atom:NavMenuItem Header="Navigation Four"/>
|
||||||
|
</atom:NavMenu>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
</desktop:ShowCaseItem>
|
||||||
|
|
||||||
</desktop:ShowCasePanel>
|
</desktop:ShowCasePanel>
|
||||||
</UserControl>
|
</UserControl>
|
@ -1,11 +1,66 @@
|
|||||||
|
using AtomUI.Controls;
|
||||||
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
|
||||||
namespace AtomUI.Demo.Desktop.ShowCase;
|
namespace AtomUI.Demo.Desktop.ShowCase;
|
||||||
|
|
||||||
public partial class MenuShowCase : UserControl
|
public partial class MenuShowCase : UserControl
|
||||||
{
|
{
|
||||||
|
public static readonly StyledProperty<bool> IsDarkProperty =
|
||||||
|
AvaloniaProperty.Register<ButtonShowCase, bool>(nameof(IsDark), false);
|
||||||
|
|
||||||
|
public static readonly StyledProperty<NavMenuMode> ModeProperty =
|
||||||
|
AvaloniaProperty.Register<ButtonShowCase, NavMenuMode>(nameof(Mode), NavMenuMode.Inline);
|
||||||
|
|
||||||
|
public bool IsDark
|
||||||
|
{
|
||||||
|
get => GetValue(IsDarkProperty);
|
||||||
|
set => SetValue(IsDarkProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NavMenuMode Mode
|
||||||
|
{
|
||||||
|
get => GetValue(ModeProperty);
|
||||||
|
set => SetValue(ModeProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
public MenuShowCase()
|
public MenuShowCase()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
DataContext = this;
|
||||||
|
ChangeModeSwitch.IsCheckedChanged += HandleChangeModeCheckChanged;
|
||||||
|
ChangeStyleSwitch.IsCheckedChanged += HandleChangeStyleCheckChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleChangeModeCheckChanged(object? sender, RoutedEventArgs? args)
|
||||||
|
{
|
||||||
|
if (ChangeModeSwitch.IsChecked.HasValue)
|
||||||
|
{
|
||||||
|
if (ChangeModeSwitch.IsChecked.Value)
|
||||||
|
{
|
||||||
|
Mode = NavMenuMode.Vertical;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Mode = NavMenuMode.Inline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Mode = NavMenuMode.Inline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleChangeStyleCheckChanged(object? sender, RoutedEventArgs? args)
|
||||||
|
{
|
||||||
|
if (ChangeStyleSwitch.IsChecked.HasValue)
|
||||||
|
{
|
||||||
|
IsDark = ChangeStyleSwitch.IsChecked.Value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IsDark = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -406,6 +406,7 @@ namespace AtomUI.Theme.Styling
|
|||||||
public static readonly TokenResourceKey ItemContentMargin = new TokenResourceKey("NavMenu.ItemContentMargin", "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 ItemContentPadding = new TokenResourceKey("NavMenu.ItemContentPadding", "AtomUI.Token");
|
||||||
public static readonly TokenResourceKey VerticalItemsPanelSpacing = new TokenResourceKey("NavMenu.VerticalItemsPanelSpacing", "AtomUI.Token");
|
public static readonly TokenResourceKey VerticalItemsPanelSpacing = new TokenResourceKey("NavMenu.VerticalItemsPanelSpacing", "AtomUI.Token");
|
||||||
|
public static readonly TokenResourceKey VerticalMenuContentPadding = new TokenResourceKey("NavMenu.VerticalMenuContentPadding", "AtomUI.Token");
|
||||||
public static readonly TokenResourceKey ItemMargin = new TokenResourceKey("NavMenu.ItemMargin", "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 HorizontalItemMargin = new TokenResourceKey("NavMenu.HorizontalItemMargin", "AtomUI.Token");
|
||||||
public static readonly TokenResourceKey HorizontalItemHoverBg = new TokenResourceKey("NavMenu.HorizontalItemHoverBg", "AtomUI.Token");
|
public static readonly TokenResourceKey HorizontalItemHoverBg = new TokenResourceKey("NavMenu.HorizontalItemHoverBg", "AtomUI.Token");
|
||||||
|
@ -20,7 +20,7 @@ namespace AtomUI.Controls;
|
|||||||
|
|
||||||
internal class BaseNavMenuItemTheme : BaseControlTheme
|
internal class BaseNavMenuItemTheme : BaseControlTheme
|
||||||
{
|
{
|
||||||
public const string ItemDecoratorPart = "PART_ItemDecorator";
|
public const string HeaderDecoratorPart = "PART_HeaderDecorator";
|
||||||
public const string MainContainerPart = "PART_MainContainer";
|
public const string MainContainerPart = "PART_MainContainer";
|
||||||
public const string ItemIconPresenterPart = "PART_ItemIconPresenter";
|
public const string ItemIconPresenterPart = "PART_ItemIconPresenter";
|
||||||
public const string ItemTextPresenterPart = "PART_ItemTextPresenter";
|
public const string ItemTextPresenterPart = "PART_ItemTextPresenter";
|
||||||
@ -35,7 +35,6 @@ internal class BaseNavMenuItemTheme : BaseControlTheme
|
|||||||
{
|
{
|
||||||
return new FuncControlTemplate<NavMenuItem>((item, scope) =>
|
return new FuncControlTemplate<NavMenuItem>((item, scope) =>
|
||||||
{
|
{
|
||||||
BuildInstanceStyles(item);
|
|
||||||
// 仅仅为了把 Popup 包进来,没有其他什么作用
|
// 仅仅为了把 Popup 包进来,没有其他什么作用
|
||||||
var layoutWrapper = new Panel();
|
var layoutWrapper = new Panel();
|
||||||
var header = BuildMenuItemContent(item, scope);
|
var header = BuildMenuItemContent(item, scope);
|
||||||
@ -49,13 +48,14 @@ internal class BaseNavMenuItemTheme : BaseControlTheme
|
|||||||
{
|
{
|
||||||
var headerFrame = new Border
|
var headerFrame = new Border
|
||||||
{
|
{
|
||||||
Name = ItemDecoratorPart
|
Name = HeaderDecoratorPart,
|
||||||
|
Transitions = new Transitions()
|
||||||
|
{
|
||||||
|
AnimationUtils.CreateTransition<SolidColorBrushTransition>(Border.BackgroundProperty),
|
||||||
|
AnimationUtils.CreateTransition<SolidColorBrushTransition>(TemplatedControl.ForegroundProperty)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
headerFrame.RegisterInNameScope(scope);
|
||||||
var transitions = new Transitions();
|
|
||||||
transitions.Add(AnimationUtils.CreateTransition<SolidColorBrushTransition>(Border.BackgroundProperty));
|
|
||||||
headerFrame.Transitions = transitions;
|
|
||||||
|
|
||||||
headerFrame.Child = BuildMenuItemInfoGrid(navMenuItem, scope);
|
headerFrame.Child = BuildMenuItemInfoGrid(navMenuItem, scope);
|
||||||
return headerFrame;
|
return headerFrame;
|
||||||
}
|
}
|
||||||
@ -84,17 +84,16 @@ internal class BaseNavMenuItemTheme : BaseControlTheme
|
|||||||
};
|
};
|
||||||
layout.RegisterInNameScope(scope);
|
layout.RegisterInNameScope(scope);
|
||||||
|
|
||||||
var iconPresenter = new Viewbox
|
var iconPresenter = new ContentPresenter()
|
||||||
{
|
{
|
||||||
Name = ItemIconPresenterPart,
|
Name = ItemIconPresenterPart,
|
||||||
HorizontalAlignment = HorizontalAlignment.Center,
|
HorizontalAlignment = HorizontalAlignment.Center,
|
||||||
VerticalAlignment = VerticalAlignment.Center,
|
VerticalAlignment = VerticalAlignment.Center,
|
||||||
Stretch = Stretch.Uniform
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Grid.SetColumn(iconPresenter, 0);
|
Grid.SetColumn(iconPresenter, 0);
|
||||||
iconPresenter.RegisterInNameScope(scope);
|
iconPresenter.RegisterInNameScope(scope);
|
||||||
CreateTemplateParentBinding(iconPresenter, Viewbox.ChildProperty, NavMenuItem.IconProperty);
|
CreateTemplateParentBinding(iconPresenter, ContentPresenter.ContentProperty, NavMenuItem.IconProperty);
|
||||||
TokenResourceBinder.CreateTokenBinding(iconPresenter, Layoutable.MarginProperty,
|
TokenResourceBinder.CreateTokenBinding(iconPresenter, Layoutable.MarginProperty,
|
||||||
NavMenuTokenResourceKey.ItemMargin);
|
NavMenuTokenResourceKey.ItemMargin);
|
||||||
TokenResourceBinder.CreateGlobalTokenBinding(iconPresenter, Layoutable.WidthProperty,
|
TokenResourceBinder.CreateGlobalTokenBinding(iconPresenter, Layoutable.WidthProperty,
|
||||||
@ -162,16 +161,8 @@ internal class BaseNavMenuItemTheme : BaseControlTheme
|
|||||||
Kind = "RightOutlined"
|
Kind = "RightOutlined"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
CreateTemplateParentBinding(menuIndicatorIcon, PathIcon.IsEnabledProperty, NavMenuItem.IsEnabledProperty);
|
CreateTemplateParentBinding(menuIndicatorIcon, PathIcon.IsEnabledProperty, NavMenuItem.IsEnabledProperty);
|
||||||
|
|
||||||
TokenResourceBinder.CreateGlobalTokenBinding(menuIndicatorIcon, PathIcon.NormalFilledBrushProperty,
|
|
||||||
NavMenuTokenResourceKey.ItemColor);
|
|
||||||
TokenResourceBinder.CreateGlobalTokenBinding(menuIndicatorIcon, PathIcon.SelectedFilledBrushProperty,
|
|
||||||
NavMenuTokenResourceKey.ItemSelectedColor);
|
|
||||||
TokenResourceBinder.CreateGlobalTokenBinding(menuIndicatorIcon, PathIcon.DisabledFilledBrushProperty,
|
|
||||||
NavMenuTokenResourceKey.ItemDisabledColor);
|
|
||||||
|
|
||||||
TokenResourceBinder.CreateGlobalTokenBinding(menuIndicatorIcon, Layoutable.WidthProperty,
|
TokenResourceBinder.CreateGlobalTokenBinding(menuIndicatorIcon, Layoutable.WidthProperty,
|
||||||
NavMenuTokenResourceKey.MenuArrowSize);
|
NavMenuTokenResourceKey.MenuArrowSize);
|
||||||
TokenResourceBinder.CreateGlobalTokenBinding(menuIndicatorIcon, Layoutable.HeightProperty,
|
TokenResourceBinder.CreateGlobalTokenBinding(menuIndicatorIcon, Layoutable.HeightProperty,
|
||||||
@ -199,17 +190,17 @@ internal class BaseNavMenuItemTheme : BaseControlTheme
|
|||||||
commonStyle.Add(keyGestureStyle);
|
commonStyle.Add(keyGestureStyle);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
var borderStyle = new Style(selector => selector.Nesting().Template().Name(ItemDecoratorPart));
|
var borderStyle = new Style(selector => selector.Nesting().Template().Name(HeaderDecoratorPart));
|
||||||
borderStyle.Add(Border.CursorProperty, new Cursor(StandardCursorType.Hand));
|
borderStyle.Add(Border.CursorProperty, new Cursor(StandardCursorType.Hand));
|
||||||
borderStyle.Add(Layoutable.MinHeightProperty, NavMenuTokenResourceKey.ItemHeight);
|
borderStyle.Add(Border.MinHeightProperty, NavMenuTokenResourceKey.ItemHeight);
|
||||||
borderStyle.Add(Decorator.PaddingProperty, NavMenuTokenResourceKey.ItemContentPadding);
|
borderStyle.Add(Border.PaddingProperty, NavMenuTokenResourceKey.ItemContentPadding);
|
||||||
borderStyle.Add(Border.BackgroundProperty, NavMenuTokenResourceKey.ItemBg);
|
borderStyle.Add(Border.BackgroundProperty, NavMenuTokenResourceKey.ItemBg);
|
||||||
borderStyle.Add(Border.CornerRadiusProperty, NavMenuTokenResourceKey.ItemBorderRadius);
|
borderStyle.Add(Border.CornerRadiusProperty, NavMenuTokenResourceKey.ItemBorderRadius);
|
||||||
commonStyle.Add(borderStyle);
|
commonStyle.Add(borderStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hover 状态
|
// Hover 状态
|
||||||
var hoverStyle = new Style(selector => selector.Nesting().Template().Name(ItemDecoratorPart).Class(StdPseudoClass.PointerOver));
|
var hoverStyle = new Style(selector => selector.Nesting().Template().Name(HeaderDecoratorPart).Class(StdPseudoClass.PointerOver));
|
||||||
hoverStyle.Add(TemplatedControl.ForegroundProperty, NavMenuTokenResourceKey.ItemHoverColor);
|
hoverStyle.Add(TemplatedControl.ForegroundProperty, NavMenuTokenResourceKey.ItemHoverColor);
|
||||||
hoverStyle.Add(Border.BackgroundProperty, NavMenuTokenResourceKey.ItemHoverBg);
|
hoverStyle.Add(Border.BackgroundProperty, NavMenuTokenResourceKey.ItemHoverBg);
|
||||||
commonStyle.Add(hoverStyle);
|
commonStyle.Add(hoverStyle);
|
||||||
@ -219,7 +210,7 @@ internal class BaseNavMenuItemTheme : BaseControlTheme
|
|||||||
{
|
{
|
||||||
var selectedStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.Selected));
|
var selectedStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.Selected));
|
||||||
{
|
{
|
||||||
var itemDecoratorStyle = new Style(selector => selector.Nesting().Template().Name(ItemDecoratorPart));
|
var itemDecoratorStyle = new Style(selector => selector.Nesting().Template().Name(HeaderDecoratorPart));
|
||||||
itemDecoratorStyle.Add(Border.BackgroundProperty, NavMenuTokenResourceKey.ItemSelectedBg);
|
itemDecoratorStyle.Add(Border.BackgroundProperty, NavMenuTokenResourceKey.ItemSelectedBg);
|
||||||
itemDecoratorStyle.Add(TemplatedControl.ForegroundProperty, NavMenuTokenResourceKey.ItemSelectedColor);
|
itemDecoratorStyle.Add(TemplatedControl.ForegroundProperty, NavMenuTokenResourceKey.ItemSelectedColor);
|
||||||
selectedStyle.Add(itemDecoratorStyle);
|
selectedStyle.Add(itemDecoratorStyle);
|
||||||
@ -232,7 +223,7 @@ internal class BaseNavMenuItemTheme : BaseControlTheme
|
|||||||
{
|
{
|
||||||
var selectedStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.Selected));
|
var selectedStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.Selected));
|
||||||
{
|
{
|
||||||
var itemDecoratorStyle = new Style(selector => selector.Nesting().Template().Name(ItemDecoratorPart));
|
var itemDecoratorStyle = new Style(selector => selector.Nesting().Template().Name(HeaderDecoratorPart));
|
||||||
itemDecoratorStyle.Add(TemplatedControl.ForegroundProperty, NavMenuTokenResourceKey.ItemSelectedColor);
|
itemDecoratorStyle.Add(TemplatedControl.ForegroundProperty, NavMenuTokenResourceKey.ItemSelectedColor);
|
||||||
selectedStyle.Add(itemDecoratorStyle);
|
selectedStyle.Add(itemDecoratorStyle);
|
||||||
}
|
}
|
||||||
@ -240,16 +231,85 @@ internal class BaseNavMenuItemTheme : BaseControlTheme
|
|||||||
}
|
}
|
||||||
commonStyle.Add(hasSubMenuStyle);
|
commonStyle.Add(hasSubMenuStyle);
|
||||||
Add(commonStyle);
|
Add(commonStyle);
|
||||||
|
|
||||||
|
BuildDarkCommonStyle();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BuildDarkCommonStyle()
|
||||||
|
{
|
||||||
|
var darkCommonStyle = new Style(selector => selector.Nesting().PropertyEquals(NavMenuItem.IsDarkStyleProperty, true));
|
||||||
|
darkCommonStyle.Add(NavMenuItem.ForegroundProperty, NavMenuTokenResourceKey.DarkItemColor);
|
||||||
|
|
||||||
|
{
|
||||||
|
var borderStyle = new Style(selector => selector.Nesting().Template().Name(HeaderDecoratorPart));
|
||||||
|
borderStyle.Add(Border.BackgroundProperty, NavMenuTokenResourceKey.DarkItemBg);
|
||||||
|
darkCommonStyle.Add(borderStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选中分两种,一种是有子菜单一种是没有子菜单
|
||||||
|
var hasNoSubMenuStyle = new Style(selector => selector.Nesting().PropertyEquals(NavMenuItem.HasSubMenuProperty, false));
|
||||||
|
{
|
||||||
|
// Hover 状态
|
||||||
|
var hoverStyle = new Style(selector => selector.Nesting().Template().Name(HeaderDecoratorPart).Class(StdPseudoClass.PointerOver));
|
||||||
|
hoverStyle.Add(TemplatedControl.ForegroundProperty, NavMenuTokenResourceKey.DarkItemHoverColor);
|
||||||
|
hoverStyle.Add(Border.BackgroundProperty, NavMenuTokenResourceKey.DarkItemHoverBg);
|
||||||
|
hasNoSubMenuStyle.Add(hoverStyle);
|
||||||
|
|
||||||
|
var selectedStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.Selected));
|
||||||
|
{
|
||||||
|
var itemDecoratorStyle = new Style(selector => selector.Nesting().Template().Name(HeaderDecoratorPart));
|
||||||
|
itemDecoratorStyle.Add(Border.BackgroundProperty, NavMenuTokenResourceKey.DarkItemSelectedBg);
|
||||||
|
itemDecoratorStyle.Add(TemplatedControl.ForegroundProperty, NavMenuTokenResourceKey.DarkItemSelectedColor);
|
||||||
|
selectedStyle.Add(itemDecoratorStyle);
|
||||||
|
}
|
||||||
|
hasNoSubMenuStyle.Add(selectedStyle);
|
||||||
|
}
|
||||||
|
darkCommonStyle.Add(hasNoSubMenuStyle);
|
||||||
|
|
||||||
|
var hasSubMenuStyle = new Style(selector => selector.Nesting().PropertyEquals(NavMenuItem.HasSubMenuProperty, true));
|
||||||
|
{
|
||||||
|
// Hover 状态
|
||||||
|
var hoverStyle = new Style(selector => selector.Nesting().Template().Name(HeaderDecoratorPart).Class(StdPseudoClass.PointerOver));
|
||||||
|
hoverStyle.Add(TemplatedControl.ForegroundProperty, NavMenuTokenResourceKey.DarkItemColor);
|
||||||
|
hoverStyle.Add(Border.BackgroundProperty, NavMenuTokenResourceKey.DarkItemBg);
|
||||||
|
hasSubMenuStyle.Add(hoverStyle);
|
||||||
|
|
||||||
|
var selectedStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.Selected));
|
||||||
|
{
|
||||||
|
var itemDecoratorStyle = new Style(selector => selector.Nesting().Template().Name(HeaderDecoratorPart));
|
||||||
|
itemDecoratorStyle.Add(TemplatedControl.ForegroundProperty, NavMenuTokenResourceKey.DarkItemSelectedColor);
|
||||||
|
selectedStyle.Add(itemDecoratorStyle);
|
||||||
|
}
|
||||||
|
hasSubMenuStyle.Add(selectedStyle);
|
||||||
|
}
|
||||||
|
darkCommonStyle.Add(hasSubMenuStyle);
|
||||||
|
|
||||||
|
Add(darkCommonStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BuildMenuIndicatorStyle()
|
private void BuildMenuIndicatorStyle()
|
||||||
{
|
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
var menuIndicatorStyle = new Style(selector => selector.Nesting().Template().Name(MenuIndicatorIconPart));
|
var menuIndicatorStyle = new Style(selector => selector.Nesting().Template().Name(MenuIndicatorIconPart));
|
||||||
menuIndicatorStyle.Add(Visual.IsVisibleProperty, true);
|
menuIndicatorStyle.Add(Visual.IsVisibleProperty, true);
|
||||||
|
menuIndicatorStyle.Add(PathIcon.NormalFilledBrushProperty, NavMenuTokenResourceKey.ItemColor);
|
||||||
|
menuIndicatorStyle.Add(PathIcon.SelectedFilledBrushProperty, NavMenuTokenResourceKey.ItemSelectedColor);
|
||||||
|
menuIndicatorStyle.Add(PathIcon.DisabledFilledBrushProperty, NavMenuTokenResourceKey.ItemDisabledColor);
|
||||||
|
// 设置颜色
|
||||||
|
|
||||||
Add(menuIndicatorStyle);
|
Add(menuIndicatorStyle);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
var darkCommonStyle = new Style(selector => selector.Nesting().PropertyEquals(NavMenuItem.IsDarkStyleProperty, true));
|
||||||
|
{
|
||||||
|
var menuIndicatorStyle = new Style(selector => selector.Nesting().Template().Name(MenuIndicatorIconPart));
|
||||||
|
menuIndicatorStyle.Add(PathIcon.NormalFilledBrushProperty, NavMenuTokenResourceKey.DarkItemColor);
|
||||||
|
menuIndicatorStyle.Add(PathIcon.SelectedFilledBrushProperty, NavMenuTokenResourceKey.DarkItemSelectedColor);
|
||||||
|
menuIndicatorStyle.Add(PathIcon.DisabledFilledBrushProperty, NavMenuTokenResourceKey.DarkItemDisabledColor);
|
||||||
|
darkCommonStyle.Add(menuIndicatorStyle);
|
||||||
|
}
|
||||||
|
Add(darkCommonStyle);
|
||||||
|
}
|
||||||
|
|
||||||
var selectedStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.Selected));
|
var selectedStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.Selected));
|
||||||
{
|
{
|
||||||
@ -258,7 +318,7 @@ internal class BaseNavMenuItemTheme : BaseControlTheme
|
|||||||
selectedStyle.Add(menuIndicatorStyle);
|
selectedStyle.Add(menuIndicatorStyle);
|
||||||
}
|
}
|
||||||
Add(selectedStyle);
|
Add(selectedStyle);
|
||||||
}
|
|
||||||
var hasNoSubMenuStyle = new Style(selector => selector.Nesting().PropertyEquals(NavMenuItem.HasSubMenuProperty, false));
|
var hasNoSubMenuStyle = new Style(selector => selector.Nesting().PropertyEquals(NavMenuItem.HasSubMenuProperty, false));
|
||||||
{
|
{
|
||||||
var menuIndicatorStyle = new Style(selector => selector.Nesting().Template().Name(MenuIndicatorIconPart));
|
var menuIndicatorStyle = new Style(selector => selector.Nesting().Template().Name(MenuIndicatorIconPart));
|
||||||
@ -271,41 +331,34 @@ internal class BaseNavMenuItemTheme : BaseControlTheme
|
|||||||
private void BuildMenuIconStyle()
|
private void BuildMenuIconStyle()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
var iconViewBoxStyle = new Style(selector => selector.Nesting().Template().Name(ItemIconPresenterPart));
|
var iconContentPresenterStyle = new Style(selector => selector.Nesting().Template().Name(ItemIconPresenterPart));
|
||||||
iconViewBoxStyle.Add(Visual.IsVisibleProperty, false);
|
iconContentPresenterStyle.Add(Visual.IsVisibleProperty, false);
|
||||||
Add(iconViewBoxStyle);
|
Add(iconContentPresenterStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
var hasIconStyle = new Style(selector => selector.Nesting().Class(":icon"));
|
var hasIconStyle = new Style(selector => selector.Nesting().Class(":icon"));
|
||||||
{
|
{
|
||||||
var iconViewBoxStyle = new Style(selector => selector.Nesting().Template().Name(ItemIconPresenterPart));
|
var iconContentPresenterStyle = new Style(selector => selector.Nesting().Template().Name(ItemIconPresenterPart));
|
||||||
iconViewBoxStyle.Add(Visual.IsVisibleProperty, true);
|
iconContentPresenterStyle.Add(Visual.IsVisibleProperty, true);
|
||||||
hasIconStyle.Add(iconViewBoxStyle);
|
hasIconStyle.Add(iconContentPresenterStyle);
|
||||||
}
|
}
|
||||||
Add(hasIconStyle);
|
Add(hasIconStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BuildDisabledStyle()
|
private void BuildDisabledStyle()
|
||||||
|
{
|
||||||
{
|
{
|
||||||
var disabledStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.Disabled));
|
var disabledStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.Disabled));
|
||||||
disabledStyle.Add(TemplatedControl.ForegroundProperty, NavMenuTokenResourceKey.ItemDisabledColor);
|
disabledStyle.Add(TemplatedControl.ForegroundProperty, NavMenuTokenResourceKey.ItemDisabledColor);
|
||||||
Add(disabledStyle);
|
Add(disabledStyle);
|
||||||
}
|
}
|
||||||
|
var darkStyle = new Style(selector => selector.Nesting().PropertyEquals(NavMenuItem.IsDarkStyleProperty, true));
|
||||||
protected override void BuildInstanceStyles(Control control)
|
|
||||||
{
|
{
|
||||||
{
|
var disabledStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.Disabled));
|
||||||
var iconStyle = new Style(selector => selector.Name(ThemeConstants.ItemIconPart));
|
disabledStyle.Add(TemplatedControl.ForegroundProperty, NavMenuTokenResourceKey.DarkItemDisabledColor);
|
||||||
iconStyle.Add(PathIcon.WidthProperty, NavMenuTokenResourceKey.ItemIconSize);
|
darkStyle.Add(disabledStyle);
|
||||||
iconStyle.Add(PathIcon.HeightProperty, NavMenuTokenResourceKey.ItemIconSize);
|
}
|
||||||
iconStyle.Add(PathIcon.NormalFilledBrushProperty, GlobalTokenResourceKey.ColorText);
|
Add(darkStyle);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -56,20 +56,21 @@ internal class InlineNavMenuItemTheme : BaseNavMenuItemTheme
|
|||||||
|
|
||||||
var headerContent = base.BuildMenuItemContent(navMenuItem, scope);
|
var headerContent = base.BuildMenuItemContent(navMenuItem, scope);
|
||||||
|
|
||||||
TokenResourceBinder.CreateTokenBinding(headerContent, Control.MarginProperty, NavMenuTokenResourceKey.VerticalItemsPanelSpacing, BindingPriority.Template,
|
|
||||||
(v) =>
|
|
||||||
{
|
|
||||||
if (v is double dval)
|
|
||||||
{
|
|
||||||
return new Thickness(0, 0, 0, dval);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Thickness();
|
|
||||||
});
|
|
||||||
var childItemsLayoutTransform = new LayoutTransformControl()
|
var childItemsLayoutTransform = new LayoutTransformControl()
|
||||||
{
|
{
|
||||||
Name = ChildItemsLayoutTransformPart,
|
Name = ChildItemsLayoutTransformPart,
|
||||||
};
|
};
|
||||||
|
TokenResourceBinder.CreateTokenBinding(childItemsLayoutTransform, LayoutTransformControl.MarginProperty,
|
||||||
|
NavMenuTokenResourceKey.VerticalItemsPanelSpacing, BindingPriority.Template,
|
||||||
|
(v) =>
|
||||||
|
{
|
||||||
|
if (v is double dval)
|
||||||
|
{
|
||||||
|
return new Thickness(0, dval, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Thickness();
|
||||||
|
});
|
||||||
childItemsLayoutTransform.RegisterInNameScope(scope);
|
childItemsLayoutTransform.RegisterInNameScope(scope);
|
||||||
|
|
||||||
var itemsPresenter = new ItemsPresenter
|
var itemsPresenter = new ItemsPresenter
|
||||||
@ -106,6 +107,10 @@ internal class InlineNavMenuItemTheme : BaseNavMenuItemTheme
|
|||||||
{
|
{
|
||||||
base.BuildStyles();
|
base.BuildStyles();
|
||||||
BuildMenuIndicatorStyle();
|
BuildMenuIndicatorStyle();
|
||||||
|
|
||||||
|
var itemsPanelStyle = new Style(selector => selector.Nesting().Template().Name(ChildItemsPresenterPart).Child().OfType<StackPanel>());
|
||||||
|
itemsPanelStyle.Add(StackPanel.SpacingProperty, NavMenuTokenResourceKey.VerticalItemsPanelSpacing);
|
||||||
|
Add(itemsPanelStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BuildMenuIndicatorStyle()
|
private void BuildMenuIndicatorStyle()
|
||||||
|
@ -147,13 +147,20 @@ public class NavMenu : NavMenuBase
|
|||||||
{
|
{
|
||||||
if (change.Property == ModeProperty)
|
if (change.Property == ModeProperty)
|
||||||
{
|
{
|
||||||
SetupItemContainerTheme(true);
|
HandleModeChanged();
|
||||||
SetupInteractionHandler(true);
|
|
||||||
}
|
}
|
||||||
UpdatePseudoClasses();
|
UpdatePseudoClasses();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void HandleModeChanged()
|
||||||
|
{
|
||||||
|
CloseChildItemsRecursively();
|
||||||
|
SetupItemContainerTheme(true);
|
||||||
|
RegenerateContainersRecursively();
|
||||||
|
SetupInteractionHandler(true);
|
||||||
|
}
|
||||||
|
|
||||||
protected override void PrepareContainerForItemOverride(Control element, object? item, int index)
|
protected override void PrepareContainerForItemOverride(Control element, object? item, int index)
|
||||||
{
|
{
|
||||||
base.PrepareContainerForItemOverride(element, item, index);
|
base.PrepareContainerForItemOverride(element, item, index);
|
||||||
@ -172,7 +179,9 @@ public class NavMenu : NavMenuBase
|
|||||||
BindUtils.RelayBind(this, ActiveBarWidthProperty, navMenuItem, NavMenuItem.ActiveBarWidthProperty);
|
BindUtils.RelayBind(this, ActiveBarWidthProperty, navMenuItem, NavMenuItem.ActiveBarWidthProperty);
|
||||||
}
|
}
|
||||||
BindUtils.RelayBind(this, ModeProperty, navMenuItem, NavMenuItem.ModeProperty);
|
BindUtils.RelayBind(this, ModeProperty, navMenuItem, NavMenuItem.ModeProperty);
|
||||||
|
BindUtils.RelayBind(this, IsDarkStyleProperty, navMenuItem, NavMenuItem.IsDarkStyleProperty);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdatePseudoClasses()
|
private void UpdatePseudoClasses()
|
||||||
@ -276,4 +285,48 @@ public class NavMenu : NavMenuBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CloseChildItemsRecursively()
|
||||||
|
{
|
||||||
|
CloseInlineItems();
|
||||||
|
foreach (var i in ((INavMenu)this).SubItems)
|
||||||
|
{
|
||||||
|
i.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RegenerateContainersRecursively()
|
||||||
|
{
|
||||||
|
foreach (var item in Items)
|
||||||
|
{
|
||||||
|
if (item is NavMenuItem navMenuItem)
|
||||||
|
{
|
||||||
|
navMenuItem.RegenerateContainers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CloseInlineItems()
|
||||||
|
{
|
||||||
|
foreach (var item in Items)
|
||||||
|
{
|
||||||
|
if (item is NavMenuItem navMenuItem)
|
||||||
|
{
|
||||||
|
CloseInlineItemRecursively(navMenuItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CloseInlineItemRecursively(NavMenuItem navMenuItem)
|
||||||
|
{
|
||||||
|
foreach (var item in navMenuItem.Items)
|
||||||
|
{
|
||||||
|
if (item is NavMenuItem childNavMenuItem)
|
||||||
|
{
|
||||||
|
CloseInlineItemRecursively(childNavMenuItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
navMenuItem.CloseInlineItem();
|
||||||
|
navMenuItem.IsSubMenuOpen = false;
|
||||||
|
}
|
||||||
}
|
}
|
@ -61,8 +61,8 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the <see cref="Icon"/> property.
|
/// Defines the <see cref="Icon"/> property.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly StyledProperty<object?> IconProperty =
|
public static readonly StyledProperty<PathIcon?> IconProperty =
|
||||||
AvaloniaProperty.Register<NavMenuItem, object?>(nameof(Icon));
|
AvaloniaProperty.Register<NavMenuItem, PathIcon?>(nameof(Icon));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the <see cref="InputGesture"/> property.
|
/// Defines the <see cref="InputGesture"/> property.
|
||||||
@ -126,7 +126,7 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the icon that appears in a <see cref="NavMenuItem"/>.
|
/// Gets or sets the icon that appears in a <see cref="NavMenuItem"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public object? Icon
|
public PathIcon? Icon
|
||||||
{
|
{
|
||||||
get => GetValue(IconProperty);
|
get => GetValue(IconProperty);
|
||||||
set => SetValue(IconProperty, value);
|
set => SetValue(IconProperty, value);
|
||||||
@ -285,6 +285,11 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
|||||||
o => o.InlineItemIndentUnit,
|
o => o.InlineItemIndentUnit,
|
||||||
(o, v) => o.InlineItemIndentUnit = v);
|
(o, v) => o.InlineItemIndentUnit = v);
|
||||||
|
|
||||||
|
internal static readonly DirectProperty<NavMenuItem, bool> IsDarkStyleProperty =
|
||||||
|
AvaloniaProperty.RegisterDirect<NavMenuItem, bool>(nameof(IsDarkStyle),
|
||||||
|
o => o.IsDarkStyle,
|
||||||
|
(o, v) => o.IsDarkStyle = v);
|
||||||
|
|
||||||
internal double ActiveBarWidth
|
internal double ActiveBarWidth
|
||||||
{
|
{
|
||||||
get => GetValue(ActiveBarWidthProperty);
|
get => GetValue(ActiveBarWidthProperty);
|
||||||
@ -340,6 +345,14 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
|||||||
set => SetAndRaise(InlineItemIndentUnitProperty, ref _inlineItemIndentUnit, value);
|
set => SetAndRaise(InlineItemIndentUnitProperty, ref _inlineItemIndentUnit, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool _isDarkStyle;
|
||||||
|
|
||||||
|
internal bool IsDarkStyle
|
||||||
|
{
|
||||||
|
get => _isDarkStyle;
|
||||||
|
set => SetAndRaise(IsDarkStyleProperty, ref _isDarkStyle, value);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 公共事件定义
|
#region 公共事件定义
|
||||||
@ -444,6 +457,7 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
|||||||
private Border? _horizontalFrame;
|
private Border? _horizontalFrame;
|
||||||
private IDisposable? _itemContainerThemeDisposable;
|
private IDisposable? _itemContainerThemeDisposable;
|
||||||
private LayoutTransformControl? _childItemsLayoutTransform;
|
private LayoutTransformControl? _childItemsLayoutTransform;
|
||||||
|
private Border? _headerFrame;
|
||||||
private bool _animating = false;
|
private bool _animating = false;
|
||||||
|
|
||||||
static NavMenuItem()
|
static NavMenuItem()
|
||||||
@ -639,7 +653,13 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
|||||||
_popup.DependencyResolver = null;
|
_popup.DependencyResolver = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
_popup = e.NameScope.Find<Popup>("PART_Popup");
|
_popup = e.NameScope.Find<Popup>(ThemeConstants.PopupPart);
|
||||||
|
_headerFrame = e.NameScope.Find<Border>(BaseNavMenuItemTheme.HeaderDecoratorPart);
|
||||||
|
if (_headerFrame is not null)
|
||||||
|
{
|
||||||
|
_headerFrame.PointerEntered += HandleHeaderFrameEnter;
|
||||||
|
_headerFrame.PointerExited += HandleHeaderFrameExit;
|
||||||
|
}
|
||||||
|
|
||||||
if (_popup != null)
|
if (_popup != null)
|
||||||
{
|
{
|
||||||
@ -670,6 +690,34 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void HandleHeaderFrameEnter(object? sender, PointerEventArgs args)
|
||||||
|
{
|
||||||
|
if (!IsDarkStyle || Icon is null || HasSubMenu)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Icon.IconMode = IconMode.Active;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleHeaderFrameExit(object? sender, PointerEventArgs args)
|
||||||
|
{
|
||||||
|
if (!IsDarkStyle || Icon is null || HasSubMenu)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsSelected)
|
||||||
|
{
|
||||||
|
Icon.IconMode = IconMode.Selected;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Icon.IconMode = IconMode.Normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
protected override void UpdateDataValidation(
|
protected override void UpdateDataValidation(
|
||||||
AvaloniaProperty property,
|
AvaloniaProperty property,
|
||||||
BindingValueType state,
|
BindingValueType state,
|
||||||
@ -816,10 +864,7 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
|||||||
{
|
{
|
||||||
SetupHorizontalEffectiveIndicatorWidth();
|
SetupHorizontalEffectiveIndicatorWidth();
|
||||||
}
|
}
|
||||||
else if (change.Property == IconProperty)
|
else if (change.Property == ModeProperty)
|
||||||
{
|
|
||||||
SetupItemIcon();
|
|
||||||
} else if (change.Property == ModeProperty)
|
|
||||||
{
|
{
|
||||||
SetupItemContainerTheme(true);
|
SetupItemContainerTheme(true);
|
||||||
} else if (change.Property == ItemCountProperty)
|
} else if (change.Property == ItemCountProperty)
|
||||||
@ -833,13 +878,35 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
|||||||
SetupEffectivePopupMinWidth();
|
SetupEffectivePopupMinWidth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (change.Property == IconProperty ||
|
||||||
|
change.Property == IsDarkStyleProperty)
|
||||||
|
{
|
||||||
|
SetupItemIcon();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetupItemIcon()
|
private void SetupItemIcon()
|
||||||
{
|
{
|
||||||
if (Icon is not null && Icon is PathIcon menuItemIcon)
|
if (Icon is not null && Icon is PathIcon menuItemIcon)
|
||||||
{
|
{
|
||||||
menuItemIcon.Name = ThemeConstants.ItemIconPart;
|
BindUtils.RelayBind(this, IsEnabledProperty, menuItemIcon, PathIcon.IsEnabledProperty);
|
||||||
|
TokenResourceBinder.CreateTokenBinding(menuItemIcon, PathIcon.WidthProperty, NavMenuTokenResourceKey.ItemIconSize);
|
||||||
|
TokenResourceBinder.CreateTokenBinding(menuItemIcon, PathIcon.HeightProperty, NavMenuTokenResourceKey.ItemIconSize);
|
||||||
|
|
||||||
|
if (IsDarkStyle)
|
||||||
|
{
|
||||||
|
TokenResourceBinder.CreateTokenBinding(menuItemIcon, PathIcon.NormalFilledBrushProperty, NavMenuTokenResourceKey.DarkItemColor);
|
||||||
|
TokenResourceBinder.CreateTokenBinding(menuItemIcon, PathIcon.SelectedFilledBrushProperty, NavMenuTokenResourceKey.DarkItemSelectedColor);
|
||||||
|
TokenResourceBinder.CreateTokenBinding(menuItemIcon, PathIcon.ActiveFilledBrushProperty, NavMenuTokenResourceKey.DarkItemHoverColor);
|
||||||
|
TokenResourceBinder.CreateTokenBinding(menuItemIcon, PathIcon.DisabledFilledBrushProperty, NavMenuTokenResourceKey.DarkItemDisabledColor);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TokenResourceBinder.CreateTokenBinding(menuItemIcon, PathIcon.NormalFilledBrushProperty, NavMenuTokenResourceKey.ItemColor);
|
||||||
|
TokenResourceBinder.CreateTokenBinding(menuItemIcon, PathIcon.SelectedFilledBrushProperty, NavMenuTokenResourceKey.ItemSelectedColor);
|
||||||
|
TokenResourceBinder.CreateTokenBinding(menuItemIcon, PathIcon.ActiveFilledBrushProperty, NavMenuTokenResourceKey.ItemHoverColor);
|
||||||
|
TokenResourceBinder.CreateTokenBinding(menuItemIcon, PathIcon.DisabledFilledBrushProperty, NavMenuTokenResourceKey.ItemDisabledColor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -901,7 +968,7 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
|||||||
/// <param name="e">The property change event.</param>
|
/// <param name="e">The property change event.</param>
|
||||||
private void IconChanged(AvaloniaPropertyChangedEventArgs e)
|
private void IconChanged(AvaloniaPropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
var (oldValue, newValue) = e.GetOldAndNewValue<object?>();
|
var (oldValue, newValue) = e.GetOldAndNewValue<PathIcon?>();
|
||||||
|
|
||||||
if (oldValue is ILogical oldLogical)
|
if (oldValue is ILogical oldLogical)
|
||||||
{
|
{
|
||||||
@ -988,7 +1055,7 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OpenInlineItem()
|
internal void OpenInlineItem()
|
||||||
{
|
{
|
||||||
if (_childItemsLayoutTransform is not null)
|
if (_childItemsLayoutTransform is not null)
|
||||||
{
|
{
|
||||||
@ -1011,7 +1078,7 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CloseInlineItem()
|
internal void CloseInlineItem()
|
||||||
{
|
{
|
||||||
if (_childItemsLayoutTransform is not null)
|
if (_childItemsLayoutTransform is not null)
|
||||||
{
|
{
|
||||||
@ -1030,6 +1097,7 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
|||||||
_animating = false;
|
_animating = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -1116,6 +1184,7 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
|||||||
if (element is NavMenuItem navMenuItem)
|
if (element is NavMenuItem navMenuItem)
|
||||||
{
|
{
|
||||||
BindUtils.RelayBind(this, ModeProperty, navMenuItem, ModeProperty);
|
BindUtils.RelayBind(this, ModeProperty, navMenuItem, ModeProperty);
|
||||||
|
BindUtils.RelayBind(this, IsDarkStyleProperty, navMenuItem, IsDarkStyleProperty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1131,6 +1200,20 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void RegenerateContainers()
|
||||||
|
{
|
||||||
|
foreach (var item in Items)
|
||||||
|
{
|
||||||
|
if (item is NavMenuItem childNavMenuItem)
|
||||||
|
{
|
||||||
|
childNavMenuItem.RegenerateContainers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemsPanel = new FuncTemplate<Panel?>(() => new StackPanel());
|
||||||
|
RefreshContainers();
|
||||||
|
}
|
||||||
|
|
||||||
private static int CalculateDistanceFromLogicalParent<T>(ILogical? logical, int @default = -1) where T : class
|
private static int CalculateDistanceFromLogicalParent<T>(ILogical? logical, int @default = -1) where T : class
|
||||||
{
|
{
|
||||||
var result = 0;
|
var result = 0;
|
||||||
@ -1143,4 +1226,5 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
|||||||
|
|
||||||
return logical != null ? result : @default;
|
return logical != null ? result : @default;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -13,6 +13,7 @@ namespace AtomUI.Controls;
|
|||||||
internal class NavMenuItemTheme : BaseNavMenuItemTheme
|
internal class NavMenuItemTheme : BaseNavMenuItemTheme
|
||||||
{
|
{
|
||||||
public const string ItemsPresenterPart = "PART_ItemsPresenter";
|
public const string ItemsPresenterPart = "PART_ItemsPresenter";
|
||||||
|
public const string PopupFramePart = "PART_PopupFrame";
|
||||||
|
|
||||||
public NavMenuItemTheme()
|
public NavMenuItemTheme()
|
||||||
: base(typeof(NavMenuItem))
|
: base(typeof(NavMenuItem))
|
||||||
@ -37,12 +38,16 @@ internal class NavMenuItemTheme : BaseNavMenuItemTheme
|
|||||||
Name = ThemeConstants.PopupPart,
|
Name = ThemeConstants.PopupPart,
|
||||||
WindowManagerAddShadowHint = false,
|
WindowManagerAddShadowHint = false,
|
||||||
IsLightDismissEnabled = false,
|
IsLightDismissEnabled = false,
|
||||||
Placement = PlacementMode.RightEdgeAlignedTop
|
Placement = PlacementMode.RightEdgeAlignedTop,
|
||||||
};
|
};
|
||||||
|
|
||||||
var border = new Border();
|
var border = new Border()
|
||||||
TokenResourceBinder.CreateTokenBinding(border, Border.BackgroundProperty,
|
{
|
||||||
GlobalTokenResourceKey.ColorBgContainer);
|
Name = PopupFramePart
|
||||||
|
};
|
||||||
|
|
||||||
|
TokenResourceBinder.CreateTokenBinding(popup, Popup.MarginToAnchorProperty,
|
||||||
|
NavMenuTokenResourceKey.TopLevelItemPopupMarginToAnchor);
|
||||||
TokenResourceBinder.CreateTokenBinding(border, Border.CornerRadiusProperty,
|
TokenResourceBinder.CreateTokenBinding(border, Border.CornerRadiusProperty,
|
||||||
NavMenuTokenResourceKey.MenuPopupBorderRadius);
|
NavMenuTokenResourceKey.MenuPopupBorderRadius);
|
||||||
TokenResourceBinder.CreateTokenBinding(border, Layoutable.MinWidthProperty,
|
TokenResourceBinder.CreateTokenBinding(border, Layoutable.MinWidthProperty,
|
||||||
@ -70,7 +75,7 @@ internal class NavMenuItemTheme : BaseNavMenuItemTheme
|
|||||||
NavMenuTokenResourceKey.TopLevelItemPopupMarginToAnchor);
|
NavMenuTokenResourceKey.TopLevelItemPopupMarginToAnchor);
|
||||||
TokenResourceBinder.CreateTokenBinding(popup, Popup.MaskShadowsProperty,
|
TokenResourceBinder.CreateTokenBinding(popup, Popup.MaskShadowsProperty,
|
||||||
NavMenuTokenResourceKey.MenuPopupBoxShadows);
|
NavMenuTokenResourceKey.MenuPopupBoxShadows);
|
||||||
CreateTemplateParentBinding(popup, Avalonia.Controls.Primitives.Popup.IsOpenProperty,
|
CreateTemplateParentBinding(popup, Popup.IsOpenProperty,
|
||||||
NavMenuItem.IsSubMenuOpenProperty, BindingMode.TwoWay);
|
NavMenuItem.IsSubMenuOpenProperty, BindingMode.TwoWay);
|
||||||
|
|
||||||
return popup;
|
return popup;
|
||||||
@ -82,5 +87,19 @@ internal class NavMenuItemTheme : BaseNavMenuItemTheme
|
|||||||
var itemsPanelStyle = new Style(selector => selector.Nesting().Template().Name(ItemsPresenterPart).Child().OfType<StackPanel>());
|
var itemsPanelStyle = new Style(selector => selector.Nesting().Template().Name(ItemsPresenterPart).Child().OfType<StackPanel>());
|
||||||
itemsPanelStyle.Add(StackPanel.SpacingProperty, NavMenuTokenResourceKey.VerticalItemsPanelSpacing);
|
itemsPanelStyle.Add(StackPanel.SpacingProperty, NavMenuTokenResourceKey.VerticalItemsPanelSpacing);
|
||||||
Add(itemsPanelStyle);
|
Add(itemsPanelStyle);
|
||||||
|
|
||||||
|
{
|
||||||
|
var popupFrameStyle = new Style(selector => selector.Nesting().Template().Name(PopupFramePart));
|
||||||
|
popupFrameStyle.Add(Border.BackgroundProperty, GlobalTokenResourceKey.ColorBgContainer);
|
||||||
|
Add(popupFrameStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
var darkCommonStyle = new Style(selector => selector.Nesting().PropertyEquals(NavMenuItem.IsDarkStyleProperty, true));
|
||||||
|
{
|
||||||
|
var popupFrameStyle = new Style(selector => selector.Nesting().Template().Name(PopupFramePart));
|
||||||
|
popupFrameStyle.Add(Border.BackgroundProperty, NavMenuTokenResourceKey.DarkItemBg);
|
||||||
|
darkCommonStyle.Add(popupFrameStyle);
|
||||||
|
}
|
||||||
|
Add(darkCommonStyle);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -72,7 +72,6 @@ internal class NavMenuTheme : BaseControlTheme
|
|||||||
var commonStyle = new Style(selector => selector.Nesting());
|
var commonStyle = new Style(selector => selector.Nesting());
|
||||||
|
|
||||||
commonStyle.Add(TemplatedControl.BorderBrushProperty, GlobalTokenResourceKey.ColorBorderSecondary);
|
commonStyle.Add(TemplatedControl.BorderBrushProperty, GlobalTokenResourceKey.ColorBorderSecondary);
|
||||||
commonStyle.Add(TemplatedControl.CornerRadiusProperty, GlobalTokenResourceKey.BorderRadius);
|
|
||||||
|
|
||||||
var horizontalStyle = new Style(selector => selector.Nesting().Class(NavMenu.HorizontalModePC));
|
var horizontalStyle = new Style(selector => selector.Nesting().Class(NavMenu.HorizontalModePC));
|
||||||
horizontalStyle.Add(NavMenu.BackgroundProperty, GlobalTokenResourceKey.ColorBgContainer);
|
horizontalStyle.Add(NavMenu.BackgroundProperty, GlobalTokenResourceKey.ColorBgContainer);
|
||||||
@ -92,6 +91,7 @@ internal class NavMenuTheme : BaseControlTheme
|
|||||||
|
|
||||||
var verticalOrInlineStyle = new Style(selector => Selectors.Or(selector.Nesting().Class(NavMenu.VerticalModePC),
|
var verticalOrInlineStyle = new Style(selector => Selectors.Or(selector.Nesting().Class(NavMenu.VerticalModePC),
|
||||||
selector.Nesting().Class(NavMenu.InlineModePC)));
|
selector.Nesting().Class(NavMenu.InlineModePC)));
|
||||||
|
verticalOrInlineStyle.Add(NavMenu.PaddingProperty, NavMenuTokenResourceKey.VerticalMenuContentPadding);
|
||||||
verticalOrInlineStyle.Add(NavMenu.HorizontalAlignmentProperty, HorizontalAlignment.Left);
|
verticalOrInlineStyle.Add(NavMenu.HorizontalAlignmentProperty, HorizontalAlignment.Left);
|
||||||
verticalOrInlineStyle.Add(NavMenu.VerticalAlignmentProperty, VerticalAlignment.Stretch);
|
verticalOrInlineStyle.Add(NavMenu.VerticalAlignmentProperty, VerticalAlignment.Stretch);
|
||||||
verticalOrInlineStyle.Add(NavMenu.BackgroundProperty, GlobalTokenResourceKey.ColorBgContainer);
|
verticalOrInlineStyle.Add(NavMenu.BackgroundProperty, GlobalTokenResourceKey.ColorBgContainer);
|
||||||
|
@ -190,6 +190,11 @@ internal class NavMenuToken : AbstractControlDesignToken
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public double VerticalItemsPanelSpacing { get; set; }
|
public double VerticalItemsPanelSpacing { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 垂直面板的内容内间距
|
||||||
|
/// </summary>
|
||||||
|
public Thickness VerticalMenuContentPadding { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 菜单项内部元素边距
|
/// 菜单项内部元素边距
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -444,7 +449,7 @@ internal class NavMenuToken : AbstractControlDesignToken
|
|||||||
MenuPopupMinWidth = 160d;
|
MenuPopupMinWidth = 160d;
|
||||||
MenuPopupMaxWidth = 800d;
|
MenuPopupMaxWidth = 800d;
|
||||||
MenuPopupMaxHeight = ItemHeight * 30;
|
MenuPopupMaxHeight = ItemHeight * 30;
|
||||||
TopLevelItemPopupMarginToAnchor = _globalToken.MarginXXS;
|
TopLevelItemPopupMarginToAnchor = _globalToken.MarginXS;
|
||||||
|
|
||||||
MenuPopupBg = _globalToken.ColorBgElevated;
|
MenuPopupBg = _globalToken.ColorBgElevated;
|
||||||
MenuPopupBorderRadius = _globalToken.BorderRadiusLG;
|
MenuPopupBorderRadius = _globalToken.BorderRadiusLG;
|
||||||
@ -453,5 +458,6 @@ internal class NavMenuToken : AbstractControlDesignToken
|
|||||||
VerticalItemsPanelSpacing = _globalToken.MarginXXS;
|
VerticalItemsPanelSpacing = _globalToken.MarginXXS;
|
||||||
|
|
||||||
InlineItemIndentUnit = ItemHeight / 2;
|
InlineItemIndentUnit = ItemHeight / 2;
|
||||||
|
VerticalMenuContentPadding = new Thickness(_globalToken.PaddingXXS);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -471,16 +471,16 @@ public sealed class PathIcon : Control, ICustomHitTest
|
|||||||
base.OnAttachedToLogicalTree(e);
|
base.OnAttachedToLogicalTree(e);
|
||||||
SetupTransitions();
|
SetupTransitions();
|
||||||
SetupRotateAnimation();
|
SetupRotateAnimation();
|
||||||
if (_sourceGeometriesData.Count == 0)
|
|
||||||
{
|
|
||||||
BuildSourceRenderData();
|
|
||||||
SetupFilledBrush();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
||||||
{
|
{
|
||||||
base.OnAttachedToVisualTree(e);
|
base.OnAttachedToVisualTree(e);
|
||||||
|
if (_sourceGeometriesData.Count == 0)
|
||||||
|
{
|
||||||
|
BuildSourceRenderData();
|
||||||
|
SetupFilledBrush();
|
||||||
|
}
|
||||||
if (_animation is not null && _animationCancellationTokenSource is null)
|
if (_animation is not null && _animationCancellationTokenSource is null)
|
||||||
{
|
{
|
||||||
_animationCancellationTokenSource = new CancellationTokenSource();
|
_animationCancellationTokenSource = new CancellationTokenSource();
|
||||||
@ -516,8 +516,7 @@ public sealed class PathIcon : Control, ICustomHitTest
|
|||||||
|
|
||||||
protected override Size ArrangeOverride(Size finalSize)
|
protected override Size ArrangeOverride(Size finalSize)
|
||||||
{
|
{
|
||||||
if (_sourceGeometriesData.Count != 0)
|
_transforms.Clear();
|
||||||
{
|
|
||||||
// This should probably use GetRenderBounds(strokeThickness) but then the calculations
|
// This should probably use GetRenderBounds(strokeThickness) but then the calculations
|
||||||
// will multiply the stroke thickness as well, which isn't correct.
|
// will multiply the stroke thickness as well, which isn't correct.
|
||||||
for (var i = 0; i < _sourceGeometriesData.Count; i++)
|
for (var i = 0; i < _sourceGeometriesData.Count; i++)
|
||||||
@ -530,14 +529,12 @@ public sealed class PathIcon : Control, ICustomHitTest
|
|||||||
return finalSize;
|
return finalSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Render(DrawingContext context)
|
public override void Render(DrawingContext context)
|
||||||
{
|
{
|
||||||
if (_sourceGeometriesData.Count > 0 &&
|
if (IsVisible &&
|
||||||
DesiredSize.Width > 0 &&
|
_sourceGeometriesData.Count > 0 &&
|
||||||
DesiredSize.Width > 0)
|
Bounds.Width > 0 &&
|
||||||
|
Bounds.Width > 0)
|
||||||
{
|
{
|
||||||
for (var i = 0; i < _sourceGeometriesData.Count; i++)
|
for (var i = 0; i < _sourceGeometriesData.Count; i++)
|
||||||
{
|
{
|
||||||
|
@ -70,8 +70,8 @@ public class Popup : AvaloniaPopup
|
|||||||
private IDisposable? _selfLightDismissDisposable;
|
private IDisposable? _selfLightDismissDisposable;
|
||||||
private bool _initialized;
|
private bool _initialized;
|
||||||
private ManagedPopupPositionerInfo? _managedPopupPositioner;
|
private ManagedPopupPositionerInfo? _managedPopupPositioner;
|
||||||
protected bool _animating;
|
|
||||||
private bool _isNeedFlip = true;
|
private bool _isNeedFlip = true;
|
||||||
|
protected bool _animating;
|
||||||
|
|
||||||
// 当鼠标移走了,但是打开动画还没完成,我们需要记录下来这个信号
|
// 当鼠标移走了,但是打开动画还没完成,我们需要记录下来这个信号
|
||||||
internal bool RequestCloseWhereAnimationCompleted { get; set; }
|
internal bool RequestCloseWhereAnimationCompleted { get; set; }
|
||||||
|
@ -309,7 +309,7 @@ public class ToggleSwitch : ToggleButton,
|
|||||||
_switchKnob.KnobSize = new Size(handleSize, handleSize);
|
_switchKnob.KnobSize = new Size(handleSize, handleSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
CalculateElementsOffset(DesiredSize);
|
CalculateElementsOffset(Bounds.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnPointerPressed(PointerPressedEventArgs e)
|
protected override void OnPointerPressed(PointerPressedEventArgs e)
|
||||||
@ -524,7 +524,7 @@ public class ToggleSwitch : ToggleButton,
|
|||||||
CollectStyleState();
|
CollectStyleState();
|
||||||
if (e.Property == IsCheckedProperty)
|
if (e.Property == IsCheckedProperty)
|
||||||
{
|
{
|
||||||
CalculateElementsOffset(DesiredSize);
|
CalculateElementsOffset(Bounds.Size);
|
||||||
WaveSpiritAdorner.ShowWaveAdorner(this, WaveType.PillWave);
|
WaveSpiritAdorner.ShowWaveAdorner(this, WaveType.PillWave);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -546,12 +546,12 @@ public class ToggleSwitch : ToggleButton,
|
|||||||
|
|
||||||
private Rect GrooveRect()
|
private Rect GrooveRect()
|
||||||
{
|
{
|
||||||
return new Rect(new Point(0, 0), DesiredSize);
|
return new Rect(new Point(0, 0), Bounds.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Rect HandleRect()
|
private Rect HandleRect()
|
||||||
{
|
{
|
||||||
return HandleRect(IsChecked.HasValue && IsChecked.Value, DesiredSize);
|
return HandleRect(IsChecked.HasValue && IsChecked.Value, Bounds.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Rect HandleRect(bool isChecked, Size controlSize)
|
private Rect HandleRect(bool isChecked, Size controlSize)
|
||||||
|
Loading…
Reference in New Issue
Block a user