feat: improve styling.

This commit is contained in:
rabbitism
2024-04-15 03:35:27 +08:00
parent edf0e387cc
commit 1521b07785
5 changed files with 188 additions and 21 deletions

View File

@@ -8,13 +8,85 @@
<converters:MarginMultiplierConverter x:Key="LeftMarginConverter" Indent="20" Left="True"/> <converters:MarginMultiplierConverter x:Key="LeftMarginConverter" Indent="20" Left="True"/>
<ControlTheme x:Key="{x:Type u:TreeComboBox}" TargetType="u:TreeComboBox"> <ControlTheme x:Key="{x:Type u:TreeComboBox}" TargetType="u:TreeComboBox">
<Setter Property="Padding" Value="{DynamicResource ComboBoxSelectorDefaultPadding}"/>
<Setter Property="FocusAdorner" Value="{x:Null}"/>
<Setter Property="Background" Value="{DynamicResource ComboBoxSelectorBackground}"/>
<Setter Property="CornerRadius" Value="{DynamicResource ComboBoxSelectorCornerRadius}"/>
<Setter Property="VerticalContentAlignment" Value="Center"></Setter>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template"> <Setter Property="Template">
<ControlTemplate TargetType="u:TreeComboBox"> <ControlTemplate TargetType="u:TreeComboBox">
<Grid ColumnDefinitions="*, Auto, 32" Background="Transparent"> <Grid ColumnDefinitions="*, Auto, 32">
<Border Grid.Column="0" Grid.ColumnSpan="3" Background="Transparent" BorderBrush="Blue" BorderThickness="1" CornerRadius="3"/> <Border Grid.Column="0"
<ContentPresenter Grid.Column="0" MinHeight="32" Content="{TemplateBinding SelectionBoxItem}"/> Name="Background"
<Popup Name="{x:Static iri:PartNames.PART_Popup}" Grid.Column="0" IsLightDismissEnabled="True" IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}"> Grid.ColumnSpan="3"
<Border Background="{DynamicResource ComboBoxPopupBackground}"> Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
MinHeight="32"
/>
<TextBlock
Name="PlaceholderTextBlock"
Grid.Column="0"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
TextTrimming="CharacterEllipsis"
Foreground="{TemplateBinding Foreground}"
Opacity="0.3"
IsVisible="{TemplateBinding SelectionBoxItem, Converter={x:Static ObjectConverters.IsNull}}"
Text="{TemplateBinding Watermark}"
></TextBlock>
<ContentPresenter
Grid.Column="0"
Margin="{TemplateBinding Padding}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
VerticalAlignment="Center"
ContentTemplate="{TemplateBinding SelectedItemTemplate}"
Content="{TemplateBinding SelectionBoxItem}"/>
<Border
x:Name="DropDownOverlay"
Grid.Column="2"
Width="30"
Margin="0,1,1,1"
HorizontalAlignment="Right"
Background="Transparent"
IsVisible="False" />
<PathIcon
x:Name="DropDownGlyph"
Grid.Column="2"
Width="12"
Height="12"
Margin="0,0,10,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Data="{DynamicResource ComboBoxIcon}"
Foreground="{DynamicResource ComboBoxIconDefaultForeground}"
IsHitTestVisible="False"
UseLayoutRounding="False" />
<Popup
Name="{x:Static iri:PartNames.PART_Popup}"
Grid.Column="0"
MinWidth="{Binding Bounds.Width, RelativeSource={RelativeSource TemplatedParent}}"
MinHeight="{TemplateBinding MaxDropDownHeight}"
ClipToBounds="False"
InheritsTransform="True"
PlacementTarget="Background"
WindowManagerAddShadowHint="False"
IsLightDismissEnabled="True"
IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}">
<Border
Name="PopupBorder"
Margin="0 4"
Background="{DynamicResource ComboBoxPopupBackground}"
BorderBrush="{DynamicResource ComboBoxPopupBorderBrush}"
BoxShadow="{DynamicResource ComboBoxPopupBoxShadow}"
ClipToBounds="True"
CornerRadius="6"
>
<ScrollViewer> <ScrollViewer>
<ItemsPresenter ItemsPanel="{TemplateBinding ItemsPanel}"/> <ItemsPresenter ItemsPanel="{TemplateBinding ItemsPanel}"/>
</ScrollViewer> </ScrollViewer>
@@ -26,21 +98,81 @@
</ControlTheme> </ControlTheme>
<ControlTheme x:Key="{x:Type u:TreeComboBoxItem}" TargetType="u:TreeComboBoxItem"> <ControlTheme x:Key="{x:Type u:TreeComboBoxItem}" TargetType="u:TreeComboBoxItem">
<Setter Property="Background" Value="{DynamicResource TreeViewItemDefaultBackground}"/>
<Setter Property="Foreground" Value="{DynamicResource TreeViewItemDefaultForeground}"/>
<Setter Property="CornerRadius" Value="3"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Template"> <Setter Property="Template">
<ControlTemplate TargetType="u:TreeComboBoxItem"> <ControlTemplate TargetType="u:TreeComboBoxItem">
<StackPanel> <StackPanel>
<Border Name="PART_LayoutRoot" MinHeight="{TemplateBinding MinHeight}" TemplatedControl.IsTemplateFocusTarget="True"> <Border
Name="PART_LayoutRoot"
MinHeight="{TemplateBinding MinHeight}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
TemplatedControl.IsTemplateFocusTarget="True">
<Grid <Grid
Name="{x:Static iri:PartNames.PART_Header}" Name="{x:Static iri:PartNames.PART_Header}"
Margin="{TemplateBinding Level, Mode=OneWay, Converter={StaticResource LeftMarginConverter}}" Margin="{TemplateBinding Level, Mode=OneWay, Converter={StaticResource LeftMarginConverter}}"
ColumnDefinitions="Auto, *"> ColumnDefinitions="Auto, *">
<ToggleButton IsChecked="{TemplateBinding IsExpanded, Mode=TwoWay}" Theme="{DynamicResource ToggleButtonTreeViewItemIconButton}" Name="PART_ExpandCollapseChevron" Grid.Column="0" Focusable="False"></ToggleButton> <ToggleButton
<ContentPresenter Grid.Column="1" Name="{x:Static iri:PartNames.PART_HeaderPresenter}" Content="{TemplateBinding Header}" ContentTemplate="{TemplateBinding HeaderTemplate}" Focusable="False"/> IsChecked="{TemplateBinding IsExpanded, Mode=TwoWay}"
Theme="{DynamicResource ToggleButtonTreeViewItemIconButton}"
Name="PART_ExpandCollapseChevron"
Grid.Column="0"
Padding="{DynamicResource TreeViewItemIconMargin}"
Focusable="False"></ToggleButton>
<ContentPresenter
Grid.Column="1"
Name="{x:Static iri:PartNames.PART_HeaderPresenter}"
Margin="{TemplateBinding Padding}"
Padding="{DynamicResource TreeViewItemPadding}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
Foreground="{TemplateBinding Foreground}"
Content="{TemplateBinding Header}"
ContentTemplate="{TemplateBinding HeaderTemplate}"
Focusable="False"/>
</Grid> </Grid>
</Border> </Border>
<ItemsPresenter IsVisible="{TemplateBinding IsExpanded}" Name="{x:Static iri:PartNames.PART_ItemsPresenter}" ItemsPanel="{TemplateBinding ItemsPanel}"/> <ItemsPresenter IsVisible="{TemplateBinding IsExpanded}" Name="{x:Static iri:PartNames.PART_ItemsPresenter}" ItemsPanel="{TemplateBinding ItemsPanel}"/>
</StackPanel> </StackPanel>
</ControlTemplate> </ControlTemplate>
</Setter> </Setter>
<!-- Pointerover state -->
<Style Selector="^ /template/ Border#PART_LayoutRoot:pointerover">
<Setter Property="Background" Value="{DynamicResource TreeViewItemPointeroverBackground}" />
</Style>
<!-- Pressed state -->
<Style Selector="^:pressed /template/ Border#PART_LayoutRoot:pointerover">
<Setter Property="Background" Value="{DynamicResource TreeViewItemPressedBackground}" />
</Style>
<!-- Disabled state -->
<Style Selector="^:disabled /template/ Border#PART_LayoutRoot">
<Setter Property="Background" Value="{DynamicResource TreeViewItemDisabledBackground}" />
</Style>
<Style Selector="^:disabled /template/ ContentPresenter#PART_HeaderPresenter">
<Setter Property="Foreground" Value="{DynamicResource TreeViewItemDisabledForeground}" />
</Style>
<!-- Selected state -->
<Style Selector="^:selected /template/ Border#PART_LayoutRoot">
<Setter Property="Background" Value="{DynamicResource TreeViewItemSelectedBackground}" />
</Style>
<!-- Disabled Selected state -->
<Style Selector="^:disabled:selected /template/ Border#PART_LayoutRoot">
<Setter Property="Background" Value="{DynamicResource TreeViewItemSelectedDisabledBackground}" />
</Style>
<Style Selector="^:empty /template/ ToggleButton#PART_ExpandCollapseChevron">
<Setter Property="Opacity" Value="0" />
<Setter Property="IsHitTestVisible" Value="False" />
</Style>
</ControlTheme> </ControlTheme>
</ResourceDictionary> </ResourceDictionary>

View File

@@ -6,6 +6,7 @@ using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates; using Avalonia.Controls.Templates;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Layout; using Avalonia.Layout;
using Avalonia.LogicalTree;
using Avalonia.OpenGL.Controls; using Avalonia.OpenGL.Controls;
using Irihi.Avalonia.Shared.Common; using Irihi.Avalonia.Shared.Common;
@@ -115,11 +116,6 @@ public class TreeComboBox: SelectingItemsControl
return CreateContainerForItemOverride(item, index, recycleKey); return CreateContainerForItemOverride(item, index, recycleKey);
} }
protected override void ContainerForItemPreparedOverride(Control container, object? item, int index)
{
base.ContainerForItemPreparedOverride(container, item, index);
}
internal void ContainerForItemPreparedInternal(Control container, object? item, int index) internal void ContainerForItemPreparedInternal(Control container, object? item, int index)
{ {
ContainerForItemPreparedOverride(container, item, index); ContainerForItemPreparedOverride(container, item, index);
@@ -130,9 +126,21 @@ public class TreeComboBox: SelectingItemsControl
base.OnPointerReleased(e); base.OnPointerReleased(e);
if (e.InitialPressMouseButton == MouseButton.Left) if (e.InitialPressMouseButton == MouseButton.Left)
{ {
if (_popup is not null && _popup.IsOpen && e.Source is TextBlock v && _popup.IsInsidePopup(v)) if (_popup is not null && _popup.IsOpen && e.Source is Visual v && _popup.IsInsidePopup(v))
{ {
SelectionBoxItem = v.Text; var container = v.FindLogicalAncestorOfType<TreeComboBoxItem>();
container?.SetValue(IsSelectedProperty, true);
if (container?.Header is Control control)
{
SelectionBoxItem = control.DataContext ?? control.ToString();
// UpdateSelectionFromEventSource(e.Source);
}
else
{
SelectionBoxItem = container?.Header;
// UpdateSelectionFromEventSource(e.Source);
}
SetCurrentValue(IsDropDownOpenProperty, false); SetCurrentValue(IsDropDownOpenProperty, false);
} }
else else

View File

@@ -1,6 +1,7 @@
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Metadata; using Avalonia.Controls.Metadata;
using Avalonia.Controls.Mixins;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
@@ -45,6 +46,13 @@ public class TreeComboBoxItem: HeaderedItemsControl, ISelectable
protected set => SetAndRaise(LevelProperty, ref _level, value); protected set => SetAndRaise(LevelProperty, ref _level, value);
} }
static TreeComboBoxItem()
{
IsSelectedProperty.AffectsPseudoClass<TreeComboBoxItem>(PseudoClassName.PC_Selected,
SelectingItemsControl.IsSelectedChangedEvent);
PressedMixin.Attach<TreeComboBoxItem>();
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e) protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{ {
base.OnApplyTemplate(e); base.OnApplyTemplate(e);
@@ -57,14 +65,15 @@ public class TreeComboBoxItem: HeaderedItemsControl, ISelectable
{ {
base.OnAttachedToLogicalTree(e); base.OnAttachedToLogicalTree(e);
_treeComboBox = this.FindLogicalAncestorOfType<TreeComboBox>(); _treeComboBox = this.FindLogicalAncestorOfType<TreeComboBox>();
Level = CalculateDistanceFromLogicalParent<TreeComboBox>(this); Level = CalculateDistanceFromLogicalParent<TreeComboBox>(this) - 1;
if (this.ItemTemplate is null && this._treeComboBox?.ItemTemplate is not null) if (this.ItemTemplate is null && this._treeComboBox?.ItemTemplate is not null)
{ {
SetCurrentValue(ItemTemplateProperty, this._treeComboBox.ItemTemplate); SetCurrentValue(ItemTemplateProperty, this._treeComboBox.ItemTemplate);
} }
if(this.ItemContainerTheme is null && this._treeComboBox?.ItemContainerTheme is not null)
{
SetCurrentValue(ItemContainerThemeProperty, this._treeComboBox.ItemContainerTheme);
}
} }
private void OnDoubleTapped(object sender, TappedEventArgs e) private void OnDoubleTapped(object sender, TappedEventArgs e)
@@ -76,6 +85,8 @@ public class TreeComboBoxItem: HeaderedItemsControl, ISelectable
protected override bool NeedsContainerOverride(object? item, int index, out object? recycleKey) protected override bool NeedsContainerOverride(object? item, int index, out object? recycleKey)
{ {
TreeViewItem t = new TreeViewItem();
ComboBox c = new ComboBox();
return EnsureParent().NeedsContainerInternal(item, index, out recycleKey); return EnsureParent().NeedsContainerInternal(item, index, out recycleKey);
} }

View File

@@ -0,0 +1,16 @@
using System.Globalization;
using Avalonia.Controls.Templates;
using Avalonia.Data.Converters;
namespace Ursa.Converters;
public class SelectionBoxTemplateConverter: IMultiValueConverter
{
public object? Convert(IList<object?> values, Type targetType, object? parameter, CultureInfo culture)
{
var selectedItemTemplate = values.Count > 0 ? values[0] as IDataTemplate : null;
if (selectedItemTemplate is not null) return selectedItemTemplate;
var itemTemplate = values.Count > 1 ? values[1] as IDataTemplate : null;
return itemTemplate;
}
}

View File

@@ -17,7 +17,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Avalonia" Version="$(AvaloniaVersion)"/> <PackageReference Include="Avalonia" Version="$(AvaloniaVersion)"/>
<PackageReference Include="Irihi.Avalonia.Shared" Version="0.1.6" /> <PackageReference Include="Irihi.Avalonia.Shared" Version="0.1.7" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>