Refactor folder structure
This commit is contained in:
62
src/Editor/Ghost.Editor/View/Controls/Hierarchy.xaml
Normal file
62
src/Editor/Ghost.Editor/View/Controls/Hierarchy.xaml
Normal file
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<UserControl
|
||||
x:Class="Ghost.Editor.View.Controls.Hierarchy"
|
||||
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.Editor.View.Controls"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid
|
||||
Grid.Row="0"
|
||||
Height="40"
|
||||
Padding="8,8,8,4"
|
||||
Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}"
|
||||
BorderBrush="{ThemeResource DividerStrokeColorDefaultBrush}"
|
||||
BorderThickness="0,0,0,1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<AutoSuggestBox
|
||||
Grid.Column="0"
|
||||
PlaceholderText="Search"
|
||||
QueryIcon="Find" />
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal">
|
||||
<AppBarSeparator />
|
||||
<Button Style="{ThemeResource ToolbarButton}">
|
||||
<FontIcon FontSize="{StaticResource ToolbarIconSize}" Glyph="" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Border Grid.Row="1" Padding="4">
|
||||
<ListView>
|
||||
<StackPanel Orientation="Horizontal" Spacing="4">
|
||||
<FontIcon FontSize="{StaticResource ToolbarIconSize}" Glyph="" />
|
||||
<TextBlock Text="Test" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Spacing="4">
|
||||
<FontIcon FontSize="{StaticResource ToolbarIconSize}" Glyph="" />
|
||||
<TextBlock Text="Test" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Spacing="4">
|
||||
<FontIcon FontSize="{StaticResource ToolbarIconSize}" Glyph="" />
|
||||
<TextBlock Text="Test" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Spacing="4">
|
||||
<FontIcon FontSize="{StaticResource ToolbarIconSize}" Glyph="" />
|
||||
<TextBlock Text="Test" />
|
||||
</StackPanel>
|
||||
</ListView>
|
||||
</Border>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
27
src/Editor/Ghost.Editor/View/Controls/Hierarchy.xaml.cs
Normal file
27
src/Editor/Ghost.Editor/View/Controls/Hierarchy.xaml.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
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.
|
||||
|
||||
namespace Ghost.Editor.View.Controls;
|
||||
|
||||
public sealed partial class Hierarchy : UserControl
|
||||
{
|
||||
public Hierarchy()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
53
src/Editor/Ghost.Editor/View/Controls/ProjectBrowser.Menu.cs
Normal file
53
src/Editor/Ghost.Editor/View/Controls/ProjectBrowser.Menu.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using Ghost.Editor.Core;
|
||||
|
||||
namespace Ghost.Editor.View.Controls;
|
||||
|
||||
internal partial class ProjectBrowser
|
||||
{
|
||||
[ContextMenuItem("project-browser", "Show in Explorer")]
|
||||
private static void ShowInExplorer()
|
||||
{
|
||||
var path = LastFocused?.ViewModel.CurrentDirectoryPath;
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo()
|
||||
{
|
||||
FileName = path,
|
||||
UseShellExecute = true,
|
||||
Verb = "open"
|
||||
});
|
||||
}
|
||||
|
||||
[ContextMenuItem("project-browser", "Create/Folder")]
|
||||
private static void CreateFolder()
|
||||
{
|
||||
// TODO: Use AssetService
|
||||
|
||||
var viewModel = LastFocused?.ViewModel;
|
||||
if (viewModel is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var currentDir = viewModel.CurrentDirectoryPath;
|
||||
if (!Directory.Exists(currentDir))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var newFolderPath = Path.Combine(currentDir, "New Folder");
|
||||
var folderIndex = 1;
|
||||
while (Directory.Exists(newFolderPath))
|
||||
{
|
||||
newFolderPath = Path.Combine(currentDir, $"New Folder ({folderIndex})");
|
||||
folderIndex++;
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(newFolderPath);
|
||||
// Refresh the view model to show the new folder
|
||||
viewModel.NavigateToDirectory(currentDir);
|
||||
}
|
||||
}
|
||||
216
src/Editor/Ghost.Editor/View/Controls/ProjectBrowser.xaml
Normal file
216
src/Editor/Ghost.Editor/View/Controls/ProjectBrowser.xaml
Normal file
@@ -0,0 +1,216 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<UserControl
|
||||
x:Class="Ghost.Editor.View.Controls.ProjectBrowser"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:community="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:converter="using:Ghost.Editor.Utilities.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:ghost="using:Ghost.Editor.Core.Controls"
|
||||
xmlns:local="using:Ghost.Editor.View.Controls"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:model="using:Ghost.Editor.Models"
|
||||
xmlns:sys="using:System"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.Resources>
|
||||
<converter:ExplorerItemToIconUriConverter x:Key="ExplorerItemToIconUriConverter" />
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Toolbar -->
|
||||
<Grid
|
||||
Height="36"
|
||||
Padding="4"
|
||||
Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}"
|
||||
BorderBrush="{ThemeResource DividerStrokeColorDefaultBrush}"
|
||||
BorderThickness="0,0,0,1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal">
|
||||
<Button Style="{ThemeResource ToolbarButton}">
|
||||
<Button.Content>
|
||||
<FontIcon FontSize="{StaticResource ToolbarIconSize}" Glyph="" />
|
||||
</Button.Content>
|
||||
<Button.Flyout>
|
||||
<MenuFlyout>
|
||||
<MenuFlyoutItem Text="Folder" />
|
||||
<MenuFlyoutItem Text="Script" />
|
||||
<MenuFlyoutSubItem Text="Rendering">
|
||||
<MenuFlyoutItem Text="Material" />
|
||||
<MenuFlyoutItem Text="Volume Profile" />
|
||||
</MenuFlyoutSubItem>
|
||||
</MenuFlyout>
|
||||
</Button.Flyout>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal">
|
||||
<AutoSuggestBox
|
||||
Width="250"
|
||||
PlaceholderText="Search"
|
||||
QueryIcon="Find" />
|
||||
<AppBarSeparator />
|
||||
<Button Style="{ThemeResource ToolbarButton}">
|
||||
<Button.Content>
|
||||
<FontIcon FontSize="{StaticResource ToolbarIconSize}" Glyph="" />
|
||||
</Button.Content>
|
||||
<Button.Flyout>
|
||||
<MenuFlyout>
|
||||
<ToggleMenuFlyoutItem Text="Animation" />
|
||||
<ToggleMenuFlyoutItem Text="Audio" />
|
||||
<ToggleMenuFlyoutItem Text="Material" />
|
||||
<ToggleMenuFlyoutItem Text="Script" />
|
||||
<ToggleMenuFlyoutItem Text="Texture" />
|
||||
</MenuFlyout>
|
||||
</Button.Flyout>
|
||||
</Button>
|
||||
<Button Style="{ThemeResource ToolbarButton}">
|
||||
<Button.Content>
|
||||
<FontIcon FontSize="{StaticResource ToolbarIconSize}" Glyph="" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<!-- Conent Viewer -->
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Border
|
||||
Grid.Column="0"
|
||||
Width="200"
|
||||
Padding="4,0,0,0"
|
||||
Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}"
|
||||
BorderBrush="{ThemeResource DividerStrokeColorDefaultBrush}"
|
||||
BorderThickness="0,0,1,0">
|
||||
<TreeView
|
||||
x:Name="PART_DirectoriesView"
|
||||
ItemsSource="{x:Bind ViewModel.Directories, Mode=OneWay}"
|
||||
SelectionChanged="PART_DirectoriesView_SelectionChanged"
|
||||
SelectionMode="Single">
|
||||
<TreeView.ItemTemplate>
|
||||
<DataTemplate x:DataType="model:ExplorerItem">
|
||||
<TreeViewItem ItemsSource="{x:Bind Children}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="4">
|
||||
<!-- TODO: Open/Close folder icon based on state -->
|
||||
<FontIcon
|
||||
VerticalAlignment="Center"
|
||||
FontSize="12"
|
||||
Glyph="" />
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind Name}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
</DataTemplate>
|
||||
</TreeView.ItemTemplate>
|
||||
</TreeView>
|
||||
</Border>
|
||||
|
||||
<Grid Grid.Column="1">
|
||||
<Grid.RowDefinitions>
|
||||
<!--<RowDefinition Height="Auto" />-->
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!--<Border
|
||||
Grid.Row="0"
|
||||
Height="24"
|
||||
Background="{ThemeResource LayerFillColorDefaultBrush}"
|
||||
BorderBrush="{ThemeResource DividerStrokeColorDefaultBrush}"
|
||||
BorderThickness="0,0,0,1">
|
||||
<BreadcrumbBar />
|
||||
</Border>-->
|
||||
|
||||
<ItemsView
|
||||
x:Name="PART_FilesView"
|
||||
Grid.Row="0"
|
||||
Padding="8"
|
||||
DoubleTapped="PART_FilesView_DoubleTapped"
|
||||
IsDoubleTapEnabled="True"
|
||||
ItemsSource="{x:Bind ViewModel.Files, Mode=OneWay}"
|
||||
SelectionChanged="PART_FilesView_SelectionChanged"
|
||||
SelectionMode="Single">
|
||||
<ItemsView.ItemTemplate>
|
||||
<DataTemplate x:DataType="model:ExplorerItem">
|
||||
<ItemContainer>
|
||||
<Grid
|
||||
Padding="8"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
RowSpacing="4"
|
||||
ToolTipService.ToolTip="{x:Bind Name}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid.ContextFlyout>
|
||||
<MenuFlyout>
|
||||
<MenuFlyoutItem Text="Open" />
|
||||
<MenuFlyoutItem Text="Rename" />
|
||||
<MenuFlyoutItem Text="Delete" />
|
||||
<MenuFlyoutItem Text="Show in Explorer" />
|
||||
</MenuFlyout>
|
||||
</Grid.ContextFlyout>
|
||||
|
||||
<community:ConstrainedBox Grid.Row="0" AspectRatio="1:1">
|
||||
<Image HorizontalAlignment="Center">
|
||||
<Image.Source>
|
||||
<BitmapImage DecodePixelWidth="48" UriSource="{x:Bind Converter={StaticResource ExplorerItemToIconUriConverter}}" />
|
||||
</Image.Source>
|
||||
</Image>
|
||||
</community:ConstrainedBox>
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
HorizontalAlignment="Center"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind Name}"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
TextWrapping="NoWrap" />
|
||||
</Grid>
|
||||
</ItemContainer>
|
||||
</DataTemplate>
|
||||
</ItemsView.ItemTemplate>
|
||||
<ItemsView.Layout>
|
||||
<UniformGridLayout
|
||||
ItemsStretch="Fill"
|
||||
MinColumnSpacing="4"
|
||||
MinItemWidth="72"
|
||||
MinRowSpacing="4" />
|
||||
</ItemsView.Layout>
|
||||
<ItemsView.ContextFlyout>
|
||||
<ghost:ContextFlyout Tag="project-browser" />
|
||||
</ItemsView.ContextFlyout>
|
||||
</ItemsView>
|
||||
|
||||
<Border
|
||||
Grid.Row="1"
|
||||
Height="24"
|
||||
Padding="8,2"
|
||||
Background="{ThemeResource LayerFillColorDefaultBrush}"
|
||||
BorderBrush="{ThemeResource DividerStrokeColorDefaultBrush}"
|
||||
BorderThickness="0,1,0,0">
|
||||
<StackPanel>
|
||||
<TextBlock Text="{x:Bind sys:String.Format('{0} items', ViewModel.Files.Count), Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
146
src/Editor/Ghost.Editor/View/Controls/ProjectBrowser.xaml.cs
Normal file
146
src/Editor/Ghost.Editor/View/Controls/ProjectBrowser.xaml.cs
Normal file
@@ -0,0 +1,146 @@
|
||||
using Ghost.Editor.Core.Contracts;
|
||||
using Ghost.Editor.Models;
|
||||
using Ghost.Editor.ViewModels.Controls;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
|
||||
namespace Ghost.Editor.View.Controls;
|
||||
|
||||
internal sealed partial class ProjectBrowser : UserControl
|
||||
{
|
||||
public static ProjectBrowser? LastFocused
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
private readonly IInspectorService _inspectorService;
|
||||
private bool _isUpdatingSelection = false;
|
||||
|
||||
public ProjectBrowserViewModel ViewModel
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public ProjectBrowser()
|
||||
{
|
||||
_inspectorService = App.GetService<IInspectorService>();
|
||||
ViewModel = App.GetService<ProjectBrowserViewModel>();
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
Loaded += ProjectBrowser_Loaded;
|
||||
Unloaded += ProjectBrowser_Unloaded;
|
||||
|
||||
GettingFocus += ProjectBrowser_GettingFocus;
|
||||
}
|
||||
|
||||
private void ProjectBrowser_GettingFocus(UIElement sender, GettingFocusEventArgs args)
|
||||
{
|
||||
if (_isUpdatingSelection)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LastFocused = this;
|
||||
}
|
||||
|
||||
private void ProjectBrowser_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_inspectorService.OnSelectionChanged += _inspectorService_OnSelectionChanged;
|
||||
}
|
||||
|
||||
private void ProjectBrowser_Unloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_inspectorService.OnSelectionChanged -= _inspectorService_OnSelectionChanged;
|
||||
|
||||
if (LastFocused == this)
|
||||
{
|
||||
LastFocused = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void _inspectorService_OnSelectionChanged(object? sender, InspectorSelectionChangedEventArgs e)
|
||||
{
|
||||
if (e.Source is not ProjectBrowserViewModel)
|
||||
{
|
||||
PART_FilesView.DeselectAll();
|
||||
PART_DirectoriesView.SelectedNodes.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void PART_DirectoriesView_SelectionChanged(TreeView sender, TreeViewSelectionChangedEventArgs args)
|
||||
{
|
||||
if (_isUpdatingSelection)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_isUpdatingSelection = true;
|
||||
|
||||
PART_FilesView.DeselectAll();
|
||||
if (args.AddedItems.Count > 0 && args.AddedItems[0] is ExplorerItem selectedItem)
|
||||
{
|
||||
ViewModel.SelectedItem = selectedItem;
|
||||
ViewModel.NavigateToDirectory(selectedItem.FullName);
|
||||
}
|
||||
|
||||
_isUpdatingSelection = false;
|
||||
}
|
||||
|
||||
private void PART_FilesView_SelectionChanged(ItemsView sender, ItemsViewSelectionChangedEventArgs args)
|
||||
{
|
||||
if (_isUpdatingSelection)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_isUpdatingSelection = true;
|
||||
|
||||
PART_DirectoriesView.SelectedNodes.Clear();
|
||||
if (PART_FilesView.SelectedItem is ExplorerItem selectedItem)
|
||||
{
|
||||
ViewModel.SelectedItem = selectedItem;
|
||||
}
|
||||
|
||||
_isUpdatingSelection = false;
|
||||
}
|
||||
|
||||
private async void PART_FilesView_DoubleTapped(object sender, Microsoft.UI.Xaml.Input.DoubleTappedRoutedEventArgs e)
|
||||
{
|
||||
if (PART_FilesView.SelectedItem is ExplorerItem selectedItem)
|
||||
{
|
||||
_isUpdatingSelection = true;
|
||||
|
||||
PART_FilesView.DeselectAll();
|
||||
PART_DirectoriesView.SelectedNodes.Clear();
|
||||
|
||||
// NOTE: There is bug that the hover state of the item may remain when navigating to another folder.
|
||||
// Which causes incorrect selection (double click a folder -> directories view select target folder -> files view select the item that has the same index as the double clicked one and the hover visual stay remain from last level)
|
||||
// Not sure if this is a WinUI bug or something else. This may because of the virtualization of the ItemsView.
|
||||
// The core issue is not sure why PART_FilesView_SelectionChanged been triggered after NavigateToDirectory is already finished. And this only happens after the first double click navigation (first time is always fine).
|
||||
|
||||
// HACK: Wait a moment to let the ui clear it's state, otherwise the bug above will happen because of the virtualization.
|
||||
await Task.Delay(100);
|
||||
|
||||
ViewModel.SelectedItem = selectedItem;
|
||||
|
||||
var navigatedItem = ViewModel.OpenSelected();
|
||||
if (navigatedItem.Item1 != null)
|
||||
{
|
||||
if (navigatedItem.Item2 == 0)
|
||||
{
|
||||
PART_DirectoriesView.SelectedItem = navigatedItem.Item1;
|
||||
}
|
||||
else if (navigatedItem.Item2 == 1)
|
||||
{
|
||||
var index = ViewModel.Files.IndexOf(navigatedItem.Item1);
|
||||
PART_FilesView.Select(index);
|
||||
}
|
||||
}
|
||||
|
||||
_isUpdatingSelection = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user