using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Data; namespace Ghost.Editor.View.Controls.Docking; /// /// A container that displays its children (documents) as tabs. /// [TemplatePart(Name = PART_TAB_VIEW, Type = typeof(TabView))] public partial class DockGroup : DockContainer { private const string PART_TAB_VIEW = "PART_TabView"; private const string DRAG_DOCUMENT_KEY = "DockDocument"; private TabView? _tabView; public DockGroup() { DefaultStyleKey = typeof(DockGroup); } protected override void ValidateChild(DockModule module) { base.ValidateChild(module); if (module is not DockDocument) { throw new ArgumentException($"{nameof(DockGroup)} only accepts {nameof(DockDocument)} children.", nameof(module)); } } protected override void OnApplyTemplate() { base.OnApplyTemplate(); if (_tabView != null) { _tabView.TabDragStarting -= OnTabDragStarting; _tabView.TabDroppedOutside -= OnTabDroppedOutside; _tabView.DragOver -= OnDragOver; _tabView.Drop -= OnDrop; _tabView.DragLeave -= OnDragLeave; _tabView.TabCloseRequested -= OnTabCloseRequested; } _tabView = GetTemplateChild(PART_TAB_VIEW) as TabView; if (_tabView != null) { _tabView.TabDragStarting += OnTabDragStarting; _tabView.TabDroppedOutside += OnTabDroppedOutside; _tabView.DragOver += OnDragOver; _tabView.Drop += OnDrop; _tabView.DragLeave += OnDragLeave; _tabView.TabCloseRequested += OnTabCloseRequested; } UpdateTabs(); } private void OnTabDragStarting(TabView sender, TabViewTabDragStartingEventArgs args) { if (args.Tab.Tag is DockDocument doc) { args.Data.Properties.Add(DRAG_DOCUMENT_KEY, doc); } } private void OnTabDroppedOutside(TabView sender, TabViewTabDroppedOutsideEventArgs args) { if (args.Tab.Tag is DockDocument doc) { Root?.CreateFloatingWindow(doc); } } private void OnDragOver(object sender, DragEventArgs e) { if (e.DataView.Properties.ContainsKey(DRAG_DOCUMENT_KEY)) { e.AcceptedOperation = global::Windows.ApplicationModel.DataTransfer.DataPackageOperation.Move; Root?.ShowHighlight(this, e.GetPosition(this)); } } private void OnDrop(object sender, DragEventArgs e) { if (e.DataView.Properties.TryGetValue(DRAG_DOCUMENT_KEY, out var obj) && obj is DockDocument doc) { Root?.HandleDrop(doc, this, e.GetPosition(this)); } } private void OnDragLeave(object sender, DragEventArgs e) { Root?.HideHighlight(); } private void OnTabCloseRequested(TabView sender, TabViewTabCloseRequestedEventArgs args) { if (args.Tab.Tag is DockDocument doc) { RemoveChild(doc); } } protected override void OnChildrenUpdated() { UpdateTabs(); } private void UpdateTabs() { if (_tabView == null) return; var selectedDoc = _tabView.SelectedItem is TabViewItem selectedItem ? selectedItem.Tag as DockDocument : null; // Detach all existing tabs foreach (var item in _tabView.TabItems) { if (item is TabViewItem tabItem) { tabItem.Content = null; } } _tabView.TabItems.Clear(); TabViewItem? newSelectedItem = null; foreach (var child in Children) { if (child is DockDocument doc) { var tabItem = new TabViewItem { Tag = doc }; tabItem.SetBinding(TabViewItem.HeaderProperty, new Microsoft.UI.Xaml.Data.Binding { Source = doc, Path = new PropertyPath(nameof(DockDocument.Title)), Mode = Microsoft.UI.Xaml.Data.BindingMode.OneWay }); tabItem.Content = doc; _tabView.TabItems.Add(tabItem); if (doc == selectedDoc) { newSelectedItem = tabItem; } } } if (newSelectedItem != null) { _tabView.SelectedItem = newSelectedItem; } else if (_tabView.TabItems.Count > 0) { _tabView.SelectedItem = _tabView.TabItems[0]; } } }