refactor(core): asset pipeline overhaul & dock removal
- Introduced IAsset interface and refactored asset loading/saving. - Migrated TextureContentHeader to Ghost.Engine; updated usage. - Rewrote AssetRegistry, AssetCatalog, ImportCoordinator for new asset flow. - Added thread-safe ConcurrentHashSet utility. - Improved EditorApplication folder management/init. - Updated TextureAssetHandler/TextureProcessor for new import/export. - Added EditorContentProvider for asset access. - Updated AssetManager to use new AssetType enum; removed GCHandle. - Removed all custom docking controls and templates. - Deleted obsolete ViewModels/Pages (Console, Hierarchy, Inspector, Project). - Renamed ProjectBrowser to ContentBrowser; updated references. - Updated NuGet packages, Result conversions, and commit instructions. - General cleanup: namespaces, dead code, structure.
This commit is contained in:
@@ -2,7 +2,7 @@ using Ghost.Editor.Core;
|
||||
|
||||
namespace Ghost.Editor.Views.Controls;
|
||||
|
||||
internal partial class ProjectBrowser
|
||||
internal partial class ContentBrowser
|
||||
{
|
||||
[ContextMenuItem("project-browser", "Show in Explorer")]
|
||||
private static void ShowInExplorer()
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<UserControl
|
||||
x:Class="Ghost.Editor.Views.Controls.ProjectBrowser"
|
||||
x:Class="Ghost.Editor.Views.Controls.ContentBrowser"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:community="using:CommunityToolkit.WinUI.Controls"
|
||||
@@ -8,9 +8,9 @@ using Microsoft.UI.Xaml.Input;
|
||||
|
||||
namespace Ghost.Editor.Views.Controls;
|
||||
|
||||
internal sealed partial class ProjectBrowser : UserControl
|
||||
internal sealed partial class ContentBrowser : UserControl
|
||||
{
|
||||
public static ProjectBrowser? LastFocused
|
||||
public static ContentBrowser? LastFocused
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
@@ -24,7 +24,7 @@ internal sealed partial class ProjectBrowser : UserControl
|
||||
get;
|
||||
}
|
||||
|
||||
public ProjectBrowser()
|
||||
public ContentBrowser()
|
||||
{
|
||||
_inspectorService = App.GetService<IInspectorService>();
|
||||
ViewModel = App.GetService<ProjectBrowserViewModel>();
|
||||
@@ -1,211 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Ghost.Editor.Views.Controls.Docking;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for containers that can hold other dock modules.
|
||||
/// </summary>
|
||||
public abstract class DockContainer : DockModule
|
||||
{
|
||||
private readonly ObservableCollection<DockModule> _children = new();
|
||||
private bool _isCleaningUp;
|
||||
/// <summary>
|
||||
/// Gets the collection of child modules.
|
||||
/// </summary>
|
||||
public ReadOnlyObservableCollection<DockModule> Children { get; }
|
||||
|
||||
protected DockContainer()
|
||||
{
|
||||
Children = new ReadOnlyObservableCollection<DockModule>(_children);
|
||||
_children.CollectionChanged += OnChildrenChanged;
|
||||
}
|
||||
|
||||
private void OnChildrenChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
OnChildrenUpdated();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a child module to the end of the container.
|
||||
/// </summary>
|
||||
/// <param name="module">The module to add.</param>
|
||||
public virtual void AddChild(DockModule module)
|
||||
{
|
||||
InsertChild(_children.Count, module);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a child module at the specified index.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method does not support reordering existing children within the same container.
|
||||
/// Cross-layout moves are intentionally allowed and supported (e.g., for dragging tabs between floating windows and the main window).
|
||||
/// </remarks>
|
||||
/// <param name="index">The zero-based index at which the module should be inserted.</param>
|
||||
/// <param name="module">The module to insert.</param>
|
||||
public virtual void InsertChild(int index, DockModule module)
|
||||
{
|
||||
ValidateChild(module);
|
||||
|
||||
if (module.Owner == null && module.Root != null && module.Root != this.Root)
|
||||
throw new InvalidOperationException("Cannot insert a module that is the root of another layout. Detach it first.");
|
||||
|
||||
if (index < 0 || index > _children.Count)
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
|
||||
if (_children.Contains(module))
|
||||
return;
|
||||
|
||||
module.Owner?.RemoveChild(module);
|
||||
|
||||
module.Owner = this;
|
||||
module.Root = Root;
|
||||
_children.Insert(index, module);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a child module from the container.
|
||||
/// </summary>
|
||||
/// <param name="module">The module to remove.</param>
|
||||
public virtual void RemoveChild(DockModule module)
|
||||
{
|
||||
RemoveChildInternal(module, true);
|
||||
}
|
||||
|
||||
internal void RemoveChildInternal(DockModule module, bool triggerCleanup)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(module);
|
||||
|
||||
if (_children.Remove(module))
|
||||
{
|
||||
module.Owner = null;
|
||||
module.Root = null;
|
||||
if (!_isCleaningUp && triggerCleanup)
|
||||
{
|
||||
CheckCleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces an existing child module with a new one.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Cross-layout moves are intentionally allowed and supported (e.g., for dragging tabs between floating windows and the main window).
|
||||
/// </remarks>
|
||||
/// <param name="oldChild">The child module to be replaced.</param>
|
||||
/// <param name="newChild">The new child module to insert.</param>
|
||||
public virtual void ReplaceChild(DockModule oldChild, DockModule newChild)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(oldChild);
|
||||
ValidateChild(newChild);
|
||||
|
||||
if (newChild.Owner == null && newChild.Root != null && newChild.Root != this.Root)
|
||||
throw new InvalidOperationException("Cannot insert a module that is the root of another layout. Detach it first.");
|
||||
|
||||
if (oldChild == newChild) return;
|
||||
|
||||
int index = _children.IndexOf(oldChild);
|
||||
if (index < 0) throw new ArgumentException("oldChild not found in this container", nameof(oldChild));
|
||||
|
||||
// Detach newChild from its current owner if any
|
||||
if (newChild.Owner == this)
|
||||
{
|
||||
throw new ArgumentException("newChild is already in this container", nameof(newChild));
|
||||
}
|
||||
|
||||
var oldOwner = newChild.Owner;
|
||||
newChild.Owner?.RemoveChildInternal(newChild, false);
|
||||
|
||||
// Remove oldChild without triggering cleanup
|
||||
_isCleaningUp = true;
|
||||
try
|
||||
{
|
||||
_children.RemoveAt(index);
|
||||
oldChild.Owner = null;
|
||||
oldChild.Root = null;
|
||||
|
||||
newChild.Owner = this;
|
||||
newChild.Root = Root;
|
||||
_children.Insert(index, newChild);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isCleaningUp = false;
|
||||
}
|
||||
|
||||
CheckCleanup();
|
||||
oldOwner?.CheckCleanup();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the container is empty and removes it from its owner if necessary.
|
||||
/// </summary>
|
||||
internal virtual void CheckCleanup()
|
||||
{
|
||||
if (Children.Count == 0)
|
||||
{
|
||||
if (Owner != null)
|
||||
{
|
||||
Owner.RemoveChildInternal(this, true);
|
||||
}
|
||||
else if (Root != null && Root.RootModule == this)
|
||||
{
|
||||
var root = Root;
|
||||
root.RootModule = null;
|
||||
root.NotifyLayoutEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates if a module can be added as a child to this container.
|
||||
/// </summary>
|
||||
/// <param name="module">The module to validate.</param>
|
||||
protected virtual void ValidateChild(DockModule module)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(module);
|
||||
|
||||
if (module == this)
|
||||
throw new ArgumentException("Cannot add a container to itself.", nameof(module));
|
||||
|
||||
if (module is DockContainer container)
|
||||
{
|
||||
var current = Owner;
|
||||
while (current != null)
|
||||
{
|
||||
if (current == container)
|
||||
throw new ArgumentException("Cannot add a container that is an ancestor of this container.", nameof(module));
|
||||
current = current.Owner;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all child modules from the container.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
foreach (var child in _children)
|
||||
{
|
||||
child.Owner = null;
|
||||
child.Root = null;
|
||||
}
|
||||
_children.Clear();
|
||||
if (!_isCleaningUp)
|
||||
{
|
||||
CheckCleanup();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnRootChanged()
|
||||
{
|
||||
foreach (var child in _children)
|
||||
{
|
||||
child.Root = Root;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnChildrenUpdated() { }
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Ghost.Editor.Views.Controls.Docking;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a document module in the docking system.
|
||||
/// </summary>
|
||||
public partial class DockDocument : DockModule
|
||||
{
|
||||
public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(
|
||||
nameof(Title), typeof(string), typeof(DockDocument), new PropertyMetadata(string.Empty));
|
||||
|
||||
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(
|
||||
nameof(Content), typeof(object), typeof(DockDocument), new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the title of the document.
|
||||
/// </summary>
|
||||
public string? Title
|
||||
{
|
||||
get => (string?)GetValue(TitleProperty);
|
||||
set => SetValue(TitleProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the content of the document.
|
||||
/// </summary>
|
||||
public object? Content
|
||||
{
|
||||
get => GetValue(ContentProperty);
|
||||
set => SetValue(ContentProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DockDocument"/> class.
|
||||
/// </summary>
|
||||
public DockDocument()
|
||||
{
|
||||
DefaultStyleKey = typeof(DockDocument);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Ghost.Editor.Views.Controls.Docking">
|
||||
|
||||
<Style TargetType="local:DockDocument">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Stretch" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="local:DockDocument">
|
||||
<Border Background="Transparent">
|
||||
<ContentPresenter
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Content="{TemplateBinding Content}" />
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -1,182 +0,0 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
|
||||
namespace Ghost.Editor.Views.Controls.Docking;
|
||||
|
||||
/// <summary>
|
||||
/// A container that displays its children (documents) as tabs.
|
||||
/// </summary>
|
||||
[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 || Root == null) return;
|
||||
|
||||
var selectedDoc = _tabView.SelectedItem is TabViewItem selectedItem ? selectedItem.Tag as DockDocument : null;
|
||||
|
||||
// Remove tabs that are no longer in Children
|
||||
for (int i = _tabView.TabItems.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (_tabView.TabItems[i] is TabViewItem tabItem && tabItem.Tag is DockDocument doc)
|
||||
{
|
||||
if (!Children.Contains(doc))
|
||||
{
|
||||
tabItem.Content = null;
|
||||
_tabView.TabItems.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add new tabs that aren't in TabItems yet, and ensure correct order
|
||||
for (int i = 0; i < Children.Count; i++)
|
||||
{
|
||||
if (Children[i] is DockDocument doc)
|
||||
{
|
||||
TabViewItem? existingTab = null;
|
||||
for (int j = 0; j < _tabView.TabItems.Count; j++)
|
||||
{
|
||||
if (_tabView.TabItems[j] is TabViewItem tabItem && tabItem.Tag == doc)
|
||||
{
|
||||
existingTab = tabItem;
|
||||
// Fix order if necessary
|
||||
if (j != i)
|
||||
{
|
||||
_tabView.TabItems.RemoveAt(j);
|
||||
_tabView.TabItems.Insert(i, existingTab);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (existingTab == null)
|
||||
{
|
||||
existingTab = new TabViewItem
|
||||
{
|
||||
Tag = doc,
|
||||
Content = doc
|
||||
};
|
||||
|
||||
existingTab.SetBinding(TabViewItem.HeaderProperty, new Binding
|
||||
{
|
||||
Source = doc,
|
||||
Path = new PropertyPath(nameof(DockDocument.Title)),
|
||||
Mode = Microsoft.UI.Xaml.Data.BindingMode.OneWay
|
||||
});
|
||||
|
||||
_tabView.TabItems.Insert(i, existingTab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Restore selection
|
||||
if (selectedDoc != null && _tabView.TabItems.FirstOrDefault(t => t is TabViewItem item && item.Tag == selectedDoc) is TabViewItem newSelected)
|
||||
{
|
||||
_tabView.SelectedItem = newSelected;
|
||||
}
|
||||
else if (_tabView.TabItems.Count > 0)
|
||||
{
|
||||
_tabView.SelectedItem = _tabView.TabItems[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Ghost.Editor.Views.Controls.Docking">
|
||||
|
||||
<Style TargetType="local:DockGroup">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="local:DockGroup">
|
||||
<TabView
|
||||
x:Name="PART_TabView"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
AllowDrop="True"
|
||||
CanDragTabs="True"
|
||||
CanReorderTabs="True"
|
||||
IsAddTabButtonVisible="True"
|
||||
TabWidthMode="Compact" />
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -1,47 +0,0 @@
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Ghost.Editor.Views.Controls.Docking;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for all dockable modules in the docking system.
|
||||
/// </summary>
|
||||
public abstract class DockModule : Control
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the container that owns this module.
|
||||
/// </summary>
|
||||
public DockContainer? Owner { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the proportional length (star weight) of this module within its parent panel.
|
||||
/// </summary>
|
||||
public double DockLength { get; set; } = 1.0;
|
||||
|
||||
private DockingLayout? _root;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the root docking layout this module belongs to.
|
||||
/// </summary>
|
||||
public virtual DockingLayout? Root
|
||||
{
|
||||
get => _root;
|
||||
internal set
|
||||
{
|
||||
if (_root != value)
|
||||
{
|
||||
_root = value;
|
||||
OnRootChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnRootChanged() { }
|
||||
|
||||
/// <summary>
|
||||
/// Detaches this module from its current owner.
|
||||
/// </summary>
|
||||
public void Detach()
|
||||
{
|
||||
Owner?.RemoveChild(this);
|
||||
}
|
||||
}
|
||||
@@ -1,231 +0,0 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using CommunityToolkit.WinUI.Controls;
|
||||
using Windows.Foundation;
|
||||
|
||||
namespace Ghost.Editor.Views.Controls.Docking;
|
||||
|
||||
/// <summary>
|
||||
/// A container that can host multiple dock modules with splitters.
|
||||
/// </summary>
|
||||
[TemplatePart(Name = PART_GRID, Type = typeof(Grid))]
|
||||
public partial class DockPanel : DockContainer
|
||||
{
|
||||
private const string PART_GRID = "PART_Grid";
|
||||
private const double SPLITTER_THICKNESS = 4;
|
||||
|
||||
public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(
|
||||
nameof(Orientation), typeof(Orientation), typeof(DockPanel), new PropertyMetadata(Orientation.Horizontal, OnOrientationChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the orientation of the panel.
|
||||
/// </summary>
|
||||
public Orientation Orientation
|
||||
{
|
||||
get => (Orientation)GetValue(OrientationProperty);
|
||||
set => SetValue(OrientationProperty, value);
|
||||
}
|
||||
|
||||
private Grid? _grid;
|
||||
|
||||
public DockPanel()
|
||||
{
|
||||
DefaultStyleKey = typeof(DockPanel);
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
_grid = GetTemplateChild(PART_GRID) as Grid;
|
||||
UpdateLayoutStructure();
|
||||
}
|
||||
|
||||
protected override void OnChildrenUpdated()
|
||||
{
|
||||
UpdateLayoutStructure();
|
||||
}
|
||||
|
||||
internal void SyncLengths()
|
||||
{
|
||||
if (_grid == null) return;
|
||||
if (Orientation == Orientation.Horizontal)
|
||||
{
|
||||
for (int i = 0; i < Children.Count; i++)
|
||||
{
|
||||
int col = i * 2;
|
||||
if (col < _grid.ColumnDefinitions.Count)
|
||||
{
|
||||
Children[i].DockLength = _grid.ColumnDefinitions[col].Width.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < Children.Count; i++)
|
||||
{
|
||||
int row = i * 2;
|
||||
if (row < _grid.RowDefinitions.Count)
|
||||
{
|
||||
Children[i].DockLength = _grid.RowDefinitions[row].Height.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal override void CheckCleanup()
|
||||
{
|
||||
base.CheckCleanup();
|
||||
|
||||
if (Children.Count == 1)
|
||||
{
|
||||
var child = Children[0];
|
||||
var owner = Owner;
|
||||
|
||||
if (owner != null)
|
||||
{
|
||||
owner.ReplaceChild(this, child);
|
||||
}
|
||||
else if (Root != null && Root.RootModule == this)
|
||||
{
|
||||
RemoveChildInternal(child, false);
|
||||
Root.RootModule = child;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnOrientationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
((DockPanel)d).UpdateLayoutStructure();
|
||||
}
|
||||
|
||||
private void UpdateLayoutStructure()
|
||||
{
|
||||
if (_grid == null) return;
|
||||
|
||||
// Remove splitters and children that are no longer in the collection
|
||||
for (int i = _grid.Children.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var child = _grid.Children[i];
|
||||
if (child is GridSplitter)
|
||||
{
|
||||
_grid.Children.RemoveAt(i);
|
||||
}
|
||||
else if (child is DockModule module && !Children.Contains(module))
|
||||
{
|
||||
_grid.Children.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (Children.Count == 0)
|
||||
{
|
||||
_grid.RowDefinitions.Clear();
|
||||
_grid.ColumnDefinitions.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Orientation == Orientation.Horizontal)
|
||||
{
|
||||
_grid.RowDefinitions.Clear();
|
||||
|
||||
int requiredColumns = (Children.Count * 2) - 1;
|
||||
while (_grid.ColumnDefinitions.Count > requiredColumns)
|
||||
{
|
||||
_grid.ColumnDefinitions.RemoveAt(_grid.ColumnDefinitions.Count - 1);
|
||||
}
|
||||
|
||||
for (var i = 0; i < Children.Count; i++)
|
||||
{
|
||||
int columnIndex = i * 2;
|
||||
if (columnIndex >= _grid.ColumnDefinitions.Count)
|
||||
{
|
||||
_grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(Children[i].DockLength, GridUnitType.Star), MinWidth = 250 });
|
||||
}
|
||||
else
|
||||
{
|
||||
_grid.ColumnDefinitions[columnIndex].Width = new GridLength(Children[i].DockLength, GridUnitType.Star);
|
||||
_grid.ColumnDefinitions[columnIndex].MinWidth = 250;
|
||||
}
|
||||
|
||||
var child = Children[i];
|
||||
if (!_grid.Children.Contains(child))
|
||||
{
|
||||
_grid.Children.Add(child);
|
||||
}
|
||||
|
||||
Grid.SetColumn(child, columnIndex);
|
||||
Grid.SetRow(child, 0);
|
||||
|
||||
if (i < Children.Count - 1)
|
||||
{
|
||||
int splitterIndex = columnIndex + 1;
|
||||
if (splitterIndex >= _grid.ColumnDefinitions.Count)
|
||||
{
|
||||
_grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
|
||||
}
|
||||
else
|
||||
{
|
||||
_grid.ColumnDefinitions[splitterIndex].Width = GridLength.Auto;
|
||||
}
|
||||
|
||||
var splitter = new GridSplitter { ResizeDirection = GridSplitter.GridResizeDirection.Columns, Width = SPLITTER_THICKNESS };
|
||||
Grid.SetColumn(splitter, splitterIndex);
|
||||
Grid.SetRow(splitter, 0);
|
||||
_grid.Children.Add(splitter);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_grid.ColumnDefinitions.Clear();
|
||||
|
||||
int requiredRows = (Children.Count * 2) - 1;
|
||||
while (_grid.RowDefinitions.Count > requiredRows)
|
||||
{
|
||||
_grid.RowDefinitions.RemoveAt(_grid.RowDefinitions.Count - 1);
|
||||
}
|
||||
|
||||
for (var i = 0; i < Children.Count; i++)
|
||||
{
|
||||
int rowIndex = i * 2;
|
||||
if (rowIndex >= _grid.RowDefinitions.Count)
|
||||
{
|
||||
_grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(Children[i].DockLength, GridUnitType.Star), MinHeight = 250 });
|
||||
}
|
||||
else
|
||||
{
|
||||
_grid.RowDefinitions[rowIndex].Height = new GridLength(Children[i].DockLength, GridUnitType.Star);
|
||||
_grid.RowDefinitions[rowIndex].MinHeight = 250;
|
||||
}
|
||||
|
||||
var child = Children[i];
|
||||
if (!_grid.Children.Contains(child))
|
||||
{
|
||||
_grid.Children.Add(child);
|
||||
}
|
||||
|
||||
Grid.SetRow(child, rowIndex);
|
||||
Grid.SetColumn(child, 0);
|
||||
|
||||
if (i < Children.Count - 1)
|
||||
{
|
||||
int splitterIndex = rowIndex + 1;
|
||||
if (splitterIndex >= _grid.RowDefinitions.Count)
|
||||
{
|
||||
_grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
|
||||
}
|
||||
else
|
||||
{
|
||||
_grid.RowDefinitions[splitterIndex].Height = GridLength.Auto;
|
||||
}
|
||||
|
||||
var splitter = new GridSplitter { ResizeDirection = GridSplitter.GridResizeDirection.Rows, Height = SPLITTER_THICKNESS };
|
||||
Grid.SetRow(splitter, splitterIndex);
|
||||
Grid.SetColumn(splitter, 0);
|
||||
_grid.Children.Add(splitter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UpdateLayout();
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Ghost.Editor.Views.Controls.Docking">
|
||||
|
||||
<Style TargetType="local:DockPanel">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="local:DockPanel">
|
||||
<Grid x:Name="PART_Grid" />
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -1,15 +0,0 @@
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Ghost.Editor.Views.Controls.Docking;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a visual highlight for a docking region.
|
||||
/// </summary>
|
||||
public partial class DockRegionHighlight : Control
|
||||
{
|
||||
public DockRegionHighlight()
|
||||
{
|
||||
DefaultStyleKey = typeof(DockRegionHighlight);
|
||||
IsHitTestVisible = false;
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Ghost.Editor.Views.Controls.Docking">
|
||||
|
||||
<Style TargetType="local:DockRegionHighlight">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="local:DockRegionHighlight">
|
||||
<Border
|
||||
Background="{ThemeResource SystemControlHighlightAccentBrush}"
|
||||
BorderBrush="{ThemeResource SystemControlHighlightAccentBrush}"
|
||||
BorderThickness="2"
|
||||
CornerRadius="4"
|
||||
Opacity="0.25" />
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -1,344 +0,0 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Ghost.Editor.Views.Controls.Docking;
|
||||
|
||||
/// <summary>
|
||||
/// The root control for the docking system layout.
|
||||
/// </summary>
|
||||
[TemplatePart(Name = PART_OVERLAY_CANVAS, Type = typeof(Canvas))]
|
||||
[TemplatePart(Name = PART_HIGHLIGHT, Type = typeof(DockRegionHighlight))]
|
||||
public partial class DockingLayout : Control
|
||||
{
|
||||
private const string PART_OVERLAY_CANVAS = "PART_OverlayCanvas";
|
||||
private const string PART_HIGHLIGHT = "PART_Highlight";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the root module of the docking layout.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty RootModuleProperty = DependencyProperty.Register(
|
||||
nameof(RootModule), typeof(DockModule), typeof(DockingLayout), new PropertyMetadata(null, OnRootModuleChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the root module of the docking layout.
|
||||
/// </summary>
|
||||
public DockModule? RootModule
|
||||
{
|
||||
get => (DockModule?)GetValue(RootModuleProperty);
|
||||
set => SetValue(RootModuleProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the layout becomes empty.
|
||||
/// </summary>
|
||||
public event EventHandler? LayoutEmpty;
|
||||
|
||||
internal void NotifyLayoutEmpty() => LayoutEmpty?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
private Canvas? _overlayCanvas;
|
||||
private DockRegionHighlight? _highlight;
|
||||
private readonly List<FloatingWindow> _floatingWindows = new();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DockingLayout"/> class.
|
||||
/// </summary>
|
||||
public DockingLayout()
|
||||
{
|
||||
DefaultStyleKey = typeof(DockingLayout);
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
_overlayCanvas = GetTemplateChild(PART_OVERLAY_CANVAS) as Canvas;
|
||||
_highlight = GetTemplateChild(PART_HIGHLIGHT) as DockRegionHighlight;
|
||||
}
|
||||
|
||||
private static void OnRootModuleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is DockingLayout layout)
|
||||
{
|
||||
if (e.OldValue is DockModule oldModule)
|
||||
{
|
||||
oldModule.Root = null;
|
||||
}
|
||||
|
||||
if (e.NewValue is DockModule newModule)
|
||||
{
|
||||
if (newModule.Root != null && newModule.Root != layout)
|
||||
{
|
||||
throw new InvalidOperationException("Module is already owned by another DockingLayout");
|
||||
}
|
||||
|
||||
if (newModule.Owner != null)
|
||||
{
|
||||
newModule.Owner.RemoveChild(newModule);
|
||||
}
|
||||
|
||||
newModule.Root = layout;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a document to the docking layout.
|
||||
/// </summary>
|
||||
/// <param name="document">The document to add.</param>
|
||||
/// <param name="target">The docking target position.</param>
|
||||
/// <param name="targetGroup">The target group to add the document to. If null, a suitable group will be found or created.</param>
|
||||
public void AddDocument(DockDocument document, DockTarget target, DockGroup? targetGroup = null)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(document);
|
||||
|
||||
if (targetGroup != null && targetGroup.Root != this)
|
||||
{
|
||||
throw new ArgumentException("targetGroup does not belong to this DockingLayout", nameof(targetGroup));
|
||||
}
|
||||
|
||||
if (targetGroup == null)
|
||||
{
|
||||
if (RootModule != null)
|
||||
{
|
||||
targetGroup = FindFirstDockGroup(RootModule as DockContainer);
|
||||
if (targetGroup == null)
|
||||
{
|
||||
// Root is not a container, or contains no pGroups. Wrap it.
|
||||
var newGroup = new DockGroup();
|
||||
newGroup.AddChild(document);
|
||||
|
||||
if (RootModule is DockDocument existingDoc)
|
||||
{
|
||||
RootModule = null;
|
||||
newGroup.AddChild(existingDoc);
|
||||
RootModule = newGroup;
|
||||
}
|
||||
else
|
||||
{
|
||||
var oldRoot = RootModule;
|
||||
RootModule = null;
|
||||
var panel = new DockPanel();
|
||||
panel.AddChild(oldRoot);
|
||||
panel.AddChild(newGroup);
|
||||
RootModule = panel;
|
||||
}
|
||||
targetGroup = newGroup;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
targetGroup = new DockGroup();
|
||||
RootModule = targetGroup;
|
||||
}
|
||||
}
|
||||
|
||||
if (target == DockTarget.Center || targetGroup.Children.Count == 0)
|
||||
{
|
||||
targetGroup.AddChild(document);
|
||||
}
|
||||
else
|
||||
{
|
||||
SplitGroup(targetGroup, document, target);
|
||||
}
|
||||
}
|
||||
|
||||
private void SplitGroup(DockGroup targetGroup, DockDocument doc, DockTarget target)
|
||||
{
|
||||
var parentPanel = targetGroup.Owner as DockPanel;
|
||||
parentPanel?.SyncLengths(); // Sync before modifying!
|
||||
|
||||
var newGroup = new DockGroup();
|
||||
newGroup.AddChild(doc);
|
||||
|
||||
var orientation = (target == DockTarget.Left || target == DockTarget.Right) ? Orientation.Horizontal : Orientation.Vertical;
|
||||
|
||||
if (parentPanel == null)
|
||||
{
|
||||
// targetGroup is the RootModule
|
||||
var newPanel = new DockPanel { Orientation = orientation };
|
||||
RootModule = newPanel;
|
||||
|
||||
targetGroup.DockLength = 1.0;
|
||||
newGroup.DockLength = 1.0;
|
||||
|
||||
if (target == DockTarget.Left || target == DockTarget.Top)
|
||||
{
|
||||
newPanel.AddChild(newGroup);
|
||||
newPanel.AddChild(targetGroup);
|
||||
}
|
||||
else
|
||||
{
|
||||
newPanel.AddChild(targetGroup);
|
||||
newPanel.AddChild(newGroup);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int index = parentPanel.Children.IndexOf(targetGroup);
|
||||
|
||||
if (index < 0)
|
||||
{
|
||||
throw new InvalidOperationException("targetGroup not found in parentPanel");
|
||||
}
|
||||
|
||||
if (parentPanel.Orientation == orientation)
|
||||
{
|
||||
// Splitting in the same orientation. Share the length.
|
||||
double halfLength = targetGroup.DockLength / 2.0;
|
||||
targetGroup.DockLength = halfLength;
|
||||
newGroup.DockLength = halfLength;
|
||||
|
||||
if (target == DockTarget.Left || target == DockTarget.Top)
|
||||
{
|
||||
parentPanel.InsertChild(index, newGroup);
|
||||
}
|
||||
else
|
||||
{
|
||||
parentPanel.InsertChild(index + 1, newGroup);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Splitting in opposite orientation. New panel takes the full length.
|
||||
var newPanel = new DockPanel { Orientation = orientation };
|
||||
newPanel.DockLength = targetGroup.DockLength;
|
||||
|
||||
targetGroup.DockLength = 1.0;
|
||||
newGroup.DockLength = 1.0;
|
||||
|
||||
parentPanel.ReplaceChild(targetGroup, newPanel);
|
||||
|
||||
if (target == DockTarget.Left || target == DockTarget.Top)
|
||||
{
|
||||
newPanel.AddChild(newGroup);
|
||||
newPanel.AddChild(targetGroup);
|
||||
}
|
||||
else
|
||||
{
|
||||
newPanel.AddChild(targetGroup);
|
||||
newPanel.AddChild(newGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static DockGroup? FindFirstDockGroup(DockContainer? container)
|
||||
{
|
||||
if (container == null) return null;
|
||||
|
||||
if (container is DockGroup group)
|
||||
{
|
||||
return group;
|
||||
}
|
||||
|
||||
foreach (var child in container.Children)
|
||||
{
|
||||
if (child is DockContainer childContainer)
|
||||
{
|
||||
var result = FindFirstDockGroup(childContainer);
|
||||
if (result != null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
internal void ShowHighlight(DockGroup targetGroup, global::Windows.Foundation.Point position)
|
||||
{
|
||||
if (_highlight == null || _overlayCanvas == null) return;
|
||||
|
||||
_highlight.Visibility = Visibility.Visible;
|
||||
var target = CalculateDockTarget(targetGroup, position);
|
||||
|
||||
// Calculate rect based on target
|
||||
double width = targetGroup.ActualWidth;
|
||||
double height = targetGroup.ActualHeight;
|
||||
double x = 0, y = 0;
|
||||
|
||||
switch (target)
|
||||
{
|
||||
case DockTarget.Left: width /= 2; break;
|
||||
case DockTarget.Right: width /= 2; x = width; break;
|
||||
case DockTarget.Top: height /= 2; break;
|
||||
case DockTarget.Bottom: height /= 2; y = height; break;
|
||||
case DockTarget.Center: break;
|
||||
}
|
||||
|
||||
var transform = targetGroup.TransformToVisual(_overlayCanvas);
|
||||
var point = transform.TransformPoint(new global::Windows.Foundation.Point(x, y));
|
||||
|
||||
Microsoft.UI.Xaml.Controls.Canvas.SetLeft(_highlight, point.X);
|
||||
Microsoft.UI.Xaml.Controls.Canvas.SetTop(_highlight, point.Y);
|
||||
_highlight.Width = width;
|
||||
_highlight.Height = height;
|
||||
}
|
||||
|
||||
internal void HideHighlight()
|
||||
{
|
||||
if (_highlight != null) _highlight.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
internal void HandleDrop(DockDocument doc, DockGroup targetGroup, global::Windows.Foundation.Point position)
|
||||
{
|
||||
HideHighlight();
|
||||
var target = CalculateDockTarget(targetGroup, position);
|
||||
|
||||
var oldOwner = doc.Owner as DockContainer;
|
||||
oldOwner?.RemoveChildInternal(doc, false);
|
||||
|
||||
if (target == DockTarget.Center)
|
||||
{
|
||||
if (doc.Owner == targetGroup) return;
|
||||
targetGroup.AddChild(doc);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (doc.Owner == targetGroup && targetGroup.Children.Count == 1) return;
|
||||
SplitGroup(targetGroup, doc, target);
|
||||
}
|
||||
|
||||
if (oldOwner != null)
|
||||
{
|
||||
DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal, () =>
|
||||
{
|
||||
oldOwner.CheckCleanup();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private DockTarget CalculateDockTarget(DockGroup group, global::Windows.Foundation.Point position)
|
||||
{
|
||||
double w = group.ActualWidth;
|
||||
double h = group.ActualHeight;
|
||||
double x = position.X;
|
||||
double y = position.Y;
|
||||
|
||||
if (x < w * 0.25) return DockTarget.Left;
|
||||
if (x > w * 0.75) return DockTarget.Right;
|
||||
if (y < h * 0.25) return DockTarget.Top;
|
||||
if (y > h * 0.75) return DockTarget.Bottom;
|
||||
return DockTarget.Center;
|
||||
}
|
||||
|
||||
internal void CreateFloatingWindow(DockDocument doc)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(doc);
|
||||
|
||||
var oldOwner = doc.Owner as DockContainer;
|
||||
oldOwner?.RemoveChildInternal(doc, false);
|
||||
|
||||
var window = new FloatingWindow(doc);
|
||||
_floatingWindows.Add(window);
|
||||
window.Closed += (s, e) => _floatingWindows.Remove(window);
|
||||
window.Activate();
|
||||
|
||||
if (oldOwner != null)
|
||||
{
|
||||
DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal, () =>
|
||||
{
|
||||
oldOwner.CheckCleanup();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Ghost.Editor.Views.Controls.Docking">
|
||||
|
||||
<Style TargetType="local:DockingLayout">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="local:DockingLayout">
|
||||
<Grid>
|
||||
<ContentPresenter x:Name="PART_Content" Content="{TemplateBinding RootModule}" />
|
||||
<Canvas x:Name="PART_OverlayCanvas" IsHitTestVisible="False">
|
||||
<local:DockRegionHighlight x:Name="PART_Highlight" Visibility="Collapsed" />
|
||||
</Canvas>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -1,10 +0,0 @@
|
||||
namespace Ghost.Editor.Views.Controls.Docking;
|
||||
|
||||
public enum DockTarget
|
||||
{
|
||||
Center,
|
||||
Left,
|
||||
Right,
|
||||
Top,
|
||||
Bottom
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
|
||||
namespace Ghost.Editor.Views.Controls.Docking;
|
||||
|
||||
/// <summary>
|
||||
/// A floating window that contains a docking layout.
|
||||
/// </summary>
|
||||
public class FloatingWindow : Window
|
||||
{
|
||||
private readonly DockingLayout _layout;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FloatingWindow"/> class with the specified document.
|
||||
/// </summary>
|
||||
/// <param name="document">The document to display in the floating window.</param>
|
||||
public FloatingWindow(DockDocument document)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(document);
|
||||
|
||||
_layout = new DockingLayout();
|
||||
var group = new DockGroup();
|
||||
group.AddChild(document);
|
||||
|
||||
_layout.RootModule = group;
|
||||
_layout.LayoutEmpty += (s, e) => Close();
|
||||
|
||||
Content = _layout;
|
||||
|
||||
// Basic window setup
|
||||
AppWindow.Resize(new global::Windows.Graphics.SizeInt32(800, 600));
|
||||
|
||||
// When the user manually closes the window, ensure we clean up the documents inside
|
||||
this.Closed += FloatingWindow_Closed;
|
||||
}
|
||||
|
||||
private void FloatingWindow_Closed(object sender, WindowEventArgs args)
|
||||
{
|
||||
// Force cleanup of the visual tree so we don't leak anything from this window
|
||||
_layout.RootModule = null;
|
||||
Content = null;
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Page
|
||||
x:Class="Ghost.Editor.Views.Pages.EngineEditor.ConsolePage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Ghost.Editor.Views.Pages.EngineEditor"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Background="{ThemeResource LayerFillColorDefaultBrush}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Toolbar -->
|
||||
<Grid
|
||||
Grid.Row="0"
|
||||
Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}"
|
||||
BorderBrush="{ThemeResource CardStrokeColorDefaultSolid}"
|
||||
BorderThickness="0,0,0,1">
|
||||
<CommandBar DefaultLabelPosition="Collapsed">
|
||||
<CommandBar.PrimaryCommands>
|
||||
<AppBarButton Command="{x:Bind ViewModel.ClearLogsCommand}" Content="Clear" />
|
||||
<AppBarSeparator />
|
||||
<AppBarToggleButton Width="45" IsChecked="{x:Bind ViewModel.ShowInfo, Mode=TwoWay}">
|
||||
<AppBarToggleButton.Icon>
|
||||
<FontIcon Glyph="" />
|
||||
</AppBarToggleButton.Icon>
|
||||
</AppBarToggleButton>
|
||||
<AppBarToggleButton Width="45" IsChecked="{x:Bind ViewModel.ShowWarning, Mode=TwoWay}">
|
||||
<AppBarToggleButton.Icon>
|
||||
<FontIcon Glyph="" />
|
||||
</AppBarToggleButton.Icon>
|
||||
</AppBarToggleButton>
|
||||
<AppBarToggleButton Width="45" IsChecked="{x:Bind ViewModel.ShowError, Mode=TwoWay}">
|
||||
<AppBarToggleButton.Icon>
|
||||
<FontIcon Glyph="" />
|
||||
</AppBarToggleButton.Icon>
|
||||
</AppBarToggleButton>
|
||||
</CommandBar.PrimaryCommands>
|
||||
|
||||
<CommandBar.SecondaryCommands>
|
||||
<AppBarToggleButton BorderThickness="0" Label="Clear On Play" />
|
||||
<AppBarToggleButton
|
||||
BorderThickness="0"
|
||||
IsChecked="{x:Bind ViewModel.ShowStackTrace, Mode=TwoWay}"
|
||||
Label="Show Stack Trace" />
|
||||
</CommandBar.SecondaryCommands>
|
||||
</CommandBar>
|
||||
</Grid>
|
||||
|
||||
<!-- Log Content -->
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="100" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<ListView
|
||||
x:Name="LogListView"
|
||||
Grid.Row="0"
|
||||
ItemsSource="{x:Bind ViewModel.Logs, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind ViewModel.SelectedLog, Mode=TwoWay}" />
|
||||
<Grid
|
||||
Grid.Row="1"
|
||||
Padding="4"
|
||||
BorderBrush="{ThemeResource CardStrokeColorDefaultSolid}"
|
||||
BorderThickness="0,1,0,0">
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||
<TextBlock
|
||||
IsTextSelectionEnabled="True"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind ViewModel.SelectedLog.ToString(), Mode=OneWay}"
|
||||
TextWrapping="Wrap" />
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>
|
||||
@@ -1,19 +0,0 @@
|
||||
using Ghost.Editor.ViewModels.Pages.EngineEditor;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Ghost.Editor.Views.Pages.EngineEditor;
|
||||
|
||||
internal sealed partial class ConsolePage : Page
|
||||
{
|
||||
public ConsoleViewModel ViewModel
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public ConsolePage()
|
||||
{
|
||||
ViewModel = App.GetService<ConsoleViewModel>();
|
||||
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<internal:NavigationTabPage
|
||||
x:Class="Ghost.Editor.Views.Pages.EngineEditor.HierarchyPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:internal="using:Ghost.Editor.Controls"
|
||||
xmlns:local="using:Ghost.Editor.Views.Pages.EngineEditor"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:sg="using:Ghost.Editor.Core.SceneGraph"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<internal:NavigationTabPage.Resources>
|
||||
<DataTemplate x:Key="SceneTemplate" x:DataType="sg:SceneGraphNode">
|
||||
<TreeViewItem
|
||||
AutomationProperties.Name="{x:Bind Name, Mode=OneWay}"
|
||||
Background="{ThemeResource ControlSolidFillColorDefaultBrush}"
|
||||
IsExpanded="True"
|
||||
ItemsSource="{x:Bind Children, Mode=OneWay}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<FontIcon FontSize="14" Glyph="" />
|
||||
<TextBlock Margin="10,0" Text="{x:Bind Name, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="EntityTemplate" x:DataType="sg:SceneGraphNode">
|
||||
<TreeViewItem AutomationProperties.Name="{x:Bind Name, Mode=OneWay}" ItemsSource="{x:Bind Children, Mode=OneWay}">
|
||||
<StackPanel Margin="10,0" Orientation="Horizontal">
|
||||
<FontIcon FontSize="14" Glyph="" />
|
||||
<TextBlock Margin="5,0,0,0" Text="{x:Bind Name, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
</DataTemplate>
|
||||
</internal:NavigationTabPage.Resources>
|
||||
|
||||
<Grid Padding="4,6" Background="{ThemeResource LayerFillColorDefaultBrush}">
|
||||
<!--<TreeView ItemsSource="{x:Bind ViewModel.SceneList}" SelectionChanged="TreeView_SelectionChanged">
|
||||
<TreeView.ItemTemplateSelector>
|
||||
<local:HierarchyTemplateSector />
|
||||
</TreeView.ItemTemplateSelector>
|
||||
</TreeView>-->
|
||||
</Grid>
|
||||
</internal:NavigationTabPage>
|
||||
@@ -1,61 +0,0 @@
|
||||
using Ghost.Editor.Controls;
|
||||
using Ghost.Editor.Core.Contracts;
|
||||
using Ghost.Editor.Core.SceneGraph;
|
||||
using Ghost.Editor.ViewModels.Pages.EngineEditor;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Ghost.Editor.Views.Pages.EngineEditor;
|
||||
|
||||
internal sealed partial class HierarchyPage : NavigationTabPage
|
||||
{
|
||||
private readonly IInspectorService _inspectorService;
|
||||
|
||||
public HierarchyViewModel ViewModel
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public HierarchyPage()
|
||||
{
|
||||
_inspectorService = App.GetService<IInspectorService>();
|
||||
ViewModel = App.GetService<HierarchyViewModel>();
|
||||
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public override void OnNavigatedTo(object? parameter)
|
||||
{
|
||||
ViewModel.OnNavigatedTo(parameter);
|
||||
}
|
||||
|
||||
public override void OnNavigatedFrom()
|
||||
{
|
||||
ViewModel.OnNavigatedFrom();
|
||||
}
|
||||
|
||||
private void TreeView_SelectionChanged(TreeView sender, TreeViewSelectionChangedEventArgs args)
|
||||
{
|
||||
if (args.AddedItems.Count > 0 && args.AddedItems[0] is IInspectable inspectable)
|
||||
{
|
||||
_inspectorService.SetSelected(inspectable, ViewModel);
|
||||
}
|
||||
else
|
||||
{
|
||||
_inspectorService.SetSelected(null, ViewModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal partial class HierarchyTemplateSector : DataTemplateSelector
|
||||
{
|
||||
protected override DataTemplate SelectTemplateCore(object item)
|
||||
{
|
||||
if (item is not SceneGraphNode node)
|
||||
{
|
||||
return base.SelectTemplateCore(item);
|
||||
}
|
||||
|
||||
return node.GetSceneHierarchyTemplate();
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<internal:NavigationTabPage
|
||||
x:Class="Ghost.Editor.Views.Pages.EngineEditor.InspectorPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:internal="using:Ghost.Editor.Controls"
|
||||
xmlns:local="using:Ghost.Editor.Views.Pages.EngineEditor"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Background="{ThemeResource LayerFillColorDefaultBrush}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="75" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Header -->
|
||||
<Grid
|
||||
Grid.Row="0"
|
||||
Padding="15,0,10,0"
|
||||
Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}"
|
||||
BorderBrush="{ThemeResource CardStrokeColorDefaultSolid}"
|
||||
BorderThickness="0,0,0,1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<!--<IconSourceElement
|
||||
Grid.Column="0"
|
||||
Margin="0,0,15,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
IconSource="{x:Bind ViewModel.Inspectable.Icon, Mode=OneWay}" />-->
|
||||
<!--<ContentPresenter Grid.Column="1" Content="{x:Bind ViewModel.Inspectable.HeaderContent, Mode=OneWay}" />-->
|
||||
</Grid>
|
||||
|
||||
<!-- Content -->
|
||||
<Grid Grid.Row="1" Padding="0,0,0,0">
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
|
||||
<!--<ContentPresenter Content="{x:Bind ViewModel.Inspectable.InspectorContent, Mode=OneWay}" />-->
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</internal:NavigationTabPage>
|
||||
@@ -1,29 +0,0 @@
|
||||
using Ghost.Editor.Controls;
|
||||
using Ghost.Editor.ViewModels.Pages.EngineEditor;
|
||||
|
||||
namespace Ghost.Editor.Views.Pages.EngineEditor;
|
||||
|
||||
internal sealed partial class InspectorPage : NavigationTabPage
|
||||
{
|
||||
public InspectorViewModel ViewModel
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public InspectorPage()
|
||||
{
|
||||
ViewModel = App.GetService<InspectorViewModel>();
|
||||
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public override void OnNavigatedTo(object? parameter)
|
||||
{
|
||||
ViewModel.OnNavigatedTo(parameter);
|
||||
}
|
||||
|
||||
public override void OnNavigatedFrom()
|
||||
{
|
||||
ViewModel.OnNavigatedFrom();
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Page
|
||||
x:Class="Ghost.Editor.Views.Pages.EngineEditor.ProjectPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:converter="using:Ghost.Editor.Utilities.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Ghost.Editor.Views.Pages.EngineEditor"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:model="using:Ghost.Editor.Models"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Page.Resources>
|
||||
<converter:AssetPathToGlyphConverter x:Key="AssetPathToGlyphConverter" />
|
||||
</Page.Resources>
|
||||
|
||||
<Grid Background="{ThemeResource LayerFillColorDefaultBrush}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="250" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Folder Tree View -->
|
||||
<Grid
|
||||
Grid.Column="0"
|
||||
Padding="4"
|
||||
Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}"
|
||||
BorderBrush="{ThemeResource CardStrokeColorDefaultSolid}"
|
||||
BorderThickness="0,0,1,0">
|
||||
<TreeView
|
||||
x:Name="DirectoryTreeView"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
ItemsSource="{x:Bind ViewModel.SubDirectories}"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Auto"
|
||||
SelectedItem="{x:Bind ViewModel.SelectedDirectory, Mode=TwoWay}">
|
||||
<TreeView.ItemTemplate>
|
||||
<DataTemplate x:DataType="model:ExplorerItem">
|
||||
<TreeViewItem ItemsSource="{x:Bind Children}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<FontIcon
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Glyph="" />
|
||||
<TextBlock
|
||||
Margin="8,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind Name}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
</DataTemplate>
|
||||
</TreeView.ItemTemplate>
|
||||
</TreeView>
|
||||
</Grid>
|
||||
|
||||
<!-- Files -->
|
||||
<Grid Grid.Column="1">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid
|
||||
Grid.Row="0"
|
||||
Padding="4"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}"
|
||||
BorderBrush="{ThemeResource CardStrokeColorDefaultSolid}"
|
||||
BorderThickness="0,0,0,1">
|
||||
<BreadcrumbBar Height="15" />
|
||||
</Grid>
|
||||
|
||||
<ScrollViewer
|
||||
Grid.Row="1"
|
||||
Padding="8"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Auto"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<GridView
|
||||
x:Name="AssetsGridView"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
ItemsSource="{x:Bind ViewModel.DirectoryAssets, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind ViewModel.SelectedAsset, Mode=TwoWay}">
|
||||
<GridView.ItemContainerStyle>
|
||||
<Style BasedOn="{StaticResource DefaultGridViewItemStyle}" TargetType="GridViewItem">
|
||||
<Setter Property="Margin" Value="2" />
|
||||
</Style>
|
||||
</GridView.ItemContainerStyle>
|
||||
|
||||
<GridView.ItemTemplate>
|
||||
<DataTemplate x:DataType="model:ExplorerItem">
|
||||
<Grid
|
||||
Width="100"
|
||||
Height="100"
|
||||
Padding="8"
|
||||
DoubleTapped="GridViewItem_DoubleTapped"
|
||||
IsDoubleTapEnabled="True">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="0.25*" />
|
||||
</Grid.RowDefinitions>
|
||||
<FontIcon FontSize="42" Glyph="{x:Bind FullName, Converter={StaticResource AssetPathToGlyphConverter}}" />
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Margin="8,0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind Name}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</GridView.ItemTemplate>
|
||||
</GridView>
|
||||
</ScrollViewer>
|
||||
|
||||
<Grid
|
||||
Grid.Row="2"
|
||||
Padding="4"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}"
|
||||
BorderBrush="{ThemeResource CardStrokeColorDefaultSolid}"
|
||||
BorderThickness="0,1,0,0">
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
HorizontalTextAlignment="Left"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind ViewModel.SelectedAsset.FullName, Mode=OneWay}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>
|
||||
@@ -1,25 +0,0 @@
|
||||
using Ghost.Editor.ViewModels.Pages.EngineEditor;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
|
||||
namespace Ghost.Editor.Views.Pages.EngineEditor;
|
||||
|
||||
internal sealed partial class ProjectPage : Page
|
||||
{
|
||||
public ProjectViewModel ViewModel
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public ProjectPage()
|
||||
{
|
||||
ViewModel = App.GetService<ProjectViewModel>();
|
||||
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void GridViewItem_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
|
||||
{
|
||||
ViewModel.OpenSelected();
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<internal:NavigationTabPage
|
||||
x:Class="Ghost.Editor.Views.Pages.EngineEditor.ScenePage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:internal="using:Ghost.Editor.Controls"
|
||||
xmlns:local="using:Ghost.Editor.Views.Pages.EngineEditor"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid>
|
||||
<SwapChainPanel
|
||||
x:Name="SwapChainPanel"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch" />
|
||||
</Grid>
|
||||
</internal:NavigationTabPage>
|
||||
@@ -1,45 +0,0 @@
|
||||
using Ghost.Editor.Controls;
|
||||
//using Ghost.Graphics.Contracts;
|
||||
//using Microsoft.UI.Xaml;
|
||||
//using Microsoft.UI.Xaml.Controls;
|
||||
//using WinRT;
|
||||
|
||||
namespace Ghost.Editor.Views.Pages.EngineEditor;
|
||||
|
||||
internal sealed partial class ScenePage : NavigationTabPage
|
||||
{
|
||||
//private Renderer? _renderView;
|
||||
//private ISwapChainPanelNative _swapChainPanelNative;
|
||||
|
||||
public ScenePage()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
//SwapChainPanel.Loaded += SwapChainPanel_Loaded;
|
||||
//SwapChainPanel.Unloaded += SwapChainPanel_Unloaded;
|
||||
//SwapChainPanel.SizeChanged += SwapChainPanel_SizeChanged;
|
||||
}
|
||||
|
||||
//private void SwapChainPanel_Loaded(object sender, RoutedEventArgs e)
|
||||
//{
|
||||
// var guid = typeof(ISwapChainPanelNative.Interface).GUID;
|
||||
// ((IWinRTObject)SwapChainPanel).NativeObject.TryAs(guid, out var swapChainPanelNativeHandle);
|
||||
// _swapChainPanelNative = new ISwapChainPanelNative(swapChainPanelNativeHandle);
|
||||
|
||||
// _renderView = GraphicsPipeline.GraphicsDevice.CreateRenderer(new(_swapChainPanelNative, (uint)SwapChainPanel.ActualWidth, (uint)SwapChainPanel.ActualHeight));
|
||||
//}
|
||||
|
||||
//private void SwapChainPanel_Unloaded(object sender, RoutedEventArgs e)
|
||||
//{
|
||||
// _swapChainPanelNative.Dispose();
|
||||
// _renderView?.Dispose();
|
||||
//}
|
||||
|
||||
//private void SwapChainPanel_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
//{
|
||||
// if (e.NewSize.ActualWidth > 8.0 && e.NewSize.ActualHeight > 8.0)
|
||||
// {
|
||||
// _renderView?.RequestResize((uint)e.NewSize.ActualWidth, (uint)e.NewSize.ActualHeight);
|
||||
// }
|
||||
//}
|
||||
}
|
||||
@@ -1,246 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<winex:WindowEx
|
||||
x:Class="Ghost.Editor.Views.Windows.EngineEditorWindowOld"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:behaviors="using:CommunityToolkit.WinUI.Behaviors"
|
||||
xmlns:controls="using:Ghost.Editor.Views.Controls"
|
||||
xmlns:ctc="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:ee="using:Ghost.Editor.Views.Pages.EngineEditor"
|
||||
xmlns:ghost="using:Ghost.Editor.Controls"
|
||||
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
|
||||
xmlns:local="using:Ghost.Editor.Views.Windows"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:winex="using:WinUIEx"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Window.SystemBackdrop>
|
||||
<MicaBackdrop />
|
||||
</Window.SystemBackdrop>
|
||||
|
||||
<Grid Loaded="MainGrid_Loaded" Unloaded="MainGrid_Unloaded">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Titlebar -->
|
||||
<TitleBar
|
||||
x:Name="PART_TitleBar"
|
||||
Grid.Row="0"
|
||||
Background="{ThemeResource AcrylicBackgroundFillColorBaseBrush}"
|
||||
Subtitle="Ghost Engine">
|
||||
<TitleBar.IconSource>
|
||||
<ImageIconSource ImageSource="ms-appx:///Assets/icon.targetsize-48.png" />
|
||||
</TitleBar.IconSource>
|
||||
</TitleBar>
|
||||
|
||||
<!-- Toolbar -->
|
||||
<Grid
|
||||
Grid.Row="1"
|
||||
Padding="4,0,4,4"
|
||||
Background="{ThemeResource AcrylicBackgroundFillColorBaseBrush}">
|
||||
<ctc:TabbedCommandBar>
|
||||
<ctc:TabbedCommandBar.MenuItems>
|
||||
<ctc:TabbedCommandBarItem Header="Home">
|
||||
<AppBarButton Label="Undo" />
|
||||
<AppBarButton Label="Redo" />
|
||||
<AppBarButton Label="Paste" />
|
||||
</ctc:TabbedCommandBarItem>
|
||||
<ctc:TabbedCommandBarItem Header="Home">
|
||||
<AppBarButton Label="Undo" />
|
||||
<AppBarButton Label="Redo" />
|
||||
<AppBarButton Label="Paste" />
|
||||
</ctc:TabbedCommandBarItem>
|
||||
<ctc:TabbedCommandBarItem Header="Home">
|
||||
<AppBarButton Label="Undo" />
|
||||
<AppBarButton Label="Redo" />
|
||||
<AppBarButton Label="Paste" />
|
||||
</ctc:TabbedCommandBarItem>
|
||||
</ctc:TabbedCommandBar.MenuItems>
|
||||
</ctc:TabbedCommandBar>
|
||||
</Grid>
|
||||
|
||||
<Grid xmlns:dock="using:Ghost.Editor.Views.Controls.Docking" Grid.Row="2">
|
||||
<dock:DockingLayout x:Name="MainDockingLayout" />
|
||||
</Grid>
|
||||
|
||||
<!-- Editor -->
|
||||
<!--<Grid Grid.Row="2">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid Grid.Row="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<ghost:NavigationTabView
|
||||
Grid.Column="0"
|
||||
Width="350"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
<ghost:NavigationTabView.TabItems>
|
||||
<TabViewItem Header="Hierarchy">
|
||||
<TabViewItem.IconSource>
|
||||
<FontIconSource Glyph="" />
|
||||
</TabViewItem.IconSource>
|
||||
<controls:Hierarchy />
|
||||
</TabViewItem>
|
||||
</ghost:NavigationTabView.TabItems>
|
||||
</ghost:NavigationTabView>
|
||||
|
||||
<ghost:NavigationTabView Grid.Column="1">
|
||||
<ghost:NavigationTabView.TabItems>
|
||||
<ee:ScenePage Header="Scene">
|
||||
<ee:ScenePage.IconSource>
|
||||
<FontIconSource Glyph="" />
|
||||
</ee:ScenePage.IconSource>
|
||||
</ee:ScenePage>
|
||||
</ghost:NavigationTabView.TabItems>
|
||||
</ghost:NavigationTabView>
|
||||
|
||||
<ghost:NavigationTabView
|
||||
Grid.Column="2"
|
||||
Width="350"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
<ghost:NavigationTabView.TabItems>
|
||||
<ee:InspectorPage Header="Inspector">
|
||||
<ee:InspectorPage.IconSource>
|
||||
<FontIconSource Glyph="" />
|
||||
</ee:InspectorPage.IconSource>
|
||||
</ee:InspectorPage>
|
||||
</ghost:NavigationTabView.TabItems>
|
||||
</ghost:NavigationTabView>
|
||||
</Grid>
|
||||
|
||||
<ghost:NavigationTabView Grid.Row="1" Height="350">
|
||||
<ghost:NavigationTabView.TabItems>
|
||||
<TabViewItem Header="Project">
|
||||
<TabViewItem.IconSource>
|
||||
<FontIconSource Glyph="" />
|
||||
</TabViewItem.IconSource>
|
||||
<controls:ProjectBrowser />
|
||||
</TabViewItem>
|
||||
<TabViewItem Header="Console">
|
||||
<TabViewItem.IconSource>
|
||||
<FontIconSource Glyph="" />
|
||||
</TabViewItem.IconSource>
|
||||
<ee:ConsolePage />
|
||||
</TabViewItem>
|
||||
</ghost:NavigationTabView.TabItems>
|
||||
</ghost:NavigationTabView>
|
||||
</Grid>-->
|
||||
|
||||
<!-- Status Bar -->
|
||||
<Grid
|
||||
Grid.Row="3"
|
||||
Height="25"
|
||||
Background="{ThemeResource SmokeFillColorDefaultBrush}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid Grid.Column="0">
|
||||
<FontIcon
|
||||
Margin="8,0,0,0"
|
||||
FontSize="16"
|
||||
Foreground="{ThemeResource SystemFillColorSuccessBrush}"
|
||||
Glyph=""
|
||||
Visibility="Visible" />
|
||||
|
||||
<StackPanel Orientation="Horizontal" Visibility="Collapsed">
|
||||
<FontIcon
|
||||
Margin="8,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="16"
|
||||
Foreground="{ThemeResource SystemFillColorAttentionBrush}"
|
||||
Glyph="" />
|
||||
<TextBlock
|
||||
Margin="4,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="0" />
|
||||
<FontIcon
|
||||
Margin="8,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="16"
|
||||
Foreground="{ThemeResource SystemFillColorCautionBrush}"
|
||||
Glyph="" />
|
||||
<TextBlock
|
||||
Margin="4,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="0" />
|
||||
<FontIcon
|
||||
Margin="8,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="16"
|
||||
Foreground="{ThemeResource SystemFillColorCriticalBrush}"
|
||||
Glyph="" />
|
||||
<TextBlock
|
||||
Margin="4,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="0" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<!-- Info and Progress -->
|
||||
<Grid Grid.Row="0" Grid.RowSpan="4">
|
||||
<InfoBar
|
||||
x:Name="InfoBar"
|
||||
Margin="16"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Bottom">
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<behaviors:StackedNotificationsBehavior x:Name="NotificationQueue" />
|
||||
</interactivity:Interaction.Behaviors>
|
||||
</InfoBar>
|
||||
|
||||
<Grid
|
||||
x:Name="ProgressBarContainer"
|
||||
Background="{ThemeResource SmokeFillColorDefaultBrush}"
|
||||
Visibility="Collapsed">
|
||||
<Grid
|
||||
Height="100"
|
||||
Padding="36,24"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Background="{ThemeResource SolidBackgroundFillColorBaseBrush}"
|
||||
CornerRadius="{StaticResource OverlayCornerRadius}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock
|
||||
x:Name="ProgressMessage"
|
||||
Grid.Row="0"
|
||||
Margin="0,0,0,12"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource TitleTextBlockStyle}"
|
||||
Text="Loading..." />
|
||||
<ProgressBar
|
||||
x:Name="ProgressBar"
|
||||
Grid.Row="1"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
IsIndeterminate="True" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</winex:WindowEx>
|
||||
@@ -1,88 +0,0 @@
|
||||
using Ghost.Editor.Core;
|
||||
using Ghost.Editor.Core.Contracts;
|
||||
using Ghost.Editor.Core.Services;
|
||||
using Ghost.Editor.ViewModels.Windows;
|
||||
using Windows.ApplicationModel;
|
||||
using WinUIEx;
|
||||
|
||||
namespace Ghost.Editor.Views.Windows;
|
||||
/// <summary>
|
||||
/// An empty window that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
internal sealed partial class EngineEditorWindowOld : WindowEx
|
||||
{
|
||||
private readonly NotificationService _notificationService;
|
||||
private readonly ProgressService _progressService;
|
||||
|
||||
public EngineEditorViewModel ViewModel
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public EngineEditorWindowOld()
|
||||
{
|
||||
ViewModel = App.GetService<EngineEditorViewModel>();
|
||||
|
||||
_notificationService = (NotificationService)App.GetService<INotificationService>();
|
||||
_progressService = (ProgressService)App.GetService<IProgressService>();
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
AppWindow.SetIcon(Path.Combine(AppContext.BaseDirectory, "Assets/icon.ico"));
|
||||
Title = "Ghost Engine";
|
||||
ExtendsContentIntoTitleBar = true;
|
||||
|
||||
SetTitleBar(PART_TitleBar);
|
||||
this.CenterOnScreen();
|
||||
}
|
||||
|
||||
private void MainGrid_Loaded(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
||||
{
|
||||
PART_TitleBar.Title = EditorApplication.ProjectName;
|
||||
PART_TitleBar.Subtitle = $"Ghost Engine {Package.Current.Id.Version.Major}.{Package.Current.Id.Version.Minor}.{Package.Current.Id.Version.Build}";
|
||||
|
||||
_notificationService.SetReference(InfoBar, NotificationQueue);
|
||||
_progressService.SetReference(ProgressBarContainer);
|
||||
|
||||
InitializeDockingLayout();
|
||||
}
|
||||
|
||||
private void InitializeDockingLayout()
|
||||
{
|
||||
var sceneDoc = new Controls.Docking.DockDocument { Title = "Scene", Content = new Pages.EngineEditor.ScenePage() };
|
||||
var hierarchyDoc = new Controls.Docking.DockDocument { Title = "Hierarchy", Content = new Controls.Hierarchy() };
|
||||
var inspectorDoc = new Controls.Docking.DockDocument { Title = "Inspector", Content = new Pages.EngineEditor.InspectorPage() };
|
||||
var projectDoc = new Controls.Docking.DockDocument { Title = "Project", Content = new Controls.ProjectBrowser() };
|
||||
var consoleDoc = new Controls.Docking.DockDocument { Title = "Console", Content = new Pages.EngineEditor.ConsolePage() };
|
||||
|
||||
var leftGroup = new Controls.Docking.DockGroup();
|
||||
leftGroup.AddChild(hierarchyDoc);
|
||||
|
||||
var centerGroup = new Controls.Docking.DockGroup();
|
||||
centerGroup.AddChild(sceneDoc);
|
||||
|
||||
var rightGroup = new Controls.Docking.DockGroup();
|
||||
rightGroup.AddChild(inspectorDoc);
|
||||
|
||||
var bottomGroup = new Controls.Docking.DockGroup();
|
||||
bottomGroup.AddChild(projectDoc);
|
||||
bottomGroup.AddChild(consoleDoc);
|
||||
|
||||
var topPanel = new Controls.Docking.DockPanel { Orientation = Microsoft.UI.Xaml.Controls.Orientation.Horizontal };
|
||||
topPanel.AddChild(leftGroup);
|
||||
topPanel.AddChild(centerGroup);
|
||||
topPanel.AddChild(rightGroup);
|
||||
|
||||
var rootPanel = new Controls.Docking.DockPanel { Orientation = Microsoft.UI.Xaml.Controls.Orientation.Vertical };
|
||||
rootPanel.AddChild(topPanel);
|
||||
rootPanel.AddChild(bottomGroup);
|
||||
|
||||
MainDockingLayout.RootModule = rootPanel;
|
||||
}
|
||||
|
||||
private void MainGrid_Unloaded(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
||||
{
|
||||
_notificationService.ClearReference();
|
||||
_progressService.ClearReference();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user