diff --git a/src/ImeSense.ShaderPlayground/App.axaml b/src/ImeSense.ShaderPlayground/App.axaml index 7890a52..0284278 100644 --- a/src/ImeSense.ShaderPlayground/App.axaml +++ b/src/ImeSense.ShaderPlayground/App.axaml @@ -10,6 +10,7 @@ + diff --git a/src/ImeSense.ShaderPlayground/App.axaml.cs b/src/ImeSense.ShaderPlayground/App.axaml.cs index 825d742..d3ae78f 100644 --- a/src/ImeSense.ShaderPlayground/App.axaml.cs +++ b/src/ImeSense.ShaderPlayground/App.axaml.cs @@ -34,10 +34,19 @@ public override void Initialize() => public override void OnFrameworkInitializationCompleted() { if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { - desktop.MainWindow = _serviceProvider - .GetRequiredService(); - desktop.MainWindow.DataContext = _serviceProvider - .GetRequiredService(); + var mainViewModel = _serviceProvider.GetRequiredService(); + + var mainWindow = new MainWindow { + DataContext = mainViewModel, + }; + mainWindow.Closing += (_, _) => { + mainViewModel.CloseLayout(); + }; + + desktop.MainWindow = mainWindow; + desktop.Exit += (_, _) => { + mainViewModel.CloseLayout(); + }; } base.OnFrameworkInitializationCompleted(); diff --git a/src/ImeSense.ShaderPlayground/ImeSense.ShaderPlayground.csproj b/src/ImeSense.ShaderPlayground/ImeSense.ShaderPlayground.csproj index a620fb7..a757a4e 100644 --- a/src/ImeSense.ShaderPlayground/ImeSense.ShaderPlayground.csproj +++ b/src/ImeSense.ShaderPlayground/ImeSense.ShaderPlayground.csproj @@ -32,6 +32,8 @@ + + diff --git a/src/ImeSense.ShaderPlayground/ViewModels/AppFactory.cs b/src/ImeSense.ShaderPlayground/ViewModels/AppFactory.cs new file mode 100644 index 0000000..bff6e79 --- /dev/null +++ b/src/ImeSense.ShaderPlayground/ViewModels/AppFactory.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; + +using Dock.Avalonia.Controls; +using Dock.Model.Controls; +using Dock.Model.Core; +using Dock.Model.ReactiveUI; +using Dock.Model.ReactiveUI.Controls; + +using ImeSense.ShaderPlayground.ViewModels.Docks; +using ImeSense.ShaderPlayground.ViewModels.Documents; +using ImeSense.ShaderPlayground.ViewModels.Toolbars; + +namespace ImeSense.ShaderPlayground.ViewModels; + +public class AppFactory : Factory { + private IRootDock? _rootDock; + + private IDocumentDock? _shaderDock; + + private ITool? _viewportToolbar; + private ITool? _logToolbar; + + public override IDocumentDock CreateDocumentDock() { + return new ShaderDocumentDock(); + } + + public override IRootDock CreateLayout() { + var untitledShaderViewModel = new ShaderViewModel { + Title = "Untitled", + }; + + var viewportViewModel = new ViewportViewModel { + Id = "Viewport", + Title = "Viewport", + }; + var logViewModel = new LogViewModel { + Id = "Log", + Title = "Log", + }; + + // Tabs + var documentDock = new ShaderDocumentDock() { + Id = "Shaders", + Title = "Shaders", + IsCollapsable = false, + Proportion = double.NaN, + ActiveDockable = untitledShaderViewModel, + VisibleDockables = CreateList(untitledShaderViewModel), + CanCreateDocument = false, + }; + + var tools = new ProportionalDock { + Proportion = 0.5, + Orientation = Orientation.Vertical, + VisibleDockables = CreateList( + new ToolDock { + ActiveDockable = viewportViewModel, + VisibleDockables = CreateList(viewportViewModel), + Alignment = Alignment.Right, + GripMode = GripMode.Visible, + }, + new ProportionalDockSplitter(), + new ToolDock { + ActiveDockable = logViewModel, + VisibleDockables = CreateList(logViewModel), + Alignment = Alignment.Right, + GripMode = GripMode.Visible, + } + ), + }; + + var windowLayout = CreateRootDock(); + windowLayout.Title = "Default"; + windowLayout.IsCollapsable = false; + + // Content + var windowLayoutContent = new ProportionalDock { + Orientation = Orientation.Horizontal, + IsCollapsable = false, + VisibleDockables = CreateList( + documentDock, + new ProportionalDockSplitter(), + tools + ), + }; + windowLayout.VisibleDockables = CreateList(windowLayoutContent); + windowLayout.ActiveDockable = windowLayoutContent; + + // Root + var rootDock = CreateRootDock(); + rootDock.IsCollapsable = false; + rootDock.VisibleDockables = CreateList(windowLayout); + rootDock.ActiveDockable = windowLayout; + rootDock.DefaultDockable = windowLayout; + + _shaderDock = documentDock; + _rootDock = rootDock; + _viewportToolbar = viewportViewModel; + _logToolbar = logViewModel; + + return rootDock; + } + + public override void InitLayout(IDockable layout) { + ContextLocator = new Dictionary> { + ["Viewport"] = () => layout, + ["Log"] = () => layout + }; + + DockableLocator = new Dictionary> { + ["Root"] = () => _rootDock, + ["Files"] = () => _shaderDock, + ["Viewport"] = () => _viewportToolbar, + ["Log"] = () => _logToolbar, + }; + + HostWindowLocator = new Dictionary> { + [nameof(IDockWindow)] = () => new HostWindow(), + }; + + base.InitLayout(layout); + } +} diff --git a/src/ImeSense.ShaderPlayground/ViewModels/Docks/ShaderDocumentDock.cs b/src/ImeSense.ShaderPlayground/ViewModels/Docks/ShaderDocumentDock.cs new file mode 100644 index 0000000..68dc31f --- /dev/null +++ b/src/ImeSense.ShaderPlayground/ViewModels/Docks/ShaderDocumentDock.cs @@ -0,0 +1,26 @@ +using Dock.Model.ReactiveUI.Controls; + +using ImeSense.ShaderPlayground.ViewModels.Documents; + +using ReactiveUI; + +namespace ImeSense.ShaderPlayground.ViewModels.Docks; + +public class ShaderDocumentDock : DocumentDock { + private void CreateNewShader() { + if (!CanCreateDocument) { + return; + } + + var shader = new ShaderViewModel { + Title = "Shader", + }; + Factory?.AddDockable(this, shader); + Factory?.SetActiveDockable(shader); + Factory?.SetFocusedDockable(this, shader); + } + + public ShaderDocumentDock() { + CreateDocument = ReactiveCommand.Create(CreateNewShader); + } +} diff --git a/src/ImeSense.ShaderPlayground/ViewModels/Documents/ShaderViewModel.cs b/src/ImeSense.ShaderPlayground/ViewModels/Documents/ShaderViewModel.cs new file mode 100644 index 0000000..55e48f7 --- /dev/null +++ b/src/ImeSense.ShaderPlayground/ViewModels/Documents/ShaderViewModel.cs @@ -0,0 +1,6 @@ +using Dock.Model.ReactiveUI.Controls; + +namespace ImeSense.ShaderPlayground.ViewModels.Documents; + +public class ShaderViewModel : Document { +} diff --git a/src/ImeSense.ShaderPlayground/ViewModels/MainViewModel.cs b/src/ImeSense.ShaderPlayground/ViewModels/MainViewModel.cs index 8420340..274cda8 100644 --- a/src/ImeSense.ShaderPlayground/ViewModels/MainViewModel.cs +++ b/src/ImeSense.ShaderPlayground/ViewModels/MainViewModel.cs @@ -1,4 +1,5 @@ -using System.Windows.Input; +using Dock.Model.Controls; +using Dock.Model.Core; using ReactiveUI; @@ -7,6 +8,14 @@ namespace ImeSense.ShaderPlayground.ViewModels; public class MainViewModel : ReactiveObject { private readonly MenuViewModel _menuViewModel; + private readonly IFactory? _factory; + private IRootDock? _layout; + + public IRootDock? Layout { + get => _layout; + set => this.RaiseAndSetIfChanged(ref _layout, value); + } + public MainViewModel(MenuViewModel menuViewModel) { _menuViewModel = menuViewModel; @@ -16,27 +25,24 @@ public MainViewModel(MenuViewModel menuViewModel) { MenuContext = _menuViewModel; - Resolution = "800x600"; - Frame = "60"; + _factory = new AppFactory(); - PlayCommand = ReactiveCommand.Create(() => { - }); - StopCommand = ReactiveCommand.Create(() => { - }); - SettingsCommand = ReactiveCommand.Create(() => { - }); + Layout = _factory?.CreateLayout(); + if (Layout is { }) { + _factory?.InitLayout(Layout); + } } -#if DEBUG public MainViewModel() { _menuViewModel = null!; MenuContext = null!; - PlayCommand = null!; - StopCommand = null!; - SettingsCommand = null!; } -#endif + + public void CloseLayout() { + Layout?.Close.Execute(null); + Layout = null; + } private int _windowHeight; @@ -74,22 +80,4 @@ public ReactiveObject MenuContext { get => _menuContext; init => this.RaiseAndSetIfChanged(ref _menuContext, value); } - - private string _resolution = string.Empty; - - public string Resolution { - get => _resolution; - set => this.RaiseAndSetIfChanged(ref _resolution, value); - } - - private string _frame = string.Empty; - - public string Frame { - get => _frame; - set => this.RaiseAndSetIfChanged(ref _frame, value); - } - - public ICommand PlayCommand { get; private set; } - public ICommand StopCommand { get; private set; } - public ICommand SettingsCommand { get; private set; } } diff --git a/src/ImeSense.ShaderPlayground/ViewModels/Toolbars/LogViewModel.cs b/src/ImeSense.ShaderPlayground/ViewModels/Toolbars/LogViewModel.cs new file mode 100644 index 0000000..e92de95 --- /dev/null +++ b/src/ImeSense.ShaderPlayground/ViewModels/Toolbars/LogViewModel.cs @@ -0,0 +1,6 @@ +using Dock.Model.ReactiveUI.Controls; + +namespace ImeSense.ShaderPlayground.ViewModels.Toolbars; + +public class LogViewModel : Tool { +} diff --git a/src/ImeSense.ShaderPlayground/ViewModels/Toolbars/ViewportViewModel.cs b/src/ImeSense.ShaderPlayground/ViewModels/Toolbars/ViewportViewModel.cs new file mode 100644 index 0000000..666e75f --- /dev/null +++ b/src/ImeSense.ShaderPlayground/ViewModels/Toolbars/ViewportViewModel.cs @@ -0,0 +1,39 @@ +using System.Windows.Input; + +using Dock.Model.ReactiveUI.Controls; + +using ReactiveUI; + +namespace ImeSense.ShaderPlayground.ViewModels.Toolbars; + +public class ViewportViewModel : Tool { + public ViewportViewModel() { + Resolution = "800x600"; + Frame = "60"; + + PlayCommand = ReactiveCommand.Create(() => { + }); + StopCommand = ReactiveCommand.Create(() => { + }); + SettingsCommand = ReactiveCommand.Create(() => { + }); + } + + private string _resolution = string.Empty; + + public string Resolution { + get => _resolution; + set => this.RaiseAndSetIfChanged(ref _resolution, value); + } + + private string _frame = string.Empty; + + public string Frame { + get => _frame; + set => this.RaiseAndSetIfChanged(ref _frame, value); + } + + public ICommand PlayCommand { get; private set; } + public ICommand StopCommand { get; private set; } + public ICommand SettingsCommand { get; private set; } +} diff --git a/src/ImeSense.ShaderPlayground/Views/Documents/ShaderView.axaml b/src/ImeSense.ShaderPlayground/Views/Documents/ShaderView.axaml new file mode 100644 index 0000000..4c83d7d --- /dev/null +++ b/src/ImeSense.ShaderPlayground/Views/Documents/ShaderView.axaml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + +