Skip to content

Commit

Permalink
feat: setup the project explorer view
Browse files Browse the repository at this point in the history
  • Loading branch information
abdes committed Oct 15, 2024
1 parent 6a2b149 commit 9c1ae24
Show file tree
Hide file tree
Showing 16 changed files with 739 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
<TargetPlatformMinVersion>10.0.22000.0</TargetPlatformMinVersion>
<Platforms>x86;x64;arm64</Platforms>
<RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
<UseWinUI>true</UseWinUI>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>

<!--
Visual Studio can show the generated source files in the dependencies
Expand Down Expand Up @@ -47,10 +49,13 @@
<ProjectReference Include="$(ProjectsRoot)\Oxygen.Editor.Storage\src\Oxygen.Editor.Storage.csproj" />
<ProjectReference Include="$(ProjectsRoot)\Oxygen.Editor.Data\src\Oxygen.Editor.Data.csproj" />
<ProjectReference Include="$(ProjectsRoot)\Oxygen.Editor.Core\src\Oxygen.Editor.Core.csproj" />
<ProjectReference Include="$(ProjectsRoot)\Oxygen.Editor.Projects\src\Oxygen.Editor.Projects.csproj" />
<ProjectReference Include="$(ProjectsRoot)\Mvvm\src\Mvvm.csproj" />
<ProjectReference Include="$(ProjectsRoot)\Docking\src\Docking.csproj" />
<ProjectReference Include="$(ProjectsRoot)\Converters\src\Converters.csproj" />
<ProjectReference Include="$(ProjectsRoot)\Collections\src\Collections.csproj" />
<ProjectReference Include="$(ProjectsRoot)\TimeMachine\src\TimeMachine.csproj" />
<ProjectReference Include="$(ProjectsRoot)\Controls\DynamicTree\src\Controls.DynamicTree.csproj" />

<!-- Rererence the attributes project "treat as an analyzer"-->
<ProjectReference Include="$(ProjectsRoot)\Mvvm.Generators\src\Mvvm.Generators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
Expand All @@ -61,38 +66,4 @@
<ProjectReference Include="$(ProjectsRoot)\Hosting.Generators.Attributes\src\Hosting.Generators.Attributes.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="true" />
</ItemGroup>

<ItemGroup>
<Page Update="Views\ContentBrowserView.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>

<ItemGroup>
<Page Update="Views\SceneDetailsView.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>

<ItemGroup>
<Page Update="Views\ProjectExplorerView.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>

<ItemGroup>
<Page Update="Views\RendererView.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>

<ItemGroup>
<PRIResource Update="en-US\Strings.resw" />
</ItemGroup>

<ItemGroup>
<Page Update="Views\WorkspaceView.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Distributed under the MIT License. See accompanying file LICENSE or copy
// at https://opensource.org/licenses/MIT.
// SPDX-License-Identifier: MIT

namespace Oxygen.Editor.WorldEditor.ProjectExplorer;

using DroidNet.Controls;
using Oxygen.Editor.Projects;

/// <summary>
/// A <see cref="DynamicTree" /> item adapter for the <see cref="Entity" /> model class.
/// </summary>
/// <param name="entity">The <see cref="Entity" /> object to wrap as a <see cref="ITreeItem" />.</param>
public partial class EntityAdapter(Entity entity) : TreeItemAdapter, ITreeItem<Entity>
{
public override bool IsRoot => false;

public override string Label
=> this.AttachedObject.Name;

public Entity AttachedObject => entity;

protected override int GetChildrenCount() => 0;

protected override async Task LoadChildren() => await Task.CompletedTask.ConfigureAwait(false);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Distributed under the MIT License. See accompanying file LICENSE or copy
// at https://opensource.org/licenses/MIT.
// SPDX-License-Identifier: MIT

namespace Oxygen.Editor.WorldEditor.ProjectExplorer;

using DroidNet.Controls;
using Oxygen.Editor.Projects;

/// <summary>
/// A <see cref="DynamicTree" /> item adapter for the <see cref="Project" /> model class.
/// </summary>
/// <param name="project">The <see cref="Entity" /> object to wrap as a <see cref="ITreeItem" />.</param>
/// <param name="projectManager">The configured project manager service.</param>
public partial class ProjectAdapter(Project project, IProjectManagerService projectManager)
: TreeItemAdapter, ITreeItem<Project>
{
public override string Label => project.ProjectInfo.Name;

public Project AttachedObject => project;

protected override int GetChildrenCount() => project.Scenes.Count;

protected override async Task LoadChildren()
{
this.ClearChildren();

if (!await projectManager.LoadProjectScenesAsync(project).ConfigureAwait(false))
{
return;
}

foreach (var scene in project.Scenes)
{
this.AddChildInternal(
new SceneAdapter(scene, projectManager)
{
IsExpanded = true,
});
}

await Task.CompletedTask.ConfigureAwait(true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<?xml version="1.0" encoding="utf-8" ?>
<UserControl
x:Class="Oxygen.Editor.WorldEditor.ProjectExplorer.ProjectExplorerView"
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:dnc="using:DroidNet.Controls"
xmlns:local="using:Oxygen.Editor.WorldEditor.ProjectExplorer"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
KeyboardAcceleratorPlacementMode="Hidden"
mc:Ignorable="d">

<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ms-appx:///DroidNet.Controls.DynamicTree/DynamicTree/DynamicTree.xaml" />
</ResourceDictionary.MergedDictionaries>

<DataTemplate x:Key="SceneThumbnailTemplate" x:DataType="dnc:TreeItemAdapter">
<Image Source="{x:Bind local:ThumbnailGenerator.GenerateRandomImage(24, 24)}" />
</DataTemplate>

<DataTemplate x:Key="EntityThumbnailTemplate" x:DataType="dnc:TreeItemAdapter">
<SymbolIcon
Width="24"
Height="24"
Symbol="{x:Bind local:ThumbnailGenerator.GetThumbnailForEntity((dnc:TreeItemAdapter))}" />
</DataTemplate>

<DataTemplate x:Key="DefaultThumbnailTemplate">
<Border
Width="{StaticResource CellContentWidth}"
Height="{StaticResource CellContentHeight}"
BorderBrush="{ThemeResource EmptyThumbnailBorderColor}"
BorderThickness="1" />
</DataTemplate>

<local:ThumbnailTemplateSelector
x:Key="ThumbnailTemplateSelector"
DefaultTemplate="{StaticResource DefaultThumbnailTemplate}"
EntityTemplate="{StaticResource EntityThumbnailTemplate}"
SceneTemplate="{StaticResource SceneThumbnailTemplate}" />
</ResourceDictionary>

</UserControl.Resources>

<UserControl.KeyboardAccelerators>
<KeyboardAccelerator
Key="Z"
Invoked="UndoInvoked"
Modifiers="Control" />
<KeyboardAccelerator
Key="Y"
Invoked="RedoInvoked"
Modifiers="Control" />
<KeyboardAccelerator Key="Delete" Invoked="DeleteInvoked" />
</UserControl.KeyboardAccelerators>

<Grid
Padding="4"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border
Padding="0,3"
BorderBrush="Red"
BorderThickness="1"
CornerRadius="3">
<dnc:DynamicTree
SelectionMode="Multiple"
ThumbnailTemplateSelector="{StaticResource ThumbnailTemplateSelector}"
ViewModel="{x:Bind ViewModel}" />
</Border>
<Grid Grid.Row="1">
<Grid.Resources>
<Style TargetType="AppBarButton">
<Setter Property="Width" Value="40" />
</Style>
</Grid.Resources>

<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<CommandBar
Grid.Column="1"
DefaultLabelPosition="Collapsed"
OverflowButtonVisibility="Collapsed">
<AppBarButton
Icon="Rename"
IsCompact="True"
Label="Rename" />
<AppBarButton
Icon="Repair"
IsCompact="True"
Label="Edit Properties" />
<AppBarButton
Command="{x:Bind ViewModel.AddEntityCommand}"
IsCompact="True"
Label="Add Entity">
<AppBarButton.Icon>
<FontIcon Glyph="&#xECC8;" />
</AppBarButton.Icon>
</AppBarButton>
<AppBarButton
Command="{x:Bind ViewModel.AddSceneCommand}"
Icon="Add"
IsCompact="True"
Label="Create New Scene" />
<AppBarButton
Command="{x:Bind ViewModel.RemoveSelectedItemsCommand}"
Icon="Delete"
IsCompact="True"
Label="Delete"
ToolTipService.ToolTip="Delete (Del)" />
</CommandBar>
</Grid>
</Grid>
</UserControl>
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Distributed under the MIT License. See accompanying file LICENSE or copy
// at https://opensource.org/licenses/MIT.
// SPDX-License-Identifier: MIT

namespace Oxygen.Editor.WorldEditor.ProjectExplorer;

using DroidNet.Controls;
using DroidNet.Mvvm.Generators;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Input;
using Oxygen.Editor.Projects;

/// <summary>
/// A View that shows a hierarchical layout of a <see cref="Project">project</see> that has <see cref="Scene">scenes</see>, which
/// in turn can hold multiple <see cref="Entity">entities</see>. It demonstrates the flexibility of the <see cref="DynamicTree" />
/// in representing hierarchical layouts of mixed types which can be loaded dynamically.
/// </summary>
[ViewModel(typeof(ProjectExplorerViewModel))]
public sealed partial class ProjectExplorerView
{
public ProjectExplorerView()
{
this.InitializeComponent();

this.Loaded += this.OnLoaded;
}

private async void OnLoaded(object sender, RoutedEventArgs args)
{
_ = sender; // unused
_ = args; // unused

if (this.ViewModel is not null)
{
await this.ViewModel.LoadProjectCommand.ExecuteAsync(parameter: null).ConfigureAwait(true);
}
}

private void UndoInvoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args)
{
_ = sender; // unused
args.Handled = true;

this.ViewModel!.UndoCommand.Execute(parameter: null);
}

private void RedoInvoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args)
{
_ = sender; // unused
args.Handled = true;

this.ViewModel!.RedoCommand.Execute(parameter: null);
}

private async void DeleteInvoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args)
{
_ = sender; // unused
args.Handled = true;

await this.ViewModel!.RemoveSelectedItemsCommand.ExecuteAsync(parameter: null).ConfigureAwait(false);
}
}
Loading

0 comments on commit 9c1ae24

Please sign in to comment.