@@ -5,6 +5,6 @@
|
||||
xmlns:u-semi="https://irihi.tech/ursa/themes/semi">
|
||||
<Application.Styles>
|
||||
<StyleInclude Source="avares://Semi.Avalonia/Themes/Index.axaml" />
|
||||
<u-semi:SemiTheme Locale="zh-CN"/>
|
||||
<u-semi:SemiTheme Locale="zh-CN" />
|
||||
</Application.Styles>
|
||||
</Application>
|
||||
56
demo/Ursa.Demo/DataTemplates/ToolBarItemTemplateSelector.cs
Normal file
56
demo/Ursa.Demo/DataTemplates/ToolBarItemTemplateSelector.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Avalonia.Data;
|
||||
using Ursa.Controls;
|
||||
using Ursa.Demo.ViewModels;
|
||||
|
||||
namespace Ursa.Demo.Converters;
|
||||
|
||||
public class ToolBarItemTemplateSelector: IDataTemplate
|
||||
{
|
||||
|
||||
public static ToolBarItemTemplateSelector Instance { get; } = new();
|
||||
public Control? Build(object? param)
|
||||
{
|
||||
if (param is null) return null;
|
||||
if (param is ToolBarSeparatorViewModel sep)
|
||||
{
|
||||
return new ToolBarSeparator();
|
||||
}
|
||||
if (param is ToolBarButtonItemViewModel vm)
|
||||
{
|
||||
return new Button()
|
||||
{
|
||||
[!ContentControl.ContentProperty] = new Binding() { Path = "Content" },
|
||||
[!Button.CommandProperty] = new Binding() { Path = "Command" },
|
||||
[!ToolBar.OverflowModeProperty] = new Binding(){Path = nameof(ToolBarItemViewModel.OverflowMode)},
|
||||
};
|
||||
}
|
||||
if (param is ToolBarCheckBoxItemViweModel cb)
|
||||
{
|
||||
return new CheckBox()
|
||||
{
|
||||
[!ContentControl.ContentProperty] = new Binding() { Path = "Content" },
|
||||
[!ToggleButton.IsCheckedProperty] = new Binding() { Path = "IsChecked" },
|
||||
[!ToolBar.OverflowModeProperty] = new Binding(){Path = nameof(ToolBarItemViewModel.OverflowMode)},
|
||||
};
|
||||
}
|
||||
if (param is ToolBarComboBoxItemViewModel combo)
|
||||
{
|
||||
return new ComboBox()
|
||||
{
|
||||
[!ContentControl.ContentProperty] = new Binding() { Path = "Content" },
|
||||
[!SelectingItemsControl.SelectedItemProperty] = new Binding() { Path = "SelectedItem" },
|
||||
[!ItemsControl.ItemsSourceProperty] = new Binding() { Path = "Items" },
|
||||
[!ToolBar.OverflowModeProperty] = new Binding(){Path = nameof(ToolBarItemViewModel.OverflowMode)},
|
||||
};
|
||||
}
|
||||
return new Button() { Content = "Undefined Item" };
|
||||
}
|
||||
|
||||
public bool Match(object? data)
|
||||
{
|
||||
return data is ToolBarItemViewModel;
|
||||
}
|
||||
}
|
||||
@@ -31,5 +31,6 @@ public static class MenuKeys
|
||||
public const string MenuKeyTimeline = "Timeline";
|
||||
public const string MenuKeyTwoTonePathIcon = "TwoTonePathIcon";
|
||||
public const string MenuKeyThemeToggler = "ThemeToggler";
|
||||
public const string MenuKeyToolBar = "ToolBar";
|
||||
|
||||
}
|
||||
136
demo/Ursa.Demo/Pages/ToolBarDemo.axaml
Normal file
136
demo/Ursa.Demo/Pages/ToolBarDemo.axaml
Normal file
@@ -0,0 +1,136 @@
|
||||
<UserControl
|
||||
x:Class="Ursa.Demo.Pages.ToolBarDemo"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:template="using:Ursa.Demo.Converters"
|
||||
xmlns:u="https://irihi.tech/ursa"
|
||||
xmlns:vm="using:Ursa.Demo.ViewModels"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
x:CompileBindings="True"
|
||||
x:DataType="vm:ToolBarDemoViewModel"
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<StreamGeometry x:Key="BoldGlyph">M13.5,15.5H10V12.5H13.5A1.5,1.5 0 0,1 15,14A1.5,1.5 0 0,1 13.5,15.5M10,6.5H13A1.5,1.5 0 0,1 14.5,8A1.5,1.5 0 0,1 13,9.5H10M15.6,10.79C16.57,10.11 17.25,9 17.25,8C17.25,5.74 15.5,4 13.25,4H7V18H14.04C16.14,18 17.75,16.3 17.75,14.21C17.75,12.69 16.89,11.39 15.6,10.79Z</StreamGeometry>
|
||||
<StreamGeometry x:Key="ItalicGlyph">M10,4V7H12.21L8.79,15H6V18H14V15H11.79L15.21,7H18V4H10Z</StreamGeometry>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid ColumnDefinitions="Auto, Auto, *" RowDefinitions="Auto, Auto, *">
|
||||
<u:EnumSelector Name="Orientation" EnumType="Orientation" />
|
||||
<u:ToolBar
|
||||
DockPanel.Dock="Top"
|
||||
Header="Hello World"
|
||||
Orientation="{Binding #Orientation.Value}">
|
||||
<Button u:ToolBar.OverflowMode="Never" Content="Button 1" />
|
||||
<u:ToolBarSeparator />
|
||||
<Button u:ToolBar.OverflowMode="AsNeeded" Content="Button 2" />
|
||||
<Button u:ToolBar.OverflowMode="AsNeeded" Content="Button 3" />
|
||||
<ToggleButton Content="Toggle" />
|
||||
<u:ToolBar.Styles>
|
||||
<Style Selector="u|ToolBar[Orientation=Vertical]">
|
||||
<Setter Property="Grid.Row" Value="1" />
|
||||
<Setter Property="Grid.Column" Value="1" />
|
||||
<Setter Property="Grid.RowSpan" Value="2" />
|
||||
<Setter Property="Grid.ColumnSpan" Value="1" />
|
||||
</Style>
|
||||
<Style Selector="u|ToolBar[Orientation=Horizontal]">
|
||||
<Setter Property="Grid.Row" Value="1" />
|
||||
<Setter Property="Grid.Column" Value="1" />
|
||||
<Setter Property="Grid.RowSpan" Value="1" />
|
||||
<Setter Property="Grid.ColumnSpan" Value="3" />
|
||||
</Style>
|
||||
</u:ToolBar.Styles>
|
||||
</u:ToolBar>
|
||||
<u:ToolBar
|
||||
DockPanel.Dock="Top"
|
||||
ItemsSource="{Binding Items}"
|
||||
Orientation="{Binding #Orientation.Value}">
|
||||
<u:ToolBar.ItemTemplate>
|
||||
<template:ToolBarItemTemplateSelector />
|
||||
</u:ToolBar.ItemTemplate>
|
||||
<u:ToolBar.Styles>
|
||||
<Style Selector="u|ToolBar[Orientation=Vertical]">
|
||||
<Setter Property="Grid.Row" Value="1" />
|
||||
<Setter Property="Grid.Column" Value="0" />
|
||||
<Setter Property="Grid.RowSpan" Value="2" />
|
||||
<Setter Property="Grid.ColumnSpan" Value="1" />
|
||||
</Style>
|
||||
<Style Selector="u|ToolBar[Orientation=Horizontal]">
|
||||
<Setter Property="Grid.Row" Value="0" />
|
||||
<Setter Property="Grid.Column" Value="1" />
|
||||
<Setter Property="Grid.RowSpan" Value="1" />
|
||||
<Setter Property="Grid.ColumnSpan" Value="3" />
|
||||
</Style>
|
||||
</u:ToolBar.Styles>
|
||||
</u:ToolBar>
|
||||
<Grid
|
||||
Grid.Row="2"
|
||||
Grid.Column="2"
|
||||
RowDefinitions="Auto, *">
|
||||
<u:ToolBar Margin="16">
|
||||
<ToggleButton Name="bold">
|
||||
<PathIcon
|
||||
Width="16"
|
||||
Height="16"
|
||||
Data="{DynamicResource BoldGlyph}" />
|
||||
</ToggleButton>
|
||||
<ToggleButton Name="italic">
|
||||
<PathIcon
|
||||
Width="16"
|
||||
Height="16"
|
||||
Data="{DynamicResource ItalicGlyph}" />
|
||||
</ToggleButton>
|
||||
<u:ToolBarSeparator />
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="8,0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Text="Font Size" />
|
||||
<ComboBox
|
||||
Name="size"
|
||||
Width="90"
|
||||
SelectedIndex="0">
|
||||
<x:Double>8</x:Double>
|
||||
<x:Double>16</x:Double>
|
||||
<x:Double>32</x:Double>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<u:ToolBar.Styles>
|
||||
<Style Selector="u|ToolBar[Orientation=Horizontal]">
|
||||
<Setter Property="Grid.Row" Value="2" />
|
||||
<Setter Property="Grid.Column" Value="1" />
|
||||
<Setter Property="Grid.RowSpan" Value="1" />
|
||||
<Setter Property="Grid.ColumnSpan" Value="3" />
|
||||
</Style>
|
||||
</u:ToolBar.Styles>
|
||||
|
||||
</u:ToolBar>
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Classes.Bold="{Binding #bold.IsChecked}"
|
||||
Classes.Italic="{Binding #italic.IsChecked}"
|
||||
FontSize="{Binding #size.SelectedItem}"
|
||||
Text="Hello Ursa Avalonia">
|
||||
<TextBlock.Styles>
|
||||
<Style Selector="TextBlock">
|
||||
<Setter Property="FontWeight" Value="Regular" />
|
||||
<Setter Property="FontSize" Value="8" />
|
||||
<Setter Property="FontStyle" Value="Normal" />
|
||||
</Style>
|
||||
<Style Selector="TextBlock.Bold">
|
||||
<Setter Property="FontWeight" Value="Bold" />
|
||||
</Style>
|
||||
<Style Selector="TextBlock.Italic">
|
||||
<Setter Property="FontStyle" Value="Italic" />
|
||||
</Style>
|
||||
</TextBlock.Styles>
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
13
demo/Ursa.Demo/Pages/ToolBarDemo.axaml.cs
Normal file
13
demo/Ursa.Demo/Pages/ToolBarDemo.axaml.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
namespace Ursa.Demo.Pages;
|
||||
|
||||
public partial class ToolBarDemo : UserControl
|
||||
{
|
||||
public ToolBarDemo()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,7 @@ public class MainViewViewModel : ViewModelBase
|
||||
MenuKeys.MenuKeyTimeline => new TimelineDemoViewModel(),
|
||||
MenuKeys.MenuKeyTwoTonePathIcon => new TwoTonePathIconDemoViewModel(),
|
||||
MenuKeys.MenuKeyThemeToggler => new ThemeTogglerDemoViewModel(),
|
||||
MenuKeys.MenuKeyToolBar => new ToolBarDemoViewModel(),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,7 @@ public class MenuViewModel: ViewModelBase
|
||||
new() { MenuHeader = "Theme Toggler", Key = MenuKeys.MenuKeyThemeToggler },
|
||||
new() { MenuHeader = "Timeline", Key = MenuKeys.MenuKeyTimeline, Status = "Updated" },
|
||||
new() { MenuHeader = "TwoTonePathIcon", Key = MenuKeys.MenuKeyTwoTonePathIcon, Status = "New"},
|
||||
new() { MenuHeader = "ToolBar", Key = MenuKeys.MenuKeyToolBar, Status = "New" }
|
||||
};
|
||||
}
|
||||
}
|
||||
83
demo/Ursa.Demo/ViewModels/ToolBarDemoViewModel.cs
Normal file
83
demo/Ursa.Demo/ViewModels/ToolBarDemoViewModel.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Windows.Input;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Ursa.Controls;
|
||||
|
||||
namespace Ursa.Demo.ViewModels;
|
||||
|
||||
public partial class ToolBarDemoViewModel: ObservableObject
|
||||
{
|
||||
public ObservableCollection<ToolBarItemViewModel> Items { get; set; }
|
||||
public ToolBarDemoViewModel()
|
||||
{
|
||||
Items = new()
|
||||
{
|
||||
new ToolBarButtonItemViewModel() { Content = "New", OverflowMode = OverflowMode.AsNeeded},
|
||||
new ToolBarButtonItemViewModel() { Content = "Open" },
|
||||
new ToolBarButtonItemViewModel() { Content = "Save1" },
|
||||
new ToolBarButtonItemViewModel() { Content = "Save2" },
|
||||
new ToolBarSeparatorViewModel(),
|
||||
new ToolBarButtonItemViewModel() { Content = "Save3" },
|
||||
new ToolBarButtonItemViewModel() { Content = "Save4" },
|
||||
new ToolBarButtonItemViewModel() { Content = "Save5" },
|
||||
new ToolBarButtonItemViewModel() { Content = "Save6" },
|
||||
new ToolBarButtonItemViewModel() { Content = "Save7" },
|
||||
new ToolBarSeparatorViewModel(),
|
||||
new ToolBarButtonItemViewModel() { Content = "Save8" },
|
||||
new ToolBarCheckBoxItemViweModel() { Content = "Bold" },
|
||||
new ToolBarCheckBoxItemViweModel() { Content = "Italic", OverflowMode = OverflowMode.Never},
|
||||
new ToolBarComboBoxItemViewModel() { Content = "Font Size", Items = new (){ "10", "12", "14" } }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class ToolBarItemViewModel: ObservableObject
|
||||
{
|
||||
public OverflowMode OverflowMode { get; set; }
|
||||
}
|
||||
|
||||
public class ToolBarButtonItemViewModel: ToolBarItemViewModel
|
||||
{
|
||||
public string Content { get; set; }
|
||||
public ICommand Command { get; set; }
|
||||
|
||||
public ToolBarButtonItemViewModel()
|
||||
{
|
||||
Command = new AsyncRelayCommand(async () => { await MessageBox.ShowOverlayAsync(Content); });
|
||||
}
|
||||
}
|
||||
|
||||
public class ToolBarCheckBoxItemViweModel: ToolBarItemViewModel
|
||||
{
|
||||
public string Content { get; set; }
|
||||
public bool IsChecked { get; set; }
|
||||
public ICommand Command { get; set; }
|
||||
|
||||
public ToolBarCheckBoxItemViweModel()
|
||||
{
|
||||
Command = new AsyncRelayCommand(async () => { await MessageBox.ShowOverlayAsync(Content); });
|
||||
}
|
||||
}
|
||||
|
||||
public class ToolBarComboBoxItemViewModel: ToolBarItemViewModel
|
||||
{
|
||||
public string Content { get; set; }
|
||||
public ObservableCollection<string> Items { get; set; }
|
||||
|
||||
private string _selectedItem;
|
||||
public string SelectedItem
|
||||
{
|
||||
get => _selectedItem;
|
||||
set
|
||||
{
|
||||
SetProperty(ref _selectedItem, value);
|
||||
MessageBox.ShowOverlayAsync(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ToolBarSeparatorViewModel: ToolBarItemViewModel
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
|
||||
namespace Ursa.Demo.Views;
|
||||
|
||||
|
||||
137
src/Ursa.Themes.Semi/Controls/ToolBar.axaml
Normal file
137
src/Ursa.Themes.Semi/Controls/ToolBar.axaml
Normal file
@@ -0,0 +1,137 @@
|
||||
<ResourceDictionary
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:u="https://irihi.tech/ursa">
|
||||
<!-- Add Resources Here -->
|
||||
<ControlTheme x:Key="ToolBarExpandToggleButton" TargetType="ToggleButton">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate>
|
||||
<ContentPresenter
|
||||
x:Name="PART_ContentPresenter"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Content="{TemplateBinding Content}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}"
|
||||
RecognizesAccessKey="True"
|
||||
TextElement.FontSize="{TemplateBinding FontSize}"
|
||||
TextElement.FontWeight="{TemplateBinding FontWeight}"
|
||||
UseLayoutRounding="False" />
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
</ControlTheme>
|
||||
<ControlTheme x:Key="{x:Type u:ToolBar}" TargetType="u:ToolBar">
|
||||
<Setter Property="HorizontalAlignment" Value="Left"/>
|
||||
<Setter Property="VerticalAlignment" Value="Top"/>
|
||||
<Setter Property="ItemsPanel">
|
||||
<ItemsPanelTemplate>
|
||||
<u:ToolBarPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</Setter>
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate TargetType="u:ToolBar">
|
||||
<Border
|
||||
Padding="2"
|
||||
Margin="0"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalAlignment}"
|
||||
CornerRadius="4"
|
||||
Theme="{DynamicResource CardBorder}">
|
||||
<DockPanel LastChildFill="True">
|
||||
<ContentPresenter
|
||||
Name="PART_Header"
|
||||
Margin="8,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Content="{TemplateBinding Header}"
|
||||
ContentTemplate="{TemplateBinding HeaderTemplate}"
|
||||
DockPanel.Dock="Left"
|
||||
Foreground="{DynamicResource SemiColorText2}"
|
||||
IsVisible="{TemplateBinding Header,
|
||||
Converter={x:Static ObjectConverters.IsNotNull}}" />
|
||||
<Panel Name="PART_PopupButtonPanel" DockPanel.Dock="Right">
|
||||
<ToggleButton
|
||||
Name="button"
|
||||
Padding="8,0"
|
||||
VerticalAlignment="Stretch"
|
||||
IsVisible="False"
|
||||
Theme="{DynamicResource ToolBarExpandToggleButton}">
|
||||
<PathIcon
|
||||
Name="PART_Icon"
|
||||
Height="12"
|
||||
Foreground="{DynamicResource SemiColorText2}"
|
||||
Data="{DynamicResource ToolBarHorizontalMoreGlyph}" />
|
||||
</ToggleButton>
|
||||
<Popup
|
||||
IsLightDismissEnabled="True"
|
||||
IsOpen="{Binding #button.IsChecked, Mode=TwoWay}"
|
||||
Placement="{TemplateBinding PopupPlacement}"
|
||||
PlacementTarget="{Binding #button}">
|
||||
<Border Padding="2" Theme="{DynamicResource CardBorder}">
|
||||
<StackPanel Name="{x:Static u:ToolBar.PART_OverflowPanel}" />
|
||||
</Border>
|
||||
</Popup>
|
||||
</Panel>
|
||||
<ItemsPresenter
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
ItemsPanel="{TemplateBinding ItemsPanel}" />
|
||||
</DockPanel>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
<Style Selector="^[Orientation=Horizontal]">
|
||||
<Setter Property="PopupPlacement" Value="BottomEdgeAlignedLeft" />
|
||||
</Style>
|
||||
<Style Selector="^[Orientation=Vertical]">
|
||||
<Setter Property="PopupPlacement" Value="RightEdgeAlignedTop" />
|
||||
<Style Selector="^ /template/ ContentPresenter#PART_Header">
|
||||
<Setter Property="DockPanel.Dock" Value="Top" />
|
||||
<Setter Property="HorizontalAlignment" Value="Center" />
|
||||
<Setter Property="VerticalAlignment" Value="Top" />
|
||||
<Setter Property="Margin" Value="0 8" />
|
||||
</Style>
|
||||
<Style Selector="^ /template/ Panel#PART_PopupButtonPanel">
|
||||
<Setter Property="DockPanel.Dock" Value="Bottom" />
|
||||
</Style>
|
||||
<Style Selector="^ /template/ ToggleButton#button">
|
||||
<Setter Property="Padding" Value="0 8" />
|
||||
</Style>
|
||||
<Style Selector="^ /template/ PathIcon#PART_Icon">
|
||||
<Setter Property="Data" Value="{DynamicResource ToolBarVerticalMoreGlyph}" />
|
||||
<Setter Property="Width" Value="12" />
|
||||
<Setter Property="Height" Value="{x:Static x:Double.NaN}" />
|
||||
</Style>
|
||||
</Style>
|
||||
<Style Selector="^:overflow /template/ ToggleButton#button">
|
||||
<Setter Property="IsVisible" Value="True" />
|
||||
</Style>
|
||||
</ControlTheme>
|
||||
|
||||
<ControlTheme x:Key="{x:Type u:ToolBarSeparator}" TargetType="u:ToolBarSeparator">
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate>
|
||||
<Rectangle
|
||||
Name="PART_Rect"
|
||||
Margin="4"
|
||||
Fill="{DynamicResource SemiColorBorder}" />
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
<Style Selector="^ /template/ Rectangle#PART_Rect">
|
||||
<Setter Property="Width" Value="1" />
|
||||
<Setter Property="VerticalAlignment" Value="Stretch" />
|
||||
<Setter Property="HorizontalAlignment" Value="Center" />
|
||||
</Style>
|
||||
<Style Selector="^:vertical /template/ Rectangle#PART_Rect">
|
||||
<Setter Property="Height" Value="1" />
|
||||
<Setter Property="Width" Value="{x:Static x:Double.NaN}" />
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
</Style>
|
||||
</ControlTheme>
|
||||
</ResourceDictionary>
|
||||
@@ -30,5 +30,6 @@
|
||||
<ResourceInclude Source="ThemeSelector.axaml" />
|
||||
<ResourceInclude Source="Timeline.axaml" />
|
||||
<ResourceInclude Source="TwoTonePathIcon.axaml" />
|
||||
<ResourceInclude Source="ToolBar.axaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
|
||||
26
src/Ursa.Themes.Semi/Styles/ToolBar.axaml
Normal file
26
src/Ursa.Themes.Semi/Styles/ToolBar.axaml
Normal file
@@ -0,0 +1,26 @@
|
||||
<Styles xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:u="https://irihi.tech/ursa">
|
||||
<Design.PreviewWith>
|
||||
<Border Padding="20">
|
||||
<!-- Add Controls for Previewer Here -->
|
||||
</Border>
|
||||
</Design.PreviewWith>
|
||||
<Style Selector="u|ToolBar Button">
|
||||
<Setter Property="Theme" Value="{DynamicResource BorderlessButton}"></Setter>
|
||||
<Setter Property="FontWeight" Value="Regular" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource SemiColorText0}"></Setter>
|
||||
</Style>
|
||||
<Style Selector="u|ToolBar CheckBox">
|
||||
<Setter Property="Margin" Value="8 0" />
|
||||
</Style>
|
||||
<Style Selector="u|ToolBar ToggleButton">
|
||||
<Setter Property="FontWeight" Value="Regular" />
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource SemiColorText0}"/>
|
||||
</Style>
|
||||
<Style Selector="u|ToolBar ComboBox">
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||
</Style>
|
||||
<!-- Add Styles Here -->
|
||||
</Styles>
|
||||
@@ -5,5 +5,6 @@
|
||||
</Border>
|
||||
</Design.PreviewWith>
|
||||
<StyleInclude Source="ButtonGroup.axaml" />
|
||||
<StyleInclude Source="ToolBar.axaml"/>
|
||||
<!-- Add Styles Here -->
|
||||
</Styles>
|
||||
|
||||
6
src/Ursa.Themes.Semi/Themes/Shared/ToolBar.axaml
Normal file
6
src/Ursa.Themes.Semi/Themes/Shared/ToolBar.axaml
Normal file
@@ -0,0 +1,6 @@
|
||||
<ResourceDictionary xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<!-- Add Resources Here -->
|
||||
<StreamGeometry x:Key="ToolBarHorizontalMoreGlyph">M12,16A2,2 0 0,1 14,18A2,2 0 0,1 12,20A2,2 0 0,1 10,18A2,2 0 0,1 12,16M12,10A2,2 0 0,1 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12A2,2 0 0,1 12,10M12,4A2,2 0 0,1 14,6A2,2 0 0,1 12,8A2,2 0 0,1 10,6A2,2 0 0,1 12,4Z</StreamGeometry>
|
||||
<StreamGeometry x:Key="ToolBarVerticalMoreGlyph">M16,12A2,2 0 0,1 18,10A2,2 0 0,1 20,12A2,2 0 0,1 18,14A2,2 0 0,1 16,12M10,12A2,2 0 0,1 12,10A2,2 0 0,1 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12M4,12A2,2 0 0,1 6,10A2,2 0 0,1 8,12A2,2 0 0,1 6,14A2,2 0 0,1 4,12Z</StreamGeometry>
|
||||
</ResourceDictionary>
|
||||
@@ -15,5 +15,6 @@
|
||||
<MergeResourceInclude Source="Pagination.axaml" />
|
||||
<MergeResourceInclude Source="TagInput.axaml" />
|
||||
<MergeResourceInclude Source="ThemeSelector.axaml" />
|
||||
<MergeResourceInclude Source="ToolBar.axaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
|
||||
8
src/Ursa/Controls/ToolBar/OverflowMode.cs
Normal file
8
src/Ursa/Controls/ToolBar/OverflowMode.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Ursa.Controls;
|
||||
|
||||
public enum OverflowMode
|
||||
{
|
||||
AsNeeded,
|
||||
Always,
|
||||
Never
|
||||
}
|
||||
101
src/Ursa/Controls/ToolBar/ToolBar.cs
Normal file
101
src/Ursa/Controls/ToolBar/ToolBar.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Metadata;
|
||||
using Avalonia.Controls.Presenters;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Markup.Xaml.Templates;
|
||||
using Irihi.Avalonia.Shared.Helpers;
|
||||
|
||||
namespace Ursa.Controls;
|
||||
|
||||
[PseudoClasses(PC_Overflow)]
|
||||
[TemplatePart(PART_OverflowPanel, typeof(Panel))]
|
||||
public class ToolBar: HeaderedItemsControl
|
||||
{
|
||||
public const string PART_OverflowPanel = "PART_OverflowPanel";
|
||||
public const string PC_Overflow = ":overflow";
|
||||
|
||||
internal Panel? OverflowPanel { get; private set; }
|
||||
|
||||
private static readonly ITemplate<Panel?> DefaultTemplate =
|
||||
new FuncTemplate<Panel?>(() => new ToolBarPanel() { Orientation = Orientation.Horizontal });
|
||||
|
||||
public static readonly StyledProperty<Orientation> OrientationProperty =
|
||||
StackPanel.OrientationProperty.AddOwner<ToolBar>();
|
||||
|
||||
public Orientation Orientation
|
||||
{
|
||||
get => GetValue(OrientationProperty);
|
||||
set => SetValue(OrientationProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<PlacementMode> PopupPlacementProperty =
|
||||
Popup.PlacementProperty.AddOwner<ToolBar>();
|
||||
|
||||
public PlacementMode PopupPlacement
|
||||
{
|
||||
get => GetValue(PopupPlacementProperty);
|
||||
set => SetValue(PopupPlacementProperty, value);
|
||||
}
|
||||
|
||||
public static readonly AttachedProperty<OverflowMode> OverflowModeProperty =
|
||||
AvaloniaProperty.RegisterAttached<ToolBar, Control, OverflowMode>("OverflowMode");
|
||||
|
||||
public static void SetOverflowMode(Control obj, OverflowMode value) => obj.SetValue(OverflowModeProperty, value);
|
||||
public static OverflowMode GetOverflowMode(Control obj) => obj.GetValue(OverflowModeProperty);
|
||||
|
||||
internal static readonly AttachedProperty<bool> IsOverflowItemProperty =
|
||||
AvaloniaProperty.RegisterAttached<ToolBar, Control, bool>("IsOverflowItem");
|
||||
|
||||
internal static void SetIsOverflowItem(Control obj, bool value) => obj.SetValue(IsOverflowItemProperty, value);
|
||||
internal static bool GetIsOverflowItem(Control obj) => obj.GetValue(IsOverflowItemProperty);
|
||||
|
||||
private bool _hasOverflowItems;
|
||||
internal bool HasOverflowItems
|
||||
{
|
||||
get => _hasOverflowItems;
|
||||
set
|
||||
{
|
||||
_hasOverflowItems = value;
|
||||
PseudoClasses.Set(PC_Overflow, value);
|
||||
}
|
||||
}
|
||||
|
||||
static ToolBar()
|
||||
{
|
||||
IsTabStopProperty.OverrideDefaultValue<ToolBar>(false);
|
||||
ItemsPanelProperty.OverrideDefaultValue<ToolBar>(DefaultTemplate);
|
||||
OrientationProperty.OverrideDefaultValue<ToolBar>(Orientation.Horizontal);
|
||||
// TODO: use helper method after merged and upgrade helper dependency.
|
||||
IsOverflowItemProperty.Changed.AddClassHandler<Control, bool>((o, e) =>
|
||||
{
|
||||
PseudolassesExtensions.Set(o.Classes, PC_Overflow, e.NewValue.Value);
|
||||
});
|
||||
}
|
||||
|
||||
protected override bool NeedsContainerOverride(object? item, int index, out object? recycleKey)
|
||||
{
|
||||
return NeedsContainer<Control>(item, out recycleKey);
|
||||
}
|
||||
|
||||
protected override Control CreateContainerForItemOverride(object? item, int index, object? recycleKey)
|
||||
{
|
||||
if(item is Control c)
|
||||
{
|
||||
return c;
|
||||
}
|
||||
if(ItemTemplate is not null && ItemTemplate.Match(item))
|
||||
{
|
||||
return ItemTemplate.Build(item)?? new ContentPresenter();
|
||||
}
|
||||
return new ContentPresenter();
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
base.OnApplyTemplate(e);
|
||||
OverflowPanel = e.NameScope.Find<Panel>(PART_OverflowPanel);
|
||||
}
|
||||
}
|
||||
151
src/Ursa/Controls/ToolBar/ToolBarPanel.cs
Normal file
151
src/Ursa/Controls/ToolBar/ToolBarPanel.cs
Normal file
@@ -0,0 +1,151 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.LogicalTree;
|
||||
|
||||
namespace Ursa.Controls;
|
||||
|
||||
public class ToolBarPanel: StackPanel
|
||||
{
|
||||
private ToolBar? _parent;
|
||||
private Panel? _overflowPanel;
|
||||
|
||||
private Panel? OverflowPanel => _overflowPanel ??= _parent?.OverflowPanel;
|
||||
internal ToolBar? ParentToolBar => _parent ??= this.TemplatedParent as ToolBar;
|
||||
|
||||
static ToolBarPanel()
|
||||
{
|
||||
OrientationProperty.OverrideDefaultValue<ToolBarPanel>(Orientation.Horizontal);
|
||||
}
|
||||
|
||||
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
|
||||
{
|
||||
base.OnAttachedToLogicalTree(e);
|
||||
_parent = this.TemplatedParent as ToolBar;
|
||||
if (_parent is null) return;
|
||||
this[!OrientationProperty] = _parent[!OrientationProperty];
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
var logicalChildren = _parent?.GetLogicalChildren().OfType<Control>().ToList();
|
||||
Size size = new Size();
|
||||
double spacing = 0;
|
||||
Size measureSize = availableSize;
|
||||
bool horizontal = Orientation == Orientation.Horizontal;
|
||||
bool hasVisibleChildren = false;
|
||||
if (logicalChildren is null) return size;
|
||||
for (int i = 0; i < logicalChildren.Count; i++)
|
||||
{
|
||||
Control control = logicalChildren[i];
|
||||
var mode = ToolBar.GetOverflowMode(control);
|
||||
control.Measure(measureSize);
|
||||
if (mode == OverflowMode.Always)
|
||||
{
|
||||
ToolBar.SetIsOverflowItem(control, true);
|
||||
}
|
||||
else if (mode == OverflowMode.Never)
|
||||
{
|
||||
if (control.IsVisible)
|
||||
{
|
||||
hasVisibleChildren = true;
|
||||
size = horizontal
|
||||
? size.WithWidth(size.Width + control.DesiredSize.Width + spacing)
|
||||
.WithHeight(Math.Max(size.Height, control.DesiredSize.Height))
|
||||
: size.WithHeight(size.Height + control.DesiredSize.Height + spacing)
|
||||
.WithWidth(Math.Max(size.Width, control.DesiredSize.Width));
|
||||
ToolBar.SetIsOverflowItem(control, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
bool isOverflow = false;
|
||||
for(int i = 0; i < logicalChildren.Count; i++)
|
||||
{
|
||||
Control control = logicalChildren[i];
|
||||
var mode = ToolBar.GetOverflowMode(control);
|
||||
if (mode != OverflowMode.AsNeeded) continue;
|
||||
//Always keeps the order of display. It's very un reasonable to display the second but short control
|
||||
//and push the first control to the overflow panel. So once a control is marked as overflow, the following
|
||||
//controls will be marked as overflow too.
|
||||
if (isOverflow)
|
||||
{
|
||||
ToolBar.SetIsOverflowItem(control, isOverflow);
|
||||
continue;
|
||||
}
|
||||
bool isFit = horizontal
|
||||
? (size.Width + control.DesiredSize.Width <= availableSize.Width)
|
||||
: (size.Height + control.DesiredSize.Height <= availableSize.Height);
|
||||
if (isFit)
|
||||
{
|
||||
ToolBar.SetIsOverflowItem(control, false);
|
||||
size = horizontal
|
||||
? size.WithWidth(size.Width + control.DesiredSize.Width + spacing)
|
||||
.WithHeight(Math.Max(size.Height, control.DesiredSize.Height))
|
||||
: size.WithHeight(size.Height + control.DesiredSize.Height + spacing)
|
||||
.WithWidth(Math.Max(size.Width, control.DesiredSize.Width));
|
||||
}
|
||||
else
|
||||
{
|
||||
isOverflow = true;
|
||||
ToolBar.SetIsOverflowItem(control, isOverflow);
|
||||
}
|
||||
}
|
||||
if (hasVisibleChildren)
|
||||
{
|
||||
size = horizontal ? size.WithWidth(size.Width - spacing) : size.WithHeight(size.Height - spacing);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
protected override Size ArrangeOverride(Size finalSize)
|
||||
{
|
||||
Children.Clear();
|
||||
OverflowPanel?.Children.Clear();
|
||||
var logicalChildren = _parent?.GetLogicalChildren().OfType<Control>().ToList();
|
||||
if(logicalChildren is null) return finalSize;
|
||||
bool overflow = false;
|
||||
foreach (var child in logicalChildren)
|
||||
{
|
||||
if (ToolBar.GetIsOverflowItem(child))
|
||||
{
|
||||
OverflowPanel?.Children.Add(child);
|
||||
overflow = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Children.Add(child);
|
||||
}
|
||||
|
||||
if (child is ToolBarSeparator s)
|
||||
{
|
||||
s.IsVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
var thisLast = this.Children.LastOrDefault();
|
||||
if (thisLast is ToolBarSeparator s2)
|
||||
{
|
||||
s2.IsVisible = false;
|
||||
}
|
||||
|
||||
var thatFirst = OverflowPanel?.Children.FirstOrDefault();
|
||||
if (thatFirst is ToolBarSeparator s3)
|
||||
{
|
||||
s3.IsVisible = false;
|
||||
}
|
||||
if (_parent != null) _parent.HasOverflowItems = overflow;
|
||||
return base.ArrangeOverride(finalSize);
|
||||
}
|
||||
|
||||
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
|
||||
{
|
||||
var list = OverflowPanel?.Children.ToList();
|
||||
if (list is not null)
|
||||
{
|
||||
OverflowPanel?.Children.Clear();
|
||||
Children.AddRange(list);
|
||||
}
|
||||
base.OnDetachedFromVisualTree(e);
|
||||
}
|
||||
}
|
||||
41
src/Ursa/Controls/ToolBar/ToolBarSeparator.cs
Normal file
41
src/Ursa/Controls/ToolBar/ToolBarSeparator.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Metadata;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.LogicalTree;
|
||||
using Irihi.Avalonia.Shared.Helpers;
|
||||
|
||||
namespace Ursa.Controls;
|
||||
|
||||
[PseudoClasses(PC_Vertical)]
|
||||
public class ToolBarSeparator: TemplatedControl
|
||||
{
|
||||
public const string PC_Vertical = ":vertical";
|
||||
|
||||
public static readonly StyledProperty<Orientation> OrientationProperty =
|
||||
ToolBar.OrientationProperty.AddOwner<ToolBarSeparator>();
|
||||
|
||||
public Orientation Orientation
|
||||
{
|
||||
get => GetValue(OrientationProperty);
|
||||
set => SetValue(OrientationProperty, value);
|
||||
}
|
||||
|
||||
static ToolBarSeparator()
|
||||
{
|
||||
OrientationProperty.OverrideDefaultValue<ToolBarSeparator>(Orientation.Horizontal);
|
||||
OrientationProperty.Changed.AddClassHandler<ToolBarSeparator, Orientation>((separator, args) =>
|
||||
{
|
||||
separator.PseudoClasses.Set(PC_Vertical, args.NewValue.Value == Orientation.Vertical);
|
||||
});
|
||||
}
|
||||
|
||||
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
|
||||
{
|
||||
base.OnAttachedToLogicalTree(e);
|
||||
var ancestor = this.GetLogicalAncestors().OfType<ToolBar>().FirstOrDefault();
|
||||
if (ancestor is null) return;
|
||||
this[!OrientationProperty] = ancestor[!ToolBar.OrientationProperty];
|
||||
}
|
||||
}
|
||||
@@ -17,4 +17,8 @@
|
||||
<PackageReference Include="Irihi.Avalonia.Shared" Version="0.1.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Controls\Panels\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user