This commit is contained in:
Ottermandias 2022-04-06 11:34:12 +02:00
parent 33db156544
commit 8db54ef4f4
17 changed files with 546 additions and 212 deletions

@ -1 +1 @@
Subproject commit a78f17dd1bc4cbe7e9d6c04af828ff1adac4bd6f Subproject commit baee502862a5e8cdfa407f703ce98abad5cc623b

View file

@ -1,4 +1,6 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using Penumbra.Mods; using Penumbra.Mods;
namespace Penumbra.Collections; namespace Penumbra.Collections;
@ -6,10 +8,12 @@ namespace Penumbra.Collections;
// Different types a mod setting can change: // Different types a mod setting can change:
public enum ModSettingChange public enum ModSettingChange
{ {
Inheritance, // it was set to inherit from other collections or not inherit anymore Inheritance, // it was set to inherit from other collections or not inherit anymore
EnableState, // it was enabled or disabled EnableState, // it was enabled or disabled
Priority, // its priority was changed Priority, // its priority was changed
Setting, // a specific setting was changed Setting, // a specific setting was changed
MultiInheritance, // multiple mods were set to inherit from other collections or not inherit anymore.
MultiEnableState, // multiple mods were enabled or disabled at once.
} }
public partial class ModCollection public partial class ModCollection
@ -28,7 +32,7 @@ public partial class ModCollection
} }
} }
// Set the enabled state mod idx to newValue if it differs from the current priority. // Set the enabled state mod idx to newValue if it differs from the current enabled state.
// If mod idx is currently inherited, stop the inheritance. // If mod idx is currently inherited, stop the inheritance.
public void SetModState( int idx, bool newValue ) public void SetModState( int idx, bool newValue )
{ {
@ -41,6 +45,37 @@ public partial class ModCollection
} }
} }
// Enable or disable the mod inheritance of every mod in mods.
public void SetMultipleModInheritances( IEnumerable< Mod > mods, bool inherit )
{
if( mods.Aggregate( false, ( current, mod ) => current | FixInheritance( mod.Index, inherit ) ) )
{
ModSettingChanged.Invoke( ModSettingChange.MultiInheritance, -1, -1, null, false );
}
}
// Set the enabled state of every mod in mods to the new value.
// If the mod is currently inherited, stop the inheritance.
public void SetMultipleModStates( IEnumerable< Mod > mods, bool newValue )
{
var changes = false;
foreach( var mod in mods )
{
var oldValue = _settings[ mod.Index ]?.Enabled ?? this[ mod.Index ].Settings?.Enabled ?? false;
if( newValue != oldValue )
{
FixInheritance( mod.Index, false );
_settings[ mod.Index ]!.Enabled = newValue;
changes = true;
}
}
if( changes )
{
ModSettingChanged.Invoke( ModSettingChange.MultiEnableState, -1, -1, null, false );
}
}
// Set the priority of mod idx to newValue if it differs from the current priority. // Set the priority of mod idx to newValue if it differs from the current priority.
// If mod idx is currently inherited, stop the inheritance. // If mod idx is currently inherited, stop the inheritance.
public void SetModPriority( int idx, int newValue ) public void SetModPriority( int idx, int newValue )

View file

@ -3,7 +3,7 @@ using System.IO;
using Dalamud.Logging; using Dalamud.Logging;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Penumbra.Util; using OtterGui;
namespace Penumbra.Mods; namespace Penumbra.Mods;

View file

@ -0,0 +1,39 @@
using System.IO;
using OtterGui.Filesystem;
namespace Penumbra.Mods;
public sealed class ModFileSystemA : FileSystem< Mod >
{
public void Save()
=> SaveToFile( new FileInfo( Mod.Manager.SortOrderFile ), SaveMod, true );
public static ModFileSystemA Load()
{
var x = new ModFileSystemA();
if( x.Load( new FileInfo( Mod.Manager.SortOrderFile ), Penumbra.ModManager.Mods, ModToIdentifier, ModToName ) )
{
x.Save();
}
x.Changed += ( _1, _2, _3, _4 ) => x.Save();
return x;
}
private static string ModToIdentifier( Mod mod )
=> mod.BasePath.Name;
private static string ModToName( Mod mod )
=> mod.Meta.Name.Text;
private static (string, bool) SaveMod( Mod mod, string fullPath )
{
if( fullPath == ModToName( mod ) )
{
return ( string.Empty, false );
}
return ( ModToIdentifier( mod ), true );
}
}

View file

@ -5,6 +5,7 @@ using System.Linq;
using Dalamud.Logging; using Dalamud.Logging;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using OtterGui;
using Penumbra.GameData.ByteString; using Penumbra.GameData.ByteString;
using Penumbra.Util; using Penumbra.Util;

10
Penumbra/UI/Colors.cs Normal file
View file

@ -0,0 +1,10 @@
namespace Penumbra.UI;
public static class Colors
{
public const uint DefaultTextColor = 0xFFFFFFFFu;
public const uint NewModColor = 0xFF66DD66u;
public const uint DisabledModColor = 0xFF666666u;
public const uint ConflictingModColor = 0xFFAAAAFFu;
public const uint HandledConflictModColor = 0xFF88DDDDu;
}

View file

@ -0,0 +1,330 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Dalamud.Interface;
using ImGuiNET;
using OtterGui;
using OtterGui.Filesystem;
using OtterGui.FileSystem.Selector;
using OtterGui.Raii;
using Penumbra.Collections;
using Penumbra.Mods;
namespace Penumbra.UI;
public sealed class ModFileSystemSelector : FileSystemSelector< Mod, ModState >
{
private readonly IReadOnlySet< Mod > _newMods = new HashSet<Mod>();
private LowerString _modFilter = LowerString.Empty;
private LowerString _modFilterAuthor = LowerString.Empty;
private LowerString _modFilterChanges = LowerString.Empty;
private LowerString _modFilterName = LowerString.Empty;
private ModFilter _stateFilter = ModFilterExtensions.UnfilteredStateMods;
public ModFilter StateFilter
{
get => _stateFilter;
set
{
var diff = _stateFilter != value;
_stateFilter = value;
if( diff )
{
SetFilterDirty();
}
}
}
protected override bool ChangeFilter( string filterValue )
{
if( filterValue.StartsWith( "c:", StringComparison.InvariantCultureIgnoreCase ) )
{
_modFilterChanges = new LowerString( filterValue[ 2.. ] );
_modFilter = LowerString.Empty;
_modFilterAuthor = LowerString.Empty;
_modFilterName = LowerString.Empty;
}
else if( filterValue.StartsWith( "a:", StringComparison.InvariantCultureIgnoreCase ) )
{
_modFilterAuthor = new LowerString( filterValue[ 2.. ] );
_modFilter = LowerString.Empty;
_modFilterChanges = LowerString.Empty;
_modFilterName = LowerString.Empty;
}
else if( filterValue.StartsWith( "n:", StringComparison.InvariantCultureIgnoreCase ) )
{
_modFilterName = new LowerString( filterValue[ 2.. ] );
_modFilter = LowerString.Empty;
_modFilterChanges = LowerString.Empty;
_modFilterAuthor = LowerString.Empty;
}
else
{
_modFilter = new LowerString( filterValue );
_modFilterAuthor = LowerString.Empty;
_modFilterChanges = LowerString.Empty;
_modFilterName = LowerString.Empty;
}
return true;
}
private bool CheckFlags( int count, ModFilter hasNoFlag, ModFilter hasFlag )
{
if( count == 0 )
{
if( StateFilter.HasFlag( hasNoFlag ) )
{
return false;
}
}
else if( StateFilter.HasFlag( hasFlag ) )
{
return false;
}
return true;
}
private ModState GetModState( Mod mod, ModSettings? settings )
{
if( settings?.Enabled != true )
{
return new ModState { Color = ImGui.GetColorU32( ImGuiCol.TextDisabled ) };
}
return new ModState { Color = ImGui.GetColorU32( ImGuiCol.Text ) };
}
protected override bool ApplyFiltersAndState( FileSystem< Mod >.IPath path, out ModState state )
{
if( path is ModFileSystemA.Folder f )
{
return base.ApplyFiltersAndState( f, out state );
}
return ApplyFiltersAndState( ( ModFileSystemA.Leaf )path, out state );
}
private bool CheckPath( string path, Mod mod )
=> _modFilter.IsEmpty
|| path.Contains( _modFilter.Lower, StringComparison.InvariantCultureIgnoreCase )
|| mod.Meta.Name.Contains( _modFilter );
private bool CheckName( Mod mod )
=> _modFilterName.IsEmpty || mod.Meta.Name.Contains( _modFilterName );
private bool CheckAuthor( Mod mod )
=> _modFilterAuthor.IsEmpty || mod.Meta.Author.Contains( _modFilterAuthor );
private bool CheckItems( Mod mod )
=> _modFilterChanges.IsEmpty || mod.LowerChangedItemsString.Contains( _modFilterChanges.Lower );
private bool ApplyFiltersAndState( ModFileSystemA.Leaf leaf, out ModState state )
{
state = new ModState { Color = Colors.DefaultTextColor };
var mod = leaf.Value;
var (settings, collection) = Current[ mod.Index ];
// Check string filters.
if( !( CheckPath( leaf.FullName(), mod )
&& CheckName( mod )
&& CheckAuthor( mod )
&& CheckItems( mod ) ) )
{
return true;
}
var isNew = _newMods.Contains( mod );
if( CheckFlags( mod.Resources.ModFiles.Count, ModFilter.HasNoFiles, ModFilter.HasFiles )
|| CheckFlags( mod.Meta.FileSwaps.Count, ModFilter.HasNoFileSwaps, ModFilter.HasFileSwaps )
|| CheckFlags( mod.Resources.MetaManipulations.Count, ModFilter.HasNoMetaManipulations, ModFilter.HasMetaManipulations )
|| CheckFlags( mod.Meta.HasGroupsWithConfig ? 1 : 0, ModFilter.HasNoConfig, ModFilter.HasConfig )
|| CheckFlags( isNew ? 1 : 0, ModFilter.IsNew, ModFilter.NotNew ) )
{
return true;
}
if( settings == null )
{
state.Color = Colors.DisabledModColor;
if( !StateFilter.HasFlag( ModFilter.Undefined ) )
{
return true;
}
settings = new ModSettings();
}
if( !settings.Enabled )
{
state.Color = Colors.DisabledModColor;
if( !StateFilter.HasFlag( ModFilter.Disabled ) )
{
return true;
}
}
else
{
if( !StateFilter.HasFlag( ModFilter.Enabled ) )
{
return true;
}
var conflicts = Penumbra.CollectionManager.Current.ModConflicts( mod.Index ).ToList();
if( conflicts.Count > 0 )
{
if( conflicts.Any( c => !c.Solved ) )
{
if( !StateFilter.HasFlag( ModFilter.UnsolvedConflict ) )
{
return true;
}
state.Color = Colors.ConflictingModColor;
}
else
{
if( !StateFilter.HasFlag( ModFilter.SolvedConflict ) )
{
return true;
}
state.Color = Colors.HandledConflictModColor;
}
}
else if( !StateFilter.HasFlag( ModFilter.NoConflict ) )
{
return true;
}
}
if( collection == Current )
{
if( !StateFilter.HasFlag( ModFilter.Uninherited ) )
{
return true;
}
}
else
{
if( !StateFilter.HasFlag( ModFilter.Inherited ) )
{
return true;
}
}
if( isNew )
{
state.Color = Colors.NewModColor;
}
return false;
}
protected override float CustomFilters( float width )
{
var pos = ImGui.GetCursorPos();
var remainingWidth = width - ImGui.GetFrameHeight();
var comboPos = new Vector2( pos.X + remainingWidth, pos.Y );
ImGui.SetCursorPos( comboPos );
using var combo = ImRaii.Combo( "##filterCombo", string.Empty,
ImGuiComboFlags.NoPreview | ImGuiComboFlags.PopupAlignLeft | ImGuiComboFlags.HeightLargest );
if( combo )
{
ImGui.Text( "A" );
ImGui.Text( "B" );
ImGui.Text( "C" );
}
combo.Dispose();
ImGui.SetCursorPos( pos );
return remainingWidth;
}
public ModFileSystemSelector( ModFileSystemA fileSystem )
: base( fileSystem )
{
SubscribeRightClickFolder( EnableDescendants, 10 );
SubscribeRightClickFolder( DisableDescendants, 10 );
SubscribeRightClickFolder( InheritDescendants, 15 );
SubscribeRightClickFolder( OwnDescendants, 15 );
AddButton( AddNewModButton, 0 );
AddButton( DeleteModButton, 1000 );
}
private static ModCollection Current
=> Penumbra.CollectionManager.Current;
private static void EnableDescendants( ModFileSystemA.Folder folder )
{
if( ImGui.MenuItem( "Enable Descendants" ) )
{
SetDescendants( folder, true, false );
}
}
private static void DisableDescendants( ModFileSystemA.Folder folder )
{
if( ImGui.MenuItem( "Disable Descendants" ) )
{
SetDescendants( folder, false, false );
}
}
private static void InheritDescendants( ModFileSystemA.Folder folder )
{
if( ImGui.MenuItem( "Inherit Descendants" ) )
{
SetDescendants( folder, true, true );
}
}
private static void OwnDescendants( ModFileSystemA.Folder folder )
{
if( ImGui.MenuItem( "Stop Inheriting Descendants" ) )
{
SetDescendants( folder, false, true );
}
}
private static void AddNewModButton( Vector2 size )
{
if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Plus.ToIconString(), size, "Create a new, empty mod of a given name.", false, true ) )
{ }
}
private void DeleteModButton( Vector2 size )
{
if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Trash.ToIconString(), size,
"Delete the currently selected mod entirely from your drive.", SelectedLeaf == null, true ) )
{ }
}
private static void SetDescendants( ModFileSystemA.Folder folder, bool enabled, bool inherit = false )
{
var mods = folder.GetAllDescendants( SortMode.Lexicographical ).OfType< ModFileSystemA.Leaf >().Select( l => l.Value );
if( inherit )
{
Current.SetMultipleModInheritances( mods, enabled );
}
else
{
Current.SetMultipleModStates( mods, enabled );
}
}
public override SortMode SortMode
=> Penumbra.Config.SortFoldersFirst ? SortMode.FoldersFirst : SortMode.Lexicographical;
protected override void DrawLeafName( FileSystem< Mod >.Leaf leaf, in ModState state, bool selected )
{
var flags = selected ? ImGuiTreeNodeFlags.Selected | LeafFlags : LeafFlags;
using var c = ImRaii.PushColor( ImGuiCol.Text, state.Color );
using var _ = ImRaii.TreeNode( leaf.Value.Meta.Name, flags );
}
}

View file

@ -1,24 +1,37 @@
using System.Diagnostics; using System.Runtime.InteropServices;
using ImGuiNET; using OtterGui.Raii;
using Penumbra.Mods;
namespace Penumbra.UI namespace Penumbra.UI;
[StructLayout( LayoutKind.Sequential, Pack = 1 )]
public struct ModState
{ {
public partial class SettingsInterface public uint Color;
{ }
private class TabBrowser
{
[Conditional( "LEAVEMEALONE" )]
public void Draw()
{
var ret = ImGui.BeginTabItem( "Available Mods" );
if( !ret )
{
return;
}
ImGui.Text( "woah" ); public partial class SettingsInterface
ImGui.EndTabItem(); {
private class TabBrowser
{
private readonly ModFileSystemA _fileSystem;
private readonly ModFileSystemSelector _selector;
public TabBrowser()
{
_fileSystem = ModFileSystemA.Load();
_selector = new ModFileSystemSelector( _fileSystem );
}
public void Draw()
{
using var ret = ImRaii.TabItem( "Available Mods" );
if( !ret )
{
return;
} }
_selector.Draw( 400 );
} }
} }
} }

View file

@ -3,6 +3,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using ImGuiNET; using ImGuiNET;
using OtterGui.Raii;
using Penumbra.Api; using Penumbra.Api;
using Penumbra.UI.Custom; using Penumbra.UI.Custom;
using CharacterUtility = Penumbra.Interop.CharacterUtility; using CharacterUtility = Penumbra.Interop.CharacterUtility;
@ -12,6 +13,17 @@ namespace Penumbra.UI;
public partial class SettingsInterface public partial class SettingsInterface
{ {
private string ImGuiIdTester = string.Empty;
private void DrawImGuiIdTester()
{
ImGui.SetNextItemWidth( 200 );
ImGui.InputText( "##abc1", ref ImGuiIdTester, 32 );
ImGui.SameLine();
ImGui.Text( ImGui.GetID( ImGuiIdTester ).ToString( "X" ) );
}
private static void PrintValue( string name, string value ) private static void PrintValue( string name, string value )
{ {
ImGui.TableNextRow(); ImGui.TableNextRow();
@ -289,6 +301,16 @@ public partial class SettingsInterface
} }
} }
private void DrawDebugTabUtility()
{
if( !ImGui.CollapsingHeader( "Utilities##Debug" ) )
{
return;
}
DrawImGuiIdTester();
}
private void DrawDebugTab() private void DrawDebugTab()
{ {
if( !ImGui.BeginTabItem( "Debug Tab" ) ) if( !ImGui.BeginTabItem( "Debug Tab" ) )
@ -324,5 +346,7 @@ public partial class SettingsInterface
ImGui.NewLine(); ImGui.NewLine();
DrawDebugTabIpc(); DrawDebugTabIpc();
ImGui.NewLine(); ImGui.NewLine();
DrawDebugTabUtility();
ImGui.NewLine();
} }
} }

View file

@ -3,6 +3,7 @@ using System.IO;
using System.Linq; using System.Linq;
using Dalamud.Interface; using Dalamud.Interface;
using ImGuiNET; using ImGuiNET;
using OtterGui;
using Penumbra.Collections; using Penumbra.Collections;
using Penumbra.GameData.ByteString; using Penumbra.GameData.ByteString;
using Penumbra.GameData.Util; using Penumbra.GameData.Util;

View file

@ -1,50 +1,55 @@
using System; using System;
namespace Penumbra.UI namespace Penumbra.UI;
[Flags]
public enum ModFilter
{ {
[Flags] Enabled = 1 << 0,
public enum ModFilter Disabled = 1 << 1,
{ NoConflict = 1 << 2,
Enabled = 1 << 0, SolvedConflict = 1 << 3,
Disabled = 1 << 1, UnsolvedConflict = 1 << 4,
NoConflict = 1 << 2, HasNoMetaManipulations = 1 << 5,
SolvedConflict = 1 << 3, HasMetaManipulations = 1 << 6,
UnsolvedConflict = 1 << 4, HasNoFileSwaps = 1 << 7,
HasNoMetaManipulations = 1 << 5, HasFileSwaps = 1 << 8,
HasMetaManipulations = 1 << 6, HasConfig = 1 << 9,
HasNoFileSwaps = 1 << 7, HasNoConfig = 1 << 10,
HasFileSwaps = 1 << 8, HasNoFiles = 1 << 11,
HasConfig = 1 << 9, HasFiles = 1 << 12,
HasNoConfig = 1 << 10, IsNew = 1 << 13,
HasNoFiles = 1 << 11, NotNew = 1 << 14,
HasFiles = 1 << 12, Inherited = 1 << 15,
IsNew = 1 << 13, Uninherited = 1 << 16,
NotNew = 1 << 14, Undefined = 1 << 17,
}; };
public static class ModFilterExtensions public static class ModFilterExtensions
{ {
public const ModFilter UnfilteredStateMods = ( ModFilter )( ( 1 << 15 ) - 1 ); public const ModFilter UnfilteredStateMods = ( ModFilter )( ( 1 << 18 ) - 1 );
public static string ToName( this ModFilter filter ) public static string ToName( this ModFilter filter )
=> filter switch => filter switch
{ {
ModFilter.Enabled => "Enabled", ModFilter.Enabled => "Enabled",
ModFilter.Disabled => "Disabled", ModFilter.Disabled => "Disabled",
ModFilter.NoConflict => "No Conflicts", ModFilter.NoConflict => "No Conflicts",
ModFilter.SolvedConflict => "Solved Conflicts", ModFilter.SolvedConflict => "Solved Conflicts",
ModFilter.UnsolvedConflict => "Unsolved Conflicts", ModFilter.UnsolvedConflict => "Unsolved Conflicts",
ModFilter.HasNoMetaManipulations => "No Meta Manipulations", ModFilter.HasNoMetaManipulations => "No Meta Manipulations",
ModFilter.HasMetaManipulations => "Meta Manipulations", ModFilter.HasMetaManipulations => "Meta Manipulations",
ModFilter.HasNoFileSwaps => "No File Swaps", ModFilter.HasNoFileSwaps => "No File Swaps",
ModFilter.HasFileSwaps => "File Swaps", ModFilter.HasFileSwaps => "File Swaps",
ModFilter.HasNoConfig => "No Configuration", ModFilter.HasNoConfig => "No Configuration",
ModFilter.HasConfig => "Configuration", ModFilter.HasConfig => "Configuration",
ModFilter.HasNoFiles => "No Files", ModFilter.HasNoFiles => "No Files",
ModFilter.HasFiles => "Files", ModFilter.HasFiles => "Files",
ModFilter.IsNew => "Newly Imported", ModFilter.IsNew => "Newly Imported",
ModFilter.NotNew => "Not Newly Imported", ModFilter.NotNew => "Not Newly Imported",
_ => throw new ArgumentOutOfRangeException( nameof( filter ), filter, null ), ModFilter.Inherited => "Inherited Configuration",
}; ModFilter.Uninherited => "Own Configuration",
} ModFilter.Undefined => "Not Configured",
_ => throw new ArgumentOutOfRangeException( nameof( filter ), filter, null ),
};
} }

View file

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Dalamud.Logging; using Dalamud.Logging;
using OtterGui;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.Util; using Penumbra.Util;
@ -9,12 +10,7 @@ namespace Penumbra.UI;
public class ModListCache : IDisposable public class ModListCache : IDisposable
{ {
public const uint NewModColor = 0xFF66DD66u; private readonly Mod.Manager _manager;
public const uint DisabledModColor = 0xFF666666u;
public const uint ConflictingModColor = 0xFFAAAAFFu;
public const uint HandledConflictModColor = 0xFF88DDDDu;
private readonly Mods.Mod.Manager _manager;
private readonly List< FullMod > _modsInOrder = new(); private readonly List< FullMod > _modsInOrder = new();
private readonly List< (bool visible, uint color) > _visibleMods = new(); private readonly List< (bool visible, uint color) > _visibleMods = new();
@ -24,10 +20,11 @@ public class ModListCache : IDisposable
private LowerString _modFilter = LowerString.Empty; private LowerString _modFilter = LowerString.Empty;
private LowerString _modFilterAuthor = LowerString.Empty; private LowerString _modFilterAuthor = LowerString.Empty;
private LowerString _modFilterChanges = LowerString.Empty; private LowerString _modFilterChanges = LowerString.Empty;
private ModFilter _stateFilter = ModFilterExtensions.UnfilteredStateMods;
private bool _listResetNecessary;
private bool _filterResetNecessary;
private bool _listResetNecessary;
private bool _filterResetNecessary;
private ModFilter _stateFilter = ModFilterExtensions.UnfilteredStateMods;
public ModFilter StateFilter public ModFilter StateFilter
{ {
@ -43,7 +40,7 @@ public class ModListCache : IDisposable
} }
} }
public ModListCache( Mods.Mod.Manager manager, IReadOnlySet< string > newMods ) public ModListCache( Mod.Manager manager, IReadOnlySet< string > newMods )
{ {
_manager = manager; _manager = manager;
_newMods = newMods; _newMods = newMods;
@ -281,7 +278,7 @@ public class ModListCache : IDisposable
return ret; return ret;
} }
ret.Item2 = ret.Item2 == 0 ? DisabledModColor : ret.Item2; ret.Item2 = ret.Item2 == 0 ? Colors.DisabledModColor : ret.Item2;
} }
if( mod.Settings.Enabled && !StateFilter.HasFlag( ModFilter.Enabled ) ) if( mod.Settings.Enabled && !StateFilter.HasFlag( ModFilter.Enabled ) )
@ -299,7 +296,7 @@ public class ModListCache : IDisposable
return ret; return ret;
} }
ret.Item2 = ret.Item2 == 0 ? ConflictingModColor : ret.Item2; ret.Item2 = ret.Item2 == 0 ? Colors.ConflictingModColor : ret.Item2;
} }
else else
{ {
@ -308,7 +305,7 @@ public class ModListCache : IDisposable
return ret; return ret;
} }
ret.Item2 = ret.Item2 == 0 ? HandledConflictModColor : ret.Item2; ret.Item2 = ret.Item2 == 0 ? Colors.HandledConflictModColor : ret.Item2;
} }
} }
else if( !StateFilter.HasFlag( ModFilter.NoConflict ) ) else if( !StateFilter.HasFlag( ModFilter.NoConflict ) )
@ -319,7 +316,7 @@ public class ModListCache : IDisposable
ret.Item1 = true; ret.Item1 = true;
if( isNew ) if( isNew )
{ {
ret.Item2 = NewModColor; ret.Item2 = Colors.NewModColor;
} }
SetFolderAndParentsVisible( mod.Data.Order.ParentFolder ); SetFolderAndParentsVisible( mod.Data.Order.ParentFolder );

View file

@ -217,18 +217,18 @@ public partial class SettingsInterface
ImGui.Text( "Enabled in the current collection." ); ImGui.Text( "Enabled in the current collection." );
ImGui.Bullet(); ImGui.Bullet();
ImGui.SameLine(); ImGui.SameLine();
ImGui.TextColored( ImGui.ColorConvertU32ToFloat4( ModListCache.DisabledModColor ), "Disabled in the current collection." ); ImGui.TextColored( ImGui.ColorConvertU32ToFloat4( Colors.DisabledModColor ), "Disabled in the current collection." );
ImGui.Bullet(); ImGui.Bullet();
ImGui.SameLine(); ImGui.SameLine();
ImGui.TextColored( ImGui.ColorConvertU32ToFloat4( ModListCache.NewModColor ), ImGui.TextColored( ImGui.ColorConvertU32ToFloat4( Colors.NewModColor ),
"Newly imported during this session. Will go away when first enabling a mod or when Penumbra is reloaded." ); "Newly imported during this session. Will go away when first enabling a mod or when Penumbra is reloaded." );
ImGui.Bullet(); ImGui.Bullet();
ImGui.SameLine(); ImGui.SameLine();
ImGui.TextColored( ImGui.ColorConvertU32ToFloat4( ModListCache.HandledConflictModColor ), ImGui.TextColored( ImGui.ColorConvertU32ToFloat4( Colors.HandledConflictModColor ),
"Enabled and conflicting with another enabled Mod, but on different priorities (i.e. the conflict is solved)." ); "Enabled and conflicting with another enabled Mod, but on different priorities (i.e. the conflict is solved)." );
ImGui.Bullet(); ImGui.Bullet();
ImGui.SameLine(); ImGui.SameLine();
ImGui.TextColored( ImGui.ColorConvertU32ToFloat4( ModListCache.ConflictingModColor ), ImGui.TextColored( ImGui.ColorConvertU32ToFloat4( Colors.ConflictingModColor ),
"Enabled and conflicting with another enabled Mod on the same priority." ); "Enabled and conflicting with another enabled Mod on the same priority." );
ImGui.Unindent(); ImGui.Unindent();
ImGui.BulletText( "Right-click a mod to enter its sort order, which is its name by default." ); ImGui.BulletText( "Right-click a mod to enter its sort order, which is its name by default." );

View file

@ -235,7 +235,8 @@ public partial class SettingsInterface
} }
ImGui.SameLine(); ImGui.SameLine();
ImGuiComponents.HelpMarker( "Enables other applications, e.g. Anamnesis, to use some Penumbra functions, like requesting redraws." ); ImGuiComponents.HelpMarker(
"Enables other applications, e.g. Anamnesis, to use some Penumbra functions, like requesting redraws." );
} }
private static void DrawReloadResourceButton() private static void DrawReloadResourceButton()
@ -342,7 +343,6 @@ public partial class SettingsInterface
} }
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem ); using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
DrawRootFolder(); DrawRootFolder();
DrawRediscoverButton(); DrawRediscoverButton();

View file

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Linq;
using Dalamud.Logging; using Dalamud.Logging;
namespace Penumbra.Util; namespace Penumbra.Util;
@ -119,7 +120,7 @@ public static class Backup
{ {
using var fileStream = File.Open( fileName, FileMode.Create ); using var fileStream = File.Open( fileName, FileMode.Create );
using var zip = new ZipArchive( fileStream, ZipArchiveMode.Create ); using var zip = new ZipArchive( fileStream, ZipArchiveMode.Create );
foreach( var file in files ) foreach( var file in files.Where( f => File.Exists( f.FullName ) ) )
{ {
zip.CreateEntryFromFile( file.FullName, Path.GetRelativePath( configDirectory, file.FullName ), CompressionLevel.Optimal ); zip.CreateEntryFromFile( file.FullName, Path.GetRelativePath( configDirectory, file.FullName ), CompressionLevel.Optimal );
} }

View file

@ -1,122 +0,0 @@
using System;
using ImGuiNET;
using Newtonsoft.Json;
namespace Penumbra.Util;
[JsonConverter( typeof( Converter ) )]
public readonly struct LowerString : IEquatable< LowerString >, IComparable< LowerString >
{
public static readonly LowerString Empty = new(string.Empty);
public readonly string Text = string.Empty;
public readonly string Lower = string.Empty;
public LowerString( string text )
{
Text = string.Intern( text );
Lower = string.Intern( text.ToLowerInvariant() );
}
public int Length
=> Text.Length;
public int Count
=> Length;
public bool Equals( LowerString other )
=> string.Equals( Lower, other.Lower, StringComparison.InvariantCulture );
public bool Equals( string other )
=> string.Equals( Lower, other, StringComparison.InvariantCultureIgnoreCase );
public int CompareTo( LowerString other )
=> string.Compare( Lower, other.Lower, StringComparison.InvariantCulture );
public int CompareTo( string other )
=> string.Compare( Lower, other, StringComparison.InvariantCultureIgnoreCase );
public bool Contains( LowerString other )
=> Lower.Contains( other.Lower, StringComparison.InvariantCulture );
public bool Contains( string other )
=> Lower.Contains( other, StringComparison.InvariantCultureIgnoreCase );
public bool StartsWith( LowerString other )
=> Lower.StartsWith( other.Lower, StringComparison.InvariantCulture );
public bool StartsWith( string other )
=> Lower.StartsWith( other, StringComparison.InvariantCultureIgnoreCase );
public bool EndsWith( LowerString other )
=> Lower.EndsWith( other.Lower, StringComparison.InvariantCulture );
public bool EndsWith( string other )
=> Lower.EndsWith( other, StringComparison.InvariantCultureIgnoreCase );
public override string ToString()
=> Text;
public static implicit operator string( LowerString s )
=> s.Text;
public static implicit operator LowerString( string s )
=> new(s);
private class Converter : JsonConverter< LowerString >
{
public override void WriteJson( JsonWriter writer, LowerString value, JsonSerializer serializer )
{
writer.WriteValue( value.Text );
}
public override LowerString ReadJson( JsonReader reader, Type objectType, LowerString existingValue, bool hasExistingValue,
JsonSerializer serializer )
{
if( reader.Value is string text )
{
return new LowerString( text );
}
return existingValue;
}
}
public static bool InputWithHint( string label, string hint, ref LowerString s, uint maxLength = 128,
ImGuiInputTextFlags flags = ImGuiInputTextFlags.None )
{
var tmp = s.Text;
if( !ImGui.InputTextWithHint( label, hint, ref tmp, maxLength, flags ) || tmp == s.Text )
{
return false;
}
s = new LowerString( tmp );
return true;
}
public override bool Equals( object? obj )
=> obj is LowerString lowerString && Equals( lowerString );
public override int GetHashCode()
=> Text.GetHashCode();
public static bool operator ==( LowerString lhs, LowerString rhs )
=> lhs.Equals( rhs );
public static bool operator !=( LowerString lhs, LowerString rhs )
=> lhs.Equals( rhs );
public static bool operator ==( LowerString lhs, string rhs )
=> lhs.Equals( rhs );
public static bool operator !=( LowerString lhs, string rhs )
=> lhs.Equals( rhs );
public static bool operator ==( string lhs, LowerString rhs )
=> rhs.Equals( lhs );
public static bool operator !=( string lhs, LowerString rhs )
=> rhs.Equals( lhs );
}

View file

@ -26,7 +26,7 @@ public static class ModelChanger
&& Encoding.UTF8.GetByteCount( to ) == to.Length; && Encoding.UTF8.GetByteCount( to ) == to.Length;
[Conditional( "Debug" )] [Conditional( "DEBUG" )]
private static void WriteBackup( string name, byte[] text ) private static void WriteBackup( string name, byte[] text )
=> File.WriteAllBytes( name + ".bak", text ); => File.WriteAllBytes( name + ".bak", text );