diff --git a/Penumbra/UI/Custom/ImGuiFramedGroup.cs b/Penumbra/UI/Custom/ImGuiFramedGroup.cs index 74e00b29..f7a6a5b7 100644 --- a/Penumbra/UI/Custom/ImGuiFramedGroup.cs +++ b/Penumbra/UI/Custom/ImGuiFramedGroup.cs @@ -8,13 +8,13 @@ namespace Penumbra.UI.Custom public static partial class ImGuiCustom { public static void BeginFramedGroup( string label ) - => BeginFramedGroupInternal( ref label, ZeroVector, false ); + => BeginFramedGroupInternal( ref label, Vector2.Zero, false ); public static void BeginFramedGroup( string label, Vector2 minSize ) => BeginFramedGroupInternal( ref label, minSize, false ); public static bool BeginFramedGroupEdit( ref string label ) - => BeginFramedGroupInternal( ref label, ZeroVector, true ); + => BeginFramedGroupInternal( ref label, Vector2.Zero, true ); public static bool BeginFramedGroupEdit( ref string label, Vector2 minSize ) => BeginFramedGroupInternal( ref label, minSize, true ); @@ -27,8 +27,8 @@ namespace Penumbra.UI.Custom ImGui.BeginGroup(); // First group - ImGui.PushStyleVar( ImGuiStyleVar.FramePadding, ZeroVector ); - ImGui.PushStyleVar( ImGuiStyleVar.ItemSpacing, ZeroVector ); + ImGui.PushStyleVar( ImGuiStyleVar.FramePadding, Vector2.Zero ); + ImGui.PushStyleVar( ImGuiStyleVar.ItemSpacing, Vector2.Zero ); ImGui.BeginGroup(); // Second group @@ -39,7 +39,7 @@ namespace Penumbra.UI.Custom } // Ensure width. - ImGui.Dummy( new Vector2( effectiveSize.X, 0 ) ); + ImGui.Dummy( Vector2.UnitX * effectiveSize.X ); // Ensure left half boundary width/distance. ImGui.Dummy( halfFrameHeight ); @@ -64,7 +64,7 @@ namespace Penumbra.UI.Custom var labelMax = ImGui.GetItemRectMax(); ImGui.SameLine(); // Ensure height and distance to label. - ImGui.Dummy( new Vector2( 0, frameHeight + itemSpacing.Y ) ); + ImGui.Dummy( Vector2.UnitX * ( frameHeight + itemSpacing.Y ) ); ImGui.BeginGroup(); // Fourth Group. @@ -96,8 +96,8 @@ namespace Penumbra.UI.Custom ImGui.PopItemWidth(); - ImGui.PushStyleVar( ImGuiStyleVar.FramePadding, ZeroVector ); - ImGui.PushStyleVar( ImGuiStyleVar.ItemSpacing, ZeroVector ); + ImGui.PushStyleVar( ImGuiStyleVar.FramePadding, Vector2.Zero ); + ImGui.PushStyleVar( ImGuiStyleVar.ItemSpacing, Vector2.Zero ); ImGui.EndGroup(); // Close fourth group ImGui.EndGroup(); // Close third group @@ -106,19 +106,19 @@ namespace Penumbra.UI.Custom // Ensure right distance. ImGui.Dummy( halfFrameHeight ); // Ensure bottom distance - ImGui.Dummy( new Vector2( 0, frameHeight / 2 - itemSpacing.Y ) ); + ImGui.Dummy( Vector2.UnitX * ( frameHeight / 2 - itemSpacing.Y ) ); ImGui.EndGroup(); // Close second group var itemMin = ImGui.GetItemRectMin(); var itemMax = ImGui.GetItemRectMax(); - var (currentLabelMin, currentLabelMax) = LabelStack[ LabelStack.Count - 1 ]; + var (currentLabelMin, currentLabelMax) = LabelStack[ ^1 ]; LabelStack.RemoveAt( LabelStack.Count - 1 ); var halfFrame = new Vector2( frameHeight / 8, frameHeight / 2 ); currentLabelMin.X -= itemSpacing.X; currentLabelMax.X += itemSpacing.X; var frameMin = itemMin + halfFrame; - var frameMax = itemMax - new Vector2( halfFrame.X, 0 ); + var frameMax = itemMax - Vector2.UnitX * halfFrame.X; // Left DrawClippedRect( new Vector2( -float.MaxValue, -float.MaxValue ), new Vector2( currentLabelMin.X, float.MaxValue ), frameMin, @@ -136,13 +136,11 @@ namespace Penumbra.UI.Custom ImGui.PopStyleVar( 2 ); // This seems wrong? // ImGui.SetWindowSize( new Vector2( ImGui.GetWindowSize().X + frameHeight, ImGui.GetWindowSize().Y ) ); - ImGui.Dummy( ZeroVector ); + ImGui.Dummy( Vector2.Zero ); ImGui.EndGroup(); // Close first group } - private static readonly Vector2 ZeroVector = new( 0, 0 ); - private static readonly List< (Vector2, Vector2) > LabelStack = new(); } } \ No newline at end of file diff --git a/Penumbra/UI/Custom/ImGuiUtil.cs b/Penumbra/UI/Custom/ImGuiUtil.cs index 4020199c..7570de9d 100644 --- a/Penumbra/UI/Custom/ImGuiUtil.cs +++ b/Penumbra/UI/Custom/ImGuiUtil.cs @@ -1,4 +1,6 @@ +using System.Security.Cryptography.X509Certificates; using System.Windows.Forms; +using Dalamud.Interface; using ImGuiNET; namespace Penumbra.UI.Custom @@ -23,7 +25,7 @@ namespace Penumbra.UI.Custom { public static void VerticalDistance( float distance ) { - ImGui.SetCursorPosY( ImGui.GetCursorPosY() + distance ); + ImGui.SetCursorPosY( ImGui.GetCursorPosY() + distance * ImGuiHelpers.GlobalScale ); } public static void RightJustifiedText( float pos, string text ) @@ -39,4 +41,25 @@ namespace Penumbra.UI.Custom ImGui.SameLine( pos ); } } + + public static partial class ImGuiCustom + { + public static void HoverTooltip( string text ) + { + if( ImGui.IsItemHovered() ) + { + ImGui.SetTooltip( text ); + } + } + } + + public static partial class ImGuiCustom + { + public static void PrintIcon( FontAwesomeIcon icon ) + { + ImGui.PushFont( UiBuilder.IconFont ); + ImGui.TextUnformatted( icon.ToIconString() ); + ImGui.PopFont(); + } + } } \ No newline at end of file diff --git a/Penumbra/UI/Custom/Raii/Color.cs b/Penumbra/UI/Custom/Raii/Color.cs new file mode 100644 index 00000000..95541bd8 --- /dev/null +++ b/Penumbra/UI/Custom/Raii/Color.cs @@ -0,0 +1,52 @@ +using System; +using System.Numerics; +using ImGuiNET; + +namespace Penumbra.UI.Custom +{ + public static partial class ImGuiRaii + { + public static Color PushColor( ImGuiCol idx, uint color, bool condition = true ) + => new Color().Push( idx, color, condition ); + + public static Color PushColor( ImGuiCol idx, Vector4 color, bool condition = true ) + => new Color().Push( idx, color, condition ); + + public class Color : IDisposable + { + private int _count; + + public Color Push( ImGuiCol idx, uint color, bool condition = true ) + { + if( condition ) + { + ImGui.PushStyleColor( idx, color ); + ++_count; + } + + return this; + } + + public Color Push( ImGuiCol idx, Vector4 color, bool condition = true ) + { + if( condition ) + { + ImGui.PushStyleColor( idx, color ); + ++_count; + } + + return this; + } + + public void Pop( int num = 1 ) + { + num = Math.Min( num, _count ); + _count -= num; + ImGui.PopStyleColor( num ); + } + + public void Dispose() + => Pop( _count ); + } + } +} \ No newline at end of file diff --git a/Penumbra/UI/Custom/Raii/EndStack.cs b/Penumbra/UI/Custom/Raii/EndStack.cs new file mode 100644 index 00000000..ea1e03f9 --- /dev/null +++ b/Penumbra/UI/Custom/Raii/EndStack.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; + +namespace Penumbra.UI.Custom +{ + public static partial class ImGuiRaii + { + public static EndStack DeferredEnd( Action a, bool condition = true ) + => new EndStack().Push( a, condition ); + + public class EndStack : IDisposable + { + private readonly Stack< Action > _cleanActions = new(); + + public EndStack Push( Action a, bool condition = true ) + { + if( condition ) + { + _cleanActions.Push( a ); + } + + return this; + } + + + public EndStack Pop( int num = 1 ) + { + while( num-- > 0 && _cleanActions.TryPop( out var action ) ) + { + action.Invoke(); + } + + return this; + } + + public void Dispose() + => Pop( _cleanActions.Count ); + } + } +} \ No newline at end of file diff --git a/Penumbra/UI/Custom/Raii/Font.cs b/Penumbra/UI/Custom/Raii/Font.cs new file mode 100644 index 00000000..e9656d4d --- /dev/null +++ b/Penumbra/UI/Custom/Raii/Font.cs @@ -0,0 +1,39 @@ +using System; +using ImGuiNET; + +namespace Penumbra.UI.Custom +{ + public static partial class ImGuiRaii + { + public static Font PushFont( ImFontPtr font ) + => new( font ); + + public class Font : IDisposable + { + private int _count; + + public Font( ImFontPtr font ) + => Push( font ); + + public Font Push( ImFontPtr font ) + { + ImGui.PushFont( font ); + ++_count; + return this; + } + + public void Pop( int num = 1 ) + { + num = Math.Min( num, _count ); + _count -= num; + while( num-- > 0 ) + { + ImGui.PopFont(); + } + } + + public void Dispose() + => Pop( _count ); + } + } +} \ No newline at end of file diff --git a/Penumbra/UI/Custom/Raii/Indent.cs b/Penumbra/UI/Custom/Raii/Indent.cs new file mode 100644 index 00000000..da9abd8e --- /dev/null +++ b/Penumbra/UI/Custom/Raii/Indent.cs @@ -0,0 +1,72 @@ +using System; +using System.Diagnostics; +using Dalamud.Interface; +using ImGuiNET; + +namespace Penumbra.UI.Custom +{ + public static partial class ImGuiRaii + { + public static Indent PushIndent( float f, bool scaled = true, bool condition = true ) + => new Indent().Push( f, condition ); + + public static Indent PushIndent( int i = 1, bool scaled = true, bool condition = true ) + => new Indent().Push( i, condition ); + + public class Indent : IDisposable + { + private float _indentation; + + public Indent Push( float indent, bool scaled = true, bool condition = true ) + { + Debug.Assert( indent >= 0f ); + if( condition ) + { + if( scaled ) + { + indent *= ImGuiHelpers.GlobalScale; + } + + ImGui.Indent( indent ); + _indentation += indent; + } + + return this; + } + + public Indent Push( uint i = 1, bool scaled = true, bool condition = true ) + { + if( condition ) + { + var spacing = i * ImGui.GetStyle().IndentSpacing * ( scaled ? ImGuiHelpers.GlobalScale : 1f ); + ImGui.Indent( spacing ); + _indentation += spacing; + } + + return this; + } + + public void Pop( float indent, bool scaled = true ) + { + if( scaled ) + { + indent *= ImGuiHelpers.GlobalScale; + } + + Debug.Assert( indent >= 0f ); + ImGui.Unindent( indent ); + _indentation -= indent; + } + + public void Pop( uint i, bool scaled = true ) + { + var spacing = i * ImGui.GetStyle().IndentSpacing * ( scaled ? ImGuiHelpers.GlobalScale : 1f ); + ImGui.Unindent( spacing ); + _indentation += spacing; + } + + public void Dispose() + => Pop( _indentation, false ); + } + } +} \ No newline at end of file diff --git a/Penumbra/UI/Custom/Raii/Style.cs b/Penumbra/UI/Custom/Raii/Style.cs new file mode 100644 index 00000000..acc29ab6 --- /dev/null +++ b/Penumbra/UI/Custom/Raii/Style.cs @@ -0,0 +1,92 @@ +using System; +using System.Numerics; +using ImGuiNET; + +namespace Penumbra.UI.Custom +{ + public static partial class ImGuiRaii + { + public static Style PushStyle( ImGuiStyleVar idx, float value, bool condition = true ) + => new Style().Push( idx, value, condition ); + + public static Style PushStyle( ImGuiStyleVar idx, Vector2 value, bool condition = true ) + => new Style().Push( idx, value, condition ); + + public class Style : IDisposable + { + private int _count; + + [System.Diagnostics.Conditional( "DEBUG" )] + private static void CheckStyleIdx( ImGuiStyleVar idx, Type type ) + { + var shouldThrow = idx switch + { + ImGuiStyleVar.Alpha => type != typeof( float ), + ImGuiStyleVar.WindowPadding => type != typeof( Vector2 ), + ImGuiStyleVar.WindowRounding => type != typeof( float ), + ImGuiStyleVar.WindowBorderSize => type != typeof( float ), + ImGuiStyleVar.WindowMinSize => type != typeof( Vector2 ), + ImGuiStyleVar.WindowTitleAlign => type != typeof( Vector2 ), + ImGuiStyleVar.ChildRounding => type != typeof( float ), + ImGuiStyleVar.ChildBorderSize => type != typeof( float ), + ImGuiStyleVar.PopupRounding => type != typeof( float ), + ImGuiStyleVar.PopupBorderSize => type != typeof( float ), + ImGuiStyleVar.FramePadding => type != typeof( Vector2 ), + ImGuiStyleVar.FrameRounding => type != typeof( float ), + ImGuiStyleVar.FrameBorderSize => type != typeof( float ), + ImGuiStyleVar.ItemSpacing => type != typeof( Vector2 ), + ImGuiStyleVar.ItemInnerSpacing => type != typeof( Vector2 ), + ImGuiStyleVar.IndentSpacing => type != typeof( float ), + ImGuiStyleVar.CellPadding => type != typeof( Vector2 ), + ImGuiStyleVar.ScrollbarSize => type != typeof( float ), + ImGuiStyleVar.ScrollbarRounding => type != typeof( float ), + ImGuiStyleVar.GrabMinSize => type != typeof( float ), + ImGuiStyleVar.GrabRounding => type != typeof( float ), + ImGuiStyleVar.TabRounding => type != typeof( float ), + ImGuiStyleVar.ButtonTextAlign => type != typeof( Vector2 ), + ImGuiStyleVar.SelectableTextAlign => type != typeof( Vector2 ), + _ => throw new ArgumentOutOfRangeException( nameof( idx ), idx, null ), + }; + + if( shouldThrow ) + { + throw new ArgumentException( $"Unable to push {type} to {idx}." ); + } + } + + public Style Push( ImGuiStyleVar idx, float value, bool condition = true ) + { + if( condition ) + { + CheckStyleIdx( idx, typeof( float ) ); + ImGui.PushStyleVar( idx, value ); + ++_count; + } + + return this; + } + + public Style Push( ImGuiStyleVar idx, Vector2 value, bool condition = true ) + { + if( condition ) + { + CheckStyleIdx( idx, typeof( Vector2 ) ); + ImGui.PushStyleVar( idx, value ); + ++_count; + } + + return this; + } + + public void Pop( int num = 1 ) + { + num = Math.Min( num, _count ); + _count -= num; + ImGui.PopStyleVar( num ); + } + + public void Dispose() + => Pop( _count ); + } + } +} \ No newline at end of file diff --git a/Penumbra/UI/MenuBar.cs b/Penumbra/UI/MenuBar.cs index 4fdb464f..5c3c6e41 100644 --- a/Penumbra/UI/MenuBar.cs +++ b/Penumbra/UI/MenuBar.cs @@ -1,4 +1,5 @@ using ImGuiNET; +using Penumbra.UI.Custom; namespace Penumbra.UI { @@ -30,28 +31,30 @@ namespace Penumbra.UI return; } - if( ImGui.BeginMenu( MenuLabel ) ) + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndMainMenuBar ); + + if( !ImGui.BeginMenu( MenuLabel ) ) { - if( ImGui.MenuItem( MenuItemToggle, SlashCommand, _base._menu.Visible ) ) - { - _base.FlipVisibility(); - } - - if( ImGui.MenuItem( MenuItemRediscover ) ) - { - _base.ReloadMods(); - } -#if DEBUG - if( ImGui.MenuItem( MenuItemHide ) ) - { - _showDebugBar = false; - } -#endif - - ImGui.EndMenu(); + return; } - ImGui.EndMainMenuBar(); + raii.Push( ImGui.EndMenu ); + + if( ImGui.MenuItem( MenuItemToggle, SlashCommand, _base._menu.Visible ) ) + { + _base.FlipVisibility(); + } + + if( ImGui.MenuItem( MenuItemRediscover ) ) + { + _base.ReloadMods(); + } +#if DEBUG + if( ImGui.MenuItem( MenuItemHide ) ) + { + _showDebugBar = false; + } +#endif } } } diff --git a/Penumbra/UI/MenuTabs/TabCollections.cs b/Penumbra/UI/MenuTabs/TabCollections.cs index 9e73be70..ab362bad 100644 --- a/Penumbra/UI/MenuTabs/TabCollections.cs +++ b/Penumbra/UI/MenuTabs/TabCollections.cs @@ -7,6 +7,7 @@ using Dalamud.Logging; using ImGuiNET; using Penumbra.Mod; using Penumbra.Mods; +using Penumbra.UI.Custom; using Penumbra.Util; namespace Penumbra.UI @@ -97,12 +98,7 @@ namespace Penumbra.UI { ImGui.InputTextWithHint( "##New Collection", "New Collection", ref _newCollectionName, 64 ); - var changedStyle = false; - if( _newCollectionName.Length == 0 ) - { - changedStyle = true; - ImGui.PushStyleVar( ImGuiStyleVar.Alpha, 0.5f ); - } + using var style = ImGuiRaii.PushStyle( ImGuiStyleVar.Alpha, 0.5f, _newCollectionName.Length == 0 ); if( ImGui.Button( "Create New Empty Collection" ) && _newCollectionName.Length > 0 ) { @@ -115,10 +111,7 @@ namespace Penumbra.UI CreateNewCollection( _manager.Collections.CurrentCollection.Settings ); } - if( changedStyle ) - { - ImGui.PopStyleVar(); - } + style.Pop(); if( _manager.Collections.Collections.Count > 1 && _manager.Collections.CurrentCollection.Name != ModCollection.DefaultCollection ) @@ -161,11 +154,8 @@ namespace Penumbra.UI { var index = _currentCollectionIndex; var combo = ImGui.Combo( LabelCurrentCollection, ref index, _collectionNames ); - if( tooltip && ImGui.IsItemHovered() ) - { - ImGui.SetTooltip( - "This collection will be modified when using the Installed Mods tab and making changes. It does not apply to anything by itself." ); - } + ImGuiCustom.HoverTooltip( + "This collection will be modified when using the Installed Mods tab and making changes. It does not apply to anything by itself." ); if( combo ) { @@ -182,15 +172,12 @@ namespace Penumbra.UI _currentDefaultIndex = index; } - if( ImGui.IsItemHovered() ) - { - ImGui.SetTooltip( - "Mods in the default collection are loaded for any character that is not explicitly named in the character collections below.\n" - + "They also take precedence before the forced collection." ); - } + ImGuiCustom.HoverTooltip( + "Mods in the default collection are loaded for any character that is not explicitly named in the character collections below.\n" + + "They also take precedence before the forced collection." ); ImGui.SameLine(); - ImGui.Dummy( new Vector2( 24, 0 ) ); + ImGuiHelpers.ScaledDummy( 24, 0 ); ImGui.SameLine(); ImGui.Text( "Default Collection" ); } @@ -204,15 +191,12 @@ namespace Penumbra.UI _currentForcedIndex = index; } - if( ImGui.IsItemHovered() ) - { - ImGui.SetTooltip( - "Mods in the forced collection are always loaded if not overwritten by anything in the current or character-based collection.\n" - + "Please avoid mixing meta-manipulating mods in Forced and other collections, as this will probably not work correctly." ); - } + ImGuiCustom.HoverTooltip( + "Mods in the forced collection are always loaded if not overwritten by anything in the current or character-based collection.\n" + + "Please avoid mixing meta-manipulating mods in Forced and other collections, as this will probably not work correctly." ); ImGui.SameLine(); - ImGui.Dummy( new Vector2( 24, 0 ) ); + ImGuiHelpers.ScaledDummy( 24, 0 ); ImGui.SameLine(); ImGui.Text( "Forced Collection" ); } @@ -221,12 +205,7 @@ namespace Penumbra.UI { ImGui.InputTextWithHint( "##New Character", "New Character Name", ref _newCharacterName, 32 ); - var changedStyle = false; - if( _newCharacterName.Length == 0 ) - { - changedStyle = true; - ImGui.PushStyleVar( ImGuiStyleVar.Alpha, 0.5f ); - } + using var style = ImGuiRaii.PushStyle( ImGuiStyleVar.Alpha, 0.5f, _newCharacterName.Length == 0 ); ImGui.SameLine(); if( ImGui.Button( "Create New Character Collection" ) && _newCharacterName.Length > 0 ) @@ -236,25 +215,19 @@ namespace Penumbra.UI _newCharacterName = string.Empty; } - if( ImGui.IsItemHovered() ) - { - ImGui.SetTooltip( - "A character collection will be used whenever you manually redraw a character with the Name you have set up.\n" - + "If you enable automatic character redraws in the Settings tab, penumbra will try to use Character collections for corresponding characters automatically.\n" ); - } + style.Pop(); - if( changedStyle ) - { - ImGui.PopStyleVar(); - } + ImGuiCustom.HoverTooltip( + "A character collection will be used whenever you manually redraw a character with the Name you have set up.\n" + + "If you enable automatic character redraws in the Settings tab, penumbra will try to use Character collections for corresponding characters automatically.\n" ); } private void DrawCharacterCollectionSelectors() { + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndChild ); if( !ImGui.BeginChild( "##CollectionChild", AutoFillSize, true ) ) { - ImGui.EndChild(); return; } @@ -272,21 +245,20 @@ namespace Penumbra.UI } ImGui.SameLine(); - ImGui.PushFont( UiBuilder.IconFont ); + using var font = ImGuiRaii.PushFont( UiBuilder.IconFont ); if( ImGui.Button( $"{FontAwesomeIcon.Trash.ToIconString()}##{name}" ) ) { _manager.Collections.RemoveCharacterCollection( name ); } - ImGui.PopFont(); + font.Pop(); ImGui.SameLine(); ImGui.Text( name ); } DrawNewCharacterCollection(); - ImGui.EndChild(); } public void Draw() @@ -296,19 +268,20 @@ namespace Penumbra.UI return; } + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem ) + .Push( ImGui.EndChild ); + if( ImGui.BeginChild( "##CollectionHandling", new Vector2( -1, ImGui.GetTextLineHeightWithSpacing() * 6 ), true ) ) { DrawCurrentCollectionSelector( true ); - ImGui.Dummy( new Vector2( 0, 10 ) ); + ImGuiHelpers.ScaledDummy( 0, 10 ); DrawNewCollectionInput(); } - ImGui.EndChild(); + raii.Pop(); DrawCharacterCollectionSelectors(); - - ImGui.EndTabItem(); } } } diff --git a/Penumbra/UI/MenuTabs/TabDebug.cs b/Penumbra/UI/MenuTabs/TabDebug.cs index 28f939b6..0b826ad5 100644 --- a/Penumbra/UI/MenuTabs/TabDebug.cs +++ b/Penumbra/UI/MenuTabs/TabDebug.cs @@ -13,6 +13,7 @@ using Penumbra.GameData.Util; using Penumbra.Interop; using Penumbra.Meta; using Penumbra.Mods; +using Penumbra.UI.Custom; using Penumbra.Util; namespace Penumbra.UI @@ -38,6 +39,8 @@ namespace Penumbra.UI return; } + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTable ); + var identifier = GameData.GameData.GetIdentifier(); foreach( var (actor, equip) in players ) @@ -109,8 +112,6 @@ namespace Penumbra.UI ImGui.Text( identifier.Identify( equip.RFinger.Set, 0, equip.RFinger.Variant, EquipSlot.LFinger )?.Name.ToString() ?? "Unknown" ); // @formatter:on } - - ImGui.EndTable(); } private static void PrintValue( string name, string value ) @@ -135,6 +136,8 @@ namespace Penumbra.UI return; } + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTable ); + var manager = Service< ModManager >.Get(); PrintValue( "Active Collection", manager.Collections.ActiveCollection.Name ); PrintValue( "Mod Manager BasePath", manager.BasePath.Name ); @@ -147,8 +150,6 @@ namespace Penumbra.UI ( !Penumbra.Config.TempDirectory.Any() || Path.IsPathRooted( Penumbra.Config.TempDirectory ) ).ToString() ); PrintValue( "Mod Manager Temp Path Exists", Directory.Exists( manager.TempPath.FullName ).ToString() ); PrintValue( "Mod Manager Temp Path IsWritable", manager.TempWritable.ToString() ); - - ImGui.EndTable(); } private void DrawDebugTabRedraw() @@ -207,9 +208,11 @@ namespace Penumbra.UI .GetField( "_inGPose", BindingFlags.Instance | BindingFlags.NonPublic ) ?.GetValue( _penumbra.ObjectReloader ); + using var raii = new ImGuiRaii.EndStack(); if( ImGui.BeginTable( "##RedrawData", 2, ImGuiTableFlags.SizingFixedFit, new Vector2( -1, ImGui.GetTextLineHeightWithSpacing() * 7 ) ) ) { + raii.Push( ImGui.EndTable ); PrintValue( "Current Wait Frame", waitFrames?.ToString() ?? "null" ); PrintValue( "Current Frame", currentFrame?.ToString() ?? "null" ); PrintValue( "Currently in GPose", gPose?.ToString() ?? "null" ); @@ -222,13 +225,13 @@ namespace Penumbra.UI PrintValue( "Current Object Address", currentObject?.Address.ToString( "X16" ) ?? "null" ); PrintValue( "Current Object Index", currentObjectIdx >= 0 ? currentObjectIdx.ToString() : "null" ); PrintValue( "Current Object Render Flags", ( ( int? )currentRender )?.ToString( "X8" ) ?? "null" ); - ImGui.EndTable(); } if( queue.Any() && ImGui.BeginTable( "##RedrawTable", 3, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.ScrollX, new Vector2( -1, ImGui.GetTextLineHeightWithSpacing() * queue.Count ) ) ) { + raii.Push( ImGui.EndTable ); foreach( var (objectId, objectName, redraw) in queue ) { ImGui.TableNextRow(); @@ -239,8 +242,6 @@ namespace Penumbra.UI ImGui.TableNextColumn(); ImGui.Text( redraw.ToString() ); } - - ImGui.EndTable(); } if( queue.Any() && ImGui.Button( "Clear" ) ) @@ -263,6 +264,8 @@ namespace Penumbra.UI return; } + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTable ); + foreach( var collection in Service< ModManager >.Get().Collections.Collections.Values.Where( c => c.Cache != null ) ) { var manip = collection.Cache!.MetaManipulations; @@ -285,39 +288,58 @@ namespace Penumbra.UI ImGui.Text( info.Changed ? "Data Changed" : "Unchanged" ); } } - - ImGui.EndTable(); } private void DrawDebugTabIpc() { - if( !ImGui.CollapsingHeader( "IPC##Debug" ) ) { return; } var ipc = _penumbra.Ipc; - ImGui.Text($"API Version: {ipc.Api.ApiVersion}" ); - ImGui.Text("Available subscriptions:" ); - ImGui.Indent(); - if (ipc.ProviderApiVersion != null) + ImGui.Text( $"API Version: {ipc.Api.ApiVersion}" ); + ImGui.Text( "Available subscriptions:" ); + using var indent = ImGuiRaii.PushIndent(); + if( ipc.ProviderApiVersion != null ) + { ImGui.Text( PenumbraIpc.LabelProviderApiVersion ); + } + if( ipc.ProviderRedrawName != null ) + { ImGui.Text( PenumbraIpc.LabelProviderRedrawName ); + } + if( ipc.ProviderRedrawObject != null ) + { ImGui.Text( PenumbraIpc.LabelProviderRedrawObject ); + } + if( ipc.ProviderRedrawAll != null ) + { ImGui.Text( PenumbraIpc.LabelProviderRedrawAll ); + } + if( ipc.ProviderResolveDefault != null ) + { ImGui.Text( PenumbraIpc.LabelProviderResolveDefault ); + } + if( ipc.ProviderResolveCharacter != null ) + { ImGui.Text( PenumbraIpc.LabelProviderResolveCharacter ); + } + if( ipc.ProviderChangedItemTooltip != null ) + { ImGui.Text( PenumbraIpc.LabelProviderChangedItemTooltip ); + } + if( ipc.ProviderChangedItemClick != null ) + { ImGui.Text( PenumbraIpc.LabelProviderChangedItemClick ); - ImGui.Unindent(); + } } private void DrawDebugTab() @@ -327,6 +349,8 @@ namespace Penumbra.UI return; } + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem ); + DrawDebugTabGeneral(); ImGui.NewLine(); DrawDebugTabRedraw(); @@ -337,8 +361,6 @@ namespace Penumbra.UI ImGui.NewLine(); DrawDebugTabIpc(); ImGui.NewLine(); - - ImGui.EndTabItem(); } } } \ No newline at end of file diff --git a/Penumbra/UI/MenuTabs/TabEffective.cs b/Penumbra/UI/MenuTabs/TabEffective.cs index 70061097..8d46d86a 100644 --- a/Penumbra/UI/MenuTabs/TabEffective.cs +++ b/Penumbra/UI/MenuTabs/TabEffective.cs @@ -5,6 +5,7 @@ using ImGuiNET; using Penumbra.GameData.Util; using Penumbra.Meta; using Penumbra.Mods; +using Penumbra.UI.Custom; using Penumbra.Util; namespace Penumbra.UI @@ -13,9 +14,8 @@ namespace Penumbra.UI { private class TabEffective { - private const string LabelTab = "Effective Changes"; - private static readonly string LongArrowLeft = $"{( char )FontAwesomeIcon.LongArrowAltLeft}"; - private readonly ModManager _modManager; + private const string LabelTab = "Effective Changes"; + private readonly ModManager _modManager; private readonly float _leftTextLength = ImGui.CalcTextSize( "chara/human/c0000/obj/body/b0000/material/v0000/mt_c0000b0000_b.mtrl" ).X + 40; @@ -27,14 +27,12 @@ namespace Penumbra.UI private static void DrawFileLine( FileInfo file, GamePath path ) { ImGui.TableNextColumn(); - Custom.ImGuiCustom.CopyOnClickSelectable( path ); + ImGuiCustom.CopyOnClickSelectable( path ); ImGui.TableNextColumn(); - ImGui.PushFont( UiBuilder.IconFont ); - ImGui.TextUnformatted( LongArrowLeft ); - ImGui.PopFont(); + ImGuiCustom.PrintIcon( FontAwesomeIcon.LongArrowAltLeft ); ImGui.SameLine(); - Custom.ImGuiCustom.CopyOnClickSelectable( file.FullName ); + ImGuiCustom.CopyOnClickSelectable( file.FullName ); } private static void DrawManipulationLine( MetaManipulation manip, Mod.Mod mod ) @@ -43,9 +41,7 @@ namespace Penumbra.UI ImGui.Selectable( manip.IdentifierString() ); ImGui.TableNextColumn(); - ImGui.PushFont( UiBuilder.IconFont ); - ImGui.TextUnformatted( LongArrowLeft ); - ImGui.PopFont(); + ImGuiCustom.PrintIcon( FontAwesomeIcon.LongArrowAltLeft ); ImGui.SameLine(); ImGui.Selectable( mod.Data.Meta.Name ); } @@ -57,17 +53,19 @@ namespace Penumbra.UI return; } + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem ); + const ImGuiTableFlags flags = ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollX; - var activeCollection = _modManager.Collections.ActiveCollection.Cache; - var forcedCollection = _modManager.Collections.ForcedCollection.Cache; + var activeCollection = _modManager.Collections.ActiveCollection.Cache; + var forcedCollection = _modManager.Collections.ForcedCollection.Cache; var (activeResolved, activeMeta) = activeCollection != null ? ( activeCollection.ResolvedFiles.Count, activeCollection.MetaManipulations.Count ) : ( 0, 0 ); var (forcedResolved, forcedMeta) = forcedCollection != null - ? (forcedCollection.ResolvedFiles.Count, forcedCollection.MetaManipulations.Count) - : (0, 0); + ? ( forcedCollection.ResolvedFiles.Count, forcedCollection.MetaManipulations.Count ) + : ( 0, 0 ); var lines = activeResolved + forcedResolved + activeMeta + forcedMeta; ImGuiListClipperPtr clipper; @@ -80,6 +78,7 @@ namespace Penumbra.UI if( ImGui.BeginTable( "##effective_changes", 2, flags, AutoFillSize ) ) { + raii.Push( ImGui.EndTable ); ImGui.TableSetupColumn( "##tableGamePathCol", ImGuiTableColumnFlags.None, _leftTextLength ); while( clipper.Step() ) { @@ -89,32 +88,28 @@ namespace Penumbra.UI ImGui.TableNextRow(); if( row < activeResolved ) { - var file = activeCollection!.ResolvedFiles.ElementAt( row ); - DrawFileLine( file.Value, file.Key ); + var (gamePath, file) = activeCollection!.ResolvedFiles.ElementAt( row ); + DrawFileLine( file, gamePath ); } else if( ( row -= activeResolved ) < forcedResolved ) { - var file = forcedCollection!.ResolvedFiles.ElementAt( row ); - DrawFileLine( file.Value, file.Key ); + var (gamePath, file) = forcedCollection!.ResolvedFiles.ElementAt( row ); + DrawFileLine( file, gamePath ); } else if( ( row -= forcedResolved ) < activeMeta ) { - var manip = activeCollection!.MetaManipulations.Manipulations.ElementAt( row ); - DrawManipulationLine( manip.Item1, manip.Item2 ); + var (manip, mod) = activeCollection!.MetaManipulations.Manipulations.ElementAt( row ); + DrawManipulationLine( manip, mod ); } else { - row -= activeMeta; - var manip = forcedCollection!.MetaManipulations.Manipulations.ElementAt( row ); - DrawManipulationLine( manip.Item1, manip.Item2 ); + row -= activeMeta; + var (manip, mod) = forcedCollection!.MetaManipulations.Manipulations.ElementAt( row ); + DrawManipulationLine( manip, mod ); } } } - - ImGui.EndTable(); } - - ImGui.EndTabItem(); } } } diff --git a/Penumbra/UI/MenuTabs/TabImport.cs b/Penumbra/UI/MenuTabs/TabImport.cs index f34949ee..e0166852 100644 --- a/Penumbra/UI/MenuTabs/TabImport.cs +++ b/Penumbra/UI/MenuTabs/TabImport.cs @@ -8,6 +8,7 @@ using Dalamud.Logging; using ImGuiNET; using Penumbra.Importer; using Penumbra.Mods; +using Penumbra.UI.Custom; using Penumbra.Util; namespace Penumbra.UI @@ -104,20 +105,20 @@ namespace Penumbra.UI { if( !_manager.Valid ) { - ImGui.PushStyleVar( ImGuiStyleVar.Alpha, 0.5f ); + using var style = ImGuiRaii.PushStyle( ImGuiStyleVar.Alpha, 0.5f ); ImGui.Button( LabelImportButton ); - ImGui.PopStyleVar(); + style.Pop(); - ImGui.PushStyleColor( ImGuiCol.Text, ColorRed ); + 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() ); - ImGui.PopStyleColor(); + 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" ); - ImGui.PushStyleColor( ImGuiCol.Text, ColorYellow ); + color.Push( ImGuiCol.Text, ColorYellow ); ImGui.Text( " D:\\ffxivmods" ); - ImGui.PopStyleColor(); + color.Pop(); ImGui.Text( "You can return to this tab once you've done that." ); } else if( ImGui.Button( LabelImportButton ) ) @@ -156,19 +157,19 @@ namespace Penumbra.UI private void DrawFailedImportMessage() { - ImGui.PushStyleColor( ImGuiCol.Text, ColorRed ); + using var color = ImGuiRaii.PushColor( ImGuiCol.Text, ColorRed ); ImGui.Text( $"One or more of your modpacks failed to import:\n\t\t{_errorMessage}" ); - ImGui.PopStyleColor(); } public void Draw() { - var ret = ImGui.BeginTabItem( LabelTab ); - if( !ret ) + if( !ImGui.BeginTabItem( LabelTab ) ) { return; } + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem ); + if( !_isImportRunning ) { DrawImportButton(); @@ -182,8 +183,6 @@ namespace Penumbra.UI { DrawFailedImportMessage(); } - - ImGui.EndTabItem(); } } } diff --git a/Penumbra/UI/MenuTabs/TabInstalled/TabInstalled.cs b/Penumbra/UI/MenuTabs/TabInstalled/TabInstalled.cs index c44b9919..ae1764b5 100644 --- a/Penumbra/UI/MenuTabs/TabInstalled/TabInstalled.cs +++ b/Penumbra/UI/MenuTabs/TabInstalled/TabInstalled.cs @@ -1,5 +1,6 @@ using ImGuiNET; using Penumbra.Mods; +using Penumbra.UI.Custom; using Penumbra.Util; namespace Penumbra.UI @@ -34,6 +35,8 @@ namespace Penumbra.UI return; } + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem ); + if( _modManager.Mods.Count > 0 ) { Selector.Draw(); @@ -44,8 +47,6 @@ namespace Penumbra.UI { DrawNoModsAvailable(); } - - ImGui.EndTabItem(); } } } diff --git a/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledDetails.cs b/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledDetails.cs index 8a02ea0a..fd386d50 100644 --- a/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledDetails.cs +++ b/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledDetails.cs @@ -2,14 +2,15 @@ using System.IO; using System.Linq; using Dalamud.Interface; using ImGuiNET; -using Penumbra.Api; using Penumbra.GameData.Enums; using Penumbra.GameData.Util; using Penumbra.Meta; using Penumbra.Mod; using Penumbra.Mods; using Penumbra.Structs; +using Penumbra.UI.Custom; using Penumbra.Util; +using ImGui = ImGuiNET.ImGui; namespace Penumbra.UI { @@ -140,6 +141,8 @@ namespace Penumbra.UI return; } + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem ); + var desc = Meta.Description; var flags = _editMode ? ImGuiInputTextFlags.EnterReturnsTrue | ImGuiInputTextFlags.CtrlEnterForNewLine @@ -154,17 +157,12 @@ namespace Penumbra.UI _selector.SaveCurrentMod(); } - if( ImGui.IsItemHovered() ) - { - ImGui.SetTooltip( TooltipAboutEdit ); - } + ImGuiCustom.HoverTooltip( TooltipAboutEdit ); } else { ImGui.TextWrapped( desc ); } - - ImGui.EndTabItem(); } private void DrawChangedItemsTab() @@ -174,31 +172,33 @@ namespace Penumbra.UI return; } - if( ImGui.BeginListBox( LabelChangedItemsHeader, AutoFillSize ) ) + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem ); + + if( !ImGui.BeginListBox( LabelChangedItemsHeader, AutoFillSize ) ) { - foreach( var item in Mod.Data.ChangedItems ) - { - var ret = ImGui.Selectable( item.Key ) ? MouseButton.Left : MouseButton.None; - ret = ImGui.IsItemClicked( ImGuiMouseButton.Right ) ? MouseButton.Right : ret; - ret = ImGui.IsItemClicked( ImGuiMouseButton.Middle ) ? MouseButton.Middle : ret; - - if( ret != MouseButton.None ) - { - _base._penumbra.Api.InvokeClick( ret, item.Value ); - } - - if( _base._penumbra.Api.HasTooltip && ImGui.IsItemHovered() ) - { - ImGui.BeginTooltip(); - _base._penumbra.Api.InvokeTooltip( item.Value ); - ImGui.EndTooltip(); - } - } - - ImGui.EndListBox(); + return; } - ImGui.EndTabItem(); + raii.Push( ImGui.EndListBox ); + foreach( var (name, data) in Mod.Data.ChangedItems ) + { + var ret = ImGui.Selectable( name ) ? MouseButton.Left : MouseButton.None; + ret = ImGui.IsItemClicked( ImGuiMouseButton.Right ) ? MouseButton.Right : ret; + ret = ImGui.IsItemClicked( ImGuiMouseButton.Middle ) ? MouseButton.Middle : ret; + + if( ret != MouseButton.None ) + { + _base._penumbra.Api.InvokeClick( ret, data ); + } + + if( _base._penumbra.Api.HasTooltip && ImGui.IsItemHovered() ) + { + ImGui.BeginTooltip(); + raii.Push( ImGui.EndTooltip ); + _base._penumbra.Api.InvokeTooltip( data ); + raii.Pop(); + } + } } private void DrawConflictTab() @@ -208,38 +208,39 @@ namespace Penumbra.UI return; } + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem ); + ImGui.SetNextItemWidth( -1 ); - if( ImGui.BeginListBox( LabelConflictsHeader, AutoFillSize ) ) + if( !ImGui.BeginListBox( LabelConflictsHeader, AutoFillSize ) ) { - foreach( var kv in Mod.Cache.Conflicts ) - { - var mod = kv.Key; - if( ImGui.Selectable( mod.Data.Meta.Name ) ) - { - _selector.SelectModByDir( mod.Data.BasePath.Name ); - } - - ImGui.SameLine(); - ImGui.Text( $"(Priority {mod.Settings.Priority})" ); - - ImGui.Indent( 15 ); - foreach( var file in kv.Value.Files ) - { - ImGui.Selectable( file ); - } - - foreach( var manip in kv.Value.Manipulations ) - { - ImGui.Text( manip.IdentifierString() ); - } - - ImGui.Unindent( 15 ); - } - - ImGui.EndListBox(); + return; } - ImGui.EndTabItem(); + raii.Push( ImGui.EndListBox ); + using var indent = ImGuiRaii.PushIndent( 0 ); + foreach( var (mod, (files, manipulations)) in Mod.Cache.Conflicts ) + { + if( ImGui.Selectable( mod.Data.Meta.Name ) ) + { + _selector.SelectModByDir( mod.Data.BasePath.Name ); + } + + ImGui.SameLine(); + ImGui.Text( $"(Priority {mod.Settings.Priority})" ); + + indent.Push( 15f ); + foreach( var file in files ) + { + ImGui.Selectable( file ); + } + + foreach( var manip in manipulations ) + { + ImGui.Text( manip.IdentifierString() ); + } + + indent.Pop( 15f ); + } } private void DrawFileSwapTab() @@ -255,31 +256,31 @@ namespace Penumbra.UI 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 ) ) + if( !ImGui.BeginTable( LabelFileSwapHeader, 3, flags, AutoFillSize ) ) { - foreach( var file in Meta.FileSwaps ) - { - ImGui.TableNextColumn(); - Custom.ImGuiCustom.CopyOnClickSelectable( file.Key ); - - ImGui.TableNextColumn(); - ImGui.PushFont( UiBuilder.IconFont ); - ImGui.TextUnformatted( $"{( char )FontAwesomeIcon.LongArrowAltRight}" ); - ImGui.PopFont(); - - ImGui.TableNextColumn(); - Custom.ImGuiCustom.CopyOnClickSelectable( file.Value ); - - ImGui.TableNextRow(); - } - - ImGui.EndTable(); + return; } - ImGui.EndTabItem(); + raii.Push( ImGui.EndTable ); + + foreach( var (source, target) in Meta.FileSwaps ) + { + ImGui.TableNextColumn(); + ImGuiCustom.CopyOnClickSelectable( source ); + + ImGui.TableNextColumn(); + ImGuiCustom.PrintIcon( FontAwesomeIcon.LongArrowAltRight ); + + ImGui.TableNextColumn(); + ImGuiCustom.CopyOnClickSelectable( target ); + + ImGui.TableNextRow(); + } } private void UpdateFilenameList() @@ -329,30 +330,26 @@ namespace Penumbra.UI return; } - if( ImGui.IsItemHovered() ) - { - ImGui.SetTooltip( TooltipFilesTab ); - } + 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! ) { - ImGui.PushStyleColor( ImGuiCol.Text, color ); + colorRaii.Push( ImGuiCol.Text, color ); ImGui.Selectable( name.FullName ); - ImGui.PopStyleColor(); + colorRaii.Pop(); } - - ImGui.EndListBox(); } else { _fullFilenameList = null; } - - ImGui.EndTabItem(); } private static int HandleDefaultString( GamePath[] gamePaths, out int removeFolders ) @@ -469,10 +466,7 @@ namespace Penumbra.UI ImGui.SetNextItemWidth( -1 ); ImGui.InputTextWithHint( LabelGamePathsEditBox, "Hover for help...", ref _currentGamePaths, 128 ); - if( ImGui.IsItemHovered() ) - { - ImGui.SetTooltip( TooltipGamePathsEdit ); - } + ImGuiCustom.HoverTooltip( TooltipGamePathsEdit ); } private void DrawGroupRow() @@ -516,12 +510,11 @@ namespace Penumbra.UI loc = colorReplace; } - ImGui.PushStyleColor( ImGuiCol.Text, loc ); + using var colors = ImGuiRaii.PushColor( ImGuiCol.Text, loc ); ImGui.Selectable( _fullFilenameList[ idx ].name.FullName, ref _fullFilenameList[ idx ].selected ); - ImGui.PopStyleColor(); } - const float indent = 30f; + const float indentWidth = 30f; if( _selectedOption == null ) { Selectable( 0, ColorGreen ); @@ -534,8 +527,8 @@ namespace Penumbra.UI { Selectable( 0, ColorGreen ); - ImGui.Indent( indent ); - var tmpPaths = gamePaths.ToArray(); + using var indent = ImGuiRaii.PushIndent( indentWidth ); + var tmpPaths = gamePaths.ToArray(); foreach( var gamePath in tmpPaths ) { string tmp = gamePath; @@ -556,8 +549,6 @@ namespace Penumbra.UI _selector.ReloadCurrentMod(); } } - - ImGui.Unindent( indent ); } else { @@ -588,14 +579,13 @@ namespace Penumbra.UI return; } - Custom.ImGuiCustom.BeginFramedGroup( group.GroupName ); + 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}" ); } - - Custom.ImGuiCustom.EndFramedGroup(); } private void DrawSingleSelector( OptionGroup group ) @@ -635,79 +625,76 @@ namespace Penumbra.UI private void DrawConfigurationTab() { - if( !_editMode && !Meta.HasGroupsWithConfig ) + if( !_editMode && !Meta.HasGroupsWithConfig || !ImGui.BeginTabItem( LabelConfigurationTab ) ) { return; } - if( ImGui.BeginTabItem( LabelConfigurationTab ) ) + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem ); + if( _editMode ) { - if( _editMode ) - { - DrawGroupSelectorsEdit(); - } - else - { - DrawGroupSelectors(); - } - - ImGui.EndTabItem(); + DrawGroupSelectorsEdit(); + } + else + { + DrawGroupSelectors(); } } private void DrawMetaManipulationsTab() { - if( !_editMode && Mod.Data.Resources.MetaManipulations.Count == 0 ) + if( !_editMode && Mod.Data.Resources.MetaManipulations.Count == 0 || !ImGui.BeginTabItem( "Meta Manipulations" ) ) { return; } - if( !ImGui.BeginTabItem( "Meta Manipulations" ) ) + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem ); + + if( !ImGui.BeginListBox( "##MetaManipulations", AutoFillSize ) ) { return; } - if( ImGui.BeginListBox( "##MetaManipulations", AutoFillSize ) ) + raii.Push( ImGui.EndListBox ); + + var manips = Mod.Data.Resources.MetaManipulations; + var changes = false; + if( _editMode || manips.DefaultData.Count > 0 ) { - var manips = Mod.Data.Resources.MetaManipulations; - var changes = false; - if( _editMode || manips.DefaultData.Count > 0 ) + if( ImGui.CollapsingHeader( "Default" ) ) { - if( ImGui.CollapsingHeader( "Default" ) ) - { - changes = DrawMetaManipulationsTable( "##DefaultManips", manips.DefaultData, ref manips.Count ); - } + changes = DrawMetaManipulationsTable( "##DefaultManips", manips.DefaultData, ref manips.Count ); } - - foreach( var group in manips.GroupData ) - { - foreach( var option in group.Value ) - { - if( ImGui.CollapsingHeader( $"{group.Key} - {option.Key}" ) ) - { - changes |= DrawMetaManipulationsTable( $"##{group.Key}{option.Key}manips", option.Value, 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 ); - } - - ImGui.EndListBox(); } - ImGui.EndTabItem(); + 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; - ImGui.BeginTabBar( LabelPluginDetails ); + if( !ImGui.BeginTabBar( LabelPluginDetails ) ) + { + return; + } + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabBar ); DrawAboutTab(); DrawChangedItemsTab(); @@ -724,7 +711,6 @@ namespace Penumbra.UI DrawFileSwapTab(); DrawMetaManipulationsTab(); DrawConflictTab(); - ImGui.EndTabBar(); } } } diff --git a/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledDetailsEdit.cs b/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledDetailsEdit.cs index e82f9339..194b8f04 100644 --- a/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledDetailsEdit.cs +++ b/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledDetailsEdit.cs @@ -6,6 +6,7 @@ using ImGuiNET; using Penumbra.GameData.Util; using Penumbra.Mods; using Penumbra.Structs; +using Penumbra.UI.Custom; using Penumbra.Util; namespace Penumbra.UI @@ -38,7 +39,7 @@ namespace Penumbra.UI private bool DrawEditGroupSelector() { - ImGui.SetNextItemWidth( OptionSelectionWidth ); + ImGui.SetNextItemWidth( OptionSelectionWidth * ImGuiHelpers.GlobalScale ); if( Meta!.Groups.Count == 0 ) { ImGui.Combo( LabelGroupSelect, ref _selectedGroupIndex, TextNoOptionAvailable, 1 ); @@ -87,7 +88,7 @@ namespace Penumbra.UI } ImGui.SetNextItemWidth( -1 ); - if( ImGui.BeginListBox( LabelFileListHeader, AutoFillSize - new Vector2( 0, 1.5f * ImGui.GetTextLineHeight() ) ) ) + if( ImGui.BeginListBox( LabelFileListHeader, AutoFillSize - Vector2.UnitY * 1.5f * ImGui.GetTextLineHeight() ) ) { for( var i = 0; i < Mod!.Data.Resources.ModFiles.Count; ++i ) { @@ -106,23 +107,27 @@ namespace Penumbra.UI } } - private void DrawMultiSelectorEditBegin( OptionGroup group ) + private ImGuiRaii.EndStack DrawMultiSelectorEditBegin( OptionGroup group ) { var groupName = group.GroupName; - if( Custom.ImGuiCustom.BeginFramedGroupEdit( ref groupName ) ) + if( !ImGuiCustom.BeginFramedGroupEdit( ref groupName ) ) { - if( _modManager.ChangeModGroup( group.GroupName, groupName, Mod.Data ) && Mod.Data.Meta.RefreshHasGroupsWithConfig() ) - { - _selector.Cache.TriggerFilterReset(); - } + return new ImGuiRaii.EndStack(); } + + if( _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 ); + ImGui.SetNextItemWidth( MultiEditBoxWidth * ImGuiHelpers.GlobalScale ); if( ImGui.InputTextWithHint( $"##new_{group.GroupName}_l", "Add new option...", ref newOption, 64, ImGuiInputTextFlags.EnterReturnsTrue ) && newOption.Length != 0 ) @@ -142,7 +147,7 @@ namespace Penumbra.UI var nameBoxStart = CheckMarkSize; var flag = Mod!.Settings.Settings[ group.GroupName ]; - DrawMultiSelectorEditBegin( group ); + using var raii = DrawMultiSelectorEditBegin( group ); for( var i = 0; i < group.Options.Count; ++i ) { var opt = group.Options[ i ]; @@ -157,7 +162,7 @@ namespace Penumbra.UI nameBoxStart = ImGui.GetCursorPosX(); } - ImGui.SetNextItemWidth( MultiEditBoxWidth ); + ImGui.SetNextItemWidth( MultiEditBoxWidth * ImGuiHelpers.GlobalScale ); if( ImGui.InputText( $"{label}_l", ref newName, 64, ImGuiInputTextFlags.EnterReturnsTrue ) ) { if( newName.Length == 0 ) @@ -179,8 +184,6 @@ namespace Penumbra.UI } DrawMultiSelectorEditAdd( group, nameBoxStart ); - - Custom.ImGuiCustom.EndFramedGroup(); } private void DrawSingleSelectorEditGroup( OptionGroup group ) @@ -199,7 +202,7 @@ namespace Penumbra.UI { var oldSetting = Mod!.Settings.Settings[ group.GroupName ]; var code = oldSetting; - if( Custom.ImGuiCustom.RenameableCombo( $"##{group.GroupName}", ref code, out var newName, + 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 ) @@ -260,7 +263,7 @@ namespace Penumbra.UI ImGui.SetCursorPosX( labelEditPos ); if( labelEditPos == CheckMarkSize ) { - ImGui.SetNextItemWidth( MultiEditBoxWidth ); + ImGui.SetNextItemWidth( MultiEditBoxWidth * ImGuiHelpers.GlobalScale ); } if( ImGui.InputTextWithHint( LabelNewSingleGroupEdit, "Add new Single Group...", ref newGroup, 64, @@ -275,7 +278,7 @@ namespace Penumbra.UI { var newGroup = ""; ImGui.SetCursorPosX( CheckMarkSize ); - ImGui.SetNextItemWidth( MultiEditBoxWidth ); + ImGui.SetNextItemWidth( MultiEditBoxWidth * ImGuiHelpers.GlobalScale ); if( ImGui.InputTextWithHint( LabelNewMultiGroup, "Add new Multi Group...", ref newGroup, 64, ImGuiInputTextFlags.EnterReturnsTrue ) ) { @@ -310,74 +313,75 @@ namespace Penumbra.UI return; } + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem ); + ImGui.SetNextItemWidth( -1 ); - if( ImGui.BeginListBox( LabelFileSwapHeader, AutoFillSize ) ) + if( !ImGui.BeginListBox( LabelFileSwapHeader, AutoFillSize ) ) { - var swaps = Meta.FileSwaps.Keys.ToArray(); + return; + } - var arrow = $"{( char )FontAwesomeIcon.LongArrowAltRight}"; - ImGui.PushFont( UiBuilder.IconFont ); - var arrowWidth = ImGui.CalcTextSize( arrow ).X; - ImGui.PopFont(); + raii.Push( ImGui.EndListBox ); - var width = ( ImGui.GetWindowWidth() - arrowWidth - 4 * ImGui.GetStyle().ItemSpacing.X ) / 2; - for( var idx = 0; idx < swaps.Length + 1; ++idx ) + 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 ? GamePath.GenerateUnchecked( "" ) : swaps[ idx ]; + var value = idx == swaps.Length ? GamePath.GenerateUnchecked( "" ) : Meta.FileSwaps[ key ]; + string keyString = key; + string valueString = value; + + ImGui.SetNextItemWidth( width ); + if( ImGui.InputTextWithHint( $"##swapLhs_{idx}", "Enter new file to be replaced...", ref keyString, + GamePath.MaxGamePathLength, ImGuiInputTextFlags.EnterReturnsTrue ) ) { - var key = idx == swaps.Length ? GamePath.GenerateUnchecked( "" ) : swaps[ idx ]; - var value = idx == swaps.Length ? GamePath.GenerateUnchecked( "" ) : Meta.FileSwaps[ key ]; - string keyString = key; - string valueString = value; - - ImGui.SetNextItemWidth( width ); - if( ImGui.InputTextWithHint( $"##swapLhs_{idx}", "Enter new file to be replaced...", ref keyString, - GamePath.MaxGamePathLength, ImGuiInputTextFlags.EnterReturnsTrue ) ) + var newKey = new GamePath( keyString ); + if( newKey.CompareTo( key ) != 0 ) { - var newKey = new GamePath( keyString ); - if( newKey.CompareTo( key ) != 0 ) + if( idx < swaps.Length ) { - if( idx < swaps.Length ) - { - Meta.FileSwaps.Remove( key ); - } - - if( newKey != string.Empty ) - { - Meta.FileSwaps[ newKey ] = value; - } - - _selector.SaveCurrentMod(); - _selector.ReloadCurrentMod(); + Meta.FileSwaps.Remove( key ); } - } - if( idx < swaps.Length ) - { - ImGui.SameLine(); - ImGui.PushFont( UiBuilder.IconFont ); - ImGui.TextUnformatted( arrow ); - ImGui.PopFont(); - ImGui.SameLine(); - - ImGui.SetNextItemWidth( width ); - if( ImGui.InputTextWithHint( $"##swapRhs_{idx}", "Enter new replacement path...", ref valueString, - GamePath.MaxGamePathLength, - ImGuiInputTextFlags.EnterReturnsTrue ) ) + if( newKey != string.Empty ) { - var newValue = new GamePath( valueString ); - if( newValue.CompareTo( value ) != 0 ) - { - Meta.FileSwaps[ key ] = newValue; - _selector.SaveCurrentMod(); - _selector.Cache.TriggerListReset(); - } + Meta.FileSwaps[ newKey ] = value; } + + _selector.SaveCurrentMod(); + _selector.ReloadCurrentMod(); } } - ImGui.EndListBox(); - } + if( idx >= swaps.Length ) + { + continue; + } - ImGui.EndTabItem(); + 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 GamePath( valueString ); + if( newValue.CompareTo( value ) != 0 ) + { + Meta.FileSwaps[ key ] = newValue; + _selector.SaveCurrentMod(); + _selector.Cache.TriggerListReset(); + } + } + } } } } diff --git a/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledDetailsManipulations.cs b/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledDetailsManipulations.cs index 6aeba339..1766286f 100644 --- a/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledDetailsManipulations.cs +++ b/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledDetailsManipulations.cs @@ -10,6 +10,7 @@ using Penumbra.GameData.Enums; using Penumbra.GameData.Structs; using Penumbra.Meta; using Penumbra.Meta.Files; +using Penumbra.UI.Custom; using Penumbra.Util; using ObjectType = Penumbra.GameData.Enums.ObjectType; @@ -157,9 +158,8 @@ namespace Penumbra.UI return ImGui.Checkbox( name, ref value ); } - ImGui.PushStyleColor( ImGuiCol.Text, color ); - var ret = ImGui.Checkbox( name, ref value ); - ImGui.PopStyleColor(); + using var colorRaii = ImGuiRaii.PushColor( ImGuiCol.Text, color ); + var ret = ImGui.Checkbox( name, ref value ); return ret; } @@ -184,10 +184,9 @@ namespace Penumbra.UI var color = compare < 0 ? ColorDarkGreen : compare > 0 ? ColorDarkRed : ImGui.ColorConvertFloat4ToU32( ImGui.GetStyle().Colors[ ( int )ImGuiCol.Button ] ); - ImGui.PushStyleColor( ImGuiCol.Button, color ); - var ret = ImGui.Button( name, Vector2.UnitX * 120 ) && compare != 0; + using var colorRaii = ImGuiRaii.PushColor( ImGuiCol.Button, color ); + var ret = ImGui.Button( name, Vector2.UnitX * 120 ) && compare != 0; ImGui.SameLine(); - ImGui.PopStyleColor(); return ret; } @@ -204,18 +203,20 @@ namespace Penumbra.UI 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 ) + if( !ImGui.Selectable( $"{namesAndValues[ i ].Item1}##{label}{i}", idx == i ) || idx == i ) { - idx = i; - value = namesAndValues[ i ].Item2; - ImGui.EndCombo(); - return true; + continue; } + + idx = i; + value = namesAndValues[ i ].Item2; + return true; } - ImGui.EndCombo(); return false; } @@ -227,8 +228,9 @@ namespace Penumbra.UI if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) ) { - var defaults = ( EqpEntry )Service< MetaDefaults >.Get().GetDefaultValue( list[ manipIdx ] )!; - var attributes = Eqp.EqpAttributes[ id.Slot ]; + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup ); + var defaults = ( EqpEntry )Service< MetaDefaults >.Get().GetDefaultValue( list[ manipIdx ] )!; + var attributes = Eqp.EqpAttributes[ id.Slot ]; foreach( var flag in attributes ) { @@ -240,8 +242,6 @@ namespace Penumbra.UI ret = true; } } - - ImGui.EndPopup(); } ImGui.Text( ObjectType.Equipment.ToString() ); @@ -261,12 +261,13 @@ namespace Penumbra.UI if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) ) { - var enabled = val.Enabled; - var animated = val.Animated; - var rotationA = val.RotationA; - var rotationB = val.RotationB; - var rotationC = val.RotationC; - ushort unk = val.UnknownTotal; + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup ); + 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 ); @@ -284,8 +285,6 @@ namespace Penumbra.UI RotationA = rotationA, RotationB = rotationB, RotationC = rotationC, } ); } - - ImGui.EndPopup(); } ImGui.Text( ObjectType.Equipment.ToString() ); @@ -300,17 +299,17 @@ namespace Penumbra.UI { 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 ), + 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 ), }; } @@ -372,6 +371,7 @@ namespace Penumbra.UI if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) ) { + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup ); var (bit1, bit2) = GetEqdpBits( id.Slot, val ); var (defBit1, defBit2) = GetEqdpBits( id.Slot, defaults ); @@ -382,8 +382,6 @@ namespace Penumbra.UI { list[ manipIdx ] = MetaManipulation.Eqdp( id.Slot, id.GenderRace, id.SetId, SetEqdpBits( id.Slot, val, bit1, bit2 ) ); } - - ImGui.EndPopup(); } ImGui.Text( id.Slot.IsAccessory() @@ -409,13 +407,12 @@ namespace Penumbra.UI var val = list[ manipIdx ].EstValue; if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) ) { + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup ); if( DrawInputWithDefault( "No Idea what this does!##manip", ref val, defaults, ushort.MaxValue ) && _editMode ) { list[ manipIdx ] = new MetaManipulation( id.Value, val ); ret = true; } - - ImGui.EndPopup(); } ImGui.Text( id.ObjectType.ToString() ); @@ -443,12 +440,13 @@ namespace Penumbra.UI if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) ) { - ushort materialId = val.MaterialId; - ushort vfxId = val.VfxId; - ushort decalId = val.DecalId; - var soundId = ( ushort )( val.SoundId >> 10 ); - var attributeMask = val.AttributeMask; - var materialAnimationId = ( ushort )( val.MaterialAnimationId >> 12 ); + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup ); + ushort materialId = val.MaterialId; + ushort vfxId = val.VfxId; + ushort decalId = val.DecalId; + var soundId = ( ushort )( val.SoundId >> 10 ); + var attributeMask = val.AttributeMask; + var materialAnimationId = ( ushort )( val.MaterialAnimationId >> 12 ); 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 ); @@ -463,8 +461,6 @@ namespace Penumbra.UI ( byte )vfxId, ( byte )materialAnimationId ); list[ manipIdx ] = new MetaManipulation( id.Value, value.ToInteger() ); } - - ImGui.EndPopup(); } ImGui.Text( id.ObjectType.ToString() ); @@ -503,6 +499,7 @@ namespace Penumbra.UI 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 ) @@ -511,7 +508,7 @@ namespace Penumbra.UI ret = true; } - ImGui.SetNextItemWidth( 50 ); + ImGui.SetNextItemWidth( 50 * ImGuiHelpers.GlobalScale ); if( ImGui.InputFloat( "Scale###manip", ref val, 0, 0, "%.3f", _editMode ? ImGuiInputTextFlags.EnterReturnsTrue : ImGuiInputTextFlags.ReadOnly ) && val >= 0 @@ -521,8 +518,6 @@ namespace Penumbra.UI list[ manipIdx ] = MetaManipulation.Rsp( id.SubRace, id.Attribute, val ); ret = true; } - - ImGui.EndPopup(); } ImGui.Text( id.Attribute.ToUngenderedString() ); @@ -542,18 +537,15 @@ namespace Penumbra.UI if( _editMode ) { ImGui.TableNextColumn(); - ImGui.PushFont( UiBuilder.IconFont ); + using var font = ImGuiRaii.PushFont( UiBuilder.IconFont ); if( ImGui.Button( $"{FontAwesomeIcon.Trash.ToIconString()}##manipDelete{manipIdx}" ) ) { list.RemoveAt( manipIdx ); - ImGui.PopFont(); ImGui.TableNextRow(); --manipIdx; --count; return true; } - - ImGui.PopFont(); } ImGui.TableNextColumn(); @@ -613,114 +605,116 @@ namespace Penumbra.UI private bool DrawNewManipulationPopup( string popupName, IList< MetaManipulation > list, ref int count ) { var change = false; - if( ImGui.BeginPopup( popupName ) ) + if( !ImGui.BeginPopup( popupName ) ) { - var manipType = DrawNewTypeSelection(); - MetaManipulation? newManip = null; - switch( manipType ) + return change; + } + + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup ); + var manipType = DrawNewTypeSelection(); + MetaManipulation? newManip = null; + switch( manipType ) + { + case MetaType.Imc: { - case MetaType.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 ); + EquipSlot equipSlot = default; + switch( objectType ) { - 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 ); - EquipSlot equipSlot = default; - switch( objectType ) - { - case ObjectType.Equipment: - CustomCombo( "Equipment Slot", EqdpEquipSlots, out equipSlot, ref _newManipEquipSlot ); - newManip = MetaManipulation.Imc( equipSlot, _newManipSetId, _newManipVariant, - new ImcFile.ImageChangeData() ); - 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 ); - newManip = MetaManipulation.Imc( objectType, bodySlot, _newManipSetId, _newManipSecondaryId, - _newManipVariant, new ImcFile.ImageChangeData() ); - break; - } + case ObjectType.Equipment: + CustomCombo( "Equipment Slot", EqdpEquipSlots, out equipSlot, ref _newManipEquipSlot ); + newManip = MetaManipulation.Imc( equipSlot, _newManipSetId, _newManipVariant, + new ImcFile.ImageChangeData() ); + 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 ); + newManip = MetaManipulation.Imc( objectType, bodySlot, _newManipSetId, _newManipSecondaryId, + _newManipVariant, new ImcFile.ImageChangeData() ); + break; + } - break; - } - case MetaType.Eqdp: + break; + } + case MetaType.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 ); + newManip = MetaManipulation.Eqdp( equipSlot, Names.CombinedRace( gender, race ), ( ushort )_newManipSetId, + new EqdpEntry() ); + break; + } + case MetaType.Eqp: + { + RestrictedInputInt( "Set Id##newManipEqp", ref _newManipSetId, 0, ushort.MaxValue ); + CustomCombo( "Equipment Slot", EqpEquipSlots, out var equipSlot, ref _newManipEquipSlot ); + newManip = MetaManipulation.Eqp( equipSlot, ( ushort )_newManipSetId, 0 ); + break; + } + case MetaType.Est: + { + RestrictedInputInt( "Set Id##newManipEst", ref _newManipSetId, 0, ushort.MaxValue ); + CustomCombo( "Object Type", ObjectTypes, out var objectType, ref _newManipObjectType ); + EquipSlot equipSlot = default; + BodySlot bodySlot = default; + switch( ( ObjectType )_newManipObjectType ) { - 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 ); - newManip = MetaManipulation.Eqdp( equipSlot, Names.CombinedRace( gender, race ), ( ushort )_newManipSetId, - new EqdpEntry() ); - break; + case ObjectType.Equipment: + CustomCombo( "Equipment Slot", EstEquipSlots, out equipSlot, ref _newManipEquipSlot ); + break; + case ObjectType.Character: + CustomCombo( "Body Slot", EstBodySlots, out bodySlot, ref _newManipBodySlot ); + break; } - case MetaType.Eqp: - { - RestrictedInputInt( "Set Id##newManipEqp", ref _newManipSetId, 0, ushort.MaxValue ); - CustomCombo( "Equipment Slot", EqpEquipSlots, out var equipSlot, ref _newManipEquipSlot ); - newManip = MetaManipulation.Eqp( equipSlot, ( ushort )_newManipSetId, 0 ); - break; - } - case MetaType.Est: - { - RestrictedInputInt( "Set Id##newManipEst", ref _newManipSetId, 0, ushort.MaxValue ); - CustomCombo( "Object Type", ObjectTypes, out var objectType, ref _newManipObjectType ); - EquipSlot equipSlot = default; - BodySlot bodySlot = default; - switch( ( ObjectType )_newManipObjectType ) - { - case ObjectType.Equipment: - CustomCombo( "Equipment Slot", EstEquipSlots, out equipSlot, ref _newManipEquipSlot ); - break; - case ObjectType.Character: - CustomCombo( "Body Slot", EstBodySlots, out bodySlot, ref _newManipBodySlot ); - break; - } - CustomCombo( "Race", Races, out var race, ref _newManipRace ); - CustomCombo( "Gender", Genders, out var gender, ref _newManipGender ); - newManip = MetaManipulation.Est( objectType, equipSlot, Names.CombinedRace( gender, race ), bodySlot, - ( ushort )_newManipSetId, 0 ); - break; - } - case MetaType.Gmp: - RestrictedInputInt( "Set Id##newManipGmp", ref _newManipSetId, 0, ushort.MaxValue ); - newManip = MetaManipulation.Gmp( ( ushort )_newManipSetId, new GmpEntry() ); - break; - case MetaType.Rsp: - CustomCombo( "Subrace", Subraces, out var subRace, ref _newManipSubrace ); - CustomCombo( "Attribute", RspAttributes, out var rspAttribute, ref _newManipAttribute ); - newManip = MetaManipulation.Rsp( subRace, rspAttribute, 1f ); - break; + CustomCombo( "Race", Races, out var race, ref _newManipRace ); + CustomCombo( "Gender", Genders, out var gender, ref _newManipGender ); + newManip = MetaManipulation.Est( objectType, equipSlot, Names.CombinedRace( gender, race ), bodySlot, + ( ushort )_newManipSetId, 0 ); + break; + } + case MetaType.Gmp: + RestrictedInputInt( "Set Id##newManipGmp", ref _newManipSetId, 0, ushort.MaxValue ); + newManip = MetaManipulation.Gmp( ( ushort )_newManipSetId, new GmpEntry() ); + break; + case MetaType.Rsp: + CustomCombo( "Subrace", Subraces, out var subRace, ref _newManipSubrace ); + CustomCombo( "Attribute", RspAttributes, out var rspAttribute, ref _newManipAttribute ); + newManip = MetaManipulation.Rsp( subRace, rspAttribute, 1f ); + break; + } + + if( ImGui.Button( "Create Manipulation##newManip", Vector2.UnitX * -1 ) + && newManip != null + && list.All( m => m.Identifier != newManip.Value.Identifier ) ) + { + var def = Service< MetaDefaults >.Get().GetDefaultValue( newManip.Value ); + if( def != null ) + { + var manip = newManip.Value.Type switch + { + MetaType.Est => new MetaManipulation( newManip.Value.Identifier, ( ulong )def ), + MetaType.Eqp => new MetaManipulation( newManip.Value.Identifier, ( ulong )def ), + MetaType.Eqdp => new MetaManipulation( newManip.Value.Identifier, ( ulong )def ), + MetaType.Gmp => new MetaManipulation( newManip.Value.Identifier, ( ulong )def ), + MetaType.Imc => new MetaManipulation( newManip.Value.Identifier, + ( ( ImcFile.ImageChangeData )def ).ToInteger() ), + MetaType.Rsp => MetaManipulation.Rsp( newManip.Value.RspIdentifier.SubRace, + newManip.Value.RspIdentifier.Attribute, ( float )def ), + _ => throw new InvalidEnumArgumentException(), + }; + list.Add( manip ); + change = true; + ++count; } - if( ImGui.Button( "Create Manipulation##newManip", Vector2.UnitX * -1 ) - && newManip != null - && list.All( m => m.Identifier != newManip.Value.Identifier ) ) - { - var def = Service< MetaDefaults >.Get().GetDefaultValue( newManip.Value ); - if( def != null ) - { - var manip = newManip.Value.Type switch - { - MetaType.Est => new MetaManipulation( newManip.Value.Identifier, ( ulong )def ), - MetaType.Eqp => new MetaManipulation( newManip.Value.Identifier, ( ulong )def ), - MetaType.Eqdp => new MetaManipulation( newManip.Value.Identifier, ( ulong )def ), - MetaType.Gmp => new MetaManipulation( newManip.Value.Identifier, ( ulong )def ), - MetaType.Imc => new MetaManipulation( newManip.Value.Identifier, - ( ( ImcFile.ImageChangeData )def ).ToInteger() ), - MetaType.Rsp => MetaManipulation.Rsp( newManip.Value.RspIdentifier.SubRace, - newManip.Value.RspIdentifier.Attribute, ( float )def ), - _ => throw new InvalidEnumArgumentException(), - }; - list.Add( manip ); - change = true; - ++count; - } - ImGui.CloseCurrentPopup(); - } - - ImGui.EndPopup(); + ImGui.CloseCurrentPopup(); } return change; @@ -734,6 +728,7 @@ namespace Penumbra.UI && ImGui.BeginTable( label, numRows, ImGuiTableFlags.BordersInner | ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit ) ) { + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTable ); if( _editMode ) { ImGui.TableNextColumn(); @@ -764,8 +759,6 @@ namespace Penumbra.UI { changes |= DrawManipulationRow( ref i, list, ref count ); } - - ImGui.EndTable(); } var popupName = $"##newManip{label}"; diff --git a/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledModPanel.cs b/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledModPanel.cs index bd124a71..2250b80e 100644 --- a/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledModPanel.cs +++ b/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledModPanel.cs @@ -2,10 +2,12 @@ using System; using System.Diagnostics; using System.IO; using System.Numerics; +using Dalamud.Interface; using Dalamud.Logging; using ImGuiNET; using Penumbra.Mod; using Penumbra.Mods; +using Penumbra.UI.Custom; using Penumbra.Util; namespace Penumbra.UI @@ -72,7 +74,7 @@ namespace Penumbra.UI private void DrawName() { var name = Meta!.Name; - if( Custom.ImGuiCustom.InputOrText( _editMode, LabelEditName, ref name, 64 ) && _modManager.RenameMod( name, Mod!.Data ) ) + if( ImGuiCustom.InputOrText( _editMode, LabelEditName, ref name, 64 ) && _modManager.RenameMod( name, Mod!.Data ) ) { _selector.SelectModOnUpdate( Mod.Data.BasePath.Name ); if( !_modManager.Config.ModSortOrder.ContainsKey( Mod!.Data.BasePath.Name ) ) @@ -87,12 +89,13 @@ namespace Penumbra.UI if( _editMode ) { ImGui.BeginGroup(); + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndGroup ); ImGui.Text( "(Version " ); - ImGui.PushStyleVar( ImGuiStyleVar.ItemSpacing, ZeroVector ); + using var style = ImGuiRaii.PushStyle( ImGuiStyleVar.ItemSpacing, ZeroVector ); ImGui.SameLine(); var version = Meta!.Version; - if( Custom.ImGuiCustom.ResizingTextInput( LabelEditVersion, ref version, 16 ) + if( ImGuiCustom.ResizingTextInput( LabelEditVersion, ref version, 16 ) && version != Meta.Version ) { Meta.Version = version; @@ -101,8 +104,6 @@ namespace Penumbra.UI ImGui.SameLine(); ImGui.Text( ")" ); - ImGui.PopStyleVar(); - ImGui.EndGroup(); } else if( Meta!.Version.Length > 0 ) { @@ -117,7 +118,7 @@ namespace Penumbra.UI ImGui.SameLine(); var author = Meta!.Author; - if( Custom.ImGuiCustom.InputOrText( _editMode, LabelEditAuthor, ref author, 64 ) + if( ImGuiCustom.InputOrText( _editMode, LabelEditAuthor, ref author, 64 ) && author != Meta.Author ) { Meta.Author = author; @@ -131,12 +132,13 @@ namespace Penumbra.UI 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( Custom.ImGuiCustom.ResizingTextInput( LabelEditWebsite, ref website, 512 ) + if( ImGuiCustom.ResizingTextInput( LabelEditWebsite, ref website, 512 ) && website != Meta.Website ) { Meta.Website = website; @@ -170,10 +172,7 @@ namespace Penumbra.UI } } - if( ImGui.IsItemHovered() ) - { - ImGui.SetTooltip( Meta.Website ); - } + ImGuiCustom.HoverTooltip( Meta.Website ); } else { @@ -182,8 +181,6 @@ namespace Penumbra.UI ImGui.Text( Meta.Website ); } } - - ImGui.EndGroup(); } private void DrawHeaderLine() @@ -200,7 +197,7 @@ namespace Penumbra.UI private void DrawPriority() { var priority = Mod!.Settings.Priority; - ImGui.SetNextItemWidth( 50 ); + ImGui.SetNextItemWidth( 50 * ImGuiHelpers.GlobalScale ); if( ImGui.InputInt( "Priority", ref priority, 0 ) && priority != Mod!.Settings.Priority ) { Mod.Settings.Priority = priority; @@ -208,11 +205,9 @@ namespace Penumbra.UI _selector.Cache.TriggerFilterReset(); } - if( ImGui.IsItemHovered() ) - { - ImGui.SetTooltip( "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." ); - } + 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() @@ -229,7 +224,7 @@ namespace Penumbra.UI public static bool DrawSortOrder( ModData mod, ModManager manager, Selector selector ) { var currentSortOrder = mod.SortOrder.FullPath; - ImGui.SetNextItemWidth( 300 ); + ImGui.SetNextItemWidth( 300 * ImGuiHelpers.GlobalScale ); if( ImGui.InputText( "Sort Order", ref currentSortOrder, 256, ImGuiInputTextFlags.EnterReturnsTrue ) ) { manager.ChangeSortOrder( mod, currentSortOrder ); @@ -253,10 +248,7 @@ namespace Penumbra.UI Process.Start( new ProcessStartInfo( Mod!.Data.BasePath.FullName ) { UseShellExecute = true } ); } - if( ImGui.IsItemHovered() ) - { - ImGui.SetTooltip( TooltipOpenModFolder ); - } + ImGuiCustom.HoverTooltip( TooltipOpenModFolder ); } private string _newName = ""; @@ -318,35 +310,37 @@ namespace Penumbra.UI { var closeParent = false; var _ = true; - if( ImGui.BeginPopupModal( LabelOverWriteDir, ref _, ImGuiWindowFlags.AlwaysAutoResize ) ) + if( !ImGui.BeginPopupModal( LabelOverWriteDir, ref _, ImGuiWindowFlags.AlwaysAutoResize ) ) { - DirectoryInfo 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 = new Vector2( 120, 0 ); - if( ImGui.Button( "Yes", buttonSize ) ) + return closeParent; + } + + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup ); + + DirectoryInfo 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 ) ) + { + if( MergeFolderInto( dir, newDir ) ) { - if( MergeFolderInto( dir, newDir ) ) - { - Service< ModManager >.Get()!.RenameModFolder( Mod.Data, newDir, false ); + Service< ModManager >.Get()!.RenameModFolder( Mod.Data, newDir, false ); - _selector.SelectModOnUpdate( _newName ); + _selector.SelectModOnUpdate( _newName ); - closeParent = true; - ImGui.CloseCurrentPopup(); - } - } - - ImGui.SameLine(); - - if( ImGui.Button( "Cancel", buttonSize ) ) - { - _keyboardFocus = true; + closeParent = true; ImGui.CloseCurrentPopup(); } + } - ImGui.EndPopup(); + ImGui.SameLine(); + + if( ImGui.Button( "Cancel", buttonSize ) ) + { + _keyboardFocus = true; + ImGui.CloseCurrentPopup(); } return closeParent; @@ -358,38 +352,40 @@ namespace Penumbra.UI _keyboardFocus |= !ImGui.IsPopupOpen( PopupRenameFolder ); ImGui.SetNextWindowPos( ImGui.GetMainViewport().GetCenter(), ImGuiCond.Appearing, new Vector2( 0.5f, 1f ) ); - if( ImGui.BeginPopupModal( PopupRenameFolder, ref _, ImGuiWindowFlags.AlwaysAutoResize ) ) + if( !ImGui.BeginPopupModal( PopupRenameFolder, ref _, ImGuiWindowFlags.AlwaysAutoResize ) ) { - if( ImGui.IsKeyPressed( ImGui.GetKeyIndex( ImGuiKey.Escape ) ) ) - { - ImGui.CloseCurrentPopup(); - } + return; + } - var newName = Mod!.Data.BasePath.Name; + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup ); - if( _keyboardFocus ) - { - ImGui.SetKeyboardFocusHere(); - _keyboardFocus = false; - } + if( ImGui.IsKeyPressed( ImGui.GetKeyIndex( ImGuiKey.Escape ) ) ) + { + ImGui.CloseCurrentPopup(); + } - if( ImGui.InputText( "New Folder Name##RenameFolderInput", ref newName, 64, ImGuiInputTextFlags.EnterReturnsTrue ) ) - { - RenameModFolder( newName ); - } + var newName = Mod!.Data.BasePath.Name; - ImGui.TextColored( GreyColor, - "Please restrict yourself to ascii symbols that are valid in a windows path,\nother symbols will be replaced by underscores." ); + if( _keyboardFocus ) + { + ImGui.SetKeyboardFocusHere(); + _keyboardFocus = false; + } - ImGui.SetNextWindowPos( ImGui.GetMainViewport().GetCenter(), ImGuiCond.Appearing, Vector2.One / 2 ); + 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(); - } - - ImGui.EndPopup(); + if( OverwriteDirPopup() ) + { + ImGui.CloseCurrentPopup(); } } @@ -401,10 +397,7 @@ namespace Penumbra.UI ImGui.OpenPopup( PopupRenameFolder ); } - if( ImGui.IsItemHovered() ) - { - ImGui.SetTooltip( TooltipRenameModFolder ); - } + ImGuiCustom.HoverTooltip( TooltipRenameModFolder ); } private void DrawEditJsonButton() @@ -415,10 +408,7 @@ namespace Penumbra.UI Process.Start( new ProcessStartInfo( Mod!.Data.MetaFile.FullName ) { UseShellExecute = true } ); } - if( ImGui.IsItemHovered() ) - { - ImGui.SetTooltip( TooltipEditJson ); - } + ImGuiCustom.HoverTooltip( TooltipEditJson ); } private void DrawReloadJsonButton() @@ -428,10 +418,7 @@ namespace Penumbra.UI _selector.ReloadCurrentMod( true, false ); } - if( ImGui.IsItemHovered() ) - { - ImGui.SetTooltip( TooltipReloadJson ); - } + ImGuiCustom.HoverTooltip( TooltipReloadJson ); } private void DrawResetMetaButton() @@ -441,13 +428,10 @@ namespace Penumbra.UI _selector.ReloadCurrentMod( true, true ); } - if( ImGui.IsItemHovered() ) - { - ImGui.SetTooltip( - "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." ); - } + 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() @@ -459,10 +443,7 @@ namespace Penumbra.UI _selector.ReloadCurrentMod(); } - if( ImGui.IsItemHovered() ) - { - ImGui.SetTooltip( TooltipDeduplicate ); - } + ImGuiCustom.HoverTooltip( TooltipDeduplicate ); } private void DrawNormalizeButton() @@ -474,10 +455,7 @@ namespace Penumbra.UI _selector.ReloadCurrentMod(); } - if( ImGui.IsItemHovered() ) - { - ImGui.SetTooltip( TooltipNormalize ); - } + ImGuiCustom.HoverTooltip( TooltipNormalize ); } private void DrawSplitButton() @@ -487,13 +465,10 @@ namespace Penumbra.UI ModCleanup.SplitMod( Mod!.Data ); } - if( ImGui.IsItemHovered() ) - { - ImGui.SetTooltip( - "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!" ); - } + 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 DrawEditLine() @@ -521,18 +496,18 @@ namespace Penumbra.UI { try { - var ret = ImGui.BeginChild( LabelModPanel, AutoFillSize, true ); - + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndChild ); + var ret = ImGui.BeginChild( LabelModPanel, AutoFillSize, true ); + if( !ret || Mod == null ) { - ImGui.EndChild(); return; } DrawHeaderLine(); // Next line with fixed distance. - Custom.ImGuiCustom.VerticalDistance( HeaderLineDistance ); + ImGuiCustom.VerticalDistance( HeaderLineDistance ); DrawEnabledMark(); ImGui.SameLine(); @@ -550,12 +525,10 @@ namespace Penumbra.UI } Details.Draw( _editMode ); - - ImGui.EndChild(); } catch( Exception ex ) { - PluginLog.LogError( ex, "fuck" ); + PluginLog.LogError( ex, "Oh no" ); } } } diff --git a/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledSelector.cs b/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledSelector.cs index 07290ef5..5f73a2e9 100644 --- a/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledSelector.cs +++ b/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledSelector.cs @@ -3,12 +3,14 @@ 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.Importer; using Penumbra.Mod; using Penumbra.Mods; +using Penumbra.UI.Custom; using Penumbra.Util; namespace Penumbra.UI @@ -36,6 +38,8 @@ namespace Penumbra.UI 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 @@ -46,19 +50,16 @@ namespace Penumbra.UI private void DrawModTrashButton() { - ImGui.PushFont( UiBuilder.IconFont ); + using var raii = ImGuiRaii.PushFont( UiBuilder.IconFont ); if( ImGui.Button( FontAwesomeIcon.Trash.ToIconString(), SelectorButtonSizes * _selectorScalingFactor ) && _index >= 0 ) { _deleteIndex = _index; } - ImGui.PopFont(); + raii.Pop(); - if( ImGui.IsItemHovered() ) - { - ImGui.SetTooltip( TooltipDelete ); - } + ImGuiCustom.HoverTooltip( TooltipDelete ); } private void DrawDeleteModal() @@ -78,20 +79,22 @@ namespace Penumbra.UI return; } + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup ); + if( Mod == null ) { _deleteIndex = null; ImGui.CloseCurrentPopup(); - ImGui.EndPopup(); return; } ImGui.Text( "Are you sure you want to delete the following mod:" ); - ImGui.Dummy( new Vector2( ImGui.GetTextLineHeight() / 2 ) ); - ImGui.TextColored( new Vector4( 0.7f, 0.1f, 0.1f, 1 ), Mod.Data.Meta.Name ); - ImGui.Dummy( new Vector2( ImGui.GetTextLineHeight() ) / 2 ); + var halfLine = new Vector2( ImGui.GetTextLineHeight() / 2 ); + ImGui.Dummy( halfLine ); + ImGui.TextColored( DeleteModNameColor, Mod.Data.Meta.Name ); + ImGui.Dummy( halfLine ); - var buttonSize = new Vector2( 120, 0 ); + var buttonSize = ImGuiHelpers.ScaledVector2( 120, 0 ); if( ImGui.Button( ButtonYesDelete, buttonSize ) ) { ImGui.CloseCurrentPopup(); @@ -109,8 +112,6 @@ namespace Penumbra.UI ImGui.CloseCurrentPopup(); _deleteIndex = null; } - - ImGui.EndPopup(); } // === Add === @@ -118,7 +119,7 @@ namespace Penumbra.UI private void DrawModAddButton() { - ImGui.PushFont( UiBuilder.IconFont ); + using var raii = ImGuiRaii.PushFont( UiBuilder.IconFont ); if( ImGui.Button( FontAwesomeIcon.Plus.ToIconString(), SelectorButtonSizes * _selectorScalingFactor ) ) { @@ -126,12 +127,9 @@ namespace Penumbra.UI ImGui.OpenPopup( LabelAddModPopup ); } - ImGui.PopFont(); + raii.Pop(); - if( ImGui.IsItemHovered() ) - { - ImGui.SetTooltip( TooltipAdd ); - } + ImGuiCustom.HoverTooltip( TooltipAdd ); DrawModAddPopup(); } @@ -143,6 +141,8 @@ namespace Penumbra.UI return; } + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup ); + if( _modAddKeyboardFocus ) { ImGui.SetKeyboardFocusHere(); @@ -181,20 +181,16 @@ namespace Penumbra.UI { ImGui.CloseCurrentPopup(); } - - ImGui.EndPopup(); } // === Help === private void DrawModHelpButton() { - ImGui.PushFont( UiBuilder.IconFont ); + using var raii = ImGuiRaii.PushFont( UiBuilder.IconFont ); if( ImGui.Button( FontAwesomeIcon.QuestionCircle.ToIconString(), HelpButtonSizes * _selectorScalingFactor ) ) { ImGui.OpenPopup( LabelModHelpPopup ); } - - ImGui.PopFont(); } private static void DrawModHelpPopup() @@ -208,6 +204,8 @@ namespace Penumbra.UI 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." ); @@ -268,24 +266,20 @@ namespace Penumbra.UI { ImGui.CloseCurrentPopup(); } - - ImGui.EndPopup(); } // === Main === private void DrawModsSelectorButtons() { // Selector controls - ImGui.PushStyleVar( ImGuiStyleVar.WindowPadding, ZeroVector ); - ImGui.PushStyleVar( ImGuiStyleVar.FrameRounding, 0 ); + using var style = ImGuiRaii.PushStyle( ImGuiStyleVar.WindowPadding, ZeroVector ) + .Push( ImGuiStyleVar.FrameRounding, 0 ); DrawModAddButton(); ImGui.SameLine(); DrawModHelpButton(); ImGui.SameLine(); DrawModTrashButton(); - - ImGui.PopStyleVar( 2 ); } } @@ -296,7 +290,7 @@ namespace Penumbra.UI private void DrawTextFilter() { - ImGui.SetNextItemWidth( SelectorPanelWidth * _selectorScalingFactor - 22 ); + ImGui.SetNextItemWidth( SelectorPanelWidth * _selectorScalingFactor - 22 * ImGuiHelpers.GlobalScale ); var tmp = _modFilterInput; if( ImGui.InputTextWithHint( LabelModFilter, "Filter Mods...", ref tmp, 256 ) && _modFilterInput != tmp ) { @@ -304,10 +298,7 @@ namespace Penumbra.UI _modFilterInput = tmp; } - if( ImGui.IsItemHovered() ) - { - ImGui.SetTooltip( TooltipModFilter ); - } + ImGuiCustom.HoverTooltip( TooltipModFilter ); } private void DrawToggleFilter() @@ -315,30 +306,25 @@ namespace Penumbra.UI if( ImGui.BeginCombo( "##ModStateFilter", "", ImGuiComboFlags.NoPreview | ImGuiComboFlags.PopupAlignLeft | ImGuiComboFlags.HeightLargest ) ) { - var flags = ( int )Cache.StateFilter; + 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; - - ImGui.EndCombo(); } - if( ImGui.IsItemHovered() ) - { - ImGui.SetTooltip( "Filter mods for their activation status." ); - } + ImGuiCustom.HoverTooltip( "Filter mods for their activation status." ); } private void DrawModsSelectorFilter() { - ImGui.PushStyleVar( ImGuiStyleVar.ItemSpacing, ZeroVector ); + using var style = ImGuiRaii.PushStyle( ImGuiStyleVar.ItemSpacing, ZeroVector ); DrawTextFilter(); ImGui.SameLine(); DrawToggleFilter(); - ImGui.PopStyleVar(); } } @@ -360,15 +346,14 @@ namespace Penumbra.UI 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; - if( mod != null ) - { - mod.Data.Move( folder ); - } + mod?.Data.Move( folder ); } else if( IsDropping( DraggedFolderLabel ) ) { @@ -381,8 +366,6 @@ namespace Penumbra.UI droppedFolder.Move( folder ); } } - - ImGui.EndDragDropTarget(); } private void DragDropSourceFolder( ModFolder folder ) @@ -392,11 +375,12 @@ namespace Penumbra.UI 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}..." ); - ImGui.EndDragDropSource(); } private void DragDropSourceMod( int modIndex, string modName ) @@ -406,10 +390,11 @@ namespace Penumbra.UI return; } + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndDragDropSource ); + Marshal.WriteInt32( _dragDropPayload, modIndex ); ImGui.SetDragDropPayload( "ModIndex", _dragDropPayload, 4 ); ImGui.Text( $"Moving {modName}..." ); - ImGui.EndDragDropSource(); } ~Selector() @@ -496,6 +481,8 @@ namespace Penumbra.UI return; } + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup ); + if( ModPanel.DrawSortOrder( mod.Data, _modManager, this ) ) { ImGui.CloseCurrentPopup(); @@ -505,8 +492,6 @@ namespace Penumbra.UI { ImGui.SetKeyboardFocusHere( mod.Data.SortOrder.FullPath.Length - 1 ); } - - ImGui.EndPopup(); } // === Folder === @@ -545,7 +530,7 @@ namespace Penumbra.UI private void DrawRenameFolderInput( ModFolder folder ) { - ImGui.SetNextItemWidth( 150 ); + ImGui.SetNextItemWidth( 150 * ImGuiHelpers.GlobalScale ); if( !ImGui.InputTextWithHint( "##NewFolderName", "Rename Folder...", ref _newFolderName, 64, ImGuiInputTextFlags.EnterReturnsTrue ) ) { @@ -566,23 +551,25 @@ namespace Penumbra.UI private void DrawFolderContextMenu( ModFolder folder, int currentIdx, string treeName ) { - if( ImGui.BeginPopup( treeName ) ) + if( !ImGui.BeginPopup( treeName ) ) { - if( ImGui.MenuItem( "Enable All Descendants" ) ) - { - ChangeStatusOfChildren( folder, currentIdx, true ); - } - - if( ImGui.MenuItem( "Disable All Descendants" ) ) - { - ChangeStatusOfChildren( folder, currentIdx, false ); - } - - ImGui.Dummy( Vector2.UnitY * 10 ); - DrawRenameFolderInput( folder ); - - ImGui.EndPopup(); + return; } + + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup ); + + 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 ); } } @@ -607,35 +594,32 @@ namespace Penumbra.UI if( collection == ModCollection.Empty || collection == _modManager.Collections.CurrentCollection ) { - ImGui.PushStyleVar( ImGuiStyleVar.Alpha, 0.5f ); + using var _ = ImGuiRaii.PushStyle( ImGuiStyleVar.Alpha, 0.5f ); ImGui.Button( label, Vector2.UnitX * size ); - ImGui.PopStyleVar(); } else if( ImGui.Button( label, Vector2.UnitX * size ) ) { _base._menu.CollectionsTab.SetCurrentCollection( collection ); } - if( ImGui.IsItemHovered() ) - { - ImGui.SetTooltip( - $"Switches to the currently set {tooltipLabel} collection, if it is not set to None and it is not the current collection already." ); - } + 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( TabCollections.LabelCurrentCollection ).X + ImGui.GetStyle().ItemInnerSpacing.X; var comboSize = size * ImGui.GetIO().FontGlobalScale; var offset = comboSize + textSize; - var buttonSize = ( ImGui.GetWindowContentRegionWidth() + var buttonSize = Math.Max( ( ImGui.GetWindowContentRegionWidth() - offset - SelectorPanelWidth * _selectorScalingFactor - 4 * ImGui.GetStyle().ItemSpacing.X ) - / 2; + / 2, 5f ); ImGui.SameLine(); DrawCollectionButton( "Default", "default", buttonSize, _modManager.Collections.DefaultCollection ); @@ -644,9 +628,8 @@ namespace Penumbra.UI ImGui.SameLine(); ImGui.SetNextItemWidth( comboSize ); - ImGui.PushStyleVar( ImGuiStyleVar.ItemSpacing, Vector2.Zero ); + using var style = ImGuiRaii.PushStyle( ImGuiStyleVar.ItemSpacing, Vector2.Zero ); _base._menu.CollectionsTab.DrawCurrentCollectionSelector( false ); - ImGui.PopStyleVar(); } private void DrawFolderContent( ModFolder folder, ref int idx ) @@ -683,8 +666,9 @@ namespace Penumbra.UI private void DrawModFolder( ModFolder folder, ref int idx ) { - var treeName = $"{folder.Name}##{folder.FullName}"; - var open = ImGui.TreeNodeEx( treeName ); + var treeName = $"{folder.Name}##{folder.FullName}"; + var open = ImGui.TreeNodeEx( treeName ); + using var raii = ImGuiRaii.DeferredEnd( ImGui.TreePop, open ); if( ImGui.IsItemClicked( ImGuiMouseButton.Right ) ) { _newFolderName = string.Empty; @@ -698,7 +682,6 @@ namespace Penumbra.UI if( open ) { DrawFolderContent( folder, ref idx ); - ImGui.TreePop(); } else { @@ -708,17 +691,10 @@ namespace Penumbra.UI private void DrawMod( Mod.Mod mod, int modIndex, uint color ) { - if( color != 0 ) - { - ImGui.PushStyleColor( ImGuiCol.Text, color ); - } + using var colorRaii = ImGuiRaii.PushColor( ImGuiCol.Text, color, color != 0 ); var selected = ImGui.Selectable( $"{mod.Data.Meta.Name}##{modIndex}", modIndex == _index ); - - if( color != 0 ) - { - ImGui.PopStyleColor(); - } + colorRaii.Pop(); var popupName = $"##SortOrderPopup{modIndex}"; var firstOpen = false; @@ -754,37 +730,33 @@ namespace Penumbra.UI } } - try - { - _selectorScalingFactor = Penumbra.Config.ScaleModSelector + _selectorScalingFactor = ImGuiHelpers.GlobalScale + * ( Penumbra.Config.ScaleModSelector ? ImGui.GetWindowWidth() / SettingsMenu.MinSettingsSize.X - : 1f; - // Selector pane - DrawHeaderBar(); - ImGui.PushStyleVar( ImGuiStyleVar.ItemSpacing, Vector2.Zero ); - ImGui.BeginGroup(); - // Inlay selector list - if( ImGui.BeginChild( LabelSelectorList, - new Vector2( SelectorPanelWidth * _selectorScalingFactor, -ImGui.GetFrameHeightWithSpacing() ), - true, ImGuiWindowFlags.HorizontalScrollbar ) ) - { - ImGui.PushStyleVar( ImGuiStyleVar.IndentSpacing, 12.5f ); - - var modIndex = 0; - DrawFolderContent( _modManager.StructuredMods, ref modIndex ); - ImGui.PopStyleVar(); - } - - ImGui.EndChild(); - - DrawModsSelectorButtons(); - ImGui.EndGroup(); - } - finally + : 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 ) ) { - ImGui.PopStyleVar(); + style.Push( ImGuiStyleVar.IndentSpacing, 12.5f ); + + var modIndex = 0; + DrawFolderContent( _modManager.StructuredMods, ref modIndex ); + style.Pop(); } + raii.Pop(); + + DrawModsSelectorButtons(); + + style.Pop(); DrawModHelpPopup(); DrawDeleteModal(); diff --git a/Penumbra/UI/MenuTabs/TabResourceManager.cs b/Penumbra/UI/MenuTabs/TabResourceManager.cs index a480c566..107bce9f 100644 --- a/Penumbra/UI/MenuTabs/TabResourceManager.cs +++ b/Penumbra/UI/MenuTabs/TabResourceManager.cs @@ -1,8 +1,10 @@ using System.Numerics; +using Dalamud.Interface; using FFXIVClientStructs.FFXIV.Client.System.Resource; using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle; using FFXIVClientStructs.STD; using ImGuiNET; +using Penumbra.UI.Custom; namespace Penumbra.UI { @@ -26,17 +28,19 @@ namespace Penumbra.UI return; } + using var raii = ImGuiRaii.DeferredEnd( ImGui.TreePop ); if( typeMap->Count == 0 || !ImGui.BeginTable( $"##{label}_table", 4, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg ) ) { - ImGui.TreePop(); return; } - ImGui.TableSetupColumn( "Hash", ImGuiTableColumnFlags.WidthFixed, 100 ); - ImGui.TableSetupColumn( "Ptr", ImGuiTableColumnFlags.WidthFixed, 100 ); - ImGui.TableSetupColumn( "Path", ImGuiTableColumnFlags.WidthFixed, ImGui.GetWindowContentRegionWidth() - 300 ); - ImGui.TableSetupColumn( "Refs", ImGuiTableColumnFlags.WidthFixed, 30 ); + raii.Push( ImGui.EndTable ); + + ImGui.TableSetupColumn( "Hash", ImGuiTableColumnFlags.WidthFixed, 100 * ImGuiHelpers.GlobalScale ); + ImGui.TableSetupColumn( "Ptr", ImGuiTableColumnFlags.WidthFixed, 100 * ImGuiHelpers.GlobalScale ); + ImGui.TableSetupColumn( "Path", ImGuiTableColumnFlags.WidthFixed, ImGui.GetWindowContentRegionWidth() - 300 * ImGuiHelpers.GlobalScale ); + ImGui.TableSetupColumn( "Refs", ImGuiTableColumnFlags.WidthFixed, 30 * ImGuiHelpers.GlobalScale ); ImGui.TableHeadersRow(); var node = typeMap->SmallestValue; @@ -59,9 +63,6 @@ namespace Penumbra.UI ImGui.Text( node->KeyValuePair.Item2.Value->RefCount.ToString() ); node = node->Next(); } - - ImGui.EndTable(); - ImGui.TreePop(); } private unsafe void DrawCategoryContainer( string label, ResourceGraph.CategoryContainer container ) @@ -72,6 +73,8 @@ namespace Penumbra.UI return; } + using var raii = ImGuiRaii.DeferredEnd( ImGui.TreePop ); + var node = map->SmallestValue; while( !node->IsNil ) { @@ -79,8 +82,6 @@ namespace Penumbra.UI node->KeyValuePair.Item2.Value ); node = node->Next(); } - - ImGui.TreePop(); } private unsafe void DrawResourceManagerTab() @@ -90,6 +91,8 @@ namespace Penumbra.UI return; } + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem ); + var resourceHandler = *( ResourceManager** )( Dalamud.SigScanner.Module.BaseAddress + 0x1D93AC0 ); if( resourceHandler == null ) @@ -97,28 +100,27 @@ namespace Penumbra.UI return; } - if( ImGui.BeginChild( "##ResourceManagerChild", -Vector2.One, true ) ) + raii.Push( ImGui.EndChild ); + if( !ImGui.BeginChild( "##ResourceManagerChild", -Vector2.One, true ) ) { - DrawCategoryContainer( "Common", resourceHandler->ResourceGraph->CommonContainer ); - DrawCategoryContainer( "BgCommon", resourceHandler->ResourceGraph->BgCommonContainer ); - DrawCategoryContainer( "Bg", resourceHandler->ResourceGraph->BgContainer ); - DrawCategoryContainer( "Cut", resourceHandler->ResourceGraph->CutContainer ); - DrawCategoryContainer( "Chara", resourceHandler->ResourceGraph->CharaContainer ); - DrawCategoryContainer( "Shader", resourceHandler->ResourceGraph->ShaderContainer ); - DrawCategoryContainer( "Ui", resourceHandler->ResourceGraph->UiContainer ); - DrawCategoryContainer( "Sound", resourceHandler->ResourceGraph->SoundContainer ); - DrawCategoryContainer( "Vfx", resourceHandler->ResourceGraph->VfxContainer ); - DrawCategoryContainer( "UiScript", resourceHandler->ResourceGraph->UiScriptContainer ); - DrawCategoryContainer( "Exd", resourceHandler->ResourceGraph->ExdContainer ); - DrawCategoryContainer( "GameScript", resourceHandler->ResourceGraph->GameScriptContainer ); - DrawCategoryContainer( "Music", resourceHandler->ResourceGraph->MusicContainer ); - DrawCategoryContainer( "SqpackTest", resourceHandler->ResourceGraph->SqpackTestContainer ); - DrawCategoryContainer( "Debug", resourceHandler->ResourceGraph->DebugContainer ); + return; } - ImGui.EndChild(); - - ImGui.EndTabItem(); + DrawCategoryContainer( "Common", resourceHandler->ResourceGraph->CommonContainer ); + DrawCategoryContainer( "BgCommon", resourceHandler->ResourceGraph->BgCommonContainer ); + DrawCategoryContainer( "Bg", resourceHandler->ResourceGraph->BgContainer ); + DrawCategoryContainer( "Cut", resourceHandler->ResourceGraph->CutContainer ); + DrawCategoryContainer( "Chara", resourceHandler->ResourceGraph->CharaContainer ); + DrawCategoryContainer( "Shader", resourceHandler->ResourceGraph->ShaderContainer ); + DrawCategoryContainer( "Ui", resourceHandler->ResourceGraph->UiContainer ); + DrawCategoryContainer( "Sound", resourceHandler->ResourceGraph->SoundContainer ); + DrawCategoryContainer( "Vfx", resourceHandler->ResourceGraph->VfxContainer ); + DrawCategoryContainer( "UiScript", resourceHandler->ResourceGraph->UiScriptContainer ); + DrawCategoryContainer( "Exd", resourceHandler->ResourceGraph->ExdContainer ); + DrawCategoryContainer( "GameScript", resourceHandler->ResourceGraph->GameScriptContainer ); + DrawCategoryContainer( "Music", resourceHandler->ResourceGraph->MusicContainer ); + DrawCategoryContainer( "SqpackTest", resourceHandler->ResourceGraph->SqpackTestContainer ); + DrawCategoryContainer( "Debug", resourceHandler->ResourceGraph->DebugContainer ); } } } \ No newline at end of file diff --git a/Penumbra/UI/MenuTabs/TabSettings.cs b/Penumbra/UI/MenuTabs/TabSettings.cs index 1cf93dfa..05ed7fe4 100644 --- a/Penumbra/UI/MenuTabs/TabSettings.cs +++ b/Penumbra/UI/MenuTabs/TabSettings.cs @@ -7,6 +7,7 @@ using ImGuiNET; using Penumbra.GameData.Enums; using Penumbra.Interop; using Penumbra.Mods; +using Penumbra.UI.Custom; using Penumbra.Util; namespace Penumbra.UI @@ -65,13 +66,10 @@ namespace Penumbra.UI _base._modManager.SetTempDirectory( tempPath ); } - if( ImGui.IsItemHovered() ) - { - ImGui.SetTooltip( "The folder used to store temporary meta manipulation files.\n" - + "Leave this blank if you have no reason not to.\n" - + "A folder 'penumbrametatmp' will be created as a subdirectory to the specified directory.\n" - + "If none is specified (i.e. this is blank) this folder will be created in the root folder instead." ); - } + ImGuiCustom.HoverTooltip( "The folder used to store temporary meta manipulation files.\n" + + "Leave this blank if you have no reason not to.\n" + + "A folder 'penumbrametatmp' will be created as a subdirectory to the specified directory.\n" + + "If none is specified (i.e. this is blank) this folder will be created in the root folder instead." ); ImGui.SameLine(); if( ImGui.Button( LabelOpenTempFolder ) ) @@ -115,7 +113,7 @@ namespace Penumbra.UI { _config.IsEnabled = enabled; _configChanged = true; - Service.Get().ReloadPlayerResources(); + Service< ResidentResources >.Get().ReloadPlayerResources(); _base._penumbra.ObjectReloader.RedrawAll( enabled ? RedrawType.WithSettings : RedrawType.WithoutSettings ); if( _config.EnablePlayerWatch ) { @@ -177,10 +175,10 @@ namespace Penumbra.UI private void DrawDisableNotificationsBox() { - var fswatch = _config.DisableFileSystemNotifications; - if( ImGui.Checkbox( LabelDisableNotifications, ref fswatch ) ) + var fsWatch = _config.DisableFileSystemNotifications; + if( ImGui.Checkbox( LabelDisableNotifications, ref fsWatch ) ) { - _config.DisableFileSystemNotifications = fswatch; + _config.DisableFileSystemNotifications = fsWatch; _configChanged = true; } } @@ -210,39 +208,35 @@ namespace Penumbra.UI if( ImGui.Checkbox( LabelEnabledPlayerWatch, ref enabled ) ) { _config.EnablePlayerWatch = enabled; - _configChanged = true; + _configChanged = true; Penumbra.PlayerWatcher.SetStatus( enabled ); } - if( ImGui.IsItemHovered() ) + ImGuiCustom.HoverTooltip( + "If this setting is enabled, penumbra will keep tabs on characters that have a corresponding collection setup in the Collections tab.\n" + + "Penumbra will try to automatically redraw those characters using their collection when they first appear in an instance, or when they change their current equip." ); + + if( !_config.EnablePlayerWatch || !_config.ShowAdvanced ) { - ImGui.SetTooltip( - "If this setting is enabled, penumbra will keep tabs on characters that have a corresponding collection setup in the Collections tab.\n" - + "Penumbra will try to automatically redraw those characters using their collection when they first appear in an instance, or when they change their current equip." ); + return; } - if( _config.EnablePlayerWatch && _config.ShowAdvanced ) + var waitFrames = _config.WaitFrames; + ImGui.SameLine(); + ImGui.SetNextItemWidth( 50 ); + if( ImGui.InputInt( LabelWaitFrames, ref waitFrames, 0, 0 ) + && waitFrames != _config.WaitFrames + && waitFrames > 0 + && waitFrames < 3000 ) { - var waitFrames = _config.WaitFrames; - ImGui.SameLine(); - ImGui.SetNextItemWidth( 50 ); - if( ImGui.InputInt( LabelWaitFrames, ref waitFrames, 0, 0 ) - && waitFrames != _config.WaitFrames - && waitFrames > 0 - && waitFrames < 3000 ) - { - _base._penumbra.ObjectReloader.DefaultWaitFrames = waitFrames; - _config.WaitFrames = waitFrames; - _configChanged = true; - } - - if( ImGui.IsItemHovered() ) - { - ImGui.SetTooltip( - "The number of frames penumbra waits after some events (like zone changes) until it starts trying to redraw actors again, in a range of [1, 3001].\n" - + "Keep this as low as possible while producing stable results." ); - } + _base._penumbra.ObjectReloader.DefaultWaitFrames = waitFrames; + _config.WaitFrames = waitFrames; + _configChanged = true; } + + ImGuiCustom.HoverTooltip( + "The number of frames penumbra waits after some events (like zone changes) until it starts trying to redraw actors again, in a range of [1, 3001].\n" + + "Keep this as low as possible while producing stable results." ); } private static void DrawReloadResourceButton() @@ -264,23 +258,24 @@ namespace Penumbra.UI public void Draw() { - var ret = ImGui.BeginTabItem( LabelTab ); - if( !ret ) + if( !ImGui.BeginTabItem( LabelTab ) ) { return; } + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem ); + DrawRootFolder(); DrawRediscoverButton(); ImGui.SameLine(); DrawOpenModsButton(); - Custom.ImGuiCustom.VerticalDistance( DefaultVerticalSpace ); + ImGuiCustom.VerticalDistance( DefaultVerticalSpace ); DrawEnabledBox(); DrawEnabledPlayerWatcher(); - Custom.ImGuiCustom.VerticalDistance( DefaultVerticalSpace ); + ImGuiCustom.VerticalDistance( DefaultVerticalSpace ); DrawScaleModSelectorBox(); DrawSortFoldersFirstBox(); DrawShowAdvancedBox(); @@ -295,8 +290,6 @@ namespace Penumbra.UI _config.Save(); _configChanged = false; } - - ImGui.EndTabItem(); } } } diff --git a/Penumbra/UI/SettingsMenu.cs b/Penumbra/UI/SettingsMenu.cs index 430b3d06..e46034e8 100644 --- a/Penumbra/UI/SettingsMenu.cs +++ b/Penumbra/UI/SettingsMenu.cs @@ -1,6 +1,7 @@ using System.Numerics; using ImGuiNET; using Penumbra.Mods; +using Penumbra.UI.Custom; using Penumbra.Util; namespace Penumbra.UI @@ -54,13 +55,14 @@ namespace Penumbra.UI #else var ret = ImGui.Begin( _base._penumbra.Name, ref Visible ); #endif + using var raii = ImGuiRaii.DeferredEnd( ImGui.End ); if( !ret ) { - ImGui.End(); return; } ImGui.BeginTabBar( PenumbraSettingsLabel ); + raii.Push( ImGui.EndTabBar ); _settingsTab.Draw(); CollectionsTab.Draw(); @@ -82,10 +84,7 @@ namespace Penumbra.UI _base.DrawDebugTab(); _base.DrawResourceManagerTab(); } - - ImGui.EndTabBar(); - ImGui.End(); } } } -} +} \ No newline at end of file