Refactor project from Ghost.App to Ghost.Editor
Changed the project structure to reflect a shift from `Ghost.App` to `Ghost.Editor`, updating namespaces and class names throughout. Changed the application class in `App.xaml` and `App.xaml.cs` from `GhostApplication` to `EditorApplication`. Changed several service interfaces to reside under `Ghost.Editor.Services.Contracts`, including `IInspectorService`, `INotificationService`, and `IProgressService`. Added `InspectorView` and `InspectorViewModel` classes to manage inspector functionality. Added `NavigationTabView` and `NavigationTabPage` classes to facilitate navigation within the editor. Enhanced `WorldNode` and `EntityNode` classes to support scene graph functionality, including serialization and entity management. Updated the project file `Ghost.Editor.csproj` to reflect the new structure and removed old references. Modified the solution file `GhostEngine.sln` to remove references to `Ghost.App` and include `Ghost.Editor`. Updated unit tests to align with the new namespaces and project structure.
This commit is contained in:
@@ -3,7 +3,7 @@ using Ghost.Data.Services;
|
||||
using Microsoft.UI.Xaml;
|
||||
using System.IO;
|
||||
|
||||
namespace Ghost.App;
|
||||
namespace Ghost.Editor;
|
||||
|
||||
internal static class ActivationHandler
|
||||
{
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Application
|
||||
x:Class="Ghost.App.GhostApplication"
|
||||
x:Class="Ghost.Editor.EditorApplication"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Ghost.App">
|
||||
xmlns:local="using:Ghost.Editor">
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
|
||||
@@ -1,31 +1,30 @@
|
||||
using Ghost.App.Infrastructures.AppState;
|
||||
using Ghost.App.Services;
|
||||
using Ghost.App.Utilities;
|
||||
using Ghost.Editor.Core.AppState;
|
||||
using Ghost.Editor.Services;
|
||||
using Ghost.Editor.Services.Contracts;
|
||||
using Ghost.Editor.Utilities;
|
||||
using Ghost.Engine.Services;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.UI.Xaml;
|
||||
using System;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
|
||||
namespace Ghost.App;
|
||||
namespace Ghost.Editor;
|
||||
|
||||
/// <summary>
|
||||
/// Provides application-specific behavior to supplement the default Application class.
|
||||
/// </summary>
|
||||
public partial class GhostApplication : Application
|
||||
public partial class EditorApplication : Application
|
||||
{
|
||||
private Window? _window;
|
||||
|
||||
internal static Window? Window
|
||||
{
|
||||
get => (Current as GhostApplication)!._window;
|
||||
get => (Current as EditorApplication)!._window;
|
||||
set
|
||||
{
|
||||
if (Current is GhostApplication app)
|
||||
if (Current is EditorApplication app)
|
||||
{
|
||||
app._window = value;
|
||||
}
|
||||
@@ -41,7 +40,7 @@ public partial class GhostApplication : Application
|
||||
/// Initializes the singleton application object. This is the first line of authored code
|
||||
/// executed, and as such is the logical equivalent of main() or WinMain().
|
||||
/// </summary>
|
||||
internal GhostApplication()
|
||||
internal EditorApplication()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
@@ -56,6 +55,7 @@ public partial class GhostApplication : Application
|
||||
services.AddSingleton<AppStateMachine>();
|
||||
services.AddSingleton<INotificationService, NotificationService>();
|
||||
services.AddSingleton<IProgressService, ProgressService>();
|
||||
services.AddSingleton<IInspectorService, InspectorService>();
|
||||
})
|
||||
.Build();
|
||||
|
||||
@@ -64,12 +64,12 @@ public partial class GhostApplication : Application
|
||||
|
||||
internal static IServiceScope CreateScope()
|
||||
{
|
||||
return (Current as GhostApplication)!.Host.Services.CreateScope();
|
||||
return (Current as EditorApplication)!.Host.Services.CreateScope();
|
||||
}
|
||||
|
||||
public static T GetService<T>() where T : class
|
||||
{
|
||||
if ((Current as GhostApplication)!.Host.Services.GetService(typeof(T)) is not T service)
|
||||
if ((Current as EditorApplication)!.Host.Services.GetService(typeof(T)) is not T service)
|
||||
{
|
||||
throw new ArgumentException($"{typeof(T)} needs to be registered in ConfigureServices within App.xaml.cs.");
|
||||
}
|
||||
|
||||
3
Ghost.App/AssemblyInfo.cs
Normal file
3
Ghost.App/AssemblyInfo.cs
Normal file
@@ -0,0 +1,3 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("Ghost.UnitTest")]
|
||||
15
Ghost.App/Contracts/IInspectable.cs
Normal file
15
Ghost.App/Contracts/IInspectable.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Ghost.Editor.Contracts;
|
||||
|
||||
public interface IInspectable
|
||||
{
|
||||
public IconSource? Icon
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public UIElement? HeaderContent();
|
||||
public UIElement? InspectorContent();
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Ghost.App.Contracts;
|
||||
namespace Ghost.Editor.Contracts;
|
||||
|
||||
public interface INavigationAware
|
||||
{
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Ghost.Editor.Controls.Internal;
|
||||
|
||||
internal sealed partial class InspectorView : ContentControl
|
||||
{
|
||||
public UIElement? Header
|
||||
{
|
||||
get => (UIElement)GetValue(HeaderProperty);
|
||||
set => SetValue(HeaderProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(
|
||||
nameof(Header),
|
||||
typeof(UIElement),
|
||||
typeof(InspectorView),
|
||||
new PropertyMetadata(null));
|
||||
|
||||
public InspectorView()
|
||||
{
|
||||
DefaultStyleKey = typeof(InspectorView);
|
||||
}
|
||||
}
|
||||
@@ -1,41 +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">
|
||||
<Style TargetType="local:InspectorView">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="local:InspectorView">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="50" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Header -->
|
||||
<Grid Grid.Row="0">
|
||||
<ContentPresenter
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Content="{TemplateBinding Header}"
|
||||
ContentTemplate="{TemplateBinding HeaderTemplate}" />
|
||||
</Grid>
|
||||
|
||||
<!-- Content -->
|
||||
<Grid Grid.Row="1">
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||
<ContentPresenter
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Content="{TemplateBinding Content}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
ContentTransitions="{TemplateBinding ContentTransitions}" />
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
39
Ghost.App/Controls/Internal/NavigationTabView.cs
Normal file
39
Ghost.App/Controls/Internal/NavigationTabView.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using Ghost.Editor.Contracts;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Ghost.Editor.Controls.Internal;
|
||||
|
||||
public partial class NavigationTabPage : TabViewItem, INavigationAware
|
||||
{
|
||||
public virtual void OnNavigatedTo(object? parameter)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void OnNavigatedFrom()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public sealed partial class NavigationTabView : TabView
|
||||
{
|
||||
public NavigationTabView()
|
||||
{
|
||||
this.SelectionChanged += NavigationTabView_SelectionChanged;
|
||||
}
|
||||
|
||||
private void NavigationTabView_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
foreach (var oldItem in e.RemovedItems)
|
||||
{
|
||||
if (oldItem is NavigationTabPage oldPage)
|
||||
{
|
||||
oldPage.OnNavigatedFrom();
|
||||
}
|
||||
}
|
||||
|
||||
if (SelectedItem is NavigationTabPage newPage)
|
||||
{
|
||||
newPage.OnNavigatedTo(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
5
Ghost.App/Controls/Internal/NavigationTabView.xaml
Normal file
5
Ghost.App/Controls/Internal/NavigationTabView.xaml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?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" />
|
||||
@@ -1,9 +1,9 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Ghost.App.Contracts;
|
||||
using Ghost.Editor.Contracts;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
|
||||
namespace Ghost.App.Controls;
|
||||
namespace Ghost.Editor.Controls;
|
||||
|
||||
public abstract partial class ViewModelPage<VM> : Page
|
||||
where VM : ObservableObject
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ghost.App.Infrastructures.AppState;
|
||||
namespace Ghost.Editor.Core.AppState;
|
||||
|
||||
internal class AppStateMachine
|
||||
{
|
||||
@@ -1,13 +1,10 @@
|
||||
using Ghost.App.View.Windows;
|
||||
using Ghost.Data.Models;
|
||||
using Ghost.Data.Models;
|
||||
using Ghost.Data.Services;
|
||||
using Ghost.Editor;
|
||||
using Ghost.Editor.Core.AssetHandle;
|
||||
using Ghost.Editor.View.Windows;
|
||||
using Ghost.Engine;
|
||||
using Microsoft.UI.Xaml;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ghost.App.Infrastructures.AppState;
|
||||
namespace Ghost.Editor.Core.AppState;
|
||||
|
||||
internal class EditorState : IAppState
|
||||
{
|
||||
@@ -16,9 +13,9 @@ internal class EditorState : IAppState
|
||||
|
||||
public Task OnExitingAsync()
|
||||
{
|
||||
if (GhostApplication.Window == _window)
|
||||
if (EditorApplication.Window == _window)
|
||||
{
|
||||
GhostApplication.Window = null;
|
||||
EditorApplication.Window = null;
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
@@ -32,13 +29,13 @@ internal class EditorState : IAppState
|
||||
|
||||
ProjectService.CurrentProject = metadataInfo;
|
||||
|
||||
_engineCore = GhostApplication.GetService<EngineCore>();
|
||||
_engineCore = EditorApplication.GetService<EngineCore>();
|
||||
await _engineCore.StartAsync(new Engine.Models.LaunchArgument());
|
||||
|
||||
_window = GhostApplication.GetService<EngineEditorWindow>();
|
||||
_window = EditorApplication.GetService<EngineEditorWindow>();
|
||||
_window.Activate();
|
||||
|
||||
GhostApplication.Window = _window;
|
||||
EditorApplication.Window = _window;
|
||||
}
|
||||
|
||||
public async Task OnExitedAsync()
|
||||
@@ -48,9 +45,9 @@ internal class EditorState : IAppState
|
||||
await _engineCore.ShutDownAsync();
|
||||
}
|
||||
|
||||
if (GhostApplication.Window == _window)
|
||||
if (EditorApplication.Window == _window)
|
||||
{
|
||||
GhostApplication.Window = null;
|
||||
EditorApplication.Window = null;
|
||||
}
|
||||
|
||||
_window?.Close();
|
||||
@@ -59,7 +56,7 @@ internal class EditorState : IAppState
|
||||
|
||||
public Task OnEnteredAsync(object? parameter)
|
||||
{
|
||||
EditorApplication.Activate(parameter, ((GhostApplication)(Application.Current)).Host.Services);
|
||||
AssetDatabase.Initialize();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ghost.App.Infrastructures.AppState;
|
||||
namespace Ghost.Editor.Core.AppState;
|
||||
|
||||
internal interface IAppState
|
||||
{
|
||||
@@ -1,7 +1,8 @@
|
||||
using Ghost.App.View.Windows;
|
||||
using Ghost.Editor;
|
||||
using Ghost.Editor.View.Windows;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ghost.App.Infrastructures.AppState;
|
||||
namespace Ghost.Editor.Core.AppState;
|
||||
|
||||
internal class LandingState : IAppState
|
||||
{
|
||||
@@ -9,17 +10,17 @@ internal class LandingState : IAppState
|
||||
|
||||
public Task OnExitingAsync()
|
||||
{
|
||||
if (GhostApplication.Window == _window)
|
||||
if (EditorApplication.Window == _window)
|
||||
{
|
||||
GhostApplication.Window = null;
|
||||
EditorApplication.Window = null;
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task OnEnteringAsync(object? parameter)
|
||||
{
|
||||
_window = GhostApplication.GetService<LandingWindow>();
|
||||
GhostApplication.Window = _window;
|
||||
_window = EditorApplication.GetService<LandingWindow>();
|
||||
EditorApplication.Window = _window;
|
||||
|
||||
_window.Activate();
|
||||
return Task.CompletedTask;
|
||||
@@ -27,9 +28,9 @@ internal class LandingState : IAppState
|
||||
|
||||
public Task OnExitedAsync()
|
||||
{
|
||||
if (GhostApplication.Window == _window)
|
||||
if (EditorApplication.Window == _window)
|
||||
{
|
||||
GhostApplication.Window = null;
|
||||
EditorApplication.Window = null;
|
||||
}
|
||||
|
||||
_window?.Close();
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Ghost.App.Infrastructures.AppState;
|
||||
namespace Ghost.Editor.Core.AppState;
|
||||
|
||||
internal enum StateKey
|
||||
{
|
||||
24
Ghost.App/Core/AssetHandle/Asset.cs
Normal file
24
Ghost.App/Core/AssetHandle/Asset.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace Ghost.Editor.Core.AssetHandle;
|
||||
|
||||
public abstract class Asset
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the Guid of the asset.
|
||||
/// </summary>
|
||||
public Guid GUID
|
||||
{
|
||||
get;
|
||||
} = Guid.NewGuid();
|
||||
|
||||
/// <summary>
|
||||
/// True if the asset is a folder, false if it is a file.
|
||||
/// </summary>
|
||||
public bool IsFolder
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
internal void GenerateMetadata()
|
||||
{
|
||||
}
|
||||
}
|
||||
60
Ghost.App/Core/AssetHandle/AssetDatabase.cs
Normal file
60
Ghost.App/Core/AssetHandle/AssetDatabase.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Ghost.Editor.Core.AssetHandle;
|
||||
|
||||
public static class AssetDatabase
|
||||
{
|
||||
private static readonly Dictionary<string, Action<string>> _assetOpenHandlers = new(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
static AssetDatabase()
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
internal static void Initialize()
|
||||
{
|
||||
RegisterAssetHandles();
|
||||
}
|
||||
|
||||
private static void RegisterAssetHandles()
|
||||
{
|
||||
var methods = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(a => a.GetTypes())
|
||||
.SelectMany(t => t.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
|
||||
.Where(m => m.GetCustomAttribute<AssetOpenHandlerAttribute>() != null &&
|
||||
m.GetParameters().Length == 1 &&
|
||||
m.GetParameters()[0].ParameterType == typeof(string));
|
||||
|
||||
foreach (var method in methods)
|
||||
{
|
||||
var attr = method.GetCustomAttribute<AssetOpenHandlerAttribute>()!;
|
||||
var del = (Action<string>)Delegate.CreateDelegate(typeof(Action<string>), method);
|
||||
foreach (var ext in attr.Extensions)
|
||||
{
|
||||
if (_assetOpenHandlers.ContainsKey(ext))
|
||||
{
|
||||
throw new InvalidOperationException($"Duplicate handler for extension '{ext}'");
|
||||
}
|
||||
|
||||
_assetOpenHandlers[ext] = del;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void OpenAsset(string path)
|
||||
{
|
||||
var extension = Path.GetExtension(path);
|
||||
if (_assetOpenHandlers.TryGetValue(extension, out var handler))
|
||||
{
|
||||
handler(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
Process.Start(new ProcessStartInfo(path)
|
||||
{
|
||||
UseShellExecute = true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Ghost.App/Core/AssetHandle/AssetOpenHandlerAttribute .cs
Normal file
15
Ghost.App/Core/AssetHandle/AssetOpenHandlerAttribute .cs
Normal file
@@ -0,0 +1,15 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
53
Ghost.App/Core/SceneGraph/EditorWorldManager.cs
Normal file
53
Ghost.App/Core/SceneGraph/EditorWorldManager.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using Ghost.Editor.Resources;
|
||||
using Ghost.Editor.Services.Contracts;
|
||||
using Ghost.Engine.Resources;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Ghost.Editor.Core.SceneGraph;
|
||||
|
||||
public enum OpenWorldMode
|
||||
{
|
||||
Single,
|
||||
Additive,
|
||||
AdditiveWithoutLoading
|
||||
}
|
||||
|
||||
public static class EditorWorldManager
|
||||
{
|
||||
// TODO: Use guid keys instead of string paths for better performance and uniqueness
|
||||
private static readonly Dictionary<string, WorldNode> _loadedWorlds = new();
|
||||
public static IEnumerable<WorldNode> LoadedWorlds => _loadedWorlds.Values;
|
||||
|
||||
public static event Action<WorldNode>? OnWorldLoaded;
|
||||
public static event Action<WorldNode>? OnWorldUnloaded;
|
||||
|
||||
public static async Task LoadWorld(string worldPath)
|
||||
{
|
||||
if (_loadedWorlds.ContainsKey(worldPath)
|
||||
|| !File.Exists(worldPath)
|
||||
|| Path.GetExtension(worldPath) != FileExtensions.SCENE_FILE_EXTENSION)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var progressService = EditorApplication.GetService<IProgressService>();
|
||||
progressService.ShowIndeterminateProgress("Loading world...");
|
||||
|
||||
foreach (var world in _loadedWorlds)
|
||||
{
|
||||
world.Value.Unload();
|
||||
OnWorldUnloaded?.Invoke(world.Value);
|
||||
}
|
||||
|
||||
await using var readStream = new FileStream(worldPath, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
var deserializedScene = await JsonSerializer.DeserializeAsync<WorldNode>(readStream, StaticResource.defaultSerializerOptions) ?? throw new Exception("Deserialization failed.");
|
||||
|
||||
_loadedWorlds.Clear();
|
||||
|
||||
_loadedWorlds[worldPath] = deserializedScene;
|
||||
await deserializedScene.LoadAsync();
|
||||
|
||||
progressService.HideProgress();
|
||||
OnWorldLoaded?.Invoke(deserializedScene);
|
||||
}
|
||||
}
|
||||
70
Ghost.App/Core/SceneGraph/EntityNode.cs
Normal file
70
Ghost.App/Core/SceneGraph/EntityNode.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using Ghost.Editor.Contracts;
|
||||
using Ghost.Editor.Resources;
|
||||
using Ghost.Entities;
|
||||
using Microsoft.UI.Text;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
|
||||
namespace Ghost.Editor.Core.SceneGraph;
|
||||
|
||||
public partial class EntityNode : SceneGraphNode
|
||||
{
|
||||
private readonly Entity _entity;
|
||||
|
||||
public Entity Entity => _entity;
|
||||
public override SceneGraphNodeType NodeType => SceneGraphNodeType.Entity;
|
||||
|
||||
public EntityNode(Entity entity, string name)
|
||||
{
|
||||
_entity = entity;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
internal EntityNode()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public partial class EntityNode : IInspectable
|
||||
{
|
||||
public IconSource? Icon => EditorIconSource.entity_24;
|
||||
|
||||
public UIElement? HeaderContent()
|
||||
{
|
||||
var root = new StackPanel()
|
||||
{
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||
VerticalAlignment = VerticalAlignment.Center
|
||||
};
|
||||
|
||||
var nameText = new TextBox
|
||||
{
|
||||
Text = Name,
|
||||
FontWeight = FontWeights.Bold,
|
||||
};
|
||||
var idText = new TextBlock
|
||||
{
|
||||
Text = $"ID: {_entity.ID}",
|
||||
Margin = new Thickness(0, 5, 0, 0),
|
||||
};
|
||||
|
||||
nameText.SetBinding(TextBox.TextProperty, new Binding
|
||||
{
|
||||
Source = this,
|
||||
Path = new PropertyPath(nameof(Name)),
|
||||
Mode = BindingMode.TwoWay,
|
||||
UpdateSourceTrigger = UpdateSourceTrigger.LostFocus,
|
||||
});
|
||||
|
||||
root.Children.Add(nameText);
|
||||
root.Children.Add(idText);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
public UIElement? InspectorContent()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
112
Ghost.App/Core/SceneGraph/SceneGraphHelpers.cs
Normal file
112
Ghost.App/Core/SceneGraph/SceneGraphHelpers.cs
Normal file
@@ -0,0 +1,112 @@
|
||||
using Ghost.Engine.Components;
|
||||
using Ghost.Entities;
|
||||
|
||||
namespace Ghost.Editor.Core.SceneGraph;
|
||||
|
||||
public class SceneGraphHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="EntityNode"/> entity with default components.
|
||||
/// </summary>
|
||||
/// <param name="world">The world context where the entity will be created.</param>
|
||||
/// <param name="entity">The entity to be wrapped in the <see cref="EntityNode"/>.</param>
|
||||
public static EntityNode CreateEntityNode(World world, Entity entity, string name)
|
||||
{
|
||||
world.EntityManager.AddComponent(entity, LocalToWorld.Identity);
|
||||
world.EntityManager.AddComponent(entity, Hierarchy.Root);
|
||||
return new EntityNode(entity, name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="Entity"/> and <see cref="EntityNode"/> entity with default components.
|
||||
/// </summary>
|
||||
/// <param name="world">The world context where the entity will be created.</param>
|
||||
public static EntityNode CreateEntityNode(World world, string name)
|
||||
{
|
||||
var entity = world.EntityManager.CreateEntity();
|
||||
return CreateEntityNode(world, entity, name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attaches childEntity to parentEntity in the scene graph.
|
||||
/// </summary>
|
||||
/// <param name="world">The world context where the entities exist.</param>
|
||||
/// <param name="parentNode">The parent entity to which the child will be attached.</param>
|
||||
/// <param name="childNode">The child entity to be attached.</param>
|
||||
public static void AttachChild(WorldNode scene, EntityNode parentNode, EntityNode childNode)
|
||||
{
|
||||
// 1) If the child already has a parent, detach it first
|
||||
var childHierarchy = scene.World.EntityManager.GetComponent<Hierarchy>(childNode.Entity);
|
||||
if (childHierarchy.ValueRO.parent != Entity.Invalid)
|
||||
{
|
||||
DetachFromParent(scene, childNode);
|
||||
}
|
||||
|
||||
// 2) Link child to new parent
|
||||
childHierarchy.ValueRW.parent = parentNode.Entity;
|
||||
|
||||
// 3) Insert child at the head of parent's child list
|
||||
var parentHierarchy = scene.World.EntityManager.GetComponent<Hierarchy>(parentNode.Entity);
|
||||
|
||||
childHierarchy.ValueRW.nextSibling = parentHierarchy.ValueRO.firstChild;
|
||||
parentHierarchy.ValueRW.firstChild = childNode.Entity;
|
||||
|
||||
// 4) Write back
|
||||
scene.World.EntityManager.SetComponent(parentNode.Entity, in parentHierarchy.ValueRO);
|
||||
scene.World.EntityManager.SetComponent(childNode.Entity, in childHierarchy.ValueRO);
|
||||
|
||||
// 5) Update children list in parent node
|
||||
parentNode.AddChild(childNode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Detaches the specified entity from its parent in the scene graph.
|
||||
/// </summary>
|
||||
/// <param name="world">The world context where the entities exist.</param>
|
||||
/// <param name="node">The entity to detach from its parent.</param>
|
||||
public static void DetachFromParent(WorldNode scene, EntityNode node)
|
||||
{
|
||||
var hierarchy = scene.World.EntityManager.GetComponent<Hierarchy>(node.Entity);
|
||||
var parent = hierarchy.ValueRO.parent;
|
||||
if (parent == Entity.Invalid)
|
||||
{
|
||||
return; // already root
|
||||
}
|
||||
|
||||
var parentHierarchy = scene.World.EntityManager.GetComponent<Hierarchy>(parent);
|
||||
|
||||
// If entity is the first child, simply move head
|
||||
if (parentHierarchy.ValueRO.firstChild == node.Entity)
|
||||
{
|
||||
parentHierarchy.ValueRW.firstChild = hierarchy.ValueRO.nextSibling;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, find the previous sibling in the linked list
|
||||
var prevSibling = parentHierarchy.ValueRO.firstChild;
|
||||
while (prevSibling != Entity.Invalid)
|
||||
{
|
||||
var prevHierarchy = scene.World.EntityManager.GetComponent<Hierarchy>(prevSibling);
|
||||
if (prevHierarchy.ValueRW.nextSibling == node.Entity)
|
||||
{
|
||||
prevHierarchy.ValueRW.nextSibling = hierarchy.ValueRO.nextSibling;
|
||||
scene.World.EntityManager.SetComponent(prevSibling, in prevHierarchy.ValueRO);
|
||||
break;
|
||||
}
|
||||
|
||||
prevSibling = prevHierarchy.ValueRO.nextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
// Clear child's references
|
||||
hierarchy.ValueRW.parent = Entity.Invalid;
|
||||
hierarchy.ValueRW.nextSibling = Entity.Invalid;
|
||||
|
||||
// Write back
|
||||
scene.World.EntityManager.SetComponent(parent, in parentHierarchy.ValueRO);
|
||||
scene.World.EntityManager.SetComponent(node.Entity, in hierarchy.ValueRO);
|
||||
|
||||
// Remove from parent's children list
|
||||
scene.EntityNodeLookup[parent].RemoveChild(node);
|
||||
}
|
||||
}
|
||||
54
Ghost.App/Core/SceneGraph/SceneGraphNode.cs
Normal file
54
Ghost.App/Core/SceneGraph/SceneGraphNode.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Ghost.Editor.Core.SceneGraph;
|
||||
|
||||
public enum SceneGraphNodeType
|
||||
{
|
||||
Scene,
|
||||
Entity,
|
||||
}
|
||||
|
||||
public abstract partial class SceneGraphNode : ObservableObject
|
||||
{
|
||||
public ObservableCollection<SceneGraphNode>? Children
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public partial string Name
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public abstract SceneGraphNodeType NodeType
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public int ChildCount => Children?.Count ?? 0;
|
||||
|
||||
public virtual void AddChild(SceneGraphNode child)
|
||||
{
|
||||
Children ??= new();
|
||||
Children.Add(child);
|
||||
}
|
||||
|
||||
public virtual bool RemoveChild(SceneGraphNode child)
|
||||
{
|
||||
return Children?.Remove(child) ?? false;
|
||||
}
|
||||
|
||||
public SceneGraphNode GetChild(int index)
|
||||
{
|
||||
if (Children == null || index < 0 || index >= Children.Count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index), "Index is out of range.");
|
||||
}
|
||||
|
||||
return Children[index];
|
||||
}
|
||||
}
|
||||
195
Ghost.App/Core/SceneGraph/WorldNode.cs
Normal file
195
Ghost.App/Core/SceneGraph/WorldNode.cs
Normal file
@@ -0,0 +1,195 @@
|
||||
using Ghost.Editor.Contracts;
|
||||
using Ghost.Editor.Core.AssetHandle;
|
||||
using Ghost.Editor.Core.Serializer;
|
||||
using Ghost.Editor.Resources;
|
||||
using Ghost.Engine.Components;
|
||||
using Ghost.Entities;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Ghost.Editor.Core.SceneGraph;
|
||||
|
||||
[JsonConverter(typeof(WorldNodeSerializer))]
|
||||
public partial class WorldNode : SceneGraphNode, IEquatable<WorldNode>
|
||||
{
|
||||
private World _world;
|
||||
private Dictionary<Entity, EntityNode> _entityNodeLookup = new();
|
||||
|
||||
public World World => _world;
|
||||
public Dictionary<Entity, EntityNode> EntityNodeLookup => _entityNodeLookup;
|
||||
|
||||
public override SceneGraphNodeType NodeType => SceneGraphNodeType.Scene;
|
||||
|
||||
public WorldNode(World world, string name)
|
||||
{
|
||||
_world = world;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
internal WorldNode()
|
||||
{
|
||||
_world = World.Create();
|
||||
}
|
||||
|
||||
private void UpdateLookup(Entity key, EntityNode value)
|
||||
{
|
||||
_entityNodeLookup[key] = value;
|
||||
if (value.Children == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var child in value.Children)
|
||||
{
|
||||
if (child is EntityNode entityChild)
|
||||
{
|
||||
UpdateLookup(entityChild.Entity, entityChild);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void AddChild(SceneGraphNode child)
|
||||
{
|
||||
if (child is not EntityNode entityNode)
|
||||
{
|
||||
throw new ArgumentException("Child must be of type EntityNode.", nameof(child));
|
||||
}
|
||||
|
||||
base.AddChild(entityNode);
|
||||
UpdateLookup(entityNode.Entity, entityNode);
|
||||
}
|
||||
|
||||
public override bool RemoveChild(SceneGraphNode child)
|
||||
{
|
||||
if (child is not EntityNode entityNode)
|
||||
{
|
||||
throw new ArgumentException("Child must be of type EntityNode.", nameof(child));
|
||||
}
|
||||
|
||||
var result = base.RemoveChild(child);
|
||||
if (result)
|
||||
{
|
||||
_entityNodeLookup.Remove(entityNode.Entity);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private EntityNode BuildNodeRecursive(Entity entity, World world)
|
||||
{
|
||||
if (!_entityNodeLookup.TryGetValue(entity, out var node))
|
||||
{
|
||||
node = new EntityNode(entity, "New Entity");
|
||||
_entityNodeLookup[entity] = node;
|
||||
}
|
||||
|
||||
var hc = world.EntityManager.GetComponent<Hierarchy>(entity);
|
||||
var child = hc.ValueRO.firstChild;
|
||||
|
||||
while (child != Entity.Invalid)
|
||||
{
|
||||
node.AddChild(BuildNodeRecursive(child, world));
|
||||
var childHC = world.EntityManager.GetComponent<Hierarchy>(child);
|
||||
child = childHC.ValueRO.nextSibling;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
private void BuildGraph()
|
||||
{
|
||||
foreach (var (entity, hierarchy) in _world.Query<Hierarchy>())
|
||||
{
|
||||
if (hierarchy.ValueRO.parent == Entity.Invalid)
|
||||
{
|
||||
var node = BuildNodeRecursive(entity, _world);
|
||||
AddChild(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Task LoadAsync()
|
||||
{
|
||||
return Task.Run(BuildGraph);
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
_world.Dispose();
|
||||
_world = null!;
|
||||
|
||||
Children?.Clear();
|
||||
_entityNodeLookup.Clear();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"WorldNode: {Name} (World ID: {_world.ID})";
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(_world, Name);
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is WorldNode other && Equals(other);
|
||||
}
|
||||
|
||||
public bool Equals(WorldNode? other)
|
||||
{
|
||||
if (other is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(this, other))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return _world.Equals(other._world) && Name == other.Name;
|
||||
}
|
||||
|
||||
public static bool operator ==(WorldNode? left, WorldNode? right)
|
||||
{
|
||||
if (left is null)
|
||||
{
|
||||
return right is null;
|
||||
}
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(WorldNode? left, WorldNode? right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class WorldNode : IInspectable
|
||||
{
|
||||
public IconSource? Icon => EditorIconSource.scene_24;
|
||||
|
||||
[AssetOpenHandler(FileExtensions.SCENE_FILE_EXTENSION)]
|
||||
public static async void Open(string path)
|
||||
{
|
||||
await EditorWorldManager.LoadWorld(path);
|
||||
}
|
||||
|
||||
public UIElement? HeaderContent()
|
||||
{
|
||||
return new TextBlock
|
||||
{
|
||||
Text = Name,
|
||||
Style = Application.Current.Resources["SubtitleTextBlockStyle"] as Style,
|
||||
VerticalAlignment = VerticalAlignment.Center
|
||||
};
|
||||
}
|
||||
|
||||
public UIElement? InspectorContent()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
131
Ghost.App/Core/Serializer/WorldNodeSerializer.cs
Normal file
131
Ghost.App/Core/Serializer/WorldNodeSerializer.cs
Normal file
@@ -0,0 +1,131 @@
|
||||
using Ghost.Editor.Core.SceneGraph;
|
||||
using Ghost.Engine.Utilities;
|
||||
using Ghost.Entities;
|
||||
using Ghost.Entities.Components;
|
||||
using Ghost.Entities.Utilities;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Ghost.Editor.Core.Serializer;
|
||||
|
||||
internal class WorldNodeSerializer : JsonConverter<WorldNode>
|
||||
{
|
||||
private static class Property
|
||||
{
|
||||
public const string NAME = "Name";
|
||||
public const string ENTITIES = "Entities";
|
||||
public const string ID = "ID";
|
||||
public const string ENTITY_ID = "EntityID";
|
||||
public const string COMPONENTS = "Components";
|
||||
public const string DATA = "Data";
|
||||
public const string SYSTEMS = "Systems";
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type typeToConvert)
|
||||
{
|
||||
return typeToConvert == typeof(WorldNode) || typeToConvert.IsSubclassOf(typeof(WorldNode));
|
||||
}
|
||||
|
||||
public override WorldNode? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
var element = JsonDocument.ParseValue(ref reader).RootElement;
|
||||
var name = element.GetProperty(Property.NAME).GetString() ?? "New World";
|
||||
|
||||
var world = World.Create();
|
||||
var result = new WorldNode(world, name);
|
||||
|
||||
foreach (var entityElement in element.GetProperty(Property.ENTITIES).EnumerateArray())
|
||||
{
|
||||
var entityName = entityElement.GetProperty(Property.NAME).GetString() ?? "New Entity";
|
||||
var entityID = entityElement.GetProperty(Property.ID).GetInt32();
|
||||
var entity = new Entity(entityID, 0);
|
||||
var node = new EntityNode(entity, entityName);
|
||||
|
||||
world.EntityManager.AddEntityInternal(entity);
|
||||
result.EntityNodeLookup[entity] = node;
|
||||
}
|
||||
|
||||
foreach (var componentElement in element.GetProperty(Property.COMPONENTS).EnumerateObject())
|
||||
{
|
||||
var typeName = componentElement.Name;
|
||||
var type = Type.GetType(typeName) ?? throw new Exception($"Type {typeName} not found.");
|
||||
|
||||
foreach (var dataElement in componentElement.Value.EnumerateArray())
|
||||
{
|
||||
var entityID = dataElement.GetProperty(Property.ENTITY_ID).GetInt32();
|
||||
var entity = new Entity(entityID, 0);
|
||||
|
||||
var dataProperty = dataElement.GetProperty(Property.DATA);
|
||||
var component = JsonSerializer.Deserialize(dataProperty.GetRawText(), type, options);
|
||||
if (component is IComponentData data)
|
||||
{
|
||||
world.EntityManager.AddComponent(entity, data, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var systemElement in element.GetProperty(Property.SYSTEMS).EnumerateArray())
|
||||
{
|
||||
var typeString = systemElement.GetString();
|
||||
if (string.IsNullOrEmpty(typeString))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var systemType = Type.GetType(typeString);
|
||||
if (systemType == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
world.SystemStorage.AddSystem(systemType);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, WorldNode value, JsonSerializerOptions options)
|
||||
{
|
||||
writer.WriteObject(() =>
|
||||
{
|
||||
writer.WriteString(Property.NAME, value.Name);
|
||||
writer.WriteArray(Property.ENTITIES, value.World.EntityManager.Entities, entity =>
|
||||
{
|
||||
if (!entity.IsValid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteObject(() =>
|
||||
{
|
||||
writer.WriteString(Property.NAME, value.EntityNodeLookup[entity].Name);
|
||||
writer.WriteNumber(Property.ID, entity.ID);
|
||||
});
|
||||
});
|
||||
|
||||
writer.WriteObject(Property.COMPONENTS, () =>
|
||||
{
|
||||
foreach (var kvp in value.World.ComponentStorage.ComponentPools)
|
||||
{
|
||||
var type = TypeHandle.ToType(kvp.Key) ?? throw new Exception($"Type {kvp.Key} not found.");
|
||||
var typeName = type.AssemblyQualifiedName ?? type.Name;
|
||||
|
||||
writer.WriteArray(typeName, kvp.Value.Enumerate(), data =>
|
||||
{
|
||||
writer.WriteObject(() =>
|
||||
{
|
||||
writer.WriteNumber(Property.ENTITY_ID, data.entity.ID);
|
||||
writer.WritePropertyName(Property.DATA);
|
||||
JsonSerializer.Serialize(writer, data.component, type, options);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
writer.WriteArray(Property.SYSTEMS, value.World.SystemStorage.Systems, systemType =>
|
||||
{
|
||||
writer.WriteStringValue(systemType.AssemblyQualifiedName ?? systemType.Name);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net9.0-windows10.0.22621.0</TargetFramework>
|
||||
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
|
||||
<RootNamespace>Ghost.App</RootNamespace>
|
||||
<Platforms>x86;x64;ARM64</Platforms>
|
||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
|
||||
<PublishProfile>win-$(Platform).pubxml</PublishProfile>
|
||||
@@ -42,10 +41,11 @@
|
||||
<None Remove="Assets\Icon.targetsize-48_altform-unplated.png" />
|
||||
<None Remove="Controls\BasicInput\PropertyField.xaml" />
|
||||
<None Remove="Controls\EditorControls.xaml" />
|
||||
<None Remove="Controls\Internal\InspectorView.xaml" />
|
||||
<None Remove="Controls\Internal\InternalControls.xaml" />
|
||||
<None Remove="Controls\Internal\NavigationTabView.xaml" />
|
||||
<None Remove="View\Pages\EngineEditor\ConsolePage.xaml" />
|
||||
<None Remove="View\Pages\EngineEditor\HierarchyPage.xaml" />
|
||||
<None Remove="View\Pages\EngineEditor\InspectorPage.xaml" />
|
||||
<None Remove="View\Pages\EngineEditor\ProjectPage.xaml" />
|
||||
<None Remove="View\Pages\Landing\CreateProjectPage.xaml" />
|
||||
<None Remove="View\Pages\Landing\OpenProjectPage.xaml" />
|
||||
@@ -89,7 +89,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ghost.Data\Ghost.Data.csproj" />
|
||||
<ProjectReference Include="..\Ghost.Editor\Ghost.Editor.csproj" />
|
||||
<ProjectReference Include="..\Ghost.Engine\Ghost.Engine.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -107,14 +106,16 @@
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Resources\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Misaki.HighPerformance.Unsafe">
|
||||
<HintPath>..\..\Class\Misaki.HighPerformance\Misaki.HighPerformance.Unsafe\bin\Release\net9.0\Misaki.HighPerformance.Unsafe.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="View\Pages\EngineEditor\InspectorPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="View\Pages\EngineEditor\HierarchyPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
@@ -140,11 +141,6 @@
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\Internal\InspectorView.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="View\Windows\EngineEditorWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
@@ -160,6 +156,14 @@
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Controls\Layout\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\Internal\NavigationTabView.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals" />
|
||||
|
||||
<!--
|
||||
@@ -181,5 +185,7 @@
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
<PublishAot>False</PublishAot>
|
||||
<PublishTrimmed>False</PublishTrimmed>
|
||||
<RootNamespace>Ghost.Editor</RootNamespace>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Ghost.App.Models;
|
||||
namespace Ghost.Editor.Models;
|
||||
|
||||
internal struct AssetItem()
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Ghost.App.Models;
|
||||
namespace Ghost.Editor.Models;
|
||||
|
||||
internal class ExplorerItem(string name, string path, bool isDirectory)
|
||||
{
|
||||
|
||||
9
Ghost.App/Models/MessageType.cs
Normal file
9
Ghost.App/Models/MessageType.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Ghost.Editor.Models;
|
||||
|
||||
public enum MessageType
|
||||
{
|
||||
Informational,
|
||||
Success,
|
||||
Warning,
|
||||
Error
|
||||
}
|
||||
18
Ghost.App/Resources/EditorIconSource.cs
Normal file
18
Ghost.App/Resources/EditorIconSource.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Ghost.Editor.Resources;
|
||||
|
||||
public static class EditorIconSource
|
||||
{
|
||||
public static readonly IconSource scene_24 = new FontIconSource
|
||||
{
|
||||
Glyph = "\uF159",
|
||||
FontSize = 24
|
||||
};
|
||||
|
||||
public static readonly IconSource entity_24 = new FontIconSource
|
||||
{
|
||||
Glyph = "\uF158",
|
||||
FontSize = 24
|
||||
};
|
||||
}
|
||||
11
Ghost.App/Resources/FileExtensions.cs
Normal file
11
Ghost.App/Resources/FileExtensions.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace Ghost.Editor.Resources;
|
||||
|
||||
internal static class FileExtensions
|
||||
{
|
||||
public const string PROJECT_FILE_EXTENSION = ".ghostproj";
|
||||
public const string TEMPLATE_FILE_EXTENSION = ".ghosttemplate";
|
||||
public const string SCENE_FILE_EXTENSION = ".ghostscene";
|
||||
public const string ASSET_FILE_EXTENSION = ".ghostasset";
|
||||
public const string SHADER_FILE_EXTENSION = ".ghostshader";
|
||||
public const string MATERIAL_FILE_EXTENSION = ".ghostmaterial";
|
||||
}
|
||||
14
Ghost.App/Services/Contracts/IInspectorService.cs
Normal file
14
Ghost.App/Services/Contracts/IInspectorService.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Ghost.Editor.Contracts;
|
||||
|
||||
namespace Ghost.Editor.Services.Contracts;
|
||||
|
||||
internal interface IInspectorService
|
||||
{
|
||||
public IInspectable? SelectedInspectable
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public event Action? OnSelectionChanged;
|
||||
}
|
||||
8
Ghost.App/Services/Contracts/INotificationService.cs
Normal file
8
Ghost.App/Services/Contracts/INotificationService.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using Ghost.Editor.Models;
|
||||
|
||||
namespace Ghost.Editor.Services.Contracts;
|
||||
|
||||
public interface INotificationService
|
||||
{
|
||||
public void ShowNotification(string? message, MessageType type, int duration = 5, string? title = null);
|
||||
}
|
||||
9
Ghost.App/Services/Contracts/IProgressService.cs
Normal file
9
Ghost.App/Services/Contracts/IProgressService.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Ghost.Editor.Services.Contracts;
|
||||
|
||||
public interface IProgressService
|
||||
{
|
||||
public void ShowProgress(string message, double progress = 0.0);
|
||||
public void ShowIndeterminateProgress(string message);
|
||||
public void SetProgress(double progress);
|
||||
public void HideProgress();
|
||||
}
|
||||
22
Ghost.App/Services/InspectorService.cs
Normal file
22
Ghost.App/Services/InspectorService.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using Ghost.Editor.Contracts;
|
||||
using Ghost.Editor.Services.Contracts;
|
||||
|
||||
namespace Ghost.Editor.Services;
|
||||
|
||||
public class InspectorService : IInspectorService
|
||||
{
|
||||
public IInspectable? SelectedInspectable
|
||||
{
|
||||
get => field;
|
||||
set
|
||||
{
|
||||
if (field != value)
|
||||
{
|
||||
field = value;
|
||||
OnSelectionChanged?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public event Action? OnSelectionChanged;
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using Ghost.Editor.Services.Contracts;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using System;
|
||||
|
||||
namespace Ghost.App.Services;
|
||||
namespace Ghost.Editor.Services;
|
||||
|
||||
public class NotificationService : INotificationService
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@ using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ghost.App.Services;
|
||||
namespace Ghost.Editor.Services;
|
||||
|
||||
public class ProgressService : IProgressService
|
||||
{
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.UI.Xaml.Controls">
|
||||
xmlns:controls="using:Microsoft.UI.Xaml.Controls"
|
||||
xmlns:internal="using:Ghost.Editor.Controls.Internal">
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
<StaticResource x:Key="TabViewItemHeaderBackgroundSelected" ResourceKey="ControlFillColorSecondaryBrush" />
|
||||
@@ -11,7 +12,7 @@
|
||||
<StaticResource x:Key="TabViewItemHeaderBackgroundSelected" ResourceKey="ControlFillColorSecondaryBrush" />
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
<Style TargetType="TabView">
|
||||
<Style TargetType="internal:NavigationTabView">
|
||||
<Setter Property="TabWidthMode" Value="Compact" />
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -2,7 +2,7 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Ghost.App.Utilities;
|
||||
namespace Ghost.Editor.Utilities;
|
||||
|
||||
public static class ComponentTypeCache
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Ghost.App.View.Pages.EngineEditor;
|
||||
using Ghost.App.View.Pages.Landing;
|
||||
using Ghost.App.View.Windows;
|
||||
using Ghost.Data.Services;
|
||||
using Ghost.Data.Services;
|
||||
using Ghost.Editor.View.Pages.EngineEditor;
|
||||
using Ghost.Editor.View.Pages.Landing;
|
||||
using Ghost.Editor.View.Windows;
|
||||
using Ghost.Editor.ViewModels.Pages.EngineEditor;
|
||||
using Ghost.Editor.ViewModels.Pages.Landing;
|
||||
using Ghost.Editor.ViewModels.Windows;
|
||||
@@ -9,7 +9,7 @@ using Ghost.Engine;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace Ghost.App.Utilities;
|
||||
namespace Ghost.Editor.Utilities;
|
||||
|
||||
internal static partial class HostHelper
|
||||
{
|
||||
@@ -41,5 +41,8 @@ internal static partial class HostHelper
|
||||
|
||||
services.AddTransient<ConsolePage>();
|
||||
services.AddTransient<ConsoleViewModel>();
|
||||
|
||||
services.AddTransient<InspectorPage>();
|
||||
services.AddTransient<InspectorViewModel>();
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,19 @@
|
||||
using System;
|
||||
using Ghost.Editor;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Storage;
|
||||
using Windows.Storage.Pickers;
|
||||
using WinRT.Interop;
|
||||
|
||||
namespace Ghost.App.Utilities;
|
||||
namespace Ghost.Editor.Utilities;
|
||||
|
||||
public static class SystemUtilities
|
||||
{
|
||||
public static async Task<StorageFolder?> OpenFolderPickerAsync(PickerLocationId startLocation = PickerLocationId.DocumentsLibrary, string settingsIdentifier = "")
|
||||
{
|
||||
var openPicker = new FolderPicker();
|
||||
var hWnd = WindowNative.GetWindowHandle(GhostApplication.Window);
|
||||
var hWnd = WindowNative.GetWindowHandle(EditorApplication.Window);
|
||||
InitializeWithWindow.Initialize(openPicker, hWnd);
|
||||
|
||||
openPicker.SuggestedStartLocation = startLocation;
|
||||
@@ -26,7 +27,7 @@ public static class SystemUtilities
|
||||
public static async Task<StorageFile?> OpenFilePickerAsync(PickerLocationId startLocation = PickerLocationId.DocumentsLibrary, string settingsIdentifier = "", params IEnumerable<string> filter)
|
||||
{
|
||||
var openPicker = new FileOpenPicker();
|
||||
var hWnd = WindowNative.GetWindowHandle(GhostApplication.Window);
|
||||
var hWnd = WindowNative.GetWindowHandle(EditorApplication.Window);
|
||||
InitializeWithWindow.Initialize(openPicker, hWnd);
|
||||
|
||||
openPicker.SuggestedStartLocation = startLocation;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Page
|
||||
x:Class="Ghost.App.View.Pages.EngineEditor.ConsolePage"
|
||||
x:Class="Ghost.Editor.View.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.App.View.Pages.EngineEditor"
|
||||
xmlns:local="using:Ghost.Editor.View.Pages.EngineEditor"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
@@ -17,9 +17,10 @@
|
||||
<!-- Toolbar -->
|
||||
<Grid
|
||||
Grid.Row="0"
|
||||
Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}"
|
||||
BorderBrush="{ThemeResource CardStrokeColorDefaultSolid}"
|
||||
BorderThickness="0,0,0,1">
|
||||
<CommandBar Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}" DefaultLabelPosition="Collapsed">
|
||||
<CommandBar DefaultLabelPosition="Collapsed">
|
||||
<CommandBar.PrimaryCommands>
|
||||
<AppBarButton Command="{x:Bind ViewModel.ClearLogsCommand}" Content="Clear" />
|
||||
<AppBarSeparator />
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Ghost.Editor.ViewModels.Pages.EngineEditor;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Ghost.App.View.Pages.EngineEditor;
|
||||
namespace Ghost.Editor.View.Pages.EngineEditor;
|
||||
|
||||
internal sealed partial class ConsolePage : Page
|
||||
{
|
||||
@@ -12,8 +12,8 @@ internal sealed partial class ConsolePage : Page
|
||||
|
||||
public ConsolePage()
|
||||
{
|
||||
ViewModel = GhostApplication.GetService<ConsoleViewModel>();
|
||||
ViewModel = EditorApplication.GetService<ConsoleViewModel>();
|
||||
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Page
|
||||
x:Class="Ghost.App.View.Pages.EngineEditor.HierarchyPage"
|
||||
<internal:NavigationTabPage
|
||||
x:Class="Ghost.Editor.View.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:local="using:Ghost.App.View.Pages.EngineEditor"
|
||||
xmlns:internal="using:Ghost.Editor.Controls.Internal"
|
||||
xmlns:local="using:Ghost.Editor.View.Pages.EngineEditor"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:sg="using:Ghost.Editor.SceneGraph"
|
||||
xmlns:sg="using:Ghost.Editor.Core.SceneGraph"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Page.Resources>
|
||||
<internal:NavigationTabPage.Resources>
|
||||
<DataTemplate x:Key="SceneTemplate" x:DataType="sg:SceneGraphNode">
|
||||
<TreeViewItem
|
||||
AutomationProperties.Name="{x:Bind Name}"
|
||||
@@ -25,19 +26,19 @@
|
||||
|
||||
<DataTemplate x:Key="EntityTemplate" x:DataType="sg:SceneGraphNode">
|
||||
<TreeViewItem AutomationProperties.Name="{x:Bind Name}" ItemsSource="{x:Bind Children}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<StackPanel Margin="10,0" Orientation="Horizontal">
|
||||
<FontIcon FontSize="14" Glyph="" />
|
||||
<TextBlock Margin="10,0" Text="{x:Bind Name}" />
|
||||
<TextBlock Margin="5,0,0,0" Text="{x:Bind Name}" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
</DataTemplate>
|
||||
</Page.Resources>
|
||||
</internal:NavigationTabPage.Resources>
|
||||
|
||||
<Grid Padding="4,6" Background="{ThemeResource LayerFillColorDefaultBrush}">
|
||||
<TreeView ItemsSource="{x:Bind ViewModel.SceneList}">
|
||||
<TreeView ItemsSource="{x:Bind ViewModel.SceneList}" SelectionChanged="TreeView_SelectionChanged">
|
||||
<TreeView.ItemTemplateSelector>
|
||||
<local:HierarchyTemplateSector EntityTemplate="{StaticResource EntityTemplate}" WorldTemplate="{StaticResource SceneTemplate}" />
|
||||
</TreeView.ItemTemplateSelector>
|
||||
</TreeView>
|
||||
</Grid>
|
||||
</Page>
|
||||
</internal:NavigationTabPage>
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
using Ghost.Editor.SceneGraph;
|
||||
using Ghost.Editor.Contracts;
|
||||
using Ghost.Editor.Controls.Internal;
|
||||
using Ghost.Editor.Core.SceneGraph;
|
||||
using Ghost.Editor.Services.Contracts;
|
||||
using Ghost.Editor.ViewModels.Pages.EngineEditor;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
namespace Ghost.Editor.View.Pages.EngineEditor;
|
||||
|
||||
namespace Ghost.App.View.Pages.EngineEditor;
|
||||
/// <summary>
|
||||
/// An empty page that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
internal sealed partial class HierarchyPage : Page
|
||||
internal sealed partial class HierarchyPage : NavigationTabPage
|
||||
{
|
||||
private readonly IInspectorService _inspectorService;
|
||||
|
||||
public HierarchyViewModel ViewModel
|
||||
{
|
||||
get;
|
||||
@@ -19,9 +19,38 @@ internal sealed partial class HierarchyPage : Page
|
||||
|
||||
public HierarchyPage()
|
||||
{
|
||||
ViewModel = GhostApplication.GetService<HierarchyViewModel>();
|
||||
_inspectorService = EditorApplication.GetService<IInspectorService>();
|
||||
ViewModel = EditorApplication.GetService<HierarchyViewModel>();
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
Header = "Hierarchy";
|
||||
IconSource = new FontIconSource
|
||||
{
|
||||
Glyph = "\uE8A4"
|
||||
};
|
||||
}
|
||||
|
||||
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.SelectedInspectable = inspectable;
|
||||
}
|
||||
else
|
||||
{
|
||||
_inspectorService.SelectedInspectable = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
45
Ghost.App/View/Pages/EngineEditor/InspectorPage.xaml
Normal file
45
Ghost.App/View/Pages/EngineEditor/InspectorPage.xaml
Normal file
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<internal:NavigationTabPage
|
||||
x:Class="Ghost.Editor.View.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.Internal"
|
||||
xmlns:local="using:Ghost.Editor.View.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="10,0,10,0">
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||
<ContentPresenter Content="{x:Bind ViewModel.Inspectable.InspectorContent(), Mode=OneWay}" />
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</internal:NavigationTabPage>
|
||||
36
Ghost.App/View/Pages/EngineEditor/InspectorPage.xaml.cs
Normal file
36
Ghost.App/View/Pages/EngineEditor/InspectorPage.xaml.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using Ghost.Editor.Controls.Internal;
|
||||
using Ghost.Editor.ViewModels.Pages.EngineEditor;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Ghost.Editor.View.Pages.EngineEditor;
|
||||
|
||||
internal sealed partial class InspectorPage : NavigationTabPage
|
||||
{
|
||||
public InspectorViewModel ViewModel
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public InspectorPage()
|
||||
{
|
||||
ViewModel = EditorApplication.GetService<InspectorViewModel>();
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
Header = "Inspector";
|
||||
IconSource = new FontIconSource
|
||||
{
|
||||
Glyph = "\uEC7A"
|
||||
};
|
||||
}
|
||||
|
||||
public override void OnNavigatedTo(object? parameter)
|
||||
{
|
||||
ViewModel.OnNavigatedTo(parameter);
|
||||
}
|
||||
|
||||
public override void OnNavigatedFrom()
|
||||
{
|
||||
ViewModel.OnNavigatedFrom();
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Page
|
||||
x:Class="Ghost.App.View.Pages.EngineEditor.ProjectPage"
|
||||
x:Class="Ghost.Editor.View.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.App.View.Pages.EngineEditor"
|
||||
xmlns:local="using:Ghost.Editor.View.Pages.EngineEditor"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:model="using:Ghost.App.Models"
|
||||
xmlns:model="using:Ghost.Editor.Models"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Page.Resources>
|
||||
|
||||
@@ -2,7 +2,7 @@ using Ghost.Editor.ViewModels.Pages.EngineEditor;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
|
||||
namespace Ghost.App.View.Pages.EngineEditor;
|
||||
namespace Ghost.Editor.View.Pages.EngineEditor;
|
||||
|
||||
internal sealed partial class ProjectPage : Page
|
||||
{
|
||||
@@ -13,13 +13,13 @@ internal sealed partial class ProjectPage : Page
|
||||
|
||||
public ProjectPage()
|
||||
{
|
||||
ViewModel = GhostApplication.GetService<ProjectViewModel>();
|
||||
ViewModel = EditorApplication.GetService<ProjectViewModel>();
|
||||
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private async void GridViewItem_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
|
||||
private void GridViewItem_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
|
||||
{
|
||||
await ViewModel.OpenSelected();
|
||||
ViewModel.OpenSelected();
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Page
|
||||
x:Class="Ghost.App.View.Pages.Landing.CreateProjectPage"
|
||||
x:Class="Ghost.Editor.View.Pages.Landing.CreateProjectPage"
|
||||
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:data="using:Ghost.Data.Models"
|
||||
xmlns:editor="using:Ghost.Editor.Controls"
|
||||
xmlns:local="using:Ghost.App.View.Pages.Landing"
|
||||
xmlns:local="using:Ghost.Editor.View.Pages.Landing"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
NavigationCacheMode="Enabled"
|
||||
mc:Ignorable="d">
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
|
||||
namespace Ghost.App.View.Pages.Landing;
|
||||
namespace Ghost.Editor.View.Pages.Landing;
|
||||
|
||||
internal sealed partial class CreateProjectPage : Page
|
||||
{
|
||||
@@ -13,7 +13,7 @@ internal sealed partial class CreateProjectPage : Page
|
||||
|
||||
public CreateProjectPage()
|
||||
{
|
||||
ViewModel = GhostApplication.GetService<CreateProjectViewModel>();
|
||||
ViewModel = EditorApplication.GetService<CreateProjectViewModel>();
|
||||
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Page
|
||||
x:Class="Ghost.App.View.Pages.Landing.OpenProjectPage"
|
||||
x:Class="Ghost.Editor.View.Pages.Landing.OpenProjectPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:converters="using:Ghost.Editor.Utilities.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:data="using:Ghost.Data.Models"
|
||||
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
|
||||
xmlns:local="using:Ghost.App.View.Pages.Landing"
|
||||
xmlns:local="using:Ghost.Editor.View.Pages.Landing"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
NavigationCacheMode="Enabled"
|
||||
mc:Ignorable="d">
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using Ghost.Data.Models;
|
||||
using Ghost.Editor.ViewModels.Pages.Landing;
|
||||
using Ghost.Editor.ViewModels.Pages.Landing;
|
||||
using Ghost.Data.Models;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using Windows.ApplicationModel.DataTransfer;
|
||||
|
||||
namespace Ghost.App.View.Pages.Landing;
|
||||
namespace Ghost.Editor.View.Pages.Landing;
|
||||
|
||||
internal sealed partial class OpenProjectPage : Page
|
||||
{
|
||||
@@ -16,7 +16,7 @@ internal sealed partial class OpenProjectPage : Page
|
||||
|
||||
public OpenProjectPage()
|
||||
{
|
||||
ViewModel = GhostApplication.GetService<OpenProjectViewModel>();
|
||||
ViewModel = EditorApplication.GetService<OpenProjectViewModel>();
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<winex:WindowEx
|
||||
x:Class="Ghost.App.View.Windows.EngineEditorWindow"
|
||||
x:Class="Ghost.Editor.View.Windows.EngineEditorWindow"
|
||||
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:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:ee="using:Ghost.App.View.Pages.EngineEditor"
|
||||
xmlns:ee="using:Ghost.Editor.View.Pages.EngineEditor"
|
||||
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
|
||||
xmlns:local="using:Ghost.App.View.Windows"
|
||||
xmlns:internal="using:Ghost.Editor.Controls.Internal"
|
||||
xmlns:local="using:Ghost.Editor.View.Windows"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:winex="using:WinUIEx"
|
||||
Activated="WindowEx_Activated"
|
||||
@@ -86,23 +87,18 @@
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TabView
|
||||
<internal:NavigationTabView
|
||||
Grid.Column="0"
|
||||
Width="350"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
<TabView.TabItems>
|
||||
<TabViewItem Header="Hierarchy">
|
||||
<TabViewItem.IconSource>
|
||||
<FontIconSource Glyph="" />
|
||||
</TabViewItem.IconSource>
|
||||
<ee:HierarchyPage />
|
||||
</TabViewItem>
|
||||
</TabView.TabItems>
|
||||
</TabView>
|
||||
<internal:NavigationTabView.TabItems>
|
||||
<ee:HierarchyPage />
|
||||
</internal:NavigationTabView.TabItems>
|
||||
</internal:NavigationTabView>
|
||||
|
||||
<TabView Grid.Column="1">
|
||||
<TabView.TabItems>
|
||||
<internal:NavigationTabView Grid.Column="1">
|
||||
<internal:NavigationTabView.TabItems>
|
||||
<TabViewItem Header="Scene">
|
||||
<TabViewItem.IconSource>
|
||||
<FontIconSource Glyph="" />
|
||||
@@ -112,17 +108,22 @@
|
||||
Source="C:\Users\Misaki\OneDrive\Pictures\Screenshots\Screenshot 2024-07-20 021657.png"
|
||||
Stretch="UniformToFill" />
|
||||
</TabViewItem>
|
||||
</TabView.TabItems>
|
||||
</TabView>
|
||||
</internal:NavigationTabView.TabItems>
|
||||
</internal:NavigationTabView>
|
||||
|
||||
<Grid
|
||||
<internal:NavigationTabView
|
||||
Grid.Column="2"
|
||||
Width="350"
|
||||
Background="Bisque" />
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
<internal:NavigationTabView.TabItems>
|
||||
<ee:InspectorPage />
|
||||
</internal:NavigationTabView.TabItems>
|
||||
</internal:NavigationTabView>
|
||||
</Grid>
|
||||
|
||||
<TabView Grid.Row="1" Height="350">
|
||||
<TabView.TabItems>
|
||||
<internal:NavigationTabView Grid.Row="1" Height="350">
|
||||
<internal:NavigationTabView.TabItems>
|
||||
<TabViewItem Header="Project">
|
||||
<TabViewItem.IconSource>
|
||||
<FontIconSource Glyph="" />
|
||||
@@ -135,8 +136,8 @@
|
||||
</TabViewItem.IconSource>
|
||||
<ee:ConsolePage />
|
||||
</TabViewItem>
|
||||
</TabView.TabItems>
|
||||
</TabView>
|
||||
</internal:NavigationTabView.TabItems>
|
||||
</internal:NavigationTabView>
|
||||
</Grid>
|
||||
|
||||
<!-- Status Bar -->
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using Ghost.App.Services;
|
||||
using Ghost.Data.Resources;
|
||||
using Ghost.Data.Resources;
|
||||
using Ghost.Editor.Services;
|
||||
using Ghost.Editor.Services.Contracts;
|
||||
using Ghost.Editor.ViewModels.Windows;
|
||||
using Ghost.Engine.Resources;
|
||||
@@ -9,7 +9,7 @@ using WinUIEx;
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
|
||||
namespace Ghost.App.View.Windows;
|
||||
namespace Ghost.Editor.View.Windows;
|
||||
/// <summary>
|
||||
/// An empty window that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
@@ -27,10 +27,10 @@ internal sealed partial class EngineEditorWindow : WindowEx
|
||||
|
||||
public EngineEditorWindow()
|
||||
{
|
||||
ViewModel = GhostApplication.GetService<EngineEditorViewModel>();
|
||||
ViewModel = EditorApplication.GetService<EngineEditorViewModel>();
|
||||
|
||||
_notificationService = (NotificationService)GhostApplication.GetService<INotificationService>();
|
||||
_progressService = (ProgressService)GhostApplication.GetService<IProgressService>();
|
||||
_notificationService = (NotificationService)EditorApplication.GetService<INotificationService>();
|
||||
_progressService = (ProgressService)EditorApplication.GetService<IProgressService>();
|
||||
|
||||
AppWindow.SetIcon(AssetsPath.s_appIconPath);
|
||||
Title = EngineData.ENGINE_NAME;
|
||||
@@ -46,7 +46,7 @@ internal sealed partial class EngineEditorWindow : WindowEx
|
||||
Bindings.Update();
|
||||
|
||||
_editorScope?.Dispose();
|
||||
_editorScope = GhostApplication.CreateScope();
|
||||
_editorScope = EditorApplication.CreateScope();
|
||||
|
||||
_notificationService.SetReference(InfoBar, NotificationQueue);
|
||||
_progressService.SetReference(ProgressBarContainer);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<winex:WindowEx
|
||||
x:Class="Ghost.App.View.Windows.LandingWindow"
|
||||
x:Class="Ghost.Editor.View.Windows.LandingWindow"
|
||||
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:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
|
||||
xmlns:local="using:Ghost.App.View.Windows"
|
||||
xmlns:local="using:Ghost.Editor.View.Windows"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:winex="using:WinUIEx"
|
||||
Activated="WindowEx_Activated"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Ghost.App.Services;
|
||||
using Ghost.App.View.Pages.Landing;
|
||||
using Ghost.Editor.View.Pages.Landing;
|
||||
using Ghost.Data.Resources;
|
||||
using Ghost.Editor.Services;
|
||||
using Ghost.Editor.Services.Contracts;
|
||||
using Ghost.Engine.Resources;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
@@ -8,7 +8,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Media.Animation;
|
||||
using WinUIEx;
|
||||
|
||||
namespace Ghost.App.View.Windows;
|
||||
namespace Ghost.Editor.View.Windows;
|
||||
|
||||
internal sealed partial class LandingWindow : WindowEx
|
||||
{
|
||||
@@ -20,7 +20,7 @@ internal sealed partial class LandingWindow : WindowEx
|
||||
|
||||
public LandingWindow()
|
||||
{
|
||||
_notificationService = (NotificationService)GhostApplication.GetService<INotificationService>();
|
||||
_notificationService = (NotificationService)EditorApplication.GetService<INotificationService>();
|
||||
|
||||
AppWindow.SetIcon(AssetsPath.s_appIconPath);
|
||||
Title = EngineData.ENGINE_NAME;
|
||||
@@ -36,7 +36,7 @@ internal sealed partial class LandingWindow : WindowEx
|
||||
private void WindowEx_Activated(object sender, Microsoft.UI.Xaml.WindowActivatedEventArgs args)
|
||||
{
|
||||
_landingScope?.Dispose();
|
||||
_landingScope = GhostApplication.CreateScope();
|
||||
_landingScope = EditorApplication.CreateScope();
|
||||
_notificationService.SetReference(InfoBar, NotificationQueue);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Ghost.Editor.SceneGraph;
|
||||
using System;
|
||||
using Ghost.Editor.Contracts;
|
||||
using Ghost.Editor.Core.SceneGraph;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Ghost.Editor.ViewModels.Pages.EngineEditor;
|
||||
|
||||
internal partial class HierarchyViewModel : ObservableObject, IDisposable
|
||||
internal partial class HierarchyViewModel : ObservableObject, INavigationAware
|
||||
{
|
||||
[ObservableProperty]
|
||||
public partial ObservableCollection<WorldNode> SceneList
|
||||
@@ -14,12 +14,6 @@ internal partial class HierarchyViewModel : ObservableObject, IDisposable
|
||||
private set;
|
||||
} = new(EditorWorldManager.LoadedWorlds);
|
||||
|
||||
public HierarchyViewModel()
|
||||
{
|
||||
EditorWorldManager.OnWorldLoaded += OnWorldLoaded;
|
||||
EditorWorldManager.OnWorldUnloaded += OnWorldUnloaded;
|
||||
}
|
||||
|
||||
private void OnWorldLoaded(WorldNode node)
|
||||
{
|
||||
SceneList.Add(node);
|
||||
@@ -30,7 +24,13 @@ internal partial class HierarchyViewModel : ObservableObject, IDisposable
|
||||
SceneList.Remove(node);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
public void OnNavigatedTo(object? parameter)
|
||||
{
|
||||
EditorWorldManager.OnWorldLoaded += OnWorldLoaded;
|
||||
EditorWorldManager.OnWorldUnloaded += OnWorldUnloaded;
|
||||
}
|
||||
|
||||
public void OnNavigatedFrom()
|
||||
{
|
||||
EditorWorldManager.OnWorldLoaded -= OnWorldLoaded;
|
||||
EditorWorldManager.OnWorldUnloaded -= OnWorldUnloaded;
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Ghost.Editor.Contracts;
|
||||
using Ghost.Editor.Services.Contracts;
|
||||
|
||||
namespace Ghost.Editor.ViewModels.Pages.EngineEditor;
|
||||
|
||||
internal partial class InspectorViewModel(IInspectorService inspectorService) : ObservableObject, INavigationAware
|
||||
{
|
||||
[ObservableProperty]
|
||||
public partial IInspectable? Inspectable
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public void OnNavigatedTo(object? parameter)
|
||||
{
|
||||
inspectorService.OnSelectionChanged += OnSelectionChanged;
|
||||
Inspectable = inspectorService.SelectedInspectable;
|
||||
}
|
||||
|
||||
public void OnNavigatedFrom()
|
||||
{
|
||||
inspectorService.OnSelectionChanged -= OnSelectionChanged;
|
||||
Inspectable = null;
|
||||
}
|
||||
|
||||
private void OnSelectionChanged()
|
||||
{
|
||||
Inspectable = inspectorService.SelectedInspectable;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,8 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Ghost.App;
|
||||
using Ghost.App.Models;
|
||||
using Ghost.Data.Services;
|
||||
using Ghost.Editor.AssetHandle;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ghost.Editor.Core.AssetHandle;
|
||||
using Ghost.Editor.Models;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ghost.Editor.ViewModels.Pages.EngineEditor;
|
||||
|
||||
@@ -96,7 +91,7 @@ internal partial class ProjectViewModel : ObservableObject
|
||||
|
||||
private void NavigateToDirectory(string? path)
|
||||
{
|
||||
GhostApplication.Window?.DispatcherQueue.TryEnqueue(async () =>
|
||||
EditorApplication.Window?.DispatcherQueue.TryEnqueue(async () =>
|
||||
{
|
||||
DirectoryAssets.Clear();
|
||||
|
||||
@@ -121,7 +116,7 @@ internal partial class ProjectViewModel : ObservableObject
|
||||
});
|
||||
}
|
||||
|
||||
public async Task OpenSelected()
|
||||
public void OpenSelected()
|
||||
{
|
||||
if (SelectedAsset == null)
|
||||
{
|
||||
@@ -134,7 +129,7 @@ internal partial class ProjectViewModel : ObservableObject
|
||||
}
|
||||
else
|
||||
{
|
||||
await AssetDatabase.OpenAsset(SelectedAsset.FullName);
|
||||
AssetDatabase.OpenAsset(SelectedAsset.FullName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Ghost.App.Contracts;
|
||||
using Ghost.App.Infrastructures.AppState;
|
||||
using Ghost.App.Services;
|
||||
using Ghost.App.Utilities;
|
||||
using Ghost.Data.Models;
|
||||
using Ghost.Data.Services;
|
||||
using Ghost.Editor.Contracts;
|
||||
using Ghost.Editor.Core.AppState;
|
||||
using Ghost.Editor.Models;
|
||||
using Ghost.Editor.Services;
|
||||
using Ghost.Editor.Utilities;
|
||||
using Ghost.Engine.Resources;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Ghost.App.Contracts;
|
||||
using Ghost.App.Infrastructures.AppState;
|
||||
using Ghost.Data.Models;
|
||||
using Ghost.Data.Services;
|
||||
using Ghost.Editor.Contracts;
|
||||
using Ghost.Editor.Core.AppState;
|
||||
using Ghost.Editor.Models;
|
||||
using Ghost.Editor.Services.Contracts;
|
||||
using Microsoft.UI.Xaml;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.ApplicationModel.DataTransfer;
|
||||
using Windows.Storage;
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("Ghost.App")]
|
||||
[assembly: InternalsVisibleTo("Ghost.Editor")]
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Ghost.Editor.Models;
|
||||
namespace Ghost.Editor.AssetHandle;
|
||||
|
||||
public abstract class Asset
|
||||
{
|
||||
@@ -3,5 +3,6 @@
|
||||
namespace Ghost.Editor.Contracts;
|
||||
internal interface IInspectable
|
||||
{
|
||||
public UIElement OnInspectorDraw();
|
||||
public UIElement HeaderContent();
|
||||
public UIElement InspectorContent();
|
||||
}
|
||||
@@ -167,7 +167,12 @@ public partial class WorldNode : SceneGraphNode, IEquatable<WorldNode>
|
||||
|
||||
public partial class WorldNode : IInspectable
|
||||
{
|
||||
public UIElement OnInspectorDraw()
|
||||
public UIElement HeaderContent()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public UIElement InspectorContent()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
@@ -9,4 +9,6 @@ internal interface IInspectorService
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public event Action? OnSelectionChanged;
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("Ghost.App")]
|
||||
[assembly: InternalsVisibleTo("Ghost.Editor")]
|
||||
|
||||
@@ -4,7 +4,6 @@ global using WorldID = System.UInt16;
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("Ghost.App")]
|
||||
[assembly: InternalsVisibleTo("Ghost.Engine")]
|
||||
[assembly: InternalsVisibleTo("Ghost.Editor")]
|
||||
[assembly: InternalsVisibleTo("Ghost.UnitTest")]
|
||||
@@ -49,7 +49,7 @@
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.9.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ghost.Editor\Ghost.Editor.csproj" />
|
||||
<ProjectReference Include="..\Ghost.App\Ghost.Editor.csproj" />
|
||||
<ProjectReference Include="..\Ghost.Engine\Ghost.Engine.csproj" />
|
||||
<ProjectReference Include="..\Ghost.Entities\Ghost.Entities.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using Ghost.Entities;
|
||||
using Ghost.Entities.Components;
|
||||
using Ghost.Entities.Systems;
|
||||
using Ghost.Test.TestFramework;
|
||||
using Ghost.UnitTest.TestFramework;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Ghost.Test;
|
||||
namespace Ghost.UnitTest;
|
||||
|
||||
public partial class EntityTest : ITest
|
||||
{
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using Ghost.Editor.SceneGraph;
|
||||
using Ghost.Editor.Core.SceneGraph;
|
||||
using Ghost.Entities;
|
||||
using Ghost.Test.TestFramework;
|
||||
using Ghost.UnitTest.TestFramework;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Ghost.Test;
|
||||
namespace Ghost.UnitTest.Test;
|
||||
|
||||
internal class SerializationTest : ITest
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Ghost.Test.TestFramework;
|
||||
namespace Ghost.UnitTest.TestFramework;
|
||||
|
||||
internal interface ITest
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Ghost.Test.TestFramework;
|
||||
namespace Ghost.UnitTest.TestFramework;
|
||||
|
||||
internal class TestRunner
|
||||
{
|
||||
|
||||
@@ -1,21 +1,5 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using Microsoft.UI.Xaml.Shapes;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Windows.ApplicationModel;
|
||||
using Windows.ApplicationModel.Activation;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
@@ -41,7 +25,7 @@ public partial class UnitTestApp : Application
|
||||
/// Invoked when the application is launched.
|
||||
/// </summary>
|
||||
/// <param name="args">Details about the launch request and process.</param>
|
||||
protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
|
||||
protected override void OnLaunched(LaunchActivatedEventArgs args)
|
||||
{
|
||||
Microsoft.VisualStudio.TestPlatform.TestExecutor.UnitTestClient.CreateDefaultUI();
|
||||
|
||||
|
||||
@@ -1,17 +1,4 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Ghost.UnitTest;
|
||||
[TestClass]
|
||||
|
||||
@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.14.35906.104
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ghost.App", "Ghost.App\Ghost.App.csproj", "{15AFE3A1-0CAF-4B36-8835-121C4D683BBF}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ghost.Editor", "Ghost.App\Ghost.Editor.csproj", "{15AFE3A1-0CAF-4B36-8835-121C4D683BBF}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ghost.Engine", "Ghost.Engine\Ghost.Engine.csproj", "{1ED62E09-8F36-4671-896B-16C1C1530202}"
|
||||
EndProject
|
||||
@@ -15,8 +15,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ghost.Graphics", "Ghost.Gra
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ghost.Generator", "Ghost.Generator\Ghost.Generator.csproj", "{996ABECC-1C5A-4F07-B8AC-D063F91962CB}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ghost.Editor", "Ghost.Editor\Ghost.Editor.csproj", "{CC6E1FCB-A80E-4F6C-B519-C8CADB6D5650}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ghost.UnitTest", "Ghost.UnitTest\Ghost.UnitTest.csproj", "{4179873E-8174-4D17-9584-8C223BA71366}"
|
||||
EndProject
|
||||
Global
|
||||
@@ -107,18 +105,6 @@ Global
|
||||
{996ABECC-1C5A-4F07-B8AC-D063F91962CB}.Release|x64.Build.0 = Release|Any CPU
|
||||
{996ABECC-1C5A-4F07-B8AC-D063F91962CB}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{996ABECC-1C5A-4F07-B8AC-D063F91962CB}.Release|x86.Build.0 = Release|Any CPU
|
||||
{CC6E1FCB-A80E-4F6C-B519-C8CADB6D5650}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{CC6E1FCB-A80E-4F6C-B519-C8CADB6D5650}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{CC6E1FCB-A80E-4F6C-B519-C8CADB6D5650}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{CC6E1FCB-A80E-4F6C-B519-C8CADB6D5650}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{CC6E1FCB-A80E-4F6C-B519-C8CADB6D5650}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{CC6E1FCB-A80E-4F6C-B519-C8CADB6D5650}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{CC6E1FCB-A80E-4F6C-B519-C8CADB6D5650}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{CC6E1FCB-A80E-4F6C-B519-C8CADB6D5650}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{CC6E1FCB-A80E-4F6C-B519-C8CADB6D5650}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{CC6E1FCB-A80E-4F6C-B519-C8CADB6D5650}.Release|x64.Build.0 = Release|Any CPU
|
||||
{CC6E1FCB-A80E-4F6C-B519-C8CADB6D5650}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{CC6E1FCB-A80E-4F6C-B519-C8CADB6D5650}.Release|x86.Build.0 = Release|Any CPU
|
||||
{4179873E-8174-4D17-9584-8C223BA71366}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{4179873E-8174-4D17-9584-8C223BA71366}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{4179873E-8174-4D17-9584-8C223BA71366}.Debug|ARM64.Deploy.0 = Debug|ARM64
|
||||
|
||||
13
Test/Class1.cs
Normal file
13
Test/Class1.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
|
||||
namespace Test;
|
||||
public partial class Class1
|
||||
{
|
||||
}
|
||||
17
Test/Test.csproj
Normal file
17
Test/Test.csproj
Normal file
@@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
|
||||
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
|
||||
<RootNamespace>Test</RootNamespace>
|
||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
|
||||
<UseWinUI>true</UseWinUI>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.4188" />
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.7.250606001" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ghost.Editor\Ghost.Editor.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user