From 6a1ae4f317dac1663e1f3e15938637fe9ed85ab9 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Thu, 3 Jun 2021 15:29:47 +0200 Subject: [PATCH] Added option to move a mods priority via numerical input (right click) and to rename (and merge) a mod directory. Actually implemented Add Mod button. --- Penumbra/Importer/TexToolsImport.cs | 12 +- Penumbra/Mods/ModCollection.cs | 56 +++-- Penumbra/Mods/ModManager.cs | 9 +- .../TabInstalled/TabInstalledDetails.cs | 4 +- .../TabInstalled/TabInstalledModPanel.cs | 202 +++++++++++++++--- .../TabInstalled/TabInstalledSelector.cs | 193 ++++++++++++++--- 6 files changed, 387 insertions(+), 89 deletions(-) diff --git a/Penumbra/Importer/TexToolsImport.cs b/Penumbra/Importer/TexToolsImport.cs index 9a00c578..fe5f42ad 100644 --- a/Penumbra/Importer/TexToolsImport.cs +++ b/Penumbra/Importer/TexToolsImport.cs @@ -1,12 +1,10 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using Dalamud.Plugin; using ICSharpCode.SharpZipLib.Zip; -using Lumina.Data; using Newtonsoft.Json; using Penumbra.Importer.Models; using Penumbra.Models; @@ -155,7 +153,7 @@ namespace Penumbra.Importer // Open the mod data file from the modpack as a SqPackStream using var modData = GetMagicSqPackDeleterStream( extractedModPack, "TTMPD.mpd" ); - var newModFolder = CreateModFolder( Path.GetFileNameWithoutExtension( modPackFile.Name ) ); + var newModFolder = CreateModFolder( _outDirectory, Path.GetFileNameWithoutExtension( modPackFile.Name ) ); File.WriteAllText( Path.Combine( newModFolder.FullName, "meta.json" ), @@ -187,9 +185,9 @@ namespace Penumbra.Importer } } - private DirectoryInfo CreateModFolder( string modListName ) + public static DirectoryInfo CreateModFolder( DirectoryInfo outDirectory, string modListName ) { - var correctedPath = Path.Combine( _outDirectory.FullName, + var correctedPath = Path.Combine( outDirectory.FullName, Path.GetFileName( modListName ).RemoveInvalidPathSymbols().RemoveNonAsciiSymbols() ); var newModFolder = new DirectoryInfo( correctedPath ); var i = 2; @@ -224,7 +222,7 @@ namespace Penumbra.Importer // Open the mod data file from the modpack as a SqPackStream using var modData = GetMagicSqPackDeleterStream( extractedModPack, "TTMPD.mpd" ); - var newModFolder = CreateModFolder( modList.Name ?? "New Mod" ); + var newModFolder = CreateModFolder( _outDirectory, modList.Name ?? "New Mod" ); File.WriteAllText( Path.Combine( newModFolder.FullName, "meta.json" ), JsonConvert.SerializeObject( modMeta ) ); @@ -252,7 +250,7 @@ namespace Penumbra.Importer // Open the mod data file from the modpack as a SqPackStream using var modData = GetMagicSqPackDeleterStream( extractedModPack, "TTMPD.mpd" ); - var newModFolder = CreateModFolder( modList.Name ?? "New Mod" ); + var newModFolder = CreateModFolder( _outDirectory, modList.Name ?? "New Mod" ); if( modList.SimpleModsList != null ) { diff --git a/Penumbra/Mods/ModCollection.cs b/Penumbra/Mods/ModCollection.cs index 3b25b039..a9a4c2f8 100644 --- a/Penumbra/Mods/ModCollection.cs +++ b/Penumbra/Mods/ModCollection.cs @@ -55,7 +55,9 @@ namespace Penumbra.Mods foreach( var modDir in _basePath.EnumerateDirectories() ) { if( modDir.Name.ToLowerInvariant() == MetaManager.TmpDirectory ) + { continue; + } var metaFile = modDir.EnumerateFiles().FirstOrDefault( f => f.Name == "meta.json" ); @@ -115,30 +117,47 @@ namespace Penumbra.Mods } } - public void ReorderMod( ModInfo info, bool up ) + private int CleanPriority( int priority ) + => priority < 0 ? 0 : priority >= ModSettings!.Count ? ModSettings.Count - 1 : priority; + + public void ReorderMod( ModInfo info, int newPriority ) { - // todo: certified fucked tier - - var prio = info.Priority; - var swapPrio = up ? prio + 1 : prio - 1; - var swapMeta = ModSettings.FirstOrDefault( x => x.Priority == swapPrio ); - - if( swapMeta == null ) + if( ModSettings == null ) { return; } - info.Priority = swapPrio; - swapMeta.Priority = prio; + var oldPriority = info.Priority; + newPriority = CleanPriority( newPriority ); + if( oldPriority == newPriority ) + { + return; + } + + info.Priority = newPriority; + if( newPriority < oldPriority ) + { + for( var i = oldPriority - 1; i >= newPriority; --i ) + { + ++ModSettings![ i ].Priority; + ModSettings.Swap( i, i + 1 ); + } + } + else + { + for( var i = oldPriority + 1; i <= newPriority; ++i ) + { + --ModSettings![ i ].Priority; + ModSettings.Swap( i - 1, i ); + } + } - // reorder mods list - ModSettings = ModSettings.OrderBy( x => x.Priority ).ToList(); EnabledMods = GetOrderedAndEnabledModList().ToArray(); - - // save new prios Save(); } + public void ReorderMod( ModInfo info, bool up ) + => ReorderMod( info, info.Priority + ( up ? 1 : -1 ) ); public ModInfo? FindModSettings( string name ) { @@ -157,7 +176,7 @@ namespace Penumbra.Mods { Priority = ModSettings?.Count ?? 0, FolderName = mod.ModBasePath.Name, - Enabled = true + Enabled = true, }; entry.FixInvalidSettings(); #if DEBUG @@ -184,7 +203,8 @@ namespace Penumbra.Mods public IEnumerable< ModInfo > GetOrderedAndEnabledModSettings( bool invertOrder = false ) { var query = ModSettings? - .Where( x => x.Enabled ) ?? Enumerable.Empty< ModInfo >(); + .Where( x => x.Enabled ) + ?? Enumerable.Empty< ModInfo >(); if( !invertOrder ) { @@ -197,13 +217,13 @@ namespace Penumbra.Mods public IEnumerable< ResourceMod > GetOrderedAndEnabledModList( bool invertOrder = false ) { return GetOrderedAndEnabledModSettings( invertOrder ) - .Select( x => x.Mod ); + .Select( x => x.Mod ); } public IEnumerable< (ResourceMod, ModInfo) > GetOrderedAndEnabledModListWithSettings( bool invertOrder = false ) { return GetOrderedAndEnabledModSettings( invertOrder ) - .Select( x => ( x.Mod, x ) ); + .Select( x => ( x.Mod, x ) ); } } } \ No newline at end of file diff --git a/Penumbra/Mods/ModManager.cs b/Penumbra/Mods/ModManager.cs index 1cd55bdb..e8085e34 100644 --- a/Penumbra/Mods/ModManager.cs +++ b/Penumbra/Mods/ModManager.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using Dalamud.Plugin; using Penumbra.Hooks; using Penumbra.Models; @@ -117,7 +116,7 @@ namespace Penumbra.Mods } private void AddFiles( IEnumerable< GamePath > gamePaths, FileInfo file, Dictionary< GamePath, string > registeredFiles, - ResourceMod mod ) + ResourceMod mod ) { foreach( var gamePath in gamePaths ) { @@ -147,6 +146,12 @@ namespace Penumbra.Mods } } + public void ChangeModPriority( ModInfo info, int newPriority ) + { + Mods!.ReorderMod( info, newPriority ); + CalculateEffectiveFileList(); + } + public void ChangeModPriority( ModInfo info, bool up = false ) { Mods!.ReorderMod( info, up ); diff --git a/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledDetails.cs b/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledDetails.cs index 10f9b1f1..6c1aa1a3 100644 --- a/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledDetails.cs +++ b/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledDetails.cs @@ -72,7 +72,7 @@ namespace Penumbra.UI private void SelectGroup( int idx ) { // Not using the properties here because we need it to be not null forgiving in this case. - var numGroups = _selector.Mod()?.Mod.Meta.Groups.Count ?? 0; + var numGroups = _selector.Mod?.Mod.Meta.Groups.Count ?? 0; _selectedGroupIndex = idx; if( _selectedGroupIndex >= numGroups ) { @@ -130,7 +130,7 @@ namespace Penumbra.UI // This is only drawn when we have a mod selected, so we can forgive nulls. private ModInfo Mod - => _selector.Mod()!; + => _selector.Mod!; private ModMeta Meta => Mod.Mod.Meta; diff --git a/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledModPanel.cs b/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledModPanel.cs index b48c6cae..f1eeecdc 100644 --- a/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledModPanel.cs +++ b/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledModPanel.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics; +using System.IO; using System.Numerics; using Dalamud.Plugin; using ImGuiNET; @@ -12,25 +13,28 @@ namespace Penumbra.UI { private class ModPanel { - private const string LabelModPanel = "selectedModInfo"; - private const string LabelEditName = "##editName"; - private const string LabelEditVersion = "##editVersion"; - private const string LabelEditAuthor = "##editAuthor"; - private const string LabelEditWebsite = "##editWebsite"; - private const string LabelModEnabled = "Enabled"; - private const string LabelEditingEnabled = "Enable Editing"; - private const string ButtonOpenWebsite = "Open Website"; - private const string ButtonOpenModFolder = "Open Mod Folder"; - private const string ButtonEditJson = "Edit JSON"; - private const string ButtonReloadJson = "Reload JSON"; - private const string ButtonDeduplicate = "Deduplicate"; - private const string TooltipOpenModFolder = "Open the directory containing this mod in your default file explorer."; - private const string TooltipEditJson = "Open the JSON configuration file in your default application for .json."; - private const string TooltipReloadJson = "Reload the configuration of all mods."; + private const string LabelModPanel = "selectedModInfo"; + private const string LabelEditName = "##editName"; + private const string LabelEditVersion = "##editVersion"; + private const string LabelEditAuthor = "##editAuthor"; + private const string LabelEditWebsite = "##editWebsite"; + private const string LabelModEnabled = "Enabled"; + private const string LabelEditingEnabled = "Enable Editing"; + private const string ButtonOpenWebsite = "Open Website"; + private const string ButtonOpenModFolder = "Open Mod Folder"; + private const string ButtonRenameModFolder = "Rename Mod Folder"; + private const string ButtonEditJson = "Edit JSON"; + private const string ButtonReloadJson = "Reload JSON"; + private const string ButtonDeduplicate = "Deduplicate"; + private const string TooltipOpenModFolder = "Open the directory containing this mod in your default file explorer."; + private const string TooltipRenameModFolder = "Rename the directory containing this mod without opening another application."; + private const string TooltipEditJson = "Open the JSON configuration file in your default application for .json."; + private const string TooltipReloadJson = "Reload the configuration of all mods."; + private const string PopupRenameFolder = "Rename Folder"; private const string TooltipDeduplicate = - "Try to find identical files and remove duplicate occurences to reduce the mods disk size.\n" + - "Introduces an invisible single-option Group \"Duplicates\"."; + "Try to find identical files and remove duplicate occurences to reduce the mods disk size.\n" + + "Introduces an invisible single-option Group \"Duplicates\"."; private const float HeaderLineDistance = 10f; private static readonly Vector4 GreyColor = new( 1f, 1f, 1f, 0.66f ); @@ -51,14 +55,18 @@ namespace Penumbra.UI _currentWebsite = Meta?.Website ?? ""; } - private ModInfo? Mod => _selector.Mod(); - private ModMeta? Meta => Mod?.Mod.Meta; + private ModInfo? Mod + => _selector.Mod; + + private ModMeta? Meta + => Mod?.Mod.Meta; private void DrawName() { var name = Meta!.Name; if( ImGuiCustom.InputOrText( _editMode, LabelEditName, ref name, 64 ) - && name.Length > 0 && name != Meta.Name ) + && name.Length > 0 + && name != Meta.Name ) { Meta.Name = name; _selector.SaveCurrentMod(); @@ -76,7 +84,7 @@ namespace Penumbra.UI ImGui.SameLine(); var version = Meta!.Version; if( ImGuiCustom.ResizingTextInput( LabelEditVersion, ref version, 16 ) - && version != Meta.Version ) + && version != Meta.Version ) { Meta.Version = version; _selector.SaveCurrentMod(); @@ -101,7 +109,7 @@ namespace Penumbra.UI ImGui.SameLine(); var author = Meta!.Author; if( ImGuiCustom.InputOrText( _editMode, LabelEditAuthor, ref author, 64 ) - && author != Meta.Author ) + && author != Meta.Author ) { Meta.Author = author; _selector.SaveCurrentMod(); @@ -119,7 +127,7 @@ namespace Penumbra.UI ImGui.SameLine(); var website = Meta!.Website; if( ImGuiCustom.ResizingTextInput( LabelEditWebsite, ref website, 512 ) - && website != Meta.Website ) + && website != Meta.Website ) { Meta.Website = website; _selector.SaveCurrentMod(); @@ -131,7 +139,7 @@ namespace Penumbra.UI { _currentWebsite = Meta.Website; _validWebsite = Uri.TryCreate( Meta.Website, UriKind.Absolute, out var uriResult ) - && ( uriResult.Scheme == Uri.UriSchemeHttps || uriResult.Scheme == Uri.UriSchemeHttp ); + && ( uriResult.Scheme == Uri.UriSchemeHttps || uriResult.Scheme == Uri.UriSchemeHttp ); } if( _validWebsite ) @@ -142,7 +150,7 @@ namespace Penumbra.UI { var process = new ProcessStartInfo( Meta.Website ) { - UseShellExecute = true + UseShellExecute = true, }; Process.Start( process ); } @@ -209,6 +217,148 @@ namespace Penumbra.UI } } + private string _newName = ""; + private bool _keyboardFocus = true; + + private void DrawRenameModFolderButton() + { + var _ = true; + _keyboardFocus |= !ImGui.IsPopupOpen( PopupRenameFolder ); + + ImGui.SetNextWindowPos( ImGui.GetMainViewport().GetCenter(), ImGuiCond.Appearing, new Vector2( 0.5f, 1f ) ); + if( ImGui.BeginPopupModal( PopupRenameFolder, ref _, ImGuiWindowFlags.AlwaysAutoResize ) ) + { + if( ImGui.IsKeyPressed( ImGui.GetKeyIndex( ImGuiKey.Escape ) ) ) + { + ImGui.CloseCurrentPopup(); + } + + var newName = Mod!.FolderName; + + if( _keyboardFocus ) + { + PluginLog.Log( "Fuck you" ); + ImGui.SetKeyboardFocusHere(); + _keyboardFocus = false; + } + + if( ImGui.InputText( "New Folder Name##RenameFolderInput", ref newName, 64, ImGuiInputTextFlags.EnterReturnsTrue ) ) + { + _newName = newName.RemoveNonAsciiSymbols().RemoveInvalidPathSymbols(); + if( _newName.Length == 0 ) + { + ImGui.CloseCurrentPopup(); + } + else if( !string.Equals( _newName, Mod!.FolderName, StringComparison.InvariantCultureIgnoreCase ) ) + { + DirectoryInfo dir = Mod!.Mod.ModBasePath; + DirectoryInfo newDir = new( Path.Combine( dir.Parent!.FullName, _newName ) ); + if( newDir.Exists ) + { + PluginLog.Error( "GOTT" ); + ImGui.OpenPopup( "OverwriteDir" ); + } + else + { + try + { + dir.MoveTo( newDir.FullName ); + } + catch( Exception e ) + { + PluginLog.Error( $"Error while renaming directory {dir.FullName} to {newDir.FullName}:\n{e}" ); + } + + Mod!.FolderName = _newName; + Mod!.Mod.ModBasePath = newDir; + _selector.ReloadCurrentMod(); + Service< ModManager >.Get()!.Mods!.Save(); + ImGui.CloseCurrentPopup(); + } + } + } + + ImGui.TextColored( GreyColor, + "Please restrict yourself to ascii symbols that are valid in a windows path,\nother symbols will be replaced by underscores." ); + + var closeParent = false; + _ = true; + ImGui.SetNextWindowPos( ImGui.GetMainViewport().GetCenter(), ImGuiCond.Appearing, Vector2.One / 2 ); + if( ImGui.BeginPopupModal( "OverwriteDir", ref _, ImGuiWindowFlags.AlwaysAutoResize ) ) + { + DirectoryInfo dir = Mod!.Mod.ModBasePath; + DirectoryInfo newDir = new( Path.Combine( dir.Parent!.FullName, _newName ) ); + ImGui.Text( + $"The mod directory {newDir} already exists.\nDo you want to merge / overwrite both mods?\nThis may corrupt the resulting mod in irrecoverable ways." ); + var buttonSize = new Vector2( 120, 0 ); + if( ImGui.Button( "Yes", buttonSize ) ) + { + try + { + foreach( var file in dir.EnumerateFiles( "*", SearchOption.AllDirectories ) ) + { + var target = new FileInfo( Path.Combine( newDir.FullName, + file.FullName.Substring( dir.FullName.Length ) ) ); + if( target.Exists ) + { + target.Delete(); + } + + target.Directory?.Create(); + file.MoveTo( target.FullName ); + } + + dir.Delete( true ); + + var mod = Service< ModManager >.Get()!.Mods!.ModSettings! + .RemoveAll( m => m.FolderName == _newName ); + + Mod!.FolderName = _newName; + Mod!.Mod.ModBasePath = newDir; + Service< ModManager >.Get()!.Mods!.Save(); + _base.ReloadMods(); + _selector.SelectModByDir( _newName ); + } + catch( Exception e ) + { + PluginLog.Error( $"Error while renaming directory {dir.FullName} to {newDir.FullName}:\n{e}" ); + } + + closeParent = true; + ImGui.CloseCurrentPopup(); + } + + ImGui.SameLine(); + + if( ImGui.Button( "Cancel", buttonSize ) ) + { + PluginLog.Error( "FUCKFUCK" ); + _keyboardFocus = true; + ImGui.CloseCurrentPopup(); + } + + ImGui.EndPopup(); + } + + if( closeParent ) + { + ImGui.CloseCurrentPopup(); + } + + ImGui.EndPopup(); + } + + if( ImGui.Button( ButtonRenameModFolder ) ) + { + ImGui.OpenPopup( PopupRenameFolder ); + } + + if( ImGui.IsItemHovered() ) + { + ImGui.SetTooltip( TooltipRenameModFolder ); + } + } + private void DrawEditJsonButton() { if( ImGui.Button( ButtonEditJson ) ) @@ -255,6 +405,8 @@ namespace Penumbra.UI { DrawOpenModFolderButton(); ImGui.SameLine(); + DrawRenameModFolderButton(); + ImGui.SameLine(); DrawEditJsonButton(); ImGui.SameLine(); DrawReloadJsonButton(); diff --git a/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledSelector.cs b/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledSelector.cs index d62e6c0f..620605ee 100644 --- a/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledSelector.cs +++ b/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledSelector.cs @@ -1,9 +1,12 @@ +using System; using System.IO; using System.Linq; using System.Numerics; using Dalamud.Interface; +using Dalamud.Plugin; using ImGuiNET; using Newtonsoft.Json; +using Penumbra.Importer; using Penumbra.Models; using Penumbra.Mods; @@ -13,28 +16,34 @@ namespace Penumbra.UI { private class Selector { - private const string LabelSelectorList = "##availableModList"; - private const string LabelModFilter = "##ModFilter"; - private const string TooltipModFilter = "Filter mods for those containing the given substring."; - private const string TooltipMoveDown = "Move the selected mod down in priority"; - private const string TooltipMoveUp = "Move the selected mod up in priority"; - private const string TooltipDelete = "Delete the selected mod"; - private const string TooltipAdd = "Add an empty mod"; - private const string DialogDeleteMod = "PenumbraDeleteMod"; - private const string ButtonYesDelete = "Yes, delete it"; - private const string ButtonNoDelete = "No, keep it"; - private const float SelectorPanelWidth = 240f; - private const uint DisabledModColor = 0xFF666666; - private const uint ConflictingModColor = 0xFFAAAAFF; + private const string LabelSelectorList = "##availableModList"; + private const string LabelModFilter = "##ModFilter"; + private const string LabelPriorityPopup = "Priority"; + private const string LabelAddModPopup = "AddMod"; + private const string TooltipModFilter = "Filter mods for those containing the given substring."; + private const string TooltipMoveDown = "Move the selected mod down in priority"; + private const string TooltipMoveUp = "Move the selected mod up in priority"; + private const string TooltipDelete = "Delete the selected mod"; + private const string TooltipAdd = "Add an empty mod"; + private const string DialogDeleteMod = "PenumbraDeleteMod"; + private const string ButtonYesDelete = "Yes, delete it"; + private const string ButtonNoDelete = "No, keep it"; + private const string DescPriorityPopup = "New Priority:"; + + private const float SelectorPanelWidth = 240f; + private const uint DisabledModColor = 0xFF666666; + private const uint ConflictingModColor = 0xFFAAAAFF; private static readonly Vector2 SelectorButtonSizes = new( 60, 0 ); private static readonly string ArrowUpString = FontAwesomeIcon.ArrowUp.ToIconString(); private static readonly string ArrowDownString = FontAwesomeIcon.ArrowDown.ToIconString(); private readonly SettingsInterface _base; - private ModCollection? Mods => Service< ModManager >.Get().Mods; - private ModInfo? _mod; + private static ModCollection? Mods + => Service< ModManager >.Get().Mods; + + public ModInfo? Mod { get; private set; } private int _index; private int? _deleteIndex; private string _modFilter = ""; @@ -49,8 +58,9 @@ namespace Penumbra.UI public void ResetModNamesLower() { - _modNamesLower = Mods?.ModSettings?.Where(I => I.Mod != null) - .Select( I => I.Mod!.Meta.Name.ToLowerInvariant() ).ToArray() ?? new string[]{}; + _modNamesLower = Mods?.ModSettings?.Where( I => I.Mod != null ) + .Select( I => I.Mod!.Meta.Name.ToLowerInvariant() ).ToArray() + ?? new string[] { }; } private void DrawPriorityChangeButton( string iconString, bool up, int unavailableWhen ) @@ -61,7 +71,7 @@ namespace Penumbra.UI if( ImGui.Button( iconString, SelectorButtonSizes ) ) { SetSelection( _index ); - Service< ModManager >.Get().ChangeModPriority( _mod!, up ); + Service< ModManager >.Get().ChangeModPriority( Mod!, up ); _modNamesLower!.Swap( _index, _index + ( up ? 1 : -1 ) ); _index += up ? 1 : -1; } @@ -100,13 +110,58 @@ namespace Penumbra.UI } } - private static void DrawModAddButton() + private bool _keyboardFocus = true; + + private void DrawModAddButton() { + if( ImGui.BeginPopupContextItem( LabelAddModPopup ) ) + { + if( _keyboardFocus ) + { + ImGui.SetKeyboardFocusHere(); + _keyboardFocus = false; + } + + var newName = ""; + if( ImGui.InputTextWithHint( "##AddMod", "New Mod Name...", ref newName, 64, ImGuiInputTextFlags.EnterReturnsTrue ) ) + { + try + { + var newDir = TexToolsImport.CreateModFolder( new DirectoryInfo( _base._plugin.Configuration!.CurrentCollection ), + newName ); + var modMeta = new ModMeta + { + Author = "Unknown", + Name = newName, + Description = string.Empty, + }; + var metaPath = Path.Combine( newDir.FullName, "meta.json" ); + File.WriteAllText( metaPath, JsonConvert.SerializeObject( modMeta, Formatting.Indented ) ); + _base.ReloadMods(); + SelectModByDir( newDir.Name ); + } + catch( Exception e ) + { + PluginLog.Error( $"Could not create directory for new Mod {newName}:\n{e}" ); + } + + ImGui.CloseCurrentPopup(); + } + + if( ImGui.IsKeyPressed( ImGui.GetKeyIndex( ImGuiKey.Escape ) ) ) + { + ImGui.CloseCurrentPopup(); + } + + ImGui.EndPopup(); + } + ImGui.PushFont( UiBuilder.IconFont ); if( ImGui.Button( FontAwesomeIcon.Plus.ToIconString(), SelectorButtonSizes ) ) { - // Do nothing. YEAH. #TODO. + _keyboardFocus = true; + ImGui.OpenPopup( LabelAddModPopup ); } ImGui.PopFont(); @@ -158,13 +213,15 @@ namespace Penumbra.UI ImGui.OpenPopup( DialogDeleteMod ); - var ret = ImGui.BeginPopupModal( DialogDeleteMod ); + var _ = true; + ImGui.SetNextWindowPos( ImGui.GetMainViewport().GetCenter(), ImGuiCond.Appearing, Vector2.One / 2 ); + var ret = ImGui.BeginPopupModal( DialogDeleteMod, ref _, ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoDecoration ); if( !ret ) { return; } - if( _mod?.Mod == null ) + if( Mod?.Mod == null ) { ImGui.CloseCurrentPopup(); ImGui.EndPopup(); @@ -173,19 +230,22 @@ namespace Penumbra.UI ImGui.Text( "Are you sure you want to delete the following mod:" ); // todo: why the fuck does this become null?????? - ImGui.Text( _mod?.Mod?.Meta?.Name ); + ImGui.Dummy( new Vector2( ImGui.GetTextLineHeight() / 2 ) ); + ImGui.TextColored( new Vector4( 0.7f, 0.1f, 0.1f, 1 ), Mod?.Mod?.Meta?.Name ?? "Unknown" ); + ImGui.Dummy( new Vector2( ImGui.GetTextLineHeight() ) / 2 ); - if( ImGui.Button( ButtonYesDelete ) ) + var buttonSize = new Vector2( 120, 0 ); + if( ImGui.Button( ButtonYesDelete, buttonSize ) ) { ImGui.CloseCurrentPopup(); - Service< ModManager >.Get().DeleteMod( _mod?.Mod ); + Service< ModManager >.Get().DeleteMod( Mod?.Mod ); ClearSelection(); _base.ReloadMods(); } ImGui.SameLine(); - if( ImGui.Button( ButtonNoDelete ) ) + if( ImGui.Button( ButtonNoDelete, buttonSize ) ) { ImGui.CloseCurrentPopup(); _deleteIndex = null; @@ -194,6 +254,7 @@ namespace Penumbra.UI ImGui.EndPopup(); } + private int _priorityPopupIdx = 0; public void Draw() { @@ -207,7 +268,6 @@ namespace Penumbra.UI ImGui.PushStyleVar( ImGuiStyleVar.ItemSpacing, ZeroVector ); DrawModsSelectorFilter(); - // Inlay selector list ImGui.BeginChild( LabelSelectorList, new Vector2( SelectorPanelWidth, -ImGui.GetFrameHeightWithSpacing() ), true ); @@ -242,6 +302,19 @@ namespace Penumbra.UI #else var selected = ImGui.Selectable( modName, modIndex == _index ); #endif + if( ImGui.IsItemClicked( ImGuiMouseButton.Right ) ) + { + if( ImGui.IsPopupOpen( LabelPriorityPopup ) ) + { + ImGui.CloseCurrentPopup(); + } + + _priorityPopupIdx = modIndex; + _keyboardFocus = true; + ImGui.OpenPopup( LabelPriorityPopup ); + } + + ImGui.OpenPopupOnItemClick( LabelPriorityPopup, ImGuiPopupFlags.MouseButtonRight ); if( changedColour ) { @@ -261,13 +334,54 @@ namespace Penumbra.UI ImGui.EndGroup(); DrawDeleteModal(); + DrawPriorityPopup(); + } + + private void DrawPriorityPopup() + { + if( !ImGui.BeginPopupContextItem( LabelPriorityPopup ) ) + { + return; + } + + var size = ImGui.CalcTextSize( DescPriorityPopup ).X; + //ImGui.Text( DescPriorityPopup ); + var newPriority = _priorityPopupIdx; + + if( _keyboardFocus ) + { + ImGui.SetKeyboardFocusHere( -1 ); + _keyboardFocus = false; + } + + ImGui.SetNextItemWidth( size ); + if( ImGui.InputInt( "New Priority", ref newPriority, 0, 0, + ImGuiInputTextFlags.EnterReturnsTrue ) + && newPriority != _priorityPopupIdx ) + { + Service< ModManager >.Get().ChangeModPriority( Mods!.ModSettings![ _priorityPopupIdx ], newPriority ); + ResetModNamesLower(); + if( _priorityPopupIdx == _index ) + { + _index = newPriority; + SetSelection( _index ); + } + + ImGui.CloseCurrentPopup(); + } + + if( ImGui.IsKeyPressed( ImGui.GetKeyIndex( ImGuiKey.Escape ) ) ) + { + ImGui.CloseCurrentPopup(); + } + + ImGui.EndPopup(); } - public ModInfo? Mod() => _mod; private void SetSelection( int idx, ModInfo? info ) { - _mod = info; + Mod = info; if( idx != _index ) { _base._menu.InstalledTab.ModPanel.Details.ResetState(); @@ -294,7 +408,8 @@ namespace Penumbra.UI } } - public void ClearSelection() => SetSelection( -1 ); + public void ClearSelection() + => SetSelection( -1 ); public void SelectModByName( string name ) { @@ -302,32 +417,40 @@ namespace Penumbra.UI SetSelection( idx ); } + public void SelectModByDir( string name ) + { + var idx = Mods?.ModSettings?.FindIndex( mod => mod.FolderName == name ) ?? -1; + SetSelection( idx ); + } + private string GetCurrentModMetaFile() - => _mod == null ? "" : Path.Combine( _mod.Mod.ModBasePath.FullName, "meta.json" ); + => Mod == null ? "" : Path.Combine( Mod.Mod.ModBasePath.FullName, "meta.json" ); public void ReloadCurrentMod() { var metaPath = GetCurrentModMetaFile(); if( metaPath.Length > 0 && File.Exists( metaPath ) ) { - _mod!.Mod.Meta = ModMeta.LoadFromFile( metaPath ) ?? _mod.Mod.Meta; + Mod!.Mod.Meta = ModMeta.LoadFromFile( metaPath ) ?? Mod.Mod.Meta; _base._menu.InstalledTab.ModPanel.Details.ResetState(); } - _mod!.Mod.RefreshModFiles(); + Mod!.Mod.RefreshModFiles(); Service< ModManager >.Get().CalculateEffectiveFileList(); ResetModNamesLower(); } public string SaveCurrentMod() { - if( _mod == null ) + if( Mod == null ) + { return ""; + } var metaPath = GetCurrentModMetaFile(); if( metaPath.Length > 0 ) { - File.WriteAllText( metaPath, JsonConvert.SerializeObject( _mod.Mod.Meta, Formatting.Indented ) ); + File.WriteAllText( metaPath, JsonConvert.SerializeObject( Mod.Mod.Meta, Formatting.Indented ) ); } _base._menu.InstalledTab.ModPanel.Details.ResetState();