mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Asset browser: Copy, cut, paste
This commit is contained in:
@@ -11,6 +11,7 @@ using GlitchyEngine;
|
|||||||
using GlitchyEditor.Assets;
|
using GlitchyEditor.Assets;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using GlitchyEditor.CodeEditors;
|
using GlitchyEditor.CodeEditors;
|
||||||
|
using GlitchyEditor.Multithreading;
|
||||||
|
|
||||||
namespace GlitchyEditor.EditWindows
|
namespace GlitchyEditor.EditWindows
|
||||||
{
|
{
|
||||||
@@ -197,6 +198,9 @@ namespace GlitchyEditor.EditWindows
|
|||||||
|
|
||||||
private append List<String> _selectedFiles = .() ~ ClearAndDeleteItems!(_);
|
private append List<String> _selectedFiles = .() ~ ClearAndDeleteItems!(_);
|
||||||
|
|
||||||
|
private append List<String> _filesToCopy = .() ~ ClearAndDeleteItems!(_);
|
||||||
|
private bool _cutFiles = false;
|
||||||
|
|
||||||
private append String _assetToRename = .();
|
private append String _assetToRename = .();
|
||||||
private char8[128] _renameFileNameBuffer;
|
private char8[128] _renameFileNameBuffer;
|
||||||
|
|
||||||
@@ -591,6 +595,13 @@ namespace GlitchyEditor.EditWindows
|
|||||||
}
|
}
|
||||||
|
|
||||||
ImGui.AttachTooltip("Opens the C# Solution of this project.");
|
ImGui.AttachTooltip("Opens the C# Solution of this project.");
|
||||||
|
|
||||||
|
ImGui.Separator();
|
||||||
|
|
||||||
|
if (!_filesToCopy.IsEmpty && ImGui.MenuItem("Paste", "Ctrl+V"))
|
||||||
|
{
|
||||||
|
PasteFiles(CurrentDirectory);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shows the menu for the given asset creator tree.
|
/// Shows the menu for the given asset creator tree.
|
||||||
@@ -767,6 +778,24 @@ namespace GlitchyEditor.EditWindows
|
|||||||
{
|
{
|
||||||
NavigateForward();
|
NavigateForward();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Input.IsKeyPressed(.Control))
|
||||||
|
{
|
||||||
|
if (Input.IsKeyPressing(.C))
|
||||||
|
{
|
||||||
|
CopySelectedFiles(cutFiles: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Input.IsKeyPressing(.X))
|
||||||
|
{
|
||||||
|
CopySelectedFiles(cutFiles: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Input.IsKeyPressing(.V))
|
||||||
|
{
|
||||||
|
PasteFiles(CurrentDirectory);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<TreeNode<AssetNode>> directoryEntries = scope List<TreeNode<AssetNode>>();
|
List<TreeNode<AssetNode>> directoryEntries = scope List<TreeNode<AssetNode>>();
|
||||||
@@ -943,7 +972,14 @@ namespace GlitchyEditor.EditWindows
|
|||||||
// TODO: Special Icon for back-folder?
|
// TODO: Special Icon for back-folder?
|
||||||
SubTexture2D image = _thumbnailManager.GetThumbnail(entry.Value);
|
SubTexture2D image = _thumbnailManager.GetThumbnail(entry.Value);
|
||||||
|
|
||||||
ImGui.ImageButton("FileImage", image, (.)IconSize);
|
ColorRGBA imageColor = ColorRGBA.White;
|
||||||
|
|
||||||
|
if (_filesToCopy.Contains(entry->Path) && _cutFiles)
|
||||||
|
{
|
||||||
|
imageColor = ColorRGBA(1, 1, 1, 0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.ImageButton("FileImage", image, (.)IconSize, tint_col: (.)(float4)imageColor);
|
||||||
|
|
||||||
if (ImGui.IsRectangleSelecting(ref _rectangleSelection))
|
if (ImGui.IsRectangleSelecting(ref _rectangleSelection))
|
||||||
{
|
{
|
||||||
@@ -1276,6 +1312,23 @@ namespace GlitchyEditor.EditWindows
|
|||||||
|
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
|
|
||||||
|
if (ImGui.MenuItem("Cut", "Ctrl+X"))
|
||||||
|
{
|
||||||
|
CopySelectedFiles(cutFiles: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.MenuItem("Copy", "Ctrl+C"))
|
||||||
|
{
|
||||||
|
CopySelectedFiles(cutFiles: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_filesToCopy.IsEmpty && singleEntry && parent != null && ImGui.MenuItem("Paste", "Ctrl+V"))
|
||||||
|
{
|
||||||
|
PasteFiles(parent->Path);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Separator();
|
||||||
|
|
||||||
if (ImGui.MenuItem("Rename"))
|
if (ImGui.MenuItem("Rename"))
|
||||||
{
|
{
|
||||||
// Copy the path, just for the rare case that fileOrFolder gets deleted
|
// Copy the path, just for the rare case that fileOrFolder gets deleted
|
||||||
@@ -1297,6 +1350,31 @@ namespace GlitchyEditor.EditWindows
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CopySelectedFiles(bool cutFiles)
|
||||||
|
{
|
||||||
|
_filesToCopy.ClearAndDeleteItems();
|
||||||
|
_selectedFiles.Select((file) => new String(file)).ToList(_filesToCopy);
|
||||||
|
_cutFiles = cutFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PasteFiles(StringView targetDirectoryPath)
|
||||||
|
{
|
||||||
|
BackgroundTask backgroundTask;
|
||||||
|
if (_cutFiles)
|
||||||
|
{
|
||||||
|
backgroundTask = new MoveFilesBackgroundTask(_filesToCopy, targetDirectoryPath);
|
||||||
|
_filesToCopy.ClearAndDeleteItems();
|
||||||
|
_cutFiles = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
backgroundTask = new CopyBackgroundTask(_filesToCopy, targetDirectoryPath);
|
||||||
|
}
|
||||||
|
backgroundTask.DeleteWhenEnded = true;
|
||||||
|
|
||||||
|
EditorApp.Instance.BackgroundTaskManager.StartBackgroundTask(backgroundTask);
|
||||||
|
}
|
||||||
|
|
||||||
private void OpenPropertiesWindow(TreeNode<AssetNode> fileOrFolder)
|
private void OpenPropertiesWindow(TreeNode<AssetNode> fileOrFolder)
|
||||||
{
|
{
|
||||||
AssetHandle? assetHandle = fileOrFolder->AssetFile?.AssetConfig?.AssetHandle;
|
AssetHandle? assetHandle = fileOrFolder->AssetFile?.AssetConfig?.AssetHandle;
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ class CopyBackgroundTask : BackgroundTask
|
|||||||
|
|
||||||
if (Directory.Exists(targetPath) || _targetPaths.Contains(targetPath))
|
if (Directory.Exists(targetPath) || _targetPaths.Contains(targetPath))
|
||||||
{
|
{
|
||||||
if (CurrentFileMode.HasFlag(.KeepBoth))
|
if (CurrentFileMode.HasFlag(.KeepBoth) || targetPath == sourcePath)
|
||||||
{
|
{
|
||||||
Path.FindFreePath(_targetDirectoryPath, fileName, "", targetPath, fileName, _targetPaths);
|
Path.FindFreePath(_targetDirectoryPath, fileName, "", targetPath, fileName, _targetPaths);
|
||||||
}
|
}
|
||||||
@@ -184,7 +184,7 @@ class CopyBackgroundTask : BackgroundTask
|
|||||||
|
|
||||||
if (File.Exists(targetPath) || _targetPaths.Contains(targetPath))
|
if (File.Exists(targetPath) || _targetPaths.Contains(targetPath))
|
||||||
{
|
{
|
||||||
if (CurrentFileMode.HasFlag(.KeepBoth))
|
if (CurrentFileMode.HasFlag(.KeepBoth) || targetPath == sourcePath)
|
||||||
{
|
{
|
||||||
let fileExtension = scope String();
|
let fileExtension = scope String();
|
||||||
Path.GetExtension(targetPath, fileExtension);
|
Path.GetExtension(targetPath, fileExtension);
|
||||||
|
|||||||
@@ -0,0 +1,517 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using ImGui;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace GlitchyEditor.Multithreading;
|
||||||
|
|
||||||
|
class MoveFilesBackgroundTask : BackgroundTask
|
||||||
|
{
|
||||||
|
private List<String> _sourcePath ~ {ClearAndDeleteItems!(_); delete:append _;};
|
||||||
|
private String _targetDirectoryPath ~ delete:append _;
|
||||||
|
|
||||||
|
private int _totalEntriesToMove;
|
||||||
|
private append Queue<CopyInfo> _pathsToMove = .() ~ ClearAndDeleteItems!(_);
|
||||||
|
private append Queue<CopyInfo> _scanQueue = .() ~ ClearAndDeleteItems!(_);
|
||||||
|
/// Contains the file paths, that will definitely exist after copying. This is used for file renaming during scanning.
|
||||||
|
private append HashSet<StringView> _targetPaths = .();
|
||||||
|
|
||||||
|
private enum ConflictResolutionMode
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
OverwriteFile = 1,
|
||||||
|
KeepBoth = 2,
|
||||||
|
CombineDirectories = 4,
|
||||||
|
SkipFiles = 8,
|
||||||
|
SkipDirectories = 16,
|
||||||
|
SkipNotFound = 32,
|
||||||
|
IgnoreUnexpectedErrors = 64
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConflictResolutionMode _nextFileMode;
|
||||||
|
private ConflictResolutionMode _allFilesMode;
|
||||||
|
|
||||||
|
private ConflictResolutionMode CurrentFileMode => _nextFileMode | _allFilesMode;
|
||||||
|
|
||||||
|
private class CopyInfo
|
||||||
|
{
|
||||||
|
public append String SourcePath = .();
|
||||||
|
// If this entry is actually inside a directory we copy, this contains the path of this entry inside this directory.
|
||||||
|
public append String SubPath = .();
|
||||||
|
public append String TargetPath = .();
|
||||||
|
public ConflictResolutionMode ConflictResolutionMode;
|
||||||
|
|
||||||
|
[AllowAppend]
|
||||||
|
public this(StringView sourcePath, StringView targetPath, ConflictResolutionMode conflictResolutionMode)
|
||||||
|
{
|
||||||
|
SourcePath.Set(sourcePath);
|
||||||
|
TargetPath.Set(targetPath);
|
||||||
|
ConflictResolutionMode = conflictResolutionMode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ScanningFiles => !_scanQueue.IsEmpty;
|
||||||
|
|
||||||
|
[AllowAppend]
|
||||||
|
public this(List<String> sourcePaths, StringView targetDirectoryPath)
|
||||||
|
{
|
||||||
|
List<String> sourcePathList = append List<String>(sourcePaths.Count);
|
||||||
|
String targetDirectoryPathStr = append String(targetDirectoryPath);
|
||||||
|
|
||||||
|
_sourcePath = sourcePathList;
|
||||||
|
_targetDirectoryPath = targetDirectoryPathStr;
|
||||||
|
|
||||||
|
for (String path in sourcePaths)
|
||||||
|
{
|
||||||
|
_sourcePath.Add(new String(path));
|
||||||
|
_scanQueue.Add(new CopyInfo(path, "", .None));
|
||||||
|
}
|
||||||
|
|
||||||
|
_totalEntriesToMove = sourcePaths.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum CopyError : IDisposable
|
||||||
|
{
|
||||||
|
case None;
|
||||||
|
case TargetDirectoryIsNotDirectory;
|
||||||
|
case TargetFileExists(String FileName);
|
||||||
|
case TargetDirectoryExists(String DirectoryName);
|
||||||
|
case EntryNotFound(String SourcePath);
|
||||||
|
case UnexpectedError(String Message);
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
switch (this)
|
||||||
|
{
|
||||||
|
case .None:
|
||||||
|
case .TargetDirectoryIsNotDirectory:
|
||||||
|
case .TargetFileExists(let FileName):
|
||||||
|
delete FileName;
|
||||||
|
case .TargetDirectoryExists(let DirectoryName):
|
||||||
|
delete DirectoryName;
|
||||||
|
case .EntryNotFound(let SourcePath):
|
||||||
|
delete SourcePath;
|
||||||
|
case .UnexpectedError(let Message):
|
||||||
|
delete Message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result<void, CopyError> CollectFilesToMove()
|
||||||
|
{
|
||||||
|
CopyInfo currentEntry = null;
|
||||||
|
defer
|
||||||
|
{
|
||||||
|
if (currentEntry != null && @return case .Err)
|
||||||
|
{
|
||||||
|
_scanQueue.AddFront(currentEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddToMoveQueue(CopyInfo entry, StringView targetPath, ConflictResolutionMode conflictResolutionMode)
|
||||||
|
{
|
||||||
|
entry.TargetPath.Set(targetPath);
|
||||||
|
entry.ConflictResolutionMode = conflictResolutionMode;
|
||||||
|
_pathsToMove.Add(entry);
|
||||||
|
_targetPaths.Add(entry.TargetPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!_scanQueue.IsEmpty && Running)
|
||||||
|
{
|
||||||
|
currentEntry = _scanQueue.PopFront();
|
||||||
|
|
||||||
|
let sourcePath = (StringView)currentEntry.SourcePath;
|
||||||
|
|
||||||
|
let fileName = scope String();
|
||||||
|
Path.GetFileName(sourcePath, fileName);
|
||||||
|
|
||||||
|
let targetPath = scope String();
|
||||||
|
Path.Combine(targetPath, _targetDirectoryPath, currentEntry.SubPath, fileName);
|
||||||
|
|
||||||
|
if (Directory.Exists(sourcePath))
|
||||||
|
{
|
||||||
|
bool skip = false;
|
||||||
|
|
||||||
|
if (Directory.Exists(targetPath) || _targetPaths.Contains(targetPath))
|
||||||
|
{
|
||||||
|
if (CurrentFileMode.HasFlag(.KeepBoth))
|
||||||
|
{
|
||||||
|
Path.FindFreePath(_targetDirectoryPath, fileName, "", targetPath, fileName, _targetPaths);
|
||||||
|
}
|
||||||
|
else if (CurrentFileMode.HasFlag(.SkipDirectories))
|
||||||
|
{
|
||||||
|
skip = true;
|
||||||
|
}
|
||||||
|
else if (Enum.HasAnyFlag(CurrentFileMode, .CombineDirectories))
|
||||||
|
{
|
||||||
|
// Intentionally do nothing.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return .Err(.TargetDirectoryExists(new String(fileName)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skip)
|
||||||
|
{
|
||||||
|
delete currentEntry;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Current node is ready, add it to move-queue.
|
||||||
|
AddToMoveQueue(currentEntry, targetPath, CurrentFileMode);
|
||||||
|
|
||||||
|
if (Enum.HasAnyFlag(CurrentFileMode, .CombineDirectories))
|
||||||
|
{
|
||||||
|
// Add nested files and directories to the scan-queue.
|
||||||
|
for (FileFindEntry e in Directory.Enumerate(currentEntry.SourcePath))
|
||||||
|
{
|
||||||
|
let entryPath = scope String();
|
||||||
|
e.GetFilePath(entryPath);
|
||||||
|
|
||||||
|
let newEntry = new CopyInfo(entryPath, targetPath, .None);
|
||||||
|
_scanQueue.Add(newEntry);
|
||||||
|
|
||||||
|
Path.Combine(newEntry.SubPath, currentEntry.SubPath, fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_nextFileMode = .None;
|
||||||
|
}
|
||||||
|
else if (File.Exists(sourcePath))
|
||||||
|
{
|
||||||
|
bool skip = false;
|
||||||
|
|
||||||
|
if (File.Exists(targetPath) || _targetPaths.Contains(targetPath))
|
||||||
|
{
|
||||||
|
if (CurrentFileMode.HasFlag(.KeepBoth))
|
||||||
|
{
|
||||||
|
let fileExtension = scope String();
|
||||||
|
Path.GetExtension(targetPath, fileExtension);
|
||||||
|
|
||||||
|
StringView fileNameWithoutExtension = fileName.Substring(0..<^fileExtension.Length);
|
||||||
|
|
||||||
|
Path.FindFreePath(_targetDirectoryPath, fileNameWithoutExtension, fileExtension, targetPath, fileName, _targetPaths);
|
||||||
|
}
|
||||||
|
else if (CurrentFileMode.HasFlag(.SkipFiles))
|
||||||
|
{
|
||||||
|
skip = true;
|
||||||
|
}
|
||||||
|
else if (Enum.HasAnyFlag(CurrentFileMode, .OverwriteFile))
|
||||||
|
{
|
||||||
|
// Intentionally do nothing.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return .Err(.TargetFileExists(new String(fileName)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skip)
|
||||||
|
{
|
||||||
|
delete currentEntry;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddToMoveQueue(currentEntry, targetPath, CurrentFileMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
_nextFileMode = .None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_totalEntriesToMove = _pathsToMove.Count;
|
||||||
|
|
||||||
|
return .Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CopyError _currentError = .None ~ _.Dispose();
|
||||||
|
|
||||||
|
public override RunResult Run()
|
||||||
|
{
|
||||||
|
_currentError.Dispose();
|
||||||
|
_currentError = .None;
|
||||||
|
if (CollectFilesToMove() case .Err(out _currentError) || Paused)
|
||||||
|
{
|
||||||
|
return .Pause;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!_pathsToMove.IsEmpty && Running)
|
||||||
|
{
|
||||||
|
CopyInfo currentPath = _pathsToMove.Peek();
|
||||||
|
|
||||||
|
if (MovePath(currentPath) case .Err(out _currentError) || Paused)
|
||||||
|
{
|
||||||
|
return .Pause;
|
||||||
|
}
|
||||||
|
|
||||||
|
_pathsToMove.PopFront();
|
||||||
|
delete currentPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
return .Finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result<void, CopyError> MovePath(CopyInfo copyInfo)
|
||||||
|
{
|
||||||
|
if (Directory.Exists(copyInfo.SourcePath))
|
||||||
|
{
|
||||||
|
if (Directory.Exists(copyInfo.TargetPath))
|
||||||
|
{
|
||||||
|
if (copyInfo.ConflictResolutionMode.HasFlag(.CombineDirectories))
|
||||||
|
{
|
||||||
|
// We don't have to do anything, because we will be using the target directory.
|
||||||
|
return .Ok;
|
||||||
|
}
|
||||||
|
else if (!CurrentFileMode.HasFlag(.IgnoreUnexpectedErrors))
|
||||||
|
{
|
||||||
|
return .Err(.UnexpectedError(new $"The target directory already exists, but it wasn't properly handled during the scanning phase."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Directory.Move(copyInfo.SourcePath, copyInfo.TargetPath) case .Err(let err) &&
|
||||||
|
!CurrentFileMode.HasFlag(.IgnoreUnexpectedErrors))
|
||||||
|
{
|
||||||
|
return .Err(.UnexpectedError(new $"Failed to move Directory {copyInfo.TargetPath}: {err}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (File.Exists(copyInfo.SourcePath))
|
||||||
|
{
|
||||||
|
bool forceOverwrite = false;
|
||||||
|
if (File.Exists(copyInfo.TargetPath))
|
||||||
|
{
|
||||||
|
if (copyInfo.ConflictResolutionMode.HasFlag(.OverwriteFile))
|
||||||
|
{
|
||||||
|
forceOverwrite = true;
|
||||||
|
}
|
||||||
|
else if (!CurrentFileMode.HasFlag(.IgnoreUnexpectedErrors))
|
||||||
|
{
|
||||||
|
return .Err(.UnexpectedError(new $"The target file already exists, but it wasn't properly handled during the scanning phase."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (File.Move(copyInfo.SourcePath, copyInfo.TargetPath) case .Err(let err) &&
|
||||||
|
!CurrentFileMode.HasFlag(.IgnoreUnexpectedErrors))
|
||||||
|
{
|
||||||
|
return .Err(.UnexpectedError(new $"Failed to move File {copyInfo.TargetPath}: {err}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (copyInfo.ConflictResolutionMode.HasFlag(.SkipNotFound))
|
||||||
|
return .Ok;
|
||||||
|
else
|
||||||
|
return .Err(.EntryNotFound(new String(copyInfo.SourcePath)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return .Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnRenderPopup()
|
||||||
|
{
|
||||||
|
String title = scope .("Copying files...");
|
||||||
|
|
||||||
|
if (ImGui.Begin(title, null, .NoDocking | .NoCollapse | .Modal | .NoResize | .AlwaysAutoResize))
|
||||||
|
{
|
||||||
|
if (ScanningFiles)
|
||||||
|
{
|
||||||
|
ImGui.ProgressBar(-1.0f * (float)ImGui.GetTime(), .(-1, 0), scope $"Found {_pathsToMove.Count} files...");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int copiedFiles = _totalEntriesToMove - _pathsToMove.Count;
|
||||||
|
|
||||||
|
ImGui.ProgressBar(copiedFiles / _totalEntriesToMove, .(-1, 0), scope $"Copied {copiedFiles} / {_totalEntriesToMove} files.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
switch (_currentError)
|
||||||
|
{
|
||||||
|
case .TargetFileExists(let fileName):
|
||||||
|
ImGui.PushStyleColor(.Text, 0xFF0000FF);
|
||||||
|
ImGui.TextUnformatted(scope $"A file with the name \"{fileName}\" already exists.");
|
||||||
|
ImGui.PopStyleColor();
|
||||||
|
case .TargetDirectoryExists(let directoryName):
|
||||||
|
ImGui.PushStyleColor(.Text, 0xFF0000FF);
|
||||||
|
ImGui.TextUnformatted(scope $"A directory with the name \"{directoryName}\" already exists.");
|
||||||
|
ImGui.PopStyleColor();
|
||||||
|
case .EntryNotFound(let SourcePath):
|
||||||
|
ImGui.PushStyleColor(.Text, 0xFF0000FF);
|
||||||
|
ImGui.TextUnformatted(scope $"\"{SourcePath}\" doesn't exist.");
|
||||||
|
ImGui.PopStyleColor();
|
||||||
|
case .UnexpectedError(let Message):
|
||||||
|
ImGui.PushStyleColor(.Text, 0xFF0000FF);
|
||||||
|
ImGui.TextUnformatted(scope $"Unexpected error: {Message}");
|
||||||
|
ImGui.PopStyleColor();
|
||||||
|
default:
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.BeginTable("buttonTable", 2))
|
||||||
|
{
|
||||||
|
switch (_currentError)
|
||||||
|
{
|
||||||
|
case .None:
|
||||||
|
// Do nothing
|
||||||
|
case .TargetDirectoryIsNotDirectory:
|
||||||
|
// This shouldn't be possible
|
||||||
|
Debug.Break();
|
||||||
|
case .TargetFileExists(let fileName):
|
||||||
|
ImGui.TableNextRow();
|
||||||
|
ImGui.TableSetColumnIndex(0);
|
||||||
|
|
||||||
|
if (ImGui.Button("Overwrite the target file."))
|
||||||
|
{
|
||||||
|
_nextFileMode = .OverwriteFile;
|
||||||
|
Continue();
|
||||||
|
}
|
||||||
|
ImGui.TableSetColumnIndex(1);
|
||||||
|
if (ImGui.Button("Overwrite all conflicting target files."))
|
||||||
|
{
|
||||||
|
_allFilesMode |= .OverwriteFile;
|
||||||
|
Continue();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.TableNextRow();
|
||||||
|
ImGui.TableSetColumnIndex(0);
|
||||||
|
|
||||||
|
if (ImGui.Button("Rename copied file."))
|
||||||
|
{
|
||||||
|
_nextFileMode = .KeepBoth;
|
||||||
|
Continue();
|
||||||
|
}
|
||||||
|
ImGui.TableSetColumnIndex(1);
|
||||||
|
if (ImGui.Button("Rename all conflicting copied files."))
|
||||||
|
{
|
||||||
|
_allFilesMode |= .KeepBoth;
|
||||||
|
Continue();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.TableNextRow();
|
||||||
|
ImGui.TableSetColumnIndex(0);
|
||||||
|
|
||||||
|
if (ImGui.Button("Skip this file."))
|
||||||
|
{
|
||||||
|
_nextFileMode = .SkipFiles;
|
||||||
|
Continue();
|
||||||
|
}
|
||||||
|
ImGui.TableSetColumnIndex(1);
|
||||||
|
if (ImGui.Button("Skip all conflicting files."))
|
||||||
|
{
|
||||||
|
_allFilesMode |= .SkipFiles;
|
||||||
|
Continue();
|
||||||
|
}
|
||||||
|
|
||||||
|
case .TargetDirectoryExists(let directoryName):
|
||||||
|
ImGui.TableNextRow();
|
||||||
|
ImGui.TableSetColumnIndex(0);
|
||||||
|
|
||||||
|
if (ImGui.Button("Combine with target."))
|
||||||
|
{
|
||||||
|
_nextFileMode |= .CombineDirectories;
|
||||||
|
Continue();
|
||||||
|
}
|
||||||
|
ImGui.TableSetColumnIndex(1);
|
||||||
|
if (ImGui.Button("Combine all conflicting directories."))
|
||||||
|
{
|
||||||
|
_allFilesMode |= .CombineDirectories;
|
||||||
|
Continue();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.TableNextRow();
|
||||||
|
ImGui.TableSetColumnIndex(0);
|
||||||
|
|
||||||
|
if (ImGui.Button("Rename copied directory."))
|
||||||
|
{
|
||||||
|
_nextFileMode |= .KeepBoth;
|
||||||
|
Continue();
|
||||||
|
}
|
||||||
|
ImGui.TableSetColumnIndex(1);
|
||||||
|
if (ImGui.Button("Rename all conflicting directories."))
|
||||||
|
{
|
||||||
|
_allFilesMode |= .KeepBoth;
|
||||||
|
Continue();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.TableNextRow();
|
||||||
|
ImGui.TableSetColumnIndex(0);
|
||||||
|
|
||||||
|
if (ImGui.Button("Skip this directory."))
|
||||||
|
{
|
||||||
|
_nextFileMode |= .SkipDirectories;
|
||||||
|
Continue();
|
||||||
|
}
|
||||||
|
ImGui.TableSetColumnIndex(1);
|
||||||
|
if (ImGui.Button("Skip all conflicting directories."))
|
||||||
|
{
|
||||||
|
_allFilesMode |= .SkipFiles;
|
||||||
|
Continue();
|
||||||
|
}
|
||||||
|
case .EntryNotFound(let SourcePath):
|
||||||
|
if (ImGui.Button("Skip"))
|
||||||
|
{
|
||||||
|
_nextFileMode |= .SkipNotFound;
|
||||||
|
Continue();
|
||||||
|
}
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImGui.Button("Skip all"))
|
||||||
|
{
|
||||||
|
_allFilesMode |= .SkipNotFound;
|
||||||
|
Continue();
|
||||||
|
}
|
||||||
|
case .UnexpectedError(let Message):
|
||||||
|
if (ImGui.Button("Retry"))
|
||||||
|
{
|
||||||
|
Continue();
|
||||||
|
}
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImGui.Button("Ignore"))
|
||||||
|
{
|
||||||
|
_nextFileMode |= .IgnoreUnexpectedErrors;
|
||||||
|
Continue();
|
||||||
|
}
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImGui.Button("Ignore all unexpected"))
|
||||||
|
{
|
||||||
|
_allFilesMode |= .IgnoreUnexpectedErrors;
|
||||||
|
Continue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.TableNextRow();
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
|
||||||
|
if (_currentError case .None)
|
||||||
|
{
|
||||||
|
if (Paused)
|
||||||
|
{
|
||||||
|
if (ImGui.Button("Continue"))
|
||||||
|
{
|
||||||
|
Continue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ImGui.Button("Pause"))
|
||||||
|
{
|
||||||
|
Pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.Button("Cancel"))
|
||||||
|
{
|
||||||
|
Abort();
|
||||||
|
}
|
||||||
|
ImGui.EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.End();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user