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; + } +}