diff --git a/Luna b/Luna
index d580f7a6..616d66b1 160000
--- a/Luna
+++ b/Luna
@@ -1 +1 @@
-Subproject commit d580f7a6ec62b0d7d60be07130133a54f10a3337
+Subproject commit 616d66b1d384588c23a3b5725ad1330037ce6987
diff --git a/Penumbra/Mods/Manager/ModFileSystem.cs b/Penumbra/Mods/Manager/ModFileSystem.cs
index 810bc731..4528b9fc 100644
--- a/Penumbra/Mods/Manager/ModFileSystem.cs
+++ b/Penumbra/Mods/Manager/ModFileSystem.cs
@@ -68,7 +68,8 @@ public sealed class ModFileSystem : BaseFileSystem, IDisposable, IRequiredServic
NotificationType.Warning);
}
- CreateDuplicateDataNode(parent, arguments.Mod.Name, arguments.Mod);
+ var (data, _) = CreateDuplicateDataNode(parent, arguments.Mod.Name, arguments.Mod);
+ Selection.Select(data);
break;
case ModPathChangeType.Deleted:
if (arguments.Mod.Node is not null)
diff --git a/Penumbra/Mods/Manager/ModImportManager.cs b/Penumbra/Mods/Manager/ModImportManager.cs
index bef6254c..613a89f5 100644
--- a/Penumbra/Mods/Manager/ModImportManager.cs
+++ b/Penumbra/Mods/Manager/ModImportManager.cs
@@ -84,9 +84,8 @@ public class ModImportManager(
return false;
}
- modManager.AddMod(directory, true);
- mod = modManager.LastOrDefault();
- return mod != null && mod.ModPath == directory;
+ mod = modManager.AddMod(directory, true);
+ return mod is not null && mod.ModPath == directory;
}
public void Dispose()
diff --git a/Penumbra/Mods/Manager/ModManager.cs b/Penumbra/Mods/Manager/ModManager.cs
index 6cac3c79..ce7de910 100644
--- a/Penumbra/Mods/Manager/ModManager.cs
+++ b/Penumbra/Mods/Manager/ModManager.cs
@@ -82,20 +82,21 @@ public sealed class ModManager : ModStorage, IDisposable, Luna.IService
}
/// Load a new mod and add it to the manager if successful.
- public void AddMod(DirectoryInfo modFolder, bool deleteDefaultMeta)
+ public Mod? AddMod(DirectoryInfo modFolder, bool deleteDefaultMeta)
{
if (this.Any(m => m.ModPath.Name == modFolder.Name))
- return;
+ return null;
Creator.SplitMultiGroups(modFolder);
var mod = Creator.LoadMod(modFolder, true, deleteDefaultMeta);
- if (mod == null)
- return;
+ if (mod is null)
+ return null;
mod.Index = Count;
Mods.Add(mod);
_communicator.ModPathChanged.Invoke(new ModPathChanged.Arguments(ModPathChangeType.Added, mod, null, mod.ModPath));
Penumbra.Log.Debug($"Added new mod {mod.Name} from {modFolder.FullName}.");
+ return mod;
}
///
diff --git a/Penumbra/UI/GlobalModImporter.cs b/Penumbra/UI/GlobalModImporter.cs
index 592131b7..2e63cd23 100644
--- a/Penumbra/UI/GlobalModImporter.cs
+++ b/Penumbra/UI/GlobalModImporter.cs
@@ -25,6 +25,20 @@ public sealed class GlobalModImporter : IRequiredService, IDisposable
dragDropManager.AddTarget(DragDropId, ImportFiles);
}
+ public void DrawItemTarget()
+ {
+ using var target = Im.DragDrop.Target();
+ if (target.IsDropping("ModDragDrop"u8))
+ ImportFiles(_dragDropManager.DalamudManager.Files, []);
+ }
+
+ public void DrawWindowTarget()
+ {
+ using var target = Im.DragDrop.TargetWindow();
+ if (target.IsDropping("ModDragDrop"u8))
+ ImportFiles(_dragDropManager.DalamudManager.Files, []);
+ }
+
public void Dispose()
{
_dragDropManager.RemoveSource(DragDropId);
@@ -39,7 +53,9 @@ public sealed class GlobalModImporter : IRequiredService, IDisposable
private static bool DragTooltip(IDragDropManager manager)
{
- Im.Text($"Dragging mods for import:\n\t{StringU8.Join("\n\t"u8, manager.Files.Select(Path.GetFileName))}");
+ Im.Text(manager.Files.Count > 1 ? "Dragging mods for import:"u8 : "Dragging mod for import:"u8);
+ foreach (var file in manager.Files.Select(Path.GetFileName))
+ Im.BulletText(file!);
return true;
}
}
diff --git a/Penumbra/UI/ImportPopup.cs b/Penumbra/UI/ImportPopup.cs
index 626ddd40..4e8184fd 100644
--- a/Penumbra/UI/ImportPopup.cs
+++ b/Penumbra/UI/ImportPopup.cs
@@ -1,84 +1,87 @@
-using ImSharp;
-using Luna;
-using Penumbra.Import.Structs;
-using Penumbra.Mods.Manager;
-
-namespace Penumbra.UI;
-
-/// Draw the progress information for import.
-public sealed class ImportPopup : Window, IUiService
-{
- public const string WindowLabel = "Penumbra Import Status";
-
- private readonly ModImportManager _modImportManager;
- private static readonly Vector2 OneHalf = Vector2.One / 2;
-
- public bool WasDrawn { get; private set; }
- public bool PopupWasDrawn { get; private set; }
-
- public ImportPopup(ModImportManager modImportManager)
- : base(WindowLabel,
- WindowFlags.NoCollapse
- | WindowFlags.NoDecoration
- | WindowFlags.NoBackground
- | WindowFlags.NoMove
- | WindowFlags.NoInputs
- | WindowFlags.NoNavFocus
- | WindowFlags.NoFocusOnAppearing
- | WindowFlags.NoBringToFrontOnFocus
- | WindowFlags.NoDocking
- | WindowFlags.NoTitleBar, true)
- {
- _modImportManager = modImportManager;
- DisableWindowSounds = true;
- IsOpen = true;
- RespectCloseHotkey = false;
- Collapsed = false;
- SizeConstraints = new WindowSizeConstraints
- {
- MinimumSize = Vector2.Zero,
- MaximumSize = Vector2.Zero,
- };
- }
-
- public override void PreOpenCheck()
- {
- WasDrawn = false;
- PopupWasDrawn = false;
- _modImportManager.TryUnpacking();
- IsOpen = true;
- }
-
- public override void Draw()
- {
- WasDrawn = true;
- if (!_modImportManager.IsImporting(out var import))
- return;
-
- if (!Im.Popup.IsOpen("##PenumbraImportPopup"u8))
- Im.Popup.Open("##PenumbraImportPopup"u8);
-
- var display = Im.Io.DisplaySize;
- var height = Math.Max(display.Y / 4, 15 * Im.Style.FrameHeightWithSpacing);
- var width = display.X / 8;
- var size = new Vector2(width * 2, height);
- Im.Window.SetNextPosition(Im.Viewport.Main.Center, Condition.Always, OneHalf);
- Im.Window.SetNextSize(size);
- using var popup = Im.Popup.Begin("##PenumbraImportPopup"u8, WindowFlags.Modal);
- PopupWasDrawn = true;
- var terminate = false;
- using (var child = Im.Child.Begin("##import"u8, new Vector2(-1, size.Y - Im.Style.FrameHeight * 2)))
- {
- if (child.Success && import.DrawProgressInfo(new Vector2(-1, Im.Style.FrameHeight)))
- if (!Im.Mouse.IsHoveringRectangle(Rectangle.FromSize(Im.Window.Position, Im.Window.Size))
- && Im.Mouse.IsClicked(MouseButton.Left))
- terminate = true;
- }
-
- terminate |= import.State == ImporterState.Done
- ? Im.Button("Close"u8, -Vector2.UnitX)
- : import.DrawCancelButton(-Vector2.UnitX);
- if (terminate)
- _modImportManager.ClearImport();
- }
-}
+using ImSharp;
+using Luna;
+using Penumbra.Import.Structs;
+using Penumbra.Mods.Manager;
+
+namespace Penumbra.UI;
+
+/// Draw the progress information for import.
+public sealed class ImportPopup : Window
+{
+ public const string WindowLabel = "Penumbra Import Status";
+
+ private readonly ModImportManager _modImportManager;
+ private static readonly Vector2 OneHalf = Vector2.One / 2;
+
+ public bool WasDrawn { get; private set; }
+ public bool PopupWasDrawn { get; private set; }
+
+ public ImportPopup(ModImportManager modImportManager)
+ : base(WindowLabel,
+ WindowFlags.NoCollapse
+ | WindowFlags.NoDecoration
+ | WindowFlags.NoBackground
+ | WindowFlags.NoMove
+ | WindowFlags.NoInputs
+ | WindowFlags.NoNavFocus
+ | WindowFlags.NoFocusOnAppearing
+ | WindowFlags.NoBringToFrontOnFocus
+ | WindowFlags.NoDocking
+ | WindowFlags.NoTitleBar, true)
+ {
+ _modImportManager = modImportManager;
+ DisableWindowSounds = true;
+ IsOpen = true;
+ RespectCloseHotkey = false;
+ Collapsed = false;
+ SizeConstraints = new WindowSizeConstraints
+ {
+ MinimumSize = Vector2.Zero,
+ MaximumSize = Vector2.Zero,
+ };
+ }
+
+ public override void PreOpenCheck()
+ {
+ WasDrawn = false;
+ PopupWasDrawn = false;
+ _modImportManager.TryUnpacking();
+ IsOpen = true;
+
+ while (_modImportManager.AddUnpackedMod(out _))
+ ;
+ }
+
+ public override void Draw()
+ {
+ WasDrawn = true;
+ if (!_modImportManager.IsImporting(out var import))
+ return;
+
+ if (!Im.Popup.IsOpen("##PenumbraImportPopup"u8))
+ Im.Popup.Open("##PenumbraImportPopup"u8);
+
+ var display = Im.Io.DisplaySize;
+ var height = Math.Max(display.Y / 4, 15 * Im.Style.FrameHeightWithSpacing);
+ var width = display.X / 8;
+ var size = new Vector2(width * 2, height);
+ Im.Window.SetNextPosition(Im.Viewport.Main.Center, Condition.Always, OneHalf);
+ Im.Window.SetNextSize(size);
+ using var popup = Im.Popup.Begin("##PenumbraImportPopup"u8, WindowFlags.Modal);
+ PopupWasDrawn = true;
+ var terminate = false;
+ using (var child = Im.Child.Begin("##import"u8, new Vector2(-1, size.Y - Im.Style.FrameHeight * 2)))
+ {
+ if (child.Success && import.DrawProgressInfo(new Vector2(-1, Im.Style.FrameHeight)))
+ if (!Im.Mouse.IsHoveringRectangle(Rectangle.FromSize(Im.Window.Position, Im.Window.Size))
+ && Im.Mouse.IsClicked(MouseButton.Left))
+ terminate = true;
+ }
+
+ terminate |= import.State == ImporterState.Done
+ ? Im.Button("Close"u8, -Vector2.UnitX)
+ : import.DrawCancelButton(-Vector2.UnitX);
+ if (terminate)
+ _modImportManager.ClearImport();
+ }
+}
diff --git a/Penumbra/UI/MainWindow/MainWindow.cs b/Penumbra/UI/MainWindow/MainWindow.cs
index ac0f15f0..d3094940 100644
--- a/Penumbra/UI/MainWindow/MainWindow.cs
+++ b/Penumbra/UI/MainWindow/MainWindow.cs
@@ -12,17 +12,19 @@ public sealed class MainWindow : Window
private readonly IDalamudPluginInterface _pluginInterface;
private readonly Configuration _config;
private readonly ValidityChecker _validityChecker;
+ private readonly GlobalModImporter _globalModImporter;
private Penumbra? _penumbra;
private MainTabBar _configTabs = null!;
private string? _lastException;
public MainWindow(IDalamudPluginInterface pi, Configuration config, ValidityChecker checker,
- TutorialService tutorial)
+ TutorialService tutorial, GlobalModImporter globalModImporter)
: base(GetLabel(checker))
{
- _pluginInterface = pi;
- _config = config;
- _validityChecker = checker;
+ _pluginInterface = pi;
+ _config = config;
+ _validityChecker = checker;
+ _globalModImporter = globalModImporter;
RespectCloseHotkey = true;
tutorial.UpdateTutorialStep();
@@ -61,6 +63,7 @@ public sealed class MainWindow : Window
public override void Draw()
{
UiHelpers.SetupCommonSizes();
+ _globalModImporter.DrawWindowTarget();
try
{
if (_validityChecker.ImcExceptions.Count > 0)
diff --git a/Penumbra/UI/ModsTab/Selector/ModFileSystemDrawer.cs b/Penumbra/UI/ModsTab/Selector/ModFileSystemDrawer.cs
index f66ef125..b1dad750 100644
--- a/Penumbra/UI/ModsTab/Selector/ModFileSystemDrawer.cs
+++ b/Penumbra/UI/ModsTab/Selector/ModFileSystemDrawer.cs
@@ -1,3 +1,4 @@
+using ImSharp;
using Luna;
using Penumbra.Collections.Manager;
using Penumbra.Mods;
@@ -16,9 +17,11 @@ public sealed class ModFileSystemDrawer : FileSystemDrawer Id