feat: improve styling.
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
@@ -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,24 +116,31 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnPointerReleased(PointerReleasedEventArgs e)
|
protected override void OnPointerReleased(PointerReleasedEventArgs e)
|
||||||
{
|
{
|
||||||
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
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
16
src/Ursa/Converters/SelectionBoxTemplateConverter.cs
Normal file
16
src/Ursa/Converters/SelectionBoxTemplateConverter.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user