From d52086b69c9f8dc1c88d1b14813108d13e5e17f1 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Mon, 28 Jun 2021 22:33:36 +0200 Subject: [PATCH] Introducing custom Sort Order for mods and collapsible folders inside the mod selector based on '/' in the sort order. --- Penumbra/Configuration.cs | 2 + Penumbra/Mod/ModData.cs | 2 + Penumbra/Mods/ModCollectionCache.cs | 2 +- Penumbra/Mods/ModManager.cs | 29 +++++++ Penumbra/Mods/ModManagerEditExtensions.cs | 37 +++++++++ .../TabInstalled/TabInstalledModPanel.cs | 16 +++- .../TabInstalled/TabInstalledSelector.cs | 82 ++++++++++++++++--- 7 files changed, 157 insertions(+), 13 deletions(-) diff --git a/Penumbra/Configuration.cs b/Penumbra/Configuration.cs index 53606f35..4a86a3d4 100644 --- a/Penumbra/Configuration.cs +++ b/Penumbra/Configuration.cs @@ -27,6 +27,8 @@ namespace Penumbra public string CurrentCollection { get; set; } = "Default"; public string ForcedCollection { get; set; } = ""; public Dictionary< string, string > CharacterCollections { get; set; } = new(); + public Dictionary< string, string > ModSortOrder { get; set; } = new(); + public bool InvertModListOrder { internal get; set; } public static Configuration Load( DalamudPluginInterface pi ) diff --git a/Penumbra/Mod/ModData.cs b/Penumbra/Mod/ModData.cs index 94d12ae0..0ed16f5c 100644 --- a/Penumbra/Mod/ModData.cs +++ b/Penumbra/Mod/ModData.cs @@ -11,6 +11,7 @@ namespace Penumbra.Mod public DirectoryInfo BasePath; public ModMeta Meta; public ModResources Resources; + public string SortOrder; public FileInfo MetaFile { get; set; } @@ -20,6 +21,7 @@ namespace Penumbra.Mod Meta = meta; Resources = resources; MetaFile = MetaFileInfo( basePath ); + SortOrder = meta.Name; } public static FileInfo MetaFileInfo( DirectoryInfo basePath ) diff --git a/Penumbra/Mods/ModCollectionCache.cs b/Penumbra/Mods/ModCollectionCache.cs index ea34db2a..d00239cf 100644 --- a/Penumbra/Mods/ModCollectionCache.cs +++ b/Penumbra/Mods/ModCollectionCache.cs @@ -23,7 +23,7 @@ namespace Penumbra.Mods public void SortMods() { - AvailableMods.Sort( ( m1, m2 ) => string.Compare( m1.Data.Meta.Name, m2.Data.Meta.Name, StringComparison.InvariantCulture ) ); + AvailableMods.Sort( ( m1, m2 ) => string.Compare( m1.Data.SortOrder, m2.Data.SortOrder, StringComparison.InvariantCultureIgnoreCase ) ); } private void AddFiles( Dictionary< GamePath, Mod.Mod > registeredFiles, Mod.Mod mod ) diff --git a/Penumbra/Mods/ModManager.cs b/Penumbra/Mods/ModManager.cs index 5c97ba52..0f2d9c74 100644 --- a/Penumbra/Mods/ModManager.cs +++ b/Penumbra/Mods/ModManager.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using Dalamud.Plugin; using Penumbra.Meta; using Penumbra.Mod; @@ -12,13 +13,18 @@ namespace Penumbra.Mods // It also contains the CollectionManager that handles all collections. public class ModManager { + private readonly Plugin _plugin; public DirectoryInfo BasePath { get; private set; } public Dictionary< string, ModData > Mods { get; } = new(); public CollectionManager Collections { get; } + public Configuration Config + => _plugin.Configuration; + public ModManager( Plugin plugin ) { + _plugin = plugin; BasePath = new DirectoryInfo( plugin.Configuration.ModDirectory ); Collections = new CollectionManager( plugin, this ); } @@ -29,6 +35,28 @@ namespace Penumbra.Mods DiscoverMods(); } + private void SetModOrders( Configuration config ) + { + var changes = false; + foreach( var kvp in config.ModSortOrder.ToArray() ) + { + if( Mods.TryGetValue( kvp.Key, out var mod ) ) + { + mod.SortOrder = string.Join( "/", kvp.Value.Trim().Split( new[] { "/" }, StringSplitOptions.RemoveEmptyEntries ) ); + } + else + { + changes = true; + config.ModSortOrder.Remove( kvp.Key ); + } + } + + if( changes ) + { + config.Save(); + } + } + public void DiscoverMods() { Mods.Clear(); @@ -57,6 +85,7 @@ namespace Penumbra.Mods Mods.Add( modFolder.Name, mod ); } + SetModOrders( _plugin.Configuration ); Collections.RecreateCaches(); } diff --git a/Penumbra/Mods/ModManagerEditExtensions.cs b/Penumbra/Mods/ModManagerEditExtensions.cs index f19cb449..ce121444 100644 --- a/Penumbra/Mods/ModManagerEditExtensions.cs +++ b/Penumbra/Mods/ModManagerEditExtensions.cs @@ -30,6 +30,36 @@ namespace Penumbra.Mods return true; } + public static bool ChangeSortOrder( this ModManager manager, ModData mod, string newSortOrder ) + { + newSortOrder = string.Join( "/", newSortOrder.Trim().Split( new[] { "/" }, StringSplitOptions.RemoveEmptyEntries ) ); + + if( mod.SortOrder == newSortOrder ) + { + return false; + } + + if( newSortOrder == string.Empty || newSortOrder == mod.Meta.Name ) + { + mod.SortOrder = mod.Meta.Name; + manager.Config.ModSortOrder.Remove( mod.BasePath.Name ); + } + else + { + mod.SortOrder = newSortOrder; + manager.Config.ModSortOrder[ mod.BasePath.Name ] = newSortOrder; + } + + manager.Config.Save(); + + foreach( var collection in manager.Collections.Collections.Values.Where( c => c.Cache != null ) ) + { + collection.Cache!.SortMods(); + } + + return true; + } + public static bool RenameModFolder( this ModManager manager, ModData mod, DirectoryInfo newDir, bool move = true ) { if( move ) @@ -60,6 +90,13 @@ namespace Penumbra.Mods mod.MetaFile = ModData.MetaFileInfo( newDir ); manager.UpdateMod( mod ); + if( manager.Config.ModSortOrder.ContainsKey( oldBasePath.Name ) ) + { + manager.Config.ModSortOrder[ newDir.Name ] = manager.Config.ModSortOrder[ oldBasePath.Name ]; + manager.Config.ModSortOrder.Remove( oldBasePath.Name ); + manager.Config.Save(); + } + foreach( var collection in manager.Collections.Collections.Values ) { if( collection.Settings.TryGetValue( oldBasePath.Name, out var settings ) ) diff --git a/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledModPanel.cs b/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledModPanel.cs index 576561a1..716c93bc 100644 --- a/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledModPanel.cs +++ b/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledModPanel.cs @@ -2,6 +2,7 @@ using System; using System.Diagnostics; using System.IO; using System.Numerics; +using System.Windows.Forms; using Dalamud.Plugin; using ImGuiNET; using Penumbra.Mod; @@ -224,6 +225,17 @@ namespace Penumbra.UI } } + private void DrawSortOrder() + { + var currentSortOrder = Mod!.Data.SortOrder; + ImGui.SetNextItemWidth( 300 ); + if( ImGui.InputText( "Sort Order", ref currentSortOrder, 256, ImGuiInputTextFlags.EnterReturnsTrue ) ) + { + _modManager.ChangeSortOrder( Mod.Data, currentSortOrder ); + _selector.SelectModByDir( Mod.Data.BasePath.Name ); + } + } + private void DrawEditableMark() { ImGui.Checkbox( LabelEditingEnabled, ref _editMode ); @@ -262,7 +274,7 @@ namespace Penumbra.UI { ImGui.OpenPopup( LabelOverWriteDir ); } - else if( Service< ModManager >.Get()!.RenameModFolder( Mod.Data, newDir ) ) + else if( _modManager.RenameModFolder( Mod.Data, newDir ) ) { _selector.ReloadCurrentMod(); ImGui.CloseCurrentPopup(); @@ -478,6 +490,8 @@ namespace Penumbra.UI DrawDeduplicateButton(); ImGui.SameLine(); DrawNormalizeButton(); + + DrawSortOrder(); } public void Draw() diff --git a/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledSelector.cs b/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledSelector.cs index b8c1242a..926e41dc 100644 --- a/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledSelector.cs +++ b/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledSelector.cs @@ -6,6 +6,7 @@ using System.Numerics; using Dalamud.Interface; using Dalamud.Plugin; using ImGuiNET; +using ImGuiScene; using Penumbra.Importer; using Penumbra.Mod; using Penumbra.Mods; @@ -73,6 +74,7 @@ namespace Penumbra.UI private readonly SettingsInterface _base; private readonly ModManager _modManager; + private string _currentModGroup = ""; private List< Mod.Mod >? Mods => _modManager.Collections.CurrentCollection.Cache?.AvailableMods; @@ -301,17 +303,15 @@ namespace Penumbra.UI return true; } + private bool CheckFilters( Mod.Mod mod, int modIndex ) + => ( _modFilter.Length <= 0 || _modNamesLower[ modIndex ].Contains( _modFilter ) ) + && !CheckFlags( mod.Data.Resources.ModFiles.Count, ModFilter.HasNoFiles, ModFilter.HasFiles ) + && !CheckFlags( mod.Data.Meta.FileSwaps.Count, ModFilter.HasNoFileSwaps, ModFilter.HasFileSwaps ) + && !CheckFlags( mod.Data.Resources.MetaManipulations.Count, ModFilter.HasNoMetaManipulations, ModFilter.HasMetaManipulations ) + && !CheckFlags( mod.Data.Meta.HasGroupsWithConfig ? 1 : 0, ModFilter.HasNoConfig, ModFilter.HasConfig ); + public void DrawMod( Mod.Mod mod, int modIndex ) { - if( _modFilter.Length > 0 && !_modNamesLower[ modIndex ].Contains( _modFilter ) - || CheckFlags( mod.Data.Resources.ModFiles.Count, ModFilter.HasNoFiles, ModFilter.HasFiles ) - || CheckFlags( mod.Data.Meta.FileSwaps.Count, ModFilter.HasNoFileSwaps, ModFilter.HasFileSwaps ) - || CheckFlags( mod.Data.Resources.MetaManipulations.Count, ModFilter.HasNoMetaManipulations, ModFilter.HasMetaManipulations ) - || CheckFlags( mod.Data.Meta.HasGroupsWithConfig ? 1 : 0, ModFilter.HasNoConfig, ModFilter.HasConfig ) ) - { - return; - } - var changedColour = false; if( !mod.Settings.Enabled ) { @@ -372,6 +372,59 @@ namespace Penumbra.UI } } + private bool DrawModGroup( Mod.Mod mod, ref int modIndex ) + { + if( !CheckFilters( mod, modIndex ) ) + { + return true; + } + + if( !mod.Data.SortOrder.StartsWith( _currentModGroup ) ) + { + var count = _currentModGroup.Length - 2; + var lastFolder = _currentModGroup.LastIndexOf( '/', _currentModGroup.Length - 2 ); + _currentModGroup = lastFolder == -1 ? string.Empty : _currentModGroup.Substring( 0, lastFolder + 1 ); + ImGui.TreePop(); + return false; + } + + var nextFolder = mod.Data.SortOrder.IndexOf( '/', _currentModGroup.Length ); + if( nextFolder == -1 ) + { + DrawMod( mod, modIndex ); + } + else + { + var mods = Mods!; + var folderLabel = + $"{mod.Data.SortOrder.Substring( _currentModGroup.Length, nextFolder - _currentModGroup.Length )}##{modIndex}_{_currentModGroup.Length}"; + _currentModGroup = mod.Data.SortOrder.Substring( 0, nextFolder + 1 ); + if( ImGui.TreeNodeEx( folderLabel ) ) + { + for( ; modIndex < mods.Count; ++modIndex ) + { + if( !DrawModGroup( mods[ modIndex ], ref modIndex ) ) + { + return false; + } + } + } + else + { + ImGui.TreePush(); + for( ; modIndex < mods.Count; ++modIndex ) + { + if( !mods[ modIndex ].Data.SortOrder.StartsWith( _currentModGroup ) ) + { + return false; + } + } + } + } + + return true; + } + public void Draw() { if( Mods == null ) @@ -387,11 +440,18 @@ namespace Penumbra.UI // Inlay selector list ImGui.BeginChild( LabelSelectorList, new Vector2( SelectorPanelWidth, -ImGui.GetFrameHeightWithSpacing() ), true ); - for( var modIndex = 0; modIndex < Mods.Count; modIndex++ ) + ImGui.PushStyleVar( ImGuiStyleVar.IndentSpacing, 10 ); + for( var modIndex = 0; modIndex < Mods!.Count; ) { - DrawMod( Mods[ modIndex ], modIndex ); + if( DrawModGroup( Mods[ modIndex ], ref modIndex ) ) + { + ++modIndex; + } } + ImGui.PopStyleVar(); + + ImGui.EndChild(); DrawModsSelectorButtons();