Current state.

This commit is contained in:
Ottermandias 2025-09-27 12:43:48 +02:00
parent 924c9b9f7e
commit a805e9c56d
15 changed files with 345 additions and 314 deletions

2
Luna

@ -1 +1 @@
Subproject commit 15636cda90725e6af7071512cf9873dd273570fc
Subproject commit 0e9fdb2bbfb02d76468a3f968b07289664d90808

@ -1 +1 @@
Subproject commit dd14131793e5ae47cc8e9232f46469216017b5aa
Subproject commit 648b6fc2ce600a95ab2b2ced27e1639af2b04502

View file

@ -1,6 +1,7 @@
using Luna;
using Penumbra.Collections;
using Penumbra.Collections.Manager;
using Penumbra.UI.CollectionTab;
namespace Penumbra.Communication;
@ -42,6 +43,9 @@ public sealed class CollectionChange(Logger log)
/// <seealso cref="Mods.ModSelection.OnCollectionChange"/>
ModSelection = 10,
/// <seealso cref="CollectionCombo.OnCollectionChanged"/>
CollectionCombo = 15,
}
/// <summary> The arguments for a collection change event. </summary>

View file

@ -4,7 +4,6 @@ using Newtonsoft.Json;
using Penumbra.Api.Enums;
using Penumbra.Communication;
using Penumbra.Enums;
using Penumbra.Mods;
using Penumbra.Mods.Manager;
using Penumbra.Services;
using Penumbra.UI;

View file

@ -6,7 +6,7 @@ using Penumbra.Util;
namespace Penumbra.Mods.Manager;
public class ModCacheManager : IDisposable, Luna.IService
public class ModCacheManager : IDisposable, Luna.IRequiredService
{
private readonly Configuration _config;
private readonly CommunicatorService _communicator;

View file

@ -1,5 +1,4 @@
using Dalamud.Plugin;
using Dalamud.Bindings.ImGui;
using OtterGui;
using Penumbra.Api;
using Penumbra.Api.Enums;
@ -17,6 +16,7 @@ using OtterGui.Tasks;
using Penumbra.UI;
using ResidentResourceManager = Penumbra.Interop.Services.ResidentResourceManager;
using Dalamud.Plugin.Services;
using ImSharp;
using Lumina.Excel.Sheets;
using Luna;
using Penumbra.Communication;
@ -24,9 +24,9 @@ using Penumbra.GameData.Data;
using Penumbra.Interop;
using Penumbra.Interop.Hooks;
using Penumbra.Interop.Hooks.PostProcessing;
using Penumbra.Interop.Hooks.ResourceLoading;
using DynamisIpc = OtterGui.Services.DynamisIpc;
using MessageService = Penumbra.Services.MessageService;
using MouseButton = Penumbra.Api.Enums.MouseButton;
namespace Penumbra;
@ -72,20 +72,17 @@ public class Penumbra : IDalamudPlugin
: "Unknown";
Log.Information(
$"Loading Penumbra Version {_validityChecker.Version}, Commit #{_validityChecker.CommitHash} with Waiting For Plugins: {startup}...");
_services.GetService<BackupService>(); // Initialize because not required anywhere else.
_config = _services.GetService<Configuration>();
_characterUtility = _services.GetService<CharacterUtility>();
_tempMods = _services.GetService<TempModManager>();
_residentResources = _services.GetService<ResidentResourceManager>();
_services.GetService<ResourceManagerService>(); // Initialize because not required anywhere else.
_services.GetService<BackupService>(); // Initialize early to create backups.
_config = _services.GetService<Configuration>();
_characterUtility = _services.GetService<CharacterUtility>();
_tempMods = _services.GetService<TempModManager>();
_residentResources = _services.GetService<ResidentResourceManager>();
_modManager = _services.GetService<ModManager>();
_collectionManager = _services.GetService<CollectionManager>();
_tempCollections = _services.GetService<TempCollectionManager>();
_redrawService = _services.GetService<RedrawService>();
_communicatorService = _services.GetService<CommunicatorService>();
_gameData = _services.GetService<IDataManager>();
_services.GetService<ResourceService>(); // Initialize because not required anywhere else.
_services.GetService<ModCacheManager>(); // Initialize because not required anywhere else.
_collectionManager.Caches.CreateNecessaryCaches();
_services.GetService<PathResolver>();
@ -118,13 +115,13 @@ public class Penumbra : IDalamudPlugin
{
_services.GetService<IpcProviders>();
var itemSheet = _services.GetService<IDataManager>().GetExcelSheet<Item>();
_communicatorService.ChangedItemHover.Subscribe((in ChangedItemHover.Arguments args) =>
_communicatorService.ChangedItemHover.Subscribe((in args) =>
{
if (args.Data is IdentifiedItem { Item.Id.IsItem: true })
ImGui.TextUnformatted("Left Click to create an item link in chat.");
Im.Text("Left Click to create an item link in chat."u8);
}, ChangedItemHover.Priority.Link);
_communicatorService.ChangedItemClick.Subscribe((in ChangedItemClick.Arguments args) =>
_communicatorService.ChangedItemClick.Subscribe((in args) =>
{
if (args is { Button: MouseButton.Left, Data: IdentifiedItem item } && itemSheet.GetRow(item.Item.ItemId.Id) is { } i)
Messager.LinkItem(i);
@ -255,10 +252,6 @@ public class Penumbra : IDalamudPlugin
sb.Append(
$"> **`#Temp Mods: `** {_tempMods.Mods.Sum(kvp => kvp.Value.Count) + _tempMods.ModsForAllCollections.Count}\n");
void PrintCollection(ModCollection c, CollectionCache _)
=> sb.Append(
$"> **`Collection {c.Identity.AnonymizedName + ':',-18}`** Inheritances: `{c.Inheritance.DirectlyInheritsFrom.Count,3}`, Enabled Mods: `{c.ActualSettings.Count(s => s is { Enabled: true }),4}`, Conflicts: `{c.AllConflicts.SelectMany(x => x).Sum(x => x is { HasPriority: true, Solved: true } ? x.Conflicts.Count : 0),5}/{c.AllConflicts.SelectMany(x => x).Sum(x => x.HasPriority ? x.Conflicts.Count : 0),5}`\n");
sb.AppendLine("**Collections**");
sb.Append($"> **`#Collections: `** {_collectionManager.Storage.Count - 1}\n");
sb.Append($"> **`#Temp Collections: `** {_tempCollections.Count}\n");
@ -280,6 +273,10 @@ public class Penumbra : IDalamudPlugin
PrintCollection(collection, collection._cache!);
return sb.ToString();
void PrintCollection(ModCollection c, CollectionCache _)
=> sb.Append(
$"> **`Collection {c.Identity.AnonymizedName + ':',-18}`** Inheritances: `{c.Inheritance.DirectlyInheritsFrom.Count,3}`, Enabled Mods: `{c.ActualSettings.Count(s => s is { Enabled: true }),4}`, Conflicts: `{c.AllConflicts.SelectMany(x => x).Sum(x => x is { HasPriority: true, Solved: true } ? x.Conflicts.Count : 0),5}/{c.AllConflicts.SelectMany(x => x).Sum(x => x.HasPriority ? x.Conflicts.Count : 0),5}`\n");
}
private static string CollectLocaleEnvironmentVariables()

View file

@ -184,7 +184,7 @@ public partial class ModEditWindow
registry.CurrentUsage == registry.SubModUsage.Count ? ColorId.NewMod : ColorId.InheritedMod;
using (ImRaii.PushColor(ImGuiCol.Text, color.Value()))
{
if (UiHelpers.Selectable(registry.RelPath.Path, selected))
if (Im.Selectable(registry.RelPath.Path.Span, selected))
{
if (selected)
_selectedFiles.Remove(registry);

View file

@ -1,5 +1,6 @@
using Dalamud.Interface;
using Dalamud.Bindings.ImGui;
using ImSharp;
using OtterGui;
using OtterGui.Raii;
using OtterGui.Text;
@ -11,25 +12,16 @@ using Penumbra.UI.CollectionTab;
namespace Penumbra.UI.Classes;
public class CollectionSelectHeader : Luna.IUiService
public class CollectionSelectHeader(
CollectionManager collectionManager,
TutorialService tutorial,
ModSelection selection,
CollectionResolver resolver,
Configuration config,
CollectionCombo combo)
: Luna.IUiService
{
private readonly CollectionCombo _collectionCombo;
private readonly ActiveCollections _activeCollections;
private readonly TutorialService _tutorial;
private readonly ModSelection _selection;
private readonly CollectionResolver _resolver;
private readonly Configuration _config;
public CollectionSelectHeader(CollectionManager collectionManager, TutorialService tutorial, ModSelection selection,
CollectionResolver resolver, Configuration config)
{
_tutorial = tutorial;
_selection = selection;
_resolver = resolver;
_config = config;
_activeCollections = collectionManager.Active;
_collectionCombo = new CollectionCombo(collectionManager, () => collectionManager.Storage.OrderBy(c => c.Identity.Name).ToList());
}
private readonly ActiveCollections _activeCollections = collectionManager.Active;
/// <summary> Draw the header line that can quick switch between collections. </summary>
public void Draw(bool spacing)
@ -47,10 +39,10 @@ public class CollectionSelectHeader : Luna.IUiService
DrawCollectionButton(buttonSize, GetPlayerCollectionInfo(), 3);
DrawCollectionButton(buttonSize, GetInheritedCollectionInfo(), 4);
_collectionCombo.Draw("##collectionSelector", comboWidth, ColorId.SelectedCollection.Value());
combo.Draw("##collectionSelector"u8, comboWidth, ColorId.SelectedCollection.Value());
}
_tutorial.OpenTutorial(BasicTutorialSteps.CollectionSelectors);
tutorial.OpenTutorial(BasicTutorialSteps.CollectionSelectors);
if (!_activeCollections.CurrentCollectionInUse)
ImGuiUtil.DrawTextButton("The currently selected collection is not used in any way.", -Vector2.UnitX, Colors.PressEnterWarningBg);
@ -58,26 +50,26 @@ public class CollectionSelectHeader : Luna.IUiService
private void DrawTemporaryCheckbox()
{
var hold = _config.IncognitoModifier.IsActive();
var hold = config.IncognitoModifier.IsActive();
using (ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, ImUtf8.GlobalScale))
{
var tint = _config.DefaultTemporaryMode
var tint = config.DefaultTemporaryMode
? ImGuiCol.Text.Tinted(ColorId.TemporaryModSettingsTint)
: ImGui.GetColorU32(ImGuiCol.TextDisabled);
using var color = ImRaii.PushColor(ImGuiCol.ButtonHovered, ImGui.GetColorU32(ImGuiCol.FrameBg), !hold)
.Push(ImGuiCol.ButtonActive, ImGui.GetColorU32(ImGuiCol.FrameBg), !hold)
.Push(ImGuiCol.Border, tint, _config.DefaultTemporaryMode);
.Push(ImGuiCol.Border, tint, config.DefaultTemporaryMode);
if (ImUtf8.IconButton(FontAwesomeIcon.Stopwatch, ""u8, default, false, tint, ImGui.GetColorU32(ImGuiCol.FrameBg)) && hold)
{
_config.DefaultTemporaryMode = !_config.DefaultTemporaryMode;
_config.Save();
config.DefaultTemporaryMode = !config.DefaultTemporaryMode;
config.Save();
}
}
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled,
"Toggle the temporary settings mode, where all changes you do create temporary settings first and need to be made permanent if desired."u8);
if (!hold)
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, $"\nHold {_config.IncognitoModifier} while clicking to toggle.");
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, $"\nHold {config.IncognitoModifier} while clicking to toggle.");
}
private enum CollectionState
@ -116,7 +108,7 @@ public class CollectionSelectHeader : Luna.IUiService
private (ModCollection?, string, string, bool) GetPlayerCollectionInfo()
{
var collection = _resolver.PlayerCollection();
var collection = resolver.PlayerCollection();
return CheckCollection(collection) switch
{
CollectionState.Empty => (collection, "None", "The loaded player character is configured to use no mods.", true),
@ -145,7 +137,7 @@ public class CollectionSelectHeader : Luna.IUiService
private (ModCollection?, string, string, bool) GetInheritedCollectionInfo()
{
var collection = _selection.Mod == null ? null : _selection.Collection;
var collection = selection.Mod == null ? null : selection.Collection;
return CheckCollection(collection, true) switch
{
CollectionState.Unavailable => (null, "Not Inherited",

View file

@ -1,46 +1,64 @@
using Dalamud.Bindings.ImGui;
using ImSharp;
using Luna;
using OtterGui.Raii;
using OtterGui.Text;
using OtterGui.Widgets;
using Penumbra.Collections;
using Penumbra.Collections.Manager;
using Penumbra.Communication;
namespace Penumbra.UI.CollectionTab;
public sealed class CollectionCombo(CollectionManager manager, Func<IReadOnlyList<ModCollection>> items)
: FilterComboCache<ModCollection>(items, MouseWheelType.Control, Penumbra.Log)
public sealed class CollectionCombo : SimpleFilterCombo<ModCollection>, IDisposable, IUiService
{
private readonly ImRaii.Color _color = new();
private readonly Im.ColorDisposable _color = new();
private readonly Im.StyleDisposable _style = new();
private readonly CollectionManager _manager;
private readonly CollectionChange _event;
protected override void DrawFilter(int currentSelected, float width)
public CollectionCombo(CollectionManager manager, CollectionChange @event)
: base(SimpleFilterType.Text)
{
_color.Dispose();
base.DrawFilter(currentSelected, width);
_manager = manager;
_event = @event;
Current = _manager.Active.Current;
_event.Subscribe(OnCollectionChanged, CollectionChange.Priority.CollectionCombo);
ClearFilterOnSelection = true;
ClearFilterOnCacheDisposal = true;
}
public void Draw(string label, float width, uint color)
private void OnCollectionChanged(in CollectionChange.Arguments arguments)
{
var current = manager.Active.Current;
if (current != CurrentSelection)
{
CurrentSelectionIdx = Items.IndexOf(current);
UpdateSelection(current);
}
if (arguments.Type is not CollectionType.Current)
return;
_color.Push(ImGuiCol.FrameBg, color).Push(ImGuiCol.FrameBgHovered, color);
if (Draw(label, current.Identity.Name, string.Empty, width, ImGui.GetTextLineHeightWithSpacing()) && CurrentSelection != null)
manager.Active.SetCollection(CurrentSelection, CollectionType.Current);
_color.Dispose();
Current = _manager.Active.Current;
}
protected override string ToString(ModCollection obj)
=> obj.Identity.Name;
public override StringU8 DisplayString(in ModCollection value)
=> new(value.Identity.Name);
protected override void DrawCombo(string label, string preview, string tooltip, int currentSelected, float previewWidth, float itemHeight,
ImGuiComboFlags flags)
public override string FilterString(in ModCollection value)
=> value.Identity.Name;
public override IEnumerable<ModCollection> GetBaseItems()
=> _manager.Storage.OrderBy(c => c.Identity.Name);
public void Draw(Utf8StringHandler<LabelStringHandlerBuffer> label, float width, Rgba32 color)
{
base.DrawCombo(label, preview, tooltip, currentSelected, previewWidth, itemHeight, flags);
ImUtf8.HoverTooltip("Control and mouse wheel to scroll."u8);
_color.Push(ImGuiColor.FrameBackground, color)
.Push(ImGuiColor.FrameBackgroundHovered, color);
if (Draw(label, Current!, "Control and mouse wheel to scroll."u8, width, out var collection))
_manager.Active.SetCollection(collection, CollectionType.Current);
_color.Dispose();
_style.Dispose();
}
public void Dispose()
=> _event.Unsubscribe(OnCollectionChanged);
protected override void PreDrawFilter()
{
_color.Dispose();
_style.PushDefault(ImStyleDouble.ItemSpacing);
base.PreDrawFilter();
}
}

View file

@ -1,12 +1,10 @@
using Dalamud.Interface;
using Dalamud.Bindings.ImGui;
using ImSharp;
using Luna;
using Penumbra.UI.Classes;
using OtterGui.Raii;
using OtterGui.Text;
namespace Penumbra.UI;
public class IncognitoService(TutorialService tutorial, Configuration config) : Luna.IService
public class IncognitoService(TutorialService tutorial, Configuration config) : IUiService
{
public bool IncognitoMode
=> config.Ephemeral.IncognitoMode;
@ -15,18 +13,18 @@ public class IncognitoService(TutorialService tutorial, Configuration config) :
{
var hold = config.IncognitoModifier.IsActive();
var color = ColorId.FolderExpanded.Value();
using (ImRaii.PushFrameBorder(ImUtf8.GlobalScale, color))
using (new Im.ColorStyleDisposable().PushBorder(ImStyleBorder.Frame, color))
{
var tt = IncognitoMode ? "Toggle incognito mode off."u8 : "Toggle incognito mode on."u8;
var icon = IncognitoMode ? FontAwesomeIcon.EyeSlash : FontAwesomeIcon.Eye;
if (ImUtf8.IconButton(icon, tt, new Vector2(width, ImUtf8.FrameHeight), false, color) && hold)
var icon = IncognitoMode ? LunaStyle.IncognitoOn : LunaStyle.IncognitoOff;
if (ImEx.Icon.Button(icon, tt, size: new Vector2(width, Im.Style.FrameHeight), textColor: color) && hold)
{
config.Ephemeral.IncognitoMode = !IncognitoMode;
config.Ephemeral.Save();
}
if (!hold)
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, $"\nHold {config.IncognitoModifier} while clicking to toggle.");
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"\nHold {config.IncognitoModifier} while clicking to toggle.");
}
tutorial.OpenTutorial(BasicTutorialSteps.Incognito);

View file

@ -1,6 +1,7 @@
using Dalamud.Bindings.ImGui;
using FFXIVClientStructs.FFXIV.Client.Game.Object;
using FFXIVClientStructs.FFXIV.Client.System.Resource;
using ImSharp;
using OtterGui.Raii;
using OtterGui.Widgets;
using Penumbra.Api.Enums;
@ -102,50 +103,50 @@ public sealed class ResourceWatcher : IDisposable, ITab, Luna.IUiService
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + ImGui.GetTextLineHeightWithSpacing() / 2);
var isEnabled = _ephemeral.EnableResourceWatcher;
if (ImGui.Checkbox("Enable", ref isEnabled))
if (Im.Checkbox("Enable"u8, ref isEnabled))
{
_ephemeral.EnableResourceWatcher = isEnabled;
_ephemeral.Save();
}
ImGui.SameLine();
Im.Line.Same();
DrawMaxEntries();
ImGui.SameLine();
if (ImGui.Button("Clear"))
Im.Line.Same();
if (Im.Button("Clear"u8))
Clear();
ImGui.SameLine();
var onlyMatching = _ephemeral.OnlyAddMatchingResources;
if (ImGui.Checkbox("Store Only Matching", ref onlyMatching))
if (Im.Checkbox("Store Only Matching"u8, ref onlyMatching))
{
_ephemeral.OnlyAddMatchingResources = onlyMatching;
_ephemeral.Save();
}
ImGui.SameLine();
Im.Line.Same();
var writeToLog = _ephemeral.EnableResourceLogging;
if (ImGui.Checkbox("Write to Log", ref writeToLog))
if (Im.Checkbox("Write to Log"u8, ref writeToLog))
{
_ephemeral.EnableResourceLogging = writeToLog;
_ephemeral.Save();
}
ImGui.SameLine();
Im.Line.Same();
DrawFilterInput();
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + ImGui.GetTextLineHeightWithSpacing() / 2);
Im.Cursor.Y += Im.Style.TextHeightWithSpacing / 2;
_table.Draw(ImGui.GetTextLineHeightWithSpacing());
_table.Draw(Im.Style.TextHeightWithSpacing);
}
private void DrawFilterInput()
{
ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X);
Im.Item.SetNextWidth(Im.ContentRegion.Available.X);
var tmp = _logFilter;
var invalidRegex = _logRegex == null && _logFilter.Length > 0;
using var color = ImRaii.PushColor(ImGuiCol.Border, Colors.RegexWarningBorder, invalidRegex);
using var style = ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, UiHelpers.Scale, invalidRegex);
if (ImGui.InputTextWithHint("##logFilter", "If path matches this Regex...", ref tmp, 256))
var invalidRegex = _logRegex is null && _logFilter.Length > 0;
using var color =
new Im.ColorStyleDisposable().PushBorder(ImStyleBorder.Frame, Colors.RegexWarningBorder, Im.Style.GlobalScale, invalidRegex);
if (Im.Input.Text("##logFilter"u8, ref tmp, "If path matches this Regex..."u8))
UpdateFilter(tmp, true);
}
@ -180,8 +181,8 @@ public sealed class ResourceWatcher : IDisposable, ITab, Luna.IUiService
private void DrawMaxEntries()
{
ImGui.SetNextItemWidth(80 * UiHelpers.Scale);
ImGui.InputInt("Max. Entries", ref _newMaxEntries, 0, 0);
Im.Item.SetNextWidth(80 * Im.Style.GlobalScale);
Im.Input.Scalar("Max. Entries"u8, ref _newMaxEntries);
var change = ImGui.IsItemDeactivatedAfterEdit();
if (ImGui.IsItemClicked(ImGuiMouseButton.Right) && ImGui.GetIO().KeyCtrl)
{

View file

@ -789,6 +789,7 @@ public class DebugTab : Window, ITab, IUiService
Im.Text("Exists"u8);
Im.Text("File Size"u8);
}
Im.Line.SameInner();
using (Im.Group())
{
@ -1102,8 +1103,8 @@ public class DebugTab : Window, ITab, IUiService
ImGui.TableNextColumn();
Penumbra.Dynamis.DrawPointer((nint)imc);
ImGui.TableNextColumn();
if (imc != null)
UiHelpers.Text(imc);
if (imc is not null)
Im.Text(imc->FileName().Span);
var mdl = (RenderModel*)model->Models[i];
ImGui.TableNextColumn();
@ -1112,9 +1113,7 @@ public class DebugTab : Window, ITab, IUiService
continue;
ImGui.TableNextColumn();
{
UiHelpers.Text(mdl->ResourceHandle);
}
Im.Text(mdl->ResourceHandle->FileName().Span);
}
}
@ -1209,14 +1208,7 @@ public class DebugTab : Window, ITab, IUiService
ImGui.TableNextColumn();
ImGui.TextUnformatted(r->RefCount.ToString());
ImGui.TableNextColumn();
ref var name = ref r->FileName;
if (name.Capacity > 15)
UiHelpers.Text(name.BufferPtr, (int)name.Length);
else
fixed (byte* ptr = name.Buffer)
{
UiHelpers.Text(ptr, (int)name.Length);
}
Im.Text(r->FileName.AsSpan());
});
}

View file

@ -2,8 +2,8 @@ using Dalamud.Bindings.ImGui;
using Dalamud.Game;
using FFXIVClientStructs.FFXIV.Client.System.Resource;
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
using FFXIVClientStructs.Interop;
using FFXIVClientStructs.STD;
using ImSharp;
using OtterGui;
using OtterGui.Raii;
using OtterGui.Widgets;
@ -52,7 +52,7 @@ public class ResourceTab(Configuration config, ResourceManagerService resourceMa
private string _resourceManagerFilter = string.Empty;
/// <summary> Draw a single resource map. </summary>
private unsafe void DrawResourceMap(ResourceCategory category, uint ext, StdMap<uint, Pointer<ResourceHandle>>* map)
private unsafe void DrawResourceMap(ResourceCategory category, uint ext, StdMap<uint, FFXIVClientStructs.Interop.Pointer<ResourceHandle>>* map)
{
if (map == null)
return;
@ -86,7 +86,7 @@ public class ResourceTab(Configuration config, ResourceManagerService resourceMa
var resource = (Interop.Structs.ResourceHandle*)r;
ImGui.TableNextColumn();
UiHelpers.Text(resource);
Im.Text(resource->FileName().Span);
if (ImGui.IsItemClicked())
{
var data = resource->CsHandle.GetData();
@ -106,7 +106,7 @@ public class ResourceTab(Configuration config, ResourceManagerService resourceMa
/// <summary> Draw a full category for the resource manager. </summary>
private unsafe void DrawCategoryContainer(ResourceCategory category,
StdMap<uint, Pointer<StdMap<uint, Pointer<ResourceHandle>>>>* map, int idx)
StdMap<uint, FFXIVClientStructs.Interop.Pointer<StdMap<uint, FFXIVClientStructs.Interop.Pointer<ResourceHandle>>>>* map, int idx)
{
if (map == null)
return;

View file

@ -104,7 +104,77 @@ public class SettingsTab : ITab, IUiService
_tutorial.OpenTutorial(BasicTutorialSteps.Faq2);
}
private readonly TwoPanelLayout _test = new();
public sealed class TestFlattened : IFlattenedTreeNode
{
public int ParentIndex { get; set; }
public int StartsLineTo { get; set; }
public int IndentationDepth { get; set; }
public void Draw()
{
Im.Tree.Node("",
TreeNodeFlags.DefaultOpen
| TreeNodeFlags.NoTreePushOnOpen); //Im.Selectable($"{ParentIndex} {StartsLineTo} {IndentationDepth}"));
}
}
private static readonly List<TestFlattened> List =
[
new()
{
IndentationDepth = 0,
ParentIndex = -1,
StartsLineTo = 2,
},
new()
{
IndentationDepth = 1,
ParentIndex = 0,
StartsLineTo = -1,
},
new()
{
IndentationDepth = 1,
ParentIndex = 0,
StartsLineTo = -1,
},
new()
{
IndentationDepth = 0,
ParentIndex = -1,
StartsLineTo = 8,
},
new()
{
IndentationDepth = 1,
ParentIndex = 3,
StartsLineTo = 6,
},
new()
{
IndentationDepth = 2,
ParentIndex = 4,
StartsLineTo = -1,
},
new()
{
IndentationDepth = 2,
ParentIndex = 4,
StartsLineTo = 7,
},
new()
{
IndentationDepth = 3,
ParentIndex = 6,
StartsLineTo = -1,
},
new()
{
IndentationDepth = 1,
ParentIndex = 3,
StartsLineTo = -1,
},
];
public void DrawContent()
{
@ -112,22 +182,26 @@ public class SettingsTab : ITab, IUiService
if (!child)
return;
DrawEnabledBox();
EphemeralCheckbox("Lock Main Window", "Prevent the main window from being resized or moved.", _config.Ephemeral.FixMainWindow,
v => _config.Ephemeral.FixMainWindow = v);
using var c2 = ImRaii.Child("a", new Vector2(300, 5 * ImGui.GetTextLineHeightWithSpacing()), true,
ImGuiWindowFlags.AlwaysVerticalScrollbar);
TreeLine.Draw(List, 0xFFFFFFFF);
ImGui.NewLine();
DrawRootFolder();
DrawDirectoryButtons();
ImGui.NewLine();
ImGui.NewLine();
DrawGeneralSettings();
_migrationDrawer.Draw();
DrawColorSettings();
DrawPredefinedTagsSection();
DrawAdvancedSettings();
DrawSupportButtons();
//DrawEnabledBox();
//EphemeralCheckbox("Lock Main Window", "Prevent the main window from being resized or moved.", _config.Ephemeral.FixMainWindow,
// v => _config.Ephemeral.FixMainWindow = v);
//
//ImGui.NewLine();
//DrawRootFolder();
//DrawDirectoryButtons();
//ImGui.NewLine();
//ImGui.NewLine();
//
//DrawGeneralSettings();
//_migrationDrawer.Draw();
//DrawColorSettings();
//DrawPredefinedTagsSection();
//DrawAdvancedSettings();
//DrawSupportButtons();
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]

View file

@ -1,59 +1,15 @@
using Dalamud.Interface.ImGuiNotification;
using Dalamud.Interface.Utility;
using Dalamud.Bindings.ImGui;
using ImSharp;
using Luna;
using OtterGui;
using OtterGui.Raii;
using Penumbra.Interop.Structs;
using Penumbra.String;
using ImGuiId = ImSharp.ImGuiId;
namespace Penumbra.UI;
public static class UiHelpers
{
/// <summary> Draw text given by a ByteString. </summary>
public static unsafe void Text(ByteString s)
=> ImGuiNative.TextUnformatted(s.Path, s.Path + s.Length);
/// <summary> Draw text given by a byte pointer and length. </summary>
public static unsafe void Text(byte* s, int length)
=> ImGuiNative.TextUnformatted(s, s + length);
/// <summary> Draw text given by a byte span. </summary>
public static unsafe void Text(ReadOnlySpan<byte> s)
{
fixed (byte* pS = s)
{
Text(pS, s.Length);
}
}
/// <summary> Draw the name of a resource file. </summary>
public static unsafe void Text(ResourceHandle* resource)
=> Text(resource->CsHandle.FileName.AsSpan());
/// <summary> Draw a ByteString as a selectable. </summary>
public static unsafe bool Selectable(ByteString s, bool selected)
{
var tmp = (byte)(selected ? 1 : 0);
return ImGuiNative.Selectable(s.Path, tmp, ImGuiSelectableFlags.None, Vector2.Zero) != 0;
}
/// <summary>
/// A selectable that copies its text to clipboard on selection and provides a on-hover tooltip about that,
/// using an ByteString.
/// </summary>
public static unsafe void CopyOnClickSelectable(ByteString text)
{
if (ImGuiNative.Selectable(text.Path, 0, ImGuiSelectableFlags.None, Vector2.Zero) != 0)
ImGuiNative.SetClipboardText(text.Path);
if (ImGui.IsItemHovered())
ImGui.SetTooltip("Click to copy to clipboard.");
}
/// <summary> The longest support button text. </summary>
public const string SupportInfoButtonText = "Copy Support Info to Clipboard";
public static ReadOnlySpan<byte> SupportInfoButtonText
=> "Copy Support Info to Clipboard"u8;
/// <summary>
/// Draw a button that copies the support info to clipboards.
@ -61,22 +17,22 @@ public static class UiHelpers
/// <param name="penumbra"></param>
public static void DrawSupportButton(Penumbra penumbra)
{
if (!ImGui.Button(SupportInfoButtonText))
if (!Im.Button(SupportInfoButtonText))
return;
var text = penumbra.GatherSupportInformation();
ImGui.SetClipboardText(text);
Penumbra.Messager.NotificationMessage($"Copied Support Info to Clipboard.", NotificationType.Success, false);
Im.Clipboard.Set(text);
Penumbra.Messager.NotificationMessage("Copied Support Info to Clipboard.", NotificationType.Success, false);
}
/// <summary> Draw a button to open a specific directory in a file explorer.</summary>
/// <param name="id">Specific ID for the given type of directory.</param>
/// <param name="directory">The directory to open.</param>
/// <param name="condition">Whether the button is available. </param>
public static void DrawOpenDirectoryButton(int id, DirectoryInfo directory, bool condition)
public static void DrawOpenDirectoryButton(ImGuiId id, DirectoryInfo directory, bool condition)
{
using var _ = ImRaii.PushId(id);
if (ImGuiUtil.DrawDisabledButton("Open Directory", Vector2.Zero, "Open this directory in your configured file explorer.",
using var _ = Im.Id.Push(id);
if (ImEx.Button("Open Directory"u8, Vector2.Zero, "Open this directory in your configured file explorer."u8,
!condition || !Directory.Exists(directory.FullName)))
Process.Start(new ProcessStartInfo(directory.FullName)
{
@ -86,7 +42,7 @@ public static class UiHelpers
/// <summary> Draw default vertical space. </summary>
public static void DefaultLineSpace()
=> ImGui.Dummy(DefaultSpace);
=> Im.Dummy(DefaultSpace);
/// <summary> Vertical spacing between groups. </summary>
public static Vector2 DefaultSpace;
@ -113,9 +69,9 @@ public static class UiHelpers
public static void SetupCommonSizes()
{
if (ImGuiHelpers.GlobalScale != Scale)
if (Im.Style.GlobalScale != Scale)
{
Scale = ImGuiHelpers.GlobalScale;
Scale = Im.Style.GlobalScale;
DefaultSpace = new Vector2(0, 10 * Scale);
InputTextWidth = new Vector2(350f * Scale, 0);
ScaleX2 = Scale * 2;
@ -124,8 +80,8 @@ public static class UiHelpers
ScaleX5 = Scale * 5;
}
IconButtonSize = new Vector2(ImGui.GetFrameHeight());
IconButtonSize = new Vector2(Im.Style.FrameHeight);
InputTextMinusButton3 = InputTextWidth.X - IconButtonSize.X - ScaleX3;
InputTextMinusButton = InputTextWidth.X - IconButtonSize.X - ImGui.GetStyle().ItemSpacing.X;
InputTextMinusButton = InputTextWidth.X - IconButtonSize.X - Im.Style.ItemSpacing.X;
}
}