mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-19 23:24:18 +01:00
dragdrop
This commit is contained in:
parent
f07b4d5719
commit
c76cbbd518
7 changed files with 258 additions and 1 deletions
|
|
@ -1,12 +1,13 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Windows.Forms;
|
||||||
using Dalamud.Configuration.Internal;
|
using Dalamud.Configuration.Internal;
|
||||||
using Dalamud.Game.Command;
|
using Dalamud.Game.Command;
|
||||||
using Dalamud.Interface.Windowing;
|
using Dalamud.Interface.Windowing;
|
||||||
using Dalamud.Logging;
|
using Dalamud.Logging;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using Dalamud.Utility;
|
using Dalamud.Utility;
|
||||||
|
using PInvoke;
|
||||||
|
|
||||||
namespace Dalamud.CorePlugin
|
namespace Dalamud.CorePlugin
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="System.Collections.Immutable" Version="7.0.0" />
|
<PackageReference Include="System.Collections.Immutable" Version="7.0.0" />
|
||||||
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
|
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.Interop" Version="17.0" />
|
||||||
<PackageReference Include="System.Reactive" Version="5.0.0" />
|
<PackageReference Include="System.Reactive" Version="5.0.0" />
|
||||||
<PackageReference Include="System.Reflection.MetadataLoadContext" Version="7.0.0" />
|
<PackageReference Include="System.Reflection.MetadataLoadContext" Version="7.0.0" />
|
||||||
<PackageReference Include="System.Resources.Extensions" Version="7.0.0" />
|
<PackageReference Include="System.Resources.Extensions" Version="7.0.0" />
|
||||||
|
|
|
||||||
74
Dalamud/Interface/DragDrop/DragDropInterop.cs
Normal file
74
Dalamud/Interface/DragDrop/DragDropInterop.cs
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace Dalamud.Interface.DragDrop;
|
||||||
|
|
||||||
|
internal partial class DragDropManager
|
||||||
|
{
|
||||||
|
private static class DragDropInterop
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
public enum ModifierKeys
|
||||||
|
{
|
||||||
|
MK_NONE = 0x00,
|
||||||
|
MK_LBUTTON = 0x01,
|
||||||
|
MK_RBUTTON = 0x02,
|
||||||
|
MK_SHIFT = 0x04,
|
||||||
|
MK_CONTROL = 0x08,
|
||||||
|
MK_MBUTTON = 0x10,
|
||||||
|
MK_ALT = 0x20,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ClipboardFormat
|
||||||
|
{
|
||||||
|
CF_TEXT = 1,
|
||||||
|
CF_BITMAP = 2,
|
||||||
|
CF_DIB = 3,
|
||||||
|
CF_UNICODETEXT = 13,
|
||||||
|
CF_HDROP = 15,
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum DVAspect
|
||||||
|
{
|
||||||
|
DVASPECT_CONTENT = 0x01,
|
||||||
|
DVASPECT_THUMBNAIL = 0x02,
|
||||||
|
DVASPECT_ICON = 0x04,
|
||||||
|
DVASPECT_DOCPRINT = 0x08,
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum TYMED
|
||||||
|
{
|
||||||
|
TYMED_NULL = 0x00,
|
||||||
|
TYMED_HGLOBAL = 0x01,
|
||||||
|
TYMED_FILE = 0x02,
|
||||||
|
TYMED_ISTREAM = 0x04,
|
||||||
|
TYMED_ISTORAGE = 0x08,
|
||||||
|
TYMED_GDI = 0x10,
|
||||||
|
TYMED_MFPICT = 0x20,
|
||||||
|
TYMED_ENHMF = 0x40,
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum DropEffects : uint
|
||||||
|
{
|
||||||
|
None = 0x00_0000_00,
|
||||||
|
Copy = 0x00_0000_01,
|
||||||
|
Move = 0x00_0000_02,
|
||||||
|
Link = 0x00_0000_04,
|
||||||
|
Scroll = 0x80_0000_00,
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("ole32.dll")]
|
||||||
|
public static extern int RegisterDragDrop(nint hwnd, IDropTarget pDropTarget);
|
||||||
|
|
||||||
|
[DllImport("ole32.dll")]
|
||||||
|
public static extern int RevokeDragDrop(nint hwnd);
|
||||||
|
|
||||||
|
[DllImport("shell32.dll")]
|
||||||
|
public static extern int DragQueryFile(IntPtr hDrop, uint iFile, StringBuilder lpszFile, int cch);
|
||||||
|
}
|
||||||
|
}
|
||||||
106
Dalamud/Interface/DragDrop/DragDropManager.cs
Normal file
106
Dalamud/Interface/DragDrop/DragDropManager.cs
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
using ImGuiNET;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace Dalamud.Interface.DragDrop;
|
||||||
|
|
||||||
|
internal partial class DragDropManager : IDisposable, IDragDropManager
|
||||||
|
{
|
||||||
|
private readonly UiBuilder uiBuilder;
|
||||||
|
|
||||||
|
public DragDropManager(UiBuilder uiBuilder)
|
||||||
|
=> this.uiBuilder = uiBuilder;
|
||||||
|
|
||||||
|
public void Enable()
|
||||||
|
{
|
||||||
|
if (this.ServiceAvailable)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var ret2 = DragDropInterop.RegisterDragDrop(this.uiBuilder.WindowHandlePtr, this);
|
||||||
|
Marshal.ThrowExceptionForHR(ret2);
|
||||||
|
this.ServiceAvailable = true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error($"Could not create windows drag and drop utility:\n{ex}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (!this.ServiceAvailable)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ServiceAvailable { get; internal set; }
|
||||||
|
|
||||||
|
public bool IsDragging { get; private set; }
|
||||||
|
|
||||||
|
public IReadOnlyList<string> Files { get; private set; } = Array.Empty<string>();
|
||||||
|
|
||||||
|
public IReadOnlySet<string> Extensions { get; private set; } = new HashSet<string>();
|
||||||
|
|
||||||
|
public IReadOnlyList<string> Directories { get; private set; } = Array.Empty<string>();
|
||||||
|
|
||||||
|
/// <inheritdoc cref="IDragDropManager.CreateImGuiSource(string, Func{IDragDropManager, bool}, Func{IDragDropManager, bool})"/>
|
||||||
|
public void CreateImGuiSource(string label, Func<IDragDropManager, bool> validityCheck, Func<IDragDropManager, bool> tooltipBuilder)
|
||||||
|
{
|
||||||
|
if (!this.IsDragging && !this.IsDropping()) return;
|
||||||
|
if (!validityCheck(this) || !ImGui.BeginDragDropSource(ImGuiDragDropFlags.SourceExtern)) return;
|
||||||
|
|
||||||
|
ImGui.SetDragDropPayload(label, nint.Zero, 0);
|
||||||
|
if (this.CheckTooltipFrame(out var frame) && tooltipBuilder(this))
|
||||||
|
{
|
||||||
|
this.lastTooltipFrame = frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndDragDropSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="IDragDropManager.CreateImGuiTarget"/>
|
||||||
|
public bool CreateImGuiTarget(string label, out IReadOnlyList<string> files, out IReadOnlyList<string> directories)
|
||||||
|
{
|
||||||
|
files = Array.Empty<string>();
|
||||||
|
directories = Array.Empty<string>();
|
||||||
|
if (!this.IsDragging || !ImGui.BeginDragDropTarget()) return false;
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
if (ImGui.AcceptDragDropPayload(label, ImGuiDragDropFlags.AcceptBeforeDelivery).NativePtr != null && this.IsDropping())
|
||||||
|
{
|
||||||
|
this.lastDropFrame = -2;
|
||||||
|
files = this.Files;
|
||||||
|
directories = this.Directories;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndDragDropTarget();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int lastDropFrame = -2;
|
||||||
|
private int lastTooltipFrame = -1;
|
||||||
|
|
||||||
|
private bool CheckTooltipFrame(out int frame)
|
||||||
|
{
|
||||||
|
frame = ImGui.GetFrameCount();
|
||||||
|
return this.lastTooltipFrame < frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsDropping()
|
||||||
|
{
|
||||||
|
var frame = ImGui.GetFrameCount();
|
||||||
|
return this.lastDropFrame == frame || this.lastDropFrame == frame - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
23
Dalamud/Interface/DragDrop/DragDropTarget.cs
Normal file
23
Dalamud/Interface/DragDrop/DragDropTarget.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.VisualStudio.OLE.Interop;
|
||||||
|
|
||||||
|
namespace Dalamud.Interface.DragDrop;
|
||||||
|
|
||||||
|
internal partial class DragDropManager : IDropTarget
|
||||||
|
{
|
||||||
|
public void DragEnter(IDataObject pDataObj, uint grfKeyState, POINTL pt, ref uint pdwEffect)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DragOver(uint grfKeyState, POINTL pt, ref uint pdwEffect)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DragLeave()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Drop(IDataObject pDataObj, uint grfKeyState, POINTL pt, ref uint pdwEffect)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
43
Dalamud/Interface/DragDrop/IDragDropManager.cs
Normal file
43
Dalamud/Interface/DragDrop/IDragDropManager.cs
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Dalamud.Interface.DragDrop;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A service to handle external drag and drop from WinAPI.
|
||||||
|
/// </summary>
|
||||||
|
public interface IDragDropManager
|
||||||
|
{
|
||||||
|
/// <summary> Gets a value indicating whether Drag and Drop functionality is available at all. </summary>
|
||||||
|
public bool ServiceAvailable { get; }
|
||||||
|
|
||||||
|
/// <summary> Gets a value indicating whether anything is being dragged from an external application and over any of the games viewports. </summary>
|
||||||
|
public bool IsDragging { get; }
|
||||||
|
|
||||||
|
/// <summary> Gets the list of files currently being dragged from an external application over any of the games viewports. </summary>
|
||||||
|
public IReadOnlyList<string> Files { get; }
|
||||||
|
|
||||||
|
/// <summary> Gets the set of file types by extension currently being dragged from an external application over any of the games viewports. </summary>
|
||||||
|
public IReadOnlySet<string> Extensions { get; }
|
||||||
|
|
||||||
|
/// <summary> Gets the list of directories currently being dragged from an external application over any of the games viewports. </summary>
|
||||||
|
public IReadOnlyList<string> Directories { get; }
|
||||||
|
|
||||||
|
/// <summary> Create an ImGui drag & drop source that is active only if anything is being dragged from an external source. </summary>
|
||||||
|
/// <param name="label"> The label used for the drag & drop payload. </param>
|
||||||
|
/// <param name="validityCheck">A function returning whether the current status is relevant for this source. Checked before creating the source but only if something is being dragged.</param>
|
||||||
|
public void CreateImGuiSource(string label, Func<IDragDropManager, bool> validityCheck)
|
||||||
|
=> this.CreateImGuiSource(label, validityCheck, _ => false);
|
||||||
|
|
||||||
|
/// <summary> Create an ImGui drag & drop source that is active only if anything is being dragged from an external source. </summary>
|
||||||
|
/// <param name="label"> The label used for the drag & drop payload. </param>
|
||||||
|
/// <param name="validityCheck">A function returning whether the current status is relevant for this source. Checked before creating the source but only if something is being dragged.</param>
|
||||||
|
/// <param name="tooltipBuilder">Executes ImGui functions to build a tooltip. Should return true if it creates any tooltip and false otherwise. If multiple sources are active, only the first non-empty tooltip type drawn in a frame will be used.</param>
|
||||||
|
public void CreateImGuiSource(string label, Func<IDragDropManager, bool> validityCheck, Func<IDragDropManager, bool> tooltipBuilder);
|
||||||
|
|
||||||
|
/// <summary> Create an ImGui drag & drop target on the last ImGui object. </summary>
|
||||||
|
/// <param name="label">The label used for the drag & drop payload.</param>
|
||||||
|
/// <param name="files">On success, contains the files dropped onto the target.</param>
|
||||||
|
/// <returns>True if items were dropped onto the target this frame, false otherwise.</returns>
|
||||||
|
public bool CreateImGuiTarget(string label, out IReadOnlyList<string> files);
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,7 @@ using Dalamud.Configuration.Internal;
|
||||||
using Dalamud.Game;
|
using Dalamud.Game;
|
||||||
using Dalamud.Game.ClientState.Conditions;
|
using Dalamud.Game.ClientState.Conditions;
|
||||||
using Dalamud.Game.Gui;
|
using Dalamud.Game.Gui;
|
||||||
|
using Dalamud.Interface.DragDrop;
|
||||||
using Dalamud.Interface.GameFonts;
|
using Dalamud.Interface.GameFonts;
|
||||||
using Dalamud.Interface.Internal;
|
using Dalamud.Interface.Internal;
|
||||||
using Dalamud.Interface.Internal.ManagedAsserts;
|
using Dalamud.Interface.Internal.ManagedAsserts;
|
||||||
|
|
@ -30,6 +31,7 @@ public sealed class UiBuilder : IDisposable
|
||||||
private readonly string namespaceName;
|
private readonly string namespaceName;
|
||||||
private readonly InterfaceManager interfaceManager = Service<InterfaceManager>.Get();
|
private readonly InterfaceManager interfaceManager = Service<InterfaceManager>.Get();
|
||||||
private readonly GameFontManager gameFontManager = Service<GameFontManager>.Get();
|
private readonly GameFontManager gameFontManager = Service<GameFontManager>.Get();
|
||||||
|
private readonly DragDropManager dragDropManager;
|
||||||
|
|
||||||
private bool hasErrorWindow = false;
|
private bool hasErrorWindow = false;
|
||||||
private bool lastFrameUiHideState = false;
|
private bool lastFrameUiHideState = false;
|
||||||
|
|
@ -47,6 +49,7 @@ public sealed class UiBuilder : IDisposable
|
||||||
this.stopwatch = new Stopwatch();
|
this.stopwatch = new Stopwatch();
|
||||||
this.hitchDetector = new HitchDetector($"UiBuilder({namespaceName})", this.configuration.UiBuilderHitch);
|
this.hitchDetector = new HitchDetector($"UiBuilder({namespaceName})", this.configuration.UiBuilderHitch);
|
||||||
this.namespaceName = namespaceName;
|
this.namespaceName = namespaceName;
|
||||||
|
this.dragDropManager = new DragDropManager(this);
|
||||||
|
|
||||||
this.interfaceManager.Draw += this.OnDraw;
|
this.interfaceManager.Draw += this.OnDraw;
|
||||||
this.interfaceManager.BuildFonts += this.OnBuildFonts;
|
this.interfaceManager.BuildFonts += this.OnBuildFonts;
|
||||||
|
|
@ -100,6 +103,11 @@ public sealed class UiBuilder : IDisposable
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action HideUi;
|
public event Action HideUi;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the manager for external, WinAPI-based drag and drop functionality.
|
||||||
|
/// </summary>
|
||||||
|
public IDragDropManager DragDropManager => this.dragDropManager;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the default Dalamud font based on Noto Sans CJK Medium in 17pt - supporting all game languages and icons.
|
/// Gets the default Dalamud font based on Noto Sans CJK Medium in 17pt - supporting all game languages and icons.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -397,6 +405,7 @@ public sealed class UiBuilder : IDisposable
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void IDisposable.Dispose()
|
void IDisposable.Dispose()
|
||||||
{
|
{
|
||||||
|
this.dragDropManager.Dispose();
|
||||||
this.interfaceManager.Draw -= this.OnDraw;
|
this.interfaceManager.Draw -= this.OnDraw;
|
||||||
this.interfaceManager.BuildFonts -= this.OnBuildFonts;
|
this.interfaceManager.BuildFonts -= this.OnBuildFonts;
|
||||||
this.interfaceManager.ResizeBuffers -= this.OnResizeBuffers;
|
this.interfaceManager.ResizeBuffers -= this.OnResizeBuffers;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue