Use TabBar, add OpenMainWindow and CloseMainWindow to API

This commit is contained in:
Ottermandias 2023-03-08 12:48:59 +01:00
parent 6a54d24634
commit 8d38f73f52
16 changed files with 463 additions and 369 deletions

@ -1 +1 @@
Subproject commit 95a26e944d550a3e77150667af00c23ef307b672
Subproject commit 9ee5721e317457e98f2b8a4500776770f57d204e

@ -1 +1 @@
Subproject commit 1f62ae970e02e48f686a41a2cecdb79e0af87994
Subproject commit a2b680a5991d9287c2dcda7cfa54183c37384fd0

View file

@ -312,6 +312,9 @@ public class IpcTester : IDisposable
private bool _subscribedToClick = false;
private string _lastClicked = string.Empty;
private string _lastHovered = string.Empty;
private TabType _selectTab = TabType.None;
private string _modName = string.Empty;
private PenumbraApiEc _ec = PenumbraApiEc.Success;
public Ui( DalamudPluginInterface pi )
{
@ -330,6 +333,21 @@ public class IpcTester : IDisposable
return;
}
using( var combo = ImRaii.Combo( "Tab to Open at", _selectTab.ToString() ) )
{
if( combo )
{
foreach( var val in Enum.GetValues< TabType >() )
{
if( ImGui.Selectable( val.ToString(), _selectTab == val ) )
{
_selectTab = val;
}
}
}
}
ImGui.InputTextWithHint( "##openMod", "Mod to Open at...", ref _modName, 256 );
using var table = ImRaii.Table( string.Empty, 3, ImGuiTableFlags.SizingFixedFit );
if( !table )
{
@ -370,6 +388,20 @@ public class IpcTester : IDisposable
ImGui.SameLine();
ImGui.TextUnformatted( _lastClicked );
DrawIntro( Ipc.OpenMainWindow.Label, "Open Mod Window" );
if( ImGui.Button( "Open##window" ) )
{
_ec = Ipc.OpenMainWindow.Subscriber( _pi ).Invoke( _selectTab, _modName, _modName );
}
ImGui.SameLine();
ImGui.TextUnformatted( _ec.ToString() );
DrawIntro( Ipc.CloseMainWindow.Label, "Close Mod Window" );
if( ImGui.Button( "Close##window" ) )
{
Ipc.CloseMainWindow.Subscriber( _pi ).Invoke();
}
}
private void UpdateLastDrawnMod( string name )

View file

@ -171,6 +171,38 @@ public class PenumbraApi : IDisposable, IPenumbraApi
public event ChangedItemHover? ChangedItemTooltip;
public event GameObjectResourceResolvedDelegate? GameObjectResourceResolved;
public PenumbraApiEc OpenMainWindow( TabType tab, string modDirectory, string modName )
{
CheckInitialized();
_penumbra!.ConfigWindow.IsOpen = true;
if( !Enum.IsDefined( tab ) )
return PenumbraApiEc.InvalidArgument;
if( tab != TabType.None )
_penumbra!.ConfigWindow.SelectTab = tab;
if( tab == TabType.Mods && (modDirectory.Length > 0 || modName.Length > 0) )
{
if( Penumbra.ModManager.TryGetMod( modDirectory, modName, out var mod ) )
{
_penumbra!.ConfigWindow.SelectMod( mod );
}
else
{
return PenumbraApiEc.ModMissing;
}
}
return PenumbraApiEc.Success;
}
public void CloseMainWindow()
{
CheckInitialized();
_penumbra!.ConfigWindow.IsOpen = false;
}
public void RedrawObject( int tableIndex, RedrawType setting )
{
CheckInitialized();

View file

@ -29,10 +29,12 @@ public class PenumbraIpcProviders : IDisposable
internal readonly EventProvider< string, bool > ModDirectoryChanged;
// UI
internal readonly EventProvider< string > PreSettingsDraw;
internal readonly EventProvider< string > PostSettingsDraw;
internal readonly EventProvider< ChangedItemType, uint > ChangedItemTooltip;
internal readonly EventProvider< MouseButton, ChangedItemType, uint > ChangedItemClick;
internal readonly EventProvider< string > PreSettingsDraw;
internal readonly EventProvider< string > PostSettingsDraw;
internal readonly EventProvider< ChangedItemType, uint > ChangedItemTooltip;
internal readonly EventProvider< MouseButton, ChangedItemType, uint > ChangedItemClick;
internal readonly FuncProvider< TabType, string, string, PenumbraApiEc > OpenMainWindow;
internal readonly ActionProvider CloseMainWindow;
// Redrawing
internal readonly ActionProvider< RedrawType > RedrawAll;
@ -131,6 +133,8 @@ public class PenumbraIpcProviders : IDisposable
PostSettingsDraw = Ipc.PostSettingsDraw.Provider( pi, a => Api.PostSettingsPanelDraw += a, a => Api.PostSettingsPanelDraw -= a );
ChangedItemTooltip = Ipc.ChangedItemTooltip.Provider( pi, () => Api.ChangedItemTooltip += OnTooltip, () => Api.ChangedItemTooltip -= OnTooltip );
ChangedItemClick = Ipc.ChangedItemClick.Provider( pi, () => Api.ChangedItemClicked += OnClick, () => Api.ChangedItemClicked -= OnClick );
OpenMainWindow = Ipc.OpenMainWindow.Provider( pi, Api.OpenMainWindow );
CloseMainWindow = Ipc.CloseMainWindow.Provider( pi, Api.CloseMainWindow );
// Redrawing
RedrawAll = Ipc.RedrawAll.Provider( pi, Api.RedrawAll );
@ -241,6 +245,8 @@ public class PenumbraIpcProviders : IDisposable
PostSettingsDraw.Dispose();
ChangedItemTooltip.Dispose();
ChangedItemClick.Dispose();
OpenMainWindow.Dispose();
CloseMainWindow.Dispose();
// Redrawing
RedrawAll.Dispose();

View file

@ -70,23 +70,23 @@ public class Penumbra : IDalamudPlugin
public static PerformanceTracker< PerformanceType > Performance { get; private set; } = null!;
public static StartTimeTracker< StartTimeType > StartTimer = new();
public static readonly StartTimeTracker< StartTimeType > StartTimer = new();
public static readonly List< Exception > ImcExceptions = new();
public readonly ResourceLogger ResourceLogger;
public readonly PathResolver PathResolver;
public readonly ObjectReloader ObjectReloader;
public readonly ModFileSystem ModFileSystem;
public readonly PenumbraApi Api;
public readonly HttpApi HttpApi;
public readonly PenumbraIpcProviders IpcProviders;
private readonly ConfigWindow _configWindow;
private readonly LaunchButton _launchButton;
private readonly WindowSystem _windowSystem;
private readonly Changelog _changelog;
private readonly CommandHandler _commandHandler;
private readonly ResourceWatcher _resourceWatcher;
public readonly ResourceLogger ResourceLogger;
public readonly PathResolver PathResolver;
public readonly ObjectReloader ObjectReloader;
public readonly ModFileSystem ModFileSystem;
public readonly PenumbraApi Api;
public readonly HttpApi HttpApi;
public readonly PenumbraIpcProviders IpcProviders;
internal readonly ConfigWindow ConfigWindow;
private readonly LaunchButton _launchButton;
private readonly WindowSystem _windowSystem;
private readonly Changelog _changelog;
private readonly CommandHandler _commandHandler;
private readonly ResourceWatcher _resourceWatcher;
public Penumbra( DalamudPluginInterface pluginInterface )
{
@ -140,8 +140,8 @@ public class Penumbra : IDalamudPlugin
ObjectReloader = new ObjectReloader();
PathResolver = new PathResolver( ResourceLoader );
SetupInterface( out _configWindow, out _launchButton, out _windowSystem, out _changelog );
_commandHandler = new CommandHandler( Dalamud.Commands, ObjectReloader, Config, this, _configWindow, ModManager, CollectionManager, Actors );
SetupInterface( out ConfigWindow, out _launchButton, out _windowSystem, out _changelog );
_commandHandler = new CommandHandler( Dalamud.Commands, ObjectReloader, Config, this, ConfigWindow, ModManager, CollectionManager, Actors );
if( Config.EnableMods )
{
@ -152,7 +152,7 @@ public class Penumbra : IDalamudPlugin
if( Config.DebugMode )
{
ResourceLoader.EnableDebug();
_configWindow.IsOpen = true;
ConfigWindow.IsOpen = true;
}
using( var tApi = StartTimer.Measure( StartTimeType.Api ) )
@ -198,10 +198,10 @@ public class Penumbra : IDalamudPlugin
{
using var tInterface = StartTimer.Measure( StartTimeType.Interface );
cfg = new ConfigWindow( this, _resourceWatcher );
btn = new LaunchButton( _configWindow );
btn = new LaunchButton( ConfigWindow );
system = new WindowSystem( Name );
changelog = ConfigWindow.CreateChangelog();
system.AddWindow( _configWindow );
system.AddWindow( ConfigWindow );
system.AddWindow( cfg.ModEditPopup );
system.AddWindow( changelog );
Dalamud.PluginInterface.UiBuilder.OpenConfigUi += cfg.Toggle;
@ -215,10 +215,10 @@ public class Penumbra : IDalamudPlugin
}
_launchButton?.Dispose();
if( _configWindow != null )
if( ConfigWindow != null )
{
Dalamud.PluginInterface.UiBuilder.OpenConfigUi -= _configWindow.Toggle;
_configWindow.Dispose();
Dalamud.PluginInterface.UiBuilder.OpenConfigUi -= ConfigWindow.Toggle;
ConfigWindow.Dispose();
}
}

View file

@ -3,14 +3,11 @@ using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Dalamud.Interface;
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using ImGuiNET;
using Lumina.Data.Parsing;
using Lumina.Excel.GeneratedSheets;
using OtterGui;
using OtterGui.Classes;
using OtterGui.Raii;
using Penumbra.GameData.Structs;
using OtterGui.Widgets;
using Penumbra.Mods;
using Penumbra.UI.Classes;
@ -18,23 +15,71 @@ namespace Penumbra.UI;
public partial class ConfigWindow
{
private LowerString _changedItemFilter = LowerString.Empty;
private LowerString _changedItemModFilter = LowerString.Empty;
// Draw a simple clipped table containing all changed items.
private void DrawChangedItemTab()
public class ChangedItemsTab : ITab
{
private readonly ConfigWindow _config;
public ChangedItemsTab( ConfigWindow config )
=> _config = config;
public ReadOnlySpan<byte> Label
=> "Changed Items"u8;
private LowerString _changedItemFilter = LowerString.Empty;
private LowerString _changedItemModFilter = LowerString.Empty;
public void DrawContent()
{
// Draw filters.
var varWidth = ImGui.GetContentRegionAvail().X
- 400 * ImGuiHelpers.GlobalScale
- ImGui.GetStyle().ItemSpacing.X;
ImGui.SetNextItemWidth( 400 * ImGuiHelpers.GlobalScale );
LowerString.InputWithHint( "##changedItemsFilter", "Filter Item...", ref _changedItemFilter, 128 );
ImGui.SameLine();
ImGui.SetNextItemWidth( varWidth );
LowerString.InputWithHint( "##changedItemsModFilter", "Filter Mods...", ref _changedItemModFilter, 128 );
using var child = ImRaii.Child( "##changedItemsChild", -Vector2.One );
if( !child )
{
return;
}
// Draw table of changed items.
var height = ImGui.GetTextLineHeightWithSpacing() + 2 * ImGui.GetStyle().CellPadding.Y;
var skips = ImGuiClip.GetNecessarySkips( height );
using var list = ImRaii.Table( "##changedItems", 3, ImGuiTableFlags.RowBg, -Vector2.One );
if( !list )
{
return;
}
const ImGuiTableColumnFlags flags = ImGuiTableColumnFlags.NoResize | ImGuiTableColumnFlags.WidthFixed;
ImGui.TableSetupColumn( "items", flags, 400 * ImGuiHelpers.GlobalScale );
ImGui.TableSetupColumn( "mods", flags, varWidth - 120 * ImGuiHelpers.GlobalScale );
ImGui.TableSetupColumn( "id", flags, 120 * ImGuiHelpers.GlobalScale );
var items = Penumbra.CollectionManager.Current.ChangedItems;
var rest = _changedItemFilter.IsEmpty && _changedItemModFilter.IsEmpty
? ImGuiClip.ClippedDraw( items, skips, DrawChangedItemColumn, items.Count )
: ImGuiClip.FilteredClippedDraw( items, skips, FilterChangedItem, DrawChangedItemColumn );
ImGuiClip.DrawEndDummy( rest, height );
}
// Functions in here for less pollution.
bool FilterChangedItem( KeyValuePair< string, (SingleArray< IMod >, object?) > item )
private bool FilterChangedItem( KeyValuePair< string, (SingleArray< IMod >, object?) > item )
=> ( _changedItemFilter.IsEmpty
|| ChangedItemName( item.Key, item.Value.Item2 )
.Contains( _changedItemFilter.Lower, StringComparison.OrdinalIgnoreCase ) )
&& ( _changedItemModFilter.IsEmpty || item.Value.Item1.Any( m => m.Name.Contains( _changedItemModFilter ) ) );
void DrawChangedItemColumn( KeyValuePair< string, (SingleArray< IMod >, object?) > item )
private void DrawChangedItemColumn( KeyValuePair< string, (SingleArray< IMod >, object?) > item )
{
ImGui.TableNextColumn();
DrawChangedItem( item.Key, item.Value.Item2, false );
_config.DrawChangedItem( item.Key, item.Value.Item2, false );
ImGui.TableNextColumn();
if( item.Value.Item1.Count > 0 )
{
@ -52,47 +97,5 @@ public partial class ConfigWindow
ImGuiUtil.RightAlign( text );
}
}
using var tab = ImRaii.TabItem( "Changed Items" );
if( !tab )
{
return;
}
// Draw filters.
var varWidth = ImGui.GetContentRegionAvail().X
- 400 * ImGuiHelpers.GlobalScale
- ImGui.GetStyle().ItemSpacing.X;
ImGui.SetNextItemWidth( 400 * ImGuiHelpers.GlobalScale );
LowerString.InputWithHint( "##changedItemsFilter", "Filter Item...", ref _changedItemFilter, 128 );
ImGui.SameLine();
ImGui.SetNextItemWidth( varWidth );
LowerString.InputWithHint( "##changedItemsModFilter", "Filter Mods...", ref _changedItemModFilter, 128 );
using var child = ImRaii.Child( "##changedItemsChild", -Vector2.One );
if( !child )
{
return;
}
// Draw table of changed items.
var height = ImGui.GetTextLineHeightWithSpacing() + 2 * ImGui.GetStyle().CellPadding.Y;
var skips = ImGuiClip.GetNecessarySkips( height );
using var list = ImRaii.Table( "##changedItems", 3, ImGuiTableFlags.RowBg, -Vector2.One );
if( !list )
{
return;
}
const ImGuiTableColumnFlags flags = ImGuiTableColumnFlags.NoResize | ImGuiTableColumnFlags.WidthFixed;
ImGui.TableSetupColumn( "items", flags, 400 * ImGuiHelpers.GlobalScale );
ImGui.TableSetupColumn( "mods", flags, varWidth - 120 * ImGuiHelpers.GlobalScale );
ImGui.TableSetupColumn( "id", flags, 120 * ImGuiHelpers.GlobalScale );
var items = Penumbra.CollectionManager.Current.ChangedItems;
var rest = _changedItemFilter.IsEmpty && _changedItemModFilter.IsEmpty
? ImGuiClip.ClippedDraw( items, skips, DrawChangedItemColumn, items.Count )
: ImGuiClip.FilteredClippedDraw( items, skips, FilterChangedItem, DrawChangedItemColumn );
ImGuiClip.DrawEndDummy( rest, height );
}
}

View file

@ -14,7 +14,7 @@ namespace Penumbra.UI;
public partial class ConfigWindow
{
// Encapsulate for less pollution.
private partial class CollectionsTab : IDisposable
private partial class CollectionsTab : IDisposable, ITab
{
private readonly ConfigWindow _window;
@ -25,18 +25,17 @@ public partial class ConfigWindow
Penumbra.CollectionManager.CollectionChanged += UpdateIdentifiers;
}
public ReadOnlySpan<byte> Label
=> "Collections"u8;
public void Dispose()
=> Penumbra.CollectionManager.CollectionChanged -= UpdateIdentifiers;
public void Draw()
{
using var tab = ImRaii.TabItem( "Collections" );
OpenTutorial( BasicTutorialSteps.Collections );
if( !tab )
{
return;
}
public void DrawHeader()
=> OpenTutorial( BasicTutorialSteps.Collections );
public void DrawContent()
{
using var child = ImRaii.Child( "##collections", -Vector2.One );
if( child )
{

View file

@ -8,6 +8,7 @@ using FFXIVClientStructs.FFXIV.Client.Game.Object;
using FFXIVClientStructs.FFXIV.Client.System.Resource;
using ImGuiNET;
using OtterGui;
using OtterGui.Widgets;
using Penumbra.GameData.Actors;
using Penumbra.GameData.Files;
using Penumbra.Interop.Loader;
@ -24,32 +25,27 @@ namespace Penumbra.UI;
public partial class ConfigWindow
{
private class DebugTab
private class DebugTab : ITab
{
private readonly ConfigWindow _window;
public DebugTab( ConfigWindow window )
=> _window = window;
public ReadOnlySpan<byte> Label
=> "Debug"u8;
public bool IsVisible
=> Penumbra.Config.DebugMode;
#if DEBUG
private const string DebugVersionString = "(Debug)";
#else
private const string DebugVersionString = "(Release)";
#endif
public void Draw()
public void DrawContent()
{
if( !Penumbra.Config.DebugMode )
{
return;
}
using var tab = TabItem( "Debug" );
if( !tab )
{
return;
}
using var child = Child( "##DebugTab", -Vector2.One );
if( !child )
{

View file

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
@ -6,6 +7,7 @@ using ImGuiNET;
using OtterGui;
using OtterGui.Classes;
using OtterGui.Raii;
using OtterGui.Widgets;
using Penumbra.Collections;
using Penumbra.Meta.Manipulations;
using Penumbra.Mods;
@ -15,17 +17,13 @@ namespace Penumbra.UI;
public partial class ConfigWindow
{
private class EffectiveTab
private class EffectiveTab : ITab
{
// Draw the effective tab if ShowAdvanced is on.
public void Draw()
{
using var tab = ImRaii.TabItem( "Effective Changes" );
if( !tab )
{
return;
}
public ReadOnlySpan<byte> Label
=> "Effective Changes"u8;
public void DrawContent()
{
SetupEffectiveSizes();
DrawFilters();
using var child = ImRaii.Child( "##EffectiveChangesTab", -Vector2.One, false );

View file

@ -0,0 +1,79 @@
using System;
using OtterGui.Widgets;
using Penumbra.Mods;
using Penumbra.UI.Classes;
namespace Penumbra.UI;
public partial class ConfigWindow
{
// The basic setup for the mod panel.
// Details are in other files.
private partial class ModPanel : IDisposable
{
private readonly ConfigWindow _window;
private bool _valid;
private ModFileSystem.Leaf _leaf = null!;
private Mod _mod = null!;
private readonly TagButtons _localTags = new();
public ModPanel( ConfigWindow window )
=> _window = window;
public void Dispose()
{
_nameFont.Dispose();
}
public void Draw( ModFileSystemSelector selector )
{
Init( selector );
if( !_valid )
{
return;
}
DrawModHeader();
DrawTabBar();
}
private void Init( ModFileSystemSelector selector )
{
_valid = selector.Selected != null;
if( !_valid )
{
return;
}
_leaf = selector.SelectedLeaf!;
_mod = selector.Selected!;
UpdateSettingsData( selector );
UpdateModData();
}
public void OnSelectionChange( Mod? old, Mod? mod, in ModFileSystemSelector.ModState _ )
{
if( old == mod )
{
return;
}
if( mod == null )
{
_window.ModEditPopup.IsOpen = false;
}
else if( _window.ModEditPopup.IsOpen )
{
_window.ModEditPopup.ChangeMod( mod );
}
_currentPriority = null;
MoveDirectory.Reset();
OptionTable.Reset();
Input.Reset();
AddOptionGroup.Reset();
}
}
}

View file

@ -2,7 +2,6 @@ using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
using Penumbra.Collections;
using Penumbra.Mods;
using Penumbra.UI.Classes;
using System;
using System.Linq;
@ -15,249 +14,191 @@ namespace Penumbra.UI;
public partial class ConfigWindow
{
private void DrawModsTab()
private class ModsTab : ITab
{
if( !Penumbra.ModManager.Valid )
private readonly ModFileSystemSelector _selector;
private readonly ModPanel _panel;
private readonly Penumbra _penumbra;
public ModsTab(ModFileSystemSelector selector, ModPanel panel, Penumbra penumbra)
{
return;
_selector = selector;
_panel = panel;
_penumbra = penumbra;
}
try
public bool IsVisible
=> Penumbra.ModManager.Valid;
public ReadOnlySpan<byte> Label
=> "Mods"u8;
public void DrawHeader()
=> OpenTutorial( BasicTutorialSteps.Mods );
public void DrawContent()
{
using var tab = ImRaii.TabItem( "Mods" );
OpenTutorial( BasicTutorialSteps.Mods );
if( !tab )
try
{
return;
}
_selector.Draw( GetModSelectorSize() );
ImGui.SameLine();
using var group = ImRaii.Group();
DrawHeaderLine();
using var style = ImRaii.PushStyle( ImGuiStyleVar.ItemSpacing, Vector2.Zero );
using( var child = ImRaii.Child( "##ModsTabMod", new Vector2( -1, Penumbra.Config.HideRedrawBar ? 0 : -ImGui.GetFrameHeight() ),
true, ImGuiWindowFlags.HorizontalScrollbar ) )
{
style.Pop();
if( child )
{
_modPanel.Draw( _selector );
}
style.Push( ImGuiStyleVar.ItemSpacing, Vector2.Zero );
}
style.Push( ImGuiStyleVar.FrameRounding, 0 );
DrawRedrawLine();
}
catch( Exception e )
{
Penumbra.Log.Error( $"Exception thrown during ModPanel Render:\n{e}" );
Penumbra.Log.Error( $"{Penumbra.ModManager.Count} Mods\n"
+ $"{Penumbra.CollectionManager.Current.AnonymizedName} Current Collection\n"
+ $"{Penumbra.CollectionManager.Current.Settings.Count} Settings\n"
+ $"{_selector.SortMode.Name} Sort Mode\n"
+ $"{_selector.SelectedLeaf?.Name ?? "NULL"} Selected Leaf\n"
+ $"{_selector.Selected?.Name ?? "NULL"} Selected Mod\n"
+ $"{string.Join( ", ", Penumbra.CollectionManager.Current.Inheritance.Select( c => c.AnonymizedName ) )} Inheritances\n"
+ $"{_selector.SelectedSettingCollection.AnonymizedName} Collection\n" );
}
}
private void DrawRedrawLine()
{
if( Penumbra.Config.HideRedrawBar )
{
SkipTutorial( BasicTutorialSteps.Redrawing );
return;
}
var frameHeight = new Vector2( 0, ImGui.GetFrameHeight() );
var frameColor = ImGui.GetColorU32( ImGuiCol.FrameBg );
using( var _ = ImRaii.Group() )
{
using( var font = ImRaii.PushFont( UiBuilder.IconFont ) )
{
ImGuiUtil.DrawTextButton( FontAwesomeIcon.InfoCircle.ToIconString(), frameHeight, frameColor );
_selector.Draw( GetModSelectorSize() );
ImGui.SameLine();
}
using var group = ImRaii.Group();
DrawHeaderLine();
ImGuiUtil.DrawTextButton( "Redraw: ", frameHeight, frameColor );
}
using var style = ImRaii.PushStyle( ImGuiStyleVar.ItemSpacing, Vector2.Zero );
var hovered = ImGui.IsItemHovered();
OpenTutorial( BasicTutorialSteps.Redrawing );
if( hovered )
{
ImGui.SetTooltip( $"The supported modifiers for '/penumbra redraw' are:\n{SupportedRedrawModifiers}" );
}
void DrawButton( Vector2 size, string label, string lower )
{
if( ImGui.Button( label, size ) )
{
if( lower.Length > 0 )
using( var child = ImRaii.Child( "##ModsTabMod", new Vector2( -1, Penumbra.Config.HideRedrawBar ? 0 : -ImGui.GetFrameHeight() ),
true, ImGuiWindowFlags.HorizontalScrollbar ) )
{
_penumbra.ObjectReloader.RedrawObject( lower, RedrawType.Redraw );
style.Pop();
if( child )
{
_panel.Draw( _selector );
}
style.Push( ImGuiStyleVar.ItemSpacing, Vector2.Zero );
}
else
style.Push( ImGuiStyleVar.FrameRounding, 0 );
DrawRedrawLine();
}
catch( Exception e )
{
Penumbra.Log.Error( $"Exception thrown during ModPanel Render:\n{e}" );
Penumbra.Log.Error( $"{Penumbra.ModManager.Count} Mods\n"
+ $"{Penumbra.CollectionManager.Current.AnonymizedName} Current Collection\n"
+ $"{Penumbra.CollectionManager.Current.Settings.Count} Settings\n"
+ $"{_selector.SortMode.Name} Sort Mode\n"
+ $"{_selector.SelectedLeaf?.Name ?? "NULL"} Selected Leaf\n"
+ $"{_selector.Selected?.Name ?? "NULL"} Selected Mod\n"
+ $"{string.Join( ", ", Penumbra.CollectionManager.Current.Inheritance.Select( c => c.AnonymizedName ) )} Inheritances\n"
+ $"{_selector.SelectedSettingCollection.AnonymizedName} Collection\n" );
}
}
private void DrawRedrawLine()
{
if( Penumbra.Config.HideRedrawBar )
{
SkipTutorial( BasicTutorialSteps.Redrawing );
return;
}
var frameHeight = new Vector2( 0, ImGui.GetFrameHeight() );
var frameColor = ImGui.GetColorU32( ImGuiCol.FrameBg );
using( var _ = ImRaii.Group() )
{
using( var font = ImRaii.PushFont( UiBuilder.IconFont ) )
{
_penumbra.ObjectReloader.RedrawAll( RedrawType.Redraw );
ImGuiUtil.DrawTextButton( FontAwesomeIcon.InfoCircle.ToIconString(), frameHeight, frameColor );
ImGui.SameLine();
}
ImGuiUtil.DrawTextButton( "Redraw: ", frameHeight, frameColor );
}
ImGuiUtil.HoverTooltip( lower.Length > 0 ? $"Execute '/penumbra redraw {lower}'." : $"Execute '/penumbra redraw'." );
}
var hovered = ImGui.IsItemHovered();
OpenTutorial( BasicTutorialSteps.Redrawing );
if( hovered )
{
ImGui.SetTooltip( $"The supported modifiers for '/penumbra redraw' are:\n{SupportedRedrawModifiers}" );
}
using var disabled = ImRaii.Disabled( Dalamud.ClientState.LocalPlayer == null );
ImGui.SameLine();
var buttonWidth = frameHeight with { X = ImGui.GetContentRegionAvail().X / 4 };
DrawButton( buttonWidth, "All", string.Empty );
ImGui.SameLine();
DrawButton( buttonWidth, "Self", "self" );
ImGui.SameLine();
DrawButton( buttonWidth, "Target", "target" );
ImGui.SameLine();
DrawButton( frameHeight with { X = ImGui.GetContentRegionAvail().X - 1 }, "Focus", "focus" );
}
void DrawButton( Vector2 size, string label, string lower )
{
if( ImGui.Button( label, size ) )
{
if( lower.Length > 0 )
{
_penumbra.ObjectReloader.RedrawObject( lower, RedrawType.Redraw );
}
else
{
_penumbra.ObjectReloader.RedrawAll( RedrawType.Redraw );
}
}
// Draw the header line that can quick switch between collections.
private void DrawHeaderLine()
{
using var style = ImRaii.PushStyle( ImGuiStyleVar.FrameRounding, 0 ).Push( ImGuiStyleVar.ItemSpacing, Vector2.Zero );
var buttonSize = new Vector2( ImGui.GetContentRegionAvail().X / 8f, 0 );
ImGuiUtil.HoverTooltip( lower.Length > 0 ? $"Execute '/penumbra redraw {lower}'." : $"Execute '/penumbra redraw'." );
}
using( var _ = ImRaii.Group() )
{
DrawDefaultCollectionButton( 3 * buttonSize );
using var disabled = ImRaii.Disabled( Dalamud.ClientState.LocalPlayer == null );
ImGui.SameLine();
DrawInheritedCollectionButton( 3 * buttonSize );
var buttonWidth = frameHeight with { X = ImGui.GetContentRegionAvail().X / 4 };
DrawButton( buttonWidth, "All", string.Empty );
ImGui.SameLine();
DrawCollectionSelector( "##collectionSelector", 2 * buttonSize.X, CollectionType.Current, false );
DrawButton( buttonWidth, "Self", "self" );
ImGui.SameLine();
DrawButton( buttonWidth, "Target", "target" );
ImGui.SameLine();
DrawButton( frameHeight with { X = ImGui.GetContentRegionAvail().X - 1 }, "Focus", "focus" );
}
OpenTutorial( BasicTutorialSteps.CollectionSelectors );
if( !Penumbra.CollectionManager.CurrentCollectionInUse )
// Draw the header line that can quick switch between collections.
private void DrawHeaderLine()
{
ImGuiUtil.DrawTextButton( "The currently selected collection is not used in any way.", -Vector2.UnitX, Colors.PressEnterWarningBg );
}
}
using var style = ImRaii.PushStyle( ImGuiStyleVar.FrameRounding, 0 ).Push( ImGuiStyleVar.ItemSpacing, Vector2.Zero );
var buttonSize = new Vector2( ImGui.GetContentRegionAvail().X / 8f, 0 );
private static void DrawDefaultCollectionButton( Vector2 width )
{
var name = $"{DefaultCollection} ({Penumbra.CollectionManager.Default.Name})";
var isCurrent = Penumbra.CollectionManager.Default == Penumbra.CollectionManager.Current;
var isEmpty = Penumbra.CollectionManager.Default == ModCollection.Empty;
var tt = isCurrent ? $"The current collection is already the configured {DefaultCollection}."
: isEmpty ? $"The {DefaultCollection} is configured to be empty."
: $"Set the {SelectedCollection} to the configured {DefaultCollection}.";
if( ImGuiUtil.DrawDisabledButton( name, width, tt, isCurrent || isEmpty ) )
{
Penumbra.CollectionManager.SetCollection( Penumbra.CollectionManager.Default, CollectionType.Current );
}
}
private void DrawInheritedCollectionButton( Vector2 width )
{
var noModSelected = _selector.Selected == null;
var collection = _selector.SelectedSettingCollection;
var modInherited = collection != Penumbra.CollectionManager.Current;
var (name, tt) = ( noModSelected, modInherited ) switch
{
(true, _) => ( "Inherited Collection", "No mod selected." ),
(false, true) => ( $"Inherited Collection ({collection.Name})",
"Set the current collection to the collection the selected mod inherits its settings from." ),
(false, false) => ( "Not Inherited", "The selected mod does not inherit its settings." ),
};
if( ImGuiUtil.DrawDisabledButton( name, width, tt, noModSelected || !modInherited ) )
{
Penumbra.CollectionManager.SetCollection( collection, CollectionType.Current );
}
}
// Get the correct size for the mod selector based on current config.
private static float GetModSelectorSize()
{
var absoluteSize = Math.Clamp( Penumbra.Config.ModSelectorAbsoluteSize, Configuration.Constants.MinAbsoluteSize,
Math.Min( Configuration.Constants.MaxAbsoluteSize, ImGui.GetContentRegionAvail().X - 100 ) );
var relativeSize = Penumbra.Config.ScaleModSelector
? Math.Clamp( Penumbra.Config.ModSelectorScaledSize, Configuration.Constants.MinScaledSize, Configuration.Constants.MaxScaledSize )
: 0;
return !Penumbra.Config.ScaleModSelector
? absoluteSize
: Math.Max( absoluteSize, relativeSize * ImGui.GetContentRegionAvail().X / 100 );
}
// The basic setup for the mod panel.
// Details are in other files.
private partial class ModPanel : IDisposable
{
private readonly ConfigWindow _window;
private bool _valid;
private ModFileSystem.Leaf _leaf = null!;
private Mod _mod = null!;
private readonly TagButtons _localTags = new();
public ModPanel( ConfigWindow window )
=> _window = window;
public void Dispose()
{
_nameFont.Dispose();
}
public void Draw( ModFileSystemSelector selector )
{
Init( selector );
if( !_valid )
using( var _ = ImRaii.Group() )
{
return;
DrawDefaultCollectionButton( 3 * buttonSize );
ImGui.SameLine();
DrawInheritedCollectionButton( 3 * buttonSize );
ImGui.SameLine();
DrawCollectionSelector( "##collectionSelector", 2 * buttonSize.X, CollectionType.Current, false );
}
DrawModHeader();
DrawTabBar();
OpenTutorial( BasicTutorialSteps.CollectionSelectors );
if( !Penumbra.CollectionManager.CurrentCollectionInUse )
{
ImGuiUtil.DrawTextButton( "The currently selected collection is not used in any way.", -Vector2.UnitX, Colors.PressEnterWarningBg );
}
}
private void Init( ModFileSystemSelector selector )
private static void DrawDefaultCollectionButton( Vector2 width )
{
_valid = selector.Selected != null;
if( !_valid )
var name = $"{DefaultCollection} ({Penumbra.CollectionManager.Default.Name})";
var isCurrent = Penumbra.CollectionManager.Default == Penumbra.CollectionManager.Current;
var isEmpty = Penumbra.CollectionManager.Default == ModCollection.Empty;
var tt = isCurrent ? $"The current collection is already the configured {DefaultCollection}."
: isEmpty ? $"The {DefaultCollection} is configured to be empty."
: $"Set the {SelectedCollection} to the configured {DefaultCollection}.";
if( ImGuiUtil.DrawDisabledButton( name, width, tt, isCurrent || isEmpty ) )
{
return;
Penumbra.CollectionManager.SetCollection( Penumbra.CollectionManager.Default, CollectionType.Current );
}
_leaf = selector.SelectedLeaf!;
_mod = selector.Selected!;
UpdateSettingsData( selector );
UpdateModData();
}
public void OnSelectionChange( Mod? old, Mod? mod, in ModFileSystemSelector.ModState _ )
private void DrawInheritedCollectionButton( Vector2 width )
{
if( old == mod )
var noModSelected = _selector.Selected == null;
var collection = _selector.SelectedSettingCollection;
var modInherited = collection != Penumbra.CollectionManager.Current;
var (name, tt) = (noModSelected, modInherited) switch
{
return;
(true, _ ) => ("Inherited Collection", "No mod selected."),
(false, true ) => ($"Inherited Collection ({collection.Name})",
"Set the current collection to the collection the selected mod inherits its settings from."),
(false, false ) => ("Not Inherited", "The selected mod does not inherit its settings."),
};
if( ImGuiUtil.DrawDisabledButton( name, width, tt, noModSelected || !modInherited ) )
{
Penumbra.CollectionManager.SetCollection( collection, CollectionType.Current );
}
}
if( mod == null )
{
_window.ModEditPopup.IsOpen = false;
}
else if( _window.ModEditPopup.IsOpen )
{
_window.ModEditPopup.ChangeMod( mod );
}
_currentPriority = null;
MoveDirectory.Reset();
OptionTable.Reset();
Input.Reset();
AddOptionGroup.Reset();
// Get the correct size for the mod selector based on current config.
private static float GetModSelectorSize()
{
var absoluteSize = Math.Clamp( Penumbra.Config.ModSelectorAbsoluteSize, Configuration.Constants.MinAbsoluteSize,
Math.Min( Configuration.Constants.MaxAbsoluteSize, ImGui.GetContentRegionAvail().X - 100 ) );
var relativeSize = Penumbra.Config.ScaleModSelector
? Math.Clamp( Penumbra.Config.ModSelectorScaledSize, Configuration.Constants.MinScaledSize, Configuration.Constants.MaxScaledSize )
: 0;
return !Penumbra.Config.ScaleModSelector
? absoluteSize
: Math.Max( absoluteSize, relativeSize * ImGui.GetContentRegionAvail().X / 100 );
}
}
}

View file

@ -9,6 +9,7 @@ using FFXIVClientStructs.STD;
using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
using OtterGui.Widgets;
using Penumbra.Interop.Loader;
using Penumbra.String.Classes;
@ -16,12 +17,13 @@ namespace Penumbra.UI;
public partial class ConfigWindow
{
private class ResourceTab
private class ResourceTab : ITab
{
private readonly ConfigWindow _window;
public ReadOnlySpan<byte> Label
=> "Resource Manager"u8;
public ResourceTab( ConfigWindow window )
=> _window = window;
public bool IsVisible
=> Penumbra.Config.DebugMode;
private float _hashColumnWidth;
private float _pathColumnWidth;
@ -29,19 +31,8 @@ public partial class ConfigWindow
private string _resourceManagerFilter = string.Empty;
// Draw a tab to iterate over the main resource maps and see what resources are currently loaded.
public void Draw()
public void DrawContent()
{
if( !Penumbra.Config.DebugMode )
{
return;
}
using var tab = ImRaii.TabItem( "Resource Manager" );
if( !tab )
{
return;
}
// Filter for resources containing the input string.
ImGui.SetNextItemWidth( -1 );
ImGui.InputTextWithHint( "##resourceFilter", "Filter...", ref _resourceManagerFilter, Utf8GamePath.MaxGamePathLength );

View file

@ -17,26 +17,26 @@ namespace Penumbra.UI;
public partial class ConfigWindow
{
private partial class SettingsTab
private partial class SettingsTab : ITab
{
public const int RootDirectoryMaxLength = 64;
private readonly ConfigWindow _window;
public ReadOnlySpan<byte> Label
=> "Settings"u8;
public SettingsTab( ConfigWindow window )
=> _window = window;
public void Draw()
public void DrawHeader()
{
using var tab = ImRaii.TabItem( "Settings" );
OpenTutorial( BasicTutorialSteps.Fin );
OpenTutorial( BasicTutorialSteps.Faq1 );
OpenTutorial( BasicTutorialSteps.Faq2 );
OpenTutorial( BasicTutorialSteps.Faq3 );
if( !tab )
{
return;
}
}
public void DrawContent()
{
using var child = ImRaii.Child( "##SettingsTab", -Vector2.One, false );
if( !child )
{

View file

@ -5,6 +5,9 @@ using Dalamud.Interface.Windowing;
using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
using OtterGui.Widgets;
using Penumbra.Api.Enums;
using Penumbra.Mods;
using Penumbra.UI.Classes;
using Penumbra.Util;
@ -13,16 +16,23 @@ namespace Penumbra.UI;
public sealed partial class ConfigWindow : Window, IDisposable
{
private readonly Penumbra _penumbra;
private readonly SettingsTab _settingsTab;
private readonly ModFileSystemSelector _selector;
private readonly ModPanel _modPanel;
private readonly CollectionsTab _collectionsTab;
private readonly EffectiveTab _effectiveTab;
private readonly DebugTab _debugTab;
private readonly ResourceTab _resourceTab;
private readonly ResourceWatcher _resourceWatcher;
public readonly ModEditWindow ModEditPopup = new();
private readonly SettingsTab _settingsTab;
private readonly CollectionsTab _collectionsTab;
private readonly ModsTab _modsTab;
private readonly ChangedItemsTab _changedItemsTab;
private readonly EffectiveTab _effectiveTab;
private readonly DebugTab _debugTab;
private readonly ResourceTab _resourceTab;
private readonly ResourceWatcher _resourceWatcher;
public TabType SelectTab = TabType.None;
public void SelectMod( Mod mod )
=> _selector.SelectByValue( mod );
public ConfigWindow( Penumbra penumbra, ResourceWatcher watcher )
: base( GetLabel() )
{
@ -32,11 +42,13 @@ public sealed partial class ConfigWindow : Window, IDisposable
_settingsTab = new SettingsTab( this );
_selector = new ModFileSystemSelector( _penumbra.ModFileSystem );
_modPanel = new ModPanel( this );
_modsTab = new ModsTab( _selector, _modPanel, _penumbra );
_selector.SelectionChanged += _modPanel.OnSelectionChange;
_collectionsTab = new CollectionsTab( this );
_changedItemsTab = new ChangedItemsTab( this );
_effectiveTab = new EffectiveTab();
_debugTab = new DebugTab( this );
_resourceTab = new ResourceTab( this );
_resourceTab = new ResourceTab();
if( Penumbra.Config.FixMainWindow )
{
Flags |= ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove;
@ -54,6 +66,20 @@ public sealed partial class ConfigWindow : Window, IDisposable
UpdateTutorialStep();
}
private ReadOnlySpan< byte > ToLabel( TabType type )
=> type switch
{
TabType.Settings => _settingsTab.Label,
TabType.Mods => _modsTab.Label,
TabType.Collections => _collectionsTab.Label,
TabType.ChangedItems => _changedItemsTab.Label,
TabType.EffectiveChanges => _effectiveTab.Label,
TabType.ResourceWatcher => _resourceWatcher.Label,
TabType.Debug => _debugTab.Label,
TabType.ResourceManager => _resourceTab.Label,
_ => ReadOnlySpan< byte >.Empty,
};
public override void Draw()
{
using var performance = Penumbra.Performance.Measure( PerformanceType.UiMainWindow );
@ -92,16 +118,12 @@ public sealed partial class ConfigWindow : Window, IDisposable
}
else
{
using var bar = ImRaii.TabBar( string.Empty, ImGuiTabBarFlags.NoTooltip );
SetupSizes();
_settingsTab.Draw();
DrawModsTab();
_collectionsTab.Draw();
DrawChangedItemTab();
_effectiveTab.Draw();
_debugTab.Draw();
_resourceTab.Draw();
DrawResourceWatcher();
if( TabBar.Draw( string.Empty, ImGuiTabBarFlags.NoTooltip, ToLabel( SelectTab ), _settingsTab, _modsTab, _collectionsTab,
_changedItemsTab, _effectiveTab, _resourceWatcher, _debugTab, _resourceTab ) )
{
SelectTab = TabType.None;
}
}
}
catch( Exception e )
@ -163,13 +185,4 @@ public sealed partial class ConfigWindow : Window, IDisposable
_inputTextWidth = new Vector2( 350f * ImGuiHelpers.GlobalScale, 0 );
_iconButtonSize = new Vector2( ImGui.GetFrameHeight() );
}
private void DrawResourceWatcher()
{
using var tab = ImRaii.TabItem( "Resource Logger" );
if (tab)
{
_resourceWatcher.Draw();
}
}
}

View file

@ -5,6 +5,7 @@ using System.Text.RegularExpressions;
using Dalamud.Interface;
using ImGuiNET;
using OtterGui.Raii;
using OtterGui.Widgets;
using Penumbra.Collections;
using Penumbra.Interop.Loader;
using Penumbra.Interop.Structs;
@ -14,9 +15,9 @@ using Penumbra.UI.Classes;
namespace Penumbra.UI;
public partial class ResourceWatcher : IDisposable
public partial class ResourceWatcher : IDisposable, ITab
{
public const int DefaultMaxEntries = 1024 * 1024;
public const int DefaultMaxEntries = 1024;
private readonly ResourceLoader _loader;
private readonly List< Record > _records = new();
@ -59,7 +60,10 @@ public partial class ResourceWatcher : IDisposable
_table.Reset();
}
public void Draw()
public ReadOnlySpan<byte> Label
=> "Resource Logger"u8;
public void DrawContent()
{
UpdateRecords();