diff --git a/OtterGui b/OtterGui index 86ec4d72..9c7a3147 160000 --- a/OtterGui +++ b/OtterGui @@ -1 +1 @@ -Subproject commit 86ec4d72c9c9ed57aa7be4a7d0c81069c5b94ad7 +Subproject commit 9c7a3147f6e64e93074bc318a52b0723efc6ffff diff --git a/Penumbra/UI/ModsTab/ModFileSystemSelector.cs b/Penumbra/UI/ModsTab/ModFileSystemSelector.cs index 6eecf36a..8d978413 100644 --- a/Penumbra/UI/ModsTab/ModFileSystemSelector.cs +++ b/Penumbra/UI/ModsTab/ModFileSystemSelector.cs @@ -42,7 +42,7 @@ public sealed class ModFileSystemSelector : FileSystemSelector.Leaf leaf, in ModState stat var offset = remainingSpace - requiredSize; if (ImGui.GetScrollMaxY() == 0) offset -= ImGui.GetStyle().ItemInnerSpacing.X; - + if (offset > ImGui.GetStyle().ItemSpacing.X) ImGui.GetWindowDrawList().AddText(new Vector2(itemPos + offset, line), ColorId.SelectorPriority.Value(), priorityString); } @@ -341,7 +341,7 @@ private void MoveModToDefaultDirectory(Mod mod) private void DrawHelpPopup() { - ImGuiUtil.HelpPopup("ExtendedHelp", new Vector2(1000 * UiHelpers.Scale, 34.5f * ImGui.GetTextLineHeightWithSpacing()), () => + ImGuiUtil.HelpPopup("ExtendedHelp", new Vector2(1000 * UiHelpers.Scale, 36.5f * ImGui.GetTextLineHeightWithSpacing()), () => { ImGui.Dummy(Vector2.UnitY * ImGui.GetTextLineHeight()); ImGui.TextUnformatted("Mod Management"); @@ -380,6 +380,10 @@ private void DrawHelpPopup() indent.Pop(1); ImGui.BulletText( "You can drag and drop mods and subfolders into existing folders. Dropping them onto mods is the same as dropping them onto the parent of the mod."); + indent.Push(); + ImGui.BulletText("You can select multiple mods and folders by holding Control while clicking them, and then drag all of them at once." ); + ImGui.BulletText("Selected mods inside an also selected folder will be ignored when dragging and move inside their folder instead of directly into the target."); + indent.Pop(1); ImGui.BulletText("Right-clicking a folder opens a context menu."); ImGui.BulletText("Right-clicking empty space allows you to expand or collapse all folders at once."); ImGui.BulletText("Use the Filter Mods... input at the top to filter the list for mods whose name or path contain the text."); @@ -471,7 +475,7 @@ private void RestoreLastSelection() var leaf = (ModFileSystem.Leaf?)FileSystem.Root.GetAllDescendants(ISortMode.Lexicographical) .FirstOrDefault(l => l is ModFileSystem.Leaf m && m.Value.ModPath.FullName == _lastSelectedDirectory); - Select(leaf); + Select(leaf, AllowMultipleSelection); _lastSelectedDirectory = string.Empty; } diff --git a/Penumbra/UI/ModsTab/ModPanel.cs b/Penumbra/UI/ModsTab/ModPanel.cs index d85f77ff..f0d28dab 100644 --- a/Penumbra/UI/ModsTab/ModPanel.cs +++ b/Penumbra/UI/ModsTab/ModPanel.cs @@ -1,5 +1,11 @@ using System; +using System.Linq; +using System.Numerics; +using Dalamud.Interface; using Dalamud.Plugin; +using ImGuiNET; +using OtterGui; +using OtterGui.Raii; using Penumbra.Mods; using Penumbra.UI.AdvancedWindow; @@ -7,10 +13,10 @@ namespace Penumbra.UI.ModsTab; public class ModPanel : IDisposable { - private readonly ModFileSystemSelector _selector; - private readonly ModEditWindow _editWindow; - private readonly ModPanelHeader _header; - private readonly ModPanelTabBar _tabs; + private readonly ModFileSystemSelector _selector; + private readonly ModEditWindow _editWindow; + private readonly ModPanelHeader _header; + private readonly ModPanelTabBar _tabs; public ModPanel(DalamudPluginInterface pi, ModFileSystemSelector selector, ModEditWindow editWindow, ModPanelTabBar tabs) { @@ -24,7 +30,10 @@ public ModPanel(DalamudPluginInterface pi, ModFileSystemSelector selector, ModEd public void Draw() { if (!_valid) + { + DrawMultiSelection(); return; + } _header.Draw(); _tabs.Draw(_mod); @@ -36,6 +45,45 @@ public void Dispose() _header.Dispose(); } + private void DrawMultiSelection() + { + if (_selector.SelectedPaths.Count == 0) + return; + + var sizeType = ImGui.GetFrameHeight(); + var availableSizePercent = (ImGui.GetContentRegionAvail().X - sizeType - 4 * ImGui.GetStyle().CellPadding.X) / 100; + var sizeMods = availableSizePercent * 35; + var sizeFolders = availableSizePercent * 65; + + ImGui.NewLine(); + ImGui.TextUnformatted("Currently Selected Objects"); + ImGui.Separator(); + using var table = ImRaii.Table("mods", 3, ImGuiTableFlags.RowBg); + ImGui.TableSetupColumn("type", ImGuiTableColumnFlags.WidthFixed, sizeType); + ImGui.TableSetupColumn("mod", ImGuiTableColumnFlags.WidthFixed, sizeMods); + ImGui.TableSetupColumn("path", ImGuiTableColumnFlags.WidthFixed, sizeFolders); + + var i = 0; + foreach (var (fullName, path) in _selector.SelectedPaths.Select(p => (p.FullName(), p)) + .OrderBy(p => p.Item1, StringComparer.OrdinalIgnoreCase)) + { + using var id = ImRaii.PushId(i++); + ImGui.TableNextColumn(); + var icon = (path is ModFileSystem.Leaf ? FontAwesomeIcon.FileCircleMinus : FontAwesomeIcon.FolderMinus).ToIconString(); + if (ImGuiUtil.DrawDisabledButton(icon, new Vector2(sizeType), "Remove from selection.", false, true)) + _selector.RemovePathFromMultiselection(path); + + ImGui.TableNextColumn(); + ImGui.AlignTextToFramePadding(); + ImGui.TextUnformatted(path is ModFileSystem.Leaf l ? l.Value.Name : string.Empty); + + ImGui.TableNextColumn(); + ImGui.AlignTextToFramePadding(); + ImGui.TextUnformatted(fullName); + } + } + + private bool _valid; private Mod _mod = null!;