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

View file

@ -1,4 +1,6 @@
using System.Security.Cryptography.X509Certificates;
using System.Windows.Forms;
using Dalamud.Interface;
using ImGuiNET;
namespace Penumbra.UI.Custom
@ -23,7 +25,7 @@ namespace Penumbra.UI.Custom
{
public static void VerticalDistance( float distance )
{
ImGui.SetCursorPosY( ImGui.GetCursorPosY() + distance );
ImGui.SetCursorPosY( ImGui.GetCursorPosY() + distance * ImGuiHelpers.GlobalScale );
}
public static void RightJustifiedText( float pos, string text )
@ -39,4 +41,25 @@ namespace Penumbra.UI.Custom
ImGui.SameLine( pos );
}
}
public static partial class ImGuiCustom
{
public static void HoverTooltip( string text )
{
if( ImGui.IsItemHovered() )
{
ImGui.SetTooltip( text );
}
}
}
public static partial class ImGuiCustom
{
public static void PrintIcon( FontAwesomeIcon icon )
{
ImGui.PushFont( UiBuilder.IconFont );
ImGui.TextUnformatted( icon.ToIconString() );
ImGui.PopFont();
}
}
}

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -2,14 +2,15 @@ using System.IO;
using System.Linq;
using Dalamud.Interface;
using ImGuiNET;
using Penumbra.Api;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Util;
using Penumbra.Meta;
using Penumbra.Mod;
using Penumbra.Mods;
using Penumbra.Structs;
using Penumbra.UI.Custom;
using Penumbra.Util;
using ImGui = ImGuiNET.ImGui;
namespace Penumbra.UI
{
@ -140,6 +141,8 @@ namespace Penumbra.UI
return;
}
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
var desc = Meta.Description;
var flags = _editMode
? ImGuiInputTextFlags.EnterReturnsTrue | ImGuiInputTextFlags.CtrlEnterForNewLine
@ -154,17 +157,12 @@ namespace Penumbra.UI
_selector.SaveCurrentMod();
}
if( ImGui.IsItemHovered() )
{
ImGui.SetTooltip( TooltipAboutEdit );
}
ImGuiCustom.HoverTooltip( TooltipAboutEdit );
}
else
{
ImGui.TextWrapped( desc );
}
ImGui.EndTabItem();
}
private void DrawChangedItemsTab()
@ -174,31 +172,33 @@ namespace Penumbra.UI
return;
}
if( ImGui.BeginListBox( LabelChangedItemsHeader, AutoFillSize ) )
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
if( !ImGui.BeginListBox( LabelChangedItemsHeader, AutoFillSize ) )
{
foreach( var item in Mod.Data.ChangedItems )
{
var ret = ImGui.Selectable( item.Key ) ? MouseButton.Left : MouseButton.None;
ret = ImGui.IsItemClicked( ImGuiMouseButton.Right ) ? MouseButton.Right : ret;
ret = ImGui.IsItemClicked( ImGuiMouseButton.Middle ) ? MouseButton.Middle : ret;
if( ret != MouseButton.None )
{
_base._penumbra.Api.InvokeClick( ret, item.Value );
}
if( _base._penumbra.Api.HasTooltip && ImGui.IsItemHovered() )
{
ImGui.BeginTooltip();
_base._penumbra.Api.InvokeTooltip( item.Value );
ImGui.EndTooltip();
}
}
ImGui.EndListBox();
return;
}
ImGui.EndTabItem();
raii.Push( ImGui.EndListBox );
foreach( var (name, data) in Mod.Data.ChangedItems )
{
var ret = ImGui.Selectable( name ) ? MouseButton.Left : MouseButton.None;
ret = ImGui.IsItemClicked( ImGuiMouseButton.Right ) ? MouseButton.Right : ret;
ret = ImGui.IsItemClicked( ImGuiMouseButton.Middle ) ? MouseButton.Middle : ret;
if( ret != MouseButton.None )
{
_base._penumbra.Api.InvokeClick( ret, data );
}
if( _base._penumbra.Api.HasTooltip && ImGui.IsItemHovered() )
{
ImGui.BeginTooltip();
raii.Push( ImGui.EndTooltip );
_base._penumbra.Api.InvokeTooltip( data );
raii.Pop();
}
}
}
private void DrawConflictTab()
@ -208,38 +208,39 @@ namespace Penumbra.UI
return;
}
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
ImGui.SetNextItemWidth( -1 );
if( ImGui.BeginListBox( LabelConflictsHeader, AutoFillSize ) )
if( !ImGui.BeginListBox( LabelConflictsHeader, AutoFillSize ) )
{
foreach( var kv in Mod.Cache.Conflicts )
{
var mod = kv.Key;
if( ImGui.Selectable( mod.Data.Meta.Name ) )
{
_selector.SelectModByDir( mod.Data.BasePath.Name );
}
ImGui.SameLine();
ImGui.Text( $"(Priority {mod.Settings.Priority})" );
ImGui.Indent( 15 );
foreach( var file in kv.Value.Files )
{
ImGui.Selectable( file );
}
foreach( var manip in kv.Value.Manipulations )
{
ImGui.Text( manip.IdentifierString() );
}
ImGui.Unindent( 15 );
}
ImGui.EndListBox();
return;
}
ImGui.EndTabItem();
raii.Push( ImGui.EndListBox );
using var indent = ImGuiRaii.PushIndent( 0 );
foreach( var (mod, (files, manipulations)) in Mod.Cache.Conflicts )
{
if( ImGui.Selectable( mod.Data.Meta.Name ) )
{
_selector.SelectModByDir( mod.Data.BasePath.Name );
}
ImGui.SameLine();
ImGui.Text( $"(Priority {mod.Settings.Priority})" );
indent.Push( 15f );
foreach( var file in files )
{
ImGui.Selectable( file );
}
foreach( var manip in manipulations )
{
ImGui.Text( manip.IdentifierString() );
}
indent.Pop( 15f );
}
}
private void DrawFileSwapTab()
@ -255,31 +256,31 @@ namespace Penumbra.UI
return;
}
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
const ImGuiTableFlags flags = ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollX;
ImGui.SetNextItemWidth( -1 );
if( ImGui.BeginTable( LabelFileSwapHeader, 3, flags, AutoFillSize ) )
if( !ImGui.BeginTable( LabelFileSwapHeader, 3, flags, AutoFillSize ) )
{
foreach( var file in Meta.FileSwaps )
{
ImGui.TableNextColumn();
Custom.ImGuiCustom.CopyOnClickSelectable( file.Key );
ImGui.TableNextColumn();
ImGui.PushFont( UiBuilder.IconFont );
ImGui.TextUnformatted( $"{( char )FontAwesomeIcon.LongArrowAltRight}" );
ImGui.PopFont();
ImGui.TableNextColumn();
Custom.ImGuiCustom.CopyOnClickSelectable( file.Value );
ImGui.TableNextRow();
}
ImGui.EndTable();
return;
}
ImGui.EndTabItem();
raii.Push( ImGui.EndTable );
foreach( var (source, target) in Meta.FileSwaps )
{
ImGui.TableNextColumn();
ImGuiCustom.CopyOnClickSelectable( source );
ImGui.TableNextColumn();
ImGuiCustom.PrintIcon( FontAwesomeIcon.LongArrowAltRight );
ImGui.TableNextColumn();
ImGuiCustom.CopyOnClickSelectable( target );
ImGui.TableNextRow();
}
}
private void UpdateFilenameList()
@ -329,30 +330,26 @@ namespace Penumbra.UI
return;
}
if( ImGui.IsItemHovered() )
{
ImGui.SetTooltip( TooltipFilesTab );
}
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
ImGuiCustom.HoverTooltip( TooltipFilesTab );
ImGui.SetNextItemWidth( -1 );
if( ImGui.BeginListBox( LabelFileListHeader, AutoFillSize ) )
{
raii.Push( ImGui.EndListBox );
UpdateFilenameList();
using var colorRaii = new ImGuiRaii.Color();
foreach( var (name, _, color, _) in _fullFilenameList! )
{
ImGui.PushStyleColor( ImGuiCol.Text, color );
colorRaii.Push( ImGuiCol.Text, color );
ImGui.Selectable( name.FullName );
ImGui.PopStyleColor();
colorRaii.Pop();
}
ImGui.EndListBox();
}
else
{
_fullFilenameList = null;
}
ImGui.EndTabItem();
}
private static int HandleDefaultString( GamePath[] gamePaths, out int removeFolders )
@ -469,10 +466,7 @@ namespace Penumbra.UI
ImGui.SetNextItemWidth( -1 );
ImGui.InputTextWithHint( LabelGamePathsEditBox, "Hover for help...", ref _currentGamePaths,
128 );
if( ImGui.IsItemHovered() )
{
ImGui.SetTooltip( TooltipGamePathsEdit );
}
ImGuiCustom.HoverTooltip( TooltipGamePathsEdit );
}
private void DrawGroupRow()
@ -516,12 +510,11 @@ namespace Penumbra.UI
loc = colorReplace;
}
ImGui.PushStyleColor( ImGuiCol.Text, loc );
using var colors = ImGuiRaii.PushColor( ImGuiCol.Text, loc );
ImGui.Selectable( _fullFilenameList[ idx ].name.FullName, ref _fullFilenameList[ idx ].selected );
ImGui.PopStyleColor();
}
const float indent = 30f;
const float indentWidth = 30f;
if( _selectedOption == null )
{
Selectable( 0, ColorGreen );
@ -534,8 +527,8 @@ namespace Penumbra.UI
{
Selectable( 0, ColorGreen );
ImGui.Indent( indent );
var tmpPaths = gamePaths.ToArray();
using var indent = ImGuiRaii.PushIndent( indentWidth );
var tmpPaths = gamePaths.ToArray();
foreach( var gamePath in tmpPaths )
{
string tmp = gamePath;
@ -556,8 +549,6 @@ namespace Penumbra.UI
_selector.ReloadCurrentMod();
}
}
ImGui.Unindent( indent );
}
else
{
@ -588,14 +579,13 @@ namespace Penumbra.UI
return;
}
Custom.ImGuiCustom.BeginFramedGroup( group.GroupName );
ImGuiCustom.BeginFramedGroup( group.GroupName );
using var raii = ImGuiRaii.DeferredEnd( ImGuiCustom.EndFramedGroup );
for( var i = 0; i < group.Options.Count; ++i )
{
DrawMultiSelectorCheckBox( group, i, Mod.Settings.Settings[ group.GroupName ],
$"{group.Options[ i ].OptionName}##{group.GroupName}" );
}
Custom.ImGuiCustom.EndFramedGroup();
}
private void DrawSingleSelector( OptionGroup group )
@ -635,79 +625,76 @@ namespace Penumbra.UI
private void DrawConfigurationTab()
{
if( !_editMode && !Meta.HasGroupsWithConfig )
if( !_editMode && !Meta.HasGroupsWithConfig || !ImGui.BeginTabItem( LabelConfigurationTab ) )
{
return;
}
if( ImGui.BeginTabItem( LabelConfigurationTab ) )
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
if( _editMode )
{
if( _editMode )
{
DrawGroupSelectorsEdit();
}
else
{
DrawGroupSelectors();
}
ImGui.EndTabItem();
DrawGroupSelectorsEdit();
}
else
{
DrawGroupSelectors();
}
}
private void DrawMetaManipulationsTab()
{
if( !_editMode && Mod.Data.Resources.MetaManipulations.Count == 0 )
if( !_editMode && Mod.Data.Resources.MetaManipulations.Count == 0 || !ImGui.BeginTabItem( "Meta Manipulations" ) )
{
return;
}
if( !ImGui.BeginTabItem( "Meta Manipulations" ) )
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
if( !ImGui.BeginListBox( "##MetaManipulations", AutoFillSize ) )
{
return;
}
if( ImGui.BeginListBox( "##MetaManipulations", AutoFillSize ) )
raii.Push( ImGui.EndListBox );
var manips = Mod.Data.Resources.MetaManipulations;
var changes = false;
if( _editMode || manips.DefaultData.Count > 0 )
{
var manips = Mod.Data.Resources.MetaManipulations;
var changes = false;
if( _editMode || manips.DefaultData.Count > 0 )
if( ImGui.CollapsingHeader( "Default" ) )
{
if( ImGui.CollapsingHeader( "Default" ) )
{
changes = DrawMetaManipulationsTable( "##DefaultManips", manips.DefaultData, ref manips.Count );
}
changes = DrawMetaManipulationsTable( "##DefaultManips", manips.DefaultData, ref manips.Count );
}
foreach( var group in manips.GroupData )
{
foreach( var option in group.Value )
{
if( ImGui.CollapsingHeader( $"{group.Key} - {option.Key}" ) )
{
changes |= DrawMetaManipulationsTable( $"##{group.Key}{option.Key}manips", option.Value, ref manips.Count );
}
}
}
if( changes )
{
Mod.Data.Resources.MetaManipulations.SaveToFile( MetaCollection.FileName( Mod.Data.BasePath ) );
Mod.Data.Resources.SetManipulations( Meta, Mod.Data.BasePath, false );
_selector.ReloadCurrentMod( true, false );
}
ImGui.EndListBox();
}
ImGui.EndTabItem();
foreach( var (groupName, group) in manips.GroupData )
{
foreach( var (optionName, option) in group )
{
if( ImGui.CollapsingHeader( $"{groupName} - {optionName}" ) )
{
changes |= DrawMetaManipulationsTable( $"##{groupName}{optionName}manips", option, ref manips.Count );
}
}
}
if( changes )
{
Mod.Data.Resources.MetaManipulations.SaveToFile( MetaCollection.FileName( Mod.Data.BasePath ) );
Mod.Data.Resources.SetManipulations( Meta, Mod.Data.BasePath, false );
_selector.ReloadCurrentMod( true, false );
}
}
public void Draw( bool editMode )
{
_editMode = editMode;
ImGui.BeginTabBar( LabelPluginDetails );
if( !ImGui.BeginTabBar( LabelPluginDetails ) )
{
return;
}
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabBar );
DrawAboutTab();
DrawChangedItemsTab();
@ -724,7 +711,6 @@ namespace Penumbra.UI
DrawFileSwapTab();
DrawMetaManipulationsTab();
DrawConflictTab();
ImGui.EndTabBar();
}
}
}

View file

@ -6,6 +6,7 @@ using ImGuiNET;
using Penumbra.GameData.Util;
using Penumbra.Mods;
using Penumbra.Structs;
using Penumbra.UI.Custom;
using Penumbra.Util;
namespace Penumbra.UI
@ -38,7 +39,7 @@ namespace Penumbra.UI
private bool DrawEditGroupSelector()
{
ImGui.SetNextItemWidth( OptionSelectionWidth );
ImGui.SetNextItemWidth( OptionSelectionWidth * ImGuiHelpers.GlobalScale );
if( Meta!.Groups.Count == 0 )
{
ImGui.Combo( LabelGroupSelect, ref _selectedGroupIndex, TextNoOptionAvailable, 1 );
@ -87,7 +88,7 @@ namespace Penumbra.UI
}
ImGui.SetNextItemWidth( -1 );
if( ImGui.BeginListBox( LabelFileListHeader, AutoFillSize - new Vector2( 0, 1.5f * ImGui.GetTextLineHeight() ) ) )
if( ImGui.BeginListBox( LabelFileListHeader, AutoFillSize - Vector2.UnitY * 1.5f * ImGui.GetTextLineHeight() ) )
{
for( var i = 0; i < Mod!.Data.Resources.ModFiles.Count; ++i )
{
@ -106,23 +107,27 @@ namespace Penumbra.UI
}
}
private void DrawMultiSelectorEditBegin( OptionGroup group )
private ImGuiRaii.EndStack DrawMultiSelectorEditBegin( OptionGroup group )
{
var groupName = group.GroupName;
if( Custom.ImGuiCustom.BeginFramedGroupEdit( ref groupName ) )
if( !ImGuiCustom.BeginFramedGroupEdit( ref groupName ) )
{
if( _modManager.ChangeModGroup( group.GroupName, groupName, Mod.Data ) && Mod.Data.Meta.RefreshHasGroupsWithConfig() )
{
_selector.Cache.TriggerFilterReset();
}
return new ImGuiRaii.EndStack();
}
if( _modManager.ChangeModGroup( group.GroupName, groupName, Mod.Data ) && Mod.Data.Meta.RefreshHasGroupsWithConfig() )
{
_selector.Cache.TriggerFilterReset();
}
return ImGuiRaii.DeferredEnd( ImGuiCustom.EndFramedGroup );
}
private void DrawMultiSelectorEditAdd( OptionGroup group, float nameBoxStart )
{
var newOption = "";
ImGui.SetCursorPosX( nameBoxStart );
ImGui.SetNextItemWidth( MultiEditBoxWidth );
ImGui.SetNextItemWidth( MultiEditBoxWidth * ImGuiHelpers.GlobalScale );
if( ImGui.InputTextWithHint( $"##new_{group.GroupName}_l", "Add new option...", ref newOption, 64,
ImGuiInputTextFlags.EnterReturnsTrue )
&& newOption.Length != 0 )
@ -142,7 +147,7 @@ namespace Penumbra.UI
var nameBoxStart = CheckMarkSize;
var flag = Mod!.Settings.Settings[ group.GroupName ];
DrawMultiSelectorEditBegin( group );
using var raii = DrawMultiSelectorEditBegin( group );
for( var i = 0; i < group.Options.Count; ++i )
{
var opt = group.Options[ i ];
@ -157,7 +162,7 @@ namespace Penumbra.UI
nameBoxStart = ImGui.GetCursorPosX();
}
ImGui.SetNextItemWidth( MultiEditBoxWidth );
ImGui.SetNextItemWidth( MultiEditBoxWidth * ImGuiHelpers.GlobalScale );
if( ImGui.InputText( $"{label}_l", ref newName, 64, ImGuiInputTextFlags.EnterReturnsTrue ) )
{
if( newName.Length == 0 )
@ -179,8 +184,6 @@ namespace Penumbra.UI
}
DrawMultiSelectorEditAdd( group, nameBoxStart );
Custom.ImGuiCustom.EndFramedGroup();
}
private void DrawSingleSelectorEditGroup( OptionGroup group )
@ -199,7 +202,7 @@ namespace Penumbra.UI
{
var oldSetting = Mod!.Settings.Settings[ group.GroupName ];
var code = oldSetting;
if( Custom.ImGuiCustom.RenameableCombo( $"##{group.GroupName}", ref code, out var newName,
if( ImGuiCustom.RenameableCombo( $"##{group.GroupName}", ref code, out var newName,
group.Options.Select( x => x.OptionName ).ToArray(), group.Options.Count ) )
{
if( code == group.Options.Count )
@ -260,7 +263,7 @@ namespace Penumbra.UI
ImGui.SetCursorPosX( labelEditPos );
if( labelEditPos == CheckMarkSize )
{
ImGui.SetNextItemWidth( MultiEditBoxWidth );
ImGui.SetNextItemWidth( MultiEditBoxWidth * ImGuiHelpers.GlobalScale );
}
if( ImGui.InputTextWithHint( LabelNewSingleGroupEdit, "Add new Single Group...", ref newGroup, 64,
@ -275,7 +278,7 @@ namespace Penumbra.UI
{
var newGroup = "";
ImGui.SetCursorPosX( CheckMarkSize );
ImGui.SetNextItemWidth( MultiEditBoxWidth );
ImGui.SetNextItemWidth( MultiEditBoxWidth * ImGuiHelpers.GlobalScale );
if( ImGui.InputTextWithHint( LabelNewMultiGroup, "Add new Multi Group...", ref newGroup, 64,
ImGuiInputTextFlags.EnterReturnsTrue ) )
{
@ -310,74 +313,75 @@ namespace Penumbra.UI
return;
}
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
ImGui.SetNextItemWidth( -1 );
if( ImGui.BeginListBox( LabelFileSwapHeader, AutoFillSize ) )
if( !ImGui.BeginListBox( LabelFileSwapHeader, AutoFillSize ) )
{
var swaps = Meta.FileSwaps.Keys.ToArray();
return;
}
var arrow = $"{( char )FontAwesomeIcon.LongArrowAltRight}";
ImGui.PushFont( UiBuilder.IconFont );
var arrowWidth = ImGui.CalcTextSize( arrow ).X;
ImGui.PopFont();
raii.Push( ImGui.EndListBox );
var width = ( ImGui.GetWindowWidth() - arrowWidth - 4 * ImGui.GetStyle().ItemSpacing.X ) / 2;
for( var idx = 0; idx < swaps.Length + 1; ++idx )
var swaps = Meta.FileSwaps.Keys.ToArray();
ImGui.PushFont( UiBuilder.IconFont );
var arrowWidth = ImGui.CalcTextSize( FontAwesomeIcon.LongArrowAltRight.ToIconString() ).X;
ImGui.PopFont();
var width = ( ImGui.GetWindowWidth() - arrowWidth - 4 * ImGui.GetStyle().ItemSpacing.X ) / 2;
for( var idx = 0; idx < swaps.Length + 1; ++idx )
{
var key = idx == swaps.Length ? GamePath.GenerateUnchecked( "" ) : swaps[ idx ];
var value = idx == swaps.Length ? GamePath.GenerateUnchecked( "" ) : Meta.FileSwaps[ key ];
string keyString = key;
string valueString = value;
ImGui.SetNextItemWidth( width );
if( ImGui.InputTextWithHint( $"##swapLhs_{idx}", "Enter new file to be replaced...", ref keyString,
GamePath.MaxGamePathLength, ImGuiInputTextFlags.EnterReturnsTrue ) )
{
var key = idx == swaps.Length ? GamePath.GenerateUnchecked( "" ) : swaps[ idx ];
var value = idx == swaps.Length ? GamePath.GenerateUnchecked( "" ) : Meta.FileSwaps[ key ];
string keyString = key;
string valueString = value;
ImGui.SetNextItemWidth( width );
if( ImGui.InputTextWithHint( $"##swapLhs_{idx}", "Enter new file to be replaced...", ref keyString,
GamePath.MaxGamePathLength, ImGuiInputTextFlags.EnterReturnsTrue ) )
var newKey = new GamePath( keyString );
if( newKey.CompareTo( key ) != 0 )
{
var newKey = new GamePath( keyString );
if( newKey.CompareTo( key ) != 0 )
if( idx < swaps.Length )
{
if( idx < swaps.Length )
{
Meta.FileSwaps.Remove( key );
}
if( newKey != string.Empty )
{
Meta.FileSwaps[ newKey ] = value;
}
_selector.SaveCurrentMod();
_selector.ReloadCurrentMod();
Meta.FileSwaps.Remove( key );
}
}
if( idx < swaps.Length )
{
ImGui.SameLine();
ImGui.PushFont( UiBuilder.IconFont );
ImGui.TextUnformatted( arrow );
ImGui.PopFont();
ImGui.SameLine();
ImGui.SetNextItemWidth( width );
if( ImGui.InputTextWithHint( $"##swapRhs_{idx}", "Enter new replacement path...", ref valueString,
GamePath.MaxGamePathLength,
ImGuiInputTextFlags.EnterReturnsTrue ) )
if( newKey != string.Empty )
{
var newValue = new GamePath( valueString );
if( newValue.CompareTo( value ) != 0 )
{
Meta.FileSwaps[ key ] = newValue;
_selector.SaveCurrentMod();
_selector.Cache.TriggerListReset();
}
Meta.FileSwaps[ newKey ] = value;
}
_selector.SaveCurrentMod();
_selector.ReloadCurrentMod();
}
}
ImGui.EndListBox();
}
if( idx >= swaps.Length )
{
continue;
}
ImGui.EndTabItem();
ImGui.SameLine();
ImGuiCustom.PrintIcon( FontAwesomeIcon.LongArrowAltRight );
ImGui.SameLine();
ImGui.SetNextItemWidth( width );
if( ImGui.InputTextWithHint( $"##swapRhs_{idx}", "Enter new replacement path...", ref valueString,
GamePath.MaxGamePathLength,
ImGuiInputTextFlags.EnterReturnsTrue ) )
{
var newValue = new GamePath( valueString );
if( newValue.CompareTo( value ) != 0 )
{
Meta.FileSwaps[ key ] = newValue;
_selector.SaveCurrentMod();
_selector.Cache.TriggerListReset();
}
}
}
}
}
}

View file

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

View file

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

View file

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

View file

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

View file

@ -7,6 +7,7 @@ using ImGuiNET;
using Penumbra.GameData.Enums;
using Penumbra.Interop;
using Penumbra.Mods;
using Penumbra.UI.Custom;
using Penumbra.Util;
namespace Penumbra.UI
@ -65,13 +66,10 @@ namespace Penumbra.UI
_base._modManager.SetTempDirectory( tempPath );
}
if( ImGui.IsItemHovered() )
{
ImGui.SetTooltip( "The folder used to store temporary meta manipulation files.\n"
+ "Leave this blank if you have no reason not to.\n"
+ "A folder 'penumbrametatmp' will be created as a subdirectory to the specified directory.\n"
+ "If none is specified (i.e. this is blank) this folder will be created in the root folder instead." );
}
ImGuiCustom.HoverTooltip( "The folder used to store temporary meta manipulation files.\n"
+ "Leave this blank if you have no reason not to.\n"
+ "A folder 'penumbrametatmp' will be created as a subdirectory to the specified directory.\n"
+ "If none is specified (i.e. this is blank) this folder will be created in the root folder instead." );
ImGui.SameLine();
if( ImGui.Button( LabelOpenTempFolder ) )
@ -115,7 +113,7 @@ namespace Penumbra.UI
{
_config.IsEnabled = enabled;
_configChanged = true;
Service<ResidentResources>.Get().ReloadPlayerResources();
Service< ResidentResources >.Get().ReloadPlayerResources();
_base._penumbra.ObjectReloader.RedrawAll( enabled ? RedrawType.WithSettings : RedrawType.WithoutSettings );
if( _config.EnablePlayerWatch )
{
@ -177,10 +175,10 @@ namespace Penumbra.UI
private void DrawDisableNotificationsBox()
{
var fswatch = _config.DisableFileSystemNotifications;
if( ImGui.Checkbox( LabelDisableNotifications, ref fswatch ) )
var fsWatch = _config.DisableFileSystemNotifications;
if( ImGui.Checkbox( LabelDisableNotifications, ref fsWatch ) )
{
_config.DisableFileSystemNotifications = fswatch;
_config.DisableFileSystemNotifications = fsWatch;
_configChanged = true;
}
}
@ -210,39 +208,35 @@ namespace Penumbra.UI
if( ImGui.Checkbox( LabelEnabledPlayerWatch, ref enabled ) )
{
_config.EnablePlayerWatch = enabled;
_configChanged = true;
_configChanged = true;
Penumbra.PlayerWatcher.SetStatus( enabled );
}
if( ImGui.IsItemHovered() )
ImGuiCustom.HoverTooltip(
"If this setting is enabled, penumbra will keep tabs on characters that have a corresponding collection setup in the Collections tab.\n"
+ "Penumbra will try to automatically redraw those characters using their collection when they first appear in an instance, or when they change their current equip." );
if( !_config.EnablePlayerWatch || !_config.ShowAdvanced )
{
ImGui.SetTooltip(
"If this setting is enabled, penumbra will keep tabs on characters that have a corresponding collection setup in the Collections tab.\n"
+ "Penumbra will try to automatically redraw those characters using their collection when they first appear in an instance, or when they change their current equip." );
return;
}
if( _config.EnablePlayerWatch && _config.ShowAdvanced )
var waitFrames = _config.WaitFrames;
ImGui.SameLine();
ImGui.SetNextItemWidth( 50 );
if( ImGui.InputInt( LabelWaitFrames, ref waitFrames, 0, 0 )
&& waitFrames != _config.WaitFrames
&& waitFrames > 0
&& waitFrames < 3000 )
{
var waitFrames = _config.WaitFrames;
ImGui.SameLine();
ImGui.SetNextItemWidth( 50 );
if( ImGui.InputInt( LabelWaitFrames, ref waitFrames, 0, 0 )
&& waitFrames != _config.WaitFrames
&& waitFrames > 0
&& waitFrames < 3000 )
{
_base._penumbra.ObjectReloader.DefaultWaitFrames = waitFrames;
_config.WaitFrames = waitFrames;
_configChanged = true;
}
if( ImGui.IsItemHovered() )
{
ImGui.SetTooltip(
"The number of frames penumbra waits after some events (like zone changes) until it starts trying to redraw actors again, in a range of [1, 3001].\n"
+ "Keep this as low as possible while producing stable results." );
}
_base._penumbra.ObjectReloader.DefaultWaitFrames = waitFrames;
_config.WaitFrames = waitFrames;
_configChanged = true;
}
ImGuiCustom.HoverTooltip(
"The number of frames penumbra waits after some events (like zone changes) until it starts trying to redraw actors again, in a range of [1, 3001].\n"
+ "Keep this as low as possible while producing stable results." );
}
private static void DrawReloadResourceButton()
@ -264,23 +258,24 @@ namespace Penumbra.UI
public void Draw()
{
var ret = ImGui.BeginTabItem( LabelTab );
if( !ret )
if( !ImGui.BeginTabItem( LabelTab ) )
{
return;
}
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
DrawRootFolder();
DrawRediscoverButton();
ImGui.SameLine();
DrawOpenModsButton();
Custom.ImGuiCustom.VerticalDistance( DefaultVerticalSpace );
ImGuiCustom.VerticalDistance( DefaultVerticalSpace );
DrawEnabledBox();
DrawEnabledPlayerWatcher();
Custom.ImGuiCustom.VerticalDistance( DefaultVerticalSpace );
ImGuiCustom.VerticalDistance( DefaultVerticalSpace );
DrawScaleModSelectorBox();
DrawSortFoldersFirstBox();
DrawShowAdvancedBox();
@ -295,8 +290,6 @@ namespace Penumbra.UI
_config.Save();
_configChanged = false;
}
ImGui.EndTabItem();
}
}
}

View file

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