feat: simplify container generation, and add vertical demo.

This commit is contained in:
rabbitism
2024-02-23 16:26:09 +08:00
parent 39b7424cf5
commit 1ccb395ab0
8 changed files with 185 additions and 85 deletions

View File

@@ -3,6 +3,28 @@
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="ItemsPanel">
<ItemsPanelTemplate>
@@ -13,27 +35,35 @@
<ControlTemplate TargetType="u:ToolBar">
<Border
Padding="2"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
CornerRadius="4"
Theme="{DynamicResource CardBorder}">
<DockPanel LastChildFill="True">
<Rectangle
Width="1"
Margin="4,0"
VerticalAlignment="Stretch"
DockPanel.Dock="Left"
Fill="Gray" />
<ContentPresenter
Margin="4,0"
Margin="8,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Content="{TemplateBinding Header}"
ContentTemplate="{TemplateBinding HeaderTemplate}"
DockPanel.Dock="Left" />
<Panel DockPanel.Dock="Right">
<ToggleButton Name="button" Content="More" />
DockPanel.Dock="Left"
IsVisible="{TemplateBinding Header,
Converter={x:Static ObjectConverters.IsNotNull}}" />
<Panel Name="PART_PopupButton" DockPanel.Dock="Right">
<ToggleButton
Name="button"
IsVisible="False"
Padding="8,0"
VerticalAlignment="Stretch"
Theme="{DynamicResource ToolBarExpandToggleButton}">
<PathIcon Height="16" Data="{DynamicResource ToolBarHorizontalMoreGlyph}"></PathIcon>
</ToggleButton>
<Popup
IsLightDismissEnabled="True"
IsOpen="{Binding #button.IsChecked, Mode=TwoWay}"
Placement="{TemplateBinding PopupPlacement}"
PlacementTarget="{Binding #button}">
<Border Theme="{DynamicResource CardBorder}">
<Border Theme="{DynamicResource CardBorder}" Padding="2">
<StackPanel Name="{x:Static u:ToolBar.PART_OverflowPanel}" />
</Border>
</Popup>
@@ -46,5 +76,58 @@
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^[Orientation=Horizontal]">
<Setter Property="PopupPlacement" Value="BottomEdgeAlignedLeft" />
</Style>
<Style Selector="^[Orientation=Vertical]">
<Setter Property="PopupPlacement" Value="RightEdgeAlignedTop" />
<Setter Property="Template">
<ControlTemplate TargetType="u:ToolBar">
<Border
Padding="2"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
CornerRadius="4"
Theme="{DynamicResource CardBorder}">
<DockPanel LastChildFill="True">
<ContentPresenter
Margin="8,0"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Content="{TemplateBinding Header}"
ContentTemplate="{TemplateBinding HeaderTemplate}"
DockPanel.Dock="Top"
IsVisible="{TemplateBinding Header,
Converter={x:Static ObjectConverters.IsNotNull}}" />
<Panel Name="PART_PopupButton" DockPanel.Dock="Bottom">
<ToggleButton
Name="button"
IsVisible="False"
Padding="0 8"
Theme="{DynamicResource ToolBarExpandToggleButton}">
<PathIcon Width="16" Data="{DynamicResource ToolBarVerticalMoreGlyph}" />
</ToggleButton>
<Popup
IsLightDismissEnabled="True"
IsOpen="{Binding #button.IsChecked, Mode=TwoWay}"
Placement="{TemplateBinding PopupPlacement}"
PlacementTarget="{Binding #button}">
<Border 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>
<Style Selector="^:overflow /template/ ToggleButton#button">
<Setter Property="IsVisible" Value="True"></Setter>
</Style>
</ControlTheme>
</ResourceDictionary>

View 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>

View File

@@ -15,5 +15,6 @@
<MergeResourceInclude Source="Pagination.axaml" />
<MergeResourceInclude Source="TagInput.axaml" />
<MergeResourceInclude Source="ThemeSelector.axaml" />
<MergeResourceInclude Source="ToolBar.axaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

View File

@@ -6,13 +6,16 @@ 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; }
@@ -27,14 +30,14 @@ public class ToolBar: HeaderedItemsControl
get => GetValue(OrientationProperty);
set => SetValue(OrientationProperty, value);
}
public static readonly StyledProperty<int> BandProperty = AvaloniaProperty.Register<ToolBar, int>(
nameof(Band));
public int Band
public static readonly StyledProperty<PlacementMode> PopupPlacementProperty =
Popup.PlacementProperty.AddOwner<ToolBar>();
public PlacementMode PopupPlacement
{
get => GetValue(BandProperty);
set => SetValue(BandProperty, value);
get => GetValue(PopupPlacementProperty);
set => SetValue(PopupPlacementProperty, value);
}
public static readonly AttachedProperty<OverflowMode> OverflowModeProperty =
@@ -49,11 +52,27 @@ public class ToolBar: HeaderedItemsControl
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)
@@ -63,29 +82,11 @@ public class ToolBar: HeaderedItemsControl
protected override Control CreateContainerForItemOverride(object? item, int index, object? recycleKey)
{
return new ContentPresenter();
}
protected override void ContainerForItemPreparedOverride(Control container, object? item, int index)
{
base.ContainerForItemPreparedOverride(container, item, index);
if (item is Control s)
if(item is Control c)
{
container[!ToolBar.OverflowModeProperty] = s[!ToolBar.OverflowModeProperty];
}
else
{
if (container is ContentPresenter p)
{
p.ApplyTemplate();
var c = p.Child;
if (c != null)
{
container[ToolBar.OverflowModeProperty] = c[ToolBar.OverflowModeProperty];
// container[!ToolBar.OverflowModeProperty] = c[!ToolBar.OverflowModeProperty];
}
}
return c;
}
return ItemTemplate?.Build(item) ?? new ContentPresenter();
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)

View File

@@ -1,8 +0,0 @@
using Avalonia.Controls;
namespace Ursa.Controls;
public class ToolBarOverflowPanel: StackPanel
{
}

View File

@@ -10,18 +10,9 @@ public class ToolBarPanel: StackPanel
private ToolBar? _parent;
private Panel? _overflowPanel;
internal Panel? OverflowPanel => _overflowPanel ??= _parent?.OverflowPanel;
private Panel? OverflowPanel => _overflowPanel ??= _parent?.OverflowPanel;
internal ToolBar? ParentToolBar => _parent ??= this.TemplatedParent as ToolBar;
public static readonly StyledProperty<Orientation> OrientationProperty =
StackPanel.OrientationProperty.AddOwner<ToolBar>();
public Orientation Orientation
{
get => GetValue(OrientationProperty);
set => SetValue(OrientationProperty, value);
}
static ToolBarPanel()
{
OrientationProperty.OverrideDefaultValue<ToolBarPanel>(Orientation.Horizontal);
@@ -38,13 +29,11 @@ public class ToolBarPanel: StackPanel
protected override Size MeasureOverride(Size availableSize)
{
var logicalChildren = _parent?.GetLogicalChildren().OfType<Control>().ToList();
var parent = this.GetLogicalParent();
Size size = new Size();
double spacing = 0;
Size measureSize = availableSize;
bool horizontal = Orientation == Orientation.Horizontal;
bool hasVisibleChildren = false;
int index = 0;
if (logicalChildren is null) return size;
for (int i = 0; i < logicalChildren.Count; i++)
{
@@ -54,7 +43,6 @@ public class ToolBarPanel: StackPanel
if (mode == OverflowMode.Always)
{
ToolBar.SetIsOverflowItem(control, true);
continue;
}
else if (mode == OverflowMode.Never)
{
@@ -114,30 +102,33 @@ public class ToolBarPanel: StackPanel
{
Children.Clear();
OverflowPanel?.Children.Clear();
InvalidateVisual();
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
{
this.Children.Add(child);
Children.Add(child);
}
}
if (_parent != null) _parent.HasOverflowItems = overflow;
return base.ArrangeOverride(finalSize);
}
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
var list = OverflowPanel?.Children?.ToList();
var list = OverflowPanel?.Children.ToList();
if (list is not null)
{
OverflowPanel?.Children?.Clear();
this.Children.AddRange(list);
OverflowPanel?.Children.Clear();
Children.AddRange(list);
}
base.OnDetachedFromVisualTree(e);
}