feat(docking): improve tab management and error handling
Refactored DockGroup to only remove obsolete TabViewItems and restore tab selection more reliably. Updated DockGroup.xaml to enable tab reordering and add-tab button. Switched to CommunityToolkit.WinUI.Controls for GridSplitter and added a style for it. Made DockPanel, DockRegionHighlight, and DockingLayout partial classes. In App.xaml.cs, wrapped initialization in a try-catch to exit on error, and ensured process exit on window close. Improved ProjectBrowser scrollbar behavior and layout settings.
This commit is contained in:
@@ -116,6 +116,8 @@ public partial class App : Application
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
EditorApplication.Initialize(Host.Services, arguments.ProjectPath, arguments.ProjectName);
|
||||
|
||||
// NOTE: We must call DispatcherQueue.GetForCurrentThread() on the UI thread before any await.
|
||||
@@ -136,6 +138,11 @@ public partial class App : Application
|
||||
|
||||
splashWindow.Close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Environment.Exit(ex.HResult);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnClosed(object? sender, WindowEventArgs args)
|
||||
{
|
||||
@@ -153,7 +160,7 @@ public partial class App : Application
|
||||
}
|
||||
finally
|
||||
{
|
||||
//Environment.Exit(0);
|
||||
Environment.Exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.UI.Xaml.Controls"
|
||||
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:ghost="using:Ghost.Editor.Controls"
|
||||
xmlns:local="using:Ghost.Editor.Core">
|
||||
|
||||
@@ -42,6 +42,11 @@
|
||||
<Setter Property="TabWidthMode" Value="Compact" />
|
||||
</Style>
|
||||
<Style TargetType="NumberBox" />
|
||||
<Style TargetType="controls:GridSplitter">
|
||||
<Setter Property="MinHeight" Value="2" />
|
||||
<Setter Property="MinWidth" Value="2" />
|
||||
<Setter Property="Background" Value="{ThemeResource AcrylicBackgroundFillColorBaseBrush}" />
|
||||
</Style>
|
||||
|
||||
<!-- Named Style -->
|
||||
<Style
|
||||
|
||||
@@ -115,48 +115,39 @@ public partial class DockGroup : DockContainer
|
||||
|
||||
var selectedDoc = _tabView.SelectedItem is TabViewItem selectedItem ? selectedItem.Tag as DockDocument : null;
|
||||
|
||||
// Detach all existing tabs
|
||||
foreach (var item in _tabView.TabItems)
|
||||
// Remove tabs that are no longer in Children
|
||||
for (int i = _tabView.TabItems.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (item is TabViewItem tabItem)
|
||||
if (_tabView.TabItems[i] is TabViewItem tabItem && tabItem.Tag is DockDocument doc)
|
||||
{
|
||||
if (!Children.Contains(doc))
|
||||
{
|
||||
tabItem.Content = null;
|
||||
_tabView.TabItems.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
_tabView.TabItems.Clear();
|
||||
|
||||
TabViewItem? newSelectedItem = null;
|
||||
|
||||
// Add new tabs that aren't in TabItems yet
|
||||
foreach (var child in Children)
|
||||
{
|
||||
if (child is DockDocument doc)
|
||||
if (child is DockDocument doc && !_tabView.TabItems.Any(t => t is TabViewItem item && item.Tag.Equals(doc)))
|
||||
{
|
||||
var tabItem = new TabViewItem
|
||||
{
|
||||
Tag = doc
|
||||
};
|
||||
|
||||
var tabItem = new TabViewItem { Tag = doc, Content = 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
|
||||
Mode = BindingMode.OneWay
|
||||
});
|
||||
|
||||
tabItem.Content = doc;
|
||||
|
||||
_tabView.TabItems.Add(tabItem);
|
||||
|
||||
if (doc == selectedDoc)
|
||||
{
|
||||
newSelectedItem = tabItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newSelectedItem != null)
|
||||
// Restore selection
|
||||
if (selectedDoc != null && _tabView.TabItems.FirstOrDefault(t => t is TabViewItem item && item.Tag.Equals(selectedDoc)) is TabViewItem newSelected)
|
||||
{
|
||||
_tabView.SelectedItem = newSelectedItem;
|
||||
_tabView.SelectedItem = newSelected;
|
||||
}
|
||||
else if (_tabView.TabItems.Count > 0)
|
||||
{
|
||||
|
||||
@@ -7,15 +7,15 @@
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="local:DockGroup">
|
||||
<Grid>
|
||||
<TabView
|
||||
x:Name="PART_TabView"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
AllowDrop="True"
|
||||
CanDragTabs="True"
|
||||
CanReorderTabs="False"
|
||||
IsAddTabButtonVisible="False" />
|
||||
</Grid>
|
||||
CanReorderTabs="True"
|
||||
IsAddTabButtonVisible="True"
|
||||
TabWidthMode="Compact" />
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using CommunityToolkit.WinUI.Controls;
|
||||
using Windows.Foundation;
|
||||
|
||||
namespace Ghost.Editor.View.Controls.Docking;
|
||||
|
||||
@@ -8,7 +9,7 @@ namespace Ghost.Editor.View.Controls.Docking;
|
||||
/// A container that can host multiple dock modules with splitters.
|
||||
/// </summary>
|
||||
[TemplatePart(Name = PART_GRID, Type = typeof(Grid))]
|
||||
public class DockPanel : DockContainer
|
||||
public partial class DockPanel : DockContainer
|
||||
{
|
||||
private const string PART_GRID = "PART_Grid";
|
||||
private const double SPLITTER_THICKNESS = 4;
|
||||
@@ -116,5 +117,7 @@ public class DockPanel : DockContainer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UpdateLayout();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Ghost.Editor.View.Controls.Docking;
|
||||
/// <summary>
|
||||
/// Represents a visual highlight for a docking region.
|
||||
/// </summary>
|
||||
public class DockRegionHighlight : Control
|
||||
public partial class DockRegionHighlight : Control
|
||||
{
|
||||
public DockRegionHighlight()
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Ghost.Editor.View.Controls.Docking;
|
||||
/// </summary>
|
||||
[TemplatePart(Name = PART_OVERLAY_CANVAS, Type = typeof(Canvas))]
|
||||
[TemplatePart(Name = PART_HIGHLIGHT, Type = typeof(DockRegionHighlight))]
|
||||
public class DockingLayout : Control
|
||||
public partial class DockingLayout : Control
|
||||
{
|
||||
private const string PART_OVERLAY_CANVAS = "PART_OverlayCanvas";
|
||||
private const string PART_HIGHLIGHT = "PART_Highlight";
|
||||
|
||||
@@ -144,8 +144,6 @@
|
||||
DoubleTapped="PART_FilesView_DoubleTapped"
|
||||
IsDoubleTapEnabled="True"
|
||||
ItemsSource="{x:Bind ViewModel.Files, Mode=OneWay}"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||
ScrollViewer.HorizontalScrollMode="Disabled"
|
||||
SelectionChanged="PART_FilesView_SelectionChanged"
|
||||
SelectionMode="Single">
|
||||
<ItemsView.ItemTemplate>
|
||||
@@ -191,7 +189,7 @@
|
||||
</ItemsView.ItemTemplate>
|
||||
<ItemsView.Layout>
|
||||
<UniformGridLayout
|
||||
ItemsStretch="Fill"
|
||||
ItemsStretch="None"
|
||||
MinColumnSpacing="4"
|
||||
MinItemWidth="72"
|
||||
MinRowSpacing="4" />
|
||||
|
||||
@@ -49,6 +49,9 @@ internal sealed partial class ProjectBrowser : UserControl
|
||||
private void ProjectBrowser_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_inspectorService.OnSelectionChanged += _inspectorService_OnSelectionChanged;
|
||||
|
||||
// HACK: Scroll a little bit to trigger ScrollView to update it's scrollbar visibility. Otherwise the scrollbar will show a incorrect state when docking layout changes.
|
||||
PART_FilesView.ScrollView.ScrollBy(1, 0);
|
||||
}
|
||||
|
||||
private void ProjectBrowser_Unloaded(object sender, RoutedEventArgs e)
|
||||
|
||||
Reference in New Issue
Block a user