diff --git a/Luna b/Luna
index 15636cda..0e9fdb2b 160000
--- a/Luna
+++ b/Luna
@@ -1 +1 @@
-Subproject commit 15636cda90725e6af7071512cf9873dd273570fc
+Subproject commit 0e9fdb2bbfb02d76468a3f968b07289664d90808
diff --git a/Penumbra.Api b/Penumbra.Api
index dd141317..648b6fc2 160000
--- a/Penumbra.Api
+++ b/Penumbra.Api
@@ -1 +1 @@
-Subproject commit dd14131793e5ae47cc8e9232f46469216017b5aa
+Subproject commit 648b6fc2ce600a95ab2b2ced27e1639af2b04502
diff --git a/Penumbra/Communication/CollectionChange.cs b/Penumbra/Communication/CollectionChange.cs
index 487c5e16..e577e69d 100644
--- a/Penumbra/Communication/CollectionChange.cs
+++ b/Penumbra/Communication/CollectionChange.cs
@@ -1,6 +1,7 @@
using Luna;
using Penumbra.Collections;
using Penumbra.Collections.Manager;
+using Penumbra.UI.CollectionTab;
namespace Penumbra.Communication;
@@ -41,7 +42,10 @@ public sealed class CollectionChange(Logger log)
ModFileSystemSelector = 0,
///
- ModSelection = 10,
+ ModSelection = 10,
+
+ ///
+ CollectionCombo = 15,
}
/// The arguments for a collection change event.
diff --git a/Penumbra/EphemeralConfig.cs b/Penumbra/EphemeralConfig.cs
index 1cfca3da..7a5091be 100644
--- a/Penumbra/EphemeralConfig.cs
+++ b/Penumbra/EphemeralConfig.cs
@@ -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;
diff --git a/Penumbra/Mods/Manager/ModCacheManager.cs b/Penumbra/Mods/Manager/ModCacheManager.cs
index 1d03eb22..655ed250 100644
--- a/Penumbra/Mods/Manager/ModCacheManager.cs
+++ b/Penumbra/Mods/Manager/ModCacheManager.cs
@@ -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;
diff --git a/Penumbra/Penumbra.cs b/Penumbra/Penumbra.cs
index 0d9f7ad6..ab5e8fa9 100644
--- a/Penumbra/Penumbra.cs
+++ b/Penumbra/Penumbra.cs
@@ -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(); // Initialize because not required anywhere else.
- _config = _services.GetService();
- _characterUtility = _services.GetService();
- _tempMods = _services.GetService();
- _residentResources = _services.GetService();
- _services.GetService(); // Initialize because not required anywhere else.
+ _services.GetService(); // Initialize early to create backups.
+ _config = _services.GetService();
+ _characterUtility = _services.GetService();
+ _tempMods = _services.GetService();
+ _residentResources = _services.GetService();
_modManager = _services.GetService();
_collectionManager = _services.GetService();
_tempCollections = _services.GetService();
_redrawService = _services.GetService();
_communicatorService = _services.GetService();
_gameData = _services.GetService();
- _services.GetService(); // Initialize because not required anywhere else.
- _services.GetService(); // Initialize because not required anywhere else.
_collectionManager.Caches.CreateNecessaryCaches();
_services.GetService();
@@ -118,13 +115,13 @@ public class Penumbra : IDalamudPlugin
{
_services.GetService();
var itemSheet = _services.GetService().GetExcelSheet- ();
- _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()
diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Files.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Files.cs
index b538b2c9..66e51835 100644
--- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Files.cs
+++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Files.cs
@@ -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);
diff --git a/Penumbra/UI/Classes/CollectionSelectHeader.cs b/Penumbra/UI/Classes/CollectionSelectHeader.cs
index 5605b587..faef03c2 100644
--- a/Penumbra/UI/Classes/CollectionSelectHeader.cs
+++ b/Penumbra/UI/Classes/CollectionSelectHeader.cs
@@ -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;
/// Draw the header line that can quick switch between collections.
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",
diff --git a/Penumbra/UI/CollectionTab/CollectionCombo.cs b/Penumbra/UI/CollectionTab/CollectionCombo.cs
index 276899c0..28b85972 100644
--- a/Penumbra/UI/CollectionTab/CollectionCombo.cs
+++ b/Penumbra/UI/CollectionTab/CollectionCombo.cs
@@ -1,46 +1,64 @@
-using Dalamud.Bindings.ImGui;
-using Luna;
-using OtterGui.Raii;
-using OtterGui.Text;
-using OtterGui.Widgets;
-using Penumbra.Collections;
-using Penumbra.Collections.Manager;
-
-namespace Penumbra.UI.CollectionTab;
-
-public sealed class CollectionCombo(CollectionManager manager, Func> items)
- : FilterComboCache(items, MouseWheelType.Control, Penumbra.Log)
-{
- private readonly ImRaii.Color _color = new();
-
- protected override void DrawFilter(int currentSelected, float width)
- {
- _color.Dispose();
- base.DrawFilter(currentSelected, width);
- }
-
- public void Draw(string label, float width, uint color)
- {
- var current = manager.Active.Current;
- if (current != CurrentSelection)
- {
- CurrentSelectionIdx = Items.IndexOf(current);
- UpdateSelection(current);
- }
-
- _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();
- }
-
- protected override string ToString(ModCollection obj)
- => obj.Identity.Name;
-
- protected override void DrawCombo(string label, string preview, string tooltip, int currentSelected, float previewWidth, float itemHeight,
- ImGuiComboFlags flags)
- {
- base.DrawCombo(label, preview, tooltip, currentSelected, previewWidth, itemHeight, flags);
- ImUtf8.HoverTooltip("Control and mouse wheel to scroll."u8);
- }
-}
+using ImSharp;
+using Luna;
+using Penumbra.Collections;
+using Penumbra.Collections.Manager;
+using Penumbra.Communication;
+
+namespace Penumbra.UI.CollectionTab;
+
+public sealed class CollectionCombo : SimpleFilterCombo, IDisposable, IUiService
+{
+ private readonly Im.ColorDisposable _color = new();
+ private readonly Im.StyleDisposable _style = new();
+ private readonly CollectionManager _manager;
+ private readonly CollectionChange _event;
+
+ public CollectionCombo(CollectionManager manager, CollectionChange @event)
+ : base(SimpleFilterType.Text)
+ {
+ _manager = manager;
+ _event = @event;
+ Current = _manager.Active.Current;
+ _event.Subscribe(OnCollectionChanged, CollectionChange.Priority.CollectionCombo);
+ ClearFilterOnSelection = true;
+ ClearFilterOnCacheDisposal = true;
+ }
+
+ private void OnCollectionChanged(in CollectionChange.Arguments arguments)
+ {
+ if (arguments.Type is not CollectionType.Current)
+ return;
+
+ Current = _manager.Active.Current;
+ }
+
+ public override StringU8 DisplayString(in ModCollection value)
+ => new(value.Identity.Name);
+
+ public override string FilterString(in ModCollection value)
+ => value.Identity.Name;
+
+ public override IEnumerable GetBaseItems()
+ => _manager.Storage.OrderBy(c => c.Identity.Name);
+
+ public void Draw(Utf8StringHandler label, float width, Rgba32 color)
+ {
+ _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();
+ }
+}
diff --git a/Penumbra/UI/IncognitoService.cs b/Penumbra/UI/IncognitoService.cs
index b3150f39..bd988fb3 100644
--- a/Penumbra/UI/IncognitoService.cs
+++ b/Penumbra/UI/IncognitoService.cs
@@ -1,34 +1,32 @@
-using Dalamud.Interface;
-using Dalamud.Bindings.ImGui;
-using Penumbra.UI.Classes;
-using OtterGui.Raii;
-using OtterGui.Text;
-
-namespace Penumbra.UI;
-
-public class IncognitoService(TutorialService tutorial, Configuration config) : Luna.IService
-{
- public bool IncognitoMode
- => config.Ephemeral.IncognitoMode;
-
- public void DrawToggle(float width)
- {
- var hold = config.IncognitoModifier.IsActive();
- var color = ColorId.FolderExpanded.Value();
- using (ImRaii.PushFrameBorder(ImUtf8.GlobalScale, 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)
- {
- config.Ephemeral.IncognitoMode = !IncognitoMode;
- config.Ephemeral.Save();
- }
-
- if (!hold)
- ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, $"\nHold {config.IncognitoModifier} while clicking to toggle.");
- }
-
- tutorial.OpenTutorial(BasicTutorialSteps.Incognito);
- }
-}
+using ImSharp;
+using Luna;
+using Penumbra.UI.Classes;
+
+namespace Penumbra.UI;
+
+public class IncognitoService(TutorialService tutorial, Configuration config) : IUiService
+{
+ public bool IncognitoMode
+ => config.Ephemeral.IncognitoMode;
+
+ public void DrawToggle(float width)
+ {
+ var hold = config.IncognitoModifier.IsActive();
+ var color = ColorId.FolderExpanded.Value();
+ using (new Im.ColorStyleDisposable().PushBorder(ImStyleBorder.Frame, color))
+ {
+ var tt = IncognitoMode ? "Toggle incognito mode off."u8 : "Toggle incognito mode on."u8;
+ 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)
+ Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"\nHold {config.IncognitoModifier} while clicking to toggle.");
+ }
+
+ tutorial.OpenTutorial(BasicTutorialSteps.Incognito);
+ }
+}
diff --git a/Penumbra/UI/ResourceWatcher/ResourceWatcher.cs b/Penumbra/UI/ResourceWatcher/ResourceWatcher.cs
index e21a8179..a52b2957 100644
--- a/Penumbra/UI/ResourceWatcher/ResourceWatcher.cs
+++ b/Penumbra/UI/ResourceWatcher/ResourceWatcher.cs
@@ -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)
{
diff --git a/Penumbra/UI/Tabs/Debug/DebugTab.cs b/Penumbra/UI/Tabs/Debug/DebugTab.cs
index d5b02db0..4fce8866 100644
--- a/Penumbra/UI/Tabs/Debug/DebugTab.cs
+++ b/Penumbra/UI/Tabs/Debug/DebugTab.cs
@@ -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());
});
}
diff --git a/Penumbra/UI/Tabs/ResourceTab.cs b/Penumbra/UI/Tabs/ResourceTab.cs
index fc74147c..8bcd0fea 100644
--- a/Penumbra/UI/Tabs/ResourceTab.cs
+++ b/Penumbra/UI/Tabs/ResourceTab.cs
@@ -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;
/// Draw a single resource map.
- private unsafe void DrawResourceMap(ResourceCategory category, uint ext, StdMap>* map)
+ private unsafe void DrawResourceMap(ResourceCategory category, uint ext, StdMap>* 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
/// Draw a full category for the resource manager.
private unsafe void DrawCategoryContainer(ResourceCategory category,
- StdMap>>>* map, int idx)
+ StdMap>>>* map, int idx)
{
if (map == null)
return;
diff --git a/Penumbra/UI/Tabs/SettingsTab.cs b/Penumbra/UI/Tabs/SettingsTab.cs
index 48f79be6..f8fd17ac 100644
--- a/Penumbra/UI/Tabs/SettingsTab.cs
+++ b/Penumbra/UI/Tabs/SettingsTab.cs
@@ -104,30 +104,104 @@ 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 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()
{
using var child = ImRaii.Child("##SettingsTab", -Vector2.One, false);
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);
-
- ImGui.NewLine();
- DrawRootFolder();
- DrawDirectoryButtons();
- ImGui.NewLine();
- ImGui.NewLine();
-
- DrawGeneralSettings();
- _migrationDrawer.Draw();
- DrawColorSettings();
- DrawPredefinedTagsSection();
- DrawAdvancedSettings();
- DrawSupportButtons();
+
+ using var c2 = ImRaii.Child("a", new Vector2(300, 5 * ImGui.GetTextLineHeightWithSpacing()), true,
+ ImGuiWindowFlags.AlwaysVerticalScrollbar);
+ TreeLine.Draw(List, 0xFFFFFFFF);
+
+ //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)]
diff --git a/Penumbra/UI/UiHelpers.cs b/Penumbra/UI/UiHelpers.cs
index 369a2b1d..2bdd0241 100644
--- a/Penumbra/UI/UiHelpers.cs
+++ b/Penumbra/UI/UiHelpers.cs
@@ -1,131 +1,87 @@
-using Dalamud.Interface.ImGuiNotification;
-using Dalamud.Interface.Utility;
-using Dalamud.Bindings.ImGui;
-using Luna;
-using OtterGui;
-using OtterGui.Raii;
-using Penumbra.Interop.Structs;
-using Penumbra.String;
-
-namespace Penumbra.UI;
-
-public static class UiHelpers
-{
- /// Draw text given by a ByteString.
- public static unsafe void Text(ByteString s)
- => ImGuiNative.TextUnformatted(s.Path, s.Path + s.Length);
-
- /// Draw text given by a byte pointer and length.
- public static unsafe void Text(byte* s, int length)
- => ImGuiNative.TextUnformatted(s, s + length);
-
- /// Draw text given by a byte span.
- public static unsafe void Text(ReadOnlySpan s)
- {
- fixed (byte* pS = s)
- {
- Text(pS, s.Length);
- }
- }
-
- /// Draw the name of a resource file.
- public static unsafe void Text(ResourceHandle* resource)
- => Text(resource->CsHandle.FileName.AsSpan());
-
- /// Draw a ByteString as a selectable.
- 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;
- }
-
- ///
- /// A selectable that copies its text to clipboard on selection and provides a on-hover tooltip about that,
- /// using an ByteString.
- ///
- 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.");
- }
-
- /// The longest support button text.
- public const string SupportInfoButtonText = "Copy Support Info to Clipboard";
-
- ///
- /// Draw a button that copies the support info to clipboards.
- ///
- ///
- public static void DrawSupportButton(Penumbra penumbra)
- {
- if (!ImGui.Button(SupportInfoButtonText))
- return;
-
- var text = penumbra.GatherSupportInformation();
- ImGui.SetClipboardText(text);
- Penumbra.Messager.NotificationMessage($"Copied Support Info to Clipboard.", NotificationType.Success, false);
- }
-
- /// Draw a button to open a specific directory in a file explorer.
- /// Specific ID for the given type of directory.
- /// The directory to open.
- /// Whether the button is available.
- public static void DrawOpenDirectoryButton(int 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.",
- !condition || !Directory.Exists(directory.FullName)))
- Process.Start(new ProcessStartInfo(directory.FullName)
- {
- UseShellExecute = true,
- });
- }
-
- /// Draw default vertical space.
- public static void DefaultLineSpace()
- => ImGui.Dummy(DefaultSpace);
-
- /// Vertical spacing between groups.
- public static Vector2 DefaultSpace;
-
- /// Width of most input fields.
- public static Vector2 InputTextWidth;
-
- /// Frame Height for square icon buttons.
- public static Vector2 IconButtonSize;
-
- /// Input Text Width with space for an additional button with spacing of 3 between them.
- public static float InputTextMinusButton3;
-
- /// Input Text Width with space for an additional button with spacing of default item spacing between them.
- public static float InputTextMinusButton;
-
- /// Multiples of the current Global Scale
- public static float Scale;
-
- public static float ScaleX2;
- public static float ScaleX3;
- public static float ScaleX4;
- public static float ScaleX5;
-
- public static void SetupCommonSizes()
- {
- if (ImGuiHelpers.GlobalScale != Scale)
- {
- Scale = ImGuiHelpers.GlobalScale;
- DefaultSpace = new Vector2(0, 10 * Scale);
- InputTextWidth = new Vector2(350f * Scale, 0);
- ScaleX2 = Scale * 2;
- ScaleX3 = Scale * 3;
- ScaleX4 = Scale * 4;
- ScaleX5 = Scale * 5;
- }
-
- IconButtonSize = new Vector2(ImGui.GetFrameHeight());
- InputTextMinusButton3 = InputTextWidth.X - IconButtonSize.X - ScaleX3;
- InputTextMinusButton = InputTextWidth.X - IconButtonSize.X - ImGui.GetStyle().ItemSpacing.X;
- }
-}
+using Dalamud.Interface.ImGuiNotification;
+using ImSharp;
+using Luna;
+using ImGuiId = ImSharp.ImGuiId;
+
+namespace Penumbra.UI;
+
+public static class UiHelpers
+{
+ /// The longest support button text.
+ public static ReadOnlySpan SupportInfoButtonText
+ => "Copy Support Info to Clipboard"u8;
+
+ ///
+ /// Draw a button that copies the support info to clipboards.
+ ///
+ ///
+ public static void DrawSupportButton(Penumbra penumbra)
+ {
+ if (!Im.Button(SupportInfoButtonText))
+ return;
+
+ var text = penumbra.GatherSupportInformation();
+ Im.Clipboard.Set(text);
+ Penumbra.Messager.NotificationMessage("Copied Support Info to Clipboard.", NotificationType.Success, false);
+ }
+
+ /// Draw a button to open a specific directory in a file explorer.
+ /// Specific ID for the given type of directory.
+ /// The directory to open.
+ /// Whether the button is available.
+ public static void DrawOpenDirectoryButton(ImGuiId id, DirectoryInfo directory, bool condition)
+ {
+ 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)
+ {
+ UseShellExecute = true,
+ });
+ }
+
+ /// Draw default vertical space.
+ public static void DefaultLineSpace()
+ => Im.Dummy(DefaultSpace);
+
+ /// Vertical spacing between groups.
+ public static Vector2 DefaultSpace;
+
+ /// Width of most input fields.
+ public static Vector2 InputTextWidth;
+
+ /// Frame Height for square icon buttons.
+ public static Vector2 IconButtonSize;
+
+ /// Input Text Width with space for an additional button with spacing of 3 between them.
+ public static float InputTextMinusButton3;
+
+ /// Input Text Width with space for an additional button with spacing of default item spacing between them.
+ public static float InputTextMinusButton;
+
+ /// Multiples of the current Global Scale
+ public static float Scale;
+
+ public static float ScaleX2;
+ public static float ScaleX3;
+ public static float ScaleX4;
+ public static float ScaleX5;
+
+ public static void SetupCommonSizes()
+ {
+ if (Im.Style.GlobalScale != Scale)
+ {
+ Scale = Im.Style.GlobalScale;
+ DefaultSpace = new Vector2(0, 10 * Scale);
+ InputTextWidth = new Vector2(350f * Scale, 0);
+ ScaleX2 = Scale * 2;
+ ScaleX3 = Scale * 3;
+ ScaleX4 = Scale * 4;
+ ScaleX5 = Scale * 5;
+ }
+
+ IconButtonSize = new Vector2(Im.Style.FrameHeight);
+ InputTextMinusButton3 = InputTextWidth.X - IconButtonSize.X - ScaleX3;
+ InputTextMinusButton = InputTextWidth.X - IconButtonSize.X - Im.Style.ItemSpacing.X;
+ }
+}