Updating ProjectBrowser

This commit is contained in:
2026-02-04 19:08:18 +09:00
parent 59991f47d5
commit eadd13931f
30 changed files with 382 additions and 139 deletions

View File

@@ -1,15 +0,0 @@
namespace Ghost.Editor.Core.AssetHandle;
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
internal class AssetImporterAttribute : Attribute
{
public string[] SupportedExtensions
{
get;
}
public AssetImporterAttribute(params string[] supportedExtensions)
{
SupportedExtensions = supportedExtensions;
}
}

View File

@@ -1,15 +0,0 @@
namespace Ghost.Editor.Core.AssetHandle;
[AttributeUsage(AttributeTargets.Method)]
public class AssetOpenHandlerAttribute : Attribute
{
public string[] Extensions
{
get;
}
public AssetOpenHandlerAttribute(params string[] extensions)
{
Extensions = extensions.Select(e => e.StartsWith('.') ? e.ToLowerInvariant() : '.' + e.ToLowerInvariant()).ToArray();
}
}

View File

@@ -0,0 +1,102 @@
namespace Ghost.Editor.Core;
/// <summary>
/// The base class for all attributes that can be discovered via <see cref="Utilities.TypeCache"/>.
/// </summary>
public abstract class DiscoverableAttributeBase : Attribute;
[AttributeUsage(AttributeTargets.Method)]
public class AssetOpenHandlerAttribute : DiscoverableAttributeBase
{
public string[] Extensions
{
get;
}
public AssetOpenHandlerAttribute(params string[] extensions)
{
Extensions = extensions.Select(e => e.StartsWith('.') ? e.ToLowerInvariant() : '.' + e.ToLowerInvariant()).ToArray();
}
}
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
internal class AssetImporterAttribute : DiscoverableAttributeBase
{
public string[] SupportedExtensions
{
get;
}
public AssetImporterAttribute(params string[] supportedExtensions)
{
SupportedExtensions = supportedExtensions;
}
}
[AttributeUsage(AttributeTargets.Class)]
public class CustomEditorAttribute : DiscoverableAttributeBase
{
internal Type TargetType
{
get;
}
public CustomEditorAttribute(Type targetType)
{
TargetType = targetType;
}
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false, Inherited = false)]
public class EditorInjectionAttribute : DiscoverableAttributeBase
{
public enum ServiceLifetime
{
Singleton,
Transient,
Scoped
}
public ServiceLifetime Lifetime
{
get;
}
public Type? ImplementationType
{
get;
}
public EditorInjectionAttribute(ServiceLifetime lifetime, Type? implementationType = null)
{
Lifetime = lifetime;
ImplementationType = implementationType;
}
}
[AttributeUsage(AttributeTargets.Method)]
public sealed class ContextMenuItemAttribute : DiscoverableAttributeBase
{
public string Tag
{
get;
}
public string Name
{
get;
}
public int Group
{
get;
}
public ContextMenuItemAttribute(string tag, string name, int group = 0)
{
Tag = tag;
Name = name;
Group = group;
}
}

View File

@@ -4,7 +4,6 @@
<ResourceDictionary Source="ms-appx:///Ghost.Editor.Core/Controls/BasicInput/PropertyField.xaml" /> <ResourceDictionary Source="ms-appx:///Ghost.Editor.Core/Controls/BasicInput/PropertyField.xaml" />
<ResourceDictionary Source="ms-appx:///Ghost.Editor.Core/Controls/BasicInput/Float3Field.xaml" /> <ResourceDictionary Source="ms-appx:///Ghost.Editor.Core/Controls/BasicInput/Float3Field.xaml" />
<ResourceDictionary Source="ms-appx:///Ghost.Editor.Core/Controls/Internal/ComponentDataView.xaml" /> <ResourceDictionary Source="ms-appx:///Ghost.Editor.Core/Controls/Internal/ComponentView.xaml" />
<ResourceDictionary Source="ms-appx:///Ghost.Editor.Core/Controls/Internal/NavigationTabView.xaml" />
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
</ResourceDictionary> </ResourceDictionary>

View File

@@ -7,7 +7,7 @@ using Microsoft.UI.Xaml.Controls;
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Ghost.Editor.Core.Controls.Internal; namespace Ghost.Editor.Core.Controls;
internal sealed unsafe partial class ComponentView : Control internal sealed unsafe partial class ComponentView : Control
{ {

View File

@@ -2,7 +2,7 @@
<ResourceDictionary <ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Ghost.Editor.Core.Controls.Internal"> xmlns:local="using:Ghost.Editor.Core.Controls">
<Style TargetType="local:ComponentView"> <Style TargetType="local:ComponentView">
<Setter Property="Template"> <Setter Property="Template">

View File

@@ -2,7 +2,7 @@ using Ghost.Editor.Core.Contracts;
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls;
namespace Ghost.Editor.Controls.Internal; namespace Ghost.Editor.Controls;
public partial class NavigationTabPage : TabViewItem, INavigationAware public partial class NavigationTabPage : TabViewItem, INavigationAware
{ {

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Ghost.Editor.Controls.Internal" />

View File

@@ -0,0 +1,95 @@
using Ghost.Editor.Core.Utilities;
using Microsoft.UI.Xaml.Controls;
using System.Reflection;
using System.Runtime.InteropServices;
namespace Ghost.Editor.Core.Controls;
public sealed partial class ContextFlyout : MenuFlyout
{
private bool _isPopulated;
public string Tag
{
get; set;
} = string.Empty;
public ContextFlyout()
{
Opening += ContextFlyout_Opening;
}
private void PopulateContextMenu()
{
var methods = TypeCache.GetMethodsWithAttribute<ContextMenuItemAttribute>();
if (methods == null)
{
return;
}
var list = new List<(ContextMenuItemAttribute attr, MethodInfo method)>();
foreach (var method in methods)
{
var attributes = method.GetCustomAttributes(typeof(ContextMenuItemAttribute), false);
var attribute = (ContextMenuItemAttribute)attributes[0];
if (!string.Equals(attribute.Tag, Tag, StringComparison.OrdinalIgnoreCase))
{
continue;
}
list.Add((attribute, method));
}
var span = CollectionsMarshal.AsSpan(list);
span.Sort((a, b) =>
{
var result = a.attr.Group.CompareTo(b.attr.Group);
if (result == 0)
{
result = string.CompareOrdinal(a.attr.Name, b.attr.Name);
}
return result;
});
// itemContainer may be a main thread only collection (for example, ObservableCollection), we run it on the UI thread
var i = 0;
var group = 0;
while (i < list.Count)
{
var (attr, method) = list[i];
if (attr.Group != group)
{
Items.Add(new MenuFlyoutSeparator());
group = attr.Group;
}
// TODO: Group items with / in the name into submenus
var menuItem = new MenuFlyoutItem
{
Text = attr.Name
};
menuItem.Click += (_, _) =>
{
method.Invoke(null, null);
};
Items.Add(menuItem);
i++;
}
}
private async void ContextFlyout_Opening(object? sender, object e)
{
if (_isPopulated)
{
return;
}
PopulateContextMenu();
_isPopulated = true;
}
}

View File

@@ -1,3 +1,4 @@
using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml;
namespace Ghost.Editor.Core; namespace Ghost.Editor.Core;
@@ -11,10 +12,25 @@ public static class EditorApplication
private static string s_currentProjectPath = string.Empty; private static string s_currentProjectPath = string.Empty;
private static string s_currentProjectName = string.Empty; private static string s_currentProjectName = string.Empty;
private static DispatcherQueue? s_dispatcherQueue;
internal static Application CurrentApplication => Application.Current; internal static Application CurrentApplication => Application.Current;
internal static string CurrentProjectPath => s_currentProjectPath; internal static string CurrentProjectPath => s_currentProjectPath;
internal static string CurrentProjectName => s_currentProjectName; internal static string CurrentProjectName => s_currentProjectName;
public static DispatcherQueue DispatcherQueue
{
get
{
if (s_dispatcherQueue is null)
{
throw new InvalidOperationException("DispatcherQueue is not initialized.");
}
return s_dispatcherQueue;
}
}
internal static void Initialize(IServiceProvider serviceProvider, string projectPath, string projectName) internal static void Initialize(IServiceProvider serviceProvider, string projectPath, string projectName)
{ {
s_serviceProvider = serviceProvider; s_serviceProvider = serviceProvider;
@@ -22,6 +38,11 @@ public static class EditorApplication
s_currentProjectName = projectName; s_currentProjectName = projectName;
} }
internal static void SetDispatcherQueue(DispatcherQueue dispatcherQueue)
{
s_dispatcherQueue = dispatcherQueue;
}
public static T GetService<T>() public static T GetService<T>()
where T : class where T : class
{ {

View File

@@ -1,28 +0,0 @@
namespace Ghost.Editor.Core;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false, Inherited = false)]
public class EditorInjectionAttribute : Attribute
{
public enum ServiceLifetime
{
Singleton,
Transient,
Scoped
}
public ServiceLifetime Lifetime
{
get;
}
public Type? ImplementationType
{
get;
}
public EditorInjectionAttribute(ServiceLifetime lifetime, Type? implementationType = null)
{
Lifetime = lifetime;
ImplementationType = implementationType;
}
}

View File

@@ -32,13 +32,7 @@
<Page Update="Controls\BasicInput\Vector3Field.xaml"> <Page Update="Controls\BasicInput\Vector3Field.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
</Page> </Page>
<Page Update="Controls\ControlsDictionary.xaml"> <Page Update="Controls\Internal\ComponentView.xaml">
<SubType>Designer</SubType>
</Page>
<Page Update="Controls\Internal\ComponentDataView.xaml">
<SubType>Designer</SubType>
</Page>
<Page Update="Controls\Internal\NavigationTabView.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
</Page> </Page>
</ItemGroup> </ItemGroup>

View File

@@ -1,10 +0,0 @@
namespace Ghost.Editor.Core.Inspector;
[AttributeUsage(AttributeTargets.Class)]
public class CustomEditorAttribute(Type targetType) : Attribute
{
internal Type TargetType
{
get;
} = targetType;
}

View File

@@ -1,13 +1,21 @@
using Ghost.Core.Attributes; using Ghost.Core.Attributes;
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices;
namespace Ghost.Editor.Core.Utilities; namespace Ghost.Editor.Core.Utilities;
public static class TypeCache public static class TypeCache
{ {
private static readonly TypeInfo[] s_types; private static TypeInfo[] s_types;
private static Dictionary<nint, List<MethodInfo>> s_attributeMethodCache;
static TypeCache() static TypeCache()
{
s_types = LoadTypes();
s_attributeMethodCache = FindMethodWithAttribute();
}
private static TypeInfo[] LoadTypes()
{ {
var loadableTypes = new List<Type>(512); var loadableTypes = new List<Type>(512);
var assembliesToScan = AppDomain.CurrentDomain.GetAssemblies() var assembliesToScan = AppDomain.CurrentDomain.GetAssemblies()
@@ -26,7 +34,32 @@ public static class TypeCache
} }
} }
s_types = loadableTypes.Select(t => t.GetTypeInfo()).ToArray(); return loadableTypes.Select(t => t.GetTypeInfo()).ToArray();
}
private static Dictionary<nint, List<MethodInfo>> FindMethodWithAttribute()
{
var dict = new Dictionary<nint, List<MethodInfo>>();
foreach (var type in s_types)
{
foreach (var method in type.DeclaredMethods)
{
var attrs = method.GetCustomAttributes<DiscoverableAttributeBase>(false);
foreach (var attr in attrs)
{
var key = attr.GetType().TypeHandle.Value;
ref var methodList = ref CollectionsMarshal.GetValueRefOrAddDefault(dict, key, out var exist);
if (!exist)
{
methodList = new List<MethodInfo>();
}
methodList!.Add(method);
}
}
}
return dict;
} }
internal static void Init() internal static void Init()
@@ -35,8 +68,26 @@ public static class TypeCache
// This method exists to force the static constructor to run. // This method exists to force the static constructor to run.
} }
public static Type[] GetTypes() internal static void Reload()
{
s_types = LoadTypes();
s_attributeMethodCache = FindMethodWithAttribute();
}
public static IReadOnlyCollection<TypeInfo> GetTypes()
{ {
return s_types; return s_types;
} }
public static IReadOnlyCollection<MethodInfo>? GetMethodsWithAttribute<T>()
where T : DiscoverableAttributeBase
{
var key = typeof(T).TypeHandle.Value;
if (s_attributeMethodCache.TryGetValue(key, out var methods))
{
return methods;
}
return null;
}
} }

View File

@@ -10,6 +10,7 @@ using Ghost.Editor.ViewModels.Windows;
using Ghost.Engine; using Ghost.Engine;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml;
using System.Diagnostics; using System.Diagnostics;
using WinUIEx; using WinUIEx;
@@ -116,6 +117,9 @@ public partial class App : Application
EditorApplication.Initialize(Host.Services, arguments.ProjectPath, arguments.ProjectName); EditorApplication.Initialize(Host.Services, arguments.ProjectPath, arguments.ProjectName);
// NOTE: We must call DispatcherQueue.GetForCurrentThread() on the UI thread before any await.
EditorApplication.SetDispatcherQueue(DispatcherQueue.GetForCurrentThread());
var splashWindow = new SplashWindow(); var splashWindow = new SplashWindow();
splashWindow.Activate(); splashWindow.Activate();
Window = splashWindow; Window = splashWindow;

View File

@@ -1,3 +1,4 @@
using Ghost.Editor.Core;
using Ghost.Editor.Core.Controls; using Ghost.Editor.Core.Controls;
using Ghost.Editor.Core.Inspector; using Ghost.Editor.Core.Inspector;
using Ghost.Engine.Components; using Ghost.Engine.Components;

View File

@@ -183,6 +183,9 @@
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="ContextMenu\" />
</ItemGroup>
<PropertyGroup Label="Globals" /> <PropertyGroup Label="Globals" />
<!-- <!--

View File

@@ -2,7 +2,7 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:Microsoft.UI.Xaml.Controls" xmlns:controls="using:Microsoft.UI.Xaml.Controls"
xmlns:internal="using:Ghost.Editor.Controls.Internal" xmlns:ghost="using:Ghost.Editor.Controls"
xmlns:local="using:Ghost.Editor.Core"> xmlns:local="using:Ghost.Editor.Core">
<ResourceDictionary.ThemeDictionaries> <ResourceDictionary.ThemeDictionaries>
@@ -38,7 +38,7 @@
<x:Double x:Key="NavigationViewItemOnLeftMinHeight">32</x:Double> <x:Double x:Key="NavigationViewItemOnLeftMinHeight">32</x:Double>
<!-- Control override --> <!-- Control override -->
<Style TargetType="internal:NavigationTabView"> <Style TargetType="ghost:NavigationTabView">
<Setter Property="TabWidthMode" Value="Compact" /> <Setter Property="TabWidthMode" Value="Compact" />
</Style> </Style>
<Style TargetType="NumberBox" /> <Style TargetType="NumberBox" />

View File

@@ -0,0 +1,23 @@
using Ghost.Editor.Core;
namespace Ghost.Editor.View.Controls;
internal partial class ProjectBrowser
{
[ContextMenuItem("project-browser", "Show in Explorer")]
private static void ShowInExplorer()
{
var path = LastFocused?.ViewModel.CurrentDirectoryPath;
if (!Directory.Exists(path))
{
return;
}
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo()
{
FileName = path,
UseShellExecute = true,
Verb = "open"
});
}
}

View File

@@ -1,12 +1,13 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<UserControl <UserControl
x:Class="Ghost.Editor.Controls.ProjectBrowser" x:Class="Ghost.Editor.View.Controls.ProjectBrowser"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:community="using:CommunityToolkit.WinUI.Controls"
xmlns:converter="using:Ghost.Editor.Utilities.Converters" xmlns:converter="using:Ghost.Editor.Utilities.Converters"
xmlns:ctc="using:CommunityToolkit.WinUI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:Ghost.Editor.Controls" xmlns:ghost="using:Ghost.Editor.Core.Controls"
xmlns:local="using:Ghost.Editor.View.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:model="using:Ghost.Editor.Models" xmlns:model="using:Ghost.Editor.Models"
xmlns:sys="using:System" xmlns:sys="using:System"
@@ -164,13 +165,13 @@
</MenuFlyout> </MenuFlyout>
</Grid.ContextFlyout> </Grid.ContextFlyout>
<ctc:ConstrainedBox Grid.Row="0" AspectRatio="1:1"> <community:ConstrainedBox Grid.Row="0" AspectRatio="1:1">
<Image HorizontalAlignment="Center"> <Image HorizontalAlignment="Center">
<Image.Source> <Image.Source>
<BitmapImage DecodePixelWidth="48" UriSource="{x:Bind Converter={StaticResource ExplorerItemToIconUriConverter}}" /> <BitmapImage DecodePixelWidth="48" UriSource="{x:Bind Converter={StaticResource ExplorerItemToIconUriConverter}}" />
</Image.Source> </Image.Source>
</Image> </Image>
</ctc:ConstrainedBox> </community:ConstrainedBox>
<TextBlock <TextBlock
Grid.Row="1" Grid.Row="1"
HorizontalAlignment="Center" HorizontalAlignment="Center"
@@ -190,7 +191,7 @@
MinRowSpacing="4" /> MinRowSpacing="4" />
</ItemsView.Layout> </ItemsView.Layout>
<ItemsView.ContextFlyout> <ItemsView.ContextFlyout>
<MenuFlyout> <ghost:ContextFlyout Tag="project-browser">
<MenuFlyoutSubItem Text="Create"> <MenuFlyoutSubItem Text="Create">
<MenuFlyoutItem Text="Folder" /> <MenuFlyoutItem Text="Folder" />
<MenuFlyoutItem Text="Script" /> <MenuFlyoutItem Text="Script" />
@@ -199,11 +200,8 @@
<MenuFlyoutItem Text="Volume Profile" /> <MenuFlyoutItem Text="Volume Profile" />
</MenuFlyoutSubItem> </MenuFlyoutSubItem>
</MenuFlyoutSubItem> </MenuFlyoutSubItem>
<MenuFlyoutItem Text="Show in Explorer" />
<MenuFlyoutSeparator /> <MenuFlyoutSeparator />
<MenuFlyoutItem Text="Refresh" /> </ghost:ContextFlyout>
<MenuFlyoutItem Text="Reimport All" />
</MenuFlyout>
</ItemsView.ContextFlyout> </ItemsView.ContextFlyout>
</ItemsView> </ItemsView>

View File

@@ -3,11 +3,18 @@ using Ghost.Editor.Models;
using Ghost.Editor.ViewModels.Controls; using Ghost.Editor.ViewModels.Controls;
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Input;
namespace Ghost.Editor.Controls; namespace Ghost.Editor.View.Controls;
internal sealed partial class ProjectBrowser : UserControl internal sealed partial class ProjectBrowser : UserControl
{ {
public static ProjectBrowser? LastFocused
{
get;
private set;
}
private readonly IInspectorService _inspectorService; private readonly IInspectorService _inspectorService;
private bool _isUpdatingSelection = false; private bool _isUpdatingSelection = false;
@@ -25,6 +32,18 @@ internal sealed partial class ProjectBrowser : UserControl
Loaded += ProjectBrowser_Loaded; Loaded += ProjectBrowser_Loaded;
Unloaded += ProjectBrowser_Unloaded; Unloaded += ProjectBrowser_Unloaded;
GettingFocus += ProjectBrowser_GettingFocus;
}
private void ProjectBrowser_GettingFocus(UIElement sender, GettingFocusEventArgs args)
{
if (_isUpdatingSelection)
{
return;
}
LastFocused = this;
} }
private void ProjectBrowser_Loaded(object sender, RoutedEventArgs e) private void ProjectBrowser_Loaded(object sender, RoutedEventArgs e)

View File

@@ -4,7 +4,7 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:internal="using:Ghost.Editor.Controls.Internal" xmlns:internal="using:Ghost.Editor.Controls"
xmlns:local="using:Ghost.Editor.View.Pages.EngineEditor" xmlns:local="using:Ghost.Editor.View.Pages.EngineEditor"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sg="using:Ghost.Editor.Core.SceneGraph" xmlns:sg="using:Ghost.Editor.Core.SceneGraph"

View File

@@ -1,4 +1,4 @@
using Ghost.Editor.Controls.Internal; using Ghost.Editor.Controls;
using Ghost.Editor.Core.Contracts; using Ghost.Editor.Core.Contracts;
using Ghost.Editor.Core.SceneGraph; using Ghost.Editor.Core.SceneGraph;
using Ghost.Editor.ViewModels.Pages.EngineEditor; using Ghost.Editor.ViewModels.Pages.EngineEditor;

View File

@@ -4,7 +4,7 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:internal="using:Ghost.Editor.Controls.Internal" xmlns:internal="using:Ghost.Editor.Controls"
xmlns:local="using:Ghost.Editor.View.Pages.EngineEditor" xmlns:local="using:Ghost.Editor.View.Pages.EngineEditor"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"> mc:Ignorable="d">

View File

@@ -1,4 +1,4 @@
using Ghost.Editor.Controls.Internal; using Ghost.Editor.Controls;
using Ghost.Editor.ViewModels.Pages.EngineEditor; using Ghost.Editor.ViewModels.Pages.EngineEditor;
namespace Ghost.Editor.View.Pages.EngineEditor; namespace Ghost.Editor.View.Pages.EngineEditor;

View File

@@ -4,7 +4,7 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:internal="using:Ghost.Editor.Controls.Internal" xmlns:internal="using:Ghost.Editor.Controls"
xmlns:local="using:Ghost.Editor.View.Pages.EngineEditor" xmlns:local="using:Ghost.Editor.View.Pages.EngineEditor"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"> mc:Ignorable="d">

View File

@@ -1,4 +1,4 @@
using Ghost.Editor.Controls.Internal; using Ghost.Editor.Controls;
//using Ghost.Graphics.Contracts; //using Ghost.Graphics.Contracts;
//using Microsoft.UI.Xaml; //using Microsoft.UI.Xaml;
//using Microsoft.UI.Xaml.Controls; //using Microsoft.UI.Xaml.Controls;

View File

@@ -4,12 +4,12 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:behaviors="using:CommunityToolkit.WinUI.Behaviors" xmlns:behaviors="using:CommunityToolkit.WinUI.Behaviors"
xmlns:controls="using:CommunityToolkit.WinUI.Controls" xmlns:controls="using:Ghost.Editor.View.Controls"
xmlns:controls1="using:Ghost.Editor.Controls" xmlns:ctc="using:CommunityToolkit.WinUI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ee="using:Ghost.Editor.View.Pages.EngineEditor" xmlns:ee="using:Ghost.Editor.View.Pages.EngineEditor"
xmlns:ghost="using:Ghost.Editor.Controls"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity" xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:internal="using:Ghost.Editor.Controls.Internal"
xmlns:local="using:Ghost.Editor.View.Windows" xmlns:local="using:Ghost.Editor.View.Windows"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:winex="using:WinUIEx" xmlns:winex="using:WinUIEx"
@@ -43,25 +43,25 @@
Grid.Row="1" Grid.Row="1"
Padding="4,0,4,4" Padding="4,0,4,4"
Background="{ThemeResource AcrylicBackgroundFillColorBaseBrush}"> Background="{ThemeResource AcrylicBackgroundFillColorBaseBrush}">
<controls:TabbedCommandBar> <ctc:TabbedCommandBar>
<controls:TabbedCommandBar.MenuItems> <ctc:TabbedCommandBar.MenuItems>
<controls:TabbedCommandBarItem Header="Home"> <ctc:TabbedCommandBarItem Header="Home">
<AppBarButton Label="Undo" /> <AppBarButton Label="Undo" />
<AppBarButton Label="Redo" /> <AppBarButton Label="Redo" />
<AppBarButton Label="Paste" /> <AppBarButton Label="Paste" />
</controls:TabbedCommandBarItem> </ctc:TabbedCommandBarItem>
<controls:TabbedCommandBarItem Header="Home"> <ctc:TabbedCommandBarItem Header="Home">
<AppBarButton Label="Undo" /> <AppBarButton Label="Undo" />
<AppBarButton Label="Redo" /> <AppBarButton Label="Redo" />
<AppBarButton Label="Paste" /> <AppBarButton Label="Paste" />
</controls:TabbedCommandBarItem> </ctc:TabbedCommandBarItem>
<controls:TabbedCommandBarItem Header="Home"> <ctc:TabbedCommandBarItem Header="Home">
<AppBarButton Label="Undo" /> <AppBarButton Label="Undo" />
<AppBarButton Label="Redo" /> <AppBarButton Label="Redo" />
<AppBarButton Label="Paste" /> <AppBarButton Label="Paste" />
</controls:TabbedCommandBarItem> </ctc:TabbedCommandBarItem>
</controls:TabbedCommandBar.MenuItems> </ctc:TabbedCommandBar.MenuItems>
</controls:TabbedCommandBar> </ctc:TabbedCommandBar>
</Grid> </Grid>
<!-- Editor --> <!-- Editor -->
@@ -78,52 +78,52 @@
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<internal:NavigationTabView <ghost:NavigationTabView
Grid.Column="0" Grid.Column="0"
Width="350" Width="350"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"> VerticalAlignment="Stretch">
<internal:NavigationTabView.TabItems> <ghost:NavigationTabView.TabItems>
<ee:HierarchyPage Header="Hierarchy"> <ee:HierarchyPage Header="Hierarchy">
<ee:HierarchyPage.IconSource> <ee:HierarchyPage.IconSource>
<FontIconSource Glyph="&#xE8A4;" /> <FontIconSource Glyph="&#xE8A4;" />
</ee:HierarchyPage.IconSource> </ee:HierarchyPage.IconSource>
</ee:HierarchyPage> </ee:HierarchyPage>
</internal:NavigationTabView.TabItems> </ghost:NavigationTabView.TabItems>
</internal:NavigationTabView> </ghost:NavigationTabView>
<internal:NavigationTabView Grid.Column="1"> <ghost:NavigationTabView Grid.Column="1">
<internal:NavigationTabView.TabItems> <ghost:NavigationTabView.TabItems>
<ee:ScenePage Header="Scene"> <ee:ScenePage Header="Scene">
<ee:ScenePage.IconSource> <ee:ScenePage.IconSource>
<FontIconSource Glyph="&#xF159;" /> <FontIconSource Glyph="&#xF159;" />
</ee:ScenePage.IconSource> </ee:ScenePage.IconSource>
</ee:ScenePage> </ee:ScenePage>
</internal:NavigationTabView.TabItems> </ghost:NavigationTabView.TabItems>
</internal:NavigationTabView> </ghost:NavigationTabView>
<internal:NavigationTabView <ghost:NavigationTabView
Grid.Column="2" Grid.Column="2"
Width="350" Width="350"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"> VerticalAlignment="Stretch">
<internal:NavigationTabView.TabItems> <ghost:NavigationTabView.TabItems>
<ee:InspectorPage Header="Inspector"> <ee:InspectorPage Header="Inspector">
<ee:InspectorPage.IconSource> <ee:InspectorPage.IconSource>
<FontIconSource Glyph="&#xEC7A;" /> <FontIconSource Glyph="&#xEC7A;" />
</ee:InspectorPage.IconSource> </ee:InspectorPage.IconSource>
</ee:InspectorPage> </ee:InspectorPage>
</internal:NavigationTabView.TabItems> </ghost:NavigationTabView.TabItems>
</internal:NavigationTabView> </ghost:NavigationTabView>
</Grid> </Grid>
<internal:NavigationTabView Grid.Row="1" Height="350"> <ghost:NavigationTabView Grid.Row="1" Height="350">
<internal:NavigationTabView.TabItems> <ghost:NavigationTabView.TabItems>
<TabViewItem Header="Project"> <TabViewItem Header="Project">
<TabViewItem.IconSource> <TabViewItem.IconSource>
<FontIconSource Glyph="&#xEC50;" /> <FontIconSource Glyph="&#xEC50;" />
</TabViewItem.IconSource> </TabViewItem.IconSource>
<controls1:ProjectBrowser /> <controls:ProjectBrowser />
</TabViewItem> </TabViewItem>
<TabViewItem Header="Console"> <TabViewItem Header="Console">
<TabViewItem.IconSource> <TabViewItem.IconSource>
@@ -131,8 +131,8 @@
</TabViewItem.IconSource> </TabViewItem.IconSource>
<ee:ConsolePage /> <ee:ConsolePage />
</TabViewItem> </TabViewItem>
</internal:NavigationTabView.TabItems> </ghost:NavigationTabView.TabItems>
</internal:NavigationTabView> </ghost:NavigationTabView>
</Grid> </Grid>
<!-- Status Bar --> <!-- Status Bar -->

View File

@@ -1,7 +1,6 @@
using Ghost.Editor.Core; using Ghost.Editor.Core;
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml;
using Windows.ApplicationModel; using Windows.ApplicationModel;
using Windows.Storage;
using WinUIEx; using WinUIEx;
namespace Ghost.Editor.View.Windows; namespace Ghost.Editor.View.Windows;
@@ -20,7 +19,7 @@ internal sealed partial class SplashWindow : WindowEx
IsMinimizable = false; IsMinimizable = false;
ExtendsContentIntoTitleBar = true; ExtendsContentIntoTitleBar = true;
//this.CenterOnScreen(750, 400); this.CenterOnScreen(750, 400);
} }
private void MainGrid_Loaded(object sender, RoutedEventArgs e) private void MainGrid_Loaded(object sender, RoutedEventArgs e)

View File

@@ -35,6 +35,11 @@ internal partial class ProjectBrowserViewModel : ObservableObject
} }
} }
public string CurrentDirectoryPath
{
get; set;
} = string.Empty;
public ProjectBrowserViewModel(IInspectorService inspectorService) public ProjectBrowserViewModel(IInspectorService inspectorService)
{ {
_inspectorService = inspectorService; _inspectorService = inspectorService;
@@ -84,6 +89,8 @@ internal partial class ProjectBrowserViewModel : ObservableObject
var fileItem = new ExplorerItem(Path.GetFileName(file), file, false); var fileItem = new ExplorerItem(Path.GetFileName(file), file, false);
Files.Add(fileItem); Files.Add(fileItem);
} }
CurrentDirectoryPath = path;
} }
internal (ExplorerItem?, int) OpenSelected() internal (ExplorerItem?, int) OpenSelected()