diff --git a/Penumbra/Api/ModsController.cs b/Penumbra/Api/ModsController.cs
index bde6d2db..77f1b496 100644
--- a/Penumbra/Api/ModsController.cs
+++ b/Penumbra/Api/ModsController.cs
@@ -16,17 +16,15 @@ public class ModsController : WebApiController
[Route( HttpVerbs.Get, "/mods" )]
public object? GetMods()
{
- // TODO
- return null;
- //return Penumbra.ModManager.Mods.Zip( Penumbra.CollectionManager.Current.ActualSettings ).Select( x => new
- //{
- // x.Second?.Enabled,
- // x.Second?.Priority,
- // x.First.BasePath.Name,
- // x.First.Name,
- // BasePath = x.First.BasePath.FullName,
- // Files = x.First.Resources.ModFiles.Select( fi => fi.FullName ),
- //} );
+ return Penumbra.ModManager.Zip( Penumbra.CollectionManager.Current.ActualSettings ).Select( x => new
+ {
+ x.Second?.Enabled,
+ x.Second?.Priority,
+ FolderName = x.First.BasePath.Name,
+ x.First.Name,
+ BasePath = x.First.BasePath.FullName,
+ Files = x.First.AllFiles,
+ } );
}
[Route( HttpVerbs.Post, "/mods" )]
diff --git a/Penumbra/Collections/ModCollection.Cache.cs b/Penumbra/Collections/ModCollection.Cache.cs
index 5283ec4f..fe008820 100644
--- a/Penumbra/Collections/ModCollection.Cache.cs
+++ b/Penumbra/Collections/ModCollection.Cache.cs
@@ -251,7 +251,7 @@ public partial class ModCollection
return;
}
- var mod = Penumbra.ModManager.Mods[ modIdx ];
+ var mod = Penumbra.ModManager[ modIdx ];
AddSubMod( mod.Default, new FileRegister( modIdx, settings.Priority, 0, 0 ), withManipulations );
for( var idx = 0; idx < mod.Groups.Count; ++idx )
{
diff --git a/Penumbra/Collections/ModCollection.Changes.cs b/Penumbra/Collections/ModCollection.Changes.cs
index cbf0b09d..9ff07910 100644
--- a/Penumbra/Collections/ModCollection.Changes.cs
+++ b/Penumbra/Collections/ModCollection.Changes.cs
@@ -98,7 +98,7 @@ public partial class ModCollection
if( oldValue != newValue )
{
var inheritance = FixInheritance( idx, false );
- _settings[ idx ]!.SetValue( Penumbra.ModManager.Mods[ idx ], groupIdx, newValue );
+ _settings[ idx ]!.SetValue( Penumbra.ModManager[ idx ], groupIdx, newValue );
ModSettingChanged.Invoke( ModSettingChange.Setting, idx, inheritance ? -1 : ( int )oldValue, groupIdx, false );
}
}
@@ -137,7 +137,7 @@ public partial class ModCollection
return false;
}
- _settings[ idx ] = inherit ? null : this[ idx ].Settings?.DeepCopy() ?? ModSettings.DefaultSettings( Penumbra.ModManager.Mods[ idx ] );
+ _settings[ idx ] = inherit ? null : this[ idx ].Settings?.DeepCopy() ?? ModSettings.DefaultSettings( Penumbra.ModManager[ idx ] );
return true;
}
diff --git a/Penumbra/Collections/ModCollection.cs b/Penumbra/Collections/ModCollection.cs
index a540272f..54561930 100644
--- a/Penumbra/Collections/ModCollection.cs
+++ b/Penumbra/Collections/ModCollection.cs
@@ -32,6 +32,10 @@ public partial class ModCollection
public IReadOnlyList< ModSettings? > Settings
=> _settings;
+ // Returns whether there are settings not in use by any current mod.
+ public bool HasUnusedSettings
+ => _unusedSettings.Count > 0;
+
// Evaluates the settings along the whole inheritance tree.
public IEnumerable< ModSettings? > ActualSettings
=> Enumerable.Range( 0, _settings.Count ).Select( i => this[ i ].Settings );
diff --git a/Penumbra/Configuration.Constants.cs b/Penumbra/Configuration.Constants.cs
deleted file mode 100644
index 0cdcd9ec..00000000
--- a/Penumbra/Configuration.Constants.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-namespace Penumbra;
-
-public partial class Configuration
-{
- // Contains some default values or boundaries for config values.
- public static class Constants
- {
- public const int CurrentVersion = 3;
- public const float MaxAbsoluteSize = 600;
- public const int DefaultAbsoluteSize = 250;
- public const float MinAbsoluteSize = 50;
- public const int MaxScaledSize = 80;
- public const int DefaultScaledSize = 20;
- public const int MinScaledSize = 5;
- }
-}
\ No newline at end of file
diff --git a/Penumbra/MigrateConfiguration.cs b/Penumbra/Configuration.Migration.cs
similarity index 100%
rename from Penumbra/MigrateConfiguration.cs
rename to Penumbra/Configuration.Migration.cs
diff --git a/Penumbra/Configuration.cs b/Penumbra/Configuration.cs
index 05d9cc81..565d7975 100644
--- a/Penumbra/Configuration.cs
+++ b/Penumbra/Configuration.cs
@@ -86,4 +86,16 @@ public partial class Configuration : IPluginConfiguration
Save();
}
}
+
+ // Contains some default values or boundaries for config values.
+ public static class Constants
+ {
+ public const int CurrentVersion = 3;
+ public const float MaxAbsoluteSize = 600;
+ public const int DefaultAbsoluteSize = 250;
+ public const float MinAbsoluteSize = 50;
+ public const int MaxScaledSize = 80;
+ public const int DefaultScaledSize = 20;
+ public const int MinScaledSize = 5;
+ }
}
\ No newline at end of file
diff --git a/Penumbra/Mods/Manager/Mod.Manager.BasePath.cs b/Penumbra/Mods/Manager/Mod.Manager.BasePath.cs
index ce095609..8e44edfd 100644
--- a/Penumbra/Mods/Manager/Mod.Manager.BasePath.cs
+++ b/Penumbra/Mods/Manager/Mod.Manager.BasePath.cs
@@ -12,14 +12,19 @@ public partial class Mod
public delegate void ModPathChangeDelegate( ModPathChangeType type, Mod mod, DirectoryInfo? oldDirectory,
DirectoryInfo? newDirectory );
- public event ModPathChangeDelegate? ModPathChanged;
+ public event ModPathChangeDelegate ModPathChanged;
+ // Rename/Move a mod directory.
+ // Updates all collection settings and sort order settings.
public void MoveModDirectory( Index idx, DirectoryInfo newDirectory )
{
var mod = this[ idx ];
// TODO
}
+ // Delete a mod by its index.
+ // Deletes from filesystem as well as from internal data.
+ // Updates indices of later mods.
public void DeleteMod( int idx )
{
var mod = this[ idx ];
@@ -41,9 +46,10 @@ public partial class Mod
--remainingMod.Index;
}
- ModPathChanged?.Invoke( ModPathChangeType.Deleted, mod, mod.BasePath, null );
+ ModPathChanged.Invoke( ModPathChangeType.Deleted, mod, mod.BasePath, null );
}
+ // Load a new mod and add it to the manager if successful.
public void AddMod( DirectoryInfo modFolder )
{
if( _mods.Any( m => m.BasePath.Name == modFolder.Name ) )
@@ -59,7 +65,22 @@ public partial class Mod
mod.Index = _mods.Count;
_mods.Add( mod );
- ModPathChanged?.Invoke( ModPathChangeType.Added, mod, null, mod.BasePath );
+ ModPathChanged.Invoke( ModPathChangeType.Added, mod, null, mod.BasePath );
+ }
+
+ // Add new mods to NewMods and remove deleted mods from NewMods.
+ private void OnModPathChange( ModPathChangeType type, Mod mod, DirectoryInfo? oldDirectory,
+ DirectoryInfo? newDirectory )
+ {
+ switch( type )
+ {
+ case ModPathChangeType.Added:
+ NewMods.Add( mod );
+ break;
+ case ModPathChangeType.Deleted:
+ NewMods.Remove( mod );
+ break;
+ }
}
}
}
\ No newline at end of file
diff --git a/Penumbra/Mods/Manager/Mod.Manager.Options.cs b/Penumbra/Mods/Manager/Mod.Manager.Options.cs
index 78f3d58c..cdfa142b 100644
--- a/Penumbra/Mods/Manager/Mod.Manager.Options.cs
+++ b/Penumbra/Mods/Manager/Mod.Manager.Options.cs
@@ -197,6 +197,14 @@ public sealed partial class Mod
return;
}
+ if( mod._groups[ groupIdx ].Count > 63 )
+ {
+ PluginLog.Error(
+ $"Could not add option {option.Name} to {mod._groups[ groupIdx ].Name} for mod {mod.Name}, "
+ + "since only up to 64 options are supported in one group." );
+ return;
+ }
+
switch( mod._groups[ groupIdx ] )
{
case SingleModGroup s:
diff --git a/Penumbra/Mods/Manager/Mod.Manager.Root.cs b/Penumbra/Mods/Manager/Mod.Manager.Root.cs
index 6967f0bc..a27d5c02 100644
--- a/Penumbra/Mods/Manager/Mod.Manager.Root.cs
+++ b/Penumbra/Mods/Manager/Mod.Manager.Root.cs
@@ -11,16 +11,19 @@ public sealed partial class Mod
public DirectoryInfo BasePath { get; private set; } = null!;
public bool Valid { get; private set; }
-
public event Action? ModDiscoveryStarted;
public event Action? ModDiscoveryFinished;
+ // Change the mod base directory and discover available mods.
public void DiscoverMods( string newDir )
{
SetBaseDirectory( newDir, false );
DiscoverMods();
}
+ // Set the mod base directory.
+ // If its not the first time, check if it is the same directory as before.
+ // Also checks if the directory is available and tries to create it if it is not.
private void SetBaseDirectory( string newPath, bool firstTime )
{
if( !firstTime && string.Equals( newPath, Penumbra.Config.ModDirectory, StringComparison.InvariantCultureIgnoreCase ) )
@@ -59,8 +62,10 @@ public sealed partial class Mod
}
}
+ // Discover new mods.
public void DiscoverMods()
{
+ NewMods.Clear();
ModDiscoveryStarted?.Invoke();
_mods.Clear();
BasePath.Refresh();
diff --git a/Penumbra/Mods/Manager/Mod.Manager.cs b/Penumbra/Mods/Manager/Mod.Manager.cs
index e467c733..7a21a3a8 100644
--- a/Penumbra/Mods/Manager/Mod.Manager.cs
+++ b/Penumbra/Mods/Manager/Mod.Manager.cs
@@ -6,16 +6,22 @@ namespace Penumbra.Mods;
public sealed partial class Mod
{
- public sealed partial class Manager : IEnumerable< Mod >
+ public sealed partial class Manager : IReadOnlyList< Mod >
{
+ // An easily accessible set of new mods.
+ // Mods are added when they are created or imported.
+ // Mods are removed when they are deleted or when they are toggled in any collection.
+ // Also gets cleared on mod rediscovery.
+ public readonly HashSet< Mod > NewMods = new();
+
private readonly List< Mod > _mods = new();
+ public Mod this[ int idx ]
+ => _mods[ idx ];
+
public Mod this[ Index idx ]
=> _mods[ idx ];
- public IReadOnlyList< Mod > Mods
- => _mods;
-
public int Count
=> _mods.Count;
@@ -29,6 +35,7 @@ public sealed partial class Mod
{
SetBaseDirectory( modDirectory, true );
ModOptionChanged += OnModOptionChange;
+ ModPathChanged += OnModPathChange;
}
}
}
\ No newline at end of file
diff --git a/Penumbra/Mods/Mod.BasePath.cs b/Penumbra/Mods/Mod.BasePath.cs
index c925a4f0..24cf84f1 100644
--- a/Penumbra/Mods/Mod.BasePath.cs
+++ b/Penumbra/Mods/Mod.BasePath.cs
@@ -18,7 +18,7 @@ public partial class Mod
private Mod( DirectoryInfo basePath )
=> BasePath = basePath;
- public static Mod? LoadMod( DirectoryInfo basePath )
+ private static Mod? LoadMod( DirectoryInfo basePath )
{
basePath.Refresh();
if( !basePath.Exists )
diff --git a/Penumbra/Mods/Mod.ChangedItems.cs b/Penumbra/Mods/Mod.ChangedItems.cs
index 9e68225c..d2996b71 100644
--- a/Penumbra/Mods/Mod.ChangedItems.cs
+++ b/Penumbra/Mods/Mod.ChangedItems.cs
@@ -8,7 +8,7 @@ public sealed partial class Mod
public SortedList< string, object? > ChangedItems { get; } = new();
public string LowerChangedItemsString { get; private set; } = string.Empty;
- public void ComputeChangedItems()
+ private void ComputeChangedItems()
{
var identifier = GameData.GameData.GetIdentifier();
ChangedItems.Clear();
diff --git a/Penumbra/Mods/Mod.Files.cs b/Penumbra/Mods/Mod.Files.cs
index 4ff1bbd9..0eee20b0 100644
--- a/Penumbra/Mods/Mod.Files.cs
+++ b/Penumbra/Mods/Mod.Files.cs
@@ -78,7 +78,7 @@ public partial class Mod
public List< FullPath > FindMissingFiles()
=> AllFiles.Where( f => !f.Exists ).ToList();
- public static IModGroup? LoadModGroup( FileInfo file, DirectoryInfo basePath )
+ private static IModGroup? LoadModGroup( FileInfo file, DirectoryInfo basePath )
{
if( !File.Exists( file.FullName ) )
{
diff --git a/Penumbra/Mods/Mod.Meta.cs b/Penumbra/Mods/Mod.Meta.cs
index 33760dfe..6e5291a6 100644
--- a/Penumbra/Mods/Mod.Meta.cs
+++ b/Penumbra/Mods/Mod.Meta.cs
@@ -25,13 +25,13 @@ public sealed partial class Mod
{
public const uint CurrentFileVersion = 1;
public uint FileVersion { get; private set; } = CurrentFileVersion;
- public LowerString Name { get; private set; } = "Mod";
+ public LowerString Name { get; private set; } = "New Mod";
public LowerString Author { get; private set; } = LowerString.Empty;
public string Description { get; private set; } = string.Empty;
public string Version { get; private set; } = string.Empty;
public string Website { get; private set; } = string.Empty;
- private FileInfo MetaFile
+ internal FileInfo MetaFile
=> new(Path.Combine( BasePath.FullName, "meta.json" ));
private MetaChangeType LoadMeta()
diff --git a/Penumbra/Mods/ModCleanup.cs b/Penumbra/Mods/ModCleanup.cs
index 9497c9c6..996c6437 100644
--- a/Penumbra/Mods/ModCleanup.cs
+++ b/Penumbra/Mods/ModCleanup.cs
@@ -12,6 +12,7 @@ using Penumbra.Util;
namespace Penumbra.Mods;
+// TODO Everything
//ublic class ModCleanup
//
// private const string Duplicates = "Duplicates";
@@ -521,7 +522,6 @@ namespace Penumbra.Mods;
// }
// }
//
-// // TODO
// var idx = Penumbra.ModManager.Mods.IndexOf( m => m.Meta == meta );
// foreach( var collection in Penumbra.CollectionManager )
// {
diff --git a/Penumbra/Mods/ModFileSystem.cs b/Penumbra/Mods/ModFileSystem.cs
index d310250b..eb22b314 100644
--- a/Penumbra/Mods/ModFileSystem.cs
+++ b/Penumbra/Mods/ModFileSystem.cs
@@ -42,7 +42,7 @@ public sealed class ModFileSystem : FileSystem< Mod >, IDisposable
// Used on construction and on mod rediscoveries.
private void Reload()
{
- if( Load( new FileInfo( ModFileSystemFile ), Penumbra.ModManager.Mods, ModToIdentifier, ModToName ) )
+ if( Load( new FileInfo( ModFileSystemFile ), Penumbra.ModManager, ModToIdentifier, ModToName ) )
{
Save();
}
diff --git a/Penumbra/Mods/Subclasses/IModGroup.cs b/Penumbra/Mods/Subclasses/IModGroup.cs
index 924e294e..c89b2da9 100644
--- a/Penumbra/Mods/Subclasses/IModGroup.cs
+++ b/Penumbra/Mods/Subclasses/IModGroup.cs
@@ -4,10 +4,15 @@ using System.IO;
using Dalamud.Logging;
using Newtonsoft.Json;
using OtterGui.Filesystem;
-using Penumbra.Util;
namespace Penumbra.Mods;
+public enum SelectType
+{
+ Single,
+ Multi,
+}
+
public interface IModGroup : IEnumerable< ISubMod >
{
public string Name { get; }
diff --git a/Penumbra/Mods/Subclasses/Mod.Files.MultiModGroup.cs b/Penumbra/Mods/Subclasses/Mod.Files.MultiModGroup.cs
index 88350364..26d3abe3 100644
--- a/Penumbra/Mods/Subclasses/Mod.Files.MultiModGroup.cs
+++ b/Penumbra/Mods/Subclasses/Mod.Files.MultiModGroup.cs
@@ -11,6 +11,7 @@ namespace Penumbra.Mods;
public partial class Mod
{
+ // Groups that allow all available options to be selected at once.
private sealed class MultiModGroup : IModGroup
{
public SelectType Type
diff --git a/Penumbra/Mods/Subclasses/Mod.Files.SingleModGroup.cs b/Penumbra/Mods/Subclasses/Mod.Files.SingleModGroup.cs
index 8c0b4103..352bb503 100644
--- a/Penumbra/Mods/Subclasses/Mod.Files.SingleModGroup.cs
+++ b/Penumbra/Mods/Subclasses/Mod.Files.SingleModGroup.cs
@@ -11,6 +11,7 @@ namespace Penumbra.Mods;
public partial class Mod
{
+ // Groups that allow only one of their available options to be selected.
private sealed class SingleModGroup : IModGroup
{
public SelectType Type
diff --git a/Penumbra/Mods/Subclasses/Mod.Files.SubMod.cs b/Penumbra/Mods/Subclasses/Mod.Files.SubMod.cs
index e9be472d..786ac6de 100644
--- a/Penumbra/Mods/Subclasses/Mod.Files.SubMod.cs
+++ b/Penumbra/Mods/Subclasses/Mod.Files.SubMod.cs
@@ -13,9 +13,11 @@ namespace Penumbra.Mods;
public partial class Mod
{
- private string DefaultFile
+ internal string DefaultFile
=> Path.Combine( BasePath.FullName, "default_mod.json" );
+ // The default mod contains setting-independent sets of file replacements, file swaps and meta changes.
+ // Every mod has an default mod, though it may be empty.
private void SaveDefaultMod()
{
var defaultFile = DefaultFile;
@@ -55,6 +57,14 @@ public partial class Mod
}
+ // A sub mod is a collection of
+ // - file replacements
+ // - file swaps
+ // - meta manipulations
+ // that can be used either as an option or as the default data for a mod.
+ // It can be loaded and reloaded from Json.
+ // Nothing is checked for existence or validity when loading.
+ // Objects are also not checked for uniqueness, the first appearance of a game path or meta path decides.
private sealed class SubMod : ISubMod
{
public string Name { get; set; } = "Default";
@@ -78,6 +88,7 @@ public partial class Mod
FileSwapData.Clear();
ManipulationData.Clear();
+ // Every option has a name, but priorities are only relevant for multi group options.
Name = json[ nameof( ISubMod.Name ) ]?.ToObject< string >() ?? string.Empty;
priority = json[ nameof( IModGroup.Priority ) ]?.ToObject< int >() ?? 0;
@@ -115,6 +126,8 @@ public partial class Mod
}
}
+ // If .meta or .rgsp files are encountered, parse them and incorporate their meta changes into the mod.
+ // If delete is true, the files are deleted afterwards.
public void IncorporateMetaChanges( DirectoryInfo basePath, bool delete )
{
foreach( var (key, file) in Files.ToList() )
diff --git a/Penumbra/Mods/Subclasses/ModSettings.cs b/Penumbra/Mods/Subclasses/ModSettings.cs
index 982776f8..3f6b7b53 100644
--- a/Penumbra/Mods/Subclasses/ModSettings.cs
+++ b/Penumbra/Mods/Subclasses/ModSettings.cs
@@ -14,6 +14,7 @@ public class ModSettings
public int Priority { get; set; }
public bool Enabled { get; set; }
+ // Create an independent copy of the current settings.
public ModSettings DeepCopy()
=> new()
{
@@ -22,6 +23,7 @@ public class ModSettings
Settings = Settings.ToList(),
};
+ // Create default settings for a given mod.
public static ModSettings DefaultSettings( Mod mod )
=> new()
{
@@ -30,24 +32,30 @@ public class ModSettings
Settings = Enumerable.Repeat( 0u, mod.Groups.Count ).ToList(),
};
+ // Automatically react to changes in a mods available options.
public bool HandleChanges( ModOptionChangeType type, Mod mod, int groupIdx, int optionIdx, int movedToIdx )
{
switch( type )
{
case ModOptionChangeType.GroupRenamed: return true;
case ModOptionChangeType.GroupAdded:
+ // Add new empty setting for new mod.
Settings.Insert( groupIdx, 0 );
return true;
case ModOptionChangeType.GroupDeleted:
+ // Remove setting for deleted mod.
Settings.RemoveAt( groupIdx );
return true;
case ModOptionChangeType.GroupTypeChanged:
{
+ // Fix settings for a changed group type.
+ // Single -> Multi: set single as enabled, rest as disabled
+ // Multi -> Single: set the first enabled option or 0.
var group = mod.Groups[ groupIdx ];
var config = Settings[ groupIdx ];
Settings[ groupIdx ] = group.Type switch
{
- SelectType.Single => ( uint )Math.Min( group.Count - 1, BitOperations.TrailingZeroCount( config ) ),
+ SelectType.Single => ( uint )Math.Max( Math.Min( group.Count - 1, BitOperations.TrailingZeroCount( config ) ), 0 ),
SelectType.Multi => 1u << ( int )config,
_ => config,
};
@@ -55,6 +63,8 @@ public class ModSettings
}
case ModOptionChangeType.OptionDeleted:
{
+ // Single -> select the previous option if any.
+ // Multi -> excise the corresponding bit.
var group = mod.Groups[ groupIdx ];
var config = Settings[ groupIdx ];
Settings[ groupIdx ] = group.Type switch
@@ -65,9 +75,13 @@ public class ModSettings
};
return config != Settings[ groupIdx ];
}
- case ModOptionChangeType.GroupMoved: return Settings.Move( groupIdx, movedToIdx );
+ case ModOptionChangeType.GroupMoved:
+ // Move the group the same way.
+ return Settings.Move( groupIdx, movedToIdx );
case ModOptionChangeType.OptionMoved:
{
+ // Single -> select the moved option if it was currently selected
+ // Multi -> move the corresponding bit
var group = mod.Groups[ groupIdx ];
var config = Settings[ groupIdx ];
Settings[ groupIdx ] = group.Type switch
@@ -82,6 +96,7 @@ public class ModSettings
}
}
+ // Ensure that a value is valid for a group.
private static uint FixSetting( IModGroup group, uint value )
=> group.Type switch
{
@@ -90,6 +105,7 @@ public class ModSettings
_ => value,
};
+ // Set a setting. Ensures that there are enough settings and fixes the setting beforehand.
public void SetValue( Mod mod, int groupIdx, uint newValue )
{
AddMissingSettings( groupIdx + 1 );
@@ -97,6 +113,7 @@ public class ModSettings
Settings[ groupIdx ] = FixSetting( group, newValue );
}
+ // Remove a single bit, moving all further bits one down.
private static uint RemoveBit( uint config, int bit )
{
var lowMask = ( 1u << bit ) - 1u;
@@ -106,6 +123,7 @@ public class ModSettings
return low | high;
}
+ // Move a bit in an uint from its position to another, shifting other bits accordingly.
private static uint MoveBit( uint config, int bit1, int bit2 )
{
var enabled = ( config & ( 1 << bit1 ) ) != 0 ? 1u << bit2 : 0u;
@@ -116,7 +134,8 @@ public class ModSettings
return low | enabled | high;
}
- internal bool AddMissingSettings( int totalCount )
+ // Add defaulted settings up to the required count.
+ private bool AddMissingSettings( int totalCount )
{
if( totalCount <= Settings.Count )
{
@@ -127,6 +146,7 @@ public class ModSettings
return true;
}
+ // A simple struct conversion to easily save settings by name instead of value.
public struct SavedSettings
{
public Dictionary< string, uint > Settings;
@@ -154,6 +174,7 @@ public class ModSettings
}
}
+ // Convert and fix.
public bool ToSettings( Mod mod, out ModSettings settings )
{
var list = new List< uint >( mod.Groups.Count );
diff --git a/Penumbra/Mods/Subclasses/SelectType.cs b/Penumbra/Mods/Subclasses/SelectType.cs
deleted file mode 100644
index 0843729c..00000000
--- a/Penumbra/Mods/Subclasses/SelectType.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace Penumbra.Mods;
-
-public enum SelectType
-{
- Single,
- Multi,
-}
\ No newline at end of file
diff --git a/Penumbra/Penumbra.cs b/Penumbra/Penumbra.cs
index 50ce0d07..8d11133d 100644
--- a/Penumbra/Penumbra.cs
+++ b/Penumbra/Penumbra.cs
@@ -30,9 +30,9 @@ public class Penumbra : IDalamudPlugin
private const string CommandName = "/penumbra";
- public static string Version = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? string.Empty;
+ public static readonly string Version = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? string.Empty;
- public static string CommitHash =
+ public static readonly string CommitHash =
Assembly.GetExecutingAssembly().GetCustomAttribute< AssemblyInformationalVersionAttribute >()?.InformationalVersion ?? "Unknown";
public static Configuration Config { get; private set; } = null!;
@@ -295,7 +295,7 @@ public class Penumbra : IDalamudPlugin
case "reload":
{
ModManager.DiscoverMods();
- Dalamud.Chat.Print( $"Reloaded Penumbra mods. You have {ModManager.Mods.Count} mods."
+ Dalamud.Chat.Print( $"Reloaded Penumbra mods. You have {ModManager.Count} mods."
);
break;
}
diff --git a/Penumbra/UI/Classes/ModFileSystemSelector.Filters.cs b/Penumbra/UI/Classes/ModFileSystemSelector.Filters.cs
index de9cf7b7..2b342208 100644
--- a/Penumbra/UI/Classes/ModFileSystemSelector.Filters.cs
+++ b/Penumbra/UI/Classes/ModFileSystemSelector.Filters.cs
@@ -21,11 +21,10 @@ public partial class ModFileSystemSelector
public uint Color;
}
- private const StringComparison IgnoreCase = StringComparison.InvariantCultureIgnoreCase;
- private readonly IReadOnlySet< Mod > _newMods = new HashSet< Mod >();
- private LowerString _modFilter = LowerString.Empty;
- private int _filterType = -1;
- private ModFilter _stateFilter = ModFilterExtensions.UnfilteredStateMods;
+ private const StringComparison IgnoreCase = StringComparison.InvariantCultureIgnoreCase;
+ private LowerString _modFilter = LowerString.Empty;
+ private int _filterType = -1;
+ private ModFilter _stateFilter = ModFilterExtensions.UnfilteredStateMods;
private void SetFilterTooltip()
{
@@ -105,7 +104,7 @@ public partial class ModFileSystemSelector
// Only get the text color for a mod if no filters are set.
private uint GetTextColor( Mod mod, ModSettings? settings, ModCollection collection )
{
- if( _newMods.Contains( mod ) )
+ if( Penumbra.ModManager.NewMods.Contains( mod ) )
{
return ColorId.NewMod.Value();
}
@@ -133,7 +132,7 @@ public partial class ModFileSystemSelector
private bool CheckStateFilters( Mod mod, ModSettings? settings, ModCollection collection, ref ModState state )
{
- var isNew = _newMods.Contains( mod );
+ var isNew = Penumbra.ModManager.NewMods.Contains( mod );
// Handle mod details.
if( CheckFlags( mod.TotalFileCount, ModFilter.HasNoFiles, ModFilter.HasFiles )
|| CheckFlags( mod.TotalSwapCount, ModFilter.HasNoFileSwaps, ModFilter.HasFileSwaps )
diff --git a/Penumbra/UI/Classes/ModFileSystemSelector.cs b/Penumbra/UI/Classes/ModFileSystemSelector.cs
index 4d7a236e..be36ab68 100644
--- a/Penumbra/UI/Classes/ModFileSystemSelector.cs
+++ b/Penumbra/UI/Classes/ModFileSystemSelector.cs
@@ -24,10 +24,9 @@ public sealed partial class ModFileSystemSelector : FileSystemSelector< Mod, Mod
public ModSettings SelectedSettings { get; private set; } = ModSettings.Empty;
public ModCollection SelectedSettingCollection { get; private set; } = ModCollection.Empty;
- public ModFileSystemSelector( ModFileSystem fileSystem, IReadOnlySet< Mod > newMods )
+ public ModFileSystemSelector( ModFileSystem fileSystem )
: base( fileSystem )
{
- _newMods = newMods;
SubscribeRightClickFolder( EnableDescendants, 10 );
SubscribeRightClickFolder( DisableDescendants, 10 );
SubscribeRightClickFolder( InheritDescendants, 15 );
@@ -122,7 +121,8 @@ public sealed partial class ModFileSystemSelector : FileSystemSelector< Mod, Mod
private void AddNewModButton( Vector2 size )
{
- if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Plus.ToIconString(), size, "Create a new, empty mod of a given name.", !Penumbra.ModManager.Valid, true ) )
+ if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Plus.ToIconString(), size, "Create a new, empty mod of a given name.",
+ !Penumbra.ModManager.Valid, true ) )
{
ImGui.OpenPopup( "Create New Mod" );
}
@@ -167,17 +167,18 @@ public sealed partial class ModFileSystemSelector : FileSystemSelector< Mod, Mod
private void DrawInfoPopup()
{
var display = ImGui.GetIO().DisplaySize;
- ImGui.SetNextWindowSize( display / 4 );
+ ImGui.SetNextWindowSize( display / 4 );
ImGui.SetNextWindowPos( 3 * display / 8 );
using var popup = ImRaii.Popup( "Import Status", ImGuiWindowFlags.Modal );
if( _import != null && popup.Success )
{
- _import.DrawProgressInfo( ImGuiHelpers.ScaledVector2( -1, ImGui.GetFrameHeight() ) );
+ _import.DrawProgressInfo( new Vector2( -1, ImGui.GetFrameHeight() ) );
if( _import.State == ImporterState.Done )
{
ImGui.SetCursorPosY( ImGui.GetWindowHeight() - ImGui.GetFrameHeight() * 2 );
if( ImGui.Button( "Close", -Vector2.UnitX ) )
{
+ AddNewMods( _import.ExtractedMods );
_import = null;
ImGui.CloseCurrentPopup();
}
@@ -185,6 +186,37 @@ public sealed partial class ModFileSystemSelector : FileSystemSelector< Mod, Mod
}
}
+ // Clean up invalid directories if necessary.
+ // Add all successfully extracted mods.
+ private static void AddNewMods( IEnumerable< (FileInfo File, DirectoryInfo? Mod, Exception? Error) > list )
+ {
+ foreach( var (file, dir, error) in list )
+ {
+ if( error != null )
+ {
+ if( dir != null && Directory.Exists( dir.FullName ) )
+ {
+ try
+ {
+ Directory.Delete( dir.FullName );
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error($"Error cleaning up failed mod extraction of {file.FullName} to {dir.FullName}:\n{e}" );
+ }
+ }
+
+ PluginLog.Error( $"Error extracting {file.FullName}, mod skipped:\n{error}" );
+ continue;
+ }
+
+ if( dir != null )
+ {
+ Penumbra.ModManager.AddMod( dir );
+ }
+ }
+ }
+
private void DeleteModButton( Vector2 size )
{
var keys = ImGui.GetIO().KeyCtrl && ImGui.GetIO().KeyShift;
diff --git a/Penumbra/UI/ConfigWindow.ChangedItemsTab.cs b/Penumbra/UI/ConfigWindow.ChangedItemsTab.cs
index c99cb3d4..aa7b6c1e 100644
--- a/Penumbra/UI/ConfigWindow.ChangedItemsTab.cs
+++ b/Penumbra/UI/ConfigWindow.ChangedItemsTab.cs
@@ -31,6 +31,7 @@ public partial class ConfigWindow
return;
}
+ // Draw filters.
ImGui.SetNextItemWidth( -1 );
LowerString.InputWithHint( "##changedItemsFilter", "Filter...", ref _changedItemFilter, 64 );
@@ -40,6 +41,7 @@ public partial class ConfigWindow
return;
}
+ // Draw table of changed items.
var height = ImGui.GetTextLineHeightWithSpacing() + 2 * ImGui.GetStyle().CellPadding.Y;
var skips = ImGuiClip.GetNecessarySkips( height );
using var list = ImRaii.Table( "##changedItems", 1, ImGuiTableFlags.RowBg, -Vector2.One );
diff --git a/Penumbra/UI/ConfigWindow.CollectionsTab.Inheritance.cs b/Penumbra/UI/ConfigWindow.CollectionsTab.Inheritance.cs
index ac803463..6d4ed0ec 100644
--- a/Penumbra/UI/ConfigWindow.CollectionsTab.Inheritance.cs
+++ b/Penumbra/UI/ConfigWindow.CollectionsTab.Inheritance.cs
@@ -112,7 +112,7 @@ public partial class ConfigWindow
private void DrawCurrentCollectionInheritance()
{
using var list = ImRaii.ListBox( "##inheritanceList",
- new Vector2( _window._inputTextWidth.X - ImGui.GetFrameHeight() - ImGui.GetStyle().ItemSpacing.X,
+ new Vector2( _window._inputTextWidth.X - _window._iconButtonSize.X - ImGui.GetStyle().ItemSpacing.X,
ImGui.GetTextLineHeightWithSpacing() * InheritedCollectionHeight ) );
if( !list )
{
@@ -131,7 +131,7 @@ public partial class ConfigWindow
private void DrawInheritanceTrashButton()
{
ImGui.SameLine();
- var size = new Vector2( ImGui.GetFrameHeight(), ImGui.GetTextLineHeightWithSpacing() * InheritedCollectionHeight );
+ var size = new Vector2( _window._iconButtonSize.X, ImGui.GetTextLineHeightWithSpacing() * InheritedCollectionHeight );
var buttonColor = ImGui.GetColorU32( ImGuiCol.Button );
// Prevent hovering from highlighting the button.
using var color = ImRaii.PushColor( ImGuiCol.ButtonActive, buttonColor )
@@ -142,7 +142,7 @@ public partial class ConfigWindow
using var target = ImRaii.DragDropTarget();
if( target.Success && ImGuiUtil.IsDropping( InheritanceDragDropLabel ) )
{
- _inheritanceAction = ( Penumbra.CollectionManager.Current.Inheritance.IndexOf( _movedInheritance ), -1 );
+ _inheritanceAction = ( Penumbra.CollectionManager.Current.Inheritance.IndexOf( _movedInheritance! ), -1 );
}
}
@@ -192,7 +192,7 @@ public partial class ConfigWindow
ModCollection.ValidInheritance.Circle => "Inheriting from selected collection would lead to cyclic inheritance.",
_ => string.Empty,
};
- if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Plus.ToIconString(), ImGui.GetFrameHeight() * Vector2.One, tt,
+ if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Plus.ToIconString(), _window._iconButtonSize, tt,
inheritance != ModCollection.ValidInheritance.Valid, true )
&& Penumbra.CollectionManager.Current.AddInheritance( _newInheritance! ) )
{
@@ -211,7 +211,7 @@ public partial class ConfigWindow
// Only valid inheritances are drawn in the preview, or nothing if no inheritance is available.
private void DrawNewInheritanceCombo()
{
- ImGui.SetNextItemWidth( _window._inputTextWidth.X - ImGui.GetFrameHeight() - ImGui.GetStyle().ItemSpacing.X );
+ ImGui.SetNextItemWidth( _window._inputTextWidth.X - _window._iconButtonSize.X - ImGui.GetStyle().ItemSpacing.X );
_newInheritance ??= Penumbra.CollectionManager.FirstOrDefault( c
=> c != Penumbra.CollectionManager.Current && !Penumbra.CollectionManager.Current.Inheritance.Contains( c ) )
?? ModCollection.Empty;
diff --git a/Penumbra/UI/ConfigWindow.CollectionsTab.cs b/Penumbra/UI/ConfigWindow.CollectionsTab.cs
index 6d38cb69..76024c0e 100644
--- a/Penumbra/UI/ConfigWindow.CollectionsTab.cs
+++ b/Penumbra/UI/ConfigWindow.CollectionsTab.cs
@@ -47,14 +47,19 @@ public partial class ConfigWindow
}
}
+ // Only gets drawn when actually relevant.
private static void DrawCleanCollectionButton()
{
- if( ImGui.Button( "Clean Settings" ) )
+ if( Penumbra.Config.ShowAdvanced && Penumbra.CollectionManager.Current.HasUnusedSettings )
{
- Penumbra.CollectionManager.Current.CleanUnavailableSettings();
+ ImGui.SameLine();
+ if( ImGuiUtil.DrawDisabledButton( "Clean Settings", Vector2.Zero
+ , "Remove all stored settings for mods not currently available and fix invalid settings.\nUse at own risk."
+ , false ) )
+ {
+ Penumbra.CollectionManager.Current.CleanUnavailableSettings();
+ }
}
-
- ImGuiUtil.HoverTooltip( "Remove all stored settings for mods not currently available and fix invalid settings.\nUse at own risk." );
}
// Draw the new collection input as well as its buttons.
@@ -94,11 +99,7 @@ public partial class ConfigWindow
Penumbra.CollectionManager.RemoveCollection( Penumbra.CollectionManager.Current );
}
- if( Penumbra.Config.ShowAdvanced )
- {
- ImGui.SameLine();
- DrawCleanCollectionButton();
- }
+ DrawCleanCollectionButton();
}
private void DrawCurrentCollectionSelector()
@@ -152,7 +153,7 @@ public partial class ConfigWindow
using var id = ImRaii.PushId( name );
DrawCollectionSelector( string.Empty, _window._inputTextWidth.X, ModCollection.Type.Character, true, name );
ImGui.SameLine();
- if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Trash.ToIconString(), Vector2.One * ImGui.GetFrameHeight(), string.Empty,
+ if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Trash.ToIconString(), _window._iconButtonSize, string.Empty,
false,
true ) )
{
diff --git a/Penumbra/UI/ConfigWindow.EffectiveTab.cs b/Penumbra/UI/ConfigWindow.EffectiveTab.cs
index 3e843231..241a22bb 100644
--- a/Penumbra/UI/ConfigWindow.EffectiveTab.cs
+++ b/Penumbra/UI/ConfigWindow.EffectiveTab.cs
@@ -124,7 +124,7 @@ public partial class ConfigWindow
// Filters mean we can not use the known counts.
if( hasFilters )
{
- var it2 = it.Select( p => ( p.Item1.ToString() ?? string.Empty, Penumbra.ModManager.Mods[ p.Item2 ].Name ) );
+ var it2 = it.Select( p => ( p.Item1.ToString() ?? string.Empty, Penumbra.ModManager[ p.Item2 ].Name ) );
if( stop >= 0 )
{
ImGuiClip.DrawEndDummy( stop + it2.Count( CheckFilters ), height );
@@ -190,7 +190,7 @@ public partial class ConfigWindow
ImGui.TableNextColumn();
ImGuiUtil.PrintIcon( FontAwesomeIcon.LongArrowAltLeft );
ImGui.TableNextColumn();
- ImGuiUtil.CopyOnClickSelectable( Penumbra.ModManager.Mods[ modIdx ].Name );
+ ImGuiUtil.CopyOnClickSelectable( Penumbra.ModManager[ modIdx ].Name );
}
// Check filters for file replacements.
diff --git a/Penumbra/UI/ConfigWindow.Misc.cs b/Penumbra/UI/ConfigWindow.Misc.cs
index b4cf7835..850d4e85 100644
--- a/Penumbra/UI/ConfigWindow.Misc.cs
+++ b/Penumbra/UI/ConfigWindow.Misc.cs
@@ -21,16 +21,16 @@ public partial class ConfigWindow
=> ImGuiNative.igTextUnformatted( s.Path, s.Path + s.Length );
// Draw text given by a byte pointer.
- internal static unsafe void Text( byte* s, int length )
+ private static unsafe void Text( byte* s, int length )
=> ImGuiNative.igTextUnformatted( s, s + length );
// Draw the name of a resource file.
- internal static unsafe void Text( ResourceHandle* resource )
+ private static unsafe void Text( ResourceHandle* resource )
=> Text( resource->FileName(), resource->FileNameLength );
// Draw a changed item, invoking the Api-Events for clicks and tooltips.
// Also draw the item Id in grey
- internal void DrawChangedItem( string name, object? data, float itemIdOffset = 0 )
+ private void DrawChangedItem( string name, object? data, float itemIdOffset = 0 )
{
var ret = ImGui.Selectable( name ) ? MouseButton.Left : MouseButton.None;
ret = ImGui.IsItemClicked( ImGuiMouseButton.Right ) ? MouseButton.Right : ret;
@@ -64,7 +64,7 @@ public partial class ConfigWindow
// A selectable that copies its text to clipboard on selection and provides a on-hover tooltip about that,
// using an Utf8String.
- internal static unsafe void CopyOnClickSelectable( Utf8String text )
+ private static unsafe void CopyOnClickSelectable( Utf8String text )
{
if( ImGuiNative.igSelectable_Bool( text.Path, 0, ImGuiSelectableFlags.None, Vector2.Zero ) != 0 )
{
diff --git a/Penumbra/UI/ConfigWindow.ModPanel.Edit.cs b/Penumbra/UI/ConfigWindow.ModPanel.Edit.cs
index 0ca5dcd4..560dae22 100644
--- a/Penumbra/UI/ConfigWindow.ModPanel.Edit.cs
+++ b/Penumbra/UI/ConfigWindow.ModPanel.Edit.cs
@@ -1,6 +1,7 @@
using System;
-using System.Collections;
using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
using System.Numerics;
using Dalamud.Interface;
using ImGuiNET;
@@ -14,7 +15,7 @@ public partial class ConfigWindow
{
private partial class ModPanel
{
- public readonly Queue< Action > _delayedActions = new();
+ private readonly Queue< Action > _delayedActions = new();
private void DrawAddOptionGroupInput()
{
@@ -24,7 +25,7 @@ public partial class ConfigWindow
var nameValid = Mod.Manager.VerifyFileName( _mod, null, _newGroupName, false );
var tt = nameValid ? "Add new option group to the mod." : "Can not add a group of this name.";
- if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Plus.ToIconString(), ImGui.GetFrameHeight() * Vector2.One,
+ if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Plus.ToIconString(), _window._iconButtonSize,
tt, !nameValid, true ) )
{
Penumbra.ModManager.AddModGroup( _mod, SelectType.Single, _newGroupName );
@@ -73,6 +74,33 @@ public partial class ConfigWindow
EditDescriptionPopup();
}
+ private void EditButtons()
+ {
+ var folderExists = Directory.Exists( _mod.BasePath.FullName );
+ var tt = folderExists
+ ? $"Open {_mod.BasePath.FullName} in the file explorer of your choice."
+ : $"Mod directory {_mod.BasePath.FullName} does not exist.";
+ if( ImGuiUtil.DrawDisabledButton( "Open Mod Directory", Vector2.Zero, tt, !folderExists ) )
+ {
+ Process.Start( new ProcessStartInfo( _mod.BasePath.FullName ) { UseShellExecute = true } );
+ }
+
+ ImGui.SameLine();
+ ImGuiUtil.DrawDisabledButton( "Rename Mod Directory", Vector2.Zero, "Not implemented yet", true );
+ ImGui.SameLine();
+ ImGuiUtil.DrawDisabledButton( "Reload Mod", Vector2.Zero, "Not implemented yet", true );
+
+ ImGuiUtil.DrawDisabledButton( "Deduplicate", Vector2.Zero, "Not implemented yet", true );
+ ImGui.SameLine();
+ ImGuiUtil.DrawDisabledButton( "Normalize", Vector2.Zero, "Not implemented yet", true );
+ ImGui.SameLine();
+ ImGuiUtil.DrawDisabledButton( "Auto-Create Groups", Vector2.Zero, "Not implemented yet", true );
+
+ ImGuiUtil.DrawDisabledButton( "Change Material Suffix", Vector2.Zero, "Not implemented yet", true );
+
+ ImGui.Dummy( _window._defaultSpace );
+ }
+
// Special field indices to reuse the same string buffer.
private const int NoFieldIdx = -1;
@@ -105,15 +133,37 @@ public partial class ConfigWindow
Penumbra.ModManager.ChangeModWebsite( _mod.Index, newWebsite );
}
- if( ImGui.Button( "Edit Description", _window._inputTextWidth ) )
+ var reducedSize = new Vector2( _window._inputTextWidth.X - _window._iconButtonSize.X - ImGui.GetStyle().ItemSpacing.X, 0 );
+
+ if( ImGui.Button( "Edit Description", reducedSize ) )
{
_delayedActions.Enqueue( () => OpenEditDescriptionPopup( DescriptionFieldIdx ) );
}
- if( ImGui.Button( "Edit Default Mod", _window._inputTextWidth ) )
+ ImGui.SameLine();
+ var fileExists = File.Exists( _mod.MetaFile.FullName );
+ var tt = fileExists
+ ? "Open the metadata json file in the text editor of your choice."
+ : "The metadata json file does not exist.";
+ if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.FileExport.ToIconString(), _window._iconButtonSize, tt, !fileExists, true ) )
+ {
+ Process.Start( new ProcessStartInfo( _mod.MetaFile.FullName ) { UseShellExecute = true } );
+ }
+
+ if( ImGui.Button( "Edit Default Mod", reducedSize ) )
{
_window.SubModPopup.Activate( _mod, -1, 0 );
}
+
+ ImGui.SameLine();
+ fileExists = File.Exists( _mod.DefaultFile );
+ tt = fileExists
+ ? "Open the default option json file in the text editor of your choice."
+ : "The default option json file does not exist.";
+ if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.FileExport.ToIconString(), _window._iconButtonSize, tt, !fileExists, true ) )
+ {
+ Process.Start( new ProcessStartInfo( _mod.DefaultFile ) { UseShellExecute = true } );
+ }
}
@@ -144,7 +194,7 @@ public partial class ConfigWindow
ImGuiUtil.HoverTooltip( "Group Name" );
ImGui.SameLine();
- if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Trash.ToIconString(), ImGui.GetFrameHeight() * Vector2.One,
+ if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Trash.ToIconString(), _window._iconButtonSize,
"Delete this option group.\nHold Control while clicking to delete.", !ImGui.GetIO().KeyCtrl, true ) )
{
_delayedActions.Enqueue( () => Penumbra.ModManager.DeleteModGroup( _mod, groupIdx ) );
@@ -152,7 +202,7 @@ public partial class ConfigWindow
ImGui.SameLine();
- if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Edit.ToIconString(), ImGui.GetFrameHeight() * Vector2.One,
+ if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Edit.ToIconString(), _window._iconButtonSize,
"Edit group description.", false, true ) )
{
_delayedActions.Enqueue( () => OpenEditDescriptionPopup( groupIdx ) );
@@ -167,7 +217,7 @@ public partial class ConfigWindow
ImGuiUtil.HoverTooltip( "Group Priority" );
- ImGui.SetNextItemWidth( _window._inputTextWidth.X - 2 * ImGui.GetFrameHeight() - 8 * ImGuiHelpers.GlobalScale );
+ ImGui.SetNextItemWidth( _window._inputTextWidth.X - 3 * _window._iconButtonSize.X - 12 * ImGuiHelpers.GlobalScale );
using( var combo = ImRaii.Combo( "##GroupType", GroupTypeName( group.Type ) ) )
{
if( combo )
@@ -185,7 +235,7 @@ public partial class ConfigWindow
ImGui.SameLine();
var tt = groupIdx == 0 ? "Can not move this group further upwards." : $"Move this group up to group {groupIdx}.";
- if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.ArrowUp.ToIconString(), ImGui.GetFrameHeight() * Vector2.One,
+ if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.ArrowUp.ToIconString(), _window._iconButtonSize,
tt, groupIdx == 0, true ) )
{
_delayedActions.Enqueue( () => Penumbra.ModManager.MoveModGroup( _mod, groupIdx, groupIdx - 1 ) );
@@ -195,19 +245,30 @@ public partial class ConfigWindow
tt = groupIdx == _mod.Groups.Count - 1
? "Can not move this group further downwards."
: $"Move this group down to group {groupIdx + 2}.";
- if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.ArrowDown.ToIconString(), ImGui.GetFrameHeight() * Vector2.One,
+ if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.ArrowDown.ToIconString(), _window._iconButtonSize,
tt, groupIdx == _mod.Groups.Count - 1, true ) )
{
_delayedActions.Enqueue( () => Penumbra.ModManager.MoveModGroup( _mod, groupIdx, groupIdx + 1 ) );
}
+ ImGui.SameLine();
+ var fileName = group.FileName( _mod.BasePath );
+ var fileExists = File.Exists( fileName );
+ tt = fileExists
+ ? $"Open the {group.Name} json file in the text editor of your choice."
+ : $"The {group.Name} json file does not exist.";
+ if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.FileExport.ToIconString(), _window._iconButtonSize, tt, !fileExists, true ) )
+ {
+ Process.Start( new ProcessStartInfo( fileName ) { UseShellExecute = true } );
+ }
+
ImGui.Dummy( _window._defaultSpace );
using var table = ImRaii.Table( string.Empty, 5, ImGuiTableFlags.SizingFixedFit );
ImGui.TableSetupColumn( "idx", ImGuiTableColumnFlags.WidthFixed, 60 * ImGuiHelpers.GlobalScale );
ImGui.TableSetupColumn( "name", ImGuiTableColumnFlags.WidthFixed, _window._inputTextWidth.X - 62 * ImGuiHelpers.GlobalScale );
- ImGui.TableSetupColumn( "delete", ImGuiTableColumnFlags.WidthFixed, ImGui.GetFrameHeight() );
- ImGui.TableSetupColumn( "edit", ImGuiTableColumnFlags.WidthFixed, ImGui.GetFrameHeight() );
+ ImGui.TableSetupColumn( "delete", ImGuiTableColumnFlags.WidthFixed, _window._iconButtonSize.X );
+ ImGui.TableSetupColumn( "edit", ImGuiTableColumnFlags.WidthFixed, _window._iconButtonSize.X );
ImGui.TableSetupColumn( "priority", ImGuiTableColumnFlags.WidthFixed, 50 * ImGuiHelpers.GlobalScale );
if( table )
{
@@ -221,7 +282,7 @@ public partial class ConfigWindow
ImGui.SetNextItemWidth( -1 );
ImGui.InputTextWithHint( "##newOption", "Add new option...", ref _newOptionName, 256 );
ImGui.TableNextColumn();
- if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Plus.ToIconString(), ImGui.GetFrameHeight() * Vector2.One,
+ if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Plus.ToIconString(), _window._iconButtonSize,
"Add a new option to this group.", _newOptionName.Length == 0, true ) )
{
Penumbra.ModManager.AddOption( _mod, groupIdx, _newOptionName );
@@ -258,6 +319,7 @@ public partial class ConfigWindow
}
}
+ // TODO drag options to other groups without options.
using( var target = ImRaii.DragDropTarget() )
{
if( target.Success && ImGuiUtil.IsDropping( label ) )
@@ -266,14 +328,21 @@ public partial class ConfigWindow
{
if( _dragDropGroupIdx == groupIdx )
{
- // TODO
- Dalamud.Chat.Print(
- $"Dropped {_mod.Groups[ _dragDropGroupIdx ][ _dragDropOptionIdx ].Name} onto {_mod.Groups[ groupIdx ][ optionIdx ].Name}" );
+ var sourceOption = _dragDropOptionIdx;
+ _delayedActions.Enqueue( () => Penumbra.ModManager.MoveOption( _mod, groupIdx, sourceOption, optionIdx ) );
}
else
{
- Dalamud.Chat.Print(
- $"Dropped {_mod.Groups[ _dragDropGroupIdx ][ _dragDropOptionIdx ].Name} onto {_mod.Groups[ groupIdx ][ optionIdx ].Name}" );
+ // Move from one group to another by deleting, then adding the option.
+ var sourceGroup = _dragDropGroupIdx;
+ var sourceOption = _dragDropOptionIdx;
+ var option = group[ _dragDropOptionIdx ];
+ var priority = group.OptionPriority( _dragDropGroupIdx );
+ _delayedActions.Enqueue( () =>
+ {
+ Penumbra.ModManager.DeleteOption( _mod, sourceGroup, sourceOption );
+ Penumbra.ModManager.AddOption( _mod, groupIdx, option, priority );
+ } );
}
}
@@ -299,14 +368,14 @@ public partial class ConfigWindow
}
ImGui.TableNextColumn();
- if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Trash.ToIconString(), ImGui.GetFrameHeight() * Vector2.One,
+ if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Trash.ToIconString(), _window._iconButtonSize,
"Delete this option.\nHold Control while clicking to delete.", !ImGui.GetIO().KeyCtrl, true ) )
{
_delayedActions.Enqueue( () => Penumbra.ModManager.DeleteOption( _mod, groupIdx, optionIdx ) );
}
ImGui.TableNextColumn();
- if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Edit.ToIconString(), ImGui.GetFrameHeight() * Vector2.One,
+ if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Edit.ToIconString(), _window._iconButtonSize,
"Edit this option.", false, true ) )
{
_window.SubModPopup.Activate( _mod, groupIdx, optionIdx );
diff --git a/Penumbra/UI/ConfigWindow.ModPanel.Settings.cs b/Penumbra/UI/ConfigWindow.ModPanel.Settings.cs
index 7ab3b496..f4168fb3 100644
--- a/Penumbra/UI/ConfigWindow.ModPanel.Settings.cs
+++ b/Penumbra/UI/ConfigWindow.ModPanel.Settings.cs
@@ -1,4 +1,3 @@
-using System.Linq;
using System.Numerics;
using Dalamud.Interface;
using ImGuiNET;
@@ -16,7 +15,7 @@ public partial class ConfigWindow
{
private partial class ModPanel
{
- private ModSettings _settings = null!;
+ private ModSettings _settings = null!;
private ModCollection _collection = null!;
private bool _emptySetting;
private bool _inherited;
@@ -92,6 +91,7 @@ public partial class ConfigWindow
var enabled = _settings.Enabled;
if( ImGui.Checkbox( "Enabled", ref enabled ) )
{
+ Penumbra.ModManager.NewMods.Remove( _mod );
Penumbra.CollectionManager.Current.SetModState( _mod.Index, enabled );
}
}
@@ -132,7 +132,7 @@ public partial class ConfigWindow
}
var scroll = ImGui.GetScrollMaxY() > 0 ? ImGui.GetStyle().ScrollbarSize : 0;
- ImGui.SameLine( ImGui.GetWindowWidth() - ImGui.CalcTextSize( text ).X - ImGui.GetStyle().FramePadding.X * 2 - scroll);
+ ImGui.SameLine( ImGui.GetWindowWidth() - ImGui.CalcTextSize( text ).X - ImGui.GetStyle().FramePadding.X * 2 - scroll );
if( ImGui.Button( text ) )
{
Penumbra.CollectionManager.Current.SetModInheritance( _mod.Index, true );
diff --git a/Penumbra/UI/ConfigWindow.ModPanel.Tabs.cs b/Penumbra/UI/ConfigWindow.ModPanel.Tabs.cs
index 556be8dc..f8982852 100644
--- a/Penumbra/UI/ConfigWindow.ModPanel.Tabs.cs
+++ b/Penumbra/UI/ConfigWindow.ModPanel.Tabs.cs
@@ -1,6 +1,4 @@
using System;
-using System.ComponentModel.Design;
-using System.Linq;
using System.Numerics;
using ImGuiNET;
using OtterGui;
@@ -112,6 +110,7 @@ public partial class ConfigWindow
{
return;
}
+
var conflicts = Penumbra.CollectionManager.Current.ModConflicts( _mod.Index );
Mod? oldBadMod = null;
using var indent = ImRaii.PushIndent( 0f );
@@ -124,19 +123,20 @@ public partial class ConfigWindow
{
indent.Pop( 30f );
}
-
+
if( ImGui.Selectable( badMod.Name ) )
{
_window._selector.SelectByValue( badMod );
}
-
+
ImGui.SameLine();
- using var color = ImRaii.PushColor( ImGuiCol.Text, conflict.Mod1Priority ? ColorId.HandledConflictMod.Value() : ColorId.ConflictingMod.Value() );
+ using var color = ImRaii.PushColor( ImGuiCol.Text,
+ conflict.Mod1Priority ? ColorId.HandledConflictMod.Value() : ColorId.ConflictingMod.Value() );
ImGui.Text( $"(Priority {Penumbra.CollectionManager.Current[ conflict.Mod2 ].Settings!.Priority})" );
-
+
indent.Push( 30f );
}
-
+
if( conflict.Data is Utf8GamePath p )
{
unsafe
@@ -148,7 +148,7 @@ public partial class ConfigWindow
{
ImGui.Selectable( m.Manipulation?.ToString() ?? string.Empty );
}
-
+
oldBadMod = badMod;
}
}
diff --git a/Penumbra/UI/ConfigWindow.ModsTab.Details.cs b/Penumbra/UI/ConfigWindow.ModsTab.Details.cs
deleted file mode 100644
index 6dfb603f..00000000
--- a/Penumbra/UI/ConfigWindow.ModsTab.Details.cs
+++ /dev/null
@@ -1,714 +0,0 @@
-//using System.IO;
-//using System.Linq;
-//using System.Numerics;
-//using Dalamud.Interface;
-//using FFXIVClientStructs.FFXIV.Client.UI.Misc;
-//using ImGuiNET;
-//using Lumina.Data.Parsing;
-//using Lumina.Excel.GeneratedSheets;
-//using Penumbra.GameData.ByteString;
-//using Penumbra.GameData.Enums;
-//using Penumbra.GameData.Util;
-//using Penumbra.Meta;
-//using Penumbra.Meta.Manipulations;
-//using Penumbra.Mods;
-//using Penumbra.UI.Custom;
-//using Penumbra.Util;
-//using ImGui = ImGuiNET.ImGui;
-//
-//namespace Penumbra.UI;
-//
-//public partial class SettingsInterface
-//{
-// private partial class PluginDetails
-// {
-// private const string LabelPluginDetails = "PenumbraPluginDetails";
-// private const string LabelAboutTab = "About";
-// private const string LabelChangedItemsTab = "Changed Items";
-// private const string LabelChangedItemsHeader = "##changedItems";
-// private const string LabelConflictsTab = "Mod Conflicts";
-// private const string LabelConflictsHeader = "##conflicts";
-// private const string LabelFileSwapTab = "File Swaps";
-// private const string LabelFileSwapHeader = "##fileSwaps";
-// private const string LabelFileListTab = "Files";
-// private const string LabelFileListHeader = "##fileList";
-// private const string LabelGroupSelect = "##groupSelect";
-// private const string LabelOptionSelect = "##optionSelect";
-// private const string LabelConfigurationTab = "Configuration";
-//
-// private const string TooltipFilesTab =
-// "Green files replace their standard game path counterpart (not in any option) or are in all options of a Single-Select option.\n"
-// + "Yellow files are restricted to some options.";
-//
-// private const float OptionSelectionWidth = 140f;
-// private const float CheckMarkSize = 50f;
-// private const uint ColorDarkGreen = 0xFF00A000;
-// private const uint ColorGreen = 0xFF00C800;
-// private const uint ColorYellow = 0xFF00C8C8;
-// private const uint ColorDarkRed = 0xFF0000A0;
-// private const uint ColorRed = 0xFF0000C8;
-//
-//
-// private bool _editMode;
-// private int _selectedGroupIndex;
-// private OptionGroup? _selectedGroup;
-// private int _selectedOptionIndex;
-// private ConfigModule.Option? _selectedOption;
-// private string _currentGamePaths = "";
-//
-// private (FullPath name, bool selected, uint color, Utf8RelPath relName)[]? _fullFilenameList;
-//
-// private readonly Selector _selector;
-// private readonly SettingsInterface _base;
-//
-// 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?.Data.Meta.Groups.Count ?? 0;
-// _selectedGroupIndex = idx;
-// if( _selectedGroupIndex >= numGroups )
-// {
-// _selectedGroupIndex = 0;
-// }
-//
-// if( numGroups > 0 )
-// {
-// _selectedGroup = Meta.Groups.ElementAt( _selectedGroupIndex ).Value;
-// }
-// else
-// {
-// _selectedGroup = null;
-// }
-// }
-//
-// private void SelectGroup()
-// => SelectGroup( _selectedGroupIndex );
-//
-// private void SelectOption( int idx )
-// {
-// _selectedOptionIndex = idx;
-// if( _selectedOptionIndex >= _selectedGroup?.Options.Count )
-// {
-// _selectedOptionIndex = 0;
-// }
-//
-// if( _selectedGroup?.Options.Count > 0 )
-// {
-// _selectedOption = ( ( OptionGroup )_selectedGroup ).Options[ _selectedOptionIndex ];
-// }
-// else
-// {
-// _selectedOption = null;
-// }
-// }
-//
-// private void SelectOption()
-// => SelectOption( _selectedOptionIndex );
-//
-// public void ResetState()
-// {
-// _fullFilenameList = null;
-// SelectGroup();
-// SelectOption();
-// }
-//
-// public PluginDetails( SettingsInterface ui, Selector s )
-// {
-// _base = ui;
-// _selector = s;
-// ResetState();
-// }
-//
-// // This is only drawn when we have a mod selected, so we can forgive nulls.
-// private FullMod Mod
-// => _selector.Mod!;
-//
-// private ModMeta Meta
-// => Mod.Data.Meta;
-//
-// private void DrawAboutTab()
-// {
-// if( !_editMode && Meta.Description.Length == 0 )
-// {
-// return;
-// }
-//
-// if( !ImGui.BeginTabItem( LabelAboutTab ) )
-// {
-// return;
-// }
-//
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
-//
-// var desc = Meta.Description;
-// var flags = _editMode
-// ? ImGuiInputTextFlags.EnterReturnsTrue | ImGuiInputTextFlags.CtrlEnterForNewLine
-// : ImGuiInputTextFlags.ReadOnly;
-//
-// if( _editMode )
-// {
-// if( ImGui.InputTextMultiline( LabelDescEdit, ref desc, 1 << 16,
-// AutoFillSize, flags ) )
-// {
-// Meta.Description = desc;
-// _selector.SaveCurrentMod();
-// }
-//
-// ImGuiCustom.HoverTooltip( TooltipAboutEdit );
-// }
-// else
-// {
-// ImGui.TextWrapped( desc );
-// }
-// }
-//
-// private void DrawChangedItemsTab()
-// {
-// if( Mod.Data.ChangedItems.Count == 0 || !ImGui.BeginTabItem( LabelChangedItemsTab ) )
-// {
-// return;
-// }
-//
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
-//
-// if( !ImGui.BeginListBox( LabelChangedItemsHeader, AutoFillSize ) )
-// {
-// return;
-// }
-//
-// raii.Push( ImGui.EndListBox );
-// foreach( var (name, data) in Mod.Data.ChangedItems )
-// {
-// _base.DrawChangedItem( name, data );
-// }
-// }
-//
-// private void DrawConflictTab()
-// {
-// var conflicts = Penumbra.CollectionManager.Current.ModConflicts( Mod.Data.Index ).ToList();
-// if( conflicts.Count == 0 || !ImGui.BeginTabItem( LabelConflictsTab ) )
-// {
-// return;
-// }
-//
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
-//
-// ImGui.SetNextItemWidth( -1 );
-// if( !ImGui.BeginListBox( LabelConflictsHeader, AutoFillSize ) )
-// {
-// return;
-// }
-//
-// raii.Push( ImGui.EndListBox );
-// using var indent = ImGuiRaii.PushIndent( 0 );
-// Mods.Mod? oldBadMod = null;
-// foreach( var conflict in conflicts )
-// {
-// var badMod = Penumbra.ModManager[ conflict.Mod2 ];
-// if( badMod != oldBadMod )
-// {
-// if( oldBadMod != null )
-// {
-// indent.Pop( 30f );
-// }
-//
-// if( ImGui.Selectable( badMod.Meta.Name ) )
-// {
-// _selector.SelectModByDir( badMod.BasePath.Name );
-// }
-//
-// ImGui.SameLine();
-// using var color = ImGuiRaii.PushColor( ImGuiCol.Text, conflict.Mod1Priority ? ColorGreen : ColorRed );
-// ImGui.Text( $"(Priority {Penumbra.CollectionManager.Current[ conflict.Mod2 ].Settings!.Priority})" );
-//
-// indent.Push( 30f );
-// }
-//
-// if( conflict.Data is Utf8GamePath p )
-// {
-// unsafe
-// {
-// ImGuiNative.igSelectable_Bool( p.Path.Path, 0, ImGuiSelectableFlags.None, Vector2.Zero );
-// }
-// }
-// else if( conflict.Data is MetaManipulation m )
-// {
-// ImGui.Selectable( m.Manipulation?.ToString() ?? string.Empty );
-// }
-//
-// oldBadMod = badMod;
-// }
-// }
-//
-// private void DrawFileSwapTab()
-// {
-// if( _editMode )
-// {
-// DrawFileSwapTabEdit();
-// return;
-// }
-//
-// if( !Meta.FileSwaps.Any() || !ImGui.BeginTabItem( LabelFileSwapTab ) )
-// {
-// return;
-// }
-//
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
-//
-// const ImGuiTableFlags flags = ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollX;
-//
-// ImGui.SetNextItemWidth( -1 );
-// if( !ImGui.BeginTable( LabelFileSwapHeader, 3, flags, AutoFillSize ) )
-// {
-// return;
-// }
-//
-// raii.Push( ImGui.EndTable );
-//
-// foreach( var (source, target) in Meta.FileSwaps )
-// {
-// ImGui.TableNextColumn();
-// ImGuiCustom.CopyOnClickSelectable( source.Path );
-//
-// ImGui.TableNextColumn();
-// ImGuiCustom.PrintIcon( FontAwesomeIcon.LongArrowAltRight );
-//
-// ImGui.TableNextColumn();
-// ImGuiCustom.CopyOnClickSelectable( target.InternalName );
-//
-// ImGui.TableNextRow();
-// }
-// }
-//
-// private void UpdateFilenameList()
-// {
-// if( _fullFilenameList != null )
-// {
-// return;
-// }
-//
-// _fullFilenameList = Mod.Data.Resources.ModFiles
-// .Select( f => ( f, false, ColorGreen, Utf8RelPath.FromFile( f, Mod.Data.BasePath, out var p ) ? p : Utf8RelPath.Empty ) )
-// .ToArray();
-//
-// if( Meta.Groups.Count == 0 )
-// {
-// return;
-// }
-//
-// for( var i = 0; i < Mod.Data.Resources.ModFiles.Count; ++i )
-// {
-// foreach( var group in Meta.Groups.Values )
-// {
-// var inAll = true;
-// foreach( var option in group.Options )
-// {
-// if( option.OptionFiles.ContainsKey( _fullFilenameList[ i ].relName ) )
-// {
-// _fullFilenameList[ i ].color = ColorYellow;
-// }
-// else
-// {
-// inAll = false;
-// }
-// }
-//
-// if( inAll && group.SelectionType == SelectType.Single )
-// {
-// _fullFilenameList[ i ].color = ColorGreen;
-// }
-// }
-// }
-// }
-//
-// private void DrawFileListTab()
-// {
-// if( !ImGui.BeginTabItem( LabelFileListTab ) )
-// {
-// return;
-// }
-//
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
-// ImGuiCustom.HoverTooltip( TooltipFilesTab );
-//
-// ImGui.SetNextItemWidth( -1 );
-// if( ImGui.BeginListBox( LabelFileListHeader, AutoFillSize ) )
-// {
-// raii.Push( ImGui.EndListBox );
-// UpdateFilenameList();
-// using var colorRaii = new ImGuiRaii.Color();
-// foreach( var (name, _, color, _) in _fullFilenameList! )
-// {
-// colorRaii.Push( ImGuiCol.Text, color );
-// ImGui.Selectable( name.FullName );
-// colorRaii.Pop();
-// }
-// }
-// else
-// {
-// _fullFilenameList = null;
-// }
-// }
-//
-// private static int HandleDefaultString( Utf8GamePath[] gamePaths, out int removeFolders )
-// {
-// removeFolders = 0;
-// var defaultIndex = gamePaths.IndexOf( p => p.Path.StartsWith( DefaultUtf8GamePath ) );
-// if( defaultIndex < 0 )
-// {
-// return defaultIndex;
-// }
-//
-// var path = gamePaths[ defaultIndex ].Path;
-// if( path.Length == TextDefaultGamePath.Length )
-// {
-// return defaultIndex;
-// }
-//
-// if( path[ TextDefaultGamePath.Length ] != ( byte )'-'
-// || !int.TryParse( path.Substring( TextDefaultGamePath.Length + 1 ).ToString(), out removeFolders ) )
-// {
-// return -1;
-// }
-//
-// return defaultIndex;
-// }
-//
-// private void HandleSelectedFilesButton( bool remove )
-// {
-// if( _selectedOption == null )
-// {
-// return;
-// }
-//
-// var option = ( ConfigModule.Option )_selectedOption;
-//
-// var gamePaths = _currentGamePaths.Split( ';' )
-// .Select( p => Utf8GamePath.FromString( p, out var path, false ) ? path : Utf8GamePath.Empty ).Where( p => !p.IsEmpty ).ToArray();
-// if( gamePaths.Length == 0 )
-// {
-// return;
-// }
-//
-// var defaultIndex = HandleDefaultString( gamePaths, out var removeFolders );
-// var changed = false;
-// for( var i = 0; i < Mod.Data.Resources.ModFiles.Count; ++i )
-// {
-// if( !_fullFilenameList![ i ].selected )
-// {
-// continue;
-// }
-//
-// _fullFilenameList![ i ].selected = false;
-// var relName = _fullFilenameList[ i ].relName;
-// if( defaultIndex >= 0 )
-// {
-// gamePaths[ defaultIndex ] = relName.ToGamePath( removeFolders );
-// }
-//
-// if( remove && option.OptionFiles.TryGetValue( relName, out var setPaths ) )
-// {
-// if( setPaths.RemoveWhere( p => gamePaths.Contains( p ) ) > 0 )
-// {
-// changed = true;
-// }
-//
-// if( setPaths.Count == 0 && option.OptionFiles.Remove( relName ) )
-// {
-// changed = true;
-// }
-// }
-// else
-// {
-// changed = gamePaths
-// .Aggregate( changed, ( current, gamePath ) => current | option.AddFile( relName, gamePath ) );
-// }
-// }
-//
-// if( changed )
-// {
-// _fullFilenameList = null;
-// _selector.SaveCurrentMod();
-// var idx = Penumbra.ModManager.Mods.IndexOf( Mod.Data );
-// // Since files may have changed, we need to recompute effective files.
-// foreach( var collection in Penumbra.CollectionManager
-// .Where( c => c.HasCache && c[ idx ].Settings?.Enabled == true ) )
-// {
-// collection.CalculateEffectiveFileList( false, collection == Penumbra.CollectionManager.Default );
-// }
-//
-// // If the mod is enabled in the current collection, its conflicts may have changed.
-// if( Mod.Settings.Enabled )
-// {
-// _selector.Cache.TriggerFilterReset();
-// }
-// }
-// }
-//
-// private void DrawAddToGroupButton()
-// {
-// if( ImGui.Button( ButtonAddToGroup ) )
-// {
-// HandleSelectedFilesButton( false );
-// }
-// }
-//
-// private void DrawRemoveFromGroupButton()
-// {
-// if( ImGui.Button( ButtonRemoveFromGroup ) )
-// {
-// HandleSelectedFilesButton( true );
-// }
-// }
-//
-// private void DrawGamePathInput()
-// {
-// ImGui.SetNextItemWidth( -1 );
-// ImGui.InputTextWithHint( LabelGamePathsEditBox, "Hover for help...", ref _currentGamePaths,
-// 128 );
-// ImGuiCustom.HoverTooltip( TooltipGamePathsEdit );
-// }
-//
-// private void DrawGroupRow()
-// {
-// if( _selectedGroup == null )
-// {
-// SelectGroup();
-// }
-//
-// if( _selectedOption == null )
-// {
-// SelectOption();
-// }
-//
-// if( !DrawEditGroupSelector() )
-// {
-// return;
-// }
-//
-// ImGui.SameLine();
-// if( !DrawEditOptionSelector() )
-// {
-// return;
-// }
-//
-// ImGui.SameLine();
-// DrawAddToGroupButton();
-// ImGui.SameLine();
-// DrawRemoveFromGroupButton();
-// ImGui.SameLine();
-// DrawGamePathInput();
-// }
-//
-// private void DrawFileAndGamePaths( int idx )
-// {
-// void Selectable( uint colorNormal, uint colorReplace )
-// {
-// var loc = _fullFilenameList![ idx ].color;
-// if( loc == colorNormal )
-// {
-// loc = colorReplace;
-// }
-//
-// using var colors = ImGuiRaii.PushColor( ImGuiCol.Text, loc );
-// ImGui.Selectable( _fullFilenameList[ idx ].name.FullName, ref _fullFilenameList[ idx ].selected );
-// }
-//
-// const float indentWidth = 30f;
-// if( _selectedOption == null )
-// {
-// Selectable( 0, ColorGreen );
-// return;
-// }
-//
-// var fileName = _fullFilenameList![ idx ].relName;
-// var optionFiles = ( ( ConfigModule.Option )_selectedOption ).OptionFiles;
-// if( optionFiles.TryGetValue( fileName, out var gamePaths ) )
-// {
-// Selectable( 0, ColorGreen );
-//
-// using var indent = ImGuiRaii.PushIndent( indentWidth );
-// foreach( var gamePath in gamePaths.ToArray() )
-// {
-// var tmp = gamePath.ToString();
-// var old = tmp;
-// if( ImGui.InputText( $"##{fileName}_{gamePath}", ref tmp, 128, ImGuiInputTextFlags.EnterReturnsTrue )
-// && tmp != old )
-// {
-// gamePaths.Remove( gamePath );
-// if( tmp.Length > 0 && Utf8GamePath.FromString( tmp, out var p, true ) )
-// {
-// gamePaths.Add( p );
-// }
-// else if( gamePaths.Count == 0 )
-// {
-// optionFiles.Remove( fileName );
-// }
-//
-// _selector.SaveCurrentMod();
-// _selector.ReloadCurrentMod();
-// }
-// }
-// }
-// else
-// {
-// Selectable( ColorYellow, ColorRed );
-// }
-// }
-//
-// private void DrawMultiSelectorCheckBox( OptionGroup group, int idx, int flag, string label )
-// {
-// var enabled = ( flag & ( 1 << idx ) ) != 0;
-// var oldEnabled = enabled;
-// if( ImGui.Checkbox( label, ref enabled ) && oldEnabled != enabled )
-// {
-// Penumbra.CollectionManager.Current.SetModSetting( Mod.Data.Index, group.GroupName,
-// Mod.Settings.Settings[ group.GroupName ] ^ ( 1 << idx ) );
-// // If the mod is enabled, recalculate files and filters.
-// if( Mod.Settings.Enabled )
-// {
-// _selector.Cache.TriggerFilterReset();
-// }
-// }
-// }
-//
-// private void DrawMultiSelector( OptionGroup group )
-// {
-// if( group.Options.Count == 0 )
-// {
-// return;
-// }
-//
-// ImGuiCustom.BeginFramedGroup( group.GroupName );
-// using var raii = ImGuiRaii.DeferredEnd( ImGuiCustom.EndFramedGroup );
-// for( var i = 0; i < group.Options.Count; ++i )
-// {
-// DrawMultiSelectorCheckBox( group, i, Mod.Settings.Settings[ group.GroupName ],
-// $"{group.Options[ i ].OptionName}##{group.GroupName}" );
-// }
-// }
-//
-// private void DrawSingleSelector( OptionGroup group )
-// {
-// if( group.Options.Count < 2 )
-// {
-// return;
-// }
-//
-// var code = Mod.Settings.Settings[ group.GroupName ];
-// if( ImGui.Combo( group.GroupName, ref code
-// , group.Options.Select( x => x.OptionName ).ToArray(), group.Options.Count )
-// && code != Mod.Settings.Settings[ group.GroupName ] )
-// {
-// Penumbra.CollectionManager.Current.SetModSetting( Mod.Data.Index, group.GroupName, code );
-// if( Mod.Settings.Enabled )
-// {
-// _selector.Cache.TriggerFilterReset();
-// }
-// }
-// }
-//
-// private void DrawGroupSelectors()
-// {
-// foreach( var g in Meta.Groups.Values.Where( g => g.SelectionType == SelectType.Single ) )
-// {
-// DrawSingleSelector( g );
-// }
-//
-// foreach( var g in Meta.Groups.Values.Where( g => g.SelectionType == SelectType.Multi ) )
-// {
-// DrawMultiSelector( g );
-// }
-// }
-//
-// private void DrawConfigurationTab()
-// {
-// if( !_editMode && !Meta.HasGroupsWithConfig || !ImGui.BeginTabItem( LabelConfigurationTab ) )
-// {
-// return;
-// }
-//
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
-// if( _editMode )
-// {
-// DrawGroupSelectorsEdit();
-// }
-// else
-// {
-// DrawGroupSelectors();
-// }
-// }
-//
-// private void DrawMetaManipulationsTab()
-// {
-// if( !_editMode && Mod.Data.Resources.MetaManipulations.Count == 0 || !ImGui.BeginTabItem( "Meta Manipulations" ) )
-// {
-// return;
-// }
-//
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
-//
-// if( !ImGui.BeginListBox( "##MetaManipulations", AutoFillSize ) )
-// {
-// return;
-// }
-//
-// raii.Push( ImGui.EndListBox );
-//
-// var manips = Mod.Data.Resources.MetaManipulations;
-// var changes = false;
-// if( _editMode || manips.DefaultData.Count > 0 )
-// {
-// if( ImGui.CollapsingHeader( "Default" ) )
-// {
-// changes = DrawMetaManipulationsTable( "##DefaultManips", manips.DefaultData, ref manips.Count );
-// }
-// }
-//
-// foreach( var (groupName, group) in manips.GroupData )
-// {
-// foreach( var (optionName, option) in group )
-// {
-// if( ImGui.CollapsingHeader( $"{groupName} - {optionName}" ) )
-// {
-// changes |= DrawMetaManipulationsTable( $"##{groupName}{optionName}manips", option, ref manips.Count );
-// }
-// }
-// }
-//
-// if( changes )
-// {
-// Mod.Data.Resources.MetaManipulations.SaveToFile( MetaCollection.FileName( Mod.Data.BasePath ) );
-// Mod.Data.Resources.SetManipulations( Meta, Mod.Data.BasePath, false );
-// _selector.ReloadCurrentMod( true, false );
-// }
-// }
-//
-// public void Draw( bool editMode )
-// {
-// _editMode = editMode;
-// if( !ImGui.BeginTabBar( LabelPluginDetails ) )
-// {
-// return;
-// }
-//
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabBar );
-// DrawAboutTab();
-// DrawChangedItemsTab();
-//
-// DrawConfigurationTab();
-// if( _editMode )
-// {
-// DrawFileListTabEdit();
-// }
-// else
-// {
-// DrawFileListTab();
-// }
-//
-// DrawFileSwapTab();
-// DrawMetaManipulationsTab();
-// DrawConflictTab();
-// }
-// }
-//}
\ No newline at end of file
diff --git a/Penumbra/UI/ConfigWindow.ModsTab.DetailsEdit.cs b/Penumbra/UI/ConfigWindow.ModsTab.DetailsEdit.cs
deleted file mode 100644
index a6024185..00000000
--- a/Penumbra/UI/ConfigWindow.ModsTab.DetailsEdit.cs
+++ /dev/null
@@ -1,381 +0,0 @@
-//using System.Collections.Generic;
-//using System.Linq;
-//using System.Numerics;
-//using Dalamud.Interface;
-//using FFXIVClientStructs.FFXIV.Client.UI.Misc;
-//using ImGuiNET;
-//using Penumbra.GameData.ByteString;
-//using Penumbra.GameData.Util;
-//using Penumbra.Mods;
-//using Penumbra.UI.Custom;
-//using Penumbra.Util;
-//
-//namespace Penumbra.UI;
-//
-//public partial class SettingsInterface
-//{
-// private partial class PluginDetails
-// {
-// private const string LabelDescEdit = "##descedit";
-// private const string LabelNewSingleGroupEdit = "##newSingleGroup";
-// private const string LabelNewMultiGroup = "##newMultiGroup";
-// private const string LabelGamePathsEditBox = "##gamePathsEdit";
-// private const string ButtonAddToGroup = "Add to Group";
-// private const string ButtonRemoveFromGroup = "Remove from Group";
-// private const string TooltipAboutEdit = "Use Ctrl+Enter for newlines.";
-// private const string TextNoOptionAvailable = "[Not Available]";
-// private const string TextDefaultGamePath = "default";
-// private static readonly Utf8String DefaultUtf8GamePath = Utf8String.FromStringUnsafe( TextDefaultGamePath, true );
-// private const char GamePathsSeparator = ';';
-//
-// private static readonly string TooltipFilesTabEdit =
-// $"{TooltipFilesTab}\n"
-// + $"Red Files are replaced in another group or a different option in this group, but not contained in the current option.";
-//
-// private static readonly string TooltipGamePathsEdit =
-// $"Enter all game paths to add or remove, separated by '{GamePathsSeparator}'.\n"
-// + $"Use '{TextDefaultGamePath}' to add the original file path."
-// + $"Use '{TextDefaultGamePath}-#' to skip the first # relative directories.";
-//
-// private const float MultiEditBoxWidth = 300f;
-//
-// private bool DrawEditGroupSelector()
-// {
-// ImGui.SetNextItemWidth( OptionSelectionWidth * ImGuiHelpers.GlobalScale );
-// if( Meta!.Groups.Count == 0 )
-// {
-// ImGui.Combo( LabelGroupSelect, ref _selectedGroupIndex, TextNoOptionAvailable, 1 );
-// return false;
-// }
-//
-// if( ImGui.Combo( LabelGroupSelect, ref _selectedGroupIndex
-// , Meta.Groups.Values.Select( g => g.GroupName ).ToArray()
-// , Meta.Groups.Count ) )
-// {
-// SelectGroup();
-// SelectOption( 0 );
-// }
-//
-// return true;
-// }
-//
-// private bool DrawEditOptionSelector()
-// {
-// ImGui.SameLine();
-// ImGui.SetNextItemWidth( OptionSelectionWidth );
-// if( ( _selectedGroup?.Options.Count ?? 0 ) == 0 )
-// {
-// ImGui.Combo( LabelOptionSelect, ref _selectedOptionIndex, TextNoOptionAvailable, 1 );
-// return false;
-// }
-//
-// var group = ( OptionGroup )_selectedGroup!;
-// if( ImGui.Combo( LabelOptionSelect, ref _selectedOptionIndex, group.Options.Select( o => o.OptionName ).ToArray(),
-// group.Options.Count ) )
-// {
-// SelectOption();
-// }
-//
-// return true;
-// }
-//
-// private void DrawFileListTabEdit()
-// {
-// if( ImGui.BeginTabItem( LabelFileListTab ) )
-// {
-// UpdateFilenameList();
-// if( ImGui.IsItemHovered() )
-// {
-// ImGui.SetTooltip( _editMode ? TooltipFilesTabEdit : TooltipFilesTab );
-// }
-//
-// ImGui.SetNextItemWidth( -1 );
-// if( ImGui.BeginListBox( LabelFileListHeader, AutoFillSize - Vector2.UnitY * 1.5f * ImGui.GetTextLineHeight() ) )
-// {
-// for( var i = 0; i < Mod!.Data.Resources.ModFiles.Count; ++i )
-// {
-// DrawFileAndGamePaths( i );
-// }
-// }
-//
-// ImGui.EndListBox();
-//
-// DrawGroupRow();
-// ImGui.EndTabItem();
-// }
-// else
-// {
-// _fullFilenameList = null;
-// }
-// }
-//
-// private ImGuiRaii.EndStack DrawMultiSelectorEditBegin( OptionGroup group )
-// {
-// var groupName = group.GroupName;
-// if( ImGuiCustom.BeginFramedGroupEdit( ref groupName ) )
-// {
-// if( Penumbra.ModManager.ChangeModGroup( group.GroupName, groupName, Mod.Data ) && Mod.Data.Meta.RefreshHasGroupsWithConfig() )
-// {
-// _selector.Cache.TriggerFilterReset();
-// }
-// }
-//
-// return ImGuiRaii.DeferredEnd( ImGuiCustom.EndFramedGroup );
-// }
-//
-// private void DrawMultiSelectorEditAdd( OptionGroup group, float nameBoxStart )
-// {
-// var newOption = "";
-// ImGui.SetCursorPosX( nameBoxStart );
-// ImGui.SetNextItemWidth( MultiEditBoxWidth * ImGuiHelpers.GlobalScale );
-// if( ImGui.InputTextWithHint( $"##new_{group.GroupName}_l", "Add new option...", ref newOption, 64,
-// ImGuiInputTextFlags.EnterReturnsTrue )
-// && newOption.Length != 0 )
-// {
-// group.Options.Add( new ConfigModule.Option()
-// { OptionName = newOption, OptionDesc = "", OptionFiles = new Dictionary< Utf8RelPath, HashSet< Utf8GamePath > >() } );
-// _selector.SaveCurrentMod();
-// if( Mod!.Data.Meta.RefreshHasGroupsWithConfig() )
-// {
-// _selector.Cache.TriggerFilterReset();
-// }
-// }
-// }
-//
-// private void DrawMultiSelectorEdit( OptionGroup group )
-// {
-// var nameBoxStart = CheckMarkSize;
-// var flag = Mod!.Settings.Settings[ group.GroupName ];
-//
-// using var raii = DrawMultiSelectorEditBegin( group );
-// for( var i = 0; i < group.Options.Count; ++i )
-// {
-// var opt = group.Options[ i ];
-// var label = $"##{group.GroupName}_{i}";
-// DrawMultiSelectorCheckBox( group, i, flag, label );
-//
-// ImGui.SameLine();
-// var newName = opt.OptionName;
-//
-// if( nameBoxStart == CheckMarkSize )
-// {
-// nameBoxStart = ImGui.GetCursorPosX();
-// }
-//
-// ImGui.SetNextItemWidth( MultiEditBoxWidth * ImGuiHelpers.GlobalScale );
-// if( ImGui.InputText( $"{label}_l", ref newName, 64, ImGuiInputTextFlags.EnterReturnsTrue ) )
-// {
-// if( newName.Length == 0 )
-// {
-// Penumbra.ModManager.RemoveModOption( i, group, Mod.Data );
-// }
-// else if( newName != opt.OptionName )
-// {
-// group.Options[ i ] = new ConfigModule.Option()
-// { OptionName = newName, OptionDesc = opt.OptionDesc, OptionFiles = opt.OptionFiles };
-// _selector.SaveCurrentMod();
-// }
-//
-// if( Mod!.Data.Meta.RefreshHasGroupsWithConfig() )
-// {
-// _selector.Cache.TriggerFilterReset();
-// }
-// }
-// }
-//
-// DrawMultiSelectorEditAdd( group, nameBoxStart );
-// }
-//
-// private void DrawSingleSelectorEditGroup( OptionGroup group )
-// {
-// var groupName = group.GroupName;
-// if( ImGui.InputText( $"##{groupName}_add", ref groupName, 64, ImGuiInputTextFlags.EnterReturnsTrue ) )
-// {
-// if( Penumbra.ModManager.ChangeModGroup( group.GroupName, groupName, Mod.Data ) && Mod.Data.Meta.RefreshHasGroupsWithConfig() )
-// {
-// _selector.Cache.TriggerFilterReset();
-// }
-// }
-// }
-//
-// private float DrawSingleSelectorEdit( OptionGroup group )
-// {
-// var oldSetting = Mod!.Settings.Settings[ group.GroupName ];
-// var code = oldSetting;
-// if( ImGuiCustom.RenameableCombo( $"##{group.GroupName}", ref code, out var newName,
-// group.Options.Select( x => x.OptionName ).ToArray(), group.Options.Count ) )
-// {
-// if( code == group.Options.Count )
-// {
-// if( newName.Length > 0 )
-// {
-// Penumbra.CollectionManager.Current.SetModSetting(Mod.Data.Index, group.GroupName, code);
-// group.Options.Add( new ConfigModule.Option()
-// {
-// OptionName = newName,
-// OptionDesc = "",
-// OptionFiles = new Dictionary< Utf8RelPath, HashSet< Utf8GamePath > >(),
-// } );
-// _selector.SaveCurrentMod();
-// }
-// }
-// else
-// {
-// if( newName.Length == 0 )
-// {
-// Penumbra.ModManager.RemoveModOption( code, group, Mod.Data );
-// }
-// else
-// {
-// if( newName != group.Options[ code ].OptionName )
-// {
-// group.Options[ code ] = new ConfigModule.Option()
-// {
-// OptionName = newName, OptionDesc = group.Options[ code ].OptionDesc,
-// OptionFiles = group.Options[ code ].OptionFiles,
-// };
-// _selector.SaveCurrentMod();
-// }
-// }
-// }
-//
-// if( Mod.Data.Meta.RefreshHasGroupsWithConfig() )
-// {
-// _selector.Cache.TriggerFilterReset();
-// }
-// }
-//
-// ImGui.SameLine();
-// var labelEditPos = ImGui.GetCursorPosX();
-// DrawSingleSelectorEditGroup( group );
-//
-// return labelEditPos;
-// }
-//
-// private void DrawAddSingleGroupField( float labelEditPos )
-// {
-// var newGroup = "";
-// ImGui.SetCursorPosX( labelEditPos );
-// if( labelEditPos == CheckMarkSize )
-// {
-// ImGui.SetNextItemWidth( MultiEditBoxWidth * ImGuiHelpers.GlobalScale );
-// }
-//
-// if( ImGui.InputTextWithHint( LabelNewSingleGroupEdit, "Add new Single Group...", ref newGroup, 64,
-// ImGuiInputTextFlags.EnterReturnsTrue ) )
-// {
-// Penumbra.ModManager.ChangeModGroup( "", newGroup, Mod.Data, SelectType.Single );
-// // Adds empty group, so can not change filters.
-// }
-// }
-//
-// private void DrawAddMultiGroupField()
-// {
-// var newGroup = "";
-// ImGui.SetCursorPosX( CheckMarkSize );
-// ImGui.SetNextItemWidth( MultiEditBoxWidth * ImGuiHelpers.GlobalScale );
-// if( ImGui.InputTextWithHint( LabelNewMultiGroup, "Add new Multi Group...", ref newGroup, 64,
-// ImGuiInputTextFlags.EnterReturnsTrue ) )
-// {
-// Penumbra.ModManager.ChangeModGroup( "", newGroup, Mod.Data, SelectType.Multi );
-// // Adds empty group, so can not change filters.
-// }
-// }
-//
-// private void DrawGroupSelectorsEdit()
-// {
-// var labelEditPos = CheckMarkSize;
-// var groups = Meta.Groups.Values.ToArray();
-// foreach( var g in groups.Where( g => g.SelectionType == SelectType.Single ) )
-// {
-// labelEditPos = DrawSingleSelectorEdit( g );
-// }
-//
-// DrawAddSingleGroupField( labelEditPos );
-//
-// foreach( var g in groups.Where( g => g.SelectionType == SelectType.Multi ) )
-// {
-// DrawMultiSelectorEdit( g );
-// }
-//
-// DrawAddMultiGroupField();
-// }
-//
-// private void DrawFileSwapTabEdit()
-// {
-// if( !ImGui.BeginTabItem( LabelFileSwapTab ) )
-// {
-// return;
-// }
-//
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
-//
-// ImGui.SetNextItemWidth( -1 );
-// if( !ImGui.BeginListBox( LabelFileSwapHeader, AutoFillSize ) )
-// {
-// return;
-// }
-//
-// raii.Push( ImGui.EndListBox );
-//
-// var swaps = Meta.FileSwaps.Keys.ToArray();
-//
-// ImGui.PushFont( UiBuilder.IconFont );
-// var arrowWidth = ImGui.CalcTextSize( FontAwesomeIcon.LongArrowAltRight.ToIconString() ).X;
-// ImGui.PopFont();
-//
-// var width = ( ImGui.GetWindowWidth() - arrowWidth - 4 * ImGui.GetStyle().ItemSpacing.X ) / 2;
-// for( var idx = 0; idx < swaps.Length + 1; ++idx )
-// {
-// var key = idx == swaps.Length ? Utf8GamePath.Empty : swaps[ idx ];
-// var value = idx == swaps.Length ? FullPath.Empty : Meta.FileSwaps[ key ];
-// var keyString = key.ToString();
-// var valueString = value.ToString();
-//
-// ImGui.SetNextItemWidth( width );
-// if( ImGui.InputTextWithHint( $"##swapLhs_{idx}", "Enter new file to be replaced...", ref keyString,
-// GamePath.MaxGamePathLength, ImGuiInputTextFlags.EnterReturnsTrue ) )
-// {
-// if( Utf8GamePath.FromString( keyString, out var newKey, true ) && newKey.CompareTo( key ) != 0 )
-// {
-// if( idx < swaps.Length )
-// {
-// Meta.FileSwaps.Remove( key );
-// }
-//
-// if( !newKey.IsEmpty )
-// {
-// Meta.FileSwaps[ newKey ] = value;
-// }
-//
-// _selector.SaveCurrentMod();
-// _selector.ReloadCurrentMod();
-// }
-// }
-//
-// if( idx >= swaps.Length )
-// {
-// continue;
-// }
-//
-// ImGui.SameLine();
-// ImGuiCustom.PrintIcon( FontAwesomeIcon.LongArrowAltRight );
-// ImGui.SameLine();
-//
-// ImGui.SetNextItemWidth( width );
-// if( ImGui.InputTextWithHint( $"##swapRhs_{idx}", "Enter new replacement path...", ref valueString,
-// GamePath.MaxGamePathLength,
-// ImGuiInputTextFlags.EnterReturnsTrue ) )
-// {
-// var newValue = new FullPath( valueString.ToLowerInvariant() );
-// if( newValue.CompareTo( value ) != 0 )
-// {
-// Meta.FileSwaps[ key ] = newValue;
-// _selector.SaveCurrentMod();
-// _selector.Cache.TriggerListReset();
-// }
-// }
-// }
-// }
-// }
-//}
\ No newline at end of file
diff --git a/Penumbra/UI/ConfigWindow.ModsTab.DetailsManipulation.cs b/Penumbra/UI/ConfigWindow.ModsTab.DetailsManipulation.cs
deleted file mode 100644
index f1b63d5a..00000000
--- a/Penumbra/UI/ConfigWindow.ModsTab.DetailsManipulation.cs
+++ /dev/null
@@ -1,773 +0,0 @@
-//using System;
-//using System.Collections.Generic;
-//using System.ComponentModel;
-//using System.Linq;
-//using System.Numerics;
-//using Dalamud.Interface;
-//using ImGuiNET;
-//using Penumbra.GameData.Enums;
-//using Penumbra.GameData.Structs;
-//using Penumbra.Meta.Files;
-//using Penumbra.Meta.Manipulations;
-//using Penumbra.UI.Custom;
-//using ObjectType = Penumbra.GameData.Enums.ObjectType;
-//
-//namespace Penumbra.UI;
-//
-//public partial class SettingsInterface
-//{
-// private partial class PluginDetails
-// {
-// private int _newManipTypeIdx = 0;
-// private ushort _newManipSetId = 0;
-// private ushort _newManipSecondaryId = 0;
-// private int _newManipSubrace = 0;
-// private int _newManipRace = 0;
-// private int _newManipAttribute = 0;
-// private int _newManipEquipSlot = 0;
-// private int _newManipObjectType = 0;
-// private int _newManipGender = 0;
-// private int _newManipBodySlot = 0;
-// private ushort _newManipVariant = 0;
-//
-//
-// private static readonly (string, EquipSlot)[] EqpEquipSlots =
-// {
-// ( "Head", EquipSlot.Head ),
-// ( "Body", EquipSlot.Body ),
-// ( "Hands", EquipSlot.Hands ),
-// ( "Legs", EquipSlot.Legs ),
-// ( "Feet", EquipSlot.Feet ),
-// };
-//
-// private static readonly (string, EquipSlot)[] EqdpEquipSlots =
-// {
-// EqpEquipSlots[ 0 ],
-// EqpEquipSlots[ 1 ],
-// EqpEquipSlots[ 2 ],
-// EqpEquipSlots[ 3 ],
-// EqpEquipSlots[ 4 ],
-// ( "Ears", EquipSlot.Ears ),
-// ( "Neck", EquipSlot.Neck ),
-// ( "Wrist", EquipSlot.Wrists ),
-// ( "Left Finger", EquipSlot.LFinger ),
-// ( "Right Finger", EquipSlot.RFinger ),
-// };
-//
-// private static readonly (string, ModelRace)[] Races =
-// {
-// ( ModelRace.Midlander.ToName(), ModelRace.Midlander ),
-// ( ModelRace.Highlander.ToName(), ModelRace.Highlander ),
-// ( ModelRace.Elezen.ToName(), ModelRace.Elezen ),
-// ( ModelRace.Miqote.ToName(), ModelRace.Miqote ),
-// ( ModelRace.Roegadyn.ToName(), ModelRace.Roegadyn ),
-// ( ModelRace.Lalafell.ToName(), ModelRace.Lalafell ),
-// ( ModelRace.AuRa.ToName(), ModelRace.AuRa ),
-// ( ModelRace.Viera.ToName(), ModelRace.Viera ),
-// ( ModelRace.Hrothgar.ToName(), ModelRace.Hrothgar ),
-// };
-//
-// private static readonly (string, Gender)[] Genders =
-// {
-// ( Gender.Male.ToName(), Gender.Male ),
-// ( Gender.Female.ToName(), Gender.Female ),
-// ( Gender.MaleNpc.ToName(), Gender.MaleNpc ),
-// ( Gender.FemaleNpc.ToName(), Gender.FemaleNpc ),
-// };
-//
-// private static readonly (string, EstManipulation.EstType)[] EstTypes =
-// {
-// ( "Hair", EstManipulation.EstType.Hair ),
-// ( "Face", EstManipulation.EstType.Face ),
-// ( "Body", EstManipulation.EstType.Body ),
-// ( "Head", EstManipulation.EstType.Head ),
-// };
-//
-// private static readonly (string, SubRace)[] Subraces =
-// {
-// ( SubRace.Midlander.ToName(), SubRace.Midlander ),
-// ( SubRace.Highlander.ToName(), SubRace.Highlander ),
-// ( SubRace.Wildwood.ToName(), SubRace.Wildwood ),
-// ( SubRace.Duskwight.ToName(), SubRace.Duskwight ),
-// ( SubRace.SeekerOfTheSun.ToName(), SubRace.SeekerOfTheSun ),
-// ( SubRace.KeeperOfTheMoon.ToName(), SubRace.KeeperOfTheMoon ),
-// ( SubRace.Seawolf.ToName(), SubRace.Seawolf ),
-// ( SubRace.Hellsguard.ToName(), SubRace.Hellsguard ),
-// ( SubRace.Plainsfolk.ToName(), SubRace.Plainsfolk ),
-// ( SubRace.Dunesfolk.ToName(), SubRace.Dunesfolk ),
-// ( SubRace.Raen.ToName(), SubRace.Raen ),
-// ( SubRace.Xaela.ToName(), SubRace.Xaela ),
-// ( SubRace.Rava.ToName(), SubRace.Rava ),
-// ( SubRace.Veena.ToName(), SubRace.Veena ),
-// ( SubRace.Helion.ToName(), SubRace.Helion ),
-// ( SubRace.Lost.ToName(), SubRace.Lost ),
-// };
-//
-// private static readonly (string, RspAttribute)[] RspAttributes =
-// {
-// ( RspAttribute.MaleMinSize.ToFullString(), RspAttribute.MaleMinSize ),
-// ( RspAttribute.MaleMaxSize.ToFullString(), RspAttribute.MaleMaxSize ),
-// ( RspAttribute.FemaleMinSize.ToFullString(), RspAttribute.FemaleMinSize ),
-// ( RspAttribute.FemaleMaxSize.ToFullString(), RspAttribute.FemaleMaxSize ),
-// ( RspAttribute.BustMinX.ToFullString(), RspAttribute.BustMinX ),
-// ( RspAttribute.BustMaxX.ToFullString(), RspAttribute.BustMaxX ),
-// ( RspAttribute.BustMinY.ToFullString(), RspAttribute.BustMinY ),
-// ( RspAttribute.BustMaxY.ToFullString(), RspAttribute.BustMaxY ),
-// ( RspAttribute.BustMinZ.ToFullString(), RspAttribute.BustMinZ ),
-// ( RspAttribute.BustMaxZ.ToFullString(), RspAttribute.BustMaxZ ),
-// ( RspAttribute.MaleMinTail.ToFullString(), RspAttribute.MaleMinTail ),
-// ( RspAttribute.MaleMaxTail.ToFullString(), RspAttribute.MaleMaxTail ),
-// ( RspAttribute.FemaleMinTail.ToFullString(), RspAttribute.FemaleMinTail ),
-// ( RspAttribute.FemaleMaxTail.ToFullString(), RspAttribute.FemaleMaxTail ),
-// };
-//
-//
-// private static readonly (string, ObjectType)[] ImcObjectType =
-// {
-// ( "Equipment", ObjectType.Equipment ),
-// ( "Customization", ObjectType.Character ),
-// ( "Weapon", ObjectType.Weapon ),
-// ( "Demihuman", ObjectType.DemiHuman ),
-// ( "Monster", ObjectType.Monster ),
-// };
-//
-// private static readonly (string, BodySlot)[] ImcBodySlots =
-// {
-// ( "Hair", BodySlot.Hair ),
-// ( "Face", BodySlot.Face ),
-// ( "Body", BodySlot.Body ),
-// ( "Tail", BodySlot.Tail ),
-// ( "Ears", BodySlot.Zear ),
-// };
-//
-// private static bool PrintCheckBox( string name, ref bool value, bool def )
-// {
-// var color = value == def ? 0 : value ? ColorDarkGreen : ColorDarkRed;
-// if( color == 0 )
-// {
-// return ImGui.Checkbox( name, ref value );
-// }
-//
-// using var colorRaii = ImGuiRaii.PushColor( ImGuiCol.Text, color );
-// var ret = ImGui.Checkbox( name, ref value );
-// return ret;
-// }
-//
-// private bool RestrictedInputInt( string name, ref ushort value, ushort min, ushort max )
-// {
-// int tmp = value;
-// if( ImGui.InputInt( name, ref tmp, 0, 0, _editMode ? ImGuiInputTextFlags.EnterReturnsTrue : ImGuiInputTextFlags.ReadOnly )
-// && tmp != value
-// && tmp >= min
-// && tmp <= max )
-// {
-// value = ( ushort )tmp;
-// return true;
-// }
-//
-// return false;
-// }
-//
-// private static bool DefaultButton< T >( string name, ref T value, T defaultValue ) where T : IComparable< T >
-// {
-// var compare = defaultValue.CompareTo( value );
-// var color = compare < 0 ? ColorDarkGreen :
-// compare > 0 ? ColorDarkRed : ImGui.ColorConvertFloat4ToU32( ImGui.GetStyle().Colors[ ( int )ImGuiCol.Button ] );
-//
-// using var colorRaii = ImGuiRaii.PushColor( ImGuiCol.Button, color );
-// var ret = ImGui.Button( name, Vector2.UnitX * 120 ) && compare != 0;
-// ImGui.SameLine();
-// return ret;
-// }
-//
-// private bool DrawInputWithDefault( string name, ref ushort value, ushort defaultValue, ushort max )
-// => DefaultButton( $"{( _editMode ? "Set to " : "" )}Default: {defaultValue}##imc{name}", ref value, defaultValue )
-// || RestrictedInputInt( name, ref value, 0, max );
-//
-// private static bool CustomCombo< T >( string label, IList< (string, T) > namesAndValues, out T value, ref int idx )
-// {
-// value = idx < namesAndValues.Count ? namesAndValues[ idx ].Item2 : default!;
-//
-// if( !ImGui.BeginCombo( label, idx < namesAndValues.Count ? namesAndValues[ idx ].Item1 : string.Empty ) )
-// {
-// return false;
-// }
-//
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndCombo );
-//
-// for( var i = 0; i < namesAndValues.Count; ++i )
-// {
-// if( !ImGui.Selectable( $"{namesAndValues[ i ].Item1}##{label}{i}", idx == i ) || idx == i )
-// {
-// continue;
-// }
-//
-// idx = i;
-// value = namesAndValues[ i ].Item2;
-// return true;
-// }
-//
-// return false;
-// }
-//
-// private bool DrawEqpRow( int manipIdx, IList< MetaManipulation > list )
-// {
-// var ret = false;
-// var id = list[ manipIdx ].Eqp;
-// var val = id.Entry;
-//
-//
-// if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) )
-// {
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup );
-// var defaults = ExpandedEqpFile.GetDefault( id.SetId );
-// var attributes = Eqp.EqpAttributes[ id.Slot ];
-//
-// foreach( var flag in attributes )
-// {
-// var name = flag.ToLocalName();
-// var tmp = val.HasFlag( flag );
-// if( PrintCheckBox( $"{name}##manip", ref tmp, defaults.HasFlag( flag ) ) && _editMode && tmp != val.HasFlag( flag ) )
-// {
-// list[ manipIdx ] = new MetaManipulation( new EqpManipulation( tmp ? val | flag : val & ~flag, id.Slot, id.SetId ) );
-// ret = true;
-// }
-// }
-// }
-//
-// ImGui.Text( ObjectType.Equipment.ToString() );
-// ImGui.TableNextColumn();
-// ImGui.Text( id.SetId.ToString() );
-// ImGui.TableNextColumn();
-// ImGui.Text( id.Slot.ToString() );
-// return ret;
-// }
-//
-// private bool DrawGmpRow( int manipIdx, IList< MetaManipulation > list )
-// {
-// var ret = false;
-// var id = list[ manipIdx ].Gmp;
-// var val = id.Entry;
-//
-// if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) )
-// {
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup );
-// var defaults = ExpandedGmpFile.GetDefault( id.SetId );
-// var enabled = val.Enabled;
-// var animated = val.Animated;
-// var rotationA = val.RotationA;
-// var rotationB = val.RotationB;
-// var rotationC = val.RotationC;
-// ushort unk = val.UnknownTotal;
-//
-// ret |= PrintCheckBox( "Visor Enabled##manip", ref enabled, defaults.Enabled ) && enabled != val.Enabled;
-// ret |= PrintCheckBox( "Visor Animated##manip", ref animated, defaults.Animated );
-// ret |= DrawInputWithDefault( "Rotation A##manip", ref rotationA, defaults.RotationA, 0x3FF );
-// ret |= DrawInputWithDefault( "Rotation B##manip", ref rotationB, defaults.RotationB, 0x3FF );
-// ret |= DrawInputWithDefault( "Rotation C##manip", ref rotationC, defaults.RotationC, 0x3FF );
-// ret |= DrawInputWithDefault( "Unknown Byte##manip", ref unk, defaults.UnknownTotal, 0xFF );
-//
-// if( ret && _editMode )
-// {
-// list[ manipIdx ] = new MetaManipulation( new GmpManipulation( new GmpEntry
-// {
-// Animated = animated, Enabled = enabled, UnknownTotal = ( byte )unk,
-// RotationA = rotationA, RotationB = rotationB, RotationC = rotationC,
-// }, id.SetId ) );
-// }
-// }
-//
-// ImGui.Text( ObjectType.Equipment.ToString() );
-// ImGui.TableNextColumn();
-// ImGui.Text( id.SetId.ToString() );
-// ImGui.TableNextColumn();
-// ImGui.Text( EquipSlot.Head.ToString() );
-// return ret;
-// }
-//
-// private static (bool, bool) GetEqdpBits( EquipSlot slot, EqdpEntry entry )
-// {
-// return slot switch
-// {
-// EquipSlot.Head => ( entry.HasFlag( EqdpEntry.Head1 ), entry.HasFlag( EqdpEntry.Head2 ) ),
-// EquipSlot.Body => ( entry.HasFlag( EqdpEntry.Body1 ), entry.HasFlag( EqdpEntry.Body2 ) ),
-// EquipSlot.Hands => ( entry.HasFlag( EqdpEntry.Hands1 ), entry.HasFlag( EqdpEntry.Hands2 ) ),
-// EquipSlot.Legs => ( entry.HasFlag( EqdpEntry.Legs1 ), entry.HasFlag( EqdpEntry.Legs2 ) ),
-// EquipSlot.Feet => ( entry.HasFlag( EqdpEntry.Feet1 ), entry.HasFlag( EqdpEntry.Feet2 ) ),
-// EquipSlot.Neck => ( entry.HasFlag( EqdpEntry.Neck1 ), entry.HasFlag( EqdpEntry.Neck2 ) ),
-// EquipSlot.Ears => ( entry.HasFlag( EqdpEntry.Ears1 ), entry.HasFlag( EqdpEntry.Ears2 ) ),
-// EquipSlot.Wrists => ( entry.HasFlag( EqdpEntry.Wrists1 ), entry.HasFlag( EqdpEntry.Wrists2 ) ),
-// EquipSlot.RFinger => ( entry.HasFlag( EqdpEntry.RingR1 ), entry.HasFlag( EqdpEntry.RingR2 ) ),
-// EquipSlot.LFinger => ( entry.HasFlag( EqdpEntry.RingL1 ), entry.HasFlag( EqdpEntry.RingL2 ) ),
-// _ => ( false, false ),
-// };
-// }
-//
-// private static EqdpEntry SetEqdpBits( EquipSlot slot, EqdpEntry value, bool bit1, bool bit2 )
-// {
-// switch( slot )
-// {
-// case EquipSlot.Head:
-// value = bit1 ? value | EqdpEntry.Head1 : value & ~EqdpEntry.Head1;
-// value = bit2 ? value | EqdpEntry.Head2 : value & ~EqdpEntry.Head2;
-// return value;
-// case EquipSlot.Body:
-// value = bit1 ? value | EqdpEntry.Body1 : value & ~EqdpEntry.Body1;
-// value = bit2 ? value | EqdpEntry.Body2 : value & ~EqdpEntry.Body2;
-// return value;
-// case EquipSlot.Hands:
-// value = bit1 ? value | EqdpEntry.Hands1 : value & ~EqdpEntry.Hands1;
-// value = bit2 ? value | EqdpEntry.Hands2 : value & ~EqdpEntry.Hands2;
-// return value;
-// case EquipSlot.Legs:
-// value = bit1 ? value | EqdpEntry.Legs1 : value & ~EqdpEntry.Legs1;
-// value = bit2 ? value | EqdpEntry.Legs2 : value & ~EqdpEntry.Legs2;
-// return value;
-// case EquipSlot.Feet:
-// value = bit1 ? value | EqdpEntry.Feet1 : value & ~EqdpEntry.Feet1;
-// value = bit2 ? value | EqdpEntry.Feet2 : value & ~EqdpEntry.Feet2;
-// return value;
-// case EquipSlot.Neck:
-// value = bit1 ? value | EqdpEntry.Neck1 : value & ~EqdpEntry.Neck1;
-// value = bit2 ? value | EqdpEntry.Neck2 : value & ~EqdpEntry.Neck2;
-// return value;
-// case EquipSlot.Ears:
-// value = bit1 ? value | EqdpEntry.Ears1 : value & ~EqdpEntry.Ears1;
-// value = bit2 ? value | EqdpEntry.Ears2 : value & ~EqdpEntry.Ears2;
-// return value;
-// case EquipSlot.Wrists:
-// value = bit1 ? value | EqdpEntry.Wrists1 : value & ~EqdpEntry.Wrists1;
-// value = bit2 ? value | EqdpEntry.Wrists2 : value & ~EqdpEntry.Wrists2;
-// return value;
-// case EquipSlot.RFinger:
-// value = bit1 ? value | EqdpEntry.RingR1 : value & ~EqdpEntry.RingR1;
-// value = bit2 ? value | EqdpEntry.RingR2 : value & ~EqdpEntry.RingR2;
-// return value;
-// case EquipSlot.LFinger:
-// value = bit1 ? value | EqdpEntry.RingL1 : value & ~EqdpEntry.RingL1;
-// value = bit2 ? value | EqdpEntry.RingL2 : value & ~EqdpEntry.RingL2;
-// return value;
-// }
-//
-// return value;
-// }
-//
-// private bool DrawEqdpRow( int manipIdx, IList< MetaManipulation > list )
-// {
-// var ret = false;
-// var id = list[ manipIdx ].Eqdp;
-// var val = id.Entry;
-//
-// if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) )
-// {
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup );
-// var defaults = ExpandedEqdpFile.GetDefault( id.FileIndex(), id.SetId );
-// var (bit1, bit2) = GetEqdpBits( id.Slot, val );
-// var (defBit1, defBit2) = GetEqdpBits( id.Slot, defaults );
-//
-// ret |= PrintCheckBox( "Bit 1##manip", ref bit1, defBit1 );
-// ret |= PrintCheckBox( "Bit 2##manip", ref bit2, defBit2 );
-//
-// if( ret && _editMode )
-// {
-// list[ manipIdx ] = new MetaManipulation( new EqdpManipulation( SetEqdpBits( id.Slot, val, bit1, bit2 ), id.Slot, id.Gender,
-// id.Race, id.SetId ) );
-// }
-// }
-//
-// ImGui.Text( id.Slot.IsAccessory()
-// ? ObjectType.Accessory.ToString()
-// : ObjectType.Equipment.ToString() );
-// ImGui.TableNextColumn();
-// ImGui.Text( id.SetId.ToString() );
-// ImGui.TableNextColumn();
-// ImGui.Text( id.Slot.ToString() );
-// ImGui.TableNextColumn();
-// ImGui.Text( id.Race.ToString() );
-// ImGui.TableNextColumn();
-// ImGui.Text( id.Gender.ToString() );
-// return ret;
-// }
-//
-// private bool DrawEstRow( int manipIdx, IList< MetaManipulation > list )
-// {
-// var ret = false;
-// var id = list[ manipIdx ].Est;
-// var val = id.Entry;
-//
-// if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) )
-// {
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup );
-// var defaults = EstFile.GetDefault( id.Slot, Names.CombinedRace( id.Gender, id.Race ), id.SetId );
-// if( DrawInputWithDefault( "No Idea what this does!##manip", ref val, defaults, ushort.MaxValue ) && _editMode )
-// {
-// list[ manipIdx ] = new MetaManipulation( new EstManipulation( id.Gender, id.Race, id.Slot, id.SetId, val ) );
-// ret = true;
-// }
-// }
-//
-// ImGui.Text( id.Slot.ToString() );
-// ImGui.TableNextColumn();
-// ImGui.Text( id.SetId.ToString() );
-// ImGui.TableNextColumn();
-// ImGui.TableNextColumn();
-// ImGui.Text( id.Race.ToName() );
-// ImGui.TableNextColumn();
-// ImGui.Text( id.Gender.ToName() );
-//
-// return ret;
-// }
-//
-// private bool DrawImcRow( int manipIdx, IList< MetaManipulation > list )
-// {
-// var ret = false;
-// var id = list[ manipIdx ].Imc;
-// var val = id.Entry;
-//
-// if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) )
-// {
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup );
-// var defaults = new ImcFile( id.GamePath() ).GetEntry( ImcFile.PartIndex( id.EquipSlot ), id.Variant );
-// ushort materialId = val.MaterialId;
-// ushort vfxId = val.VfxId;
-// ushort decalId = val.DecalId;
-// var soundId = ( ushort )val.SoundId;
-// var attributeMask = val.AttributeMask;
-// var materialAnimationId = ( ushort )val.MaterialAnimationId;
-// ret |= DrawInputWithDefault( "Material Id", ref materialId, defaults.MaterialId, byte.MaxValue );
-// ret |= DrawInputWithDefault( "Vfx Id", ref vfxId, defaults.VfxId, byte.MaxValue );
-// ret |= DrawInputWithDefault( "Decal Id", ref decalId, defaults.DecalId, byte.MaxValue );
-// ret |= DrawInputWithDefault( "Sound Id", ref soundId, defaults.SoundId, 0x3F );
-// ret |= DrawInputWithDefault( "Attribute Mask", ref attributeMask, defaults.AttributeMask, 0x3FF );
-// ret |= DrawInputWithDefault( "Material Animation Id", ref materialAnimationId, defaults.MaterialAnimationId,
-// byte.MaxValue );
-//
-// if( ret && _editMode )
-// {
-// var value = new ImcEntry( ( byte )materialId, ( byte )decalId, attributeMask, ( byte )soundId, ( byte )vfxId,
-// ( byte )materialAnimationId );
-// list[ manipIdx ] = new MetaManipulation( new ImcManipulation( id, value ) );
-// }
-// }
-//
-// ImGui.Text( id.ObjectType.ToString() );
-// ImGui.TableNextColumn();
-// ImGui.Text( id.PrimaryId.ToString() );
-// ImGui.TableNextColumn();
-// if( id.ObjectType is ObjectType.Accessory or ObjectType.Equipment )
-// {
-// ImGui.Text( id.ObjectType is ObjectType.Equipment or ObjectType.Accessory
-// ? id.EquipSlot.ToString()
-// : id.BodySlot.ToString() );
-// }
-//
-// ImGui.TableNextColumn();
-// ImGui.TableNextColumn();
-// ImGui.TableNextColumn();
-// if( id.ObjectType != ObjectType.Equipment
-// && id.ObjectType != ObjectType.Accessory )
-// {
-// ImGui.Text( id.SecondaryId.ToString() );
-// }
-//
-// ImGui.TableNextColumn();
-// ImGui.Text( id.Variant.ToString() );
-// return ret;
-// }
-//
-// private bool DrawRspRow( int manipIdx, IList< MetaManipulation > list )
-// {
-// var ret = false;
-// var id = list[ manipIdx ].Rsp;
-// var defaults = CmpFile.GetDefault( id.SubRace, id.Attribute );
-// var val = id.Entry;
-// if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) )
-// {
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup );
-// if( DefaultButton(
-// $"{( _editMode ? "Set to " : "" )}Default: {defaults:F3}##scaleManip", ref val, defaults )
-// && _editMode )
-// {
-// list[ manipIdx ] = new MetaManipulation( new RspManipulation( id.SubRace, id.Attribute, val ) );
-// ret = true;
-// }
-//
-// ImGui.SetNextItemWidth( 50 * ImGuiHelpers.GlobalScale );
-// if( ImGui.InputFloat( "Scale###manip", ref val, 0, 0, "%.3f",
-// _editMode ? ImGuiInputTextFlags.EnterReturnsTrue : ImGuiInputTextFlags.ReadOnly )
-// && val >= 0
-// && val <= 5
-// && _editMode )
-// {
-// list[ manipIdx ] = new MetaManipulation( new RspManipulation( id.SubRace, id.Attribute, val ) );
-// ret = true;
-// }
-// }
-//
-// ImGui.Text( id.Attribute.ToUngenderedString() );
-// ImGui.TableNextColumn();
-// ImGui.TableNextColumn();
-// ImGui.TableNextColumn();
-// ImGui.Text( id.SubRace.ToString() );
-// ImGui.TableNextColumn();
-// ImGui.Text( id.Attribute.ToGender().ToString() );
-// return ret;
-// }
-//
-// private bool DrawManipulationRow( ref int manipIdx, IList< MetaManipulation > list, ref int count )
-// {
-// var type = list[ manipIdx ].ManipulationType;
-//
-// if( _editMode )
-// {
-// ImGui.TableNextColumn();
-// using var font = ImGuiRaii.PushFont( UiBuilder.IconFont );
-// if( ImGui.Button( $"{FontAwesomeIcon.Trash.ToIconString()}##manipDelete{manipIdx}" ) )
-// {
-// list.RemoveAt( manipIdx );
-// ImGui.TableNextRow();
-// --manipIdx;
-// --count;
-// return true;
-// }
-// }
-//
-// ImGui.TableNextColumn();
-// ImGui.Text( type.ToString() );
-// ImGui.TableNextColumn();
-//
-// var changes = false;
-// switch( type )
-// {
-// case MetaManipulation.Type.Eqp:
-// changes = DrawEqpRow( manipIdx, list );
-// ImGui.TableSetColumnIndex( 9 );
-// if( ImGui.Selectable( $"{list[ manipIdx ].Eqp.Entry}##{manipIdx}" ) )
-// {
-// ImGui.OpenPopup( $"##MetaPopup{manipIdx}" );
-// }
-//
-// break;
-// case MetaManipulation.Type.Gmp:
-// changes = DrawGmpRow( manipIdx, list );
-// ImGui.TableSetColumnIndex( 9 );
-// if( ImGui.Selectable( $"{list[ manipIdx ].Gmp.Entry.Value}##{manipIdx}" ) )
-// {
-// ImGui.OpenPopup( $"##MetaPopup{manipIdx}" );
-// }
-//
-// break;
-// case MetaManipulation.Type.Eqdp:
-// changes = DrawEqdpRow( manipIdx, list );
-// ImGui.TableSetColumnIndex( 9 );
-// var (bit1, bit2) = GetEqdpBits( list[ manipIdx ].Eqdp.Slot, list[ manipIdx ].Eqdp.Entry );
-// if( ImGui.Selectable( $"{bit1} {bit2}##{manipIdx}" ) )
-// {
-// ImGui.OpenPopup( $"##MetaPopup{manipIdx}" );
-// }
-//
-// break;
-// case MetaManipulation.Type.Est:
-// changes = DrawEstRow( manipIdx, list );
-// ImGui.TableSetColumnIndex( 9 );
-// if( ImGui.Selectable( $"{list[ manipIdx ].Est.Entry}##{manipIdx}" ) )
-// {
-// ImGui.OpenPopup( $"##MetaPopup{manipIdx}" );
-// }
-//
-// break;
-// case MetaManipulation.Type.Imc:
-// changes = DrawImcRow( manipIdx, list );
-// ImGui.TableSetColumnIndex( 9 );
-// if( ImGui.Selectable( $"{list[ manipIdx ].Imc.Entry.MaterialId}##{manipIdx}" ) )
-// {
-// ImGui.OpenPopup( $"##MetaPopup{manipIdx}" );
-// }
-//
-// break;
-// case MetaManipulation.Type.Rsp:
-// changes = DrawRspRow( manipIdx, list );
-// ImGui.TableSetColumnIndex( 9 );
-// if( ImGui.Selectable( $"{list[ manipIdx ].Rsp.Entry}##{manipIdx}" ) )
-// {
-// ImGui.OpenPopup( $"##MetaPopup{manipIdx}" );
-// }
-//
-// break;
-// }
-//
-//
-// ImGui.TableNextRow();
-// return changes;
-// }
-//
-//
-// private MetaManipulation.Type DrawNewTypeSelection()
-// {
-// ImGui.RadioButton( "IMC##newManipType", ref _newManipTypeIdx, 1 );
-// ImGui.SameLine();
-// ImGui.RadioButton( "EQDP##newManipType", ref _newManipTypeIdx, 2 );
-// ImGui.SameLine();
-// ImGui.RadioButton( "EQP##newManipType", ref _newManipTypeIdx, 3 );
-// ImGui.SameLine();
-// ImGui.RadioButton( "EST##newManipType", ref _newManipTypeIdx, 4 );
-// ImGui.SameLine();
-// ImGui.RadioButton( "GMP##newManipType", ref _newManipTypeIdx, 5 );
-// ImGui.SameLine();
-// ImGui.RadioButton( "RSP##newManipType", ref _newManipTypeIdx, 6 );
-// return ( MetaManipulation.Type )_newManipTypeIdx;
-// }
-//
-// private bool DrawNewManipulationPopup( string popupName, IList< MetaManipulation > list, ref int count )
-// {
-// var change = false;
-// if( !ImGui.BeginPopup( popupName ) )
-// {
-// return change;
-// }
-//
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup );
-// var manipType = DrawNewTypeSelection();
-// MetaManipulation? newManip = null;
-// switch( manipType )
-// {
-// case MetaManipulation.Type.Imc:
-// {
-// RestrictedInputInt( "Set Id##newManipImc", ref _newManipSetId, 0, ushort.MaxValue );
-// RestrictedInputInt( "Variant##newManipImc", ref _newManipVariant, 0, byte.MaxValue );
-// CustomCombo( "Object Type", ImcObjectType, out var objectType, ref _newManipObjectType );
-// ImcManipulation imc = new();
-// switch( objectType )
-// {
-// case ObjectType.Equipment:
-// CustomCombo( "Equipment Slot", EqdpEquipSlots, out var equipSlot, ref _newManipEquipSlot );
-// imc = new ImcManipulation( equipSlot, _newManipVariant, _newManipSetId, new ImcEntry() );
-// break;
-// case ObjectType.DemiHuman:
-// case ObjectType.Weapon:
-// case ObjectType.Monster:
-// RestrictedInputInt( "Secondary Id##newManipImc", ref _newManipSecondaryId, 0, ushort.MaxValue );
-// CustomCombo( "Body Slot", ImcBodySlots, out var bodySlot, ref _newManipBodySlot );
-// imc = new ImcManipulation( objectType, bodySlot, _newManipSetId, _newManipSecondaryId,
-// _newManipVariant, new ImcEntry() );
-// break;
-// }
-//
-// newManip = new MetaManipulation( new ImcManipulation( imc.ObjectType, imc.BodySlot, imc.PrimaryId, imc.SecondaryId,
-// imc.Variant, imc.EquipSlot, ImcFile.GetDefault( imc.GamePath(), imc.EquipSlot, imc.Variant ) ) );
-//
-// break;
-// }
-// case MetaManipulation.Type.Eqdp:
-// {
-// RestrictedInputInt( "Set Id##newManipEqdp", ref _newManipSetId, 0, ushort.MaxValue );
-// CustomCombo( "Equipment Slot", EqdpEquipSlots, out var equipSlot, ref _newManipEquipSlot );
-// CustomCombo( "Race", Races, out var race, ref _newManipRace );
-// CustomCombo( "Gender", Genders, out var gender, ref _newManipGender );
-// var eqdp = new EqdpManipulation( new EqdpEntry(), equipSlot, gender, race, _newManipSetId );
-// newManip = new MetaManipulation( new EqdpManipulation( ExpandedEqdpFile.GetDefault( eqdp.FileIndex(), eqdp.SetId ),
-// equipSlot, gender, race, _newManipSetId ) );
-// break;
-// }
-// case MetaManipulation.Type.Eqp:
-// {
-// RestrictedInputInt( "Set Id##newManipEqp", ref _newManipSetId, 0, ushort.MaxValue );
-// CustomCombo( "Equipment Slot", EqpEquipSlots, out var equipSlot, ref _newManipEquipSlot );
-// newManip = new MetaManipulation( new EqpManipulation( ExpandedEqpFile.GetDefault( _newManipSetId ) & Eqp.Mask( equipSlot ),
-// equipSlot, _newManipSetId ) );
-// break;
-// }
-// case MetaManipulation.Type.Est:
-// {
-// RestrictedInputInt( "Set Id##newManipEst", ref _newManipSetId, 0, ushort.MaxValue );
-// CustomCombo( "Est Type", EstTypes, out var estType, ref _newManipObjectType );
-// CustomCombo( "Race", Races, out var race, ref _newManipRace );
-// CustomCombo( "Gender", Genders, out var gender, ref _newManipGender );
-// newManip = new MetaManipulation( new EstManipulation( gender, race, estType, _newManipSetId,
-// EstFile.GetDefault( estType, Names.CombinedRace( gender, race ), _newManipSetId ) ) );
-// break;
-// }
-// case MetaManipulation.Type.Gmp:
-// RestrictedInputInt( "Set Id##newManipGmp", ref _newManipSetId, 0, ushort.MaxValue );
-// newManip = new MetaManipulation( new GmpManipulation( ExpandedGmpFile.GetDefault( _newManipSetId ), _newManipSetId ) );
-// break;
-// case MetaManipulation.Type.Rsp:
-// CustomCombo( "Subrace", Subraces, out var subRace, ref _newManipSubrace );
-// CustomCombo( "Attribute", RspAttributes, out var rspAttribute, ref _newManipAttribute );
-// newManip = new MetaManipulation( new RspManipulation( subRace, rspAttribute,
-// CmpFile.GetDefault( subRace, rspAttribute ) ) );
-// break;
-// }
-//
-// if( ImGui.Button( "Create Manipulation##newManip", Vector2.UnitX * -1 )
-// && newManip != null
-// && list.All( m => !m.Equals( newManip ) ) )
-// {
-// list.Add( newManip.Value );
-// change = true;
-// ++count;
-// ImGui.CloseCurrentPopup();
-// }
-//
-// return change;
-// }
-//
-// private bool DrawMetaManipulationsTable( string label, IList< MetaManipulation > list, ref int count )
-// {
-// var numRows = _editMode ? 11 : 10;
-// var changes = false;
-//
-//
-// if( list.Count > 0
-// && ImGui.BeginTable( label, numRows,
-// ImGuiTableFlags.BordersInner | ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit ) )
-// {
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTable );
-// if( _editMode )
-// {
-// ImGui.TableNextColumn();
-// }
-//
-// ImGui.TableNextColumn();
-// ImGui.TableHeader( $"Type##{label}" );
-// ImGui.TableNextColumn();
-// ImGui.TableHeader( $"Object Type##{label}" );
-// ImGui.TableNextColumn();
-// ImGui.TableHeader( $"Set##{label}" );
-// ImGui.TableNextColumn();
-// ImGui.TableHeader( $"Slot##{label}" );
-// ImGui.TableNextColumn();
-// ImGui.TableHeader( $"Race##{label}" );
-// ImGui.TableNextColumn();
-// ImGui.TableHeader( $"Gender##{label}" );
-// ImGui.TableNextColumn();
-// ImGui.TableHeader( $"Secondary ID##{label}" );
-// ImGui.TableNextColumn();
-// ImGui.TableHeader( $"Variant##{label}" );
-// ImGui.TableNextColumn();
-// ImGui.TableNextColumn();
-// ImGui.TableHeader( $"Value##{label}" );
-// ImGui.TableNextRow();
-//
-// for( var i = 0; i < list.Count; ++i )
-// {
-// changes |= DrawManipulationRow( ref i, list, ref count );
-// }
-// }
-//
-// var popupName = $"##newManip{label}";
-// if( _editMode )
-// {
-// changes |= DrawNewManipulationPopup( $"##newManip{label}", list, ref count );
-// if( ImGui.Button( $"Add New Manipulation##{label}", Vector2.UnitX * -1 ) )
-// {
-// ImGui.OpenPopup( popupName );
-// }
-//
-// return changes;
-// }
-//
-// return false;
-// }
-// }
-//}
\ No newline at end of file
diff --git a/Penumbra/UI/ConfigWindow.ModsTab.Import.cs b/Penumbra/UI/ConfigWindow.ModsTab.Import.cs
deleted file mode 100644
index 917408fe..00000000
--- a/Penumbra/UI/ConfigWindow.ModsTab.Import.cs
+++ /dev/null
@@ -1,177 +0,0 @@
-namespace Penumbra.UI;
-
-//public partial class ConfigWindow
-//{
-// private class TabImport
-// {
-// private const string LabelTab = "Import Mods";
-// private const string LabelImportButton = "Import TexTools Modpacks";
-// private const string LabelFileDialog = "Pick one or more modpacks.";
-// private const string LabelFileImportRunning = "Import in progress...";
-// private const string FileTypeFilter = "TexTools TTMP Modpack (*.ttmp2)|*.ttmp*|All files (*.*)|*.*";
-// private const string TooltipModpack1 = "Writing modpack to disk before extracting...";
-//
-// private const uint ColorRed = 0xFF0000C8;
-// private const uint ColorYellow = 0xFF00C8C8;
-//
-// private static readonly Vector2 ImportBarSize = new(-1, 0);
-//
-// private bool _isImportRunning;
-// private string _errorMessage = string.Empty;
-// private TexToolsImport? _texToolsImport;
-// private readonly SettingsInterface _base;
-//
-// public readonly HashSet< string > NewMods = new();
-//
-// public TabImport( SettingsInterface ui )
-// => _base = ui;
-//
-// public bool IsImporting()
-// => _isImportRunning;
-//
-// private void RunImportTask()
-// {
-// _isImportRunning = true;
-// Task.Run( async () =>
-// {
-// try
-// {
-// var picker = new OpenFileDialog
-// {
-// Multiselect = true,
-// Filter = FileTypeFilter,
-// CheckFileExists = true,
-// Title = LabelFileDialog,
-// };
-//
-// var result = await picker.ShowDialogAsync();
-//
-// if( result == DialogResult.OK )
-// {
-// _errorMessage = string.Empty;
-//
-// foreach( var fileName in picker.FileNames )
-// {
-// PluginLog.Information( $"-> {fileName} START" );
-//
-// try
-// {
-// _texToolsImport = new TexToolsImport( Penumbra.ModManager.BasePath );
-// var dir = _texToolsImport.ImportModPack( new FileInfo( fileName ) );
-// if( dir.Name.Any() )
-// {
-// NewMods.Add( dir.Name );
-// }
-//
-// PluginLog.Information( $"-> {fileName} OK!" );
-// }
-// catch( Exception ex )
-// {
-// PluginLog.LogError( ex, "Failed to import modpack at {0}", fileName );
-// _errorMessage = ex.Message;
-// }
-// }
-//
-// var directory = _texToolsImport?.ExtractedDirectory;
-// _texToolsImport = null;
-// _base.ReloadMods();
-// if( directory != null )
-// {
-// _base._menu.InstalledTab.Selector.SelectModOnUpdate( directory.Name );
-// }
-// }
-// }
-// catch( Exception e )
-// {
-// PluginLog.Error( $"Error opening file picker dialogue:\n{e}" );
-// }
-//
-// _isImportRunning = false;
-// } );
-// }
-//
-// private void DrawImportButton()
-// {
-// if( !Penumbra.ModManager.Valid )
-// {
-// using var style = ImGuiRaii.PushStyle( ImGuiStyleVar.Alpha, 0.5f );
-// ImGui.Button( LabelImportButton );
-// style.Pop();
-//
-// using var color = ImGuiRaii.PushColor( ImGuiCol.Text, ColorRed );
-// ImGui.Text( "Can not import since the mod directory path is not valid." );
-// ImGui.Dummy( Vector2.UnitY * ImGui.GetTextLineHeightWithSpacing() );
-// color.Pop();
-//
-// ImGui.Text( "Please set the mod directory in the settings tab." );
-// ImGui.Text( "This folder should preferably be close to the root directory of your (preferably SSD) drive, for example" );
-// color.Push( ImGuiCol.Text, ColorYellow );
-// ImGui.Text( " D:\\ffxivmods" );
-// color.Pop();
-// ImGui.Text( "You can return to this tab once you've done that." );
-// }
-// else if( ImGui.Button( LabelImportButton ) )
-// {
-// RunImportTask();
-// }
-// }
-//
-// private void DrawImportProgress()
-// {
-// ImGui.Button( LabelFileImportRunning );
-//
-// if( _texToolsImport == null )
-// {
-// return;
-// }
-//
-// switch( _texToolsImport.State )
-// {
-// case ImporterState.None: break;
-// case ImporterState.WritingPackToDisk:
-// ImGui.Text( TooltipModpack1 );
-// break;
-// case ImporterState.ExtractingModFiles:
-// {
-// var str =
-// $"{_texToolsImport.CurrentModPack} - {_texToolsImport.CurrentProgress} of {_texToolsImport.TotalProgress} files";
-//
-// ImGui.ProgressBar( _texToolsImport.Progress, ImportBarSize, str );
-// break;
-// }
-// case ImporterState.Done: break;
-// default: throw new ArgumentOutOfRangeException();
-// }
-// }
-//
-// private void DrawFailedImportMessage()
-// {
-// using var color = ImGuiRaii.PushColor( ImGuiCol.Text, ColorRed );
-// ImGui.Text( $"One or more of your modpacks failed to import:\n\t\t{_errorMessage}" );
-// }
-//
-// public void Draw()
-// {
-// if( !ImGui.BeginTabItem( LabelTab ) )
-// {
-// return;
-// }
-//
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
-//
-// if( !_isImportRunning )
-// {
-// DrawImportButton();
-// }
-// else
-// {
-// DrawImportProgress();
-// }
-//
-// if( _errorMessage.Any() )
-// {
-// DrawFailedImportMessage();
-// }
-// }
-// }
-//}
\ No newline at end of file
diff --git a/Penumbra/UI/ConfigWindow.ModsTab.Panel.cs b/Penumbra/UI/ConfigWindow.ModsTab.Panel.cs
deleted file mode 100644
index 63434602..00000000
--- a/Penumbra/UI/ConfigWindow.ModsTab.Panel.cs
+++ /dev/null
@@ -1,613 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Numerics;
-using Dalamud.Interface;
-using Dalamud.Logging;
-using ImGuiNET;
-using Penumbra.Mods;
-using Penumbra.Util;
-
-namespace Penumbra.UI;
-
-public partial class SettingsInterface
-{
- //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 LabelOverWriteDir = "OverwriteDir";
- // 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 ButtonNormalize = "Normalize";
- // 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\".\nExperimental - use at own risk!";
- //
- // private const string TooltipNormalize =
- // "Try to reduce unnecessary options or subdirectories to default options if possible.\nExperimental - use at own risk!";
- //
- // private const float HeaderLineDistance = 10f;
- // private static readonly Vector4 GreyColor = new(1f, 1f, 1f, 0.66f);
- //
- // private readonly SettingsInterface _base;
- // private readonly Selector _selector;
- // private readonly HashSet< string > _newMods;
- // public readonly PluginDetails Details;
- //
- // private bool _editMode;
- // private string _currentWebsite;
- // private bool _validWebsite;
- //
- // private string _fromMaterial = string.Empty;
- // private string _toMaterial = string.Empty;
- //
- // public ModPanel( SettingsInterface ui, Selector s, HashSet< string > newMods )
- // {
- // _base = ui;
- // _selector = s;
- // _newMods = newMods;
- // Details = new PluginDetails( _base, _selector );
- // _currentWebsite = Meta?.Website ?? "";
- // }
- //
- // private Mods.FullMod? Mod
- // => _selector.Mod;
- //
- // private ModMeta? Meta
- // => Mod?.Data.Meta;
- //
- // private void DrawName()
- // {
- // var name = Meta!.Name.Text;
- // var modManager = Penumbra.ModManager;
- // if( ImGuiCustom.InputOrText( _editMode, LabelEditName, ref name, 64 ) && modManager.RenameMod( name, Mod!.Data ) )
- // {
- // _selector.SelectModOnUpdate( Mod.Data.BasePath.Name );
- // if( !modManager.TemporaryModSortOrder.ContainsKey( Mod!.Data.BasePath.Name ) )
- // {
- // Mod.Data.Rename( name );
- // }
- // }
- // }
- //
- // private void DrawVersion()
- // {
- // if( _editMode )
- // {
- // ImGui.BeginGroup();
- // using var raii = ImGuiRaii.DeferredEnd( ImGui.EndGroup );
- // ImGui.Text( "(Version " );
- //
- // using var style = ImGuiRaii.PushStyle( ImGuiStyleVar.ItemSpacing, ZeroVector );
- // ImGui.SameLine();
- // var version = Meta!.Version;
- // if( ImGuiCustom.ResizingTextInput( LabelEditVersion, ref version, 16 )
- // && version != Meta.Version )
- // {
- // Meta.Version = version;
- // _selector.SaveCurrentMod();
- // }
- //
- // ImGui.SameLine();
- // ImGui.Text( ")" );
- // }
- // else if( Meta!.Version.Length > 0 )
- // {
- // ImGui.Text( $"(Version {Meta.Version})" );
- // }
- // }
- //
- // private void DrawAuthor()
- // {
- // ImGui.BeginGroup();
- // ImGui.TextColored( GreyColor, "by" );
- //
- // ImGui.SameLine();
- // var author = Meta!.Author.Text;
- // if( ImGuiCustom.InputOrText( _editMode, LabelEditAuthor, ref author, 64 )
- // && author != Meta.Author )
- // {
- // Meta.Author = author;
- // _selector.SaveCurrentMod();
- // _selector.Cache.TriggerFilterReset();
- // }
- //
- // ImGui.EndGroup();
- // }
- //
- // private void DrawWebsite()
- // {
- // ImGui.BeginGroup();
- // using var raii = ImGuiRaii.DeferredEnd( ImGui.EndGroup );
- // if( _editMode )
- // {
- // ImGui.TextColored( GreyColor, "from" );
- // ImGui.SameLine();
- // var website = Meta!.Website;
- // if( ImGuiCustom.ResizingTextInput( LabelEditWebsite, ref website, 512 )
- // && website != Meta.Website )
- // {
- // Meta.Website = website;
- // _selector.SaveCurrentMod();
- // }
- // }
- // else if( Meta!.Website.Length > 0 )
- // {
- // if( _currentWebsite != Meta.Website )
- // {
- // _currentWebsite = Meta.Website;
- // _validWebsite = Uri.TryCreate( Meta.Website, UriKind.Absolute, out var uriResult )
- // && ( uriResult.Scheme == Uri.UriSchemeHttps || uriResult.Scheme == Uri.UriSchemeHttp );
- // }
- //
- // if( _validWebsite )
- // {
- // if( ImGui.SmallButton( ButtonOpenWebsite ) )
- // {
- // try
- // {
- // var process = new ProcessStartInfo( Meta.Website )
- // {
- // UseShellExecute = true,
- // };
- // Process.Start( process );
- // }
- // catch( System.ComponentModel.Win32Exception )
- // {
- // // Do nothing.
- // }
- // }
- //
- // ImGuiCustom.HoverTooltip( Meta.Website );
- // }
- // else
- // {
- // ImGui.TextColored( GreyColor, "from" );
- // ImGui.SameLine();
- // ImGui.Text( Meta.Website );
- // }
- // }
- // }
- //
- // private void DrawHeaderLine()
- // {
- // DrawName();
- // ImGui.SameLine();
- // DrawVersion();
- // ImGui.SameLine();
- // DrawAuthor();
- // ImGui.SameLine();
- // DrawWebsite();
- // }
- //
- // private void DrawPriority()
- // {
- // var priority = Mod!.Settings.Priority;
- // ImGui.SetNextItemWidth( 50 * ImGuiHelpers.GlobalScale );
- // if( ImGui.InputInt( "Priority", ref priority, 0 ) && priority != Mod!.Settings.Priority )
- // {
- // Penumbra.CollectionManager.Current.SetModPriority( Mod.Data.Index, priority );
- // _selector.Cache.TriggerFilterReset();
- // }
- //
- // ImGuiCustom.HoverTooltip(
- // "Higher priority mods take precedence over other mods in the case of file conflicts.\n"
- // + "In case of identical priority, the alphabetically first mod takes precedence." );
- // }
- //
- // private void DrawEnabledMark()
- // {
- // var enabled = Mod!.Settings.Enabled;
- // if( ImGui.Checkbox( LabelModEnabled, ref enabled ) )
- // {
- // Penumbra.CollectionManager.Current.SetModState( Mod.Data.Index, enabled );
- // if( enabled )
- // {
- // _newMods.Remove( Mod.Data.BasePath.Name );
- // }
- // _selector.Cache.TriggerFilterReset();
- // }
- // }
- //
- // public static bool DrawSortOrder( Mods.Mod mod, Mods.Mod.Manager manager, Selector selector )
- // {
- // var currentSortOrder = mod.Order.FullPath;
- // ImGui.SetNextItemWidth( 300 * ImGuiHelpers.GlobalScale );
- // if( ImGui.InputText( "Sort Order", ref currentSortOrder, 256, ImGuiInputTextFlags.EnterReturnsTrue ) )
- // {
- // manager.ChangeSortOrder( mod, currentSortOrder );
- // selector.SelectModOnUpdate( mod.BasePath.Name );
- // return true;
- // }
- //
- // return false;
- // }
- //
- // private void DrawEditableMark()
- // {
- // ImGui.Checkbox( LabelEditingEnabled, ref _editMode );
- // }
- //
- // private void DrawOpenModFolderButton()
- // {
- // Mod!.Data.BasePath.Refresh();
- // if( ImGui.Button( ButtonOpenModFolder ) && Mod.Data.BasePath.Exists )
- // {
- // Process.Start( new ProcessStartInfo( Mod!.Data.BasePath.FullName ) { UseShellExecute = true } );
- // }
- //
- // ImGuiCustom.HoverTooltip( TooltipOpenModFolder );
- // }
- //
- // private string _newName = "";
- // private bool _keyboardFocus = true;
- //
- // private void RenameModFolder( string newName )
- // {
- // _newName = newName.ReplaceBadXivSymbols();
- // if( _newName.Length == 0 )
- // {
- // PluginLog.Debug( "New Directory name {NewName} was empty after removing invalid symbols.", newName );
- // ImGui.CloseCurrentPopup();
- // }
- // else if( !string.Equals( _newName, Mod!.Data.BasePath.Name, StringComparison.InvariantCultureIgnoreCase ) )
- // {
- // var dir = Mod!.Data.BasePath;
- // DirectoryInfo newDir = new(Path.Combine( dir.Parent!.FullName, _newName ));
- //
- // if( newDir.Exists )
- // {
- // ImGui.OpenPopup( LabelOverWriteDir );
- // }
- // else if( Penumbra.ModManager.RenameModFolder( Mod.Data, newDir ) )
- // {
- // _selector.ReloadCurrentMod();
- // ImGui.CloseCurrentPopup();
- // }
- // }
- // else if( !string.Equals( _newName, Mod!.Data.BasePath.Name, StringComparison.InvariantCulture ) )
- // {
- // var dir = Mod!.Data.BasePath;
- // DirectoryInfo newDir = new(Path.Combine( dir.Parent!.FullName, _newName ));
- // var sourceUri = new Uri( dir.FullName );
- // var targetUri = new Uri( newDir.FullName );
- // if( sourceUri.Equals( targetUri ) )
- // {
- // var tmpFolder = new DirectoryInfo( TempFile.TempFileName( dir.Parent! ).FullName );
- // if( Penumbra.ModManager.RenameModFolder( Mod.Data, tmpFolder ) )
- // {
- // if( !Penumbra.ModManager.RenameModFolder( Mod.Data, newDir ) )
- // {
- // PluginLog.Error( "Could not recapitalize folder after renaming, reverting rename." );
- // Penumbra.ModManager.RenameModFolder( Mod.Data, dir );
- // }
- //
- // _selector.ReloadCurrentMod();
- // }
- //
- // ImGui.CloseCurrentPopup();
- // }
- // else
- // {
- // ImGui.OpenPopup( LabelOverWriteDir );
- // }
- // }
- // }
- //
- // private static bool MergeFolderInto( DirectoryInfo source, DirectoryInfo target )
- // {
- // try
- // {
- // foreach( var file in source.EnumerateFiles( "*", SearchOption.AllDirectories ) )
- // {
- // var targetFile = new FileInfo( Path.Combine( target.FullName, file.FullName.Substring( source.FullName.Length + 1 ) ) );
- // if( targetFile.Exists )
- // {
- // targetFile.Delete();
- // }
- //
- // targetFile.Directory?.Create();
- // file.MoveTo( targetFile.FullName );
- // }
- //
- // source.Delete( true );
- // return true;
- // }
- // catch( Exception e )
- // {
- // PluginLog.Error( $"Could not merge directory {source.FullName} into {target.FullName}:\n{e}" );
- // }
- //
- // return false;
- // }
- //
- // private bool OverwriteDirPopup()
- // {
- // var closeParent = false;
- // var _ = true;
- // if( !ImGui.BeginPopupModal( LabelOverWriteDir, ref _, ImGuiWindowFlags.AlwaysAutoResize ) )
- // {
- // return closeParent;
- // }
- //
- // using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup );
- //
- // var dir = Mod!.Data.BasePath;
- // 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 = ImGuiHelpers.ScaledVector2( 120, 0 );
- // if( ImGui.Button( "Yes", buttonSize ) && MergeFolderInto( dir, newDir ) )
- // {
- // Penumbra.ModManager.RenameModFolder( Mod.Data, newDir, false );
- //
- // _selector.SelectModOnUpdate( _newName );
- //
- // closeParent = true;
- // ImGui.CloseCurrentPopup();
- // }
- //
- // ImGui.SameLine();
- //
- // if( ImGui.Button( "Cancel", buttonSize ) )
- // {
- // _keyboardFocus = true;
- // ImGui.CloseCurrentPopup();
- // }
- //
- // return closeParent;
- // }
- //
- // private void DrawRenameModFolderPopup()
- // {
- // 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 ) )
- // {
- // return;
- // }
- //
- // using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup );
- //
- // if( ImGui.IsKeyPressed( ImGui.GetKeyIndex( ImGuiKey.Escape ) ) )
- // {
- // ImGui.CloseCurrentPopup();
- // }
- //
- // var newName = Mod!.Data.BasePath.Name;
- //
- // if( _keyboardFocus )
- // {
- // ImGui.SetKeyboardFocusHere();
- // _keyboardFocus = false;
- // }
- //
- // if( ImGui.InputText( "New Folder Name##RenameFolderInput", ref newName, 64, ImGuiInputTextFlags.EnterReturnsTrue ) )
- // {
- // RenameModFolder( newName );
- // }
- //
- // ImGui.TextColored( GreyColor,
- // "Please restrict yourself to ascii symbols that are valid in a windows path,\nother symbols will be replaced by underscores." );
- //
- // ImGui.SetNextWindowPos( ImGui.GetMainViewport().GetCenter(), ImGuiCond.Appearing, Vector2.One / 2 );
- //
- //
- // if( OverwriteDirPopup() )
- // {
- // ImGui.CloseCurrentPopup();
- // }
- // }
- //
- // private void DrawRenameModFolderButton()
- // {
- // DrawRenameModFolderPopup();
- // if( ImGui.Button( ButtonRenameModFolder ) )
- // {
- // ImGui.OpenPopup( PopupRenameFolder );
- // }
- //
- // ImGuiCustom.HoverTooltip( TooltipRenameModFolder );
- // }
- //
- // private void DrawEditJsonButton()
- // {
- // if( ImGui.Button( ButtonEditJson ) )
- // {
- // _selector.SaveCurrentMod();
- // Process.Start( new ProcessStartInfo( Mod!.Data.MetaFile.FullName ) { UseShellExecute = true } );
- // }
- //
- // ImGuiCustom.HoverTooltip( TooltipEditJson );
- // }
- //
- // private void DrawReloadJsonButton()
- // {
- // if( ImGui.Button( ButtonReloadJson ) )
- // {
- // _selector.ReloadCurrentMod( true, false );
- // }
- //
- // ImGuiCustom.HoverTooltip( TooltipReloadJson );
- // }
- //
- // private void DrawResetMetaButton()
- // {
- // if( ImGui.Button( "Recompute Metadata" ) )
- // {
- // _selector.ReloadCurrentMod( true, true, true );
- // }
- //
- // ImGuiCustom.HoverTooltip(
- // "Force a recomputation of the metadata_manipulations.json file from all .meta files in the folder.\n"
- // + "Also reloads the mod.\n"
- // + "Be aware that this removes all manually added metadata changes." );
- // }
- //
- // private void DrawDeduplicateButton()
- // {
- // if( ImGui.Button( ButtonDeduplicate ) )
- // {
- // ModCleanup.Deduplicate( Mod!.Data.BasePath, Meta! );
- // _selector.SaveCurrentMod();
- // _selector.ReloadCurrentMod( true, true, true );
- // }
- //
- // ImGuiCustom.HoverTooltip( TooltipDeduplicate );
- // }
- //
- // private void DrawNormalizeButton()
- // {
- // if( ImGui.Button( ButtonNormalize ) )
- // {
- // ModCleanup.Normalize( Mod!.Data.BasePath, Meta! );
- // _selector.SaveCurrentMod();
- // _selector.ReloadCurrentMod( true, true, true );
- // }
- //
- // ImGuiCustom.HoverTooltip( TooltipNormalize );
- // }
- //
- // private void DrawAutoGenerateGroupsButton()
- // {
- // if( ImGui.Button( "Auto-Generate Groups" ) )
- // {
- // ModCleanup.AutoGenerateGroups( Mod!.Data.BasePath, Meta! );
- // _selector.SaveCurrentMod();
- // _selector.ReloadCurrentMod( true, true );
- // }
- //
- // ImGuiCustom.HoverTooltip( "Automatically generate single-select groups from all folders (clears existing groups):\n"
- // + "First subdirectory: Option Group\n"
- // + "Second subdirectory: Option Name\n"
- // + "Afterwards: Relative file paths.\n"
- // + "Experimental - Use at own risk!" );
- // }
- //
- // private void DrawSplitButton()
- // {
- // if( ImGui.Button( "Split Mod" ) )
- // {
- // ModCleanup.SplitMod( Mod!.Data );
- // }
- //
- // ImGuiCustom.HoverTooltip(
- // "Split off all options of a mod into single mods that are placed in a collective folder.\n"
- // + "Does not remove or change the mod itself, just create (potentially inefficient) copies.\n"
- // + "Experimental - Use at own risk!" );
- // }
- //
- // private void DrawMaterialChangeRow()
- // {
- // ImGui.SetNextItemWidth( 150 * ImGuiHelpers.GlobalScale );
- // ImGui.InputTextWithHint( "##fromMaterial", "From Material Suffix...", ref _fromMaterial, 16 );
- // ImGui.SameLine();
- // using var font = ImGuiRaii.PushFont( UiBuilder.IconFont );
- // ImGui.Text( FontAwesomeIcon.LongArrowAltRight.ToIconString() );
- // font.Pop();
- // ImGui.SameLine();
- // ImGui.SetNextItemWidth( 150 * ImGuiHelpers.GlobalScale );
- // ImGui.InputTextWithHint( "##toMaterial", "To Material Suffix...", ref _toMaterial, 16 );
- // ImGui.SameLine();
- // var validStrings = ModelChanger.ValidStrings( _fromMaterial, _toMaterial );
- // using var alpha = ImGuiRaii.PushStyle( ImGuiStyleVar.Alpha, 0.5f, !validStrings );
- // if( ImGui.Button( "Convert" ) && validStrings )
- // {
- // ModelChanger.ChangeModMaterials( Mod!.Data, _fromMaterial, _toMaterial );
- // }
- //
- // alpha.Pop();
- //
- // ImGuiCustom.HoverTooltip(
- // "Change the skin material of all models in this mod reference "
- // + "from the suffix given in the first text input to "
- // + "the suffix given in the second input.\n"
- // + "Enter only the suffix, e.g. 'd' or 'a' or 'bibo', not the whole path.\n"
- // + "This overwrites .mdl files, use at your own risk!" );
- // }
- //
- // private void DrawEditLine()
- // {
- // DrawOpenModFolderButton();
- // ImGui.SameLine();
- // DrawRenameModFolderButton();
- // ImGui.SameLine();
- // DrawEditJsonButton();
- // ImGui.SameLine();
- // DrawReloadJsonButton();
- //
- // DrawResetMetaButton();
- // ImGui.SameLine();
- // DrawDeduplicateButton();
- // ImGui.SameLine();
- // DrawNormalizeButton();
- // ImGui.SameLine();
- // DrawAutoGenerateGroupsButton();
- // ImGui.SameLine();
- // DrawSplitButton();
- //
- // DrawMaterialChangeRow();
- //
- // DrawSortOrder( Mod!.Data, Penumbra.ModManager, _selector );
- // }
- //
- // public void Draw()
- // {
- // try
- // {
- // using var raii = ImGuiRaii.DeferredEnd( ImGui.EndChild );
- // var ret = ImGui.BeginChild( LabelModPanel, AutoFillSize, true );
- //
- // if( !ret || Mod == null )
- // {
- // return;
- // }
- //
- // DrawHeaderLine();
- //
- // // Next line with fixed distance.
- // ImGuiCustom.VerticalDistance( HeaderLineDistance );
- //
- // DrawEnabledMark();
- // ImGui.SameLine();
- // DrawPriority();
- // if( Penumbra.Config.ShowAdvanced )
- // {
- // ImGui.SameLine();
- // DrawEditableMark();
- // }
- //
- // // Next line, if editable.
- // if( _editMode )
- // {
- // DrawEditLine();
- // }
- //
- // Details.Draw( _editMode );
- // }
- // catch( Exception ex )
- // {
- // PluginLog.LogError( ex, "Oh no" );
- // }
- // }
- //}
-}
\ No newline at end of file
diff --git a/Penumbra/UI/ConfigWindow.ModsTab.Selector.cs b/Penumbra/UI/ConfigWindow.ModsTab.Selector.cs
deleted file mode 100644
index 3190decb..00000000
--- a/Penumbra/UI/ConfigWindow.ModsTab.Selector.cs
+++ /dev/null
@@ -1,797 +0,0 @@
-//using System;
-//using System.Collections.Generic;
-//using System.IO;
-//using System.Linq;
-//using System.Numerics;
-//using System.Runtime.InteropServices;
-//using System.Windows.Forms.VisualStyles;
-//using Dalamud.Interface;
-//using Dalamud.Logging;
-//using ImGuiNET;
-//using Penumbra.Collections;
-//using Penumbra.Importer;
-//using Penumbra.Mods;
-//using Penumbra.UI.Classes;
-//using Penumbra.UI.Custom;
-//using Penumbra.Util;
-//
-//namespace Penumbra.UI;
-//
-//public partial class SettingsInterface
-//{
-// // Constants
-// private partial class Selector
-// {
-// private const string LabelSelectorList = "##availableModList";
-// private const string LabelModFilter = "##ModFilter";
-// private const string LabelAddModPopup = "AddModPopup";
-// private const string LabelModHelpPopup = "Help##Selector";
-//
-// private const string TooltipModFilter =
-// "Filter mods for those containing the given substring.\nEnter c:[string] to filter for mods changing specific items.\nEnter a:[string] to filter for mods by specific authors.";
-//
-// 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 static readonly Vector2 SelectorButtonSizes = new(100, 0);
-// private static readonly Vector2 HelpButtonSizes = new(40, 0);
-//
-// private static readonly Vector4 DeleteModNameColor = new(0.7f, 0.1f, 0.1f, 1);
-// }
-//
-// // Buttons
-// private partial class Selector
-// {
-// // === Delete ===
-// private int? _deleteIndex;
-//
-// private void DrawModTrashButton()
-// {
-// using var raii = ImGuiRaii.PushFont( UiBuilder.IconFont );
-//
-// if( ImGui.Button( FontAwesomeIcon.Trash.ToIconString(), SelectorButtonSizes * _selectorScalingFactor ) && _index >= 0 )
-// {
-// _deleteIndex = _index;
-// }
-//
-// raii.Pop();
-//
-// ImGuiCustom.HoverTooltip( TooltipDelete );
-// }
-//
-// private void DrawDeleteModal()
-// {
-// if( _deleteIndex == null )
-// {
-// return;
-// }
-//
-// ImGui.OpenPopup( 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;
-// }
-//
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup );
-//
-// if( Mod == null )
-// {
-// _deleteIndex = null;
-// ImGui.CloseCurrentPopup();
-// return;
-// }
-//
-// ImGui.Text( "Are you sure you want to delete the following mod:" );
-// var halfLine = new Vector2( ImGui.GetTextLineHeight() / 2 );
-// ImGui.Dummy( halfLine );
-// ImGui.TextColored( DeleteModNameColor, Mod.Data.Meta.Name );
-// ImGui.Dummy( halfLine );
-//
-// var buttonSize = ImGuiHelpers.ScaledVector2( 120, 0 );
-// if( ImGui.Button( ButtonYesDelete, buttonSize ) )
-// {
-// ImGui.CloseCurrentPopup();
-// var mod = Mod;
-// Cache.RemoveMod( mod );
-// Penumbra.ModManager.DeleteMod( mod.Data.BasePath );
-// ModFileSystem.InvokeChange();
-// ClearSelection();
-// }
-//
-// ImGui.SameLine();
-//
-// if( ImGui.Button( ButtonNoDelete, buttonSize ) )
-// {
-// ImGui.CloseCurrentPopup();
-// _deleteIndex = null;
-// }
-// }
-//
-// // === Add ===
-// private bool _modAddKeyboardFocus = true;
-//
-// private void DrawModAddButton()
-// {
-// using var raii = ImGuiRaii.PushFont( UiBuilder.IconFont );
-//
-// if( ImGui.Button( FontAwesomeIcon.Plus.ToIconString(), SelectorButtonSizes * _selectorScalingFactor ) )
-// {
-// _modAddKeyboardFocus = true;
-// ImGui.OpenPopup( LabelAddModPopup );
-// }
-//
-// raii.Pop();
-//
-// ImGuiCustom.HoverTooltip( TooltipAdd );
-//
-// DrawModAddPopup();
-// }
-//
-// private void DrawModAddPopup()
-// {
-// if( !ImGui.BeginPopup( LabelAddModPopup ) )
-// {
-// return;
-// }
-//
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup );
-//
-// if( _modAddKeyboardFocus )
-// {
-// ImGui.SetKeyboardFocusHere();
-// _modAddKeyboardFocus = false;
-// }
-//
-// var newName = "";
-// if( ImGui.InputTextWithHint( "##AddMod", "New Mod Name...", ref newName, 64, ImGuiInputTextFlags.EnterReturnsTrue ) )
-// {
-// try
-// {
-// var newDir = TexToolsImport.CreateModFolder( new DirectoryInfo( Penumbra.Config!.ModDirectory ),
-// newName );
-// var modMeta = new ModMeta
-// {
-// Author = "Unknown",
-// Name = newName.Replace( '/', '\\' ),
-// Description = string.Empty,
-// };
-//
-// var metaFile = new FileInfo( Path.Combine( newDir.FullName, "meta.json" ) );
-// modMeta.SaveToFile( metaFile );
-// Penumbra.ModManager.AddMod( newDir );
-// ModFileSystem.InvokeChange();
-// SelectModOnUpdate( 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();
-// }
-// }
-//
-// // === Help ===
-// private void DrawModHelpButton()
-// {
-// using var raii = ImGuiRaii.PushFont( UiBuilder.IconFont );
-// if( ImGui.Button( FontAwesomeIcon.QuestionCircle.ToIconString(), HelpButtonSizes * _selectorScalingFactor ) )
-// {
-// ImGui.OpenPopup( LabelModHelpPopup );
-// }
-// }
-//
-// private static void DrawModHelpPopup()
-// {
-// ImGui.SetNextWindowPos( ImGui.GetMainViewport().GetCenter(), ImGuiCond.Appearing, Vector2.One / 2 );
-// ImGui.SetNextWindowSize( new Vector2( 5 * SelectorPanelWidth, 34 * ImGui.GetTextLineHeightWithSpacing() ),
-// ImGuiCond.Appearing );
-// var _ = true;
-// if( !ImGui.BeginPopupModal( LabelModHelpPopup, ref _, ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove ) )
-// {
-// return;
-// }
-//
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup );
-//
-// ImGui.Dummy( Vector2.UnitY * ImGui.GetTextLineHeight() );
-// ImGui.Text( "Mod Selector" );
-// ImGui.BulletText( "Select a mod to obtain more information." );
-// ImGui.BulletText( "Mod names are colored according to their current state in the collection:" );
-// ImGui.Indent();
-// ImGui.Bullet();
-// ImGui.SameLine();
-// ImGui.Text( "Enabled in the current collection." );
-// ImGui.Bullet();
-// ImGui.SameLine();
-// ImGui.TextColored( ImGui.ColorConvertU32ToFloat4( ColorId.DisabledMod.Value() ), "Disabled in the current collection." );
-// ImGui.Bullet();
-// ImGui.SameLine();
-// ImGui.TextColored( ImGui.ColorConvertU32ToFloat4( ColorId.NewMod.Value() ),
-// "Newly imported during this session. Will go away when first enabling a mod or when Penumbra is reloaded." );
-// ImGui.Bullet();
-// ImGui.SameLine();
-// ImGui.TextColored( ImGui.ColorConvertU32ToFloat4( ColorId.HandledConflictMod.Value() ),
-// "Enabled and conflicting with another enabled Mod, but on different priorities (i.e. the conflict is solved)." );
-// ImGui.Bullet();
-// ImGui.SameLine();
-// ImGui.TextColored( ImGui.ColorConvertU32ToFloat4( ColorId.DisabledMod.Value() ),
-// "Enabled and conflicting with another enabled Mod on the same priority." );
-// ImGui.Unindent();
-// ImGui.BulletText( "Right-click a mod to enter its sort order, which is its name by default." );
-// ImGui.Indent();
-// ImGui.BulletText( "A sort order differing from the mods name will not be displayed, it will just be used for ordering." );
-// ImGui.BulletText(
-// "If the sort order string contains Forward-Slashes ('/'), the preceding substring will be turned into collapsible folders that can group mods." );
-// ImGui.BulletText(
-// "Collapsible folders can contain further collapsible folders, so \"folder1/folder2/folder3/1\" will produce 3 folders\n"
-// + "\t\t[folder1] -> [folder2] -> [folder3] -> [ModName],\n"
-// + "where ModName will be sorted as if it was the string '1'." );
-// ImGui.Unindent();
-// 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." );
-// ImGui.BulletText( "Right-clicking a folder opens a context menu." );
-// ImGui.Indent();
-// ImGui.BulletText(
-// "You can rename folders in the context menu. Leave the text blank and press enter to merge the folder with its parent." );
-// ImGui.BulletText( "You can also enable or disable all descendant mods of a folder." );
-// ImGui.Unindent();
-// ImGui.BulletText( "Use the Filter Mods... input at the top to filter the list for mods with names containing the text." );
-// ImGui.Indent();
-// ImGui.BulletText( "You can enter c:[string] to filter for Changed Items instead." );
-// ImGui.BulletText( "You can enter a:[string] to filter for Mod Authors instead." );
-// ImGui.Unindent();
-// ImGui.BulletText( "Use the expandable menu beside the input to filter for mods fulfilling specific criteria." );
-// ImGui.Dummy( Vector2.UnitY * ImGui.GetTextLineHeight() );
-// ImGui.Text( "Mod Management" );
-// ImGui.BulletText( "You can delete the currently selected mod with the trashcan button." );
-// ImGui.BulletText( "You can add a completely empty mod with the plus button." );
-// ImGui.BulletText( "You can import TTMP-based mods in the import tab." );
-// ImGui.BulletText(
-// "You can import penumbra-based mods by moving the corresponding folder into your mod directory in a file explorer, then rediscovering mods." );
-// ImGui.BulletText(
-// "If you enable Advanced Options in the Settings tab, you can toggle Edit Mode to manipulate your selected mod even further." );
-// ImGui.Dummy( Vector2.UnitY * ImGui.GetTextLineHeight() );
-// ImGui.Dummy( Vector2.UnitX * 2 * SelectorPanelWidth );
-// ImGui.SameLine();
-// if( ImGui.Button( "Understood", Vector2.UnitX * SelectorPanelWidth ) )
-// {
-// ImGui.CloseCurrentPopup();
-// }
-// }
-//
-// // === Main ===
-// private void DrawModsSelectorButtons()
-// {
-// // Selector controls
-// using var style = ImGuiRaii.PushStyle( ImGuiStyleVar.WindowPadding, ZeroVector )
-// .Push( ImGuiStyleVar.FrameRounding, 0 );
-//
-// DrawModAddButton();
-// ImGui.SameLine();
-// DrawModHelpButton();
-// ImGui.SameLine();
-// DrawModTrashButton();
-// }
-// }
-//
-// // Filters
-// private partial class Selector
-// {
-// private string _modFilterInput = "";
-//
-// private void DrawTextFilter()
-// {
-// ImGui.SetNextItemWidth( SelectorPanelWidth * _selectorScalingFactor - 22 * ImGuiHelpers.GlobalScale );
-// var tmp = _modFilterInput;
-// if( ImGui.InputTextWithHint( LabelModFilter, "Filter Mods...", ref tmp, 256 ) && _modFilterInput != tmp )
-// {
-// Cache.SetTextFilter( tmp );
-// _modFilterInput = tmp;
-// }
-//
-// ImGuiCustom.HoverTooltip( TooltipModFilter );
-// }
-//
-// private void DrawToggleFilter()
-// {
-// if( ImGui.BeginCombo( "##ModStateFilter", "",
-// ImGuiComboFlags.NoPreview | ImGuiComboFlags.PopupAlignLeft | ImGuiComboFlags.HeightLargest ) )
-// {
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndCombo );
-// var flags = ( int )Cache.StateFilter;
-// foreach( ModFilter flag in Enum.GetValues( typeof( ModFilter ) ) )
-// {
-// ImGui.CheckboxFlags( flag.ToName(), ref flags, ( int )flag );
-// }
-//
-// Cache.StateFilter = ( ModFilter )flags;
-// }
-//
-// ImGuiCustom.HoverTooltip( "Filter mods for their activation status." );
-// }
-//
-// private void DrawModsSelectorFilter()
-// {
-// using var style = ImGuiRaii.PushStyle( ImGuiStyleVar.ItemSpacing, ZeroVector );
-// DrawTextFilter();
-// ImGui.SameLine();
-// DrawToggleFilter();
-// }
-// }
-//
-// // Drag'n Drop
-// private partial class Selector
-// {
-// private const string DraggedModLabel = "ModIndex";
-// private const string DraggedFolderLabel = "FolderName";
-//
-// private readonly IntPtr _dragDropPayload = Marshal.AllocHGlobal( 4 );
-//
-// private static unsafe bool IsDropping( string name )
-// => ImGui.AcceptDragDropPayload( name ).NativePtr != null;
-//
-// private void DragDropTarget( ModFolder folder )
-// {
-// if( !ImGui.BeginDragDropTarget() )
-// {
-// return;
-// }
-//
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndDragDropTarget );
-//
-// if( IsDropping( DraggedModLabel ) )
-// {
-// var payload = ImGui.GetDragDropPayload();
-// var modIndex = Marshal.ReadInt32( payload.Data );
-// var mod = Cache.GetMod( modIndex ).Item1;
-// mod?.Data.Move( folder );
-// }
-// else if( IsDropping( DraggedFolderLabel ) )
-// {
-// var payload = ImGui.GetDragDropPayload();
-// var folderName = Marshal.PtrToStringUni( payload.Data );
-// if( ModFileSystem.Find( folderName!, out var droppedFolder )
-// && !ReferenceEquals( droppedFolder, folder )
-// && !folder.FullName.StartsWith( folderName!, StringComparison.InvariantCultureIgnoreCase ) )
-// {
-// droppedFolder.Move( folder );
-// }
-// }
-// }
-//
-// private void DragDropSourceFolder( ModFolder folder )
-// {
-// if( !ImGui.BeginDragDropSource() )
-// {
-// return;
-// }
-//
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndDragDropSource );
-//
-// var folderName = folder.FullName;
-// var ptr = Marshal.StringToHGlobalUni( folderName );
-// ImGui.SetDragDropPayload( DraggedFolderLabel, ptr, ( uint )( folderName.Length + 1 ) * 2 );
-// ImGui.Text( $"Moving {folderName}..." );
-// }
-//
-// private void DragDropSourceMod( int modIndex, string modName )
-// {
-// if( !ImGui.BeginDragDropSource() )
-// {
-// return;
-// }
-//
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndDragDropSource );
-//
-// Marshal.WriteInt32( _dragDropPayload, modIndex );
-// ImGui.SetDragDropPayload( "ModIndex", _dragDropPayload, 4 );
-// ImGui.Text( $"Moving {modName}..." );
-// }
-//
-// ~Selector()
-// => Marshal.FreeHGlobal( _dragDropPayload );
-// }
-//
-// // Selection
-// private partial class Selector
-// {
-// public Mods.FullMod? Mod { get; private set; }
-// private int _index;
-// private string _nextDir = string.Empty;
-//
-// private void SetSelection( int idx, Mods.FullMod? info )
-// {
-// Mod = info;
-// if( idx != _index )
-// {
-// _base._menu.InstalledTab.ModPanel.Details.ResetState();
-// }
-//
-// _index = idx;
-// _deleteIndex = null;
-// }
-//
-// private void SetSelection( int idx )
-// {
-// if( idx >= Cache.Count )
-// {
-// idx = -1;
-// }
-//
-// if( idx < 0 )
-// {
-// SetSelection( 0, null );
-// }
-// else
-// {
-// SetSelection( idx, Cache.GetMod( idx ).Item1 );
-// }
-// }
-//
-// public void ReloadSelection()
-// => SetSelection( _index, Cache.GetMod( _index ).Item1 );
-//
-// public void ClearSelection()
-// => SetSelection( -1 );
-//
-// public void SelectModOnUpdate( string directory )
-// => _nextDir = directory;
-//
-// public void SelectModByDir( string name )
-// {
-// var (mod, idx) = Cache.GetModByBasePath( name );
-// SetSelection( idx, mod );
-// }
-//
-// public void ReloadCurrentMod( bool reloadMeta = false, bool recomputeMeta = false, bool force = false )
-// {
-// if( Mod == null )
-// {
-// return;
-// }
-//
-// if( _index >= 0 && Penumbra.ModManager.UpdateMod( Mod.Data, reloadMeta, recomputeMeta, force ) )
-// {
-// SelectModOnUpdate( Mod.Data.BasePath.Name );
-// _base._menu.InstalledTab.ModPanel.Details.ResetState();
-// }
-// }
-//
-// public void SaveCurrentMod()
-// => Mod?.Data.SaveMeta();
-// }
-//
-// // Right-Clicks
-// private partial class Selector
-// {
-// // === Mod ===
-// private void DrawModOrderPopup( string popupName, Mods.FullMod mod, bool firstOpen )
-// {
-// if( !ImGui.BeginPopup( popupName ) )
-// {
-// return;
-// }
-//
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup );
-//
-// if( ModPanel.DrawSortOrder( mod.Data, Penumbra.ModManager, this ) )
-// {
-// ImGui.CloseCurrentPopup();
-// }
-//
-// if( firstOpen )
-// {
-// ImGui.SetKeyboardFocusHere( mod.Data.Order.FullPath.Length - 1 );
-// }
-// }
-//
-// // === Folder ===
-// private string _newFolderName = string.Empty;
-// private int _expandIndex = -1;
-// private bool _expandCollapse;
-// private bool _currentlyExpanding;
-//
-// private void ChangeStatusOfChildren( ModFolder folder, int currentIdx, bool toWhat )
-// {
-// var change = false;
-// var metaManips = false;
-// foreach( var _ in folder.AllMods( Penumbra.ModManager.Config.SortFoldersFirst ) )
-// {
-// var (mod, _, _) = Cache.GetMod( currentIdx++ );
-// if( mod != null )
-// {
-// change |= mod.Settings.Enabled != toWhat;
-// mod!.Settings.Enabled = toWhat;
-// metaManips |= mod.Data.Resources.MetaManipulations.Count > 0;
-// }
-// }
-//
-// if( !change )
-// {
-// return;
-// }
-//
-// Cache.TriggerFilterReset();
-// var collection = Penumbra.CollectionManager.Current;
-// if( collection.HasCache )
-// {
-// collection.CalculateEffectiveFileList( metaManips, collection == Penumbra.CollectionManager.Default );
-// }
-//
-// collection.Save();
-// }
-//
-// private void DrawRenameFolderInput( ModFolder folder )
-// {
-// ImGui.SetNextItemWidth( 150 * ImGuiHelpers.GlobalScale );
-// if( !ImGui.InputTextWithHint( "##NewFolderName", "Rename Folder...", ref _newFolderName, 64,
-// ImGuiInputTextFlags.EnterReturnsTrue ) )
-// {
-// return;
-// }
-//
-// if( _newFolderName.Any() )
-// {
-// folder.Rename( _newFolderName );
-// }
-// else
-// {
-// folder.Merge( folder.Parent! );
-// }
-//
-// _newFolderName = string.Empty;
-// }
-//
-// private void DrawFolderContextMenu( ModFolder folder, int currentIdx, string treeName )
-// {
-// if( !ImGui.BeginPopup( treeName ) )
-// {
-// return;
-// }
-//
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup );
-//
-// if( ImGui.MenuItem( "Expand All Descendants" ) )
-// {
-// _expandIndex = currentIdx;
-// _expandCollapse = false;
-// }
-//
-// if( ImGui.MenuItem( "Collapse All Descendants" ) )
-// {
-// _expandIndex = currentIdx;
-// _expandCollapse = true;
-// }
-//
-// if( ImGui.MenuItem( "Enable All Descendants" ) )
-// {
-// ChangeStatusOfChildren( folder, currentIdx, true );
-// }
-//
-// if( ImGui.MenuItem( "Disable All Descendants" ) )
-// {
-// ChangeStatusOfChildren( folder, currentIdx, false );
-// }
-//
-// ImGuiHelpers.ScaledDummy( 0, 10 );
-// DrawRenameFolderInput( folder );
-// }
-// }
-//
-// // Main-Interface
-// private partial class Selector
-// {
-// private readonly SettingsInterface _base;
-// public readonly ModListCache Cache;
-//
-// private float _selectorScalingFactor = 1;
-//
-// public Selector( SettingsInterface ui, IReadOnlySet< string > newMods )
-// {
-// _base = ui;
-// Cache = new ModListCache( Penumbra.ModManager, newMods );
-// }
-//
-// private void DrawCollectionButton( string label, string tooltipLabel, float size, ModCollection collection )
-// {
-// if( collection == ModCollection.Empty
-// || collection == Penumbra.CollectionManager.Current )
-// {
-// using var _ = ImGuiRaii.PushStyle( ImGuiStyleVar.Alpha, 0.5f );
-// ImGui.Button( label, Vector2.UnitX * size );
-// }
-// else if( ImGui.Button( label, Vector2.UnitX * size ) )
-// {
-// _base._menu.CollectionsTab.SetCurrentCollection( collection );
-// }
-//
-// ImGuiCustom.HoverTooltip(
-// $"Switches to the currently set {tooltipLabel} collection, if it is not set to None and it is not the current collection already." );
-// }
-//
-// private void DrawHeaderBar()
-// {
-// const float size = 200;
-//
-// DrawModsSelectorFilter();
-// var textSize = ImGui.CalcTextSize( "Current Collection" ).X + ImGui.GetStyle().ItemInnerSpacing.X;
-// var comboSize = size * ImGui.GetIO().FontGlobalScale;
-// var offset = comboSize + textSize;
-//
-// var buttonSize = Math.Max( ImGui.GetWindowContentRegionWidth()
-// - offset
-// - SelectorPanelWidth * _selectorScalingFactor
-// - 3 * ImGui.GetStyle().ItemSpacing.X, 5f );
-// ImGui.SameLine();
-// DrawCollectionButton( "Default", "default", buttonSize, Penumbra.CollectionManager.Default );
-//
-//
-// ImGui.SameLine();
-// ImGui.SetNextItemWidth( comboSize );
-// using var style = ImGuiRaii.PushStyle( ImGuiStyleVar.ItemSpacing, Vector2.Zero );
-// _base._menu.CollectionsTab.DrawCurrentCollectionSelector( false );
-// }
-//
-// private void DrawFolderContent( ModFolder folder, ref int idx )
-// {
-// // Collection may be manipulated.
-// foreach( var item in folder.GetItems( Penumbra.ModManager.Config.SortFoldersFirst ).ToArray() )
-// {
-// if( item is ModFolder sub )
-// {
-// var (visible, _) = Cache.GetFolder( sub );
-// if( visible )
-// {
-// DrawModFolder( sub, ref idx );
-// }
-// else
-// {
-// idx += sub.TotalDescendantMods();
-// }
-// }
-// else if( item is Mods.Mod _ )
-// {
-// var (mod, visible, color) = Cache.GetMod( idx );
-// if( mod != null && visible )
-// {
-// DrawMod( mod, idx++, color );
-// }
-// else
-// {
-// ++idx;
-// }
-// }
-// }
-// }
-//
-// private void DrawModFolder( ModFolder folder, ref int idx )
-// {
-// var treeName = $"{folder.Name}##{folder.FullName}";
-// var open = ImGui.TreeNodeEx( treeName );
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.TreePop, open );
-//
-// if( idx == _expandIndex )
-// {
-// _currentlyExpanding = true;
-// }
-//
-// if( _currentlyExpanding )
-// {
-// ImGui.SetNextItemOpen( !_expandCollapse );
-// }
-//
-// if( ImGui.IsItemClicked( ImGuiMouseButton.Right ) )
-// {
-// _newFolderName = string.Empty;
-// ImGui.OpenPopup( treeName );
-// }
-//
-// DrawFolderContextMenu( folder, idx, treeName );
-// DragDropTarget( folder );
-// DragDropSourceFolder( folder );
-//
-// if( open )
-// {
-// DrawFolderContent( folder, ref idx );
-// }
-// else
-// {
-// idx += folder.TotalDescendantMods();
-// }
-//
-// if( idx == _expandIndex )
-// {
-// _currentlyExpanding = false;
-// _expandIndex = -1;
-// }
-// }
-//
-// private void DrawMod( Mods.FullMod mod, int modIndex, uint color )
-// {
-// using var colorRaii = ImGuiRaii.PushColor( ImGuiCol.Text, color, color != 0 );
-//
-// var selected = ImGui.Selectable( $"{mod.Data.Meta.Name}##{modIndex}", modIndex == _index );
-// colorRaii.Pop();
-//
-// var popupName = $"##SortOrderPopup{modIndex}";
-// var firstOpen = false;
-// if( ImGui.IsItemClicked( ImGuiMouseButton.Right ) )
-// {
-// ImGui.OpenPopup( popupName );
-// firstOpen = true;
-// }
-//
-// DragDropTarget( mod.Data.Order.ParentFolder );
-// DragDropSourceMod( modIndex, mod.Data.Meta.Name );
-//
-// DrawModOrderPopup( popupName, mod, firstOpen );
-//
-// if( selected )
-// {
-// SetSelection( modIndex, mod );
-// }
-// }
-//
-// public void Draw()
-// {
-// if( Cache.Update() )
-// {
-// if( _nextDir.Any() )
-// {
-// SelectModByDir( _nextDir );
-// _nextDir = string.Empty;
-// }
-// else if( Mod != null )
-// {
-// SelectModByDir( Mod.Data.BasePath.Name );
-// }
-// }
-//
-// _selectorScalingFactor = ImGuiHelpers.GlobalScale
-// * ( Penumbra.Config.ScaleModSelector
-// ? ImGui.GetWindowWidth() / SettingsMenu.MinSettingsSize.X
-// : 1f );
-// // Selector pane
-// DrawHeaderBar();
-// using var style = ImGuiRaii.PushStyle( ImGuiStyleVar.ItemSpacing, Vector2.Zero );
-// ImGui.BeginGroup();
-// using var raii = ImGuiRaii.DeferredEnd( ImGui.EndGroup )
-// .Push( ImGui.EndChild );
-// // Inlay selector list
-// if( ImGui.BeginChild( LabelSelectorList,
-// new Vector2( SelectorPanelWidth * _selectorScalingFactor, -ImGui.GetFrameHeightWithSpacing() ),
-// true, ImGuiWindowFlags.HorizontalScrollbar ) )
-// {
-// style.Push( ImGuiStyleVar.IndentSpacing, 12.5f );
-//
-// var modIndex = 0;
-// DrawFolderContent( Penumbra.ModManager.StructuredMods, ref modIndex );
-// style.Pop();
-// }
-//
-// raii.Pop();
-//
-// DrawModsSelectorButtons();
-//
-// style.Pop();
-// DrawModHelpPopup();
-//
-// DrawDeleteModal();
-// }
-// }
-//}
\ No newline at end of file
diff --git a/Penumbra/UI/ConfigWindow.ModsTab.cs b/Penumbra/UI/ConfigWindow.ModsTab.cs
index dd5dddc7..de60ef03 100644
--- a/Penumbra/UI/ConfigWindow.ModsTab.cs
+++ b/Penumbra/UI/ConfigWindow.ModsTab.cs
@@ -1,18 +1,17 @@
-using System;
-using System.Numerics;
-using Dalamud.Interface;
using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
using Penumbra.Collections;
using Penumbra.Mods;
using Penumbra.UI.Classes;
+using System;
+using System.Numerics;
namespace Penumbra.UI;
public partial class ConfigWindow
{
- public void DrawModsTab()
+ private void DrawModsTab()
{
if( !Penumbra.ModManager.Valid )
{
@@ -103,12 +102,10 @@ public partial class ConfigWindow
private bool _valid;
private ModFileSystem.Leaf _leaf = null!;
- private Mod _mod = null!;
+ private Mod _mod = null!;
public ModPanel( ConfigWindow window )
- {
- _window = window;
- }
+ => _window = window;
public void Draw( ModFileSystemSelector selector )
{
diff --git a/Penumbra/UI/ConfigWindow.SettingsTab.cs b/Penumbra/UI/ConfigWindow.SettingsTab.cs
index 839809e0..9278faa9 100644
--- a/Penumbra/UI/ConfigWindow.SettingsTab.cs
+++ b/Penumbra/UI/ConfigWindow.SettingsTab.cs
@@ -47,10 +47,13 @@ public partial class ConfigWindow
DrawAdvancedSettings();
}
+ // Changing the base mod directory.
private string? _newModDirectory;
private readonly FileDialogManager _dialogManager = new();
- private bool _dialogOpen;
+ private bool _dialogOpen; // For toggling on/off.
+ // Do not change the directory without explicitly pressing enter or this button.
+ // Shows up only if the current input does not correspond to the current directory.
private static bool DrawPressEnterWarning( string old, float width )
{
using var color = ImRaii.PushColor( ImGuiCol.Button, Colors.PressEnterWarningBg );
@@ -58,9 +61,11 @@ public partial class ConfigWindow
return ImGui.Button( $"Press Enter or Click Here to Save (Current Directory: {old})", w );
}
+ // Draw a directory picker button that toggles the directory picker.
+ // Selecting a directory does behave the same as writing in the text input, i.e. needs to be saved.
private void DrawDirectoryPickerButton()
{
- if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Folder.ToIconString(), ImGui.GetFrameHeight() * Vector2.One,
+ if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Folder.ToIconString(), _window._iconButtonSize,
"Select a directory via dialog.", false, true ) )
{
if( _dialogOpen )
@@ -71,6 +76,8 @@ public partial class ConfigWindow
else
{
_newModDirectory ??= Penumbra.Config.ModDirectory;
+ // Use the current input as start directory if it exists,
+ // otherwise the current mod directory, otherwise the current application directory.
var startDir = Directory.Exists( _newModDirectory )
? _newModDirectory
: Directory.Exists( Penumbra.Config.ModDirectory )
@@ -103,13 +110,15 @@ public partial class ConfigWindow
}
}
+ // Draw the text input for the mod directory,
+ // as well as the directory picker button and the enter warning.
private void DrawRootFolder()
{
_newModDirectory ??= Penumbra.Config.ModDirectory;
var spacing = 3 * ImGuiHelpers.GlobalScale;
using var group = ImRaii.Group();
- ImGui.SetNextItemWidth( _window._inputTextWidth.X - spacing - ImGui.GetFrameHeight() );
+ ImGui.SetNextItemWidth( _window._inputTextWidth.X - spacing - _window._iconButtonSize.X );
var save = ImGui.InputText( "##rootDirectory", ref _newModDirectory, 255, ImGuiInputTextFlags.EnterReturnsTrue );
using var style = ImRaii.PushStyle( ImGuiStyleVar.ItemSpacing, new Vector2( spacing, 0 ) );
ImGui.SameLine();
@@ -127,18 +136,14 @@ public partial class ConfigWindow
var pos = ImGui.GetCursorPosX();
ImGui.NewLine();
- if( Penumbra.Config.ModDirectory == _newModDirectory || _newModDirectory.Length == 0 )
- {
- return;
- }
-
- if( save || DrawPressEnterWarning( Penumbra.Config.ModDirectory, pos ) )
+ if( Penumbra.Config.ModDirectory != _newModDirectory
+ && _newModDirectory.Length == 0
+ && ( save || DrawPressEnterWarning( Penumbra.Config.ModDirectory, pos ) ) )
{
Penumbra.ModManager.DiscoverMods( _newModDirectory );
}
}
-
private static void DrawRediscoverButton()
{
DrawOpenDirectoryButton( 0, Penumbra.ModManager.BasePath, Penumbra.ModManager.Valid );
diff --git a/Penumbra/UI/ConfigWindow.cs b/Penumbra/UI/ConfigWindow.cs
index f98ddb0a..fec85594 100644
--- a/Penumbra/UI/ConfigWindow.cs
+++ b/Penumbra/UI/ConfigWindow.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Numerics;
-using System.Reflection;
using Dalamud.Interface;
using Dalamud.Interface.Windowing;
using ImGuiNET;
@@ -28,7 +27,7 @@ public sealed partial class ConfigWindow : Window, IDisposable
{
_penumbra = penumbra;
_settingsTab = new SettingsTab( this );
- _selector = new ModFileSystemSelector( _penumbra.ModFileSystem, new HashSet< Mod >() ); // TODO
+ _selector = new ModFileSystemSelector( _penumbra.ModFileSystem );
_modPanel = new ModPanel( this );
_collectionsTab = new CollectionsTab( this );
_effectiveTab = new EffectiveTab();
diff --git a/Penumbra/Util/ArrayExtensions.cs b/Penumbra/Util/ArrayExtensions.cs
index 8cce7065..8953426f 100644
--- a/Penumbra/Util/ArrayExtensions.cs
+++ b/Penumbra/Util/ArrayExtensions.cs
@@ -7,36 +7,50 @@ namespace Penumbra.Util;
public static class ArrayExtensions
{
+ // Iterate over enumerables with additional index.
public static IEnumerable< (T, int) > WithIndex< T >( this IEnumerable< T > list )
=> list.Select( ( x, i ) => ( x, i ) );
- public static int IndexOf< T >( this IReadOnlyList< T > array, Predicate< T > predicate )
+
+ // Find the index of the first object fulfilling predicate's criteria in the given list.
+ // Returns -1 if no such object is found.
+ public static int IndexOf< T >( this IEnumerable< T > array, Predicate< T > predicate )
{
- for( var i = 0; i < array.Count; ++i )
+ var i = 0;
+ foreach( var obj in array )
{
- if( predicate( array[ i ] ) )
+ if( predicate( obj ) )
{
return i;
}
+
+ ++i;
}
return -1;
}
- public static int IndexOf< T >( this IReadOnlyList< T > array, T needle )
+ // Find the index of the first occurrence of needle in the given list.
+ // Returns -1 if needle is not contained in the list.
+ public static int IndexOf< T >( this IEnumerable< T > array, T needle ) where T : notnull
{
- for( var i = 0; i < array.Count; ++i )
+ var i = 0;
+ foreach( var obj in array )
{
- if( needle!.Equals( array[ i ] ) )
+ if( needle.Equals( obj ) )
{
return i;
}
+
+ ++i;
}
return -1;
}
- public static bool FindFirst< T >( this IReadOnlyList< T > array, Predicate< T > predicate, [NotNullWhen( true )] out T? result )
+ // Find the first object fulfilling predicate's criteria in the given list, if one exists.
+ // Returns true if an object is found, false otherwise.
+ public static bool FindFirst< T >( this IEnumerable< T > array, Predicate< T > predicate, [NotNullWhen( true )] out T? result )
{
foreach( var obj in array )
{
@@ -51,7 +65,9 @@ public static class ArrayExtensions
return false;
}
- public static bool FindFirst< T >( this IReadOnlyList< T > array, T needle, [NotNullWhen( true )] out T? result ) where T : IEquatable< T >
+ // Find the first occurrence of needle in the given list and return the value contained in the list in result.
+ // Returns true if an object is found, false otherwise.
+ public static bool FindFirst< T >( this IEnumerable< T > array, T needle, [NotNullWhen( true )] out T? result ) where T : notnull
{
foreach( var obj in array )
{
diff --git a/Penumbra/Util/BinaryReaderExtensions.cs b/Penumbra/Util/BinaryReaderExtensions.cs
deleted file mode 100644
index dec2d44d..00000000
--- a/Penumbra/Util/BinaryReaderExtensions.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-namespace Penumbra.Util;
-
-public static class BinaryReaderExtensions
-{
- ///
- /// Reads a structure from the current stream position.
- ///
- ///
- /// The structure to read in to
- /// The file data as a structure
- public static T ReadStructure< T >( this BinaryReader br ) where T : struct
- {
- ReadOnlySpan< byte > data = br.ReadBytes( Unsafe.SizeOf< T >() );
-
- return MemoryMarshal.Read< T >( data );
- }
-
- ///
- /// Reads many structures from the current stream position.
- ///
- ///
- /// The number of T to read from the stream
- /// The structure to read in to
- /// A list containing the structures read from the stream
- public static List< T > ReadStructures< T >( this BinaryReader br, int count ) where T : struct
- {
- var size = Marshal.SizeOf< T >();
- var data = br.ReadBytes( size * count );
-
- var list = new List< T >( count );
-
- for( var i = 0; i < count; i++ )
- {
- var offset = size * i;
- var span = new ReadOnlySpan< byte >( data, offset, size );
-
- list.Add( MemoryMarshal.Read< T >( span ) );
- }
-
- return list;
- }
-
- ///
- /// Seeks this BinaryReader's position to the given offset. Syntactic sugar.
- ///
- public static void Seek( this BinaryReader br, long offset )
- {
- br.BaseStream.Position = offset;
- }
-}
\ No newline at end of file
diff --git a/Penumbra/Util/FixedUlongStringEnumConverter.cs b/Penumbra/Util/FixedUlongStringEnumConverter.cs
index 1ab68e4e..750422b4 100644
--- a/Penumbra/Util/FixedUlongStringEnumConverter.cs
+++ b/Penumbra/Util/FixedUlongStringEnumConverter.cs
@@ -75,7 +75,7 @@ public static partial class JsonExtensions
return reader;
}
- public static JsonReader ReadAndAssert( this JsonReader reader )
+ private static JsonReader ReadAndAssert( this JsonReader reader )
{
if( reader == null )
{
diff --git a/Penumbra/Util/PenumbraSqPackStream.cs b/Penumbra/Util/PenumbraSqPackStream.cs
index 8e26d45b..e338a1d5 100644
--- a/Penumbra/Util/PenumbraSqPackStream.cs
+++ b/Penumbra/Util/PenumbraSqPackStream.cs
@@ -4,6 +4,7 @@ using System.IO;
using System.IO.Compression;
using System.Runtime.InteropServices;
using Lumina.Data.Structs;
+using Lumina.Extensions;
namespace Penumbra.Util;