Even almoster...

This commit is contained in:
Ottermandias 2022-04-20 11:03:19 +02:00
parent 65bd1d1b52
commit 8dd681bdda
19 changed files with 2625 additions and 1865 deletions

@ -1 +1 @@
Subproject commit 4cc1024096905b0b20c1559c534b1dd3fe7b25ad Subproject commit a832fb6ca5e7c6cb4e35a51a08d30d1800f405da

View file

@ -81,6 +81,29 @@ public partial class ModCollection
_modManager.ModPathChanged -= OnModPathChanged; _modManager.ModPathChanged -= OnModPathChanged;
} }
// Returns true if the name is not empty, it is not the name of the empty collection
// and no existing collection results in the same filename as name.
public bool CanAddCollection( string name, out string fixedName )
{
if( name.Length == 0 )
{
fixedName = string.Empty;
return false;
}
name = name.RemoveInvalidPathSymbols().ToLowerInvariant();
if( name.Length == 0
|| name == Empty.Name.ToLowerInvariant()
|| _collections.Any( c => c.Name.RemoveInvalidPathSymbols().ToLowerInvariant() == name ) )
{
fixedName = string.Empty;
return false;
}
fixedName = name;
return true;
}
// Add a new collection of the given name. // Add a new collection of the given name.
// If duplicate is not-null, the new collection will be a duplicate of it. // If duplicate is not-null, the new collection will be a duplicate of it.
// If the name of the collection would result in an already existing filename, skip it. // If the name of the collection would result in an already existing filename, skip it.
@ -88,12 +111,9 @@ public partial class ModCollection
// Also sets the current collection to the new collection afterwards. // Also sets the current collection to the new collection afterwards.
public bool AddCollection( string name, ModCollection? duplicate ) public bool AddCollection( string name, ModCollection? duplicate )
{ {
var nameFixed = name.RemoveInvalidPathSymbols().ToLowerInvariant(); if( !CanAddCollection( name, out var fixedName ) )
if( nameFixed.Length == 0
|| nameFixed == Empty.Name.ToLowerInvariant()
|| _collections.Any( c => c.Name.RemoveInvalidPathSymbols().ToLowerInvariant() == nameFixed ) )
{ {
PluginLog.Warning( $"The new collection {name} would lead to the same path as one that already exists." ); PluginLog.Warning( $"The new collection {name} would lead to the same path {fixedName} as one that already exists." );
return false; return false;
} }
@ -108,6 +128,7 @@ public partial class ModCollection
// Remove the given collection if it exists and is neither the empty nor the default-named collection. // Remove the given collection if it exists and is neither the empty nor the default-named collection.
// If the removed collection was active, it also sets the corresponding collection to the appropriate default. // If the removed collection was active, it also sets the corresponding collection to the appropriate default.
// Also removes the collection from inheritances of all other collections.
public bool RemoveCollection( int idx ) public bool RemoveCollection( int idx )
{ {
if( idx <= Empty.Index || idx >= _collections.Count ) if( idx <= Empty.Index || idx >= _collections.Count )
@ -140,9 +161,18 @@ public partial class ModCollection
var collection = _collections[ idx ]; var collection = _collections[ idx ];
collection.Delete(); collection.Delete();
_collections.RemoveAt( idx ); _collections.RemoveAt( idx );
for( var i = idx; i < _collections.Count; ++i ) foreach( var c in _collections )
{ {
--_collections[ i ].Index; var inheritedIdx = c._inheritance.IndexOf( collection );
if( inheritedIdx >= 0 )
{
c.RemoveInheritance( inheritedIdx );
}
if( c.Index > idx )
{
--c.Index;
}
} }
CollectionChanged.Invoke( Type.Inactive, collection, null ); CollectionChanged.Invoke( Type.Inactive, collection, null );

View file

@ -137,7 +137,7 @@ public partial class ModCollection
return false; return false;
} }
_settings[ idx ] = inherit ? null : this[ idx ].Settings ?? ModSettings2.DefaultSettings( Penumbra.ModManager.Mods[ idx ] ); _settings[ idx ] = inherit ? null : this[ idx ].Settings?.DeepCopy() ?? ModSettings2.DefaultSettings( Penumbra.ModManager.Mods[ idx ] );
return true; return true;
} }

View file

@ -23,23 +23,57 @@ public partial class ModCollection
// Iterate over all collections inherited from in depth-first order. // Iterate over all collections inherited from in depth-first order.
// Skip already visited collections to avoid circular dependencies. // Skip already visited collections to avoid circular dependencies.
public IEnumerable< ModCollection > GetFlattenedInheritance() public IEnumerable< ModCollection > GetFlattenedInheritance()
{ => InheritedCollections( this ).Distinct();
yield return this;
foreach( var collection in _inheritance.SelectMany( c => c.GetFlattenedInheritance() ) // All inherited collections in application order without filtering for duplicates.
.Where( c => !ReferenceEquals( this, c ) ) private static IEnumerable< ModCollection > InheritedCollections( ModCollection collection )
.Distinct() ) => collection.Inheritance.SelectMany( InheritedCollections ).Prepend( collection );
// Reasons why a collection can not be inherited from.
public enum ValidInheritance
{ {
yield return collection; Valid,
Self, // Can not inherit from self
Empty, // Can not inherit from the empty collection
Contained, // Already inherited from
Circle, // Inheritance would lead to a circle.
} }
// Check whether a collection can be inherited from.
public ValidInheritance CheckValidInheritance( ModCollection? collection )
{
if( collection == null || ReferenceEquals( collection, Empty ) )
{
return ValidInheritance.Empty;
} }
if( ReferenceEquals( collection, this ) )
{
return ValidInheritance.Self;
}
if( _inheritance.Contains( collection ) )
{
return ValidInheritance.Contained;
}
if( InheritedCollections( collection ).Any( c => c == this ) )
{
return ValidInheritance.Circle;
}
return ValidInheritance.Valid;
}
private bool CheckForCircle( ModCollection collection )
=> ReferenceEquals( collection, this ) || _inheritance.Any( c => c.CheckForCircle( collection ) );
// Add a new collection to the inheritance list. // Add a new collection to the inheritance list.
// We do not check if this collection would be visited before, // We do not check if this collection would be visited before,
// only that it is unique in the list itself. // only that it is unique in the list itself.
public bool AddInheritance( ModCollection collection ) public bool AddInheritance( ModCollection collection )
{ {
if( ReferenceEquals( collection, this ) || _inheritance.Contains( collection ) ) if( CheckValidInheritance( collection ) != ValidInheritance.Valid )
{ {
return false; return false;
} }

View file

@ -22,6 +22,7 @@ public static class Colors
{ {
public const uint PressEnterWarningBg = 0xFF202080; public const uint PressEnterWarningBg = 0xFF202080;
public const uint RegexWarningBorder = 0xFF0000B0; public const uint RegexWarningBorder = 0xFF0000B0;
public const uint MetaInfoText = 0xAAFFFFFF;
public static (uint DefaultColor, string Name, string Description) Data( this ColorId color ) public static (uint DefaultColor, string Name, string Description) Data( this ColorId color )
=> color switch => color switch

View file

@ -48,6 +48,9 @@ public sealed partial class ModFileSystemSelector : FileSystemSelector< Mod2, Mo
Penumbra.CollectionManager.CollectionChanged -= OnCollectionChange; Penumbra.CollectionManager.CollectionChanged -= OnCollectionChange;
} }
public new ModFileSystem.Leaf? SelectedLeaf
=> base.SelectedLeaf;
// Customization points. // Customization points.
public override SortMode SortMode public override SortMode SortMode
=> Penumbra.Config.SortMode; => Penumbra.Config.SortMode;
@ -199,7 +202,7 @@ public sealed partial class ModFileSystemSelector : FileSystemSelector< Mod2, Mo
{ {
if( _lastSelectedDirectory.Length > 0 ) if( _lastSelectedDirectory.Length > 0 )
{ {
SelectedLeaf = ( ModFileSystem.Leaf? )FileSystem.Root.GetAllDescendants( SortMode.Lexicographical ) base.SelectedLeaf = ( ModFileSystem.Leaf? )FileSystem.Root.GetAllDescendants( SortMode.Lexicographical )
.FirstOrDefault( l => l is ModFileSystem.Leaf m && m.Value.BasePath.FullName == _lastSelectedDirectory ); .FirstOrDefault( l => l is ModFileSystem.Leaf m && m.Value.BasePath.FullName == _lastSelectedDirectory );
_lastSelectedDirectory = string.Empty; _lastSelectedDirectory = string.Empty;
} }

View file

@ -11,8 +11,19 @@ public partial class ConfigWindow
{ {
private LowerString _changedItemFilter = LowerString.Empty; private LowerString _changedItemFilter = LowerString.Empty;
public void DrawChangedItemTab() // Draw a simple clipped table containing all changed items.
private void DrawChangedItemTab()
{ {
// Functions in here for less pollution.
bool FilterChangedItem( KeyValuePair< string, object? > item )
=> item.Key.Contains( _changedItemFilter.Lower, StringComparison.InvariantCultureIgnoreCase );
void DrawChangedItemColumn( KeyValuePair< string, object? > item )
{
ImGui.TableNextColumn();
DrawChangedItem( item.Key, item.Value, ImGui.GetStyle().ScrollbarSize );
}
using var tab = ImRaii.TabItem( "Changed Items" ); using var tab = ImRaii.TabItem( "Changed Items" );
if( !tab ) if( !tab )
{ {
@ -38,17 +49,8 @@ public partial class ConfigWindow
var items = Penumbra.CollectionManager.Default.ChangedItems; var items = Penumbra.CollectionManager.Default.ChangedItems;
var rest = _changedItemFilter.IsEmpty var rest = _changedItemFilter.IsEmpty
? ImGuiClip.ClippedDraw( items, skips, DrawChangedItem, items.Count ) ? ImGuiClip.ClippedDraw( items, skips, DrawChangedItemColumn, items.Count )
: ImGuiClip.FilteredClippedDraw( items, skips, FilterChangedItem, DrawChangedItem ); : ImGuiClip.FilteredClippedDraw( items, skips, FilterChangedItem, DrawChangedItemColumn );
ImGuiClip.DrawEndDummy( rest, height ); ImGuiClip.DrawEndDummy( rest, height );
} }
private bool FilterChangedItem( KeyValuePair< string, object? > item )
=> item.Key.Contains( _changedItemFilter.Lower, StringComparison.InvariantCultureIgnoreCase );
private void DrawChangedItem( KeyValuePair< string, object? > item )
{
ImGui.TableNextColumn();
DrawChangedItem( item.Key, item.Value, ImGui.GetStyle().ScrollbarSize );
}
} }

View file

@ -0,0 +1,288 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Dalamud.Interface;
using Dalamud.Interface.Components;
using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
using Penumbra.Collections;
using Penumbra.UI.Classes;
using Penumbra.Util;
namespace Penumbra.UI;
public partial class ConfigWindow
{
private partial class CollectionsTab
{
private const int InheritedCollectionHeight = 10;
private const string InheritanceDragDropLabel = "##InheritanceMove";
// Keep for reuse.
private readonly HashSet< ModCollection > _seenInheritedCollections = new(32);
// Execute changes only outside of loops.
private ModCollection? _newInheritance;
private ModCollection? _movedInheritance;
private (int, int)? _inheritanceAction;
private ModCollection? _newCurrentCollection;
// Draw the whole inheritance block.
private void DrawInheritanceBlock()
{
using var id = ImRaii.PushId( "##Inheritance" );
DrawCurrentCollectionInheritance();
DrawInheritanceTrashButton();
DrawNewInheritanceSelection();
DelayedActions();
}
// If an inherited collection is expanded,
// draw all its flattened, distinct children in order with a tree-line.
private void DrawInheritedChildren( ModCollection collection )
{
using var id = ImRaii.PushId( collection.Index );
using var indent = ImRaii.PushIndent();
// Get start point for the lines (top of the selector).
// Tree line stuff.
var lineStart = ImGui.GetCursorScreenPos();
var offsetX = -ImGui.GetStyle().IndentSpacing + ImGui.GetTreeNodeToLabelSpacing() / 2;
var drawList = ImGui.GetWindowDrawList();
var lineSize = Math.Max( 0, ImGui.GetStyle().IndentSpacing - 9 * ImGuiHelpers.GlobalScale );
lineStart.X += offsetX;
lineStart.Y -= 2 * ImGuiHelpers.GlobalScale;
var lineEnd = lineStart;
// Skip the collection itself.
foreach( var inheritance in collection.GetFlattenedInheritance().Skip( 1 ) )
{
// Draw the child, already seen collections are colored as conflicts.
using var color = ImRaii.PushColor( ImGuiCol.Text, ColorId.HandledConflictMod.Value(),
_seenInheritedCollections.Contains( inheritance ) );
_seenInheritedCollections.Add( inheritance );
ImRaii.TreeNode( inheritance.Name, ImGuiTreeNodeFlags.NoTreePushOnOpen | ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet );
var (minRect, maxRect) = ( ImGui.GetItemRectMin(), ImGui.GetItemRectMax() );
DrawInheritanceTreeClicks( inheritance, false );
// Tree line stuff.
if( minRect.X == 0 )
{
continue;
}
// Draw the notch and increase the line length.
var midPoint = ( minRect.Y + maxRect.Y ) / 2f - 1f;
drawList.AddLine( new Vector2( lineStart.X, midPoint ), new Vector2( lineStart.X + lineSize, midPoint ), Colors.MetaInfoText,
ImGuiHelpers.GlobalScale );
lineEnd.Y = midPoint;
}
// Finally, draw the folder line.
drawList.AddLine( lineStart, lineEnd, Colors.MetaInfoText, ImGuiHelpers.GlobalScale );
}
// Draw a single primary inherited collection.
private void DrawInheritance( ModCollection collection )
{
using var color = ImRaii.PushColor( ImGuiCol.Text, ColorId.HandledConflictMod.Value(),
_seenInheritedCollections.Contains( collection ) );
_seenInheritedCollections.Add( collection );
using var tree = ImRaii.TreeNode( collection.Name, ImGuiTreeNodeFlags.NoTreePushOnOpen );
color.Pop();
DrawInheritanceTreeClicks( collection, true );
DrawInheritanceDropSource( collection );
DrawInheritanceDropTarget( collection );
if( tree )
{
DrawInheritedChildren( collection );
}
else
{
// We still want to keep track of conflicts.
_seenInheritedCollections.UnionWith( collection.GetFlattenedInheritance() );
}
}
// Draw the list box containing the current inheritance information.
private void DrawCurrentCollectionInheritance()
{
using var list = ImRaii.ListBox( "##inheritanceList",
new Vector2( _window._inputTextWidth.X - ImGui.GetFrameHeight() - ImGui.GetStyle().ItemSpacing.X,
ImGui.GetTextLineHeightWithSpacing() * InheritedCollectionHeight ) );
if( !list )
{
return;
}
_seenInheritedCollections.Clear();
_seenInheritedCollections.Add( Penumbra.CollectionManager.Current );
foreach( var collection in Penumbra.CollectionManager.Current.Inheritance.ToList() )
{
DrawInheritance( collection );
}
}
// Draw a drag and drop button to delete.
private void DrawInheritanceTrashButton()
{
ImGui.SameLine();
var size = new Vector2( ImGui.GetFrameHeight(), ImGui.GetTextLineHeightWithSpacing() * InheritedCollectionHeight );
var buttonColor = ImGui.GetColorU32( ImGuiCol.Button );
// Prevent hovering from highlighting the button.
using var color = ImRaii.PushColor( ImGuiCol.ButtonActive, buttonColor )
.Push( ImGuiCol.ButtonHovered, buttonColor );
ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Trash.ToIconString(), size,
"Drag primary inheritance here to remove it from the list.", false, true );
using var target = ImRaii.DragDropTarget();
if( target.Success && ImGuiUtil.IsDropping( InheritanceDragDropLabel ) )
{
_inheritanceAction = ( Penumbra.CollectionManager.Current.Inheritance.IndexOf( _movedInheritance ), -1 );
}
}
// Set the current collection, or delete or move an inheritance if the action was triggered during iteration.
// Can not be done during iteration to keep collections unchanged.
private void DelayedActions()
{
if( _newCurrentCollection != null )
{
Penumbra.CollectionManager.SetCollection( _newCurrentCollection, ModCollection.Type.Current );
_newCurrentCollection = null;
}
if( _inheritanceAction == null )
{
return;
}
if( _inheritanceAction.Value.Item1 >= 0 )
{
if( _inheritanceAction.Value.Item2 == -1 )
{
Penumbra.CollectionManager.Current.RemoveInheritance( _inheritanceAction.Value.Item1 );
}
else
{
Penumbra.CollectionManager.Current.MoveInheritance( _inheritanceAction.Value.Item1, _inheritanceAction.Value.Item2 );
}
}
_inheritanceAction = null;
}
// Draw the selector to add new inheritances.
// The add button is only available if the selected collection can actually be added.
private void DrawNewInheritanceSelection()
{
DrawNewInheritanceCombo();
ImGui.SameLine();
var inheritance = Penumbra.CollectionManager.Current.CheckValidInheritance( _newInheritance );
var tt = inheritance switch
{
ModCollection.ValidInheritance.Empty => "No valid collection to inherit from selected.",
ModCollection.ValidInheritance.Valid => "Add a new inheritance to the collection.",
ModCollection.ValidInheritance.Self => "Can not inherit from itself.",
ModCollection.ValidInheritance.Contained => "Already inheriting from the selected collection.",
ModCollection.ValidInheritance.Circle => "Inheriting from selected collection would lead to cyclic inheritance.",
_ => string.Empty,
};
if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Plus.ToIconString(), ImGui.GetFrameHeight() * Vector2.One, tt,
inheritance != ModCollection.ValidInheritance.Valid, true )
&& Penumbra.CollectionManager.Current.AddInheritance( _newInheritance! ) )
{
_newInheritance = null;
}
if( inheritance != ModCollection.ValidInheritance.Valid )
{
_newInheritance = null;
}
ImGuiComponents.HelpMarker( tt );
}
// Draw the combo to select new potential inheritances.
// Only valid inheritances are drawn in the preview, or nothing if no inheritance is available.
private void DrawNewInheritanceCombo()
{
ImGui.SetNextItemWidth( _window._inputTextWidth.X - ImGui.GetFrameHeight() - ImGui.GetStyle().ItemSpacing.X );
_newInheritance ??= Penumbra.CollectionManager.FirstOrDefault( c
=> c != Penumbra.CollectionManager.Current && !Penumbra.CollectionManager.Current.Inheritance.Contains( c ) )
?? ModCollection.Empty;
using var combo = ImRaii.Combo( "##newInheritance", _newInheritance.Name );
if( !combo )
{
return;
}
foreach( var collection in Penumbra.CollectionManager
.Where( c => Penumbra.CollectionManager.Current.CheckValidInheritance( c ) == ModCollection.ValidInheritance.Valid ) )
{
if( ImGui.Selectable( collection.Name, _newInheritance == collection ) )
{
_newInheritance = collection;
}
}
}
// Move an inherited collection when dropped onto another.
// Move is delayed due to collection changes.
private void DrawInheritanceDropTarget( ModCollection collection )
{
using var target = ImRaii.DragDropTarget();
if( target.Success && ImGuiUtil.IsDropping( InheritanceDragDropLabel ) )
{
if( _movedInheritance != null )
{
var idx1 = Penumbra.CollectionManager.Current.Inheritance.IndexOf( _movedInheritance );
var idx2 = Penumbra.CollectionManager.Current.Inheritance.IndexOf( collection );
if( idx1 >= 0 && idx2 >= 0 )
{
_inheritanceAction = ( idx1, idx2 );
}
}
_movedInheritance = null;
}
}
// Move an inherited collection.
private void DrawInheritanceDropSource( ModCollection collection )
{
using var source = ImRaii.DragDropSource();
if( source )
{
ImGui.SetDragDropPayload( InheritanceDragDropLabel, IntPtr.Zero, 0 );
_movedInheritance = collection;
ImGui.Text( $"Moving {_movedInheritance?.Name ?? "Unknown"}..." );
}
}
// Ctrl + Right-Click -> Switch current collection to this (for all).
// Ctrl + Shift + Right-Click -> Delete this inheritance (only if withDelete).
// Deletion is delayed due to collection changes.
private void DrawInheritanceTreeClicks( ModCollection collection, bool withDelete )
{
if( ImGui.GetIO().KeyCtrl && ImGui.IsItemClicked( ImGuiMouseButton.Right ) )
{
if( withDelete && ImGui.GetIO().KeyShift )
{
_inheritanceAction = ( Penumbra.CollectionManager.Current.Inheritance.IndexOf( collection ), -1 );
}
else
{
_newCurrentCollection = collection;
}
}
ImGuiUtil.HoverTooltip( "Control + Right-Click to switch the current collection to this one."
+ ( withDelete ? "\nControl + Shift + Right-Click to remove this inheritance." : string.Empty ) );
}
}
}

View file

@ -11,9 +11,34 @@ namespace Penumbra.UI;
public partial class ConfigWindow public partial class ConfigWindow
{ {
// Encapsulate for less pollution.
private partial class CollectionsTab
{
private readonly ConfigWindow _window;
public CollectionsTab( ConfigWindow window )
=> _window = window;
public void Draw()
{
using var tab = ImRaii.TabItem( "Collections" );
if( !tab )
{
return;
}
DrawMainSelectors();
DrawCharacterCollectionSelectors();
}
// Input text fields.
private string _newCollectionName = string.Empty; private string _newCollectionName = string.Empty;
private bool _canAddCollection = false;
private string _newCharacterName = string.Empty; private string _newCharacterName = string.Empty;
// Create a new collection that is either empty or a duplicate of the current collection.
// Resets the new collection name.
private void CreateNewCollection( bool duplicate ) private void CreateNewCollection( bool duplicate )
{ {
if( Penumbra.CollectionManager.AddCollection( _newCollectionName, duplicate ? Penumbra.CollectionManager.Current : null ) ) if( Penumbra.CollectionManager.AddCollection( _newCollectionName, duplicate ? Penumbra.CollectionManager.Current : null ) )
@ -32,32 +57,39 @@ public partial class ConfigWindow
ImGuiUtil.HoverTooltip( "Remove all stored settings for mods not currently available and fix invalid settings.\nUse at own risk." ); ImGuiUtil.HoverTooltip( "Remove all stored settings for mods not currently available and fix invalid settings.\nUse at own risk." );
} }
// Draw the new collection input as well as its buttons.
private void DrawNewCollectionInput() private void DrawNewCollectionInput()
{ {
ImGui.SetNextItemWidth( _inputTextWidth.X ); // Input for new collection name. Also checks for validity when changed.
ImGui.InputTextWithHint( "##New Collection", "New Collection Name", ref _newCollectionName, 64 ); ImGui.SetNextItemWidth( _window._inputTextWidth.X );
if( ImGui.InputTextWithHint( "##New Collection", "New Collection Name", ref _newCollectionName, 64 ) )
{
_canAddCollection = Penumbra.CollectionManager.CanAddCollection( _newCollectionName, out _ );
}
ImGui.SameLine(); ImGui.SameLine();
ImGuiComponents.HelpMarker( ImGuiComponents.HelpMarker(
"A collection is a set of settings for your installed mods, including their enabled status, their priorities and their mod-specific configuration.\n" "A collection is a set of settings for your installed mods, including their enabled status, their priorities and their mod-specific configuration.\n"
+ "You can use multiple collections to quickly switch between sets of mods." ); + "You can use multiple collections to quickly switch between sets of mods." );
var createCondition = _newCollectionName.Length > 0; // Creation buttons.
var tt = createCondition ? string.Empty : "Please enter a name before creating a collection."; var tt = _canAddCollection ? string.Empty : "Please enter a unique name before creating a collection.";
if( ImGuiUtil.DrawDisabledButton( "Create New Empty Collection", Vector2.Zero, tt, !createCondition ) ) if( ImGuiUtil.DrawDisabledButton( "Create New Empty Collection", Vector2.Zero, tt, !_canAddCollection ) )
{ {
CreateNewCollection( false ); CreateNewCollection( false );
} }
ImGui.SameLine(); ImGui.SameLine();
if( ImGuiUtil.DrawDisabledButton( "Duplicate Current Collection", Vector2.Zero, tt, !createCondition ) ) if( ImGuiUtil.DrawDisabledButton( "Duplicate Current Collection", Vector2.Zero, tt, !_canAddCollection ) )
{ {
CreateNewCollection( true ); CreateNewCollection( true );
} }
// Deletion conditions.
var deleteCondition = Penumbra.CollectionManager.Current.Name != ModCollection.DefaultCollection; var deleteCondition = Penumbra.CollectionManager.Current.Name != ModCollection.DefaultCollection;
tt = deleteCondition ? string.Empty : "You can not delete the default collection."; tt = deleteCondition ? string.Empty : "You can not delete the default collection.";
ImGui.SameLine(); ImGui.SameLine();
if( ImGuiUtil.DrawDisabledButton( "Delete Current Collection", Vector2.Zero, tt, !deleteCondition ) ) if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Trash.ToIconString(), Vector2.Zero, tt, !deleteCondition, true ) )
{ {
Penumbra.CollectionManager.RemoveCollection( Penumbra.CollectionManager.Current ); Penumbra.CollectionManager.RemoveCollection( Penumbra.CollectionManager.Current );
} }
@ -69,9 +101,9 @@ public partial class ConfigWindow
} }
} }
public void DrawCurrentCollectionSelector() private void DrawCurrentCollectionSelector()
{ {
DrawCollectionSelector( "##current", _inputTextWidth.X, ModCollection.Type.Current, false, null ); DrawCollectionSelector( "##current", _window._inputTextWidth.X, ModCollection.Type.Current, false, null );
ImGui.SameLine(); ImGui.SameLine();
ImGuiUtil.LabeledHelpMarker( "Current Collection", ImGuiUtil.LabeledHelpMarker( "Current Collection",
"This collection will be modified when using the Installed Mods tab and making changes. It does not apply to anything by itself." ); "This collection will be modified when using the Installed Mods tab and making changes. It does not apply to anything by itself." );
@ -79,25 +111,26 @@ public partial class ConfigWindow
private void DrawDefaultCollectionSelector() private void DrawDefaultCollectionSelector()
{ {
DrawCollectionSelector( "##default", _inputTextWidth.X, ModCollection.Type.Default, true, null ); DrawCollectionSelector( "##default", _window._inputTextWidth.X, ModCollection.Type.Default, true, null );
ImGui.SameLine(); ImGui.SameLine();
ImGuiUtil.LabeledHelpMarker( "Default Collection", ImGuiUtil.LabeledHelpMarker( "Default Collection",
"Mods in the default collection are loaded for any character that is not explicitly named in the character collections below.\n" "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." ); + "They also take precedence before the forced collection." );
} }
// We do not check for valid character names.
private void DrawNewCharacterCollection() private void DrawNewCharacterCollection()
{ {
const string description = "Character Collections apply specifically to game objects of the given name.\n" const string description = "Character Collections apply specifically to game objects of the given name.\n"
+ "The default collection does not apply to any character that has a character collection specified.\n" + "The default collection does not apply to any character that has a character collection specified.\n"
+ "Certain actors - like the ones in cutscenes or preview windows - will try to use appropriate character collections.\n"; + "Certain actors - like the ones in cutscenes or preview windows - will try to use appropriate character collections.\n";
ImGui.SetNextItemWidth(_inputTextWidth.X ); ImGui.SetNextItemWidth( _window._inputTextWidth.X );
ImGui.InputTextWithHint( "##NewCharacter", "New Character Name", ref _newCharacterName, 32 ); ImGui.InputTextWithHint( "##NewCharacter", "New Character Name", ref _newCharacterName, 32 );
ImGui.SameLine(); ImGui.SameLine();
var disabled = _newCharacterName.Length == 0; var disabled = _newCharacterName.Length == 0;
var tt = disabled ? "Please enter a Character name before creating the collection.\n\n" + description : description; var tt = disabled ? "Please enter a Character name before creating the collection.\n\n" + description : description;
if( ImGuiUtil.DrawDisabledButton( "Create New Character Collection", Vector2.Zero, tt, disabled) ) if( ImGuiUtil.DrawDisabledButton( "Create New Character Collection", Vector2.Zero, tt, disabled ) )
{ {
Penumbra.CollectionManager.CreateCharacterCollection( _newCharacterName ); Penumbra.CollectionManager.CreateCharacterCollection( _newCharacterName );
_newCharacterName = string.Empty; _newCharacterName = string.Empty;
@ -108,109 +141,50 @@ public partial class ConfigWindow
{ {
using var child = ImRaii.Child( "##Collections", -Vector2.One, true ); using var child = ImRaii.Child( "##Collections", -Vector2.One, true );
if( !child ) if( !child )
{
return; return;
}
DrawDefaultCollectionSelector(); DrawDefaultCollectionSelector();
foreach( var name in Penumbra.CollectionManager.Characters.Keys.ToArray() ) foreach( var name in Penumbra.CollectionManager.Characters.Keys.ToArray() )
{ {
using var id = ImRaii.PushId( name ); using var id = ImRaii.PushId( name );
DrawCollectionSelector( string.Empty, _inputTextWidth.X, ModCollection.Type.Character, true, name ); DrawCollectionSelector( string.Empty, _window._inputTextWidth.X, ModCollection.Type.Character, true, name );
ImGui.SameLine(); ImGui.SameLine();
if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Trash.ToIconString(), Vector2.One * ImGui.GetFrameHeight(), string.Empty, false, true) ) if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Trash.ToIconString(), Vector2.One * ImGui.GetFrameHeight(), string.Empty,
false,
true ) )
{ {
Penumbra.CollectionManager.RemoveCharacterCollection( name ); Penumbra.CollectionManager.RemoveCharacterCollection( name );
} }
ImGui.SameLine(); ImGui.SameLine();
ImGui.AlignTextToFramePadding(); ImGui.AlignTextToFramePadding();
ImGui.Text( name ); ImGui.Text( name );
} }
DrawNewCharacterCollection(); DrawNewCharacterCollection();
} }
//private static void DrawInheritance( ModCollection collection )
// {
// ImGui.PushID( collection.Index );
// if( ImGui.TreeNodeEx( collection.Name, ImGuiTreeNodeFlags.DefaultOpen ) )
// {
// foreach( var inheritance in collection.Inheritance )
// {
// DrawInheritance( inheritance );
// }
// }
//
// ImGui.PopID();
// }
//
// private void DrawCurrentCollectionInheritance()
// {
// if( !ImGui.BeginListBox( "##inheritanceList",
// new Vector2( SettingsMenu.InputTextWidth, ImGui.GetTextLineHeightWithSpacing() * 10 ) ) )
// {
// return;
// }
//
// using var end = ImGuiRaii.DeferredEnd( ImGui.EndListBox );
// DrawInheritance( _collections[ _currentCollectionIndex + 1 ] );
// }
//
//private static int _newInheritanceIdx = 0;
//
//private void DrawNewInheritanceSelection()
//{
// ImGui.SetNextItemWidth( SettingsMenu.InputTextWidth - ImGui.GetFrameHeight() - ImGui.GetStyle().ItemSpacing.X );
// if( ImGui.BeginCombo( "##newInheritance", Penumbra.CollectionManager[ _newInheritanceIdx ].Name ) )
// {
// using var end = ImGuiRaii.DeferredEnd( ImGui.EndCombo );
// foreach( var collection in Penumbra.CollectionManager )
// {
// if( ImGui.Selectable( collection.Name, _newInheritanceIdx == collection.Index ) )
// {
// _newInheritanceIdx = collection.Index;
// }
// }
// }
//
// ImGui.SameLine();
// var valid = _newInheritanceIdx > ModCollection.Empty.Index
// && _collections[ _currentCollectionIndex + 1 ].Index != _newInheritanceIdx
// && _collections[ _currentCollectionIndex + 1 ].Inheritance.All( c => c.Index != _newInheritanceIdx );
// using var style = ImGuiRaii.PushStyle( ImGuiStyleVar.Alpha, 0.5f, !valid );
// using var font = ImGuiRaii.PushFont( UiBuilder.IconFont );
// if( ImGui.Button( $"{FontAwesomeIcon.Plus.ToIconString()}##newInheritanceAdd", ImGui.GetFrameHeight() * Vector2.One ) && valid )
// {
// _collections[ _currentCollectionIndex + 1 ].AddInheritance( Penumbra.CollectionManager[ _newInheritanceIdx ] );
// }
//
// style.Pop();
// font.Pop();
// ImGuiComponents.HelpMarker( "Add a new inheritance to the collection." );
//}
private void DrawMainSelectors() private void DrawMainSelectors()
{ {
using var main = ImRaii.Child( "##CollectionsMain", new Vector2( -1, ImGui.GetTextLineHeightWithSpacing() * 17 ), true ); var size = new Vector2( -1,
ImGui.GetTextLineHeightWithSpacing() * InheritedCollectionHeight
+ _window._defaultSpace.Y * 2
+ ImGui.GetFrameHeightWithSpacing() * 4
+ ImGui.GetStyle().ItemSpacing.Y * 6 );
using var main = ImRaii.Child( "##CollectionsMain", size, true );
if( !main ) if( !main )
{ {
return; return;
} }
DrawCurrentCollectionSelector(); DrawCurrentCollectionSelector();
ImGuiHelpers.ScaledDummy( 0, 10 ); ImGui.Dummy( _window._defaultSpace );
DrawNewCollectionInput(); DrawNewCollectionInput();
ImGui.Dummy( _window._defaultSpace );
DrawInheritanceBlock();
} }
public void DrawCollectionsTab()
{
using var tab = ImRaii.TabItem( "Collections" );
if( !tab )
{
return;
} }
DrawMainSelectors();
DrawCharacterCollectionSelectors();
}
} }

View file

@ -9,6 +9,7 @@ using ImGuiNET;
using OtterGui; using OtterGui;
using OtterGui.Raii; using OtterGui.Raii;
using Penumbra.Api; using Penumbra.Api;
using Penumbra.Interop.Loader;
using Penumbra.Interop.Structs; using Penumbra.Interop.Structs;
using CharacterUtility = Penumbra.Interop.CharacterUtility; using CharacterUtility = Penumbra.Interop.CharacterUtility;
@ -16,6 +17,13 @@ namespace Penumbra.UI;
public partial class ConfigWindow public partial class ConfigWindow
{ {
private class DebugTab
{
private readonly ConfigWindow _window;
public DebugTab( ConfigWindow window )
=> _window = window;
#if DEBUG #if DEBUG
private const string DebugVersionString = "(Debug)"; private const string DebugVersionString = "(Debug)";
private const bool DefaultVisibility = true; private const bool DefaultVisibility = true;
@ -26,7 +34,7 @@ public partial class ConfigWindow
public bool DebugTabVisible = DefaultVisibility; public bool DebugTabVisible = DefaultVisibility;
public void DrawDebugTab() public void Draw()
{ {
if( !DebugTabVisible ) if( !DebugTabVisible )
{ {
@ -55,6 +63,8 @@ public partial class ConfigWindow
ImGui.NewLine(); ImGui.NewLine();
DrawDebugResidentResources(); DrawDebugResidentResources();
ImGui.NewLine(); ImGui.NewLine();
DrawResourceProblems();
ImGui.NewLine();
DrawPlayerModelInfo(); DrawPlayerModelInfo();
ImGui.NewLine(); ImGui.NewLine();
DrawDebugTabIpc(); DrawDebugTabIpc();
@ -88,9 +98,9 @@ public partial class ConfigWindow
PrintValue( "Mod Manager BasePath IsRooted", Path.IsPathRooted( Penumbra.Config.ModDirectory ).ToString() ); PrintValue( "Mod Manager BasePath IsRooted", Path.IsPathRooted( Penumbra.Config.ModDirectory ).ToString() );
PrintValue( "Mod Manager BasePath Exists", Directory.Exists( manager.BasePath.FullName ).ToString() ); PrintValue( "Mod Manager BasePath Exists", Directory.Exists( manager.BasePath.FullName ).ToString() );
PrintValue( "Mod Manager Valid", manager.Valid.ToString() ); PrintValue( "Mod Manager Valid", manager.Valid.ToString() );
PrintValue( "Path Resolver Enabled", _penumbra.PathResolver.Enabled.ToString() ); PrintValue( "Path Resolver Enabled", _window._penumbra.PathResolver.Enabled.ToString() );
PrintValue( "Music Manager Streaming Disabled", ( !_penumbra.MusicManager.StreamingEnabled ).ToString() ); PrintValue( "Music Manager Streaming Disabled", ( !_window._penumbra.MusicManager.StreamingEnabled ).ToString() );
PrintValue( "Web Server Enabled", ( _penumbra.WebServer != null ).ToString() ); PrintValue( "Web Server Enabled", ( _window._penumbra.WebServer != null ).ToString() );
} }
// Draw all resources currently replaced by Penumbra and (if existing) the resources they replace. // Draw all resources currently replaced by Penumbra and (if existing) the resources they replace.
@ -150,7 +160,7 @@ public partial class ConfigWindow
using var table = ImRaii.Table( "###DrawObjectResolverTable", 5, ImGuiTableFlags.SizingFixedFit ); using var table = ImRaii.Table( "###DrawObjectResolverTable", 5, ImGuiTableFlags.SizingFixedFit );
if( table ) if( table )
{ {
foreach( var (ptr, (c, idx)) in _penumbra.PathResolver.DrawObjectToObject ) foreach( var (ptr, (c, idx)) in _window._penumbra.PathResolver.DrawObjectToObject )
{ {
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.Text( ptr.ToString( "X" ) ); ImGui.Text( ptr.ToString( "X" ) );
@ -174,7 +184,7 @@ public partial class ConfigWindow
using var table = ImRaii.Table( "###PathCollectionResolverTable", 2, ImGuiTableFlags.SizingFixedFit ); using var table = ImRaii.Table( "###PathCollectionResolverTable", 2, ImGuiTableFlags.SizingFixedFit );
if( table ) if( table )
{ {
foreach( var (path, collection) in _penumbra.PathResolver.PathCollections ) foreach( var (path, collection) in _window._penumbra.PathResolver.PathCollections )
{ {
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGuiNative.igTextUnformatted( path.Path, path.Path + path.Length ); ImGuiNative.igTextUnformatted( path.Path, path.Path + path.Length );
@ -333,6 +343,56 @@ public partial class ConfigWindow
} }
} }
// Draw resources with unusual reference count.
private static unsafe void DrawResourceProblems()
{
var header = ImGui.CollapsingHeader( "Resource Problems" );
ImGuiUtil.HoverTooltip( "Draw resources with unusually high reference count to detect overflows." );
if( !header )
{
return;
}
using var table = ImRaii.Table( "##ProblemsTable", 6, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit );
if( !table )
{
return;
}
ResourceLoader.IterateResources( ( _, r ) =>
{
if( r->RefCount < 10000 )
{
return;
}
ImGui.TableNextColumn();
ImGui.Text( r->Category.ToString() );
ImGui.TableNextColumn();
ImGui.Text( r->FileType.ToString( "X" ) );
ImGui.TableNextColumn();
ImGui.Text( r->Id.ToString( "X" ) );
ImGui.TableNextColumn();
ImGui.Text( ( ( ulong )r ).ToString( "X" ) );
ImGui.TableNextColumn();
ImGui.Text( r->RefCount.ToString() );
ImGui.TableNextColumn();
ref var name = ref r->FileName;
if( name.Capacity > 15 )
{
ImGuiNative.igTextUnformatted( name.BufferPtr, name.BufferPtr + name.Length );
}
else
{
fixed( byte* ptr = name.Buffer )
{
ImGuiNative.igTextUnformatted( ptr, ptr + name.Length );
}
}
} );
}
// Draw information about IPC options and availability. // Draw information about IPC options and availability.
private void DrawDebugTabIpc() private void DrawDebugTabIpc()
{ {
@ -341,7 +401,7 @@ public partial class ConfigWindow
return; return;
} }
var ipc = _penumbra.Ipc; var ipc = _window._penumbra.Ipc;
ImGui.Text( $"API Version: {ipc.Api.ApiVersion}" ); ImGui.Text( $"API Version: {ipc.Api.ApiVersion}" );
ImGui.Text( "Available subscriptions:" ); ImGui.Text( "Available subscriptions:" );
using var indent = ImRaii.PushIndent(); using var indent = ImRaii.PushIndent();
@ -399,4 +459,5 @@ public partial class ConfigWindow
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.Text( value ); ImGui.Text( value );
} }
}
} }

View file

@ -12,8 +12,10 @@ namespace Penumbra.UI;
public partial class ConfigWindow public partial class ConfigWindow
{ {
private class EffectiveTab
{
// Draw the effective tab if ShowAdvanced is on. // Draw the effective tab if ShowAdvanced is on.
public void DrawEffectiveChangesTab() public void Draw()
{ {
if( !Penumbra.Config.ShowAdvanced ) if( !Penumbra.Config.ShowAdvanced )
{ {
@ -56,13 +58,18 @@ public partial class ConfigWindow
private float _effectiveUnscaledArrowLength; private float _effectiveUnscaledArrowLength;
private float _effectiveArrowLength; private float _effectiveArrowLength;
// Filters
private LowerString _effectiveGamePathFilter = LowerString.Empty;
private LowerString _effectiveFilePathFilter = LowerString.Empty;
// Setup table sizes. // Setup table sizes.
private void SetupEffectiveSizes() private void SetupEffectiveSizes()
{ {
if( _effectiveUnscaledArrowLength == 0 ) if( _effectiveUnscaledArrowLength == 0 )
{ {
using var font = ImRaii.PushFont( UiBuilder.IconFont ); using var font = ImRaii.PushFont( UiBuilder.IconFont );
_effectiveUnscaledArrowLength = ImGui.CalcTextSize( FontAwesomeIcon.LongArrowAltLeft.ToIconString() ).X / ImGuiHelpers.GlobalScale; _effectiveUnscaledArrowLength =
ImGui.CalcTextSize( FontAwesomeIcon.LongArrowAltLeft.ToIconString() ).X / ImGuiHelpers.GlobalScale;
} }
_effectiveArrowLength = _effectiveUnscaledArrowLength * ImGuiHelpers.GlobalScale; _effectiveArrowLength = _effectiveUnscaledArrowLength * ImGuiHelpers.GlobalScale;
@ -70,10 +77,6 @@ public partial class ConfigWindow
_effectiveRightTextLength = ImGui.GetWindowSize().X - _effectiveArrowLength - _effectiveLeftTextLength; _effectiveRightTextLength = ImGui.GetWindowSize().X - _effectiveArrowLength - _effectiveLeftTextLength;
} }
// Filters
private LowerString _effectiveGamePathFilter = LowerString.Empty;
private LowerString _effectiveFilePathFilter = LowerString.Empty;
// Draw the header line for filters // Draw the header line for filters
private void DrawFilters() private void DrawFilters()
{ {
@ -212,4 +215,5 @@ public partial class ConfigWindow
return _effectiveFilePathFilter.Length == 0 || path.Contains( _effectiveFilePathFilter.Lower ); return _effectiveFilePathFilter.Length == 0 || path.Contains( _effectiveFilePathFilter.Lower );
} }
}
} }

View file

@ -43,8 +43,16 @@ public partial class ConfigWindow
if( _penumbra.Api.HasTooltip && ImGui.IsItemHovered() ) if( _penumbra.Api.HasTooltip && ImGui.IsItemHovered() )
{ {
// We can not be sure that any subscriber actually prints something in any case.
// Circumvent ugly blank tooltip with less-ugly useless tooltip.
using var tt = ImRaii.Tooltip(); using var tt = ImRaii.Tooltip();
using var group = ImRaii.Group();
_penumbra.Api.InvokeTooltip( data ); _penumbra.Api.InvokeTooltip( data );
group.Dispose();
if( ImGui.GetItemRectSize() == Vector2.Zero )
{
ImGui.Text( "No actions available." );
}
} }
if( data is Item it ) if( data is Item it )

File diff suppressed because it is too large Load diff

View file

@ -1,12 +1,386 @@
using System; using System;
using System.Diagnostics;
using System.Numerics; using System.Numerics;
using Dalamud.Interface;
using ImGuiNET; using ImGuiNET;
using OtterGui; using OtterGui;
using OtterGui.Raii; using OtterGui.Raii;
using OtterGui.Widgets;
using Penumbra.Collections; using Penumbra.Collections;
using Penumbra.Mods;
using Penumbra.UI.Classes;
namespace Penumbra.UI; namespace Penumbra.UI;
public partial class ConfigWindow
{
private class ModPanel
{
private readonly ConfigWindow _window;
private bool _valid;
private bool _emptySetting;
private bool _inherited;
private ModFileSystem.Leaf _leaf = null!;
private Mod2 _mod = null!;
private ModSettings2 _settings = null!;
private ModCollection _collection = null!;
private string _lastWebsite = string.Empty;
private bool _websiteValid;
private string? _currentSortOrderPath;
private int? _currentPriority;
public ModPanel( ConfigWindow window )
=> _window = window;
private void Init( ModFileSystemSelector selector )
{
_valid = selector.Selected != null;
if( !_valid )
{
return;
}
_leaf = selector.SelectedLeaf!;
_mod = selector.Selected!;
_settings = selector.SelectedSettings;
_collection = selector.SelectedSettingCollection;
_emptySetting = _settings == ModSettings2.Empty;
_inherited = _collection != Penumbra.CollectionManager.Current;
}
public void Draw( ModFileSystemSelector selector )
{
Init( selector );
if( !_valid )
{
return;
}
DrawInheritedWarning();
DrawHeaderLine();
DrawFilesystemPath();
DrawEnabledInput();
ImGui.SameLine();
DrawPriorityInput();
DrawRemoveSettings();
DrawTabBar();
}
private void DrawDescriptionTab()
{
if( _mod.Description.Length == 0 )
{
return;
}
using var tab = ImRaii.TabItem( "Description" );
if( !tab )
{
return;
}
using var child = ImRaii.Child( "##tab" );
if( !child )
{
return;
}
ImGui.TextWrapped( _mod.Description );
}
private void DrawSettingsTab()
{
if( !_mod.HasOptions )
{
return;
}
using var tab = ImRaii.TabItem( "Settings" );
if( !tab )
{
return;
}
using var child = ImRaii.Child( "##tab" );
if( !child )
{
return;
}
for( var idx = 0; idx < _mod.Groups.Count; ++idx )
{
var group = _mod.Groups[ idx ];
if( group.Type == SelectType.Single && group.IsOption )
{
using var id = ImRaii.PushId( idx );
var selectedOption = _emptySetting ? 0 : ( int )_settings.Settings[ idx ];
ImGui.SetNextItemWidth( _window._inputTextWidth.X );
using var combo = ImRaii.Combo( string.Empty, group[ selectedOption ].Name );
if( combo )
{
for( var idx2 = 0; idx2 < group.Count; ++idx2 )
{
if( ImGui.Selectable( group[ idx2 ].Name, idx2 == selectedOption ) )
{
Penumbra.CollectionManager.Current.SetModSetting( _mod.Index, idx, ( uint )idx2 );
}
}
}
combo.Dispose();
ImGui.SameLine();
if( group.Description.Length > 0 )
{
ImGuiUtil.LabeledHelpMarker( group.Name, group.Description );
}
else
{
ImGui.Text( group.Name );
}
}
}
// TODO add description
for( var idx = 0; idx < _mod.Groups.Count; ++idx )
{
var group = _mod.Groups[ idx ];
if( group.Type == SelectType.Multi && group.IsOption )
{
using var id = ImRaii.PushId( idx );
var flags = _emptySetting ? 0u : _settings.Settings[ idx ];
Widget.BeginFramedGroup( group.Name );
for( var idx2 = 0; idx2 < group.Count; ++idx2 )
{
var flag = 1u << idx2;
var setting = ( flags & flag ) != 0;
if( ImGui.Checkbox( group[ idx2 ].Name, ref setting ) )
{
flags = setting ? flags | flag : flags & ~flag;
Penumbra.CollectionManager.Current.SetModSetting( _mod.Index, idx, flags );
}
}
Widget.EndFramedGroup();
}
}
}
private void DrawChangedItemsTab()
{
if( _mod.ChangedItems.Count == 0 )
{
return;
}
using var tab = ImRaii.TabItem( "Changed Items" );
if( !tab )
{
return;
}
using var list = ImRaii.ListBox( "##changedItems", -Vector2.One );
if( !list )
{
return;
}
foreach( var (name, data) in _mod.ChangedItems )
{
_window.DrawChangedItem( name, data );
}
}
private void DrawTabBar()
{
using var tabBar = ImRaii.TabBar( "##ModTabs" );
if( !tabBar )
{
return;
}
DrawDescriptionTab();
DrawSettingsTab();
DrawChangedItemsTab();
}
private void DrawInheritedWarning()
{
if( _inherited )
{
using var color = ImRaii.PushColor( ImGuiCol.Button, Colors.PressEnterWarningBg );
var w = new Vector2( ImGui.GetContentRegionAvail().X, 0 );
if( ImGui.Button( $"These settings are inherited from {_collection.Name}.", w ) )
{
Penumbra.CollectionManager.Current.SetModInheritance( _mod.Index, false );
}
}
}
private void DrawPriorityInput()
{
var priority = _currentPriority ?? _settings.Priority;
ImGui.SetNextItemWidth( 50 * ImGuiHelpers.GlobalScale );
if( ImGui.InputInt( "Priority", ref priority, 0, 0 ) )
{
_currentPriority = priority;
}
if( ImGui.IsItemDeactivatedAfterEdit() && _currentPriority.HasValue )
{
if( _currentPriority != _settings.Priority )
{
Penumbra.CollectionManager.Current.SetModPriority( _mod.Index, _currentPriority.Value );
}
_currentPriority = null;
}
}
private void DrawRemoveSettings()
{
if( _inherited )
{
return;
}
ImGui.SameLine();
if( ImGui.Button( "Remove Settings" ) )
{
Penumbra.CollectionManager.Current.SetModInheritance( _mod.Index, true );
}
ImGuiUtil.HoverTooltip( "Remove current settings from this collection so that it can inherit them.\n"
+ "If no inherited collection has settings for this mod, it will be disabled." );
}
private void DrawEnabledInput()
{
var enabled = _settings.Enabled;
if( ImGui.Checkbox( "Enabled", ref enabled ) )
{
Penumbra.CollectionManager.Current.SetModState( _mod.Index, enabled );
}
}
private void DrawFilesystemPath()
{
var fullName = _leaf.FullName();
var path = _currentSortOrderPath ?? fullName;
ImGui.SetNextItemWidth( 300 * ImGuiHelpers.GlobalScale );
if( ImGui.InputText( "Sort Order", ref path, 256 ) )
{
_currentSortOrderPath = path;
}
if( ImGui.IsItemDeactivatedAfterEdit() && _currentSortOrderPath != null )
{
if( _currentSortOrderPath != fullName )
{
_window._penumbra.ModFileSystem.RenameAndMove( _leaf, _currentSortOrderPath );
}
_currentSortOrderPath = null;
}
}
// Draw the first info line for the mod panel,
// containing all basic meta information.
private void DrawHeaderLine()
{
DrawName();
ImGui.SameLine();
DrawVersion();
ImGui.SameLine();
DrawAuthor();
ImGui.SameLine();
DrawWebsite();
}
// Draw the mod name.
private void DrawName()
{
ImGui.Text( _mod.Name.Text );
}
// Draw the author of the mod, if any.
private void DrawAuthor()
{
using var group = ImRaii.Group();
ImGuiUtil.TextColored( Colors.MetaInfoText, "by" );
ImGui.SameLine();
ImGui.Text( _mod.Author.IsEmpty ? "Unknown" : _mod.Author.Text );
}
// Draw the mod version, if any.
private void DrawVersion()
{
if( _mod.Version.Length > 0 )
{
ImGui.Text( $"(Version {_mod.Version})" );
}
else
{
ImGui.Dummy( Vector2.Zero );
}
}
// Update the last seen website and check for validity.
private void UpdateWebsite( string newWebsite )
{
if( _lastWebsite == newWebsite )
{
return;
}
_lastWebsite = newWebsite;
_websiteValid = Uri.TryCreate( _lastWebsite, UriKind.Absolute, out var uriResult )
&& ( uriResult.Scheme == Uri.UriSchemeHttps || uriResult.Scheme == Uri.UriSchemeHttp );
}
// Draw the website source either as a button to open the site,
// if it is a valid http website, or as pure text.
private void DrawWebsite()
{
UpdateWebsite( _mod.Website );
if( _lastWebsite.Length == 0 )
{
ImGui.Dummy( Vector2.Zero );
return;
}
using var group = ImRaii.Group();
if( _websiteValid )
{
if( ImGui.Button( "Open Website" ) )
{
try
{
var process = new ProcessStartInfo( _lastWebsite )
{
UseShellExecute = true,
};
Process.Start( process );
}
catch
{
// ignored
}
}
ImGuiUtil.HoverTooltip( _lastWebsite );
}
else
{
ImGuiUtil.TextColored( Colors.MetaInfoText, "from" );
ImGui.SameLine();
ImGui.Text( _lastWebsite );
}
}
}
}
public partial class ConfigWindow public partial class ConfigWindow
{ {
public void DrawModsTab() public void DrawModsTab()
@ -22,7 +396,7 @@ public partial class ConfigWindow
return; return;
} }
Selector.Draw( GetModSelectorSize() ); _selector.Draw( GetModSelectorSize() );
ImGui.SameLine(); ImGui.SameLine();
using var group = ImRaii.Group(); using var group = ImRaii.Group();
DrawHeaderLine(); DrawHeaderLine();
@ -30,17 +404,10 @@ public partial class ConfigWindow
using var child = ImRaii.Child( "##ModsTabMod", -Vector2.One, true ); using var child = ImRaii.Child( "##ModsTabMod", -Vector2.One, true );
if( child ) if( child )
{ {
DrawModPanel(); _modPanel.Draw( _selector );
} }
} }
private void DrawModPanel()
{
if( Selector.Selected == null )
{
return;
}
}
// Draw the header line that can quick switch between collections. // Draw the header line that can quick switch between collections.
private void DrawHeaderLine() private void DrawHeaderLine()
@ -71,8 +438,8 @@ public partial class ConfigWindow
private void DrawInheritedCollectionButton( Vector2 width ) private void DrawInheritedCollectionButton( Vector2 width )
{ {
var noModSelected = Selector.Selected == null; var noModSelected = _selector.Selected == null;
var collection = Selector.SelectedSettingCollection; var collection = _selector.SelectedSettingCollection;
var modInherited = collection != Penumbra.CollectionManager.Current; var modInherited = collection != Penumbra.CollectionManager.Current;
var (name, tt) = ( noModSelected, modInherited ) switch var (name, tt) = ( noModSelected, modInherited ) switch
{ {

View file

@ -10,16 +10,27 @@ using OtterGui;
using OtterGui.Raii; using OtterGui.Raii;
using Penumbra.GameData.ByteString; using Penumbra.GameData.ByteString;
using Penumbra.Interop.Loader; using Penumbra.Interop.Loader;
using Penumbra.UI.Custom;
namespace Penumbra.UI; namespace Penumbra.UI;
public partial class ConfigWindow public partial class ConfigWindow
{ {
// Draw a tab to iterate over the main resource maps and see what resources are currently loaded. private class ResourceTab
public void DrawResourceManagerTab()
{ {
if( !DebugTabVisible ) private readonly ConfigWindow _window;
public ResourceTab( ConfigWindow window )
=> _window = window;
private float _hashColumnWidth;
private float _pathColumnWidth;
private float _refsColumnWidth;
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()
{
if( !_window._debugTab.DebugTabVisible )
{ {
return; return;
} }
@ -46,11 +57,6 @@ public partial class ConfigWindow
} }
} }
private float _hashColumnWidth;
private float _pathColumnWidth;
private float _refsColumnWidth;
private string _resourceManagerFilter = string.Empty;
private unsafe void DrawResourceMap( ResourceCategory category, uint ext, StdMap< uint, Pointer< ResourceHandle > >* map ) private unsafe void DrawResourceMap( ResourceCategory category, uint ext, StdMap< uint, Pointer< ResourceHandle > >* map )
{ {
if( map == null ) if( map == null )
@ -144,47 +150,5 @@ public partial class ConfigWindow
_pathColumnWidth = ImGui.GetWindowContentRegionWidth() - 300 * ImGuiHelpers.GlobalScale; _pathColumnWidth = ImGui.GetWindowContentRegionWidth() - 300 * ImGuiHelpers.GlobalScale;
_refsColumnWidth = 30 * ImGuiHelpers.GlobalScale; _refsColumnWidth = 30 * ImGuiHelpers.GlobalScale;
} }
}
//private static unsafe void DrawResourceProblems()
//{
// if( !ImGui.CollapsingHeader( "Resource Problems##ResourceManager" )
// || !ImGui.BeginTable( "##ProblemsTable", 6, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit ) )
// {
// return;
// }
//
// using var end = ImGuiRaii.DeferredEnd( ImGui.EndTable );
//
// ResourceLoader.IterateResources( ( _, r ) =>
// {
// if( r->RefCount < 10000 )
// {
// return;
// }
//
// ImGui.TableNextColumn();
// ImGui.Text( r->Category.ToString() );
// ImGui.TableNextColumn();
// ImGui.Text( r->FileType.ToString( "X" ) );
// ImGui.TableNextColumn();
// ImGui.Text( r->Id.ToString( "X" ) );
// ImGui.TableNextColumn();
// ImGui.Text( ( ( ulong )r ).ToString( "X" ) );
// ImGui.TableNextColumn();
// ImGui.Text( r->RefCount.ToString() );
// ImGui.TableNextColumn();
// ref var name = ref r->FileName;
// if( name.Capacity > 15 )
// {
// ImGuiNative.igTextUnformatted( name.BufferPtr, name.BufferPtr + name.Length );
// }
// else
// {
// fixed( byte* ptr = name.Buffer )
// {
// ImGuiNative.igTextUnformatted( ptr, ptr + name.Length );
// }
// }
// } );
//}
} }

View file

@ -1,5 +1,4 @@
using Dalamud.Interface; using Dalamud.Interface;
using Dalamud.Interface.Components;
using ImGuiNET; using ImGuiNET;
using OtterGui; using OtterGui;
using OtterGui.Raii; using OtterGui.Raii;
@ -10,6 +9,24 @@ namespace Penumbra.UI;
public partial class ConfigWindow public partial class ConfigWindow
{ {
private partial class SettingsTab
{
private void DrawAdvancedSettings()
{
if( !Penumbra.Config.ShowAdvanced || !ImGui.CollapsingHeader( "Advanced" ) )
{
return;
}
DrawRequestedResourceLogging();
DrawDisableSoundStreamingBox();
DrawEnableHttpApiBox();
DrawEnableDebugModeBox();
DrawEnableFullResourceLoggingBox();
DrawReloadResourceButton();
ImGui.NewLine();
}
// Sets the resource logger state when toggled, // Sets the resource logger state when toggled,
// and the filter when entered. // and the filter when entered.
private void DrawRequestedResourceLogging() private void DrawRequestedResourceLogging()
@ -17,7 +34,7 @@ public partial class ConfigWindow
var tmp = Penumbra.Config.EnableResourceLogging; var tmp = Penumbra.Config.EnableResourceLogging;
if( ImGui.Checkbox( "##resourceLogging", ref tmp ) ) if( ImGui.Checkbox( "##resourceLogging", ref tmp ) )
{ {
_penumbra.ResourceLogger.SetState( tmp ); _window._penumbra.ResourceLogger.SetState( tmp );
} }
ImGui.SameLine(); ImGui.SameLine();
@ -29,12 +46,13 @@ public partial class ConfigWindow
// Red borders if the string is not a valid regex. // Red borders if the string is not a valid regex.
var tmpString = Penumbra.Config.ResourceLoggingFilter; var tmpString = Penumbra.Config.ResourceLoggingFilter;
using var color = ImRaii.PushColor( ImGuiCol.Border, Colors.RegexWarningBorder, !_penumbra.ResourceLogger.ValidRegex ); using var color = ImRaii.PushColor( ImGuiCol.Border, Colors.RegexWarningBorder, !_window._penumbra.ResourceLogger.ValidRegex );
using var style = ImRaii.PushStyle( ImGuiStyleVar.FrameBorderSize, ImGuiHelpers.GlobalScale, !_penumbra.ResourceLogger.ValidRegex ); using var style = ImRaii.PushStyle( ImGuiStyleVar.FrameBorderSize, ImGuiHelpers.GlobalScale,
!_window._penumbra.ResourceLogger.ValidRegex );
ImGui.SetNextItemWidth( -1 ); ImGui.SetNextItemWidth( -1 );
if( ImGui.InputTextWithHint( "##ResourceLogFilter", "Filter...", ref tmpString, Utf8GamePath.MaxGamePathLength ) ) if( ImGui.InputTextWithHint( "##ResourceLogFilter", "Filter...", ref tmpString, Utf8GamePath.MaxGamePathLength ) )
{ {
_penumbra.ResourceLogger.SetFilter( tmpString ); _window._penumbra.ResourceLogger.SetFilter( tmpString );
} }
} }
@ -49,11 +67,11 @@ public partial class ConfigWindow
Penumbra.Config.Save(); Penumbra.Config.Save();
if( tmp ) if( tmp )
{ {
_penumbra.MusicManager.DisableStreaming(); _window._penumbra.MusicManager.DisableStreaming();
} }
else else
{ {
_penumbra.MusicManager.EnableStreaming(); _window._penumbra.MusicManager.EnableStreaming();
} }
Penumbra.ModManager.DiscoverMods(); Penumbra.ModManager.DiscoverMods();
@ -76,11 +94,11 @@ public partial class ConfigWindow
{ {
if( http ) if( http )
{ {
_penumbra.CreateWebServer(); _window._penumbra.CreateWebServer();
} }
else else
{ {
_penumbra.ShutdownWebServer(); _window._penumbra.ShutdownWebServer();
} }
Penumbra.Config.EnableHttpApi = http; Penumbra.Config.EnableHttpApi = http;
@ -150,20 +168,5 @@ public partial class ConfigWindow
ImGuiUtil.HoverTooltip( "Reload some specific files that the game keeps in memory at all times.\n" ImGuiUtil.HoverTooltip( "Reload some specific files that the game keeps in memory at all times.\n"
+ "You usually should not need to do this." ); + "You usually should not need to do this." );
} }
private void DrawAdvancedSettings()
{
if( !Penumbra.Config.ShowAdvanced || !ImGui.CollapsingHeader( "Advanced" ) )
{
return;
}
DrawRequestedResourceLogging();
DrawDisableSoundStreamingBox();
DrawEnableHttpApiBox();
DrawEnableDebugModeBox();
DrawEnableFullResourceLoggingBox();
DrawReloadResourceButton();
ImGui.NewLine();
} }
} }

View file

@ -8,73 +8,8 @@ namespace Penumbra.UI;
public partial class ConfigWindow public partial class ConfigWindow
{ {
// Store separately to use IsItemDeactivatedAfterEdit. private partial class SettingsTab
private float _absoluteSelectorSize = Penumbra.Config.ModSelectorAbsoluteSize;
private int _relativeSelectorSize = Penumbra.Config.ModSelectorScaledSize;
// Different supported sort modes as a combo.
private void DrawFolderSortType()
{ {
var sortMode = Penumbra.Config.SortMode;
ImGui.SetNextItemWidth( _inputTextWidth.X );
using var combo = ImRaii.Combo( "##sortMode", sortMode.Data().Name );
if( combo )
{
foreach( var val in Enum.GetValues< SortMode >() )
{
var (name, desc) = val.Data();
if( ImGui.Selectable( name, val == sortMode ) && val != sortMode )
{
Penumbra.Config.SortMode = val;
Selector.SetFilterDirty();
Penumbra.Config.Save();
}
ImGuiUtil.HoverTooltip( desc );
}
}
combo.Dispose();
ImGuiUtil.LabeledHelpMarker( "Sort Mode", "Choose the sort mode for the mod selector in the mods tab." );
}
private void DrawAbsoluteSizeSelector()
{
if( ImGuiUtil.DragFloat( "##absoluteSize", ref _absoluteSelectorSize, _inputTextWidth.X, 1,
Configuration.Constants.MinAbsoluteSize, Configuration.Constants.MaxAbsoluteSize, "%.0f" )
&& _absoluteSelectorSize != Penumbra.Config.ModSelectorAbsoluteSize )
{
Penumbra.Config.ModSelectorAbsoluteSize = _absoluteSelectorSize;
Penumbra.Config.Save();
}
ImGui.SameLine();
ImGuiUtil.LabeledHelpMarker( "Mod Selector Absolute Size", "The minimal absolute size of the mod selector in the mod tab in pixels." );
}
private void DrawRelativeSizeSelector()
{
var scaleModSelector = Penumbra.Config.ScaleModSelector;
if( ImGui.Checkbox( "Scale Mod Selector With Window Size", ref scaleModSelector ) )
{
Penumbra.Config.ScaleModSelector = scaleModSelector;
Penumbra.Config.Save();
}
ImGui.SameLine();
if( ImGuiUtil.DragInt( "##relativeSize", ref _relativeSelectorSize, _inputTextWidth.X - ImGui.GetCursorPosX(), 0.1f,
Configuration.Constants.MinScaledSize, Configuration.Constants.MaxScaledSize, "%i%%" )
&& _relativeSelectorSize != Penumbra.Config.ModSelectorScaledSize )
{
Penumbra.Config.ModSelectorScaledSize = _relativeSelectorSize;
Penumbra.Config.Save();
}
ImGui.SameLine();
ImGuiUtil.LabeledHelpMarker( "Mod Selector Relative Size",
"Instead of keeping the mod-selector in the Installed Mods tab a fixed width, this will let it scale with the total size of the Penumbra window." );
}
private void DrawModSelectorSettings() private void DrawModSelectorSettings()
{ {
if( !ImGui.CollapsingHeader( "Mod Selector" ) ) if( !ImGui.CollapsingHeader( "Mod Selector" ) )
@ -88,4 +23,75 @@ public partial class ConfigWindow
ImGui.NewLine(); ImGui.NewLine();
} }
// Store separately to use IsItemDeactivatedAfterEdit.
private float _absoluteSelectorSize = Penumbra.Config.ModSelectorAbsoluteSize;
private int _relativeSelectorSize = Penumbra.Config.ModSelectorScaledSize;
// Different supported sort modes as a combo.
private void DrawFolderSortType()
{
var sortMode = Penumbra.Config.SortMode;
ImGui.SetNextItemWidth( _window._inputTextWidth.X );
using var combo = ImRaii.Combo( "##sortMode", sortMode.Data().Name );
if( combo )
{
foreach( var val in Enum.GetValues< SortMode >() )
{
var (name, desc) = val.Data();
if( ImGui.Selectable( name, val == sortMode ) && val != sortMode )
{
Penumbra.Config.SortMode = val;
_window._selector.SetFilterDirty();
Penumbra.Config.Save();
}
ImGuiUtil.HoverTooltip( desc );
}
}
combo.Dispose();
ImGuiUtil.LabeledHelpMarker( "Sort Mode", "Choose the sort mode for the mod selector in the mods tab." );
}
// Absolute size in pixels.
private void DrawAbsoluteSizeSelector()
{
if( ImGuiUtil.DragFloat( "##absoluteSize", ref _absoluteSelectorSize, _window._inputTextWidth.X, 1,
Configuration.Constants.MinAbsoluteSize, Configuration.Constants.MaxAbsoluteSize, "%.0f" )
&& _absoluteSelectorSize != Penumbra.Config.ModSelectorAbsoluteSize )
{
Penumbra.Config.ModSelectorAbsoluteSize = _absoluteSelectorSize;
Penumbra.Config.Save();
}
ImGui.SameLine();
ImGuiUtil.LabeledHelpMarker( "Mod Selector Absolute Size",
"The minimal absolute size of the mod selector in the mod tab in pixels." );
}
// Relative size toggle and percentage.
private void DrawRelativeSizeSelector()
{
var scaleModSelector = Penumbra.Config.ScaleModSelector;
if( ImGui.Checkbox( "Scale Mod Selector With Window Size", ref scaleModSelector ) )
{
Penumbra.Config.ScaleModSelector = scaleModSelector;
Penumbra.Config.Save();
}
ImGui.SameLine();
if( ImGuiUtil.DragInt( "##relativeSize", ref _relativeSelectorSize, _window._inputTextWidth.X - ImGui.GetCursorPosX(), 0.1f,
Configuration.Constants.MinScaledSize, Configuration.Constants.MaxScaledSize, "%i%%" )
&& _relativeSelectorSize != Penumbra.Config.ModSelectorScaledSize )
{
Penumbra.Config.ModSelectorScaledSize = _relativeSelectorSize;
Penumbra.Config.Save();
}
ImGui.SameLine();
ImGuiUtil.LabeledHelpMarker( "Mod Selector Relative Size",
"Instead of keeping the mod-selector in the Installed Mods tab a fixed width, this will let it scale with the total size of the Penumbra window." );
}
}
} }

View file

@ -4,20 +4,50 @@ using System.IO;
using System.Numerics; using System.Numerics;
using Dalamud.Interface; using Dalamud.Interface;
using Dalamud.Interface.ImGuiFileDialog; using Dalamud.Interface.ImGuiFileDialog;
using Dalamud.Interface.Components;
using Dalamud.Logging;
using ImGuiNET; using ImGuiNET;
using OtterGui; using OtterGui;
using OtterGui.Raii; using OtterGui.Raii;
using OtterGui.Widgets; using OtterGui.Widgets;
using Penumbra.UI.Classes; using Penumbra.UI.Classes;
using Penumbra.UI.Custom;
namespace Penumbra.UI; namespace Penumbra.UI;
public partial class ConfigWindow public partial class ConfigWindow
{ {
private string _settingsNewModDirectory = string.Empty; private partial class SettingsTab
{
private readonly ConfigWindow _window;
public SettingsTab( ConfigWindow window )
=> _window = window;
public void Draw()
{
using var tab = ImRaii.TabItem( "Settings" );
if( !tab )
{
return;
}
using var child = ImRaii.Child( "##SettingsTab", -Vector2.One, false );
if( !child )
{
return;
}
DrawEnabledBox();
DrawShowAdvancedBox();
ImGui.NewLine();
DrawRootFolder();
DrawRediscoverButton();
ImGui.NewLine();
DrawModSelectorSettings();
DrawColorSettings();
DrawAdvancedSettings();
}
private string? _settingsNewModDirectory;
private readonly FileDialogManager _dialogManager = new(); private readonly FileDialogManager _dialogManager = new();
private bool _dialogOpen; private bool _dialogOpen;
@ -40,6 +70,7 @@ public partial class ConfigWindow
} }
else else
{ {
// TODO
//_dialogManager.OpenFolderDialog( "Choose Mod Directory", ( b, s ) => //_dialogManager.OpenFolderDialog( "Choose Mod Directory", ( b, s ) =>
//{ //{
// _newModDirectory = b ? s : _newModDirectory; // _newModDirectory = b ? s : _newModDirectory;
@ -68,15 +99,11 @@ public partial class ConfigWindow
private void DrawRootFolder() private void DrawRootFolder()
{ {
// Initialize first time. _settingsNewModDirectory ??= Penumbra.Config.ModDirectory;
if( _settingsNewModDirectory.Length == 0 )
{
_settingsNewModDirectory = Penumbra.Config.ModDirectory;
}
var spacing = 3 * ImGuiHelpers.GlobalScale; var spacing = 3 * ImGuiHelpers.GlobalScale;
using var group = ImRaii.Group(); using var group = ImRaii.Group();
ImGui.SetNextItemWidth( _inputTextWidth.X - spacing - ImGui.GetFrameHeight() ); ImGui.SetNextItemWidth( _window._inputTextWidth.X - spacing - ImGui.GetFrameHeight() );
var save = ImGui.InputText( "##rootDirectory", ref _settingsNewModDirectory, 255, ImGuiInputTextFlags.EnterReturnsTrue ); var save = ImGui.InputText( "##rootDirectory", ref _settingsNewModDirectory, 255, ImGuiInputTextFlags.EnterReturnsTrue );
using var style = ImRaii.PushStyle( ImGuiStyleVar.ItemSpacing, new Vector2( spacing, 0 ) ); using var style = ImRaii.PushStyle( ImGuiStyleVar.ItemSpacing, new Vector2( spacing, 0 ) );
ImGui.SameLine(); ImGui.SameLine();
@ -123,7 +150,7 @@ public partial class ConfigWindow
var enabled = Penumbra.Config.EnableMods; var enabled = Penumbra.Config.EnableMods;
if( ImGui.Checkbox( "Enable Mods", ref enabled ) ) if( ImGui.Checkbox( "Enable Mods", ref enabled ) )
{ {
_penumbra.SetEnabled( enabled ); _window._penumbra.SetEnabled( enabled );
} }
} }
@ -160,31 +187,5 @@ public partial class ConfigWindow
ImGui.NewLine(); ImGui.NewLine();
} }
public void DrawSettingsTab()
{
using var tab = ImRaii.TabItem( "Settings" );
if( !tab )
{
return;
}
using var child = ImRaii.Child( "##SettingsTab", -Vector2.One, false );
if( !child )
{
return;
}
DrawEnabledBox();
DrawShowAdvancedBox();
ImGui.NewLine();
DrawRootFolder();
DrawRediscoverButton();
ImGui.NewLine();
DrawModSelectorSettings();
DrawColorSettings();
DrawAdvancedSettings();
} }
} }

View file

@ -14,13 +14,26 @@ namespace Penumbra.UI;
public sealed partial class ConfigWindow : Window, IDisposable public sealed partial class ConfigWindow : Window, IDisposable
{ {
private readonly Penumbra _penumbra; private readonly Penumbra _penumbra;
public readonly ModFileSystemSelector Selector; 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;
public ConfigWindow( Penumbra penumbra ) public ConfigWindow( Penumbra penumbra )
: base( GetLabel() ) : base( GetLabel() )
{ {
_penumbra = penumbra; _penumbra = penumbra;
Selector = new ModFileSystemSelector( _penumbra.ModFileSystem, new HashSet< Mod2 >() ); // TODO _settingsTab = new SettingsTab( this );
_selector = new ModFileSystemSelector( _penumbra.ModFileSystem, new HashSet< Mod2 >() ); // TODO
_modPanel = new ModPanel( this );
_collectionsTab = new CollectionsTab( this );
_effectiveTab = new EffectiveTab();
_debugTab = new DebugTab( this );
_resourceTab = new ResourceTab( this );
Dalamud.PluginInterface.UiBuilder.DisableGposeUiHide = true; Dalamud.PluginInterface.UiBuilder.DisableGposeUiHide = true;
Dalamud.PluginInterface.UiBuilder.DisableCutsceneUiHide = true; Dalamud.PluginInterface.UiBuilder.DisableCutsceneUiHide = true;
Dalamud.PluginInterface.UiBuilder.DisableUserUiHide = true; Dalamud.PluginInterface.UiBuilder.DisableUserUiHide = true;
@ -36,18 +49,18 @@ public sealed partial class ConfigWindow : Window, IDisposable
{ {
using var bar = ImRaii.TabBar( string.Empty, ImGuiTabBarFlags.NoTooltip ); using var bar = ImRaii.TabBar( string.Empty, ImGuiTabBarFlags.NoTooltip );
SetupSizes(); SetupSizes();
DrawSettingsTab(); _settingsTab.Draw();
DrawModsTab(); DrawModsTab();
DrawCollectionsTab(); _collectionsTab.Draw();
DrawChangedItemTab(); DrawChangedItemTab();
DrawEffectiveChangesTab(); _effectiveTab.Draw();
DrawDebugTab(); _debugTab.Draw();
DrawResourceManagerTab(); _resourceTab.Draw();
} }
public void Dispose() public void Dispose()
{ {
Selector.Dispose(); _selector.Dispose();
} }
private static string GetLabel() private static string GetLabel()
@ -55,10 +68,12 @@ public sealed partial class ConfigWindow : Window, IDisposable
? "Penumbra###PenumbraConfigWindow" ? "Penumbra###PenumbraConfigWindow"
: $"Penumbra v{Penumbra.Version}###PenumbraConfigWindow"; : $"Penumbra v{Penumbra.Version}###PenumbraConfigWindow";
private Vector2 _defaultSpace;
private Vector2 _inputTextWidth; private Vector2 _inputTextWidth;
private void SetupSizes() private void SetupSizes()
{ {
_defaultSpace = new Vector2( 0, 10 * ImGuiHelpers.GlobalScale );
_inputTextWidth = new Vector2( 350f * ImGuiHelpers.GlobalScale, 0 ); _inputTextWidth = new Vector2( 350f * ImGuiHelpers.GlobalScale, 0 );
} }
} }