Make interface code exception-resistant due to RAII, and global scale resistant.

This commit is contained in:
Ottermandias 2021-09-06 17:27:39 +02:00
parent 69cb329b8f
commit 23ebaf7a0d
21 changed files with 1053 additions and 822 deletions

View file

@ -8,13 +8,13 @@ namespace Penumbra.UI.Custom
public static partial class ImGuiCustom public static partial class ImGuiCustom
{ {
public static void BeginFramedGroup( string label ) 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 ) public static void BeginFramedGroup( string label, Vector2 minSize )
=> BeginFramedGroupInternal( ref label, minSize, false ); => BeginFramedGroupInternal( ref label, minSize, false );
public static bool BeginFramedGroupEdit( ref string label ) 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 ) public static bool BeginFramedGroupEdit( ref string label, Vector2 minSize )
=> BeginFramedGroupInternal( ref label, minSize, true ); => BeginFramedGroupInternal( ref label, minSize, true );
@ -27,8 +27,8 @@ namespace Penumbra.UI.Custom
ImGui.BeginGroup(); // First group ImGui.BeginGroup(); // First group
ImGui.PushStyleVar( ImGuiStyleVar.FramePadding, ZeroVector ); ImGui.PushStyleVar( ImGuiStyleVar.FramePadding, Vector2.Zero );
ImGui.PushStyleVar( ImGuiStyleVar.ItemSpacing, ZeroVector ); ImGui.PushStyleVar( ImGuiStyleVar.ItemSpacing, Vector2.Zero );
ImGui.BeginGroup(); // Second group ImGui.BeginGroup(); // Second group
@ -39,7 +39,7 @@ namespace Penumbra.UI.Custom
} }
// Ensure width. // Ensure width.
ImGui.Dummy( new Vector2( effectiveSize.X, 0 ) ); ImGui.Dummy( Vector2.UnitX * effectiveSize.X );
// Ensure left half boundary width/distance. // Ensure left half boundary width/distance.
ImGui.Dummy( halfFrameHeight ); ImGui.Dummy( halfFrameHeight );
@ -64,7 +64,7 @@ namespace Penumbra.UI.Custom
var labelMax = ImGui.GetItemRectMax(); var labelMax = ImGui.GetItemRectMax();
ImGui.SameLine(); ImGui.SameLine();
// Ensure height and distance to label. // 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. ImGui.BeginGroup(); // Fourth Group.
@ -96,8 +96,8 @@ namespace Penumbra.UI.Custom
ImGui.PopItemWidth(); ImGui.PopItemWidth();
ImGui.PushStyleVar( ImGuiStyleVar.FramePadding, ZeroVector ); ImGui.PushStyleVar( ImGuiStyleVar.FramePadding, Vector2.Zero );
ImGui.PushStyleVar( ImGuiStyleVar.ItemSpacing, ZeroVector ); ImGui.PushStyleVar( ImGuiStyleVar.ItemSpacing, Vector2.Zero );
ImGui.EndGroup(); // Close fourth group ImGui.EndGroup(); // Close fourth group
ImGui.EndGroup(); // Close third group ImGui.EndGroup(); // Close third group
@ -106,19 +106,19 @@ namespace Penumbra.UI.Custom
// Ensure right distance. // Ensure right distance.
ImGui.Dummy( halfFrameHeight ); ImGui.Dummy( halfFrameHeight );
// Ensure bottom distance // 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 ImGui.EndGroup(); // Close second group
var itemMin = ImGui.GetItemRectMin(); var itemMin = ImGui.GetItemRectMin();
var itemMax = ImGui.GetItemRectMax(); var itemMax = ImGui.GetItemRectMax();
var (currentLabelMin, currentLabelMax) = LabelStack[ LabelStack.Count - 1 ]; var (currentLabelMin, currentLabelMax) = LabelStack[ ^1 ];
LabelStack.RemoveAt( LabelStack.Count - 1 ); LabelStack.RemoveAt( LabelStack.Count - 1 );
var halfFrame = new Vector2( frameHeight / 8, frameHeight / 2 ); var halfFrame = new Vector2( frameHeight / 8, frameHeight / 2 );
currentLabelMin.X -= itemSpacing.X; currentLabelMin.X -= itemSpacing.X;
currentLabelMax.X += itemSpacing.X; currentLabelMax.X += itemSpacing.X;
var frameMin = itemMin + halfFrame; var frameMin = itemMin + halfFrame;
var frameMax = itemMax - new Vector2( halfFrame.X, 0 ); var frameMax = itemMax - Vector2.UnitX * halfFrame.X;
// Left // Left
DrawClippedRect( new Vector2( -float.MaxValue, -float.MaxValue ), new Vector2( currentLabelMin.X, float.MaxValue ), frameMin, 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 ); ImGui.PopStyleVar( 2 );
// This seems wrong? // This seems wrong?
// ImGui.SetWindowSize( new Vector2( ImGui.GetWindowSize().X + frameHeight, ImGui.GetWindowSize().Y ) ); // ImGui.SetWindowSize( new Vector2( ImGui.GetWindowSize().X + frameHeight, ImGui.GetWindowSize().Y ) );
ImGui.Dummy( ZeroVector ); ImGui.Dummy( Vector2.Zero );
ImGui.EndGroup(); // Close first group ImGui.EndGroup(); // Close first group
} }
private static readonly Vector2 ZeroVector = new( 0, 0 );
private static readonly List< (Vector2, Vector2) > LabelStack = new(); private static readonly List< (Vector2, Vector2) > LabelStack = new();
} }
} }

View file

@ -1,4 +1,6 @@
using System.Security.Cryptography.X509Certificates;
using System.Windows.Forms; using System.Windows.Forms;
using Dalamud.Interface;
using ImGuiNET; using ImGuiNET;
namespace Penumbra.UI.Custom namespace Penumbra.UI.Custom
@ -23,7 +25,7 @@ namespace Penumbra.UI.Custom
{ {
public static void VerticalDistance( float distance ) 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 ) public static void RightJustifiedText( float pos, string text )
@ -39,4 +41,25 @@ namespace Penumbra.UI.Custom
ImGui.SameLine( pos ); 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();
}
}
} }

View file

@ -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 );
}
}
}

View file

@ -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 );
}
}
}

View file

@ -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 );
}
}
}

View file

@ -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 );
}
}
}

View file

@ -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 );
}
}
}

View file

@ -1,4 +1,5 @@
using ImGuiNET; using ImGuiNET;
using Penumbra.UI.Custom;
namespace Penumbra.UI namespace Penumbra.UI
{ {
@ -30,28 +31,30 @@ namespace Penumbra.UI
return; return;
} }
if( ImGui.BeginMenu( MenuLabel ) ) using var raii = ImGuiRaii.DeferredEnd( ImGui.EndMainMenuBar );
if( !ImGui.BeginMenu( MenuLabel ) )
{ {
if( ImGui.MenuItem( MenuItemToggle, SlashCommand, _base._menu.Visible ) ) return;
{
_base.FlipVisibility();
}
if( ImGui.MenuItem( MenuItemRediscover ) )
{
_base.ReloadMods();
}
#if DEBUG
if( ImGui.MenuItem( MenuItemHide ) )
{
_showDebugBar = false;
}
#endif
ImGui.EndMenu();
} }
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
} }
} }
} }

View file

@ -7,6 +7,7 @@ using Dalamud.Logging;
using ImGuiNET; using ImGuiNET;
using Penumbra.Mod; using Penumbra.Mod;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.UI.Custom;
using Penumbra.Util; using Penumbra.Util;
namespace Penumbra.UI namespace Penumbra.UI
@ -97,12 +98,7 @@ namespace Penumbra.UI
{ {
ImGui.InputTextWithHint( "##New Collection", "New Collection", ref _newCollectionName, 64 ); ImGui.InputTextWithHint( "##New Collection", "New Collection", ref _newCollectionName, 64 );
var changedStyle = false; using var style = ImGuiRaii.PushStyle( ImGuiStyleVar.Alpha, 0.5f, _newCollectionName.Length == 0 );
if( _newCollectionName.Length == 0 )
{
changedStyle = true;
ImGui.PushStyleVar( ImGuiStyleVar.Alpha, 0.5f );
}
if( ImGui.Button( "Create New Empty Collection" ) && _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 ); CreateNewCollection( _manager.Collections.CurrentCollection.Settings );
} }
if( changedStyle ) style.Pop();
{
ImGui.PopStyleVar();
}
if( _manager.Collections.Collections.Count > 1 if( _manager.Collections.Collections.Count > 1
&& _manager.Collections.CurrentCollection.Name != ModCollection.DefaultCollection ) && _manager.Collections.CurrentCollection.Name != ModCollection.DefaultCollection )
@ -161,11 +154,8 @@ namespace Penumbra.UI
{ {
var index = _currentCollectionIndex; var index = _currentCollectionIndex;
var combo = ImGui.Combo( LabelCurrentCollection, ref index, _collectionNames ); var combo = ImGui.Combo( LabelCurrentCollection, ref index, _collectionNames );
if( tooltip && ImGui.IsItemHovered() ) ImGuiCustom.HoverTooltip(
{ "This collection will be modified when using the Installed Mods tab and making changes. It does not apply to anything by itself." );
ImGui.SetTooltip(
"This collection will be modified when using the Installed Mods tab and making changes. It does not apply to anything by itself." );
}
if( combo ) if( combo )
{ {
@ -182,15 +172,12 @@ namespace Penumbra.UI
_currentDefaultIndex = index; _currentDefaultIndex = index;
} }
if( ImGui.IsItemHovered() ) ImGuiCustom.HoverTooltip(
{ "Mods in the default collection are loaded for any character that is not explicitly named in the character collections below.\n"
ImGui.SetTooltip( + "They also take precedence before the forced collection." );
"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.SameLine();
ImGui.Dummy( new Vector2( 24, 0 ) ); ImGuiHelpers.ScaledDummy( 24, 0 );
ImGui.SameLine(); ImGui.SameLine();
ImGui.Text( "Default Collection" ); ImGui.Text( "Default Collection" );
} }
@ -204,15 +191,12 @@ namespace Penumbra.UI
_currentForcedIndex = index; _currentForcedIndex = index;
} }
if( ImGui.IsItemHovered() ) ImGuiCustom.HoverTooltip(
{ "Mods in the forced collection are always loaded if not overwritten by anything in the current or character-based collection.\n"
ImGui.SetTooltip( + "Please avoid mixing meta-manipulating mods in Forced and other collections, as this will probably not work correctly." );
"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.SameLine();
ImGui.Dummy( new Vector2( 24, 0 ) ); ImGuiHelpers.ScaledDummy( 24, 0 );
ImGui.SameLine(); ImGui.SameLine();
ImGui.Text( "Forced Collection" ); ImGui.Text( "Forced Collection" );
} }
@ -221,12 +205,7 @@ namespace Penumbra.UI
{ {
ImGui.InputTextWithHint( "##New Character", "New Character Name", ref _newCharacterName, 32 ); ImGui.InputTextWithHint( "##New Character", "New Character Name", ref _newCharacterName, 32 );
var changedStyle = false; using var style = ImGuiRaii.PushStyle( ImGuiStyleVar.Alpha, 0.5f, _newCharacterName.Length == 0 );
if( _newCharacterName.Length == 0 )
{
changedStyle = true;
ImGui.PushStyleVar( ImGuiStyleVar.Alpha, 0.5f );
}
ImGui.SameLine(); ImGui.SameLine();
if( ImGui.Button( "Create New Character Collection" ) && _newCharacterName.Length > 0 ) if( ImGui.Button( "Create New Character Collection" ) && _newCharacterName.Length > 0 )
@ -236,25 +215,19 @@ namespace Penumbra.UI
_newCharacterName = string.Empty; _newCharacterName = string.Empty;
} }
if( ImGui.IsItemHovered() ) style.Pop();
{
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" );
}
if( changedStyle ) ImGuiCustom.HoverTooltip(
{ "A character collection will be used whenever you manually redraw a character with the Name you have set up.\n"
ImGui.PopStyleVar(); + "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() private void DrawCharacterCollectionSelectors()
{ {
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndChild );
if( !ImGui.BeginChild( "##CollectionChild", AutoFillSize, true ) ) if( !ImGui.BeginChild( "##CollectionChild", AutoFillSize, true ) )
{ {
ImGui.EndChild();
return; return;
} }
@ -272,21 +245,20 @@ namespace Penumbra.UI
} }
ImGui.SameLine(); ImGui.SameLine();
ImGui.PushFont( UiBuilder.IconFont );
using var font = ImGuiRaii.PushFont( UiBuilder.IconFont );
if( ImGui.Button( $"{FontAwesomeIcon.Trash.ToIconString()}##{name}" ) ) if( ImGui.Button( $"{FontAwesomeIcon.Trash.ToIconString()}##{name}" ) )
{ {
_manager.Collections.RemoveCharacterCollection( name ); _manager.Collections.RemoveCharacterCollection( name );
} }
ImGui.PopFont(); font.Pop();
ImGui.SameLine(); ImGui.SameLine();
ImGui.Text( name ); ImGui.Text( name );
} }
DrawNewCharacterCollection(); DrawNewCharacterCollection();
ImGui.EndChild();
} }
public void Draw() public void Draw()
@ -296,19 +268,20 @@ namespace Penumbra.UI
return; return;
} }
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem )
.Push( ImGui.EndChild );
if( ImGui.BeginChild( "##CollectionHandling", new Vector2( -1, ImGui.GetTextLineHeightWithSpacing() * 6 ), true ) ) if( ImGui.BeginChild( "##CollectionHandling", new Vector2( -1, ImGui.GetTextLineHeightWithSpacing() * 6 ), true ) )
{ {
DrawCurrentCollectionSelector( true ); DrawCurrentCollectionSelector( true );
ImGui.Dummy( new Vector2( 0, 10 ) ); ImGuiHelpers.ScaledDummy( 0, 10 );
DrawNewCollectionInput(); DrawNewCollectionInput();
} }
ImGui.EndChild(); raii.Pop();
DrawCharacterCollectionSelectors(); DrawCharacterCollectionSelectors();
ImGui.EndTabItem();
} }
} }
} }

View file

@ -13,6 +13,7 @@ using Penumbra.GameData.Util;
using Penumbra.Interop; using Penumbra.Interop;
using Penumbra.Meta; using Penumbra.Meta;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.UI.Custom;
using Penumbra.Util; using Penumbra.Util;
namespace Penumbra.UI namespace Penumbra.UI
@ -38,6 +39,8 @@ namespace Penumbra.UI
return; return;
} }
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTable );
var identifier = GameData.GameData.GetIdentifier(); var identifier = GameData.GameData.GetIdentifier();
foreach( var (actor, equip) in players ) 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" ); ImGui.Text( identifier.Identify( equip.RFinger.Set, 0, equip.RFinger.Variant, EquipSlot.LFinger )?.Name.ToString() ?? "Unknown" );
// @formatter:on // @formatter:on
} }
ImGui.EndTable();
} }
private static void PrintValue( string name, string value ) private static void PrintValue( string name, string value )
@ -135,6 +136,8 @@ namespace Penumbra.UI
return; return;
} }
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTable );
var manager = Service< ModManager >.Get(); var manager = Service< ModManager >.Get();
PrintValue( "Active Collection", manager.Collections.ActiveCollection.Name ); PrintValue( "Active Collection", manager.Collections.ActiveCollection.Name );
PrintValue( "Mod Manager BasePath", manager.BasePath.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() ); ( !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 Exists", Directory.Exists( manager.TempPath.FullName ).ToString() );
PrintValue( "Mod Manager Temp Path IsWritable", manager.TempWritable.ToString() ); PrintValue( "Mod Manager Temp Path IsWritable", manager.TempWritable.ToString() );
ImGui.EndTable();
} }
private void DrawDebugTabRedraw() private void DrawDebugTabRedraw()
@ -207,9 +208,11 @@ namespace Penumbra.UI
.GetField( "_inGPose", BindingFlags.Instance | BindingFlags.NonPublic ) .GetField( "_inGPose", BindingFlags.Instance | BindingFlags.NonPublic )
?.GetValue( _penumbra.ObjectReloader ); ?.GetValue( _penumbra.ObjectReloader );
using var raii = new ImGuiRaii.EndStack();
if( ImGui.BeginTable( "##RedrawData", 2, ImGuiTableFlags.SizingFixedFit, if( ImGui.BeginTable( "##RedrawData", 2, ImGuiTableFlags.SizingFixedFit,
new Vector2( -1, ImGui.GetTextLineHeightWithSpacing() * 7 ) ) ) new Vector2( -1, ImGui.GetTextLineHeightWithSpacing() * 7 ) ) )
{ {
raii.Push( ImGui.EndTable );
PrintValue( "Current Wait Frame", waitFrames?.ToString() ?? "null" ); PrintValue( "Current Wait Frame", waitFrames?.ToString() ?? "null" );
PrintValue( "Current Frame", currentFrame?.ToString() ?? "null" ); PrintValue( "Current Frame", currentFrame?.ToString() ?? "null" );
PrintValue( "Currently in GPose", gPose?.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 Address", currentObject?.Address.ToString( "X16" ) ?? "null" );
PrintValue( "Current Object Index", currentObjectIdx >= 0 ? currentObjectIdx.ToString() : "null" ); PrintValue( "Current Object Index", currentObjectIdx >= 0 ? currentObjectIdx.ToString() : "null" );
PrintValue( "Current Object Render Flags", ( ( int? )currentRender )?.ToString( "X8" ) ?? "null" ); PrintValue( "Current Object Render Flags", ( ( int? )currentRender )?.ToString( "X8" ) ?? "null" );
ImGui.EndTable();
} }
if( queue.Any() if( queue.Any()
&& ImGui.BeginTable( "##RedrawTable", 3, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.ScrollX, && ImGui.BeginTable( "##RedrawTable", 3, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.ScrollX,
new Vector2( -1, ImGui.GetTextLineHeightWithSpacing() * queue.Count ) ) ) new Vector2( -1, ImGui.GetTextLineHeightWithSpacing() * queue.Count ) ) )
{ {
raii.Push( ImGui.EndTable );
foreach( var (objectId, objectName, redraw) in queue ) foreach( var (objectId, objectName, redraw) in queue )
{ {
ImGui.TableNextRow(); ImGui.TableNextRow();
@ -239,8 +242,6 @@ namespace Penumbra.UI
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.Text( redraw.ToString() ); ImGui.Text( redraw.ToString() );
} }
ImGui.EndTable();
} }
if( queue.Any() && ImGui.Button( "Clear" ) ) if( queue.Any() && ImGui.Button( "Clear" ) )
@ -263,6 +264,8 @@ namespace Penumbra.UI
return; return;
} }
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTable );
foreach( var collection in Service< ModManager >.Get().Collections.Collections.Values.Where( c => c.Cache != null ) ) foreach( var collection in Service< ModManager >.Get().Collections.Collections.Values.Where( c => c.Cache != null ) )
{ {
var manip = collection.Cache!.MetaManipulations; var manip = collection.Cache!.MetaManipulations;
@ -285,39 +288,58 @@ namespace Penumbra.UI
ImGui.Text( info.Changed ? "Data Changed" : "Unchanged" ); ImGui.Text( info.Changed ? "Data Changed" : "Unchanged" );
} }
} }
ImGui.EndTable();
} }
private void DrawDebugTabIpc() private void DrawDebugTabIpc()
{ {
if( !ImGui.CollapsingHeader( "IPC##Debug" ) ) if( !ImGui.CollapsingHeader( "IPC##Debug" ) )
{ {
return; return;
} }
var ipc = _penumbra.Ipc; var ipc = _penumbra.Ipc;
ImGui.Text($"API Version: {ipc.Api.ApiVersion}" ); ImGui.Text( $"API Version: {ipc.Api.ApiVersion}" );
ImGui.Text("Available subscriptions:" ); ImGui.Text( "Available subscriptions:" );
ImGui.Indent(); using var indent = ImGuiRaii.PushIndent();
if (ipc.ProviderApiVersion != null) if( ipc.ProviderApiVersion != null )
{
ImGui.Text( PenumbraIpc.LabelProviderApiVersion ); ImGui.Text( PenumbraIpc.LabelProviderApiVersion );
}
if( ipc.ProviderRedrawName != null ) if( ipc.ProviderRedrawName != null )
{
ImGui.Text( PenumbraIpc.LabelProviderRedrawName ); ImGui.Text( PenumbraIpc.LabelProviderRedrawName );
}
if( ipc.ProviderRedrawObject != null ) if( ipc.ProviderRedrawObject != null )
{
ImGui.Text( PenumbraIpc.LabelProviderRedrawObject ); ImGui.Text( PenumbraIpc.LabelProviderRedrawObject );
}
if( ipc.ProviderRedrawAll != null ) if( ipc.ProviderRedrawAll != null )
{
ImGui.Text( PenumbraIpc.LabelProviderRedrawAll ); ImGui.Text( PenumbraIpc.LabelProviderRedrawAll );
}
if( ipc.ProviderResolveDefault != null ) if( ipc.ProviderResolveDefault != null )
{
ImGui.Text( PenumbraIpc.LabelProviderResolveDefault ); ImGui.Text( PenumbraIpc.LabelProviderResolveDefault );
}
if( ipc.ProviderResolveCharacter != null ) if( ipc.ProviderResolveCharacter != null )
{
ImGui.Text( PenumbraIpc.LabelProviderResolveCharacter ); ImGui.Text( PenumbraIpc.LabelProviderResolveCharacter );
}
if( ipc.ProviderChangedItemTooltip != null ) if( ipc.ProviderChangedItemTooltip != null )
{
ImGui.Text( PenumbraIpc.LabelProviderChangedItemTooltip ); ImGui.Text( PenumbraIpc.LabelProviderChangedItemTooltip );
}
if( ipc.ProviderChangedItemClick != null ) if( ipc.ProviderChangedItemClick != null )
{
ImGui.Text( PenumbraIpc.LabelProviderChangedItemClick ); ImGui.Text( PenumbraIpc.LabelProviderChangedItemClick );
ImGui.Unindent(); }
} }
private void DrawDebugTab() private void DrawDebugTab()
@ -327,6 +349,8 @@ namespace Penumbra.UI
return; return;
} }
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
DrawDebugTabGeneral(); DrawDebugTabGeneral();
ImGui.NewLine(); ImGui.NewLine();
DrawDebugTabRedraw(); DrawDebugTabRedraw();
@ -337,8 +361,6 @@ namespace Penumbra.UI
ImGui.NewLine(); ImGui.NewLine();
DrawDebugTabIpc(); DrawDebugTabIpc();
ImGui.NewLine(); ImGui.NewLine();
ImGui.EndTabItem();
} }
} }
} }

View file

@ -5,6 +5,7 @@ using ImGuiNET;
using Penumbra.GameData.Util; using Penumbra.GameData.Util;
using Penumbra.Meta; using Penumbra.Meta;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.UI.Custom;
using Penumbra.Util; using Penumbra.Util;
namespace Penumbra.UI namespace Penumbra.UI
@ -13,9 +14,8 @@ namespace Penumbra.UI
{ {
private class TabEffective private class TabEffective
{ {
private const string LabelTab = "Effective Changes"; private const string LabelTab = "Effective Changes";
private static readonly string LongArrowLeft = $"{( char )FontAwesomeIcon.LongArrowAltLeft}"; private readonly ModManager _modManager;
private readonly ModManager _modManager;
private readonly float _leftTextLength = private readonly float _leftTextLength =
ImGui.CalcTextSize( "chara/human/c0000/obj/body/b0000/material/v0000/mt_c0000b0000_b.mtrl" ).X + 40; 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 ) private static void DrawFileLine( FileInfo file, GamePath path )
{ {
ImGui.TableNextColumn(); ImGui.TableNextColumn();
Custom.ImGuiCustom.CopyOnClickSelectable( path ); ImGuiCustom.CopyOnClickSelectable( path );
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.PushFont( UiBuilder.IconFont ); ImGuiCustom.PrintIcon( FontAwesomeIcon.LongArrowAltLeft );
ImGui.TextUnformatted( LongArrowLeft );
ImGui.PopFont();
ImGui.SameLine(); ImGui.SameLine();
Custom.ImGuiCustom.CopyOnClickSelectable( file.FullName ); ImGuiCustom.CopyOnClickSelectable( file.FullName );
} }
private static void DrawManipulationLine( MetaManipulation manip, Mod.Mod mod ) private static void DrawManipulationLine( MetaManipulation manip, Mod.Mod mod )
@ -43,9 +41,7 @@ namespace Penumbra.UI
ImGui.Selectable( manip.IdentifierString() ); ImGui.Selectable( manip.IdentifierString() );
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.PushFont( UiBuilder.IconFont ); ImGuiCustom.PrintIcon( FontAwesomeIcon.LongArrowAltLeft );
ImGui.TextUnformatted( LongArrowLeft );
ImGui.PopFont();
ImGui.SameLine(); ImGui.SameLine();
ImGui.Selectable( mod.Data.Meta.Name ); ImGui.Selectable( mod.Data.Meta.Name );
} }
@ -57,17 +53,19 @@ namespace Penumbra.UI
return; return;
} }
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
const ImGuiTableFlags flags = ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollX; const ImGuiTableFlags flags = ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollX;
var activeCollection = _modManager.Collections.ActiveCollection.Cache; var activeCollection = _modManager.Collections.ActiveCollection.Cache;
var forcedCollection = _modManager.Collections.ForcedCollection.Cache; var forcedCollection = _modManager.Collections.ForcedCollection.Cache;
var (activeResolved, activeMeta) = activeCollection != null var (activeResolved, activeMeta) = activeCollection != null
? ( activeCollection.ResolvedFiles.Count, activeCollection.MetaManipulations.Count ) ? ( activeCollection.ResolvedFiles.Count, activeCollection.MetaManipulations.Count )
: ( 0, 0 ); : ( 0, 0 );
var (forcedResolved, forcedMeta) = forcedCollection != null var (forcedResolved, forcedMeta) = forcedCollection != null
? (forcedCollection.ResolvedFiles.Count, forcedCollection.MetaManipulations.Count) ? ( forcedCollection.ResolvedFiles.Count, forcedCollection.MetaManipulations.Count )
: (0, 0); : ( 0, 0 );
var lines = activeResolved + forcedResolved + activeMeta + forcedMeta; var lines = activeResolved + forcedResolved + activeMeta + forcedMeta;
ImGuiListClipperPtr clipper; ImGuiListClipperPtr clipper;
@ -80,6 +78,7 @@ namespace Penumbra.UI
if( ImGui.BeginTable( "##effective_changes", 2, flags, AutoFillSize ) ) if( ImGui.BeginTable( "##effective_changes", 2, flags, AutoFillSize ) )
{ {
raii.Push( ImGui.EndTable );
ImGui.TableSetupColumn( "##tableGamePathCol", ImGuiTableColumnFlags.None, _leftTextLength ); ImGui.TableSetupColumn( "##tableGamePathCol", ImGuiTableColumnFlags.None, _leftTextLength );
while( clipper.Step() ) while( clipper.Step() )
{ {
@ -89,32 +88,28 @@ namespace Penumbra.UI
ImGui.TableNextRow(); ImGui.TableNextRow();
if( row < activeResolved ) if( row < activeResolved )
{ {
var file = activeCollection!.ResolvedFiles.ElementAt( row ); var (gamePath, file) = activeCollection!.ResolvedFiles.ElementAt( row );
DrawFileLine( file.Value, file.Key ); DrawFileLine( file, gamePath );
} }
else if( ( row -= activeResolved ) < forcedResolved ) else if( ( row -= activeResolved ) < forcedResolved )
{ {
var file = forcedCollection!.ResolvedFiles.ElementAt( row ); var (gamePath, file) = forcedCollection!.ResolvedFiles.ElementAt( row );
DrawFileLine( file.Value, file.Key ); DrawFileLine( file, gamePath );
} }
else if( ( row -= forcedResolved ) < activeMeta ) else if( ( row -= forcedResolved ) < activeMeta )
{ {
var manip = activeCollection!.MetaManipulations.Manipulations.ElementAt( row ); var (manip, mod) = activeCollection!.MetaManipulations.Manipulations.ElementAt( row );
DrawManipulationLine( manip.Item1, manip.Item2 ); DrawManipulationLine( manip, mod );
} }
else else
{ {
row -= activeMeta; row -= activeMeta;
var manip = forcedCollection!.MetaManipulations.Manipulations.ElementAt( row ); var (manip, mod) = forcedCollection!.MetaManipulations.Manipulations.ElementAt( row );
DrawManipulationLine( manip.Item1, manip.Item2 ); DrawManipulationLine( manip, mod );
} }
} }
} }
ImGui.EndTable();
} }
ImGui.EndTabItem();
} }
} }
} }

View file

@ -8,6 +8,7 @@ using Dalamud.Logging;
using ImGuiNET; using ImGuiNET;
using Penumbra.Importer; using Penumbra.Importer;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.UI.Custom;
using Penumbra.Util; using Penumbra.Util;
namespace Penumbra.UI namespace Penumbra.UI
@ -104,20 +105,20 @@ namespace Penumbra.UI
{ {
if( !_manager.Valid ) if( !_manager.Valid )
{ {
ImGui.PushStyleVar( ImGuiStyleVar.Alpha, 0.5f ); using var style = ImGuiRaii.PushStyle( ImGuiStyleVar.Alpha, 0.5f );
ImGui.Button( LabelImportButton ); 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.Text( "Can not import since the mod directory path is not valid." );
ImGui.Dummy( Vector2.UnitY * ImGui.GetTextLineHeightWithSpacing() ); ImGui.Dummy( Vector2.UnitY * ImGui.GetTextLineHeightWithSpacing() );
ImGui.PopStyleColor(); color.Pop();
ImGui.Text( "Please set the mod directory in the settings tab." ); 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.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.Text( " D:\\ffxivmods" );
ImGui.PopStyleColor(); color.Pop();
ImGui.Text( "You can return to this tab once you've done that." ); ImGui.Text( "You can return to this tab once you've done that." );
} }
else if( ImGui.Button( LabelImportButton ) ) else if( ImGui.Button( LabelImportButton ) )
@ -156,19 +157,19 @@ namespace Penumbra.UI
private void DrawFailedImportMessage() 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.Text( $"One or more of your modpacks failed to import:\n\t\t{_errorMessage}" );
ImGui.PopStyleColor();
} }
public void Draw() public void Draw()
{ {
var ret = ImGui.BeginTabItem( LabelTab ); if( !ImGui.BeginTabItem( LabelTab ) )
if( !ret )
{ {
return; return;
} }
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
if( !_isImportRunning ) if( !_isImportRunning )
{ {
DrawImportButton(); DrawImportButton();
@ -182,8 +183,6 @@ namespace Penumbra.UI
{ {
DrawFailedImportMessage(); DrawFailedImportMessage();
} }
ImGui.EndTabItem();
} }
} }
} }

View file

@ -1,5 +1,6 @@
using ImGuiNET; using ImGuiNET;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.UI.Custom;
using Penumbra.Util; using Penumbra.Util;
namespace Penumbra.UI namespace Penumbra.UI
@ -34,6 +35,8 @@ namespace Penumbra.UI
return; return;
} }
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
if( _modManager.Mods.Count > 0 ) if( _modManager.Mods.Count > 0 )
{ {
Selector.Draw(); Selector.Draw();
@ -44,8 +47,6 @@ namespace Penumbra.UI
{ {
DrawNoModsAvailable(); DrawNoModsAvailable();
} }
ImGui.EndTabItem();
} }
} }
} }

View file

@ -2,14 +2,15 @@ using System.IO;
using System.Linq; using System.Linq;
using Dalamud.Interface; using Dalamud.Interface;
using ImGuiNET; using ImGuiNET;
using Penumbra.Api;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Penumbra.GameData.Util; using Penumbra.GameData.Util;
using Penumbra.Meta; using Penumbra.Meta;
using Penumbra.Mod; using Penumbra.Mod;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.Structs; using Penumbra.Structs;
using Penumbra.UI.Custom;
using Penumbra.Util; using Penumbra.Util;
using ImGui = ImGuiNET.ImGui;
namespace Penumbra.UI namespace Penumbra.UI
{ {
@ -140,6 +141,8 @@ namespace Penumbra.UI
return; return;
} }
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
var desc = Meta.Description; var desc = Meta.Description;
var flags = _editMode var flags = _editMode
? ImGuiInputTextFlags.EnterReturnsTrue | ImGuiInputTextFlags.CtrlEnterForNewLine ? ImGuiInputTextFlags.EnterReturnsTrue | ImGuiInputTextFlags.CtrlEnterForNewLine
@ -154,17 +157,12 @@ namespace Penumbra.UI
_selector.SaveCurrentMod(); _selector.SaveCurrentMod();
} }
if( ImGui.IsItemHovered() ) ImGuiCustom.HoverTooltip( TooltipAboutEdit );
{
ImGui.SetTooltip( TooltipAboutEdit );
}
} }
else else
{ {
ImGui.TextWrapped( desc ); ImGui.TextWrapped( desc );
} }
ImGui.EndTabItem();
} }
private void DrawChangedItemsTab() private void DrawChangedItemsTab()
@ -174,31 +172,33 @@ namespace Penumbra.UI
return; 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 ) return;
{
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();
} }
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() private void DrawConflictTab()
@ -208,38 +208,39 @@ namespace Penumbra.UI
return; return;
} }
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
ImGui.SetNextItemWidth( -1 ); ImGui.SetNextItemWidth( -1 );
if( ImGui.BeginListBox( LabelConflictsHeader, AutoFillSize ) ) if( !ImGui.BeginListBox( LabelConflictsHeader, AutoFillSize ) )
{ {
foreach( var kv in Mod.Cache.Conflicts ) return;
{
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();
} }
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() private void DrawFileSwapTab()
@ -255,31 +256,31 @@ namespace Penumbra.UI
return; return;
} }
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
const ImGuiTableFlags flags = ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollX; const ImGuiTableFlags flags = ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollX;
ImGui.SetNextItemWidth( -1 ); ImGui.SetNextItemWidth( -1 );
if( ImGui.BeginTable( LabelFileSwapHeader, 3, flags, AutoFillSize ) ) if( !ImGui.BeginTable( LabelFileSwapHeader, 3, flags, AutoFillSize ) )
{ {
foreach( var file in Meta.FileSwaps ) return;
{
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();
} }
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() private void UpdateFilenameList()
@ -329,30 +330,26 @@ namespace Penumbra.UI
return; return;
} }
if( ImGui.IsItemHovered() ) using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
{ ImGuiCustom.HoverTooltip( TooltipFilesTab );
ImGui.SetTooltip( TooltipFilesTab );
}
ImGui.SetNextItemWidth( -1 ); ImGui.SetNextItemWidth( -1 );
if( ImGui.BeginListBox( LabelFileListHeader, AutoFillSize ) ) if( ImGui.BeginListBox( LabelFileListHeader, AutoFillSize ) )
{ {
raii.Push( ImGui.EndListBox );
UpdateFilenameList(); UpdateFilenameList();
using var colorRaii = new ImGuiRaii.Color();
foreach( var (name, _, color, _) in _fullFilenameList! ) foreach( var (name, _, color, _) in _fullFilenameList! )
{ {
ImGui.PushStyleColor( ImGuiCol.Text, color ); colorRaii.Push( ImGuiCol.Text, color );
ImGui.Selectable( name.FullName ); ImGui.Selectable( name.FullName );
ImGui.PopStyleColor(); colorRaii.Pop();
} }
ImGui.EndListBox();
} }
else else
{ {
_fullFilenameList = null; _fullFilenameList = null;
} }
ImGui.EndTabItem();
} }
private static int HandleDefaultString( GamePath[] gamePaths, out int removeFolders ) private static int HandleDefaultString( GamePath[] gamePaths, out int removeFolders )
@ -469,10 +466,7 @@ namespace Penumbra.UI
ImGui.SetNextItemWidth( -1 ); ImGui.SetNextItemWidth( -1 );
ImGui.InputTextWithHint( LabelGamePathsEditBox, "Hover for help...", ref _currentGamePaths, ImGui.InputTextWithHint( LabelGamePathsEditBox, "Hover for help...", ref _currentGamePaths,
128 ); 128 );
if( ImGui.IsItemHovered() ) ImGuiCustom.HoverTooltip( TooltipGamePathsEdit );
{
ImGui.SetTooltip( TooltipGamePathsEdit );
}
} }
private void DrawGroupRow() private void DrawGroupRow()
@ -516,12 +510,11 @@ namespace Penumbra.UI
loc = colorReplace; 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.Selectable( _fullFilenameList[ idx ].name.FullName, ref _fullFilenameList[ idx ].selected );
ImGui.PopStyleColor();
} }
const float indent = 30f; const float indentWidth = 30f;
if( _selectedOption == null ) if( _selectedOption == null )
{ {
Selectable( 0, ColorGreen ); Selectable( 0, ColorGreen );
@ -534,8 +527,8 @@ namespace Penumbra.UI
{ {
Selectable( 0, ColorGreen ); Selectable( 0, ColorGreen );
ImGui.Indent( indent ); using var indent = ImGuiRaii.PushIndent( indentWidth );
var tmpPaths = gamePaths.ToArray(); var tmpPaths = gamePaths.ToArray();
foreach( var gamePath in tmpPaths ) foreach( var gamePath in tmpPaths )
{ {
string tmp = gamePath; string tmp = gamePath;
@ -556,8 +549,6 @@ namespace Penumbra.UI
_selector.ReloadCurrentMod(); _selector.ReloadCurrentMod();
} }
} }
ImGui.Unindent( indent );
} }
else else
{ {
@ -588,14 +579,13 @@ namespace Penumbra.UI
return; 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 ) for( var i = 0; i < group.Options.Count; ++i )
{ {
DrawMultiSelectorCheckBox( group, i, Mod.Settings.Settings[ group.GroupName ], DrawMultiSelectorCheckBox( group, i, Mod.Settings.Settings[ group.GroupName ],
$"{group.Options[ i ].OptionName}##{group.GroupName}" ); $"{group.Options[ i ].OptionName}##{group.GroupName}" );
} }
Custom.ImGuiCustom.EndFramedGroup();
} }
private void DrawSingleSelector( OptionGroup group ) private void DrawSingleSelector( OptionGroup group )
@ -635,79 +625,76 @@ namespace Penumbra.UI
private void DrawConfigurationTab() private void DrawConfigurationTab()
{ {
if( !_editMode && !Meta.HasGroupsWithConfig ) if( !_editMode && !Meta.HasGroupsWithConfig || !ImGui.BeginTabItem( LabelConfigurationTab ) )
{ {
return; return;
} }
if( ImGui.BeginTabItem( LabelConfigurationTab ) ) using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
if( _editMode )
{ {
if( _editMode ) DrawGroupSelectorsEdit();
{ }
DrawGroupSelectorsEdit(); else
} {
else DrawGroupSelectors();
{
DrawGroupSelectors();
}
ImGui.EndTabItem();
} }
} }
private void DrawMetaManipulationsTab() private void DrawMetaManipulationsTab()
{ {
if( !_editMode && Mod.Data.Resources.MetaManipulations.Count == 0 ) if( !_editMode && Mod.Data.Resources.MetaManipulations.Count == 0 || !ImGui.BeginTabItem( "Meta Manipulations" ) )
{ {
return; return;
} }
if( !ImGui.BeginTabItem( "Meta Manipulations" ) ) using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
if( !ImGui.BeginListBox( "##MetaManipulations", AutoFillSize ) )
{ {
return; 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; if( ImGui.CollapsingHeader( "Default" ) )
var changes = false;
if( _editMode || manips.DefaultData.Count > 0 )
{ {
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 ) public void Draw( bool editMode )
{ {
_editMode = editMode; _editMode = editMode;
ImGui.BeginTabBar( LabelPluginDetails ); if( !ImGui.BeginTabBar( LabelPluginDetails ) )
{
return;
}
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabBar );
DrawAboutTab(); DrawAboutTab();
DrawChangedItemsTab(); DrawChangedItemsTab();
@ -724,7 +711,6 @@ namespace Penumbra.UI
DrawFileSwapTab(); DrawFileSwapTab();
DrawMetaManipulationsTab(); DrawMetaManipulationsTab();
DrawConflictTab(); DrawConflictTab();
ImGui.EndTabBar();
} }
} }
} }

View file

@ -6,6 +6,7 @@ using ImGuiNET;
using Penumbra.GameData.Util; using Penumbra.GameData.Util;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.Structs; using Penumbra.Structs;
using Penumbra.UI.Custom;
using Penumbra.Util; using Penumbra.Util;
namespace Penumbra.UI namespace Penumbra.UI
@ -38,7 +39,7 @@ namespace Penumbra.UI
private bool DrawEditGroupSelector() private bool DrawEditGroupSelector()
{ {
ImGui.SetNextItemWidth( OptionSelectionWidth ); ImGui.SetNextItemWidth( OptionSelectionWidth * ImGuiHelpers.GlobalScale );
if( Meta!.Groups.Count == 0 ) if( Meta!.Groups.Count == 0 )
{ {
ImGui.Combo( LabelGroupSelect, ref _selectedGroupIndex, TextNoOptionAvailable, 1 ); ImGui.Combo( LabelGroupSelect, ref _selectedGroupIndex, TextNoOptionAvailable, 1 );
@ -87,7 +88,7 @@ namespace Penumbra.UI
} }
ImGui.SetNextItemWidth( -1 ); 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 ) 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; 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() ) return new ImGuiRaii.EndStack();
{
_selector.Cache.TriggerFilterReset();
}
} }
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 ) private void DrawMultiSelectorEditAdd( OptionGroup group, float nameBoxStart )
{ {
var newOption = ""; var newOption = "";
ImGui.SetCursorPosX( nameBoxStart ); ImGui.SetCursorPosX( nameBoxStart );
ImGui.SetNextItemWidth( MultiEditBoxWidth ); ImGui.SetNextItemWidth( MultiEditBoxWidth * ImGuiHelpers.GlobalScale );
if( ImGui.InputTextWithHint( $"##new_{group.GroupName}_l", "Add new option...", ref newOption, 64, if( ImGui.InputTextWithHint( $"##new_{group.GroupName}_l", "Add new option...", ref newOption, 64,
ImGuiInputTextFlags.EnterReturnsTrue ) ImGuiInputTextFlags.EnterReturnsTrue )
&& newOption.Length != 0 ) && newOption.Length != 0 )
@ -142,7 +147,7 @@ namespace Penumbra.UI
var nameBoxStart = CheckMarkSize; var nameBoxStart = CheckMarkSize;
var flag = Mod!.Settings.Settings[ group.GroupName ]; var flag = Mod!.Settings.Settings[ group.GroupName ];
DrawMultiSelectorEditBegin( group ); using var raii = DrawMultiSelectorEditBegin( group );
for( var i = 0; i < group.Options.Count; ++i ) for( var i = 0; i < group.Options.Count; ++i )
{ {
var opt = group.Options[ i ]; var opt = group.Options[ i ];
@ -157,7 +162,7 @@ namespace Penumbra.UI
nameBoxStart = ImGui.GetCursorPosX(); nameBoxStart = ImGui.GetCursorPosX();
} }
ImGui.SetNextItemWidth( MultiEditBoxWidth ); ImGui.SetNextItemWidth( MultiEditBoxWidth * ImGuiHelpers.GlobalScale );
if( ImGui.InputText( $"{label}_l", ref newName, 64, ImGuiInputTextFlags.EnterReturnsTrue ) ) if( ImGui.InputText( $"{label}_l", ref newName, 64, ImGuiInputTextFlags.EnterReturnsTrue ) )
{ {
if( newName.Length == 0 ) if( newName.Length == 0 )
@ -179,8 +184,6 @@ namespace Penumbra.UI
} }
DrawMultiSelectorEditAdd( group, nameBoxStart ); DrawMultiSelectorEditAdd( group, nameBoxStart );
Custom.ImGuiCustom.EndFramedGroup();
} }
private void DrawSingleSelectorEditGroup( OptionGroup group ) private void DrawSingleSelectorEditGroup( OptionGroup group )
@ -199,7 +202,7 @@ namespace Penumbra.UI
{ {
var oldSetting = Mod!.Settings.Settings[ group.GroupName ]; var oldSetting = Mod!.Settings.Settings[ group.GroupName ];
var code = oldSetting; 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 ) ) group.Options.Select( x => x.OptionName ).ToArray(), group.Options.Count ) )
{ {
if( code == group.Options.Count ) if( code == group.Options.Count )
@ -260,7 +263,7 @@ namespace Penumbra.UI
ImGui.SetCursorPosX( labelEditPos ); ImGui.SetCursorPosX( labelEditPos );
if( labelEditPos == CheckMarkSize ) if( labelEditPos == CheckMarkSize )
{ {
ImGui.SetNextItemWidth( MultiEditBoxWidth ); ImGui.SetNextItemWidth( MultiEditBoxWidth * ImGuiHelpers.GlobalScale );
} }
if( ImGui.InputTextWithHint( LabelNewSingleGroupEdit, "Add new Single Group...", ref newGroup, 64, if( ImGui.InputTextWithHint( LabelNewSingleGroupEdit, "Add new Single Group...", ref newGroup, 64,
@ -275,7 +278,7 @@ namespace Penumbra.UI
{ {
var newGroup = ""; var newGroup = "";
ImGui.SetCursorPosX( CheckMarkSize ); ImGui.SetCursorPosX( CheckMarkSize );
ImGui.SetNextItemWidth( MultiEditBoxWidth ); ImGui.SetNextItemWidth( MultiEditBoxWidth * ImGuiHelpers.GlobalScale );
if( ImGui.InputTextWithHint( LabelNewMultiGroup, "Add new Multi Group...", ref newGroup, 64, if( ImGui.InputTextWithHint( LabelNewMultiGroup, "Add new Multi Group...", ref newGroup, 64,
ImGuiInputTextFlags.EnterReturnsTrue ) ) ImGuiInputTextFlags.EnterReturnsTrue ) )
{ {
@ -310,74 +313,75 @@ namespace Penumbra.UI
return; return;
} }
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
ImGui.SetNextItemWidth( -1 ); 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}"; raii.Push( ImGui.EndListBox );
ImGui.PushFont( UiBuilder.IconFont );
var arrowWidth = ImGui.CalcTextSize( arrow ).X;
ImGui.PopFont();
var width = ( ImGui.GetWindowWidth() - arrowWidth - 4 * ImGui.GetStyle().ItemSpacing.X ) / 2; var swaps = Meta.FileSwaps.Keys.ToArray();
for( var idx = 0; idx < swaps.Length + 1; ++idx )
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 newKey = new GamePath( keyString );
var value = idx == swaps.Length ? GamePath.GenerateUnchecked( "" ) : Meta.FileSwaps[ key ]; if( newKey.CompareTo( key ) != 0 )
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( idx < swaps.Length )
if( newKey.CompareTo( key ) != 0 )
{ {
if( idx < swaps.Length ) Meta.FileSwaps.Remove( key );
{
Meta.FileSwaps.Remove( key );
}
if( newKey != string.Empty )
{
Meta.FileSwaps[ newKey ] = value;
}
_selector.SaveCurrentMod();
_selector.ReloadCurrentMod();
} }
}
if( idx < swaps.Length ) if( newKey != string.Empty )
{
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 ) )
{ {
var newValue = new GamePath( valueString ); Meta.FileSwaps[ newKey ] = value;
if( newValue.CompareTo( value ) != 0 )
{
Meta.FileSwaps[ key ] = newValue;
_selector.SaveCurrentMod();
_selector.Cache.TriggerListReset();
}
} }
_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();
}
}
}
} }
} }
} }

View file

@ -10,6 +10,7 @@ using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs; using Penumbra.GameData.Structs;
using Penumbra.Meta; using Penumbra.Meta;
using Penumbra.Meta.Files; using Penumbra.Meta.Files;
using Penumbra.UI.Custom;
using Penumbra.Util; using Penumbra.Util;
using ObjectType = Penumbra.GameData.Enums.ObjectType; using ObjectType = Penumbra.GameData.Enums.ObjectType;
@ -157,9 +158,8 @@ namespace Penumbra.UI
return ImGui.Checkbox( name, ref value ); return ImGui.Checkbox( name, ref value );
} }
ImGui.PushStyleColor( ImGuiCol.Text, color ); using var colorRaii = ImGuiRaii.PushColor( ImGuiCol.Text, color );
var ret = ImGui.Checkbox( name, ref value ); var ret = ImGui.Checkbox( name, ref value );
ImGui.PopStyleColor();
return ret; return ret;
} }
@ -184,10 +184,9 @@ namespace Penumbra.UI
var color = compare < 0 ? ColorDarkGreen : var color = compare < 0 ? ColorDarkGreen :
compare > 0 ? ColorDarkRed : ImGui.ColorConvertFloat4ToU32( ImGui.GetStyle().Colors[ ( int )ImGuiCol.Button ] ); compare > 0 ? ColorDarkRed : ImGui.ColorConvertFloat4ToU32( ImGui.GetStyle().Colors[ ( int )ImGuiCol.Button ] );
ImGui.PushStyleColor( ImGuiCol.Button, color ); using var colorRaii = ImGuiRaii.PushColor( ImGuiCol.Button, color );
var ret = ImGui.Button( name, Vector2.UnitX * 120 ) && compare != 0; var ret = ImGui.Button( name, Vector2.UnitX * 120 ) && compare != 0;
ImGui.SameLine(); ImGui.SameLine();
ImGui.PopStyleColor();
return ret; return ret;
} }
@ -204,18 +203,20 @@ namespace Penumbra.UI
return false; return false;
} }
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndCombo );
for( var i = 0; i < namesAndValues.Count; ++i ) 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; continue;
value = namesAndValues[ i ].Item2;
ImGui.EndCombo();
return true;
} }
idx = i;
value = namesAndValues[ i ].Item2;
return true;
} }
ImGui.EndCombo();
return false; return false;
} }
@ -227,8 +228,9 @@ namespace Penumbra.UI
if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) ) if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) )
{ {
var defaults = ( EqpEntry )Service< MetaDefaults >.Get().GetDefaultValue( list[ manipIdx ] )!; using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup );
var attributes = Eqp.EqpAttributes[ id.Slot ]; var defaults = ( EqpEntry )Service< MetaDefaults >.Get().GetDefaultValue( list[ manipIdx ] )!;
var attributes = Eqp.EqpAttributes[ id.Slot ];
foreach( var flag in attributes ) foreach( var flag in attributes )
{ {
@ -240,8 +242,6 @@ namespace Penumbra.UI
ret = true; ret = true;
} }
} }
ImGui.EndPopup();
} }
ImGui.Text( ObjectType.Equipment.ToString() ); ImGui.Text( ObjectType.Equipment.ToString() );
@ -261,12 +261,13 @@ namespace Penumbra.UI
if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) ) if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) )
{ {
var enabled = val.Enabled; using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup );
var animated = val.Animated; var enabled = val.Enabled;
var rotationA = val.RotationA; var animated = val.Animated;
var rotationB = val.RotationB; var rotationA = val.RotationA;
var rotationC = val.RotationC; var rotationB = val.RotationB;
ushort unk = val.UnknownTotal; var rotationC = val.RotationC;
ushort unk = val.UnknownTotal;
ret |= PrintCheckBox( "Visor Enabled##manip", ref enabled, defaults.Enabled ) && enabled != val.Enabled; ret |= PrintCheckBox( "Visor Enabled##manip", ref enabled, defaults.Enabled ) && enabled != val.Enabled;
ret |= PrintCheckBox( "Visor Animated##manip", ref animated, defaults.Animated ); ret |= PrintCheckBox( "Visor Animated##manip", ref animated, defaults.Animated );
@ -284,8 +285,6 @@ namespace Penumbra.UI
RotationA = rotationA, RotationB = rotationB, RotationC = rotationC, RotationA = rotationA, RotationB = rotationB, RotationC = rotationC,
} ); } );
} }
ImGui.EndPopup();
} }
ImGui.Text( ObjectType.Equipment.ToString() ); ImGui.Text( ObjectType.Equipment.ToString() );
@ -300,17 +299,17 @@ namespace Penumbra.UI
{ {
return slot switch return slot switch
{ {
EquipSlot.Head => ( entry.HasFlag( EqdpEntry.Head1 ), entry.HasFlag( EqdpEntry.Head2 ) ), EquipSlot.Head => ( entry.HasFlag( EqdpEntry.Head1 ), entry.HasFlag( EqdpEntry.Head2 ) ),
EquipSlot.Body => ( entry.HasFlag( EqdpEntry.Body1 ), entry.HasFlag( EqdpEntry.Body2 ) ), EquipSlot.Body => ( entry.HasFlag( EqdpEntry.Body1 ), entry.HasFlag( EqdpEntry.Body2 ) ),
EquipSlot.Hands => ( entry.HasFlag( EqdpEntry.Hands1 ), entry.HasFlag( EqdpEntry.Hands2 ) ), EquipSlot.Hands => ( entry.HasFlag( EqdpEntry.Hands1 ), entry.HasFlag( EqdpEntry.Hands2 ) ),
EquipSlot.Legs => ( entry.HasFlag( EqdpEntry.Legs1 ), entry.HasFlag( EqdpEntry.Legs2 ) ), EquipSlot.Legs => ( entry.HasFlag( EqdpEntry.Legs1 ), entry.HasFlag( EqdpEntry.Legs2 ) ),
EquipSlot.Feet => ( entry.HasFlag( EqdpEntry.Feet1 ), entry.HasFlag( EqdpEntry.Feet2 ) ), EquipSlot.Feet => ( entry.HasFlag( EqdpEntry.Feet1 ), entry.HasFlag( EqdpEntry.Feet2 ) ),
EquipSlot.Neck => ( entry.HasFlag( EqdpEntry.Neck1 ), entry.HasFlag( EqdpEntry.Neck2 ) ), EquipSlot.Neck => ( entry.HasFlag( EqdpEntry.Neck1 ), entry.HasFlag( EqdpEntry.Neck2 ) ),
EquipSlot.Ears => ( entry.HasFlag( EqdpEntry.Ears1 ), entry.HasFlag( EqdpEntry.Ears2 ) ), EquipSlot.Ears => ( entry.HasFlag( EqdpEntry.Ears1 ), entry.HasFlag( EqdpEntry.Ears2 ) ),
EquipSlot.Wrists => ( entry.HasFlag( EqdpEntry.Wrists1 ), entry.HasFlag( EqdpEntry.Wrists2 ) ), EquipSlot.Wrists => ( entry.HasFlag( EqdpEntry.Wrists1 ), entry.HasFlag( EqdpEntry.Wrists2 ) ),
EquipSlot.RFinger => ( entry.HasFlag( EqdpEntry.RingR1 ), entry.HasFlag( EqdpEntry.RingR2 ) ), EquipSlot.RFinger => ( entry.HasFlag( EqdpEntry.RingR1 ), entry.HasFlag( EqdpEntry.RingR2 ) ),
EquipSlot.LFinger => ( entry.HasFlag( EqdpEntry.RingL1 ), entry.HasFlag( EqdpEntry.RingL2 ) ), EquipSlot.LFinger => ( entry.HasFlag( EqdpEntry.RingL1 ), entry.HasFlag( EqdpEntry.RingL2 ) ),
_ => ( false, false ), _ => ( false, false ),
}; };
} }
@ -372,6 +371,7 @@ namespace Penumbra.UI
if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) ) if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) )
{ {
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup );
var (bit1, bit2) = GetEqdpBits( id.Slot, val ); var (bit1, bit2) = GetEqdpBits( id.Slot, val );
var (defBit1, defBit2) = GetEqdpBits( id.Slot, defaults ); 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 ) ); list[ manipIdx ] = MetaManipulation.Eqdp( id.Slot, id.GenderRace, id.SetId, SetEqdpBits( id.Slot, val, bit1, bit2 ) );
} }
ImGui.EndPopup();
} }
ImGui.Text( id.Slot.IsAccessory() ImGui.Text( id.Slot.IsAccessory()
@ -409,13 +407,12 @@ namespace Penumbra.UI
var val = list[ manipIdx ].EstValue; var val = list[ manipIdx ].EstValue;
if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) ) 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 ) if( DrawInputWithDefault( "No Idea what this does!##manip", ref val, defaults, ushort.MaxValue ) && _editMode )
{ {
list[ manipIdx ] = new MetaManipulation( id.Value, val ); list[ manipIdx ] = new MetaManipulation( id.Value, val );
ret = true; ret = true;
} }
ImGui.EndPopup();
} }
ImGui.Text( id.ObjectType.ToString() ); ImGui.Text( id.ObjectType.ToString() );
@ -443,12 +440,13 @@ namespace Penumbra.UI
if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) ) if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) )
{ {
ushort materialId = val.MaterialId; using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup );
ushort vfxId = val.VfxId; ushort materialId = val.MaterialId;
ushort decalId = val.DecalId; ushort vfxId = val.VfxId;
var soundId = ( ushort )( val.SoundId >> 10 ); ushort decalId = val.DecalId;
var attributeMask = val.AttributeMask; var soundId = ( ushort )( val.SoundId >> 10 );
var materialAnimationId = ( ushort )( val.MaterialAnimationId >> 12 ); var attributeMask = val.AttributeMask;
var materialAnimationId = ( ushort )( val.MaterialAnimationId >> 12 );
ret |= DrawInputWithDefault( "Material Id", ref materialId, defaults.MaterialId, byte.MaxValue ); ret |= DrawInputWithDefault( "Material Id", ref materialId, defaults.MaterialId, byte.MaxValue );
ret |= DrawInputWithDefault( "Vfx Id", ref vfxId, defaults.VfxId, byte.MaxValue ); ret |= DrawInputWithDefault( "Vfx Id", ref vfxId, defaults.VfxId, byte.MaxValue );
ret |= DrawInputWithDefault( "Decal Id", ref decalId, defaults.DecalId, byte.MaxValue ); ret |= DrawInputWithDefault( "Decal Id", ref decalId, defaults.DecalId, byte.MaxValue );
@ -463,8 +461,6 @@ namespace Penumbra.UI
( byte )vfxId, ( byte )materialAnimationId ); ( byte )vfxId, ( byte )materialAnimationId );
list[ manipIdx ] = new MetaManipulation( id.Value, value.ToInteger() ); list[ manipIdx ] = new MetaManipulation( id.Value, value.ToInteger() );
} }
ImGui.EndPopup();
} }
ImGui.Text( id.ObjectType.ToString() ); ImGui.Text( id.ObjectType.ToString() );
@ -503,6 +499,7 @@ namespace Penumbra.UI
if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) ) if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) )
{ {
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup );
if( DefaultButton( if( DefaultButton(
$"{( _editMode ? "Set to " : "" )}Default: {defaults:F3}##scaleManip", ref val, defaults ) $"{( _editMode ? "Set to " : "" )}Default: {defaults:F3}##scaleManip", ref val, defaults )
&& _editMode ) && _editMode )
@ -511,7 +508,7 @@ namespace Penumbra.UI
ret = true; ret = true;
} }
ImGui.SetNextItemWidth( 50 ); ImGui.SetNextItemWidth( 50 * ImGuiHelpers.GlobalScale );
if( ImGui.InputFloat( "Scale###manip", ref val, 0, 0, "%.3f", if( ImGui.InputFloat( "Scale###manip", ref val, 0, 0, "%.3f",
_editMode ? ImGuiInputTextFlags.EnterReturnsTrue : ImGuiInputTextFlags.ReadOnly ) _editMode ? ImGuiInputTextFlags.EnterReturnsTrue : ImGuiInputTextFlags.ReadOnly )
&& val >= 0 && val >= 0
@ -521,8 +518,6 @@ namespace Penumbra.UI
list[ manipIdx ] = MetaManipulation.Rsp( id.SubRace, id.Attribute, val ); list[ manipIdx ] = MetaManipulation.Rsp( id.SubRace, id.Attribute, val );
ret = true; ret = true;
} }
ImGui.EndPopup();
} }
ImGui.Text( id.Attribute.ToUngenderedString() ); ImGui.Text( id.Attribute.ToUngenderedString() );
@ -542,18 +537,15 @@ namespace Penumbra.UI
if( _editMode ) if( _editMode )
{ {
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.PushFont( UiBuilder.IconFont ); using var font = ImGuiRaii.PushFont( UiBuilder.IconFont );
if( ImGui.Button( $"{FontAwesomeIcon.Trash.ToIconString()}##manipDelete{manipIdx}" ) ) if( ImGui.Button( $"{FontAwesomeIcon.Trash.ToIconString()}##manipDelete{manipIdx}" ) )
{ {
list.RemoveAt( manipIdx ); list.RemoveAt( manipIdx );
ImGui.PopFont();
ImGui.TableNextRow(); ImGui.TableNextRow();
--manipIdx; --manipIdx;
--count; --count;
return true; return true;
} }
ImGui.PopFont();
} }
ImGui.TableNextColumn(); ImGui.TableNextColumn();
@ -613,114 +605,116 @@ namespace Penumbra.UI
private bool DrawNewManipulationPopup( string popupName, IList< MetaManipulation > list, ref int count ) private bool DrawNewManipulationPopup( string popupName, IList< MetaManipulation > list, ref int count )
{ {
var change = false; var change = false;
if( ImGui.BeginPopup( popupName ) ) if( !ImGui.BeginPopup( popupName ) )
{ {
var manipType = DrawNewTypeSelection(); return change;
MetaManipulation? newManip = null; }
switch( manipType )
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 ); case ObjectType.Equipment:
RestrictedInputInt( "Variant##newManipImc", ref _newManipVariant, 0, byte.MaxValue ); CustomCombo( "Equipment Slot", EqdpEquipSlots, out equipSlot, ref _newManipEquipSlot );
CustomCombo( "Object Type", ImcObjectType, out var objectType, ref _newManipObjectType ); newManip = MetaManipulation.Imc( equipSlot, _newManipSetId, _newManipVariant,
EquipSlot equipSlot = default; new ImcFile.ImageChangeData() );
switch( objectType ) break;
{ case ObjectType.DemiHuman:
case ObjectType.Equipment: case ObjectType.Weapon:
CustomCombo( "Equipment Slot", EqdpEquipSlots, out equipSlot, ref _newManipEquipSlot ); case ObjectType.Monster:
newManip = MetaManipulation.Imc( equipSlot, _newManipSetId, _newManipVariant, RestrictedInputInt( "Secondary Id##newManipImc", ref _newManipSecondaryId, 0, ushort.MaxValue );
new ImcFile.ImageChangeData() ); CustomCombo( "Body Slot", ImcBodySlots, out var bodySlot, ref _newManipBodySlot );
break; newManip = MetaManipulation.Imc( objectType, bodySlot, _newManipSetId, _newManipSecondaryId,
case ObjectType.DemiHuman: _newManipVariant, new ImcFile.ImageChangeData() );
case ObjectType.Weapon: break;
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; break;
} }
case MetaType.Eqdp: 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 ); case ObjectType.Equipment:
CustomCombo( "Equipment Slot", EqdpEquipSlots, out var equipSlot, ref _newManipEquipSlot ); CustomCombo( "Equipment Slot", EstEquipSlots, out equipSlot, ref _newManipEquipSlot );
CustomCombo( "Race", Races, out var race, ref _newManipRace ); break;
CustomCombo( "Gender", Genders, out var gender, ref _newManipGender ); case ObjectType.Character:
newManip = MetaManipulation.Eqdp( equipSlot, Names.CombinedRace( gender, race ), ( ushort )_newManipSetId, CustomCombo( "Body Slot", EstBodySlots, out bodySlot, ref _newManipBodySlot );
new EqdpEntry() ); break;
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( "Race", Races, out var race, ref _newManipRace );
CustomCombo( "Gender", Genders, out var gender, ref _newManipGender ); CustomCombo( "Gender", Genders, out var gender, ref _newManipGender );
newManip = MetaManipulation.Est( objectType, equipSlot, Names.CombinedRace( gender, race ), bodySlot, newManip = MetaManipulation.Est( objectType, equipSlot, Names.CombinedRace( gender, race ), bodySlot,
( ushort )_newManipSetId, 0 ); ( ushort )_newManipSetId, 0 );
break; break;
} }
case MetaType.Gmp: case MetaType.Gmp:
RestrictedInputInt( "Set Id##newManipGmp", ref _newManipSetId, 0, ushort.MaxValue ); RestrictedInputInt( "Set Id##newManipGmp", ref _newManipSetId, 0, ushort.MaxValue );
newManip = MetaManipulation.Gmp( ( ushort )_newManipSetId, new GmpEntry() ); newManip = MetaManipulation.Gmp( ( ushort )_newManipSetId, new GmpEntry() );
break; break;
case MetaType.Rsp: case MetaType.Rsp:
CustomCombo( "Subrace", Subraces, out var subRace, ref _newManipSubrace ); CustomCombo( "Subrace", Subraces, out var subRace, ref _newManipSubrace );
CustomCombo( "Attribute", RspAttributes, out var rspAttribute, ref _newManipAttribute ); CustomCombo( "Attribute", RspAttributes, out var rspAttribute, ref _newManipAttribute );
newManip = MetaManipulation.Rsp( subRace, rspAttribute, 1f ); newManip = MetaManipulation.Rsp( subRace, rspAttribute, 1f );
break; 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 ) ImGui.CloseCurrentPopup();
&& 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();
} }
return change; return change;
@ -734,6 +728,7 @@ namespace Penumbra.UI
&& ImGui.BeginTable( label, numRows, && ImGui.BeginTable( label, numRows,
ImGuiTableFlags.BordersInner | ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit ) ) ImGuiTableFlags.BordersInner | ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit ) )
{ {
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTable );
if( _editMode ) if( _editMode )
{ {
ImGui.TableNextColumn(); ImGui.TableNextColumn();
@ -764,8 +759,6 @@ namespace Penumbra.UI
{ {
changes |= DrawManipulationRow( ref i, list, ref count ); changes |= DrawManipulationRow( ref i, list, ref count );
} }
ImGui.EndTable();
} }
var popupName = $"##newManip{label}"; var popupName = $"##newManip{label}";

View file

@ -2,10 +2,12 @@ using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Numerics; using System.Numerics;
using Dalamud.Interface;
using Dalamud.Logging; using Dalamud.Logging;
using ImGuiNET; using ImGuiNET;
using Penumbra.Mod; using Penumbra.Mod;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.UI.Custom;
using Penumbra.Util; using Penumbra.Util;
namespace Penumbra.UI namespace Penumbra.UI
@ -72,7 +74,7 @@ namespace Penumbra.UI
private void DrawName() private void DrawName()
{ {
var name = Meta!.Name; 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 ); _selector.SelectModOnUpdate( Mod.Data.BasePath.Name );
if( !_modManager.Config.ModSortOrder.ContainsKey( Mod!.Data.BasePath.Name ) ) if( !_modManager.Config.ModSortOrder.ContainsKey( Mod!.Data.BasePath.Name ) )
@ -87,12 +89,13 @@ namespace Penumbra.UI
if( _editMode ) if( _editMode )
{ {
ImGui.BeginGroup(); ImGui.BeginGroup();
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndGroup );
ImGui.Text( "(Version " ); ImGui.Text( "(Version " );
ImGui.PushStyleVar( ImGuiStyleVar.ItemSpacing, ZeroVector ); using var style = ImGuiRaii.PushStyle( ImGuiStyleVar.ItemSpacing, ZeroVector );
ImGui.SameLine(); ImGui.SameLine();
var version = Meta!.Version; var version = Meta!.Version;
if( Custom.ImGuiCustom.ResizingTextInput( LabelEditVersion, ref version, 16 ) if( ImGuiCustom.ResizingTextInput( LabelEditVersion, ref version, 16 )
&& version != Meta.Version ) && version != Meta.Version )
{ {
Meta.Version = version; Meta.Version = version;
@ -101,8 +104,6 @@ namespace Penumbra.UI
ImGui.SameLine(); ImGui.SameLine();
ImGui.Text( ")" ); ImGui.Text( ")" );
ImGui.PopStyleVar();
ImGui.EndGroup();
} }
else if( Meta!.Version.Length > 0 ) else if( Meta!.Version.Length > 0 )
{ {
@ -117,7 +118,7 @@ namespace Penumbra.UI
ImGui.SameLine(); ImGui.SameLine();
var author = Meta!.Author; var author = Meta!.Author;
if( Custom.ImGuiCustom.InputOrText( _editMode, LabelEditAuthor, ref author, 64 ) if( ImGuiCustom.InputOrText( _editMode, LabelEditAuthor, ref author, 64 )
&& author != Meta.Author ) && author != Meta.Author )
{ {
Meta.Author = author; Meta.Author = author;
@ -131,12 +132,13 @@ namespace Penumbra.UI
private void DrawWebsite() private void DrawWebsite()
{ {
ImGui.BeginGroup(); ImGui.BeginGroup();
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndGroup );
if( _editMode ) if( _editMode )
{ {
ImGui.TextColored( GreyColor, "from" ); ImGui.TextColored( GreyColor, "from" );
ImGui.SameLine(); ImGui.SameLine();
var website = Meta!.Website; var website = Meta!.Website;
if( Custom.ImGuiCustom.ResizingTextInput( LabelEditWebsite, ref website, 512 ) if( ImGuiCustom.ResizingTextInput( LabelEditWebsite, ref website, 512 )
&& website != Meta.Website ) && website != Meta.Website )
{ {
Meta.Website = website; Meta.Website = website;
@ -170,10 +172,7 @@ namespace Penumbra.UI
} }
} }
if( ImGui.IsItemHovered() ) ImGuiCustom.HoverTooltip( Meta.Website );
{
ImGui.SetTooltip( Meta.Website );
}
} }
else else
{ {
@ -182,8 +181,6 @@ namespace Penumbra.UI
ImGui.Text( Meta.Website ); ImGui.Text( Meta.Website );
} }
} }
ImGui.EndGroup();
} }
private void DrawHeaderLine() private void DrawHeaderLine()
@ -200,7 +197,7 @@ namespace Penumbra.UI
private void DrawPriority() private void DrawPriority()
{ {
var priority = Mod!.Settings.Priority; var priority = Mod!.Settings.Priority;
ImGui.SetNextItemWidth( 50 ); ImGui.SetNextItemWidth( 50 * ImGuiHelpers.GlobalScale );
if( ImGui.InputInt( "Priority", ref priority, 0 ) && priority != Mod!.Settings.Priority ) if( ImGui.InputInt( "Priority", ref priority, 0 ) && priority != Mod!.Settings.Priority )
{ {
Mod.Settings.Priority = priority; Mod.Settings.Priority = priority;
@ -208,11 +205,9 @@ namespace Penumbra.UI
_selector.Cache.TriggerFilterReset(); _selector.Cache.TriggerFilterReset();
} }
if( ImGui.IsItemHovered() ) ImGuiCustom.HoverTooltip(
{ "Higher priority mods take precedence over other mods in the case of file conflicts.\n"
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." );
+ "In case of identical priority, the alphabetically first mod takes precedence." );
}
} }
private void DrawEnabledMark() private void DrawEnabledMark()
@ -229,7 +224,7 @@ namespace Penumbra.UI
public static bool DrawSortOrder( ModData mod, ModManager manager, Selector selector ) public static bool DrawSortOrder( ModData mod, ModManager manager, Selector selector )
{ {
var currentSortOrder = mod.SortOrder.FullPath; var currentSortOrder = mod.SortOrder.FullPath;
ImGui.SetNextItemWidth( 300 ); ImGui.SetNextItemWidth( 300 * ImGuiHelpers.GlobalScale );
if( ImGui.InputText( "Sort Order", ref currentSortOrder, 256, ImGuiInputTextFlags.EnterReturnsTrue ) ) if( ImGui.InputText( "Sort Order", ref currentSortOrder, 256, ImGuiInputTextFlags.EnterReturnsTrue ) )
{ {
manager.ChangeSortOrder( mod, currentSortOrder ); manager.ChangeSortOrder( mod, currentSortOrder );
@ -253,10 +248,7 @@ namespace Penumbra.UI
Process.Start( new ProcessStartInfo( Mod!.Data.BasePath.FullName ) { UseShellExecute = true } ); Process.Start( new ProcessStartInfo( Mod!.Data.BasePath.FullName ) { UseShellExecute = true } );
} }
if( ImGui.IsItemHovered() ) ImGuiCustom.HoverTooltip( TooltipOpenModFolder );
{
ImGui.SetTooltip( TooltipOpenModFolder );
}
} }
private string _newName = ""; private string _newName = "";
@ -318,35 +310,37 @@ namespace Penumbra.UI
{ {
var closeParent = false; var closeParent = false;
var _ = true; var _ = true;
if( ImGui.BeginPopupModal( LabelOverWriteDir, ref _, ImGuiWindowFlags.AlwaysAutoResize ) ) if( !ImGui.BeginPopupModal( LabelOverWriteDir, ref _, ImGuiWindowFlags.AlwaysAutoResize ) )
{ {
DirectoryInfo dir = Mod!.Data.BasePath; return closeParent;
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." ); using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup );
var buttonSize = new Vector2( 120, 0 );
if( ImGui.Button( "Yes", buttonSize ) ) 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; closeParent = true;
ImGui.CloseCurrentPopup();
}
}
ImGui.SameLine();
if( ImGui.Button( "Cancel", buttonSize ) )
{
_keyboardFocus = true;
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
} }
}
ImGui.EndPopup(); ImGui.SameLine();
if( ImGui.Button( "Cancel", buttonSize ) )
{
_keyboardFocus = true;
ImGui.CloseCurrentPopup();
} }
return closeParent; return closeParent;
@ -358,38 +352,40 @@ namespace Penumbra.UI
_keyboardFocus |= !ImGui.IsPopupOpen( PopupRenameFolder ); _keyboardFocus |= !ImGui.IsPopupOpen( PopupRenameFolder );
ImGui.SetNextWindowPos( ImGui.GetMainViewport().GetCenter(), ImGuiCond.Appearing, new Vector2( 0.5f, 1f ) ); 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 ) ) ) return;
{ }
ImGui.CloseCurrentPopup();
}
var newName = Mod!.Data.BasePath.Name; using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup );
if( _keyboardFocus ) if( ImGui.IsKeyPressed( ImGui.GetKeyIndex( ImGuiKey.Escape ) ) )
{ {
ImGui.SetKeyboardFocusHere(); ImGui.CloseCurrentPopup();
_keyboardFocus = false; }
}
if( ImGui.InputText( "New Folder Name##RenameFolderInput", ref newName, 64, ImGuiInputTextFlags.EnterReturnsTrue ) ) var newName = Mod!.Data.BasePath.Name;
{
RenameModFolder( newName );
}
ImGui.TextColored( GreyColor, if( _keyboardFocus )
"Please restrict yourself to ascii symbols that are valid in a windows path,\nother symbols will be replaced by underscores." ); {
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() ) if( OverwriteDirPopup() )
{ {
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
}
ImGui.EndPopup();
} }
} }
@ -401,10 +397,7 @@ namespace Penumbra.UI
ImGui.OpenPopup( PopupRenameFolder ); ImGui.OpenPopup( PopupRenameFolder );
} }
if( ImGui.IsItemHovered() ) ImGuiCustom.HoverTooltip( TooltipRenameModFolder );
{
ImGui.SetTooltip( TooltipRenameModFolder );
}
} }
private void DrawEditJsonButton() private void DrawEditJsonButton()
@ -415,10 +408,7 @@ namespace Penumbra.UI
Process.Start( new ProcessStartInfo( Mod!.Data.MetaFile.FullName ) { UseShellExecute = true } ); Process.Start( new ProcessStartInfo( Mod!.Data.MetaFile.FullName ) { UseShellExecute = true } );
} }
if( ImGui.IsItemHovered() ) ImGuiCustom.HoverTooltip( TooltipEditJson );
{
ImGui.SetTooltip( TooltipEditJson );
}
} }
private void DrawReloadJsonButton() private void DrawReloadJsonButton()
@ -428,10 +418,7 @@ namespace Penumbra.UI
_selector.ReloadCurrentMod( true, false ); _selector.ReloadCurrentMod( true, false );
} }
if( ImGui.IsItemHovered() ) ImGuiCustom.HoverTooltip( TooltipReloadJson );
{
ImGui.SetTooltip( TooltipReloadJson );
}
} }
private void DrawResetMetaButton() private void DrawResetMetaButton()
@ -441,13 +428,10 @@ namespace Penumbra.UI
_selector.ReloadCurrentMod( true, true ); _selector.ReloadCurrentMod( true, true );
} }
if( ImGui.IsItemHovered() ) ImGuiCustom.HoverTooltip(
{ "Force a recomputation of the metadata_manipulations.json file from all .meta files in the folder.\n"
ImGui.SetTooltip( + "Also reloads the mod.\n"
"Force a recomputation of the metadata_manipulations.json file from all .meta files in the folder.\n" + "Be aware that this removes all manually added metadata changes." );
+ "Also reloads the mod.\n"
+ "Be aware that this removes all manually added metadata changes." );
}
} }
private void DrawDeduplicateButton() private void DrawDeduplicateButton()
@ -459,10 +443,7 @@ namespace Penumbra.UI
_selector.ReloadCurrentMod(); _selector.ReloadCurrentMod();
} }
if( ImGui.IsItemHovered() ) ImGuiCustom.HoverTooltip( TooltipDeduplicate );
{
ImGui.SetTooltip( TooltipDeduplicate );
}
} }
private void DrawNormalizeButton() private void DrawNormalizeButton()
@ -474,10 +455,7 @@ namespace Penumbra.UI
_selector.ReloadCurrentMod(); _selector.ReloadCurrentMod();
} }
if( ImGui.IsItemHovered() ) ImGuiCustom.HoverTooltip( TooltipNormalize );
{
ImGui.SetTooltip( TooltipNormalize );
}
} }
private void DrawSplitButton() private void DrawSplitButton()
@ -487,13 +465,10 @@ namespace Penumbra.UI
ModCleanup.SplitMod( Mod!.Data ); ModCleanup.SplitMod( Mod!.Data );
} }
if( ImGui.IsItemHovered() ) ImGuiCustom.HoverTooltip(
{ "Split off all options of a mod into single mods that are placed in a collective folder.\n"
ImGui.SetTooltip( + "Does not remove or change the mod itself, just create (potentially inefficient) copies.\n"
"Split off all options of a mod into single mods that are placed in a collective folder.\n" + "Experimental - Use at own risk!" );
+ "Does not remove or change the mod itself, just create (potentially inefficient) copies.\n"
+ "Experimental - Use at own risk!" );
}
} }
private void DrawEditLine() private void DrawEditLine()
@ -521,18 +496,18 @@ namespace Penumbra.UI
{ {
try 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 ) if( !ret || Mod == null )
{ {
ImGui.EndChild();
return; return;
} }
DrawHeaderLine(); DrawHeaderLine();
// Next line with fixed distance. // Next line with fixed distance.
Custom.ImGuiCustom.VerticalDistance( HeaderLineDistance ); ImGuiCustom.VerticalDistance( HeaderLineDistance );
DrawEnabledMark(); DrawEnabledMark();
ImGui.SameLine(); ImGui.SameLine();
@ -550,12 +525,10 @@ namespace Penumbra.UI
} }
Details.Draw( _editMode ); Details.Draw( _editMode );
ImGui.EndChild();
} }
catch( Exception ex ) catch( Exception ex )
{ {
PluginLog.LogError( ex, "fuck" ); PluginLog.LogError( ex, "Oh no" );
} }
} }
} }

View file

@ -3,12 +3,14 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Windows.Forms.VisualStyles;
using Dalamud.Interface; using Dalamud.Interface;
using Dalamud.Logging; using Dalamud.Logging;
using ImGuiNET; using ImGuiNET;
using Penumbra.Importer; using Penumbra.Importer;
using Penumbra.Mod; using Penumbra.Mod;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.UI.Custom;
using Penumbra.Util; using Penumbra.Util;
namespace Penumbra.UI namespace Penumbra.UI
@ -36,6 +38,8 @@ namespace Penumbra.UI
private static readonly Vector2 SelectorButtonSizes = new( 100, 0 ); private static readonly Vector2 SelectorButtonSizes = new( 100, 0 );
private static readonly Vector2 HelpButtonSizes = new( 40, 0 ); private static readonly Vector2 HelpButtonSizes = new( 40, 0 );
private static readonly Vector4 DeleteModNameColor = new( 0.7f, 0.1f, 0.1f, 1 );
} }
// Buttons // Buttons
@ -46,19 +50,16 @@ namespace Penumbra.UI
private void DrawModTrashButton() private void DrawModTrashButton()
{ {
ImGui.PushFont( UiBuilder.IconFont ); using var raii = ImGuiRaii.PushFont( UiBuilder.IconFont );
if( ImGui.Button( FontAwesomeIcon.Trash.ToIconString(), SelectorButtonSizes * _selectorScalingFactor ) && _index >= 0 ) if( ImGui.Button( FontAwesomeIcon.Trash.ToIconString(), SelectorButtonSizes * _selectorScalingFactor ) && _index >= 0 )
{ {
_deleteIndex = _index; _deleteIndex = _index;
} }
ImGui.PopFont(); raii.Pop();
if( ImGui.IsItemHovered() ) ImGuiCustom.HoverTooltip( TooltipDelete );
{
ImGui.SetTooltip( TooltipDelete );
}
} }
private void DrawDeleteModal() private void DrawDeleteModal()
@ -78,20 +79,22 @@ namespace Penumbra.UI
return; return;
} }
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup );
if( Mod == null ) if( Mod == null )
{ {
_deleteIndex = null; _deleteIndex = null;
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
ImGui.EndPopup();
return; return;
} }
ImGui.Text( "Are you sure you want to delete the following mod:" ); ImGui.Text( "Are you sure you want to delete the following mod:" );
ImGui.Dummy( new Vector2( ImGui.GetTextLineHeight() / 2 ) ); var halfLine = new Vector2( ImGui.GetTextLineHeight() / 2 );
ImGui.TextColored( new Vector4( 0.7f, 0.1f, 0.1f, 1 ), Mod.Data.Meta.Name ); ImGui.Dummy( halfLine );
ImGui.Dummy( new Vector2( ImGui.GetTextLineHeight() ) / 2 ); 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 ) ) if( ImGui.Button( ButtonYesDelete, buttonSize ) )
{ {
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
@ -109,8 +112,6 @@ namespace Penumbra.UI
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
_deleteIndex = null; _deleteIndex = null;
} }
ImGui.EndPopup();
} }
// === Add === // === Add ===
@ -118,7 +119,7 @@ namespace Penumbra.UI
private void DrawModAddButton() private void DrawModAddButton()
{ {
ImGui.PushFont( UiBuilder.IconFont ); using var raii = ImGuiRaii.PushFont( UiBuilder.IconFont );
if( ImGui.Button( FontAwesomeIcon.Plus.ToIconString(), SelectorButtonSizes * _selectorScalingFactor ) ) if( ImGui.Button( FontAwesomeIcon.Plus.ToIconString(), SelectorButtonSizes * _selectorScalingFactor ) )
{ {
@ -126,12 +127,9 @@ namespace Penumbra.UI
ImGui.OpenPopup( LabelAddModPopup ); ImGui.OpenPopup( LabelAddModPopup );
} }
ImGui.PopFont(); raii.Pop();
if( ImGui.IsItemHovered() ) ImGuiCustom.HoverTooltip( TooltipAdd );
{
ImGui.SetTooltip( TooltipAdd );
}
DrawModAddPopup(); DrawModAddPopup();
} }
@ -143,6 +141,8 @@ namespace Penumbra.UI
return; return;
} }
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup );
if( _modAddKeyboardFocus ) if( _modAddKeyboardFocus )
{ {
ImGui.SetKeyboardFocusHere(); ImGui.SetKeyboardFocusHere();
@ -181,20 +181,16 @@ namespace Penumbra.UI
{ {
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
} }
ImGui.EndPopup();
} }
// === Help === // === Help ===
private void DrawModHelpButton() private void DrawModHelpButton()
{ {
ImGui.PushFont( UiBuilder.IconFont ); using var raii = ImGuiRaii.PushFont( UiBuilder.IconFont );
if( ImGui.Button( FontAwesomeIcon.QuestionCircle.ToIconString(), HelpButtonSizes * _selectorScalingFactor ) ) if( ImGui.Button( FontAwesomeIcon.QuestionCircle.ToIconString(), HelpButtonSizes * _selectorScalingFactor ) )
{ {
ImGui.OpenPopup( LabelModHelpPopup ); ImGui.OpenPopup( LabelModHelpPopup );
} }
ImGui.PopFont();
} }
private static void DrawModHelpPopup() private static void DrawModHelpPopup()
@ -208,6 +204,8 @@ namespace Penumbra.UI
return; return;
} }
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup );
ImGui.Dummy( Vector2.UnitY * ImGui.GetTextLineHeight() ); ImGui.Dummy( Vector2.UnitY * ImGui.GetTextLineHeight() );
ImGui.Text( "Mod Selector" ); ImGui.Text( "Mod Selector" );
ImGui.BulletText( "Select a mod to obtain more information." ); ImGui.BulletText( "Select a mod to obtain more information." );
@ -268,24 +266,20 @@ namespace Penumbra.UI
{ {
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
} }
ImGui.EndPopup();
} }
// === Main === // === Main ===
private void DrawModsSelectorButtons() private void DrawModsSelectorButtons()
{ {
// Selector controls // Selector controls
ImGui.PushStyleVar( ImGuiStyleVar.WindowPadding, ZeroVector ); using var style = ImGuiRaii.PushStyle( ImGuiStyleVar.WindowPadding, ZeroVector )
ImGui.PushStyleVar( ImGuiStyleVar.FrameRounding, 0 ); .Push( ImGuiStyleVar.FrameRounding, 0 );
DrawModAddButton(); DrawModAddButton();
ImGui.SameLine(); ImGui.SameLine();
DrawModHelpButton(); DrawModHelpButton();
ImGui.SameLine(); ImGui.SameLine();
DrawModTrashButton(); DrawModTrashButton();
ImGui.PopStyleVar( 2 );
} }
} }
@ -296,7 +290,7 @@ namespace Penumbra.UI
private void DrawTextFilter() private void DrawTextFilter()
{ {
ImGui.SetNextItemWidth( SelectorPanelWidth * _selectorScalingFactor - 22 ); ImGui.SetNextItemWidth( SelectorPanelWidth * _selectorScalingFactor - 22 * ImGuiHelpers.GlobalScale );
var tmp = _modFilterInput; var tmp = _modFilterInput;
if( ImGui.InputTextWithHint( LabelModFilter, "Filter Mods...", ref tmp, 256 ) && _modFilterInput != tmp ) if( ImGui.InputTextWithHint( LabelModFilter, "Filter Mods...", ref tmp, 256 ) && _modFilterInput != tmp )
{ {
@ -304,10 +298,7 @@ namespace Penumbra.UI
_modFilterInput = tmp; _modFilterInput = tmp;
} }
if( ImGui.IsItemHovered() ) ImGuiCustom.HoverTooltip( TooltipModFilter );
{
ImGui.SetTooltip( TooltipModFilter );
}
} }
private void DrawToggleFilter() private void DrawToggleFilter()
@ -315,30 +306,25 @@ namespace Penumbra.UI
if( ImGui.BeginCombo( "##ModStateFilter", "", if( ImGui.BeginCombo( "##ModStateFilter", "",
ImGuiComboFlags.NoPreview | ImGuiComboFlags.PopupAlignLeft | ImGuiComboFlags.HeightLargest ) ) 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 ) ) ) foreach( ModFilter flag in Enum.GetValues( typeof( ModFilter ) ) )
{ {
ImGui.CheckboxFlags( flag.ToName(), ref flags, ( int )flag ); ImGui.CheckboxFlags( flag.ToName(), ref flags, ( int )flag );
} }
Cache.StateFilter = ( ModFilter )flags; Cache.StateFilter = ( ModFilter )flags;
ImGui.EndCombo();
} }
if( ImGui.IsItemHovered() ) ImGuiCustom.HoverTooltip( "Filter mods for their activation status." );
{
ImGui.SetTooltip( "Filter mods for their activation status." );
}
} }
private void DrawModsSelectorFilter() private void DrawModsSelectorFilter()
{ {
ImGui.PushStyleVar( ImGuiStyleVar.ItemSpacing, ZeroVector ); using var style = ImGuiRaii.PushStyle( ImGuiStyleVar.ItemSpacing, ZeroVector );
DrawTextFilter(); DrawTextFilter();
ImGui.SameLine(); ImGui.SameLine();
DrawToggleFilter(); DrawToggleFilter();
ImGui.PopStyleVar();
} }
} }
@ -360,15 +346,14 @@ namespace Penumbra.UI
return; return;
} }
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndDragDropTarget );
if( IsDropping( DraggedModLabel ) ) if( IsDropping( DraggedModLabel ) )
{ {
var payload = ImGui.GetDragDropPayload(); var payload = ImGui.GetDragDropPayload();
var modIndex = Marshal.ReadInt32( payload.Data ); var modIndex = Marshal.ReadInt32( payload.Data );
var mod = Cache.GetMod( modIndex ).Item1; var mod = Cache.GetMod( modIndex ).Item1;
if( mod != null ) mod?.Data.Move( folder );
{
mod.Data.Move( folder );
}
} }
else if( IsDropping( DraggedFolderLabel ) ) else if( IsDropping( DraggedFolderLabel ) )
{ {
@ -381,8 +366,6 @@ namespace Penumbra.UI
droppedFolder.Move( folder ); droppedFolder.Move( folder );
} }
} }
ImGui.EndDragDropTarget();
} }
private void DragDropSourceFolder( ModFolder folder ) private void DragDropSourceFolder( ModFolder folder )
@ -392,11 +375,12 @@ namespace Penumbra.UI
return; return;
} }
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndDragDropSource );
var folderName = folder.FullName; var folderName = folder.FullName;
var ptr = Marshal.StringToHGlobalUni( folderName ); var ptr = Marshal.StringToHGlobalUni( folderName );
ImGui.SetDragDropPayload( DraggedFolderLabel, ptr, ( uint )( folderName.Length + 1 ) * 2 ); ImGui.SetDragDropPayload( DraggedFolderLabel, ptr, ( uint )( folderName.Length + 1 ) * 2 );
ImGui.Text( $"Moving {folderName}..." ); ImGui.Text( $"Moving {folderName}..." );
ImGui.EndDragDropSource();
} }
private void DragDropSourceMod( int modIndex, string modName ) private void DragDropSourceMod( int modIndex, string modName )
@ -406,10 +390,11 @@ namespace Penumbra.UI
return; return;
} }
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndDragDropSource );
Marshal.WriteInt32( _dragDropPayload, modIndex ); Marshal.WriteInt32( _dragDropPayload, modIndex );
ImGui.SetDragDropPayload( "ModIndex", _dragDropPayload, 4 ); ImGui.SetDragDropPayload( "ModIndex", _dragDropPayload, 4 );
ImGui.Text( $"Moving {modName}..." ); ImGui.Text( $"Moving {modName}..." );
ImGui.EndDragDropSource();
} }
~Selector() ~Selector()
@ -496,6 +481,8 @@ namespace Penumbra.UI
return; return;
} }
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup );
if( ModPanel.DrawSortOrder( mod.Data, _modManager, this ) ) if( ModPanel.DrawSortOrder( mod.Data, _modManager, this ) )
{ {
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
@ -505,8 +492,6 @@ namespace Penumbra.UI
{ {
ImGui.SetKeyboardFocusHere( mod.Data.SortOrder.FullPath.Length - 1 ); ImGui.SetKeyboardFocusHere( mod.Data.SortOrder.FullPath.Length - 1 );
} }
ImGui.EndPopup();
} }
// === Folder === // === Folder ===
@ -545,7 +530,7 @@ namespace Penumbra.UI
private void DrawRenameFolderInput( ModFolder folder ) private void DrawRenameFolderInput( ModFolder folder )
{ {
ImGui.SetNextItemWidth( 150 ); ImGui.SetNextItemWidth( 150 * ImGuiHelpers.GlobalScale );
if( !ImGui.InputTextWithHint( "##NewFolderName", "Rename Folder...", ref _newFolderName, 64, if( !ImGui.InputTextWithHint( "##NewFolderName", "Rename Folder...", ref _newFolderName, 64,
ImGuiInputTextFlags.EnterReturnsTrue ) ) ImGuiInputTextFlags.EnterReturnsTrue ) )
{ {
@ -566,23 +551,25 @@ namespace Penumbra.UI
private void DrawFolderContextMenu( ModFolder folder, int currentIdx, string treeName ) private void DrawFolderContextMenu( ModFolder folder, int currentIdx, string treeName )
{ {
if( ImGui.BeginPopup( treeName ) ) if( !ImGui.BeginPopup( treeName ) )
{ {
if( ImGui.MenuItem( "Enable All Descendants" ) ) return;
{
ChangeStatusOfChildren( folder, currentIdx, true );
}
if( ImGui.MenuItem( "Disable All Descendants" ) )
{
ChangeStatusOfChildren( folder, currentIdx, false );
}
ImGui.Dummy( Vector2.UnitY * 10 );
DrawRenameFolderInput( folder );
ImGui.EndPopup();
} }
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 if( collection == ModCollection.Empty
|| collection == _modManager.Collections.CurrentCollection ) || 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.Button( label, Vector2.UnitX * size );
ImGui.PopStyleVar();
} }
else if( ImGui.Button( label, Vector2.UnitX * size ) ) else if( ImGui.Button( label, Vector2.UnitX * size ) )
{ {
_base._menu.CollectionsTab.SetCurrentCollection( collection ); _base._menu.CollectionsTab.SetCurrentCollection( collection );
} }
if( ImGui.IsItemHovered() ) ImGuiCustom.HoverTooltip(
{ $"Switches to the currently set {tooltipLabel} collection, if it is not set to None and it is not the current collection already." );
ImGui.SetTooltip(
$"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() private void DrawHeaderBar()
{ {
const float size = 200; const float size = 200;
DrawModsSelectorFilter(); DrawModsSelectorFilter();
var textSize = ImGui.CalcTextSize( TabCollections.LabelCurrentCollection ).X + ImGui.GetStyle().ItemInnerSpacing.X; var textSize = ImGui.CalcTextSize( TabCollections.LabelCurrentCollection ).X + ImGui.GetStyle().ItemInnerSpacing.X;
var comboSize = size * ImGui.GetIO().FontGlobalScale; var comboSize = size * ImGui.GetIO().FontGlobalScale;
var offset = comboSize + textSize; var offset = comboSize + textSize;
var buttonSize = ( ImGui.GetWindowContentRegionWidth() var buttonSize = Math.Max( ( ImGui.GetWindowContentRegionWidth()
- offset - offset
- SelectorPanelWidth * _selectorScalingFactor - SelectorPanelWidth * _selectorScalingFactor
- 4 * ImGui.GetStyle().ItemSpacing.X ) - 4 * ImGui.GetStyle().ItemSpacing.X )
/ 2; / 2, 5f );
ImGui.SameLine(); ImGui.SameLine();
DrawCollectionButton( "Default", "default", buttonSize, _modManager.Collections.DefaultCollection ); DrawCollectionButton( "Default", "default", buttonSize, _modManager.Collections.DefaultCollection );
@ -644,9 +628,8 @@ namespace Penumbra.UI
ImGui.SameLine(); ImGui.SameLine();
ImGui.SetNextItemWidth( comboSize ); ImGui.SetNextItemWidth( comboSize );
ImGui.PushStyleVar( ImGuiStyleVar.ItemSpacing, Vector2.Zero ); using var style = ImGuiRaii.PushStyle( ImGuiStyleVar.ItemSpacing, Vector2.Zero );
_base._menu.CollectionsTab.DrawCurrentCollectionSelector( false ); _base._menu.CollectionsTab.DrawCurrentCollectionSelector( false );
ImGui.PopStyleVar();
} }
private void DrawFolderContent( ModFolder folder, ref int idx ) private void DrawFolderContent( ModFolder folder, ref int idx )
@ -683,8 +666,9 @@ namespace Penumbra.UI
private void DrawModFolder( ModFolder folder, ref int idx ) private void DrawModFolder( ModFolder folder, ref int idx )
{ {
var treeName = $"{folder.Name}##{folder.FullName}"; var treeName = $"{folder.Name}##{folder.FullName}";
var open = ImGui.TreeNodeEx( treeName ); var open = ImGui.TreeNodeEx( treeName );
using var raii = ImGuiRaii.DeferredEnd( ImGui.TreePop, open );
if( ImGui.IsItemClicked( ImGuiMouseButton.Right ) ) if( ImGui.IsItemClicked( ImGuiMouseButton.Right ) )
{ {
_newFolderName = string.Empty; _newFolderName = string.Empty;
@ -698,7 +682,6 @@ namespace Penumbra.UI
if( open ) if( open )
{ {
DrawFolderContent( folder, ref idx ); DrawFolderContent( folder, ref idx );
ImGui.TreePop();
} }
else else
{ {
@ -708,17 +691,10 @@ namespace Penumbra.UI
private void DrawMod( Mod.Mod mod, int modIndex, uint color ) private void DrawMod( Mod.Mod mod, int modIndex, uint color )
{ {
if( color != 0 ) using var colorRaii = ImGuiRaii.PushColor( ImGuiCol.Text, color, color != 0 );
{
ImGui.PushStyleColor( ImGuiCol.Text, color );
}
var selected = ImGui.Selectable( $"{mod.Data.Meta.Name}##{modIndex}", modIndex == _index ); var selected = ImGui.Selectable( $"{mod.Data.Meta.Name}##{modIndex}", modIndex == _index );
colorRaii.Pop();
if( color != 0 )
{
ImGui.PopStyleColor();
}
var popupName = $"##SortOrderPopup{modIndex}"; var popupName = $"##SortOrderPopup{modIndex}";
var firstOpen = false; var firstOpen = false;
@ -754,37 +730,33 @@ namespace Penumbra.UI
} }
} }
try _selectorScalingFactor = ImGuiHelpers.GlobalScale
{ * ( Penumbra.Config.ScaleModSelector
_selectorScalingFactor = Penumbra.Config.ScaleModSelector
? ImGui.GetWindowWidth() / SettingsMenu.MinSettingsSize.X ? ImGui.GetWindowWidth() / SettingsMenu.MinSettingsSize.X
: 1f; : 1f );
// Selector pane // Selector pane
DrawHeaderBar(); DrawHeaderBar();
ImGui.PushStyleVar( ImGuiStyleVar.ItemSpacing, Vector2.Zero ); using var style = ImGuiRaii.PushStyle( ImGuiStyleVar.ItemSpacing, Vector2.Zero );
ImGui.BeginGroup(); ImGui.BeginGroup();
// Inlay selector list using var raii = ImGuiRaii.DeferredEnd( ImGui.EndGroup )
if( ImGui.BeginChild( LabelSelectorList, .Push( ImGui.EndChild );
new Vector2( SelectorPanelWidth * _selectorScalingFactor, -ImGui.GetFrameHeightWithSpacing() ), // Inlay selector list
true, ImGuiWindowFlags.HorizontalScrollbar ) ) if( ImGui.BeginChild( LabelSelectorList,
{ new Vector2( SelectorPanelWidth * _selectorScalingFactor, -ImGui.GetFrameHeightWithSpacing() ),
ImGui.PushStyleVar( ImGuiStyleVar.IndentSpacing, 12.5f ); true, ImGuiWindowFlags.HorizontalScrollbar ) )
var modIndex = 0;
DrawFolderContent( _modManager.StructuredMods, ref modIndex );
ImGui.PopStyleVar();
}
ImGui.EndChild();
DrawModsSelectorButtons();
ImGui.EndGroup();
}
finally
{ {
ImGui.PopStyleVar(); style.Push( ImGuiStyleVar.IndentSpacing, 12.5f );
var modIndex = 0;
DrawFolderContent( _modManager.StructuredMods, ref modIndex );
style.Pop();
} }
raii.Pop();
DrawModsSelectorButtons();
style.Pop();
DrawModHelpPopup(); DrawModHelpPopup();
DrawDeleteModal(); DrawDeleteModal();

View file

@ -1,8 +1,10 @@
using System.Numerics; using System.Numerics;
using Dalamud.Interface;
using FFXIVClientStructs.FFXIV.Client.System.Resource; using FFXIVClientStructs.FFXIV.Client.System.Resource;
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle; using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
using FFXIVClientStructs.STD; using FFXIVClientStructs.STD;
using ImGuiNET; using ImGuiNET;
using Penumbra.UI.Custom;
namespace Penumbra.UI namespace Penumbra.UI
{ {
@ -26,17 +28,19 @@ namespace Penumbra.UI
return; return;
} }
using var raii = ImGuiRaii.DeferredEnd( ImGui.TreePop );
if( typeMap->Count == 0 || !ImGui.BeginTable( $"##{label}_table", 4, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg ) ) if( typeMap->Count == 0 || !ImGui.BeginTable( $"##{label}_table", 4, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg ) )
{ {
ImGui.TreePop();
return; return;
} }
ImGui.TableSetupColumn( "Hash", ImGuiTableColumnFlags.WidthFixed, 100 ); raii.Push( ImGui.EndTable );
ImGui.TableSetupColumn( "Ptr", ImGuiTableColumnFlags.WidthFixed, 100 );
ImGui.TableSetupColumn( "Path", ImGuiTableColumnFlags.WidthFixed, ImGui.GetWindowContentRegionWidth() - 300 ); ImGui.TableSetupColumn( "Hash", ImGuiTableColumnFlags.WidthFixed, 100 * ImGuiHelpers.GlobalScale );
ImGui.TableSetupColumn( "Refs", ImGuiTableColumnFlags.WidthFixed, 30 ); 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(); ImGui.TableHeadersRow();
var node = typeMap->SmallestValue; var node = typeMap->SmallestValue;
@ -59,9 +63,6 @@ namespace Penumbra.UI
ImGui.Text( node->KeyValuePair.Item2.Value->RefCount.ToString() ); ImGui.Text( node->KeyValuePair.Item2.Value->RefCount.ToString() );
node = node->Next(); node = node->Next();
} }
ImGui.EndTable();
ImGui.TreePop();
} }
private unsafe void DrawCategoryContainer( string label, ResourceGraph.CategoryContainer container ) private unsafe void DrawCategoryContainer( string label, ResourceGraph.CategoryContainer container )
@ -72,6 +73,8 @@ namespace Penumbra.UI
return; return;
} }
using var raii = ImGuiRaii.DeferredEnd( ImGui.TreePop );
var node = map->SmallestValue; var node = map->SmallestValue;
while( !node->IsNil ) while( !node->IsNil )
{ {
@ -79,8 +82,6 @@ namespace Penumbra.UI
node->KeyValuePair.Item2.Value ); node->KeyValuePair.Item2.Value );
node = node->Next(); node = node->Next();
} }
ImGui.TreePop();
} }
private unsafe void DrawResourceManagerTab() private unsafe void DrawResourceManagerTab()
@ -90,6 +91,8 @@ namespace Penumbra.UI
return; return;
} }
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
var resourceHandler = *( ResourceManager** )( Dalamud.SigScanner.Module.BaseAddress + 0x1D93AC0 ); var resourceHandler = *( ResourceManager** )( Dalamud.SigScanner.Module.BaseAddress + 0x1D93AC0 );
if( resourceHandler == null ) if( resourceHandler == null )
@ -97,28 +100,27 @@ namespace Penumbra.UI
return; return;
} }
if( ImGui.BeginChild( "##ResourceManagerChild", -Vector2.One, true ) ) raii.Push( ImGui.EndChild );
if( !ImGui.BeginChild( "##ResourceManagerChild", -Vector2.One, true ) )
{ {
DrawCategoryContainer( "Common", resourceHandler->ResourceGraph->CommonContainer ); return;
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 );
} }
ImGui.EndChild(); DrawCategoryContainer( "Common", resourceHandler->ResourceGraph->CommonContainer );
DrawCategoryContainer( "BgCommon", resourceHandler->ResourceGraph->BgCommonContainer );
ImGui.EndTabItem(); 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 );
} }
} }
} }

View file

@ -7,6 +7,7 @@ using ImGuiNET;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Penumbra.Interop; using Penumbra.Interop;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.UI.Custom;
using Penumbra.Util; using Penumbra.Util;
namespace Penumbra.UI namespace Penumbra.UI
@ -65,13 +66,10 @@ namespace Penumbra.UI
_base._modManager.SetTempDirectory( tempPath ); _base._modManager.SetTempDirectory( tempPath );
} }
if( ImGui.IsItemHovered() ) ImGuiCustom.HoverTooltip( "The folder used to store temporary meta manipulation files.\n"
{ + "Leave this blank if you have no reason not to.\n"
ImGui.SetTooltip( "The folder used to store temporary meta manipulation files.\n" + "A folder 'penumbrametatmp' will be created as a subdirectory to the specified directory.\n"
+ "Leave this blank if you have no reason not to.\n" + "If none is specified (i.e. this is blank) this folder will be created in the root folder instead." );
+ "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(); ImGui.SameLine();
if( ImGui.Button( LabelOpenTempFolder ) ) if( ImGui.Button( LabelOpenTempFolder ) )
@ -115,7 +113,7 @@ namespace Penumbra.UI
{ {
_config.IsEnabled = enabled; _config.IsEnabled = enabled;
_configChanged = true; _configChanged = true;
Service<ResidentResources>.Get().ReloadPlayerResources(); Service< ResidentResources >.Get().ReloadPlayerResources();
_base._penumbra.ObjectReloader.RedrawAll( enabled ? RedrawType.WithSettings : RedrawType.WithoutSettings ); _base._penumbra.ObjectReloader.RedrawAll( enabled ? RedrawType.WithSettings : RedrawType.WithoutSettings );
if( _config.EnablePlayerWatch ) if( _config.EnablePlayerWatch )
{ {
@ -177,10 +175,10 @@ namespace Penumbra.UI
private void DrawDisableNotificationsBox() private void DrawDisableNotificationsBox()
{ {
var fswatch = _config.DisableFileSystemNotifications; var fsWatch = _config.DisableFileSystemNotifications;
if( ImGui.Checkbox( LabelDisableNotifications, ref fswatch ) ) if( ImGui.Checkbox( LabelDisableNotifications, ref fsWatch ) )
{ {
_config.DisableFileSystemNotifications = fswatch; _config.DisableFileSystemNotifications = fsWatch;
_configChanged = true; _configChanged = true;
} }
} }
@ -210,39 +208,35 @@ namespace Penumbra.UI
if( ImGui.Checkbox( LabelEnabledPlayerWatch, ref enabled ) ) if( ImGui.Checkbox( LabelEnabledPlayerWatch, ref enabled ) )
{ {
_config.EnablePlayerWatch = enabled; _config.EnablePlayerWatch = enabled;
_configChanged = true; _configChanged = true;
Penumbra.PlayerWatcher.SetStatus( enabled ); 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( return;
"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 ) 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; _base._penumbra.ObjectReloader.DefaultWaitFrames = waitFrames;
ImGui.SameLine(); _config.WaitFrames = waitFrames;
ImGui.SetNextItemWidth( 50 ); _configChanged = true;
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." );
}
} }
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() private static void DrawReloadResourceButton()
@ -264,23 +258,24 @@ namespace Penumbra.UI
public void Draw() public void Draw()
{ {
var ret = ImGui.BeginTabItem( LabelTab ); if( !ImGui.BeginTabItem( LabelTab ) )
if( !ret )
{ {
return; return;
} }
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
DrawRootFolder(); DrawRootFolder();
DrawRediscoverButton(); DrawRediscoverButton();
ImGui.SameLine(); ImGui.SameLine();
DrawOpenModsButton(); DrawOpenModsButton();
Custom.ImGuiCustom.VerticalDistance( DefaultVerticalSpace ); ImGuiCustom.VerticalDistance( DefaultVerticalSpace );
DrawEnabledBox(); DrawEnabledBox();
DrawEnabledPlayerWatcher(); DrawEnabledPlayerWatcher();
Custom.ImGuiCustom.VerticalDistance( DefaultVerticalSpace ); ImGuiCustom.VerticalDistance( DefaultVerticalSpace );
DrawScaleModSelectorBox(); DrawScaleModSelectorBox();
DrawSortFoldersFirstBox(); DrawSortFoldersFirstBox();
DrawShowAdvancedBox(); DrawShowAdvancedBox();
@ -295,8 +290,6 @@ namespace Penumbra.UI
_config.Save(); _config.Save();
_configChanged = false; _configChanged = false;
} }
ImGui.EndTabItem();
} }
} }
} }

View file

@ -1,6 +1,7 @@
using System.Numerics; using System.Numerics;
using ImGuiNET; using ImGuiNET;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.UI.Custom;
using Penumbra.Util; using Penumbra.Util;
namespace Penumbra.UI namespace Penumbra.UI
@ -54,13 +55,14 @@ namespace Penumbra.UI
#else #else
var ret = ImGui.Begin( _base._penumbra.Name, ref Visible ); var ret = ImGui.Begin( _base._penumbra.Name, ref Visible );
#endif #endif
using var raii = ImGuiRaii.DeferredEnd( ImGui.End );
if( !ret ) if( !ret )
{ {
ImGui.End();
return; return;
} }
ImGui.BeginTabBar( PenumbraSettingsLabel ); ImGui.BeginTabBar( PenumbraSettingsLabel );
raii.Push( ImGui.EndTabBar );
_settingsTab.Draw(); _settingsTab.Draw();
CollectionsTab.Draw(); CollectionsTab.Draw();
@ -82,10 +84,7 @@ namespace Penumbra.UI
_base.DrawDebugTab(); _base.DrawDebugTab();
_base.DrawResourceManagerTab(); _base.DrawResourceManagerTab();
} }
ImGui.EndTabBar();
ImGui.End();
} }
} }
} }
} }