diff --git a/Installer/SkEditorInstaller.wixproj b/Installer/SkEditorInstaller.wixproj
index cbd4b8ab..1a983db0 100644
--- a/Installer/SkEditorInstaller.wixproj
+++ b/Installer/SkEditorInstaller.wixproj
@@ -4,6 +4,7 @@
+
\ No newline at end of file
diff --git a/SkEditor/Assets/Icons.axaml b/SkEditor/Assets/Icons.axaml
index d9b0175d..d8ec5e7e 100644
--- a/SkEditor/Assets/Icons.axaml
+++ b/SkEditor/Assets/Icons.axaml
@@ -44,5 +44,10 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/SkEditor/Controls/Sidebar/ExplorerSidebarPanel.axaml b/SkEditor/Controls/Sidebar/ExplorerSidebarPanel.axaml
index de19b46f..1dd2f21e 100644
--- a/SkEditor/Controls/Sidebar/ExplorerSidebarPanel.axaml
+++ b/SkEditor/Controls/Sidebar/ExplorerSidebarPanel.axaml
@@ -3,6 +3,9 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="using:FluentAvalonia.UI.Controls"
+ xmlns:ar="clr-namespace:SkEditor.Utilities.Projects"
+ xmlns:elements="clr-namespace:SkEditor.Utilities.Projects.Elements"
+ xmlns:visualBasic="clr-namespace:Microsoft.VisualBasic;assembly=Microsoft.VisualBasic.Core"
x:Class="SkEditor.Controls.Sidebar.ExplorerSidebarPanel">
@@ -26,12 +29,81 @@
-
+
-
-
+
+
+ Loading XX files ...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ You don't have any folders opened yet. Keep in mind they are in beta!
+
+
diff --git a/SkEditor/Controls/Sidebar/ExplorerSidebarPanel.axaml.cs b/SkEditor/Controls/Sidebar/ExplorerSidebarPanel.axaml.cs
index 2ef46737..24f09777 100644
--- a/SkEditor/Controls/Sidebar/ExplorerSidebarPanel.axaml.cs
+++ b/SkEditor/Controls/Sidebar/ExplorerSidebarPanel.axaml.cs
@@ -1,8 +1,8 @@
-using Avalonia;
-using Avalonia.Controls;
-using Avalonia.Markup.Xaml;
+using Avalonia.Controls;
+using Avalonia.Interactivity;
using FluentAvalonia.UI.Controls;
using SkEditor.Utilities;
+using SkEditor.Utilities.Projects;
namespace SkEditor.Controls.Sidebar;
@@ -21,4 +21,9 @@ public class ExplorerPanel : SidebarPanel
public readonly ExplorerSidebarPanel Panel = new ();
}
+
+ private void OpenFolder(object? sender, RoutedEventArgs e)
+ {
+ ProjectOpener.OpenProject();
+ }
}
\ No newline at end of file
diff --git a/SkEditor/Languages/English.xaml b/SkEditor/Languages/English.xaml
index 52281c21..4d7464a8 100644
--- a/SkEditor/Languages/English.xaml
+++ b/SkEditor/Languages/English.xaml
@@ -13,6 +13,8 @@
Generate command
Select item
Marketplace
+ Rename
+ Create
File
@@ -46,11 +48,19 @@
GUI
Command
Refactor
-
+
Marketplace
Refresh syntax
+
+ Open in explorer
+ Copy relative path
+ Copy absolute path
+ Rename
+ New file
+ New folder
+
Apply
Confirm
@@ -98,6 +108,21 @@
Convert spaces to tabs
Renaming '{0}' into ...
+
+
+ Explorer
+ Projects are still in beta and bugs may occur!
+ Open Folder
+ Renaming into ...
+ Name cannot be empty.
+ Parent cannot be null.
+ A file or folder with this name already exists.
+ The new name is the same as the old name.
+ A file or folder with this name already exists.
+ File Name
+ Folder Name
+ Template
+
Select file association
There's multiple provider for this file type. Please select one.
@@ -106,6 +131,7 @@
Remember my choice
Confirm
+
Enabled
Disabled
diff --git a/SkEditor/SkEditor.csproj b/SkEditor/SkEditor.csproj
index 991b81b2..f9965cd8 100644
--- a/SkEditor/SkEditor.csproj
+++ b/SkEditor/SkEditor.csproj
@@ -46,6 +46,7 @@
+
diff --git a/SkEditor/Utilities/Editor/CustomCommandsHandler.cs b/SkEditor/Utilities/Editor/CustomCommandsHandler.cs
index 485d0d24..c8b0eabd 100644
--- a/SkEditor/Utilities/Editor/CustomCommandsHandler.cs
+++ b/SkEditor/Utilities/Editor/CustomCommandsHandler.cs
@@ -18,23 +18,39 @@ public static void OnCommentCommandExecuted(object target)
var document = editor.Document;
var selectionStart = editor.SelectionStart;
var selectionLength = editor.SelectionLength;
+ var indentation = editor.Options.IndentationString;
var selectedLines = document.Lines
.Where(line => selectionStart <= line.EndOffset && selectionStart + selectionLength >= line.Offset)
.ToList();
- bool allLinesCommented = selectedLines.All(line => document.GetText(line).StartsWith("#"));
-
var modifiedLines = selectedLines.Select(line =>
{
var text = document.GetText(line);
- if (allLinesCommented)
+ if (string.IsNullOrWhiteSpace(text))
+ return text;
+
+ // Find the first non-tabulator character
+ var strippedLine = text.TrimStart();
+ var isCommented = text.TrimStart().StartsWith("#");
+ var indentationAmount = 0;
+ while (text.StartsWith(indentation))
{
- return text.StartsWith('#') ? text[1..] : text;
+ text = text[indentation.Length..];
+ indentationAmount++;
}
- else
+
+ string indentationToInsert = "";
+ for (int i = 0; i < indentationAmount; i++)
+ indentationToInsert += indentation;
+
+ ApiVault.Get().Log("Indentation 2 insert: " + indentationToInsert + " | Line: '" + text + "'", true);
+ if (isCommented)
+ {
+ return indentationToInsert + strippedLine[1..];
+ } else
{
- return text.StartsWith('#') ? "##" + text[1..] : "#" + text;
+ return indentationToInsert + "#" + strippedLine;
}
}).ToList();
diff --git a/SkEditor/Utilities/Files/Icon.cs b/SkEditor/Utilities/Files/Icon.cs
index 29adfd02..2b230e39 100644
--- a/SkEditor/Utilities/Files/Icon.cs
+++ b/SkEditor/Utilities/Files/Icon.cs
@@ -28,4 +28,17 @@ public static void SetIcon(TabViewItem tabViewItem)
tabViewItem.IconSource = iconSource;
}
+
+ public static IconSource? GetIcon(string extension)
+ {
+ string iconName = IconDictionary.GetValueOrDefault(extension);
+
+ if (iconName is not null)
+ {
+ Application.Current.TryGetResource(iconName, Avalonia.Styling.ThemeVariant.Default, out object icon);
+ return icon as PathIconSource;
+ }
+
+ return null;
+ }
}
diff --git a/SkEditor/Utilities/Projects/Elements/File.cs b/SkEditor/Utilities/Projects/Elements/File.cs
new file mode 100644
index 00000000..aec079dc
--- /dev/null
+++ b/SkEditor/Utilities/Projects/Elements/File.cs
@@ -0,0 +1,88 @@
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using Avalonia.Platform.Storage;
+using CommunityToolkit.Mvvm.Input;
+using SkEditor.API;
+using SkEditor.Utilities.Files;
+
+namespace SkEditor.Utilities.Projects.Elements;
+
+public class File : StorageElement
+{
+
+ public string StorageFilePath { get; set; }
+
+ public File(string file, Folder? parent = null)
+ {
+ Parent = parent;
+ StorageFilePath = file;
+
+ Name = Path.GetFileName(file);
+ IsFile = true;
+
+ var icon = Files.Icon.GetIcon(Path.GetExtension(file));
+ if (icon is not null)
+ Icon = icon;
+
+ // Commands
+ OpenInExplorerCommand = new RelayCommand(OpenInExplorer);
+ DeleteCommand = new RelayCommand(DeleteFile);
+ CopyAbsolutePathCommand = new RelayCommand(CopyAbsolutePath);
+ CopyPathCommand = new RelayCommand(CopyPath);
+ }
+
+ public void OpenInExplorer()
+ {
+ Process.Start(new ProcessStartInfo(Parent.StorageFolderPath) { UseShellExecute = true });
+ }
+
+ public void DeleteFile()
+ {
+ System.IO.File.Delete(StorageFilePath);
+ Parent.Children.Remove(this);
+ }
+
+ public override string? ValidateName(string input)
+ {
+ if (input == Name)
+ return Translation.Get("ProjectRenameErrorSameName");
+
+ if (Parent is null)
+ return Translation.Get("ProjectRenameErrorParentNull");
+
+ var file = Parent.Children.FirstOrDefault(x => x.Name == input);
+ if (file is not null)
+ return Translation.Get("ProjectRenameErrorNameExists");
+
+ return null;
+ }
+
+ public override void RenameElement(string newName)
+ {
+ var newPath = Path.Combine(Parent.StorageFolderPath, newName);
+
+ System.IO.File.Move(StorageFilePath, newPath);
+ StorageFilePath = newPath;
+
+ Name = newName;
+
+ RefreshSelf();
+ }
+
+ public override void HandleDoubleClick()
+ {
+ FileHandler.OpenFile(StorageFilePath);
+ }
+
+ public void CopyAbsolutePath()
+ {
+ ApiVault.Get().GetMainWindow().Clipboard.SetTextAsync(StorageFilePath.Replace("\\", "/"));
+ }
+
+ public void CopyPath()
+ {
+ var path = StorageFilePath.Replace(ProjectOpener.ProjectRootFolder.StorageFolderPath, "");
+ ApiVault.Get().GetMainWindow().Clipboard.SetTextAsync(path.Replace("\\", "/"));
+ }
+}
\ No newline at end of file
diff --git a/SkEditor/Utilities/Projects/Elements/Folder.cs b/SkEditor/Utilities/Projects/Elements/Folder.cs
new file mode 100644
index 00000000..05ec7be2
--- /dev/null
+++ b/SkEditor/Utilities/Projects/Elements/Folder.cs
@@ -0,0 +1,141 @@
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using Avalonia.Platform.Storage;
+using CommunityToolkit.Mvvm.Input;
+using SkEditor.API;
+using SkEditor.Utilities.Files;
+using SkEditor.Views;
+using SkEditor.Views.Projects;
+
+namespace SkEditor.Utilities.Projects.Elements;
+
+public class Folder : StorageElement
+{
+
+ public string StorageFolderPath { get; set; }
+
+ public Folder(string folder, Folder? parent = null)
+ {
+ Parent = parent;
+ StorageFolderPath = folder;
+ Name = Path.GetFileName(folder);
+ IsFile = false;
+
+ Children = new ObservableCollection();
+ LoadChildren();
+
+ // Commands
+ OpenInExplorerCommand = new RelayCommand(OpenInExplorer);
+ DeleteCommand = new RelayCommand(DeleteFolder);
+ CopyPathCommand = new RelayCommand(CopyPath);
+ CopyAbsolutePathCommand = new RelayCommand(CopyAbsolutePath);
+ CreateNewFileCommand = new RelayCommand(() => CreateNewElement(true));
+ CreateNewFolderCommand = new RelayCommand(() => CreateNewElement(false));
+ }
+
+ private void LoadChildren()
+ {
+ foreach (var child in Directory.GetDirectories(StorageFolderPath))
+ Children.Add(new Folder(child, this));
+
+ foreach (var child in Directory.GetFiles(StorageFolderPath))
+ Children.Add(new File(child, this));
+ }
+
+ public void OpenInExplorer()
+ {
+ Process.Start(new ProcessStartInfo(StorageFolderPath) { UseShellExecute = true });
+ }
+
+ public void DeleteFolder()
+ {
+ Directory.Delete(StorageFolderPath, true);
+ Parent.Children.Remove(this);
+ }
+
+ public override void RenameElement(string newName)
+ {
+ var newPath = Path.Combine(Parent.StorageFolderPath, newName);
+ Directory.Move(StorageFolderPath, newPath);
+ StorageFolderPath = newPath;
+ Name = newName;
+
+ RefreshSelf();
+ }
+
+ public override string? ValidateName(string input)
+ {
+ if (input == Name)
+ return Translation.Get("ProjectRenameErrorSameName");
+
+ if (Parent is null)
+ return Translation.Get("ProjectRenameErrorParentNull");
+
+ var folder = Parent.Children.FirstOrDefault(x => x.Name == input);
+ if (folder is not null)
+ return Translation.Get("ProjectRenameErrorNameExists");
+
+ return null;
+ }
+
+ public string? ValidateCreationName(string input)
+ {
+ if (string.IsNullOrWhiteSpace(input))
+ return Translation.Get("ProjectCreateErrorNameEmpty");
+
+ if (Children.Any(x => x.Name == input))
+ return Translation.Get("ProjectCreateErrorNameExists");
+
+ return null;
+ }
+
+ public override void HandleDoubleClick()
+ {
+ if (Children.Count == 0)
+ return;
+
+ IsExpanded = !IsExpanded;
+ }
+
+ public void CopyAbsolutePath()
+ {
+ ApiVault.Get().GetMainWindow().Clipboard.SetTextAsync(StorageFolderPath.Replace("\\", "/"));
+ }
+
+ public void CopyPath()
+ {
+ var path = StorageFolderPath.Replace(ProjectOpener.ProjectRootFolder.StorageFolderPath, "");
+ ApiVault.Get().GetMainWindow().Clipboard.SetTextAsync(path.Replace("\\", "/"));
+ }
+
+ public async void CreateNewElement(bool file)
+ {
+ var window = new CreateStorageElementWindow(this, file);
+ await window.ShowDialog(MainWindow.Instance);
+ }
+
+ public async void CreateFile(string name)
+ {
+ var path = Path.Combine(StorageFolderPath, name);
+
+ System.IO.File.Create(path).Close();
+ FileHandler.OpenFile(path);
+
+ var element = new File(path, this);
+ Children.Add(element);
+ Sort(this);
+ }
+
+ public void CreateFolder(string name)
+ {
+ var path = Path.Combine(StorageFolderPath, name);
+
+ Directory.CreateDirectory(path);
+
+ var element = new Folder(path, this);
+ Children.Add(element);
+ Sort(this);
+ }
+}
\ No newline at end of file
diff --git a/SkEditor/Utilities/Projects/Elements/StorageElement.cs b/SkEditor/Utilities/Projects/Elements/StorageElement.cs
new file mode 100644
index 00000000..a5c2f2be
--- /dev/null
+++ b/SkEditor/Utilities/Projects/Elements/StorageElement.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections.ObjectModel;
+using System.Linq;
+using AvaloniaEdit.Utils;
+using CommunityToolkit.Mvvm.Input;
+using FluentAvalonia.UI.Controls;
+using SkEditor.Views;
+using SkEditor.Views.Projects;
+
+namespace SkEditor.Utilities.Projects.Elements;
+
+public abstract class StorageElement
+{
+ public ObservableCollection? Children { get; set; }
+ public Folder? Parent { get; set; }
+
+ public string Name { get; set; } = "";
+ public bool IsExpanded { get; set; } = false;
+
+ public bool IsFile { get; set; }
+
+ public IconSource Icon { get; set; } = new SymbolIconSource() { Symbol = Symbol.Document, FontSize = 24};
+
+ public RelayCommand OpenInExplorerCommand { get; set; }
+ public RelayCommand RenameCommand => new (OpenRenameWindow);
+ public RelayCommand DeleteCommand { get; set; }
+ public RelayCommand DoubleClickCommand => new (HandleDoubleClick);
+ public RelayCommand CopyPathCommand { get; set; }
+ public RelayCommand CopyAbsolutePathCommand { get; set; }
+ public RelayCommand CreateNewFileCommand { get; set; }
+ public RelayCommand CreateNewFolderCommand { get; set; }
+
+ public abstract string? ValidateName(string input);
+
+ public abstract void RenameElement(string newName);
+
+ public abstract void HandleDoubleClick();
+
+ public async void OpenRenameWindow()
+ {
+ var window = new RenameElementWindow(this);
+ await window.ShowDialog(MainWindow.Instance);
+ }
+
+ public void RefreshSelf()
+ {
+ Parent.Children[Parent.Children.IndexOf(this)] = this;
+ Sort(Parent);
+ }
+
+ public void Sort(StorageElement element)
+ {
+ if (element.Children != null)
+ {
+ var temp = element.Children.ToList();
+ element.Children.Clear();
+ element.Children.AddRange(temp.OrderBy(x => x.IsFile).ThenBy(x => x.Name));
+ }
+ }
+}
\ No newline at end of file
diff --git a/SkEditor/Utilities/Projects/ProjectOpener.cs b/SkEditor/Utilities/Projects/ProjectOpener.cs
index 337ad96c..b72e5564 100644
--- a/SkEditor/Utilities/Projects/ProjectOpener.cs
+++ b/SkEditor/Utilities/Projects/ProjectOpener.cs
@@ -1,18 +1,24 @@
-using Avalonia.Controls;
-using Avalonia.Media;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+using System.Linq;
+using Avalonia.Controls;
using Avalonia.Platform.Storage;
+using CommunityToolkit.Mvvm.Input;
+using FluentAvalonia.UI.Controls;
using SkEditor.API;
-using SkEditor.Utilities.Files;
-using System;
-using System.Collections.Generic;
-using System.IO;
+using SkEditor.Controls.Sidebar;
+using SkEditor.Utilities.Projects.Elements;
namespace SkEditor.Utilities.Projects;
public static class ProjectOpener
{
- private static TreeView FileTreeView => ApiVault.Get().GetMainWindow().SideBar.ProjectPanel.Panel.FileTreeView;
+ public static Folder? ProjectRootFolder = null;
+ private static ExplorerSidebarPanel Panel => ApiVault.Get().GetMainWindow().SideBar.ProjectPanel.Panel;
+ private static TreeView FileTreeView => Panel.FileTreeView;
+ private static StackPanel NoFolderMessage => Panel.NoFolderMessage;
- public async static void OpenProject()
+ public static async void OpenProject()
{
TopLevel topLevel = TopLevel.GetTopLevel(ApiVault.Get().GetMainWindow());
@@ -22,60 +28,150 @@ public async static void OpenProject()
AllowMultiple = false
});
- if (folder.Count == 0) return;
-
- FileTreeView.Items.Clear();
+ if (folder.Count == 0)
+ {
+ NoFolderMessage.IsVisible = true;
+ return;
+ }
+
+ NoFolderMessage.IsVisible = false;
+
+ ProjectRootFolder = new Folder(folder[0].Path.AbsolutePath)
+ { IsExpanded = true };
+ FileTreeView.ItemsSource = new ObservableCollection { ProjectRootFolder };
+ }
+
+ #region ContextMenu Creation
+
+ private static MenuFlyout CreateContextMenu(TreeViewItem treeViewItem, IStorageItem storageItem)
+ {
+ var commands = new[]
+ {
+ new { Header = "MenuHeaderNewFile", Command = new RelayCommand(() => CreateElement(treeViewItem, storageItem)), Icon = Symbol.New },
+ new { Header = "MenuHeaderNewFolder", Command = new RelayCommand(() => CreateElement(treeViewItem, storageItem, true)), Icon = Symbol.NewFolder },
+ new { Header = "MenuHeaderOpenInExplorer", Command = new RelayCommand(() => OpenInExplorer(storageItem)), Icon = Symbol.OpenLocal },
+ null,
+ new { Header = "MenuHeaderCopyPath", Command = new RelayCommand(() => CopyPath(storageItem)), Icon = Symbol.Copy },
+ new { Header = "MenuHeaderCopyAbsolutePath", Command = new RelayCommand(() => CopyPath(storageItem, true)), Icon = Symbol.Copy },
+ null,
+ new { Header = "MenuHeaderRename", Command = new RelayCommand(() => DeleteItem(storageItem)), Icon = Symbol.Rename },
+ new { Header = "MenuHeaderDelete", Command = new RelayCommand(() => DeleteItem(storageItem)), Icon = Symbol.Delete }
+ };
- foreach (IStorageFolder storageFolder in folder)
+ var contextMenu = new MenuFlyout();
+ List list = new List();
+ foreach (var item in commands)
{
- TreeViewItem rootFolder = new()
- {
- Header = storageFolder.Name,
- Tag = storageFolder.Path,
- IsExpanded = true,
- FontWeight = FontWeight.SemiBold
- };
+ if (item == null)
+ list.Add(new Separator());
+ else
+ list.Add(new MenuItem { Header = Translation.Get(item.Header), Command = item.Command, Icon = new SymbolIcon { Symbol = item.Icon, FontSize = 20 } });
+ }
- FileTreeView.Items.Add(rootFolder);
+ list.ForEach(item => contextMenu.Items.Add(item));
- AddChildren(rootFolder, storageFolder);
+ return contextMenu;
+ }
+
+ private static async void DeleteItem(IStorageItem storageItem)
+ {
+ if (storageItem is IStorageFolder storageFolder)
+ {
+ await storageFolder.DeleteAsync();
+
+ var parent = FileTreeView.SelectedItem as TreeViewItem;
+ parent.Items.Remove(parent);
+
+ SortTabItem(parent);
+ }
+ else
+ {
+ await storageItem.DeleteAsync();
+
+ var parent = FileTreeView.SelectedItem as TreeViewItem;
+ parent.Items.Remove(parent);
+
+ SortTabItem(parent);
}
}
-
- public async static void AddChildren(TreeViewItem viewItem, IStorageFolder folder)
+
+ private static void CreateElement(TreeViewItem treeViewItem,
+ IStorageItem storageItem, bool isFolder = false)
{
- await foreach (IStorageItem storageItem in folder.GetItemsAsync())
+ if (storageItem is IStorageFolder storageFolder)
{
- string path = Uri.UnescapeDataString(storageItem.Path.AbsolutePath);
- if (storageItem is IStorageFolder storageFolder)
+ if (!treeViewItem.IsExpanded)
+ treeViewItem.IsExpanded = true;
+
+ /*
+ TreeViewItem item = CreateInputItem(treeViewItem, async (name) =>
{
- TreeViewItem folderItem = new()
- {
- Header = Path.GetFileName(path),
- Tag = path,
- FontWeight = FontWeight.Medium,
- };
+ await Task.Delay(10).ContinueWith(_ => Dispatcher.UIThread.InvokeAsync(() => treeViewItem.IsExpanded = true));
- viewItem.Items.Add(folderItem);
+ IStorageItem newStorageItem;
+ if (isFolder)
+ newStorageItem = await storageFolder.CreateFolderAsync(name);
+ else
+ newStorageItem = await storageFolder.CreateFileAsync(name);
- AddChildren(folderItem, storageFolder);
- }
- else
+ TreeViewItem createdViewItem = CreateTreeViewItem(newStorageItem);
+ treeViewItem.IsExpanded = true;
+ treeViewItem.Items.Add(createdViewItem);
+
+ if (newStorageItem is IStorageFile)
+ FileHandler.OpenFile(newStorageItem.Path.AbsolutePath);
+ });
+
+ treeViewItem.Items.Insert(0, item);
+ item.Focus(NavigationMethod.Pointer); */
+ }
+ }
+
+ private static async void CopyPath(IStorageItem storageItem, bool absolutePath = false)
+ {
+ if (absolutePath)
+ {
+ await ApiVault.Get().GetMainWindow().Clipboard.SetTextAsync(storageItem.Path.AbsolutePath);
+ return;
+ }
+
+ IStorageFolder folder = storageItem as IStorageFolder;
+ while (folder != null && folder.Path.AbsolutePath != ProjectRootFolder?.StorageFolderPath)
+ folder = await folder.GetParentAsync();
+
+ if (folder == null)
+ return;
+
+ string path = storageItem.Path.AbsolutePath.Replace(folder.Path.AbsolutePath, "");
+ await ApiVault.Get().GetMainWindow().Clipboard.SetTextAsync(path);
+ }
+
+ private static void OpenInExplorer(IStorageItem storageItem)
+ {
+ if (storageItem is IStorageFolder storageFolder)
+ {
+ var path = storageFolder.Path.AbsolutePath;
+ Process.Start(new ProcessStartInfo
{
- TreeViewItem item = new()
- {
- Header = Path.GetFileName(path),
- Tag = path,
- FontWeight = FontWeight.Normal
- };
+ FileName = path,
+ UseShellExecute = true
+ });
+ }
+ }
- item.DoubleTapped += (sender, e) =>
- {
- FileHandler.OpenFile(path);
- };
+ #endregion
- viewItem.Items.Add(item);
- }
- }
+ #region Sorting
+
+ private static void SortTabItem(TreeViewItem parent)
+ {
+ var folders = parent.Items.OfType().Where(item => item.Tag is IStorageFolder).OrderBy(item => item.Header);
+ var files = parent.Items.OfType().Where(item => item.Tag is IStorageFile).OrderBy(item => item.Header);
+
+ parent.Items.Clear();
+ foreach (var folder in folders) parent.Items.Add(folder);
+ foreach (var file in files) parent.Items.Add(file);
}
+
+ #endregion
}
diff --git a/SkEditor/Views/Projects/CreateStorageElementWindow.axaml b/SkEditor/Views/Projects/CreateStorageElementWindow.axaml
new file mode 100644
index 00000000..f4b58f79
--- /dev/null
+++ b/SkEditor/Views/Projects/CreateStorageElementWindow.axaml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ File Name
+
+
+
+ File Template
+
+
+
+
+
+
+
+
+
diff --git a/SkEditor/Views/Projects/CreateStorageElementWindow.axaml.cs b/SkEditor/Views/Projects/CreateStorageElementWindow.axaml.cs
new file mode 100644
index 00000000..10a60a10
--- /dev/null
+++ b/SkEditor/Views/Projects/CreateStorageElementWindow.axaml.cs
@@ -0,0 +1,52 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using CommunityToolkit.Mvvm.Input;
+using FluentAvalonia.UI.Windowing;
+using SkEditor.Utilities;
+using SkEditor.Utilities.Projects.Elements;
+using SkEditor.Utilities.Styling;
+
+namespace SkEditor.Views.Projects;
+
+public partial class CreateStorageElementWindow : AppWindow
+{
+ public Folder Folder;
+ public bool IsFile;
+
+ public CreateStorageElementWindow(Folder folder, bool isFile)
+ {
+ Folder = folder;
+ IsFile = isFile;
+
+ InitializeComponent();
+ WindowStyler.Style(this);
+
+ FileNameTextBlock.Text = Translation.Get(isFile ? "ProjectCreateFileName" : "ProjectCreateFolderName");
+ FileTemplateTextBlock.Text = Translation.Get("ProjectCreateTemplate");
+
+ CreateButton.Command = new RelayCommand(Create);
+ }
+
+ private void Create()
+ {
+ var input = NameTextBox.Text;
+ string? error = Folder.ValidateCreationName(input);
+ if (error != null)
+ {
+ ErrorBox.Text = error;
+ return;
+ }
+
+ if (IsFile)
+ {
+ Folder.CreateFile(input);
+ }
+ else
+ {
+ Folder.CreateFolder(input);
+ }
+
+ Close();
+ }
+}
\ No newline at end of file
diff --git a/SkEditor/Views/Projects/RenameElementWindow.axaml b/SkEditor/Views/Projects/RenameElementWindow.axaml
new file mode 100644
index 00000000..1cb41cb6
--- /dev/null
+++ b/SkEditor/Views/Projects/RenameElementWindow.axaml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SkEditor/Views/Projects/RenameElementWindow.axaml.cs b/SkEditor/Views/Projects/RenameElementWindow.axaml.cs
new file mode 100644
index 00000000..586a01e0
--- /dev/null
+++ b/SkEditor/Views/Projects/RenameElementWindow.axaml.cs
@@ -0,0 +1,47 @@
+using Avalonia.Interactivity;
+using FluentAvalonia.UI.Windowing;
+using SkEditor.Utilities;
+using SkEditor.Utilities.Projects.Elements;
+using SkEditor.Utilities.Styling;
+
+namespace SkEditor.Views.Projects;
+
+public partial class RenameElementWindow : AppWindow
+{
+ public StorageElement Element { get; }
+
+ public RenameElementWindow(StorageElement element)
+ {
+ InitializeComponent();
+
+ Element = element;
+ NameBox.Text = element.Name;
+
+ WindowStyler.Style(this);
+ }
+
+ private void RenameButtonClick(object? sender, RoutedEventArgs e)
+ {
+ var input = NameBox.Text;
+ if (string.IsNullOrWhiteSpace(input))
+ {
+ ErrorBox.Text = Translation.Get("ProjectRenameErrorNameEmpty");
+ return;
+ }
+
+ var error = Element.ValidateName(input);
+ if (error != null)
+ {
+ ErrorBox.Text = error;
+ return;
+ }
+
+ Element.RenameElement(NameBox.Text);
+ Close();
+ }
+
+ private void Cancel(object? sender, RoutedEventArgs e)
+ {
+ Close();
+ }
+}
\ No newline at end of file