From e64acf03171fb293ca98ebb3471914ae99d667db Mon Sep 17 00:00:00 2001 From: Miku-666 <74728189+NessieHax@users.noreply.github.com> Date: Thu, 18 Apr 2024 19:07:19 +0200 Subject: [PATCH] Re-implemented Drag n drop (#26) * [WIP] MainForm - Re-implemented drag n drop * MainForm - Fix drag n drop issue for files * MainForm - Add drag n drop for external files * MainForm - Add folder drag n drop --- PCK-Studio/Extensions/TreeNodeExtensions.cs | 2 +- PCK-Studio/MainForm.Designer.cs | 4 + PCK-Studio/MainForm.cs | 140 ++++++++++++++++++-- Vendor/OMI-Lib | 2 +- 4 files changed, 134 insertions(+), 14 deletions(-) diff --git a/PCK-Studio/Extensions/TreeNodeExtensions.cs b/PCK-Studio/Extensions/TreeNodeExtensions.cs index 0fab1fcd..d6c70fe3 100644 --- a/PCK-Studio/Extensions/TreeNodeExtensions.cs +++ b/PCK-Studio/Extensions/TreeNodeExtensions.cs @@ -11,7 +11,7 @@ namespace PckStudio.Extensions { internal static bool IsTagOfType(this TreeNode node) where T : class { - return node.Tag is T; + return node?.Tag is T; } internal static bool TryGetTagData(this TreeNode node, out TOut tagData) where TOut : class diff --git a/PCK-Studio/MainForm.Designer.cs b/PCK-Studio/MainForm.Designer.cs index 91eecc45..48c707c4 100644 --- a/PCK-Studio/MainForm.Designer.cs +++ b/PCK-Studio/MainForm.Designer.cs @@ -1121,6 +1121,10 @@ this.treeViewMain.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.selectNode); this.treeViewMain.DoubleClick += new System.EventHandler(this.treeViewMain_DoubleClick); this.treeViewMain.KeyDown += new System.Windows.Forms.KeyEventHandler(this.treeViewMain_KeyDown); + this.treeViewMain.ItemDrag += new System.Windows.Forms.ItemDragEventHandler(this.treeViewMain_ItemDrag); + this.treeViewMain.DragDrop += new System.Windows.Forms.DragEventHandler(this.treeViewMain_DragDrop); + this.treeViewMain.DragEnter += new System.Windows.Forms.DragEventHandler(this.treeViewMain_DragEnter); + this.treeViewMain.DragOver += new System.Windows.Forms.DragEventHandler(this.treeViewMain_DragOver); // // imageList // diff --git a/PCK-Studio/MainForm.cs b/PCK-Studio/MainForm.cs index 992697a9..b5dddc51 100644 --- a/PCK-Studio/MainForm.cs +++ b/PCK-Studio/MainForm.cs @@ -1388,36 +1388,152 @@ namespace PckStudio #region drag and drop for main tree node - // Most of the code below is modified code from this link: https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.treeview.itemdrag?view=windowsdesktop-6.0 + // Most of the code below is modified code from this link: + // https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.treeview.itemdrag?view=windowsdesktop-6.0 // - MattNL private void treeViewMain_ItemDrag(object sender, ItemDragEventArgs e) { + if (e.Button != MouseButtons.Left || e.Item is not TreeNode node) + return; + if ((node.TryGetTagData(out PckFileData file) && currentPCK.Contains(file.Filename, file.Filetype)) || node.Parent is TreeNode) + { + treeViewMain.DoDragDrop(node, DragDropEffects.Move); + } } - // Set the target drop effect to the effect - // specified in the ItemDrag event handler. - private void treeViewMain_DragEnter(object sender, DragEventArgs e) - { - e.Effect = e.AllowedEffect; - } - - // Select the node under the mouse pointer to indicate the - // expected drop location. private void treeViewMain_DragOver(object sender, DragEventArgs e) { + Point dragLocation = new Point(e.X, e.Y); + TreeNode node = treeViewMain.GetNodeAt(treeViewMain.PointToClient(dragLocation)); + treeViewMain.SelectedNode = node.IsTagOfType() ? null : node; + } + private void treeViewMain_DragEnter(object sender, DragEventArgs e) + { + e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop) ? DragDropEffects.Copy : e.AllowedEffect; } private void treeViewMain_DragDrop(object sender, DragEventArgs e) { + if (e.Data.GetDataPresent(DataFormats.FileDrop) && e.Data.GetData(DataFormats.FileDrop) is string[] files) + { + ImportFiles(files); + return; + } + string dataFormat = typeof(TreeNode).FullName; + + if (!e.Data.GetDataPresent(dataFormat)) + return; + + // Retrieve the client coordinates of the drop location. + Point dragLocation = new Point(e.X, e.Y); + Point targetPoint = treeViewMain.PointToClient(dragLocation); + + if (!treeViewMain.ClientRectangle.Contains(targetPoint)) + return; + + // Retrieve the node at the drop location. + TreeNode targetNode = treeViewMain.GetNodeAt(targetPoint); + bool isTargetPckFile = targetNode.IsTagOfType(); + + if (e.Data.GetData(dataFormat) is not TreeNode draggedNode) + { + Debug.WriteLine("Dragged data was not of type TreeNode."); + return; + } + + if (targetNode.Equals(draggedNode.Parent)) + { + Debug.WriteLine("target node is parent of dragged node... nothing done."); + return; + } + + if (draggedNode.Equals(targetNode.Parent)) + { + Debug.WriteLine("dragged node is parent of target node... nothing done."); + return; + } + + if ((targetNode.Parent?.Equals(draggedNode.Parent) ?? false) && isTargetPckFile) + { + Debug.WriteLine("target node and dragged node have the same parent... nothing done."); + return; + } + + Debug.WriteLine($"Target drop location is {(isTargetPckFile ? "file" : "folder")}."); + + // Retrieve the node that was dragged. + if (draggedNode.TryGetTagData(out PckFileData draggedFile) && + targetNode.FullPath != draggedFile.Filename) + { + Debug.WriteLine(draggedFile.Filename + " was droped onto " + targetNode.FullPath); + string newFilePath = Path.Combine(isTargetPckFile + ? Path.GetDirectoryName(targetNode.FullPath) + : targetNode.FullPath, Path.GetFileName(draggedFile.Filename)); + Debug.WriteLine("New filepath: " + newFilePath); + draggedFile.Filename = newFilePath; + wasModified = true; + BuildMainTreeView(); + return; + } + else + { + List pckFiles = GetEndingNodes(draggedNode.Nodes).Where(t => t.IsTagOfType()).Select(t => t.Tag as PckFileData).ToList(); + string oldPath = draggedNode.FullPath; + string newPath = Path.Combine(isTargetPckFile ? Path.GetDirectoryName(targetNode.FullPath) : targetNode.FullPath, draggedNode.Text).Replace('\\', '/'); + foreach (var pckFile in pckFiles) + { + pckFile.Filename = Path.Combine(newPath, pckFile.Filename.Substring(oldPath.Length + 1)).Replace('\\', '/'); + } + wasModified = true; + BuildMainTreeView(); + } } - #endregion + private IEnumerable GetEndingNodes(TreeNodeCollection collection) + { + List trailingNodes = new List(collection.Count); + foreach (TreeNode node in collection) + { + if (node.Nodes.Count > 0) + { + trailingNodes.AddRange(GetEndingNodes(node.Nodes)); + continue; + } + trailingNodes.Add(node); + } + return trailingNodes; + } - private PckFile InitializePack(int packId, int packVersion, string packName, bool createSkinsPCK) + private void ImportFiles(string[] files) + { + int addedCount = 0; + foreach (var file in files) + { + using AddFilePrompt addFile = new AddFilePrompt(Path.GetFileName(file)); + if (addFile.ShowDialog(this) != DialogResult.OK) + continue; + + if (currentPCK.Contains(addFile.Filepath, addFile.Filetype)) + { + MessageBox.Show(this, $"'{addFile.Filepath}' of type {addFile.Filetype} already exists.", "Import failed", MessageBoxButtons.OK, MessageBoxIcon.Warning); + continue; + } + currentPCK.CreateNewFile(addFile.Filepath, addFile.Filetype, () => File.ReadAllBytes(file)); + addedCount++; + + BuildMainTreeView(); + wasModified = true; + } + Trace.TraceInformation("[{0}] Imported {1} file(s).", nameof(ImportFiles), addedCount); + } + + #endregion + + private PckFile InitializePack(int packId, int packVersion, string packName, bool createSkinsPCK) { var pack = new PckFile(3); diff --git a/Vendor/OMI-Lib b/Vendor/OMI-Lib index 637772bf..91878fe5 160000 --- a/Vendor/OMI-Lib +++ b/Vendor/OMI-Lib @@ -1 +1 @@ -Subproject commit 637772bfb63bf93e1b91e5d18c191c1a616598b3 +Subproject commit 91878fe55cb937bd7538685646bb2f3e15f2af82