Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Quantum.Editor.Avalonia/App.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
x:Class="Quantum.Editor.Avalonia.App"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dockTheme="using:Dock.Avalonia.Themes.Fluent"
RequestedThemeVariant="Dark">
<Application.Styles>
<FluentTheme />
<dockTheme:DockFluentTheme DensityStyle="Compact" />
</Application.Styles>
</Application>
59 changes: 16 additions & 43 deletions Quantum.Editor.Avalonia/MainWindow.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
x:Class="Quantum.Editor.Avalonia.MainWindow"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:Quantum.Editor.Avalonia.Controls"
xmlns:dock="using:Dock.Avalonia.Controls"
Title="Quantum CoasterWorks Editor"
Width="1480"
Height="920"
Expand Down Expand Up @@ -42,7 +42,7 @@
</Style>
</Window.Styles>

<Grid x:Name="WorkbenchGrid" RowDefinitions="Auto,48,*,5,300,28">
<Grid x:Name="WorkbenchGrid" RowDefinitions="Auto,48,*,28">
<Border
x:Name="MenuBarRegion"
Grid.Row="0"
Expand All @@ -67,6 +67,14 @@
<MenuItem Header="_Fit Track F" Click="OnFitViewportClick" />
<MenuItem Header="Toggle Transported _Frames" Click="OnMenuShowFramesClick" />
<MenuItem Header="Math _Plots" Click="OnShowEngineeringPlotsClick" />
<Separator />
<MenuItem Header="_Panes">
<MenuItem Header="_Route" Tag="route" Click="OnShowPaneClick" />
<MenuItem Header="_Viewport" Tag="viewport" Click="OnShowPaneClick" />
<MenuItem Header="_Inspector" Tag="inspector" Click="OnShowPaneClick" />
<MenuItem Header="_Math Plots" Tag="math-plots" Click="OnShowPaneClick" />
<MenuItem Header="_Diagnostics" Tag="diagnostics" Click="OnShowPaneClick" />
</MenuItem>
</MenuItem>
</Menu>
</Border>
Expand Down Expand Up @@ -106,50 +114,15 @@
</Grid>
</Border>

<Grid x:Name="ContentPaneGrid" Grid.Row="2" ColumnDefinitions="320,5,*,5,340">
<controls:RoutePaneControl
x:Name="RoutePane"
Grid.Column="0"
NodeSelected="OnGraphNodeSelected"
SectionPointerChanged="OnSectionPointerChanged" />

<GridSplitter x:Name="RouteSplitter" Grid.Column="1" ResizeDirection="Columns" Background="#2B3948" />

<controls:ViewportPaneControl
x:Name="ViewportPane"
Grid.Column="2"
SectionPointerChanged="OnSectionPointerChanged"
SampleSelected="OnViewportSampleSelected" />

<GridSplitter x:Name="InspectorSplitter" Grid.Column="3" ResizeDirection="Columns" Background="#2B3948" />

<controls:InspectorPaneControl x:Name="InspectorPane" Grid.Column="4" />
</Grid>

<GridSplitter x:Name="BottomPanelSplitter" Grid.Row="3" ResizeDirection="Rows" Background="#2B3948" />

<Border
x:Name="BottomPanelRegion"
Grid.Row="4"
Classes="panel"
BorderThickness="0,1,0,0">
<TabControl x:Name="BottomWorkspaceTabs" SelectedIndex="0">
<TabItem x:Name="MathPlotsTab" Header="MATH PLOTS">
<controls:MathPlotsPaneControl
x:Name="MathPlotsPane"
SectionPointerChanged="OnSectionPointerChanged"
StationChanged="OnEngineeringPlotStationChanged"
StationSelected="OnEngineeringPlotStationSelected" />
</TabItem>
<TabItem x:Name="DiagnosticsTab" Header="DIAGNOSTICS">
<controls:DiagnosticsPaneControl x:Name="DiagnosticsPane" />
</TabItem>
</TabControl>
</Border>
<dock:DockControl
x:Name="DockHost"
Grid.Row="2"
InitializeFactory="False"
InitializeLayout="False" />

<Border
x:Name="StatusBarRegion"
Grid.Row="5"
Grid.Row="3"
Background="#0B1016"
BorderBrush="#2B3948"
BorderThickness="0,1,0,0"
Expand Down
98 changes: 65 additions & 33 deletions Quantum.Editor.Avalonia/MainWindow.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Quantum.Editor.Avalonia.Models;
using Quantum.Editor.Avalonia.Services;
using Quantum.Editor.Avalonia.Services.Commands;
using Quantum.Editor.Avalonia.Services.Docking;
using Quantum.Editor.Avalonia.Services.Documents;
using Quantum.Editor.Avalonia.Services.Workspaces;

Expand All @@ -23,6 +24,12 @@ public partial class MainWindow : Window

private readonly EditorWorkspace workspace;
private readonly WorkspaceProfileManager workspaceProfiles;
private readonly EditorDockingAdapter docking;
private readonly RoutePaneControl RoutePane;
private readonly ViewportPaneControl ViewportPane;
private readonly InspectorPaneControl InspectorPane;
private readonly MathPlotsPaneControl MathPlotsPane;
private readonly DiagnosticsPaneControl DiagnosticsPane;

public MainWindow()
: this(CreateWorkspace(), new WorkspaceProfileManager())
Expand All @@ -43,6 +50,27 @@ public MainWindow(
throw new ArgumentNullException(nameof(workspaceProfiles));
InitializeComponent();

RoutePane = new RoutePaneControl();
ViewportPane = new ViewportPaneControl();
InspectorPane = new InspectorPaneControl();
MathPlotsPane = new MathPlotsPaneControl();
DiagnosticsPane = new DiagnosticsPaneControl();
WirePaneInteractions();

DockPaneRegistry paneRegistry = DockPaneRegistry.CreateDefaultTrack();
docking = new EditorDockingAdapter(
paneRegistry,
new Dictionary<string, object>(StringComparer.Ordinal)
{
[WorkspacePaneIds.Route] = RoutePane,
[WorkspacePaneIds.Viewport] = ViewportPane,
[WorkspacePaneIds.Inspector] = InspectorPane,
[WorkspacePaneIds.MathPlots] = MathPlotsPane,
[WorkspacePaneIds.Diagnostics] = DiagnosticsPane
});
DockHost.Factory = docking.Factory;
DockHost.Layout = docking.Layout;

this.workspace.WorkspaceChanged += OnWorkspaceChanged;
this.workspace.StationCursorChanged += OnStationCursorChanged;
this.workspace.SectionHighlightChanged += OnSectionHighlightChanged;
Expand All @@ -57,13 +85,26 @@ public MainWindow(

public WorkspaceProfileManager WorkspaceProfiles => workspaceProfiles;

public EditorDockingAdapter Docking => docking;

private static EditorWorkspace CreateWorkspace()
{
var result = new EditorWorkspace();
result.NewDocument();
return result;
}

private void WirePaneInteractions()
{
RoutePane.NodeSelected += OnGraphNodeSelected;
RoutePane.SectionPointerChanged += OnSectionPointerChanged;
ViewportPane.SectionPointerChanged += OnSectionPointerChanged;
ViewportPane.SampleSelected += OnViewportSampleSelected;
MathPlotsPane.SectionPointerChanged += OnSectionPointerChanged;
MathPlotsPane.StationChanged += OnEngineeringPlotStationChanged;
MathPlotsPane.StationSelected += OnEngineeringPlotStationSelected;
}

private void OnWorkspaceChanged(object? sender, EventArgs eventArgs)
{
UpdateWorkspaceView();
Expand All @@ -77,38 +118,21 @@ private void OnCurrentProfileChanged(object? sender, EventArgs eventArgs)

private void ApplyWorkspaceProfile(WorkspaceProfile profile)
{
bool showRoute = profile.IsPaneVisibleByDefault(WorkspacePaneIds.Route);
bool showViewport = profile.IsPaneVisibleByDefault(WorkspacePaneIds.Viewport);
bool showInspector = profile.IsPaneVisibleByDefault(WorkspacePaneIds.Inspector);
bool showMathPlots = profile.IsPaneVisibleByDefault(WorkspacePaneIds.MathPlots);
bool showDiagnostics = profile.IsPaneVisibleByDefault(WorkspacePaneIds.Diagnostics);
bool showBottomPanel = showMathPlots || showDiagnostics;

RoutePane.IsVisible = showRoute;
ViewportPane.IsVisible = showViewport;
InspectorPane.IsVisible = showInspector;
RouteSplitter.IsVisible = showRoute && showViewport;
InspectorSplitter.IsVisible = showViewport && showInspector;
MathPlotsTab.IsVisible = showMathPlots;
DiagnosticsTab.IsVisible = showDiagnostics;
BottomPanelRegion.IsVisible = showBottomPanel;
BottomPanelSplitter.IsVisible = showBottomPanel;
if (showBottomPanel &&
BottomWorkspaceTabs.SelectedItem is Control selectedTab &&
!selectedTab.IsVisible)
{
BottomWorkspaceTabs.SelectedItem = showMathPlots ? MathPlotsTab : DiagnosticsTab;
}

ContentPaneGrid.ColumnDefinitions[0].Width = new GridLength(showRoute ? 320 : 0);
ContentPaneGrid.ColumnDefinitions[1].Width = new GridLength(showRoute && showViewport ? 5 : 0);
ContentPaneGrid.ColumnDefinitions[2].Width = showViewport
? new GridLength(1, GridUnitType.Star)
: new GridLength(0);
ContentPaneGrid.ColumnDefinitions[3].Width = new GridLength(showViewport && showInspector ? 5 : 0);
ContentPaneGrid.ColumnDefinitions[4].Width = new GridLength(showInspector ? 340 : 0);
WorkbenchGrid.RowDefinitions[3].Height = new GridLength(showBottomPanel ? 5 : 0);
WorkbenchGrid.RowDefinitions[4].Height = new GridLength(showBottomPanel ? 300 : 0);
docking.SetPaneVisible(
WorkspacePaneIds.Route,
profile.IsPaneVisibleByDefault(WorkspacePaneIds.Route));
docking.SetPaneVisible(
WorkspacePaneIds.Viewport,
profile.IsPaneVisibleByDefault(WorkspacePaneIds.Viewport));
docking.SetPaneVisible(
WorkspacePaneIds.Inspector,
profile.IsPaneVisibleByDefault(WorkspacePaneIds.Inspector));
docking.SetPaneVisible(
WorkspacePaneIds.MathPlots,
profile.IsPaneVisibleByDefault(WorkspacePaneIds.MathPlots));
docking.SetPaneVisible(
WorkspacePaneIds.Diagnostics,
profile.IsPaneVisibleByDefault(WorkspacePaneIds.Diagnostics));

bool showFileCommands = profile.HasCommandGroup(WorkspaceCommandGroupIds.File);
bool showEditCommands = profile.HasCommandGroup(WorkspaceCommandGroupIds.Edit);
Expand Down Expand Up @@ -361,7 +385,15 @@ private void OnMenuShowFramesClick(object? sender, RoutedEventArgs eventArgs)

private void OnShowEngineeringPlotsClick(object? sender, RoutedEventArgs eventArgs)
{
BottomWorkspaceTabs.SelectedIndex = 0;
docking.ShowPane(WorkspacePaneIds.MathPlots);
}

private void OnShowPaneClick(object? sender, RoutedEventArgs eventArgs)
{
if (sender is MenuItem { Tag: string paneId })
{
docking.ShowPane(paneId);
}
}

private void OnEngineeringPlotStationChanged(
Expand Down
3 changes: 3 additions & 0 deletions Quantum.Editor.Avalonia/Quantum.Editor.Avalonia.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
<PackageReference Include="Avalonia" Version="12.0.5" />
<PackageReference Include="Avalonia.Desktop" Version="12.0.5" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="12.0.5" />
<PackageReference Include="Dock.Avalonia" Version="12.0.0.2" />
<PackageReference Include="Dock.Avalonia.Themes.Fluent" Version="12.0.0.2" />
<PackageReference Include="Dock.Model.Mvvm" Version="12.0.0.2" />
</ItemGroup>

<ItemGroup>
Expand Down
30 changes: 30 additions & 0 deletions Quantum.Editor.Avalonia/Services/Docking/DockPaneRegistration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
namespace Quantum.Editor.Avalonia.Services.Docking;

/// <summary>
/// Frontend-only metadata for one dockable editor pane.
/// </summary>
public sealed class DockPaneRegistration
{
public DockPaneRegistration(string id, string title, bool canClose = true)
{
if (string.IsNullOrWhiteSpace(id))
{
throw new ArgumentException("A dock pane identifier cannot be empty.", nameof(id));
}

if (string.IsNullOrWhiteSpace(title))
{
throw new ArgumentException("A dock pane title cannot be empty.", nameof(title));
}

Id = id.Trim();
Title = title.Trim();
CanClose = canClose;
}

public string Id { get; }

public string Title { get; }

public bool CanClose { get; }
}
57 changes: 57 additions & 0 deletions Quantum.Editor.Avalonia/Services/Docking/DockPaneRegistry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using Quantum.Editor.Avalonia.Services.Workspaces;

namespace Quantum.Editor.Avalonia.Services.Docking;

/// <summary>
/// Registers the panes understood by the Avalonia docking composition root.
/// </summary>
public sealed class DockPaneRegistry
{
private readonly Dictionary<string, DockPaneRegistration> panesById =
new(StringComparer.Ordinal);
private readonly List<DockPaneRegistration> panes = new();

public IReadOnlyList<DockPaneRegistration> Panes => panes.AsReadOnly();

public static DockPaneRegistry CreateDefaultTrack()
{
var result = new DockPaneRegistry();
result.Register(new DockPaneRegistration(WorkspacePaneIds.Route, "Route"));
result.Register(new DockPaneRegistration(
WorkspacePaneIds.Viewport,
"Viewport",
canClose: false));
result.Register(new DockPaneRegistration(WorkspacePaneIds.Inspector, "Inspector"));
result.Register(new DockPaneRegistration(WorkspacePaneIds.MathPlots, "Math Plots"));
result.Register(new DockPaneRegistration(WorkspacePaneIds.Diagnostics, "Diagnostics"));
return result;
}

public void Register(DockPaneRegistration pane)
{
ArgumentNullException.ThrowIfNull(pane);
if (panesById.ContainsKey(pane.Id))
{
throw new InvalidOperationException($"Dock pane '{pane.Id}' is already registered.");
}

panesById.Add(pane.Id, pane);
panes.Add(pane);
}

public bool Contains(string paneId) =>
!string.IsNullOrWhiteSpace(paneId) && panesById.ContainsKey(paneId);

public bool TryGet(string paneId, out DockPaneRegistration pane) =>
panesById.TryGetValue(paneId, out pane!);

public DockPaneRegistration Get(string paneId)
{
if (!panesById.TryGetValue(paneId, out DockPaneRegistration? pane))
{
throw new KeyNotFoundException($"Dock pane '{paneId}' is not registered.");
}

return pane;
}
}
15 changes: 15 additions & 0 deletions Quantum.Editor.Avalonia/Services/Docking/DockingLayoutIds.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace Quantum.Editor.Avalonia.Services.Docking;

/// <summary>
/// Stable identifiers for the frontend-only default docking graph.
/// </summary>
public static class DockingLayoutIds
{
public const string Root = "track-root";
public const string Main = "track-main";
public const string Top = "track-top";
public const string RouteHost = "track-route-host";
public const string ViewportHost = "track-viewport-host";
public const string InspectorHost = "track-inspector-host";
public const string BottomHost = "track-bottom-host";
}
Loading
Loading