diff --git a/src/Ursa/Controls/ComboBox/TreeComboBox.cs b/src/Ursa/Controls/ComboBox/TreeComboBox.cs index 921535f..430105b 100644 --- a/src/Ursa/Controls/ComboBox/TreeComboBox.cs +++ b/src/Ursa/Controls/ComboBox/TreeComboBox.cs @@ -1,17 +1,16 @@ -using System.Collections; -using System.Collections.Specialized; -using System.Data; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Metadata; using Avalonia.Controls.Primitives; -using Avalonia.Controls.Selection; +using Avalonia.Controls.Shapes; using Avalonia.Controls.Templates; using Avalonia.Input; using Avalonia.Layout; using Avalonia.LogicalTree; -using Avalonia.OpenGL.Controls; +using Avalonia.Media; +using Avalonia.VisualTree; using Irihi.Avalonia.Shared.Common; +using Size = Avalonia.Size; namespace Ursa.Controls; @@ -86,34 +85,40 @@ public class TreeComboBox: ItemsControl get => _selectionBoxItem; protected set => SetAndRaise(SelectionBoxItemProperty, ref _selectionBoxItem, value); } + + private object? _selectedItem; + + public static readonly DirectProperty SelectedItemProperty = AvaloniaProperty.RegisterDirect( + nameof(SelectedItem), o => o.SelectedItem, (o, v) => o.SelectedItem = v); + + public object? SelectedItem + { + get + { + return _selectedItem; + } + set + { + SetAndRaise(SelectedItemProperty, ref _selectedItem, value); + + } + } static TreeComboBox() { ItemsPanelProperty.OverrideDefaultValue(DefaultPanel); FocusableProperty.OverrideDefaultValue(true); + SelectedItemProperty.Changed.AddClassHandler((box, args) => box.OnSelectedItemChanged(args)); } - - private Control? TreeContainerFromItem(object item) - { - return TreeContainerFromItemInternal(this, item); - static Control? TreeContainerFromItemInternal(ItemsControl itemsControl, object item) + private void OnSelectedItemChanged(AvaloniaPropertyChangedEventArgs args) + { + if (args.NewValue.Value is not null) { - Control? control = itemsControl.ContainerFromItem(item); - if(control is not null) return control; - foreach (var child in itemsControl.GetRealizedContainers()) - { - if (child is ItemsControl childItemsControl) - { - control = TreeContainerFromItemInternal(childItemsControl, item); - if (control is not null) return control; - } - } - return null; + UpdateSelectionBoxItem(args.NewValue.Value); } } - - + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { base.OnApplyTemplate(e); @@ -148,12 +153,25 @@ public class TreeComboBox: ItemsControl protected override void OnPointerReleased(PointerReleasedEventArgs e) { base.OnPointerReleased(e); - if (e.InitialPressMouseButton == MouseButton.Left) + if (e is { InitialPressMouseButton: MouseButton.Left, Source: Visual source }) { - if (_popup is not null && _popup.IsOpen && e.Source is Visual v && _popup.IsInsidePopup(v)) + if (_popup is not null && _popup.IsOpen && _popup.IsInsidePopup(source)) { - var container = v.FindLogicalAncestorOfType(); - + var container = GetContainerFromEventSource(source); + if (container is null) return; + var item = TreeItemFromContainer(container); + if (item is null) return; + if (SelectedItem is not null) + { + var selectedContainer = TreeContainerFromItem(SelectedItem); + if(selectedContainer is TreeComboBoxItem selectedTreeComboBoxItem) + { + selectedTreeComboBoxItem.IsSelected = false; + } + } + this.SelectedItem = item; + container.IsSelected = true; + IsDropDownOpen = false; } else { @@ -162,4 +180,104 @@ public class TreeComboBox: ItemsControl } } + + private void UpdateSelectionBoxItem(object? item) + { + if (item is ContentControl contentControl) + { + item = contentControl.Content; + } + else if(item is HeaderedItemsControl headeredItemsControl) + { + item = headeredItemsControl.Header; + } + + if (item is Control control) + { + if (VisualRoot == null) return; + control.Measure(Size.Infinity); + SelectionBoxItem = new Rectangle + { + Width = control.DesiredSize.Width, + Height = control.DesiredSize.Height, + Fill = new VisualBrush + { + Visual = control, + Stretch = Stretch.None, + AlignmentX = AlignmentX.Left, + } + }; + // TODO: Implement flow direction udpate + } + else + { + if (ItemTemplate is null && DisplayMemberBinding is { } binding) + { + var template = new FuncDataTemplate((a,_) => new TextBlock + { + [DataContextProperty] = a, + [!TextBlock.TextProperty] = binding, + }); + var textBlock = template.Build(item); + SelectionBoxItem = textBlock; + } + else + { + SelectionBoxItem = item; + } + } + } + + private TreeComboBoxItem? GetContainerFromEventSource(object eventSource) + { + if (eventSource is Visual visual) + { + var item = visual.GetSelfAndVisualAncestors().OfType().FirstOrDefault(); + return item?.Owner == this ? item : null!; + } + + return null; + } + + private object? TreeItemFromContainer(Control container) + { + return TreeItemFromContainer(this, container); + } + + private Control? TreeContainerFromItem(object item) + { + return TreeContainerFromItem(this, item); + } + + private static Control? TreeContainerFromItem(ItemsControl itemsControl, object item) + { + if (itemsControl.ContainerFromItem(item) is { } container) + { + return container; + } + foreach (var child in itemsControl.GetRealizedContainers()) + { + if(child is ItemsControl childItemsControl && TreeContainerFromItem(childItemsControl, item) is { } childContainer) + { + return childContainer; + } + } + return null; + } + + private static object? TreeItemFromContainer(ItemsControl itemsControl, Control container) + { + if (itemsControl.ItemFromContainer(container) is { } item) + { + return item; + } + foreach (var child in itemsControl.GetRealizedContainers()) + { + if(child is ItemsControl childItemsControl && TreeItemFromContainer(childItemsControl, container) is { } childItem) + { + return childItem; + } + } + return null; + } } \ No newline at end of file diff --git a/src/Ursa/Controls/ComboBox/TreeComboBoxItem.cs b/src/Ursa/Controls/ComboBox/TreeComboBoxItem.cs index f2d3b1c..cab3e1e 100644 --- a/src/Ursa/Controls/ComboBox/TreeComboBoxItem.cs +++ b/src/Ursa/Controls/ComboBox/TreeComboBoxItem.cs @@ -18,6 +18,7 @@ public class TreeComboBoxItem: HeaderedItemsControl, ISelectable { private Control? _header; private TreeComboBox? _treeComboBox; + public TreeComboBox? Owner => _treeComboBox; public static readonly StyledProperty IsSelectedProperty = TreeViewItem.IsSelectedProperty.AddOwner();