Update some files for Luna.

This commit is contained in:
Ottermandias 2025-10-19 22:24:52 +02:00
parent 3f48cd6910
commit a4302c9145
23 changed files with 1669 additions and 1712 deletions

2
Luna

@ -1 +1 @@
Subproject commit 2542a4665aca0ee7a66ad940638ff84cd04e35b5 Subproject commit 1ffa8c5de118f94b609f7d6352e3b63de463398c

@ -1 +1 @@
Subproject commit fcb443b79b0954967a959aa2f498699bd1a54923 Subproject commit 3a9406bc634228cc0815ddb6fe5e20419cafb864

View file

@ -1,4 +1,5 @@
using Dalamud.Bindings.ImGui; using Dalamud.Bindings.ImGui;
using ImSharp;
using OtterGui; using OtterGui;
using OtterGui.Raii; using OtterGui.Raii;
using Penumbra.Import.Structs; using Penumbra.Import.Structs;
@ -89,12 +90,12 @@ public partial class TexToolsImporter
ImGui.TableNextColumn(); ImGui.TableNextColumn();
if (ex == null) if (ex == null)
{ {
using var color = ImRaii.PushColor(ImGuiCol.Text, ColorId.FolderExpanded.Value()); using var color = ImGuiColor.Text.Push(ColorId.FolderExpanded.Value());
ImGui.TextUnformatted(dir?.FullName[(_baseDirectory.FullName.Length + 1)..] ?? "Unknown Directory"); ImGui.TextUnformatted(dir?.FullName[(_baseDirectory.FullName.Length + 1)..] ?? "Unknown Directory");
} }
else else
{ {
using var color = ImRaii.PushColor(ImGuiCol.Text, ColorId.ConflictingMod.Value()); using var color = ImGuiColor.Text.Push(ColorId.ConflictingMod.Value());
ImGui.TextUnformatted(ex.Message); ImGui.TextUnformatted(ex.Message);
ImGuiUtil.HoverTooltip(ex.ToString()); ImGuiUtil.HoverTooltip(ex.ToString());
} }

View file

@ -125,9 +125,9 @@ public static class TextureDrawer
{ {
var (path, game, isOnPlayer) = Items[globalIdx]; var (path, game, isOnPlayer) = Items[globalIdx];
bool ret; bool ret;
using (var color = ImRaii.PushColor(ImGuiCol.Text, ColorId.FolderExpanded.Value(), game)) using (var color = ImGuiColor.Text.Push(ColorId.FolderExpanded.Value(), game))
{ {
color.Push(ImGuiCol.Text, ColorId.HandledConflictMod.Value(), isOnPlayer); color.Push(ImGuiColor.Text, ColorId.HandledConflictMod.Value(), isOnPlayer);
var equals = string.Equals(CurrentSelection.Path, path, StringComparison.OrdinalIgnoreCase); var equals = string.Equals(CurrentSelection.Path, path, StringComparison.OrdinalIgnoreCase);
var p = game ? $"--> {path}" : path[_skipPrefix..]; var p = game ? $"--> {path}" : path[_skipPrefix..];
ret = ImGui.Selectable(p, selected) && !equals; ret = ImGui.Selectable(p, selected) && !equals;

View file

@ -56,25 +56,24 @@ public static class FeatureChecker
var size = new Vector2((width - (numButtons - 1) * innerSpacing.X) / numButtons, 0); var size = new Vector2((width - (numButtons - 1) * innerSpacing.X) / numButtons, 0);
var buttonColor = ImGui.GetColorU32(ImGuiCol.FrameBg); var buttonColor = ImGui.GetColorU32(ImGuiCol.FrameBg);
var textColor = ImGui.GetColorU32(ImGuiCol.TextDisabled); var textColor = ImGui.GetColorU32(ImGuiCol.TextDisabled);
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, innerSpacing) using (var style = ImStyleBorder.Frame.Push(ColorId.FolderLine.Value(), 0)
.Push(ImGuiStyleVar.FrameBorderSize, 0); .Push(ImStyleDouble.ItemSpacing, innerSpacing)
using (var color = ImRaii.PushColor(ImGuiCol.Border, ColorId.FolderLine.Value()) .Push(ImGuiColor.Button, buttonColor)
.Push(ImGuiCol.Button, buttonColor) .Push(ImGuiColor.Text, textColor))
.Push(ImGuiCol.Text, textColor))
{ {
foreach (var flag in SupportedFlags.Values) foreach (var flag in SupportedFlags.Values)
{ {
if (mod.RequiredFeatures.HasFlag(flag)) if (mod.RequiredFeatures.HasFlag(flag))
{ {
style.Push(ImGuiStyleVar.FrameBorderSize, ImUtf8.GlobalScale); style.Push(ImStyleSingle.FrameBorderThickness, ImUtf8.GlobalScale);
color.Pop(2); style.PopColor(2);
if (ImUtf8.Button($"{flag}", size)) if (Im.Button($"{flag}", size))
editor.ChangeRequiredFeatures(mod, mod.RequiredFeatures & ~flag); editor.ChangeRequiredFeatures(mod, mod.RequiredFeatures & ~flag);
color.Push(ImGuiCol.Button, buttonColor) style.Push(ImGuiColor.Button, buttonColor)
.Push(ImGuiCol.Text, textColor); .Push(ImGuiColor.Text, textColor);
style.Pop(); style.PopStyle();
} }
else if (ImUtf8.Button($"{flag}", size)) else if (Im.Button($"{flag}", size))
{ {
editor.ChangeRequiredFeatures(mod, mod.RequiredFeatures | flag); editor.ChangeRequiredFeatures(mod, mod.RequiredFeatures | flag);
} }

View file

@ -1,5 +1,6 @@
using Dalamud.Bindings.ImGui; using Dalamud.Bindings.ImGui;
using Dalamud.Interface; using Dalamud.Interface;
using Dalamud.Interface.Colors;
using Dalamud.Interface.ImGuiNotification; using Dalamud.Interface.ImGuiNotification;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using ImSharp; using ImSharp;
@ -297,7 +298,7 @@ public class FileEditor<T>(
{ {
var file = Items[globalIdx]; var file = Items[globalIdx];
bool ret; bool ret;
using (var c = ImRaii.PushColor(ImGuiCol.Text, ColorId.HandledConflictMod.Value(), file.IsOnPlayer)) using (var c = ImGuiColor.Text.Push(ColorId.HandledConflictMod.Value(), file.IsOnPlayer))
{ {
ret = ImGui.Selectable(file.RelPath.ToString(), selected); ret = ImGui.Selectable(file.RelPath.ToString(), selected);
} }
@ -313,7 +314,7 @@ public class FileEditor<T>(
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImUtf8.Text(gamePath.Path.Span); ImUtf8.Text(gamePath.Path.Span);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
using var color = ImRaii.PushColor(ImGuiCol.Text, ColorId.ItemId.Value()); using var color = ImGuiColor.Text.Push(ColorId.ItemId.Value());
ImGui.TextUnformatted(option.GetFullName()); ImGui.TextUnformatted(option.GetFullName());
} }
} }
@ -321,7 +322,7 @@ public class FileEditor<T>(
if (file.SubModUsage.Count > 0) if (file.SubModUsage.Count > 0)
{ {
Im.Line.Same(); Im.Line.Same();
using var color = ImRaii.PushColor(ImGuiCol.Text, ColorId.ItemId.Value()); using var color = ImGuiColor.Text.Push(ColorId.ItemId.Value());
ImGuiUtil.RightAlign(file.SubModUsage[0].Item2.Path.ToString()); ImGuiUtil.RightAlign(file.SubModUsage[0].Item2.Path.ToString());
} }

View file

@ -159,9 +159,9 @@ public class ItemSwapTab : IDisposable, ITab, IUiService
{ {
var (_, inMod, inCollection) = Items[globalIdx]; var (_, inMod, inCollection) = Items[globalIdx];
using var color = inMod using var color = inMod
? ImRaii.PushColor(ImGuiCol.Text, ColorId.ResTreeLocalPlayer.Value()) ? ImGuiColor.Text.Push(ColorId.ResTreeLocalPlayer.Value())
: inCollection.Count > 0 : inCollection.Count > 0
? ImRaii.PushColor(ImGuiCol.Text, ColorId.ResTreeNonNetworked.Value()) ? ImGuiColor.Text.Push(ColorId.ResTreeNonNetworked.Value())
: null; : null;
var ret = base.DrawSelectable(globalIdx, selected); var ret = base.DrawSelectable(globalIdx, selected);
if (inCollection.Count > 0) if (inCollection.Count > 0)

View file

@ -58,12 +58,12 @@ public class ModMergeTab(ModMerger modMerger) : Luna.IUiService
ImGui.SameLine(0, 0); ImGui.SameLine(0, 0);
if (size - textSize < minComboSize) if (size - textSize < minComboSize)
{ {
ImUtf8.Text("selected mod"u8, ColorId.FolderLine.Value()); Im.Text("selected mod"u8, ColorId.FolderLine.Value());
ImUtf8.HoverTooltip(modMerger.MergeFromMod!.Name); ImUtf8.HoverTooltip(modMerger.MergeFromMod!.Name);
} }
else else
{ {
ImUtf8.Text(modMerger.MergeFromMod!.Name, ColorId.FolderLine.Value()); Im.Text(modMerger.MergeFromMod!.Name, ColorId.FolderLine.Value());
} }
ImGui.SameLine(0, 0); ImGui.SameLine(0, 0);

View file

@ -3,12 +3,9 @@ using Dalamud.Interface.Textures;
using Dalamud.Interface.Textures.TextureWraps; using Dalamud.Interface.Textures.TextureWraps;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using Dalamud.Utility; using Dalamud.Utility;
using Dalamud.Bindings.ImGui;
using ImSharp; using ImSharp;
using Lumina.Data.Files; using Lumina.Data.Files;
using OtterGui; using Luna;
using OtterGui.Raii;
using OtterGui.Text;
using Penumbra.Communication; using Penumbra.Communication;
using Penumbra.GameData.Data; using Penumbra.GameData.Data;
using Penumbra.Services; using Penumbra.Services;
@ -17,9 +14,9 @@ using MouseButton = Penumbra.Api.Enums.MouseButton;
namespace Penumbra.UI; namespace Penumbra.UI;
public class ChangedItemDrawer : IDisposable, Luna.IUiService public class ChangedItemDrawer : IDisposable, IUiService
{ {
private static readonly string[] LowerNames = ChangedItemFlagExtensions.Order.Select(f => f.ToDescription().ToLowerInvariant()).ToArray(); private static readonly string[] LowerNames = ChangedItemFlagExtensions.Order.Select(f => f.ToDescription().ToString().ToLowerInvariant()).ToArray();
public static bool TryParseIndex(ReadOnlySpan<char> input, out ChangedItemIconFlag slot) public static bool TryParseIndex(ReadOnlySpan<char> input, out ChangedItemIconFlag slot)
{ {
@ -69,7 +66,7 @@ public class ChangedItemDrawer : IDisposable, Luna.IUiService
private float _smallestIconWidth; private float _smallestIconWidth;
public static Vector2 TypeFilterIconSize public static Vector2 TypeFilterIconSize
=> new(2 * ImGui.GetTextLineHeight()); => new(2 * Im.Style.TextHeight);
public ChangedItemDrawer(IUiBuilder uiBuilder, IDataManager gameData, ITextureProvider textureProvider, CommunicatorService communicator, public ChangedItemDrawer(IUiBuilder uiBuilder, IDataManager gameData, ITextureProvider textureProvider, CommunicatorService communicator,
Configuration config) Configuration config)
@ -97,44 +94,44 @@ public class ChangedItemDrawer : IDisposable, Luna.IUiService
=> DrawCategoryIcon(data.GetIcon().ToFlag(), height); => DrawCategoryIcon(data.GetIcon().ToFlag(), height);
public void DrawCategoryIcon(ChangedItemIconFlag iconFlagType) public void DrawCategoryIcon(ChangedItemIconFlag iconFlagType)
=> DrawCategoryIcon(iconFlagType, ImGui.GetFrameHeight()); => DrawCategoryIcon(iconFlagType, Im.Style.FrameHeight);
public void DrawCategoryIcon(ChangedItemIconFlag iconFlagType, float height) public void DrawCategoryIcon(ChangedItemIconFlag iconFlagType, float height)
{ {
if (!_icons.TryGetValue(iconFlagType, out var icon)) if (!_icons.TryGetValue(iconFlagType, out var icon))
{ {
ImGui.Dummy(new Vector2(height)); Im.Dummy(0, height);
return; return;
} }
ImGui.Image(icon.Handle, new Vector2(height)); Im.Image.Draw(icon.Id(), new Vector2(height));
if (ImGui.IsItemHovered()) if (Im.Item.Hovered())
{ {
using var tt = ImRaii.Tooltip(); using var tt = Im.Tooltip.Begin();
ImGui.Image(icon.Handle, new Vector2(_smallestIconWidth)); Im.Image.Draw(icon.Id(), new Vector2(_smallestIconWidth));
Im.Line.Same(); Im.Line.Same();
ImGuiUtil.DrawTextButton(iconFlagType.ToDescription(), new Vector2(0, _smallestIconWidth), 0); ImEx.TextFramed(iconFlagType.ToDescription(), new Vector2(0, _smallestIconWidth), 0);
} }
} }
public void ChangedItemHandling(IIdentifiedObjectData data, bool leftClicked) public void ChangedItemHandling(IIdentifiedObjectData data, bool leftClicked)
{ {
var ret = leftClicked ? MouseButton.Left : MouseButton.None; var ret = leftClicked ? MouseButton.Left : MouseButton.None;
ret = ImGui.IsItemClicked(ImGuiMouseButton.Right) ? MouseButton.Right : ret; ret = Im.Item.Clicked(ImSharp.MouseButton.Right) ? MouseButton.Right : ret;
ret = ImGui.IsItemClicked(ImGuiMouseButton.Middle) ? MouseButton.Middle : ret; ret = Im.Item.Clicked(ImSharp.MouseButton.Middle) ? MouseButton.Middle : ret;
if (ret != MouseButton.None) if (ret != MouseButton.None)
_communicator.ChangedItemClick.Invoke(new ChangedItemClick.Arguments(ret, data)); _communicator.ChangedItemClick.Invoke(new ChangedItemClick.Arguments(ret, data));
if (!ImGui.IsItemHovered()) if (!Im.Item.Hovered())
return; return;
using var tt = ImUtf8.Tooltip(); using var tt = Im.Tooltip.Begin();
if (data.Count == 1) if (data.Count == 1)
ImUtf8.Text("This item is changed through a single effective change.\n"); Im.Text("This item is changed through a single effective change.\n"u8);
else else
ImUtf8.Text($"This item is changed through {data.Count} distinct effective changes.\n"); Im.Text($"This item is changed through {data.Count} distinct effective changes.\n");
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 3 * ImUtf8.GlobalScale); Im.Cursor.Y += 3 * Im.Style.GlobalScale;
ImGui.Separator(); Im.Separator();
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 3 * ImUtf8.GlobalScale); Im.Cursor.Y += 3 * Im.Style.GlobalScale;
_communicator.ChangedItemHover.Invoke(new ChangedItemHover.Arguments(data)); _communicator.ChangedItemHover.Invoke(new ChangedItemHover.Arguments(data));
} }
@ -146,9 +143,9 @@ public class ChangedItemDrawer : IDisposable, Luna.IUiService
return; return;
Im.Line.Same(); Im.Line.Same();
using var color = ImRaii.PushColor(ImGuiCol.Text, ColorId.ItemId.Value()); using var color = ImGuiColor.Text.Push(ColorId.ItemId.Value());
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + (height - ImGui.GetTextLineHeight()) / 2); Im.Cursor.Y += height - Im.Style.TextHeight / 2;
ImUtf8.TextRightAligned(additionalData, ImGui.GetStyle().ItemInnerSpacing.X); ImEx.TextRightAligned(additionalData, Im.Style.ItemInnerSpacing.X);
} }
/// <summary> Draw the model information, right-justified. </summary> /// <summary> Draw the model information, right-justified. </summary>
@ -158,9 +155,9 @@ public class ChangedItemDrawer : IDisposable, Luna.IUiService
return; return;
Im.Line.Same(); Im.Line.Same();
using var color = ImRaii.PushColor(ImGuiCol.Text, ColorId.ItemId.Value()); using var color = ImGuiColor.Text.Push(ColorId.ItemId.Value());
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + (height - ImGui.GetTextLineHeight()) / 2); Im.Cursor.Y += height - Im.Style.TextHeight / 2;
ImUtf8.TextRightAligned(text, ImGui.GetStyle().ItemInnerSpacing.X); ImEx.TextRightAligned(text, Im.Style.ItemInnerSpacing.X);
} }
/// <summary> Draw a header line with the different icon types to filter them. </summary> /// <summary> Draw a header line with the different icon types to filter them. </summary>
@ -181,9 +178,9 @@ public class ChangedItemDrawer : IDisposable, Luna.IUiService
public bool DrawTypeFilter(ref ChangedItemIconFlag typeFilter) public bool DrawTypeFilter(ref ChangedItemIconFlag typeFilter)
{ {
var ret = false; var ret = false;
using var _ = ImRaii.PushId("ChangedItemIconFilter"); using var _ = Im.Id.Push("ChangedItemIconFilter"u8);
var size = TypeFilterIconSize; var size = TypeFilterIconSize;
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero); using var style = ImStyleDouble.ItemSpacing.Push(Vector2.Zero);
foreach (var iconType in ChangedItemFlagExtensions.Order) foreach (var iconType in ChangedItemFlagExtensions.Order)
@ -192,15 +189,15 @@ public class ChangedItemDrawer : IDisposable, Luna.IUiService
Im.Line.Same(); Im.Line.Same();
} }
ImGui.SetCursorPosX(ImGui.GetContentRegionMax().X - size.X); Im.Cursor.X = Im.ContentRegion.Maximum.X - size.X;
ImGui.Image(_icons[ChangedItemFlagExtensions.AllFlags].Handle, size, Vector2.Zero, Vector2.One, Im.Image.Draw(_icons[ChangedItemFlagExtensions.AllFlags].Id(), size, Vector2.Zero, Vector2.One,
typeFilter switch typeFilter switch
{ {
0 => new Vector4(0.6f, 0.3f, 0.3f, 1f), 0 => new Vector4(0.6f, 0.3f, 0.3f, 1f),
ChangedItemFlagExtensions.AllFlags => new Vector4(0.75f, 0.75f, 0.75f, 1f), ChangedItemFlagExtensions.AllFlags => new Vector4(0.75f, 0.75f, 0.75f, 1f),
_ => new Vector4(0.5f, 0.5f, 1f, 1f), _ => new Vector4(0.5f, 0.5f, 1f, 1f),
}); });
if (ImGui.IsItemClicked()) if (Im.Item.Clicked())
{ {
typeFilter = typeFilter == ChangedItemFlagExtensions.AllFlags ? 0 : ChangedItemFlagExtensions.AllFlags; typeFilter = typeFilter == ChangedItemFlagExtensions.AllFlags ? 0 : ChangedItemFlagExtensions.AllFlags;
ret = true; ret = true;
@ -213,28 +210,28 @@ public class ChangedItemDrawer : IDisposable, Luna.IUiService
var localRet = false; var localRet = false;
var icon = _icons[type]; var icon = _icons[type];
var flag = typeFilter.HasFlag(type); var flag = typeFilter.HasFlag(type);
ImGui.Image(icon.Handle, size, Vector2.Zero, Vector2.One, flag ? Vector4.One : new Vector4(0.6f, 0.3f, 0.3f, 1f)); Im.Image.Draw(icon.Id(), size, Vector2.Zero, Vector2.One, flag ? Vector4.One : new Vector4(0.6f, 0.3f, 0.3f, 1f));
if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) if (Im.Item.Clicked())
{ {
typeFilter = flag ? typeFilter & ~type : typeFilter | type; typeFilter = flag ? typeFilter & ~type : typeFilter | type;
localRet = true; localRet = true;
} }
using var popup = ImRaii.ContextPopupItem(type.ToString()); using var popup = Im.Popup.BeginContextItem($"{type}");
if (popup) if (popup)
if (ImGui.MenuItem("Enable Only This")) if (Im.Menu.Item("Enable Only This"u8))
{ {
typeFilter = type; typeFilter = type;
localRet = true; localRet = true;
ImGui.CloseCurrentPopup(); Im.Popup.CloseCurrent();
} }
if (ImGui.IsItemHovered()) if (Im.Item.Hovered())
{ {
using var tt = ImRaii.Tooltip(); using var tt = Im.Tooltip.Begin();
ImGui.Image(icon.Handle, new Vector2(_smallestIconWidth)); Im.Image.Draw(icon.Id(), new Vector2(_smallestIconWidth));
Im.Line.Same(); Im.Line.Same();
ImGuiUtil.DrawTextButton(type.ToDescription(), new Vector2(0, _smallestIconWidth), 0); ImEx.TextFramed(type.ToDescription(), new Vector2(0, _smallestIconWidth), 0);
} }
return localRet; return localRet;

View file

@ -52,26 +52,26 @@ public static class ChangedItemFlagExtensions
public static readonly int NumCategories = Order.Count; public static readonly int NumCategories = Order.Count;
public const ChangedItemIconFlag DefaultFlags = AllFlags & ~ChangedItemIconFlag.Offhand; public const ChangedItemIconFlag DefaultFlags = AllFlags & ~ChangedItemIconFlag.Offhand;
public static string ToDescription(this ChangedItemIconFlag iconFlag) public static ReadOnlySpan<byte> ToDescription(this ChangedItemIconFlag iconFlag)
=> iconFlag switch => iconFlag switch
{ {
ChangedItemIconFlag.Head => EquipSlot.Head.ToName(), ChangedItemIconFlag.Head => EquipSlot.Head.ToNameU8(),
ChangedItemIconFlag.Body => EquipSlot.Body.ToName(), ChangedItemIconFlag.Body => EquipSlot.Body.ToNameU8(),
ChangedItemIconFlag.Hands => EquipSlot.Hands.ToName(), ChangedItemIconFlag.Hands => EquipSlot.Hands.ToNameU8(),
ChangedItemIconFlag.Legs => EquipSlot.Legs.ToName(), ChangedItemIconFlag.Legs => EquipSlot.Legs.ToNameU8(),
ChangedItemIconFlag.Feet => EquipSlot.Feet.ToName(), ChangedItemIconFlag.Feet => EquipSlot.Feet.ToNameU8(),
ChangedItemIconFlag.Ears => EquipSlot.Ears.ToName(), ChangedItemIconFlag.Ears => EquipSlot.Ears.ToNameU8(),
ChangedItemIconFlag.Neck => EquipSlot.Neck.ToName(), ChangedItemIconFlag.Neck => EquipSlot.Neck.ToNameU8(),
ChangedItemIconFlag.Wrists => EquipSlot.Wrists.ToName(), ChangedItemIconFlag.Wrists => EquipSlot.Wrists.ToNameU8(),
ChangedItemIconFlag.Finger => "Ring", ChangedItemIconFlag.Finger => "Ring"u8,
ChangedItemIconFlag.Monster => "Monster", ChangedItemIconFlag.Monster => "Monster"u8,
ChangedItemIconFlag.Demihuman => "Demi-Human", ChangedItemIconFlag.Demihuman => "Demi-Human"u8,
ChangedItemIconFlag.Customization => "Customization", ChangedItemIconFlag.Customization => "Customization"u8,
ChangedItemIconFlag.Action => "Action", ChangedItemIconFlag.Action => "Action"u8,
ChangedItemIconFlag.Emote => "Emote", ChangedItemIconFlag.Emote => "Emote"u8,
ChangedItemIconFlag.Mainhand => "Weapon (Mainhand)", ChangedItemIconFlag.Mainhand => "Weapon (Mainhand)"u8,
ChangedItemIconFlag.Offhand => "Weapon (Offhand)", ChangedItemIconFlag.Offhand => "Weapon (Offhand)"u8,
_ => "Other", _ => "Other"u8,
}; };
public static ChangedItemIcon ToApiIcon(this ChangedItemIconFlag iconFlag) public static ChangedItemIcon ToApiIcon(this ChangedItemIconFlag iconFlag)

View file

@ -1,14 +1,14 @@
using Dalamud.Interface; using Dalamud.Interface;
using Dalamud.Bindings.ImGui;
using ImSharp; using ImSharp;
using OtterGui; using Luna;
using OtterGui.Raii;
using OtterGui.Text;
using Penumbra.Collections; using Penumbra.Collections;
using Penumbra.Collections.Manager; using Penumbra.Collections.Manager;
using Penumbra.Interop.PathResolving; using Penumbra.Interop.PathResolving;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.UI.CollectionTab; using Penumbra.UI.CollectionTab;
using CollectionTuple =
ImSharp.RefTuple<Penumbra.Collections.ModCollection?, ImSharp.Utf8StringHandler<ImSharp.LabelStringHandlerBuffer>,
ImSharp.Utf8StringHandler<ImSharp.TextStringHandlerBuffer>, bool>;
namespace Penumbra.UI.Classes; namespace Penumbra.UI.Classes;
@ -19,20 +19,21 @@ public class CollectionSelectHeader(
CollectionResolver resolver, CollectionResolver resolver,
Configuration config, Configuration config,
CollectionCombo combo) CollectionCombo combo)
: Luna.IUiService : IUiService
{ {
private readonly ActiveCollections _activeCollections = collectionManager.Active; private readonly ActiveCollections _activeCollections = collectionManager.Active;
private static readonly AwesomeIcon Icon = FontAwesomeIcon.Stopwatch;
/// <summary> Draw the header line that can quick switch between collections. </summary> /// <summary> Draw the header line that can quick switch between collections. </summary>
public void Draw(bool spacing) public void Draw(bool spacing)
{ {
using var style = ImRaii.PushStyle(ImGuiStyleVar.FrameRounding, 0) using var style = ImStyleSingle.FrameRounding.Push(0)
.Push(ImGuiStyleVar.ItemSpacing, new Vector2(0, spacing ? ImGui.GetStyle().ItemSpacing.Y : 0)); .Push(ImStyleDouble.ItemSpacing, new Vector2(0, spacing ? Im.Style.ItemSpacing.Y : 0));
DrawTemporaryCheckbox(); DrawTemporaryCheckbox();
Im.Line.Same(); Im.Line.Same();
var comboWidth = ImGui.GetContentRegionAvail().X / 4f; var comboWidth = Im.ContentRegion.Available.X / 4f;
var buttonSize = new Vector2(comboWidth * 3f / 4f, 0f); var buttonSize = new Vector2(comboWidth * 3f / 4f, 0f);
using (var _ = ImRaii.Group()) using (var _ = Im.Group())
{ {
DrawCollectionButton(buttonSize, GetDefaultCollectionInfo(), 1); DrawCollectionButton(buttonSize, GetDefaultCollectionInfo(), 1);
DrawCollectionButton(buttonSize, GetInterfaceCollectionInfo(), 2); DrawCollectionButton(buttonSize, GetInterfaceCollectionInfo(), 2);
@ -45,31 +46,32 @@ public class CollectionSelectHeader(
tutorial.OpenTutorial(BasicTutorialSteps.CollectionSelectors); tutorial.OpenTutorial(BasicTutorialSteps.CollectionSelectors);
if (!_activeCollections.CurrentCollectionInUse) if (!_activeCollections.CurrentCollectionInUse)
ImGuiUtil.DrawTextButton("The currently selected collection is not used in any way.", -Vector2.UnitX, Colors.PressEnterWarningBg); ImEx.TextFramed("The currently selected collection is not used in any way."u8, -Vector2.UnitX, Colors.PressEnterWarningBg);
} }
private void DrawTemporaryCheckbox() private void DrawTemporaryCheckbox()
{ {
var hold = config.IncognitoModifier.IsActive(); var hold = config.IncognitoModifier.IsActive();
using (ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, ImUtf8.GlobalScale)) var tint = config.DefaultTemporaryMode
? Rgba32.TintColor(Im.Style[ImGuiColor.Text], ColorId.TemporaryModSettingsTint.Value().ToVector())
: Im.Style[ImGuiColor.TextDisabled];
var frameBg = Im.Style[ImGuiColor.FrameBackground];
using (ImStyleBorder.Frame.Push(tint)
.Push(ImGuiColor.ButtonHovered, frameBg, !hold)
.Push(ImGuiColor.ButtonActive, frameBg, !hold))
{ {
var tint = config.DefaultTemporaryMode if (ImEx.Icon.Button(Icon, buttonColor: frameBg, textColor: tint) && hold)
? 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);
if (ImUtf8.IconButton(FontAwesomeIcon.Stopwatch, ""u8, default, false, tint, ImGui.GetColorU32(ImGuiCol.FrameBg)) && hold)
{ {
config.DefaultTemporaryMode = !config.DefaultTemporaryMode; config.DefaultTemporaryMode = !config.DefaultTemporaryMode;
config.Save(); config.Save();
} }
} }
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled,
"Toggle the temporary settings mode, where all changes you do create temporary settings first and need to be made permanent if desired."u8); "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) 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.");
} }
private enum CollectionState private enum CollectionState
@ -82,7 +84,7 @@ public class CollectionSelectHeader(
private CollectionState CheckCollection(ModCollection? collection, bool inheritance = false) private CollectionState CheckCollection(ModCollection? collection, bool inheritance = false)
{ {
if (collection == null) if (collection is null)
return CollectionState.Unavailable; return CollectionState.Unavailable;
if (collection == ModCollection.Empty) if (collection == ModCollection.Empty)
return CollectionState.Empty; return CollectionState.Empty;
@ -92,68 +94,70 @@ public class CollectionSelectHeader(
return CollectionState.Available; return CollectionState.Available;
} }
private (ModCollection?, string, string, bool) GetDefaultCollectionInfo() private CollectionTuple GetDefaultCollectionInfo()
{ {
var collection = _activeCollections.Default; var collection = _activeCollections.Default;
return CheckCollection(collection) switch return CheckCollection(collection) switch
{ {
CollectionState.Empty => (collection, "None", "The base collection is configured to use no mods.", true), CollectionState.Empty => new CollectionTuple(collection, "None"u8, "The base collection is configured to use no mods."u8, true),
CollectionState.Selected => (collection, collection.Identity.Name, CollectionState.Selected => new CollectionTuple(collection, collection.Identity.Name,
"The configured base collection is already selected as the current collection.", true), "The configured base collection is already selected as the current collection."u8, true),
CollectionState.Available => (collection, collection.Identity.Name, CollectionState.Available => new CollectionTuple(collection, collection.Identity.Name,
$"Select the configured base collection {collection.Identity.Name} as the current collection.", false), $"Select the configured base collection {collection.Identity.Name} as the current collection.", false),
_ => throw new Exception("Can not happen."), _ => throw new Exception("Can not happen."),
}; };
} }
private (ModCollection?, string, string, bool) GetPlayerCollectionInfo() private CollectionTuple GetPlayerCollectionInfo()
{ {
var collection = resolver.PlayerCollection(); var collection = resolver.PlayerCollection();
return CheckCollection(collection) switch return CheckCollection(collection) switch
{ {
CollectionState.Empty => (collection, "None", "The loaded player character is configured to use no mods.", true), CollectionState.Empty => new CollectionTuple(collection, "None"u8, "The loaded player character is configured to use no mods."u8,
CollectionState.Selected => (collection, collection.Identity.Name, true),
"The collection configured to apply to the loaded player character is already selected as the current collection.", true), CollectionState.Selected => new CollectionTuple(collection, collection.Identity.Name,
CollectionState.Available => (collection, collection.Identity.Name, "The collection configured to apply to the loaded player character is already selected as the current collection."u8, true),
CollectionState.Available => new CollectionTuple(collection, collection.Identity.Name,
$"Select the collection {collection.Identity.Name} that applies to the loaded player character as the current collection.", $"Select the collection {collection.Identity.Name} that applies to the loaded player character as the current collection.",
false), false),
_ => throw new Exception("Can not happen."), _ => throw new Exception("Can not happen."),
}; };
} }
private (ModCollection?, string, string, bool) GetInterfaceCollectionInfo() private CollectionTuple GetInterfaceCollectionInfo()
{ {
var collection = _activeCollections.Interface; var collection = _activeCollections.Interface;
return CheckCollection(collection) switch return CheckCollection(collection) switch
{ {
CollectionState.Empty => (collection, "None", "The interface collection is configured to use no mods.", true), CollectionState.Empty => new CollectionTuple(collection, "None"u8, "The interface collection is configured to use no mods."u8,
CollectionState.Selected => (collection, collection.Identity.Name, true),
"The configured interface collection is already selected as the current collection.", true), CollectionState.Selected => new CollectionTuple(collection, collection.Identity.Name,
CollectionState.Available => (collection, collection.Identity.Name, "The configured interface collection is already selected as the current collection."u8, true),
CollectionState.Available => new CollectionTuple(collection, collection.Identity.Name,
$"Select the configured interface collection {collection.Identity.Name} as the current collection.", false), $"Select the configured interface collection {collection.Identity.Name} as the current collection.", false),
_ => throw new Exception("Can not happen."), _ => throw new Exception("Can not happen."),
}; };
} }
private (ModCollection?, string, string, bool) GetInheritedCollectionInfo() private CollectionTuple GetInheritedCollectionInfo()
{ {
var collection = selection.Mod == null ? null : selection.Collection; var collection = selection.Mod is null ? null : selection.Collection;
return CheckCollection(collection, true) switch return CheckCollection(collection, true) switch
{ {
CollectionState.Unavailable => (null, "Not Inherited", CollectionState.Unavailable => new CollectionTuple(null, "Not Inherited"u8,
"The settings of the selected mod are not inherited from another collection.", true), "The settings of the selected mod are not inherited from another collection."u8, true),
CollectionState.Available => (collection, collection!.Identity.Name, CollectionState.Available => new CollectionTuple(collection, collection!.Identity.Name,
$"Select the collection {collection!.Identity.Name} from which the selected mod inherits its settings as the current collection.", $"Select the collection {collection.Identity.Name} from which the selected mod inherits its settings as the current collection.",
false), false),
_ => throw new Exception("Can not happen."), _ => throw new Exception("Can not happen."),
}; };
} }
private void DrawCollectionButton(Vector2 buttonWidth, (ModCollection?, string, string, bool) tuple, int id) private void DrawCollectionButton(Vector2 buttonWidth, in CollectionTuple tuple, int id)
{ {
var (collection, name, tooltip, disabled) = tuple; var (collection, name, tooltip, disabled) = tuple;
using var _ = ImRaii.PushId(id); using var _ = Im.Id.Push(id);
if (ImGuiUtil.DrawDisabledButton(name, buttonWidth, tooltip, disabled)) if (ImEx.Button(name, buttonWidth, tooltip, disabled))
_activeCollections.SetCollection(collection!, CollectionType.Current); _activeCollections.SetCollection(collection!, CollectionType.Current);
Im.Line.Same(); Im.Line.Same();
} }

View file

@ -1,4 +1,4 @@
using Dalamud.Bindings.ImGui; using ImSharp;
using OtterGui.Custom; using OtterGui.Custom;
namespace Penumbra.UI.Classes; namespace Penumbra.UI.Classes;
@ -53,30 +53,6 @@ public static class Colors
public const uint ReniColorHovered = CustomGui.ReniColorHovered; public const uint ReniColorHovered = CustomGui.ReniColorHovered;
public const uint ReniColorActive = CustomGui.ReniColorActive; public const uint ReniColorActive = CustomGui.ReniColorActive;
public static uint Tinted(this ColorId color, ColorId tint)
{
var tintValue = ImGui.ColorConvertU32ToFloat4(tint.Value());
var value = ImGui.ColorConvertU32ToFloat4(color.Value());
return ImGui.ColorConvertFloat4ToU32(TintColor(value, tintValue));
}
public static unsafe uint Tinted(this ImGuiCol color, ColorId tint)
{
var tintValue = ImGui.ColorConvertU32ToFloat4(tint.Value());
ref var value = ref *ImGui.GetStyleColorVec4(color);
return ImGui.ColorConvertFloat4ToU32(TintColor(value, tintValue));
}
private static unsafe Vector4 TintColor(in Vector4 color, in Vector4 tint)
{
var negAlpha = 1 - tint.W;
var newAlpha = negAlpha * color.W + tint.W;
var newR = (negAlpha * color.W * color.X + tint.W * tint.X) / newAlpha;
var newG = (negAlpha * color.W * color.Y + tint.W * tint.Y) / newAlpha;
var newB = (negAlpha * color.W * color.Z + tint.W * tint.Z) / newAlpha;
return new Vector4(newR, newG, newB, newAlpha);
}
public static (uint DefaultColor, string Name, string Description) Data(this ColorId color) public static (uint DefaultColor, string Name, string Description) Data(this ColorId color)
=> color switch => color switch
{ {
@ -116,10 +92,10 @@ public static class Colors
// @formatter:on // @formatter:on
}; };
private static IReadOnlyDictionary<ColorId, uint> _colors = new Dictionary<ColorId, uint>(); private static Dictionary<ColorId, uint> _colors = [];
/// <summary> Obtain the configured value for a color. </summary> /// <summary> Obtain the configured value for a color. </summary>
public static uint Value(this ColorId color) public static Rgba32 Value(this ColorId color)
=> _colors.TryGetValue(color, out var value) ? value : color.Data().DefaultColor; => _colors.TryGetValue(color, out var value) ? value : color.Data().DefaultColor;
/// <summary> Set the configurable colors dictionary to a value. </summary> /// <summary> Set the configurable colors dictionary to a value. </summary>

View file

@ -74,7 +74,7 @@ public sealed class CollectionPanel(
DrawSimpleCollectionButton(CollectionType.MaleNonPlayerCharacter, buttonWidth); DrawSimpleCollectionButton(CollectionType.MaleNonPlayerCharacter, buttonWidth);
DrawSimpleCollectionButton(CollectionType.FemaleNonPlayerCharacter, buttonWidth); DrawSimpleCollectionButton(CollectionType.FemaleNonPlayerCharacter, buttonWidth);
ImGuiUtil.DrawColoredText(("Individual ", ColorId.NewMod.Value()), ImGuiUtil.DrawColoredText(("Individual ", ColorId.NewMod.Value().Color),
("Assignments take precedence before anything else and only apply to one specific character or monster.", 0)); ("Assignments take precedence before anything else and only apply to one specific character or monster.", 0));
ImGui.Dummy(Vector2.UnitX); ImGui.Dummy(Vector2.UnitX);
@ -382,27 +382,27 @@ public sealed class CollectionPanel(
{ {
case CollectionType.Default: ImGui.TextUnformatted("Overruled by any other Assignment."); break; case CollectionType.Default: ImGui.TextUnformatted("Overruled by any other Assignment."); break;
case CollectionType.Yourself: case CollectionType.Yourself:
ImGuiUtil.DrawColoredText(("Overruled by ", 0), ("Individual ", ColorId.NewMod.Value()), ("Assignments.", 0)); ImGuiUtil.DrawColoredText(("Overruled by ", 0), ("Individual ", ColorId.NewMod.Value().Color), ("Assignments.", 0));
break; break;
case CollectionType.MalePlayerCharacter: case CollectionType.MalePlayerCharacter:
ImGuiUtil.DrawColoredText(("Overruled by ", 0), ("Male Racial Player", Colors.DiscordColor), (", ", 0), ImGuiUtil.DrawColoredText(("Overruled by ", 0), ("Male Racial Player", Colors.DiscordColor), (", ", 0),
("Your Character", ColorId.HandledConflictMod.Value()), (", or ", 0), ("Your Character", ColorId.HandledConflictMod.Value().Color), (", or ", 0),
("Individual ", ColorId.NewMod.Value()), ("Assignments.", 0)); ("Individual ", ColorId.NewMod.Value().Color), ("Assignments.", 0));
break; break;
case CollectionType.FemalePlayerCharacter: case CollectionType.FemalePlayerCharacter:
ImGuiUtil.DrawColoredText(("Overruled by ", 0), ("Female Racial Player", Colors.ReniColorActive), (", ", 0), ImGuiUtil.DrawColoredText(("Overruled by ", 0), ("Female Racial Player", Colors.ReniColorActive), (", ", 0),
("Your Character", ColorId.HandledConflictMod.Value()), (", or ", 0), ("Your Character", ColorId.HandledConflictMod.Value().Color), (", or ", 0),
("Individual ", ColorId.NewMod.Value()), ("Assignments.", 0)); ("Individual ", ColorId.NewMod.Value().Color), ("Assignments.", 0));
break; break;
case CollectionType.MaleNonPlayerCharacter: case CollectionType.MaleNonPlayerCharacter:
ImGuiUtil.DrawColoredText(("Overruled by ", 0), ("Male Racial NPC", Colors.DiscordColor), (", ", 0), ImGuiUtil.DrawColoredText(("Overruled by ", 0), ("Male Racial NPC", Colors.DiscordColor), (", ", 0),
("Children", ColorId.FolderLine.Value()), (", ", 0), ("Elderly", Colors.MetaInfoText), (", or ", 0), ("Children", ColorId.FolderLine.Value().Color), (", ", 0), ("Elderly", Colors.MetaInfoText), (", or ", 0),
("Individual ", ColorId.NewMod.Value()), ("Assignments.", 0)); ("Individual ", ColorId.NewMod.Value().Color), ("Assignments.", 0));
break; break;
case CollectionType.FemaleNonPlayerCharacter: case CollectionType.FemaleNonPlayerCharacter:
ImGuiUtil.DrawColoredText(("Overruled by ", 0), ("Female Racial NPC", Colors.ReniColorActive), (", ", 0), ImGuiUtil.DrawColoredText(("Overruled by ", 0), ("Female Racial NPC", Colors.ReniColorActive), (", ", 0),
("Children", ColorId.FolderLine.Value()), (", ", 0), ("Elderly", Colors.MetaInfoText), (", or ", 0), ("Children", ColorId.FolderLine.Value().Color), (", ", 0), ("Elderly", Colors.MetaInfoText), (", or ", 0),
("Individual ", ColorId.NewMod.Value()), ("Assignments.", 0)); ("Individual ", ColorId.NewMod.Value().Color), ("Assignments.", 0));
break; break;
} }
} }

View file

@ -3,7 +3,6 @@ using Dalamud.Interface.ImGuiFileDialog;
using Dalamud.Utility; using Dalamud.Utility;
using Dalamud.Bindings.ImGui; using Dalamud.Bindings.ImGui;
using Luna; using Luna;
using OtterGui;
using Penumbra.Communication; using Penumbra.Communication;
using Penumbra.Services; using Penumbra.Services;
@ -16,11 +15,16 @@ public class FileDialogService : IDisposable, IUiService
private readonly ConcurrentDictionary<string, string> _startPaths = new(); private readonly ConcurrentDictionary<string, string> _startPaths = new();
private bool _isOpen; private bool _isOpen;
private readonly Func<object?, object?>? _dialogGetter;
public FileDialogService(CommunicatorService communicator, Configuration config) public FileDialogService(CommunicatorService communicator, Configuration config)
{ {
_communicator = communicator; _communicator = communicator;
_manager = SetupFileManager(config.ModDirectory); _manager = SetupFileManager(config.ModDirectory);
_communicator.ModDirectoryChanged.Subscribe(OnModDirectoryChange, ModDirectoryChanged.Priority.FileDialogService); _communicator.ModDirectoryChanged.Subscribe(OnModDirectoryChange, ModDirectoryChanged.Priority.FileDialogService);
var fieldType = _manager.GetType().GetField("dialog", BindingFlags.Instance | BindingFlags.NonPublic);
_dialogGetter = fieldType is null ? null : fieldType.GetValue;
} }
public void OpenFilePicker(string title, string filters, Action<bool, List<string>> callback, int selectionCountMax, string? startPath, public void OpenFilePicker(string title, string filters, Action<bool, List<string>> callback, int selectionCountMax, string? startPath,
@ -108,11 +112,8 @@ public class FileDialogService : IDisposable, IUiService
return path; return path;
} }
// TODO: maybe change this from reflection when its public.
private string GetCurrentLocation() private string GetCurrentLocation()
=> (_manager.GetType().GetField("dialog", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(_manager) as FileDialog) => (_dialogGetter?.Invoke(_manager) as FileDialog)?.GetCurrentPath() ?? ".";
?.GetCurrentPath()
?? ".";
/// <summary> Set up the file selector with the right flags and custom side bar items. </summary> /// <summary> Set up the file selector with the right flags and custom side bar items. </summary>
private static FileDialogManager SetupFileManager(string modDirectory) private static FileDialogManager SetupFileManager(string modDirectory)
@ -122,10 +123,10 @@ public class FileDialogService : IDisposable, IUiService
AddedWindowFlags = ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoDocking, AddedWindowFlags = ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoDocking,
}; };
if (Functions.GetDownloadsFolder(out var downloadsFolder)) if (WindowsFunctions.GetDownloadsFolder(out var downloadsFolder))
fileManager.CustomSideBarItems.Add(("Downloads", downloadsFolder, FontAwesomeIcon.Download, -1)); fileManager.CustomSideBarItems.Add(("Downloads", downloadsFolder, FontAwesomeIcon.Download, -1));
if (Functions.GetQuickAccessFolders(out var folders)) if (WindowsFunctions.GetQuickAccessFolders(out var folders))
foreach (var (idx, (name, path)) in folders.Index()) foreach (var (idx, (name, path)) in folders.Index())
fileManager.CustomSideBarItems.Add(($"{name}##{idx}", path, FontAwesomeIcon.Folder, -1)); fileManager.CustomSideBarItems.Add(($"{name}##{idx}", path, FontAwesomeIcon.Folder, -1));

View file

@ -1,33 +1,33 @@
using Dalamud.Interface.Windowing; using ImSharp;
using Dalamud.Bindings.ImGui; using Luna;
using OtterGui.Raii;
using Penumbra.Import.Structs; using Penumbra.Import.Structs;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
namespace Penumbra.UI; namespace Penumbra.UI;
/// <summary> Draw the progress information for import. </summary> /// <summary> Draw the progress information for import. </summary>
public sealed class ImportPopup : Window, Luna.IUiService public sealed class ImportPopup : Window, IUiService
{ {
public const string WindowLabel = "Penumbra Import Status"; public const string WindowLabel = "Penumbra Import Status";
private readonly ModImportManager _modImportManager; private readonly ModImportManager _modImportManager;
private static readonly Vector2 OneHalf = Vector2.One / 2;
public bool WasDrawn { get; private set; } public bool WasDrawn { get; private set; }
public bool PopupWasDrawn { get; private set; } public bool PopupWasDrawn { get; private set; }
public ImportPopup(ModImportManager modImportManager) public ImportPopup(ModImportManager modImportManager)
: base(WindowLabel, : base(WindowLabel,
ImGuiWindowFlags.NoCollapse WindowFlags.NoCollapse
| ImGuiWindowFlags.NoDecoration | WindowFlags.NoDecoration
| ImGuiWindowFlags.NoBackground | WindowFlags.NoBackground
| ImGuiWindowFlags.NoMove | WindowFlags.NoMove
| ImGuiWindowFlags.NoInputs | WindowFlags.NoInputs
| ImGuiWindowFlags.NoNavFocus | WindowFlags.NoNavFocus
| ImGuiWindowFlags.NoFocusOnAppearing | WindowFlags.NoFocusOnAppearing
| ImGuiWindowFlags.NoBringToFrontOnFocus | WindowFlags.NoBringToFrontOnFocus
| ImGuiWindowFlags.NoDocking | WindowFlags.NoDocking
| ImGuiWindowFlags.NoTitleBar, true) | WindowFlags.NoTitleBar, true)
{ {
_modImportManager = modImportManager; _modImportManager = modImportManager;
DisableWindowSounds = true; DisableWindowSounds = true;
@ -55,29 +55,28 @@ public sealed class ImportPopup : Window, Luna.IUiService
if (!_modImportManager.IsImporting(out var import)) if (!_modImportManager.IsImporting(out var import))
return; return;
const string importPopup = "##PenumbraImportPopup"; if (!Im.Popup.IsOpen("##PenumbraImportPopup"u8))
if (!ImGui.IsPopupOpen(importPopup)) Im.Popup.Open("##PenumbraImportPopup"u8);
ImGui.OpenPopup(importPopup);
var display = ImGui.GetIO().DisplaySize; var display = Im.Io.DisplaySize;
var height = Math.Max(display.Y / 4, 15 * ImGui.GetFrameHeightWithSpacing()); var height = Math.Max(display.Y / 4, 15 * Im.Style.FrameHeightWithSpacing);
var width = display.X / 8; var width = display.X / 8;
var size = new Vector2(width * 2, height); var size = new Vector2(width * 2, height);
ImGui.SetNextWindowPos(ImGui.GetMainViewport().GetCenter(), ImGuiCond.Always, Vector2.One / 2); Im.Window.SetNextPosition(Im.Viewport.Main.Center, Condition.Always, OneHalf);
ImGui.SetNextWindowSize(size); Im.Window.SetNextSize(size);
using var popup = ImRaii.Popup(importPopup, ImGuiWindowFlags.Modal); using var popup = Im.Popup.Begin("##PenumbraImportPopup"u8, WindowFlags.Modal);
PopupWasDrawn = true; PopupWasDrawn = true;
var terminate = false; var terminate = false;
using (var child = ImRaii.Child("##import", new Vector2(-1, size.Y - ImGui.GetFrameHeight() * 2))) using (var child = Im.Child.Begin("##import"u8, new Vector2(-1, size.Y - Im.Style.FrameHeight * 2)))
{ {
if (child.Success && import.DrawProgressInfo(new Vector2(-1, ImGui.GetFrameHeight()))) if (child.Success && import.DrawProgressInfo(new Vector2(-1, Im.Style.FrameHeight)))
if (!ImGui.IsMouseHoveringRect(ImGui.GetWindowPos(), ImGui.GetWindowPos() + ImGui.GetWindowSize()) if (!Im.Mouse.IsHoveringRectangle(Rectangle.FromSize(Im.Window.Position, Im.Window.Size))
&& ImGui.IsMouseClicked(ImGuiMouseButton.Left)) && Im.Mouse.IsClicked(MouseButton.Left))
terminate = true; terminate = true;
} }
terminate |= import.State == ImporterState.Done terminate |= import.State == ImporterState.Done
? ImGui.Button("Close", -Vector2.UnitX) ? Im.Button("Close"u8, -Vector2.UnitX)
: import.DrawCancelButton(-Vector2.UnitX); : import.DrawCancelButton(-Vector2.UnitX);
if (terminate) if (terminate)
_modImportManager.ClearImport(); _modImportManager.ClearImport();

View file

@ -13,7 +13,7 @@ public class IncognitoService(TutorialService tutorial, Configuration config) :
{ {
var hold = config.IncognitoModifier.IsActive(); var hold = config.IncognitoModifier.IsActive();
var color = ColorId.FolderExpanded.Value(); var color = ColorId.FolderExpanded.Value();
using (new Im.ColorStyleDisposable().PushBorder(ImStyleBorder.Frame, color)) using (ImStyleBorder.Frame.Push(color))
{ {
var tt = IncognitoMode ? "Toggle incognito mode off."u8 : "Toggle incognito mode on."u8; var tt = IncognitoMode ? "Toggle incognito mode off."u8 : "Toggle incognito mode on."u8;
var icon = IncognitoMode ? LunaStyle.IncognitoOn : LunaStyle.IncognitoOff; var icon = IncognitoMode ? LunaStyle.IncognitoOn : LunaStyle.IncognitoOff;

View file

@ -1,13 +1,11 @@
using Dalamud.Interface.Utility.Raii; using ImSharp;
using Dalamud.Interface.Windowing; using Luna;
using Dalamud.Bindings.ImGui;
using OtterGui.Text;
using Penumbra.String; using Penumbra.String;
namespace Penumbra.UI.Knowledge; namespace Penumbra.UI.Knowledge;
/// <summary> Draw the progress information for import. </summary> /// <summary> Draw the progress information for import. </summary>
public sealed class KnowledgeWindow : Window, Luna.IUiService public sealed class KnowledgeWindow : Window, IUiService
{ {
private readonly IReadOnlyList<IKnowledgeTab> _tabs = private readonly IReadOnlyList<IKnowledgeTab> _tabs =
[ [
@ -31,21 +29,21 @@ public sealed class KnowledgeWindow : Window, Luna.IUiService
public override void Draw() public override void Draw()
{ {
DrawSelector(); DrawSelector();
ImUtf8.SameLineInner(); Im.Line.SameInner();
DrawMain(); DrawMain();
} }
private void DrawSelector() private void DrawSelector()
{ {
using var group = ImUtf8.Group(); using var group = Im.Group();
using (ImRaii.PushStyle(ImGuiStyleVar.FrameRounding, 0).Push(ImGuiStyleVar.ItemSpacing, Vector2.Zero)) using (ImStyleSingle.FrameRounding.Push(0).Push(ImStyleDouble.ItemSpacing, Vector2.Zero))
{ {
ImGui.SetNextItemWidth(200 * ImUtf8.GlobalScale); Im.Item.SetNextWidthScaled(200);
if (ImUtf8.InputText("##Filter"u8, _filterStore, out TerminatedByteString filter, "Filter..."u8)) if (Im.Input.Text("##Filter"u8, _filterStore, out ulong length, "Filter..."u8))
_lower = ByteString.FromSpanUnsafe(filter, true, null, null).AsciiToLowerClone(); _lower = ByteString.FromSpanUnsafe(_filterStore.AsSpan(0, (int)length), true, null, null).AsciiToLowerClone();
} }
using var child = ImUtf8.Child("KnowledgeSelector"u8, new Vector2(200 * ImUtf8.GlobalScale, ImGui.GetContentRegionAvail().Y), true); using var child = Im.Child.Begin("KnowledgeSelector"u8, Im.ContentRegion.Available with { X = 200 * Im.Style.GlobalScale }, true);
if (!child) if (!child)
return; return;
@ -54,21 +52,20 @@ public sealed class KnowledgeWindow : Window, Luna.IUiService
if (!_lower.IsEmpty && tab.SearchTags.IndexOf(_lower.Span) < 0) if (!_lower.IsEmpty && tab.SearchTags.IndexOf(_lower.Span) < 0)
continue; continue;
if (ImUtf8.Selectable(tab.Name, _selected == tab)) if (Im.Selectable(tab.Name, _selected == tab))
_selected = tab; _selected = tab;
} }
} }
private void DrawMain() private void DrawMain()
{ {
using var group = ImUtf8.Group(); using var group = Im.Group();
using (ImRaii.PushStyle(ImGuiStyleVar.FrameRounding, 0).Push(ImGuiStyleVar.ItemSpacing, Vector2.Zero)) using (ImStyleSingle.FrameRounding.Push(0).Push(ImStyleDouble.ItemSpacing, Vector2.Zero))
{ {
ImUtf8.TextFramed(_selected == null ? "No Selection"u8 : _selected.Name, ImGui.GetColorU32(ImGuiCol.FrameBg), ImEx.TextFramed(_selected == null ? "No Selection"u8 : _selected.Name, Im.ContentRegion.Available with { Y = 0 });
new Vector2(ImGui.GetContentRegionAvail().X, 0));
} }
using var child = ImUtf8.Child("KnowledgeMain"u8, ImGui.GetContentRegionAvail(), true); using var child = Im.Child.Begin("KnowledgeMain"u8, Im.ContentRegion.Available, true);
if (!child || _selected == null) if (!child || _selected == null)
return; return;

View file

@ -1,11 +1,9 @@
using Dalamud.Bindings.ImGui;
using ImSharp; using ImSharp;
using OtterGui.Text;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
namespace Penumbra.UI.Knowledge; namespace Penumbra.UI.Knowledge;
public sealed class RaceCodeTab() : IKnowledgeTab public sealed class RaceCodeTab : IKnowledgeTab
{ {
public ReadOnlySpan<byte> Name public ReadOnlySpan<byte> Name
=> "Race Codes"u8; => "Race Codes"u8;
@ -15,69 +13,65 @@ public sealed class RaceCodeTab() : IKnowledgeTab
public void Draw() public void Draw()
{ {
var size = new Vector2((ImGui.GetContentRegionAvail().X - ImUtf8.ItemSpacing.X) / 2, 0); var size = new Vector2((Im.ContentRegion.Available.X - Im.Style.ItemSpacing.X) / 2, 0);
using (var table = ImUtf8.Table("adults"u8, 4, ImGuiTableFlags.BordersOuter, size)) using (var table = Im.Table.Begin("adults"u8, 4, TableFlags.BordersOuter, size))
{ {
if (!table) if (!table)
return; return;
DrawHeaders(); DrawHeaders(table);
foreach (var gr in Enum.GetValues<GenderRace>()) foreach (var gr in Enum.GetValues<GenderRace>())
{ {
var (gender, race) = gr.Split(); var (gender, race) = gr.Split();
if (gender is not Gender.Male and not Gender.Female || race is ModelRace.Unknown) if (gender is not Gender.Male and not Gender.Female || race is ModelRace.Unknown)
continue; continue;
DrawRow(gender, race, false); DrawRow(table, gender, race, false);
} }
} }
Im.Line.Same(); Im.Line.Same();
using (var table = ImUtf8.Table("children"u8, 4, ImGuiTableFlags.BordersOuter, size)) using (var table = Im.Table.Begin("children"u8, 4, TableFlags.BordersOuter, size))
{ {
if (!table) if (!table)
return; return;
DrawHeaders(); DrawHeaders(table);
foreach (var race in (ReadOnlySpan<ModelRace>) foreach (var race in (ReadOnlySpan<ModelRace>)
[ModelRace.Midlander, ModelRace.Elezen, ModelRace.Miqote, ModelRace.AuRa, ModelRace.Unknown]) [ModelRace.Midlander, ModelRace.Elezen, ModelRace.Miqote, ModelRace.AuRa, ModelRace.Unknown])
{ {
foreach (var gender in (ReadOnlySpan<Gender>) [Gender.Male, Gender.Female]) foreach (var gender in (ReadOnlySpan<Gender>)[Gender.Male, Gender.Female])
DrawRow(gender, race, true); DrawRow(table, gender, race, true);
} }
} }
return; return;
static void DrawHeaders() static void DrawHeaders(in Im.TableDisposable table)
{ {
ImGui.TableNextColumn(); table.NextColumn();
ImUtf8.TableHeader("Race"u8); table.Header("Race"u8);
ImGui.TableNextColumn(); table.NextColumn();
ImUtf8.TableHeader("Gender"u8); table.Header("Gender"u8);
ImGui.TableNextColumn(); table.NextColumn();
ImUtf8.TableHeader("Age"u8); table.Header("Age"u8);
ImGui.TableNextColumn(); table.NextColumn();
ImUtf8.TableHeader("Race Code"u8); table.Header("Race Code"u8);
} }
static void DrawRow(Gender gender, ModelRace race, bool child) static void DrawRow(in Im.TableDisposable table, Gender gender, ModelRace race, bool child)
{ {
var gr = child var gr = child
? Names.CombinedRace(gender is Gender.Male ? Gender.MaleNpc : Gender.FemaleNpc, race) ? Names.CombinedRace(gender is Gender.Male ? Gender.MaleNpc : Gender.FemaleNpc, race)
: Names.CombinedRace(gender, race); : Names.CombinedRace(gender, race);
ImGui.TableNextColumn();
ImUtf8.Text(race.ToName());
ImGui.TableNextColumn(); table.DrawColumn(race.ToNameU8());
ImUtf8.Text(gender.ToName()); table.DrawColumn(gender.ToNameU8());
table.DrawColumn(child ? "Child"u8 : "Adult"u8);
ImGui.TableNextColumn(); table.NextColumn();
ImUtf8.Text(child ? "Child"u8 : "Adult"u8); ImEx.CopyOnClickSelectable(gr.ToRaceCode());
ImGui.TableNextColumn();
ImUtf8.CopyOnClickSelectable(gr.ToRaceCode());
} }
} }
} }

View file

@ -3,6 +3,7 @@ using Dalamud.Interface.DragDrop;
using Dalamud.Interface.ImGuiNotification; using Dalamud.Interface.ImGuiNotification;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using Dalamud.Bindings.ImGui; using Dalamud.Bindings.ImGui;
using ImSharp;
using Luna; using Luna;
using OtterGui; using OtterGui;
using OtterGui.Filesystem; using OtterGui.Filesystem;
@ -186,13 +187,13 @@ public sealed class ModFileSystemSelector : FileSystemSelector<Mod, ModFileSyste
=> _config.SortMode; => _config.SortMode;
protected override uint ExpandedFolderColor protected override uint ExpandedFolderColor
=> ColorId.FolderExpanded.Value(); => ColorId.FolderExpanded.Value().Color;
protected override uint CollapsedFolderColor protected override uint CollapsedFolderColor
=> ColorId.FolderCollapsed.Value(); => ColorId.FolderCollapsed.Value().Color;
protected override uint FolderLineColor protected override uint FolderLineColor
=> ColorId.FolderLine.Value(); => ColorId.FolderLine.Value().Color;
protected override bool FoldersDefaultOpen protected override bool FoldersDefaultOpen
=> _config.OpenFoldersByDefault; => _config.OpenFoldersByDefault;
@ -218,8 +219,8 @@ public sealed class ModFileSystemSelector : FileSystemSelector<Mod, ModFileSyste
protected override void DrawLeafName(FileSystem<Mod>.Leaf leaf, in ModState state, bool selected) protected override void DrawLeafName(FileSystem<Mod>.Leaf leaf, in ModState state, bool selected)
{ {
var flags = selected ? ImGuiTreeNodeFlags.Selected | LeafFlags : LeafFlags; var flags = selected ? ImGuiTreeNodeFlags.Selected | LeafFlags : LeafFlags;
using var c = ImRaii.PushColor(ImGuiCol.Text, state.Color.Tinted(state.Tint)) using var c = ImGuiColor.Text.Push(state.Color.Value().Tinted(state.Tint.Value()))
.Push(ImGuiCol.HeaderHovered, 0x4000FFFF, leaf.Value.Favorite); .Push(ImGuiColor.HeaderHovered, 0x4000FFFF, leaf.Value.Favorite);
using var id = ImUtf8.PushId(leaf.Value.Index); using var id = ImUtf8.PushId(leaf.Value.Index);
ImUtf8.TreeNode(leaf.Value.Name, flags).Dispose(); ImUtf8.TreeNode(leaf.Value.Name, flags).Dispose();
if (ImGui.IsItemClicked(ImGuiMouseButton.Middle)) if (ImGui.IsItemClicked(ImGuiMouseButton.Middle))
@ -265,7 +266,7 @@ public sealed class ModFileSystemSelector : FileSystemSelector<Mod, ModFileSyste
offset -= ImGui.GetStyle().ItemInnerSpacing.X; offset -= ImGui.GetStyle().ItemInnerSpacing.X;
if (offset > ImGui.GetStyle().ItemSpacing.X) if (offset > ImGui.GetStyle().ItemSpacing.X)
ImGui.GetWindowDrawList().AddText(new Vector2(itemPos + offset, line), ColorId.SelectorPriority.Value(), priorityString); ImGui.GetWindowDrawList().AddText(new Vector2(itemPos + offset, line), ColorId.SelectorPriority.Value().Color, priorityString);
} }
} }
@ -456,17 +457,17 @@ public sealed class ModFileSystemSelector : FileSystemSelector<Mod, ModFileSyste
ImUtf8.BulletText("Select a mod to obtain more information or change settings."u8); ImUtf8.BulletText("Select a mod to obtain more information or change settings."u8);
ImUtf8.BulletText("Names are colored according to your config and their current state in the collection:"u8); ImUtf8.BulletText("Names are colored according to your config and their current state in the collection:"u8);
indent.Push(); indent.Push();
ImUtf8.BulletTextColored(ColorId.EnabledMod.Value(), "enabled in the current collection."u8); ImUtf8.BulletTextColored(ColorId.EnabledMod.Value().Color, "enabled in the current collection."u8);
ImUtf8.BulletTextColored(ColorId.DisabledMod.Value(), "disabled in the current collection."u8); ImUtf8.BulletTextColored(ColorId.DisabledMod.Value().Color, "disabled in the current collection."u8);
ImUtf8.BulletTextColored(ColorId.InheritedMod.Value(), "enabled due to inheritance from another collection."u8); ImUtf8.BulletTextColored(ColorId.InheritedMod.Value().Color, "enabled due to inheritance from another collection."u8);
ImUtf8.BulletTextColored(ColorId.InheritedDisabledMod.Value(), "disabled due to inheritance from another collection."u8); ImUtf8.BulletTextColored(ColorId.InheritedDisabledMod.Value().Color, "disabled due to inheritance from another collection."u8);
ImUtf8.BulletTextColored(ColorId.UndefinedMod.Value(), "unconfigured in all inherited collections."u8); ImUtf8.BulletTextColored(ColorId.UndefinedMod.Value().Color, "unconfigured in all inherited collections."u8);
ImUtf8.BulletTextColored(ColorId.HandledConflictMod.Value(), ImUtf8.BulletTextColored(ColorId.HandledConflictMod.Value().Color,
"enabled and conflicting with another enabled Mod, but on different priorities (i.e. the conflict is solved)."u8); "enabled and conflicting with another enabled Mod, but on different priorities (i.e. the conflict is solved)."u8);
ImUtf8.BulletTextColored(ColorId.ConflictingMod.Value(), ImUtf8.BulletTextColored(ColorId.ConflictingMod.Value().Color,
"enabled and conflicting with another enabled Mod on the same priority."u8); "enabled and conflicting with another enabled Mod on the same priority."u8);
ImUtf8.BulletTextColored(ColorId.FolderExpanded.Value(), "expanded mod folder."u8); ImUtf8.BulletTextColored(ColorId.FolderExpanded.Value().Color, "expanded mod folder."u8);
ImUtf8.BulletTextColored(ColorId.FolderCollapsed.Value(), "collapsed mod folder"u8); ImUtf8.BulletTextColored(ColorId.FolderCollapsed.Value().Color, "collapsed mod folder"u8);
indent.Pop(1); indent.Pop(1);
ImUtf8.BulletText("Middle-click a mod to disable it if it is enabled or enable it if it is disabled."u8); ImUtf8.BulletText("Middle-click a mod to disable it if it is enabled or enable it if it is disabled."u8);
indent.Push(); indent.Push();

View file

@ -124,7 +124,7 @@ public class ModPanelCollectionsTab(CollectionManager manager, ModFileSystemSele
: settings.Enabled : settings.Enabled
? (parent == collection ? enabled : inherited, ModState.Enabled) ? (parent == collection ? enabled : inherited, ModState.Enabled)
: (parent == collection ? disabled : disInherited, ModState.Disabled); : (parent == collection ? disabled : disInherited, ModState.Disabled);
_cache.Add((collection, parent, color, text)); _cache.Add((collection, parent, color.Color, text));
if (color == enabled) if (color == enabled)
++directCount; ++directCount;

View file

@ -75,7 +75,7 @@ public class ModPanelSettingsTab(
if (!_temporary) if (!_temporary)
return; return;
using var color = ImRaii.PushColor(ImGuiCol.Button, ImGuiCol.Button.Tinted(ColorId.TemporaryModSettingsTint)); using var color = ImGuiColor.Button.Push(Rgba32.TintColor(Im.Style[ImGuiColor.Button], ColorId.TemporaryModSettingsTint.Value().ToVector()));
var width = new Vector2(ImGui.GetContentRegionAvail().X, 0); var width = new Vector2(ImGui.GetContentRegionAvail().X, 0);
if (ImUtf8.ButtonEx($"These settings are temporarily set by {selection.TemporarySettings!.Source}{(_locked ? " and locked." : ".")}", if (ImUtf8.ButtonEx($"These settings are temporarily set by {selection.TemporarySettings!.Source}{(_locked ? " and locked." : ".")}",
width, width,

View file

@ -1,13 +1,8 @@
using Dalamud.Bindings.ImGui; using Dalamud.Interface.ImGuiNotification;
using Dalamud.Interface;
using Dalamud.Interface.ImGuiNotification;
using ImSharp; using ImSharp;
using Luna; using Luna;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using OtterGui;
using OtterGui.Raii;
using OtterGui.Text;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using Penumbra.Services; using Penumbra.Services;
@ -116,17 +111,15 @@ public sealed class PredefinedTagManager : ISavable, IReadOnlyList<string>, ISer
public void DrawToggleButton() public void DrawToggleButton()
{ {
using var color = ImRaii.PushColor(ImGuiCol.Button, ImGui.GetColorU32(ImGuiCol.ButtonActive), _isListOpen); using var color = ImGuiColor.Button.Push(Im.Style[ImGuiColor.ButtonActive], _isListOpen);
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Tags.ToIconString(), new Vector2(ImGui.GetFrameHeight()), if (ImEx.Icon.Button(LunaStyle.TagsMarker, "Add Predefined Tags..."u8))
"Add Predefined Tags...", false, true))
_isListOpen = !_isListOpen; _isListOpen = !_isListOpen;
} }
private void DrawToggleButtonTopRight() private void DrawToggleButtonTopRight()
{ {
ImGui.SameLine(ImGui.GetContentRegionMax().X var scrollBar = Im.Scroll.MaximumY > 0 ? Im.Style.ItemInnerSpacing.X : 0;
- ImGui.GetFrameHeight() Im.Line.Same(Im.ContentRegion.Maximum.X - Im.Style.FrameHeight - scrollBar);
- (ImGui.GetScrollMaxY() > 0 ? ImGui.GetStyle().ItemInnerSpacing.X : 0));
DrawToggleButton(); DrawToggleButton();
} }
@ -139,8 +132,8 @@ public sealed class PredefinedTagManager : ISavable, IReadOnlyList<string>, ISer
if (!_isListOpen) if (!_isListOpen)
return false; return false;
ImUtf8.Text("Predefined Tags"u8); Im.Text("Predefined Tags"u8);
ImGui.Separator(); Im.Separator();
var ret = false; var ret = false;
_enabledColor = ColorId.PredefinedTagAdd.Value(); _enabledColor = ColorId.PredefinedTagAdd.Value();
@ -159,8 +152,8 @@ public sealed class PredefinedTagManager : ISavable, IReadOnlyList<string>, ISer
Im.Line.Same(); Im.Line.Same();
} }
ImGui.NewLine(); Im.Line.New();
ImGui.Separator(); Im.Separator();
return ret; return ret;
} }
@ -181,12 +174,12 @@ public sealed class PredefinedTagManager : ISavable, IReadOnlyList<string>, ISer
if (!_isListOpen) if (!_isListOpen)
return; return;
ImUtf8.Text("Predefined Tags"u8); Im.Text("Predefined Tags"u8);
PrepareLists(selection); PrepareLists(selection);
_enabledColor = ColorId.PredefinedTagAdd.Value(); _enabledColor = ColorId.PredefinedTagAdd.Value();
_disabledColor = ColorId.PredefinedTagRemove.Value(); _disabledColor = ColorId.PredefinedTagRemove.Value();
using var color = new ImRaii.Color(); using var color = new Im.ColorDisposable();
foreach (var (idx, tag) in _predefinedTags.Keys.Index()) foreach (var (idx, tag) in _predefinedTags.Keys.Index())
{ {
var alreadyContained = 0; var alreadyContained = 0;
@ -217,22 +210,22 @@ public sealed class PredefinedTagManager : ISavable, IReadOnlyList<string>, ISer
} }
} }
using var id = ImRaii.PushId(idx); using var id = Im.Id.Push(idx);
var buttonWidth = CalcTextButtonWidth(tag); var buttonWidth = new Vector2(Im.Font.CalculateButtonSize(tag).X, 0);
// Prevent adding a new tag past the right edge of the popup // Prevent adding a new tag past the right edge of the popup
if (buttonWidth + ImGui.GetStyle().ItemSpacing.X >= ImGui.GetContentRegionAvail().X) if (buttonWidth.X + Im.Style.ItemSpacing.X >= Im.ContentRegion.Available.X)
ImGui.NewLine(); Im.Line.New();
var (usedColor, disabled, tt) = (missing, alreadyContained) switch var (usedColor, disabled, tt) = (missing, alreadyContained) switch
{ {
(> 0, _) => (_enabledColor, false, (> 0, _) => (_enabledColor, false,
$"Add this tag to {missing} mods.{(inModData > 0 ? $" {inModData} mods contain it in their mod tags and are untouched." : string.Empty)}"), new StringU8($"Add this tag to {missing} mods.{(inModData > 0 ? $" {inModData} mods contain it in their mod tags and are untouched." : string.Empty)}")),
(_, > 0) => (_disabledColor, false, (_, > 0) => (_disabledColor, false,
$"Remove this tag from {alreadyContained} mods.{(inModData > 0 ? $" {inModData} mods contain it in their mod tags and are untouched." : string.Empty)}"), new StringU8($"Remove this tag from {alreadyContained} mods.{(inModData > 0 ? $" {inModData} mods contain it in their mod tags and are untouched." : string.Empty)}")),
_ => (_disabledColor, true, "This tag is already present in the mod tags of all selected mods."), _ => (_disabledColor, true, new StringU8("This tag is already present in the mod tags of all selected mods.")),
}; };
color.Push(ImGuiCol.Button, usedColor); color.Push(ImGuiColor.Button, usedColor);
if (ImUtf8.ButtonEx(tag, tt, new Vector2(buttonWidth, 0), disabled)) if (ImEx.Button(tag, buttonWidth, tt, disabled))
{ {
if (missing > 0) if (missing > 0)
foreach (var (mod, (localIdx, _)) in _selectedMods.Zip(_countedMods)) foreach (var (mod, (localIdx, _)) in _selectedMods.Zip(_countedMods))
@ -256,34 +249,30 @@ public sealed class PredefinedTagManager : ISavable, IReadOnlyList<string>, ISer
color.Pop(); color.Pop();
} }
ImGui.NewLine(); Im.Line.New();
} }
private bool DrawColoredButton(string buttonLabel, int index, int tagIdx, bool inOther) private bool DrawColoredButton(string buttonLabel, int index, int tagIdx, bool inOther)
{ {
using var id = ImRaii.PushId(index); using var id = Im.Id.Push(index);
var buttonWidth = CalcTextButtonWidth(buttonLabel); var buttonWidth = Im.Font.CalculateButtonSize(buttonLabel).X;
// Prevent adding a new tag past the right edge of the popup // Prevent adding a new tag past the right edge of the popup
if (buttonWidth + ImGui.GetStyle().ItemSpacing.X >= ImGui.GetContentRegionAvail().X) if (buttonWidth + Im.Style.ItemSpacing.X >= Im.ContentRegion.Available.X)
ImGui.NewLine(); Im.Line.New();
bool ret; bool ret;
using (ImRaii.Disabled(inOther)) using (Im.Disabled(inOther))
{ {
using var color = ImRaii.PushColor(ImGuiCol.Button, tagIdx >= 0 || inOther ? _disabledColor : _enabledColor); using var color = ImGuiColor.Button.Push(tagIdx >= 0 || inOther ? _disabledColor : _enabledColor);
ret = ImGui.Button(buttonLabel); ret = Im.Button(buttonLabel);
} }
if (inOther && ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled)) if (inOther)
ImGui.SetTooltip("This tag is already present in the other set of tags."); Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, "This tag is already present in the other set of tags."u8);
return ret; return ret;
} }
private static float CalcTextButtonWidth(string text)
=> ImGui.CalcTextSize(text).X + 2 * ImGui.GetStyle().FramePadding.X;
public IEnumerator<string> GetEnumerator() public IEnumerator<string> GetEnumerator()
=> _predefinedTags.Keys.GetEnumerator(); => _predefinedTags.Keys.GetEnumerator();

View file

@ -2,7 +2,6 @@ using Dalamud.Bindings.ImGui;
using FFXIVClientStructs.FFXIV.Client.Game.Object; using FFXIVClientStructs.FFXIV.Client.Game.Object;
using FFXIVClientStructs.FFXIV.Client.System.Resource; using FFXIVClientStructs.FFXIV.Client.System.Resource;
using ImSharp; using ImSharp;
using OtterGui.Raii;
using OtterGui.Widgets; using OtterGui.Widgets;
using Penumbra.Api.Enums; using Penumbra.Api.Enums;
using Penumbra.Collections; using Penumbra.Collections;
@ -144,8 +143,7 @@ public sealed class ResourceWatcher : IDisposable, ITab, Luna.IUiService
Im.Item.SetNextWidth(Im.ContentRegion.Available.X); Im.Item.SetNextWidth(Im.ContentRegion.Available.X);
var tmp = _logFilter; var tmp = _logFilter;
var invalidRegex = _logRegex is null && _logFilter.Length > 0; var invalidRegex = _logRegex is null && _logFilter.Length > 0;
using var color = using var color = ImStyleBorder.Frame.Push(Colors.RegexWarningBorder, Im.Style.GlobalScale, invalidRegex);
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)) if (Im.Input.Text("##logFilter"u8, ref tmp, "If path matches this Regex..."u8))
UpdateFilter(tmp, true); UpdateFilter(tmp, true);
} }