mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 10:17:22 +01:00
Update UIDebug2, ImGuiComponents, ImGuiHelpers (#2081)
* Update ImGuiComponents & ImGuiHelpers Took some helper functions created for `UiDebug2`, and incorporated them into `ImGuiComponents` / `ImGuiHelpers` instead - `IconButton()` (and its various overloads) now includes an optional size parameter - `IconButtonSelect()` has been added, allowing a row or grid of IconButtons to serve as a radio-like input - `HelpMarker()` now includes an optional color parameter - `ClickToCopyText()` now includes an optional color parameter, and includes the `FontAwesome.Copy` icon in the tooltip. - Implemented ImRaii in these files These changes are intended not to break any existing calls in plugins or within Dalamud itself. * Fix ambiguous overloads * UiDebug2 Updates - Fixed XY coordinate display - Added AtkValue table to AddonTree display - Restored old behaviour wherein the Addon display initially only shows the Root node and a collapsed node list - The above should also fix the Element Selector / Search behaviour, allowing it to scroll correctly to the searched node - Now displays field offsets for any node/component whose pointer exists in the addon struct - Tidied up node tree headers by removing memory addresses (they're still readable in the opened tree, of course)
This commit is contained in:
parent
94f16ac16e
commit
ee63f60877
18 changed files with 649 additions and 278 deletions
|
|
@ -1,6 +1,8 @@
|
|||
using System.Numerics;
|
||||
|
||||
using Dalamud.Interface.Utility;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.Components;
|
||||
|
|
@ -41,7 +43,9 @@ public static partial class ImGuiComponents
|
|||
ImGui.OpenPopup($"###ColorPickerPopup{id}");
|
||||
}
|
||||
|
||||
if (ImGui.BeginPopup($"###ColorPickerPopup{id}"))
|
||||
using var popup = ImRaii.Popup($"###ColorPickerPopup{id}");
|
||||
|
||||
if (popup)
|
||||
{
|
||||
if (ImGui.ColorPicker4($"###ColorPicker{id}", ref existingColor, flags))
|
||||
{
|
||||
|
|
@ -61,8 +65,6 @@ public static partial class ImGuiComponents
|
|||
ImGui.SameLine();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
|
||||
return selectedColor;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
using System.Numerics;
|
||||
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.Components;
|
||||
|
|
@ -21,17 +23,16 @@ public static partial class ImGuiComponents
|
|||
/// <returns>Indicator if button is clicked.</returns>
|
||||
public static bool DisabledButton(FontAwesomeIcon icon, int? id = null, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null, float alphaMult = .5f)
|
||||
{
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
|
||||
using (ImRaii.PushFont(UiBuilder.IconFont))
|
||||
{
|
||||
var text = icon.ToIconString();
|
||||
if (id.HasValue)
|
||||
{
|
||||
text = $"{text}##{id}";
|
||||
}
|
||||
|
||||
var button = DisabledButton(text, defaultColor, activeColor, hoveredColor, alphaMult);
|
||||
|
||||
ImGui.PopFont();
|
||||
|
||||
return button;
|
||||
return DisabledButton(text, defaultColor, activeColor, hoveredColor, alphaMult);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -45,31 +46,28 @@ public static partial class ImGuiComponents
|
|||
/// <returns>Indicator if button is clicked.</returns>
|
||||
public static bool DisabledButton(string labelWithId, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null, float alphaMult = .5f)
|
||||
{
|
||||
using var col = new ImRaii.Color();
|
||||
|
||||
if (defaultColor.HasValue)
|
||||
ImGui.PushStyleColor(ImGuiCol.Button, defaultColor.Value);
|
||||
{
|
||||
col.Push(ImGuiCol.Button, defaultColor.Value);
|
||||
}
|
||||
|
||||
if (activeColor.HasValue)
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonActive, activeColor.Value);
|
||||
{
|
||||
col.Push(ImGuiCol.ButtonActive, activeColor.Value);
|
||||
}
|
||||
|
||||
if (hoveredColor.HasValue)
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, hoveredColor.Value);
|
||||
{
|
||||
col.Push(ImGuiCol.ButtonHovered, hoveredColor.Value);
|
||||
}
|
||||
|
||||
var style = ImGui.GetStyle();
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.Alpha, style.Alpha * alphaMult);
|
||||
|
||||
var button = ImGui.Button(labelWithId);
|
||||
|
||||
ImGui.PopStyleVar();
|
||||
|
||||
if (defaultColor.HasValue)
|
||||
ImGui.PopStyleColor();
|
||||
|
||||
if (activeColor.HasValue)
|
||||
ImGui.PopStyleColor();
|
||||
|
||||
if (hoveredColor.HasValue)
|
||||
ImGui.PopStyleColor();
|
||||
|
||||
return button;
|
||||
using (ImRaii.PushStyle(ImGuiStyleVar.Alpha, style.Alpha * alphaMult))
|
||||
{
|
||||
return ImGui.Button(labelWithId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
using Dalamud.Interface.Utility.Raii;
|
||||
|
||||
using FFXIVClientStructs.FFXIV.Common.Math;
|
||||
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.Components;
|
||||
|
|
@ -18,17 +22,32 @@ public static partial class ImGuiComponents
|
|||
/// </summary>
|
||||
/// <param name="helpText">The text to display on hover.</param>
|
||||
/// <param name="icon">The icon to use.</param>
|
||||
public static void HelpMarker(string helpText, FontAwesomeIcon icon)
|
||||
/// <param name="color">The color of the icon.</param>
|
||||
public static void HelpMarker(string helpText, FontAwesomeIcon icon, Vector4? color = null)
|
||||
{
|
||||
using var col = new ImRaii.Color();
|
||||
|
||||
if (color.HasValue)
|
||||
{
|
||||
col.Push(ImGuiCol.TextDisabled, color.Value);
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
|
||||
using (ImRaii.PushFont(UiBuilder.IconFont))
|
||||
{
|
||||
ImGui.TextDisabled(icon.ToIconString());
|
||||
ImGui.PopFont();
|
||||
if (!ImGui.IsItemHovered()) return;
|
||||
ImGui.BeginTooltip();
|
||||
ImGui.PushTextWrapPos(ImGui.GetFontSize() * 35.0f);
|
||||
}
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
using (ImRaii.Tooltip())
|
||||
{
|
||||
using (ImRaii.TextWrapPos(ImGui.GetFontSize() * 35.0f))
|
||||
{
|
||||
ImGui.TextUnformatted(helpText);
|
||||
ImGui.PopTextWrapPos();
|
||||
ImGui.EndTooltip();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
using System.Numerics;
|
||||
|
||||
using Dalamud.Interface.Utility;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.Components;
|
||||
|
|
@ -15,8 +17,26 @@ public static partial class ImGuiComponents
|
|||
/// </summary>
|
||||
/// <param name="icon">The icon for the button.</param>
|
||||
/// <returns>Indicator if button is clicked.</returns>
|
||||
public static bool IconButton(FontAwesomeIcon icon)
|
||||
=> IconButton(icon, null, null, null);
|
||||
public static bool IconButton(FontAwesomeIcon icon) => IconButton(icon, null);
|
||||
|
||||
/// <summary>
|
||||
/// IconButton component to use an icon as a button.
|
||||
/// </summary>
|
||||
/// <param name="icon">The icon for the button.</param>
|
||||
/// <param name="size">Sets the size of the button. If either dimension is set to 0, that dimension will conform to the size of the icon.</param>
|
||||
/// <returns>Indicator if button is clicked.</returns>
|
||||
public static bool IconButton(FontAwesomeIcon icon, Vector2 size) => IconButton(icon, null, null, null, size);
|
||||
|
||||
/// <summary>
|
||||
/// IconButton component to use an icon as a button.
|
||||
/// </summary>
|
||||
/// <param name="icon">The icon for the button.</param>
|
||||
/// <param name="defaultColor">The default color of the button.</param>
|
||||
/// <param name="activeColor">The color of the button when active.</param>
|
||||
/// <param name="hoveredColor">The color of the button when hovered.</param>
|
||||
/// <param name="size">Sets the size of the button. If either dimension is set to 0, that dimension will conform to the size of the icon.</param>
|
||||
/// <returns>Indicator if button is clicked.</returns>
|
||||
public static bool IconButton(FontAwesomeIcon icon, Vector4? defaultColor, Vector4? activeColor = null, Vector4? hoveredColor = null, Vector2? size = null) => IconButton($"{icon.ToIconString()}", defaultColor, activeColor, hoveredColor, size);
|
||||
|
||||
/// <summary>
|
||||
/// IconButton component to use an icon as a button.
|
||||
|
|
@ -24,8 +44,28 @@ public static partial class ImGuiComponents
|
|||
/// <param name="id">The ID of the button.</param>
|
||||
/// <param name="icon">The icon for the button.</param>
|
||||
/// <returns>Indicator if button is clicked.</returns>
|
||||
public static bool IconButton(int id, FontAwesomeIcon icon)
|
||||
=> IconButton(id, icon, null, null, null);
|
||||
public static bool IconButton(int id, FontAwesomeIcon icon) => IconButton(id, icon, null);
|
||||
|
||||
/// <summary>
|
||||
/// IconButton component to use an icon as a button.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the button.</param>
|
||||
/// <param name="icon">The icon for the button.</param>
|
||||
/// <param name="size">Sets the size of the button. If either dimension is set to 0, that dimension will conform to the size of the icon.</param>
|
||||
/// <returns>Indicator if button is clicked.</returns>
|
||||
public static bool IconButton(int id, FontAwesomeIcon icon, Vector2 size) => IconButton(id, icon, null, null, null, size);
|
||||
|
||||
/// <summary>
|
||||
/// IconButton component to use an icon as a button with color options.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the button.</param>
|
||||
/// <param name="icon">The icon for the button.</param>
|
||||
/// <param name="defaultColor">The default color of the button.</param>
|
||||
/// <param name="activeColor">The color of the button when active.</param>
|
||||
/// <param name="hoveredColor">The color of the button when hovered.</param>
|
||||
/// <param name="size">Sets the size of the button. If either dimension is set to 0, that dimension will conform to the size of the icon.</param>
|
||||
/// <returns>Indicator if button is clicked.</returns>
|
||||
public static bool IconButton(int id, FontAwesomeIcon icon, Vector4? defaultColor, Vector4? activeColor = null, Vector4? hoveredColor = null, Vector2? size = null) => IconButton($"{icon.ToIconString()}##{id}", defaultColor, activeColor, hoveredColor, size);
|
||||
|
||||
/// <summary>
|
||||
/// IconButton component to use an icon as a button.
|
||||
|
|
@ -33,51 +73,45 @@ public static partial class ImGuiComponents
|
|||
/// <param name="id">The ID of the button.</param>
|
||||
/// <param name="icon">The icon for the button.</param>
|
||||
/// <returns>Indicator if button is clicked.</returns>
|
||||
public static bool IconButton(string id, FontAwesomeIcon icon)
|
||||
=> IconButton(id, icon, null, null, null);
|
||||
public static bool IconButton(string id, FontAwesomeIcon icon) => IconButton(id, icon, null);
|
||||
|
||||
/// <summary>
|
||||
/// IconButton component to use an icon as a button.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the button.</param>
|
||||
/// <param name="icon">The icon for the button.</param>
|
||||
/// <param name="size">Sets the size of the button. If either dimension is set to 0, that dimension will conform to the size of the icon.</param>
|
||||
/// <returns>Indicator if button is clicked.</returns>
|
||||
public static bool IconButton(string id, FontAwesomeIcon icon, Vector2 size)
|
||||
=> IconButton(id, icon, null, null, null, size);
|
||||
|
||||
/// <summary>
|
||||
/// IconButton component to use an icon as a button with color options.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the button.</param>
|
||||
/// <param name="icon">The icon for the button.</param>
|
||||
/// <param name="defaultColor">The default color of the button.</param>
|
||||
/// <param name="activeColor">The color of the button when active.</param>
|
||||
/// <param name="hoveredColor">The color of the button when hovered.</param>
|
||||
/// <param name="size">Sets the size of the button. If either dimension is set to 0, that dimension will conform to the size of the icon.</param>
|
||||
/// <returns>Indicator if button is clicked.</returns>
|
||||
public static bool IconButton(string id, FontAwesomeIcon icon, Vector4? defaultColor, Vector4? activeColor = null, Vector4? hoveredColor = null, Vector2? size = null)
|
||||
=> IconButton($"{icon.ToIconString()}##{id}", defaultColor, activeColor, hoveredColor, size);
|
||||
|
||||
/// <summary>
|
||||
/// IconButton component to use an icon as a button.
|
||||
/// </summary>
|
||||
/// <param name="iconText">Text already containing the icon string.</param>
|
||||
/// <returns>Indicator if button is clicked.</returns>
|
||||
public static bool IconButton(string iconText)
|
||||
=> IconButton(iconText, null, null, null);
|
||||
public static bool IconButton(string iconText) => IconButton(iconText, null);
|
||||
|
||||
/// <summary>
|
||||
/// IconButton component to use an icon as a button.
|
||||
/// </summary>
|
||||
/// <param name="icon">The icon for the button.</param>
|
||||
/// <param name="defaultColor">The default color of the button.</param>
|
||||
/// <param name="activeColor">The color of the button when active.</param>
|
||||
/// <param name="hoveredColor">The color of the button when hovered.</param>
|
||||
/// <param name="iconText">Text already containing the icon string.</param>
|
||||
/// <param name="size">Sets the size of the button. If either dimension is set to 0, that dimension will conform to the size of the icon.</param>
|
||||
/// <returns>Indicator if button is clicked.</returns>
|
||||
public static bool IconButton(FontAwesomeIcon icon, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null)
|
||||
=> IconButton($"{icon.ToIconString()}", defaultColor, activeColor, hoveredColor);
|
||||
|
||||
/// <summary>
|
||||
/// IconButton component to use an icon as a button with color options.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the button.</param>
|
||||
/// <param name="icon">The icon for the button.</param>
|
||||
/// <param name="defaultColor">The default color of the button.</param>
|
||||
/// <param name="activeColor">The color of the button when active.</param>
|
||||
/// <param name="hoveredColor">The color of the button when hovered.</param>
|
||||
/// <returns>Indicator if button is clicked.</returns>
|
||||
public static bool IconButton(int id, FontAwesomeIcon icon, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null)
|
||||
=> IconButton($"{icon.ToIconString()}##{id}", defaultColor, activeColor, hoveredColor);
|
||||
|
||||
/// <summary>
|
||||
/// IconButton component to use an icon as a button with color options.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the button.</param>
|
||||
/// <param name="icon">The icon for the button.</param>
|
||||
/// <param name="defaultColor">The default color of the button.</param>
|
||||
/// <param name="activeColor">The color of the button when active.</param>
|
||||
/// <param name="hoveredColor">The color of the button when hovered.</param>
|
||||
/// <returns>Indicator if button is clicked.</returns>
|
||||
public static bool IconButton(string id, FontAwesomeIcon icon, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null)
|
||||
=> IconButton($"{icon.ToIconString()}##{id}", defaultColor, activeColor, hoveredColor);
|
||||
public static bool IconButton(string iconText, Vector2 size) => IconButton(iconText, null, null, null, size);
|
||||
|
||||
/// <summary>
|
||||
/// IconButton component to use an icon as a button with color options.
|
||||
|
|
@ -86,62 +120,72 @@ public static partial class ImGuiComponents
|
|||
/// <param name="defaultColor">The default color of the button.</param>
|
||||
/// <param name="activeColor">The color of the button when active.</param>
|
||||
/// <param name="hoveredColor">The color of the button when hovered.</param>
|
||||
/// <param name="size">Sets the size of the button. If either dimension is set to 0, that dimension will conform to the size of the icon.</param>
|
||||
/// <returns>Indicator if button is clicked.</returns>
|
||||
public static bool IconButton(string iconText, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null)
|
||||
public static bool IconButton(string iconText, Vector4? defaultColor, Vector4? activeColor = null, Vector4? hoveredColor = null, Vector2? size = null)
|
||||
{
|
||||
var numColors = 0;
|
||||
using var col = new ImRaii.Color();
|
||||
|
||||
if (defaultColor.HasValue)
|
||||
{
|
||||
ImGui.PushStyleColor(ImGuiCol.Button, defaultColor.Value);
|
||||
numColors++;
|
||||
col.Push(ImGuiCol.Button, defaultColor.Value);
|
||||
}
|
||||
|
||||
if (activeColor.HasValue)
|
||||
{
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonActive, activeColor.Value);
|
||||
numColors++;
|
||||
col.Push(ImGuiCol.ButtonActive, activeColor.Value);
|
||||
}
|
||||
|
||||
if (hoveredColor.HasValue)
|
||||
{
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, hoveredColor.Value);
|
||||
numColors++;
|
||||
col.Push(ImGuiCol.ButtonHovered, hoveredColor.Value);
|
||||
}
|
||||
|
||||
if (size.HasValue)
|
||||
{
|
||||
size *= ImGuiHelpers.GlobalScale;
|
||||
}
|
||||
|
||||
var icon = iconText;
|
||||
if (icon.Contains("#"))
|
||||
icon = icon[..icon.IndexOf("#", StringComparison.Ordinal)];
|
||||
if (icon.Contains('#'))
|
||||
{
|
||||
icon = icon[..icon.IndexOf('#', StringComparison.Ordinal)];
|
||||
}
|
||||
|
||||
ImGui.PushID(iconText);
|
||||
bool button;
|
||||
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
using (ImRaii.PushFont(UiBuilder.IconFont))
|
||||
{
|
||||
var iconSize = ImGui.CalcTextSize(icon);
|
||||
ImGui.PopFont();
|
||||
|
||||
var dl = ImGui.GetWindowDrawList();
|
||||
var cursor = ImGui.GetCursorScreenPos();
|
||||
|
||||
// Draw an ImGui button with the icon and text
|
||||
var buttonWidth = iconSize.X + (ImGui.GetStyle().FramePadding.X * 2);
|
||||
var buttonHeight = ImGui.GetFrameHeight();
|
||||
var button = ImGui.Button(string.Empty, new Vector2(buttonWidth, buttonHeight));
|
||||
var width = size is { X: not 0 } ? size.Value.X : iconSize.X + (ImGui.GetStyle().FramePadding.X * 2);
|
||||
var height = size is { Y: not 0 } ? size.Value.Y : ImGui.GetFrameHeight();
|
||||
|
||||
// Draw the icon on the window drawlist
|
||||
var iconPos = new Vector2(cursor.X + ImGui.GetStyle().FramePadding.X, cursor.Y + ImGui.GetStyle().FramePadding.Y);
|
||||
var buttonSize = new Vector2(width, height);
|
||||
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
dl.AddText(iconPos, ImGui.GetColorU32(ImGuiCol.Text), icon);
|
||||
ImGui.PopFont();
|
||||
using (ImRaii.PushId(iconText))
|
||||
{
|
||||
button = ImGui.Button(string.Empty, buttonSize);
|
||||
}
|
||||
|
||||
ImGui.PopID();
|
||||
var iconPos = cursor + ((buttonSize - iconSize) / 2f);
|
||||
|
||||
if (numColors > 0)
|
||||
ImGui.PopStyleColor(numColors);
|
||||
ImGui.GetWindowDrawList().AddText(iconPos, ImGui.GetColorU32(ImGuiCol.Text), icon);
|
||||
}
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IconButton component to use an icon as a button with color options.
|
||||
/// </summary>
|
||||
/// <param name="icon">Icon to show.</param>
|
||||
/// <param name="text">Text to show.</param>
|
||||
/// <param name="size">Sets the size of the button. If either dimension is set to 0, that dimension will conform to the size of the icon & text.</param>
|
||||
/// <returns>Indicator if button is clicked.</returns>
|
||||
public static bool IconButtonWithText(FontAwesomeIcon icon, string text, Vector2 size) => IconButtonWithText(icon, text, null, null, null, size);
|
||||
|
||||
/// <summary>
|
||||
/// IconButton component to use an icon as a button with color options.
|
||||
/// </summary>
|
||||
|
|
@ -150,61 +194,72 @@ public static partial class ImGuiComponents
|
|||
/// <param name="defaultColor">The default color of the button.</param>
|
||||
/// <param name="activeColor">The color of the button when active.</param>
|
||||
/// <param name="hoveredColor">The color of the button when hovered.</param>
|
||||
/// <param name="size">Sets the size of the button. If either dimension is set to 0, that dimension will conform to the size of the icon & text.</param>
|
||||
/// <returns>Indicator if button is clicked.</returns>
|
||||
public static bool IconButtonWithText(FontAwesomeIcon icon, string text, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null)
|
||||
public static bool IconButtonWithText(FontAwesomeIcon icon, string text, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null, Vector2? size = null)
|
||||
{
|
||||
var numColors = 0;
|
||||
using var col = new ImRaii.Color();
|
||||
|
||||
if (defaultColor.HasValue)
|
||||
{
|
||||
ImGui.PushStyleColor(ImGuiCol.Button, defaultColor.Value);
|
||||
numColors++;
|
||||
col.Push(ImGuiCol.Button, defaultColor.Value);
|
||||
}
|
||||
|
||||
if (activeColor.HasValue)
|
||||
{
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonActive, activeColor.Value);
|
||||
numColors++;
|
||||
col.Push(ImGuiCol.ButtonActive, activeColor.Value);
|
||||
}
|
||||
|
||||
if (hoveredColor.HasValue)
|
||||
{
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, hoveredColor.Value);
|
||||
numColors++;
|
||||
col.Push(ImGuiCol.ButtonHovered, hoveredColor.Value);
|
||||
}
|
||||
|
||||
ImGui.PushID(text);
|
||||
if (size.HasValue)
|
||||
{
|
||||
size *= ImGuiHelpers.GlobalScale;
|
||||
}
|
||||
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
var iconSize = ImGui.CalcTextSize(icon.ToIconString());
|
||||
ImGui.PopFont();
|
||||
bool button;
|
||||
|
||||
var textSize = ImGui.CalcTextSize(text);
|
||||
var dl = ImGui.GetWindowDrawList();
|
||||
var cursor = ImGui.GetCursorScreenPos();
|
||||
Vector2 iconSize;
|
||||
using (ImRaii.PushFont(UiBuilder.IconFont))
|
||||
{
|
||||
iconSize = ImGui.CalcTextSize(icon.ToIconString());
|
||||
}
|
||||
|
||||
var textStr = text;
|
||||
if (textStr.Contains('#'))
|
||||
{
|
||||
textStr = textStr[..textStr.IndexOf('#', StringComparison.Ordinal)];
|
||||
}
|
||||
|
||||
var framePadding = ImGui.GetStyle().FramePadding;
|
||||
var iconPadding = 3 * ImGuiHelpers.GlobalScale;
|
||||
|
||||
// Draw an ImGui button with the icon and text
|
||||
var buttonWidth = iconSize.X + textSize.X + (ImGui.GetStyle().FramePadding.X * 2) + iconPadding;
|
||||
var buttonHeight = ImGui.GetFrameHeight();
|
||||
var button = ImGui.Button(string.Empty, new Vector2(buttonWidth, buttonHeight));
|
||||
var cursor = ImGui.GetCursorScreenPos();
|
||||
|
||||
// Draw the icon on the window drawlist
|
||||
var iconPos = new Vector2(cursor.X + ImGui.GetStyle().FramePadding.X, cursor.Y + ImGui.GetStyle().FramePadding.Y);
|
||||
using (ImRaii.PushId(text))
|
||||
{
|
||||
var textSize = ImGui.CalcTextSize(textStr);
|
||||
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
var width = size is { X: not 0 } ? size.Value.X : iconSize.X + textSize.X + (framePadding.X * 2) + iconPadding;
|
||||
var height = size is { Y: not 0 } ? size.Value.Y : ImGui.GetFrameHeight();
|
||||
|
||||
button = ImGui.Button(string.Empty, new Vector2(width, height));
|
||||
}
|
||||
|
||||
var iconPos = cursor + framePadding;
|
||||
var textPos = new Vector2(iconPos.X + iconSize.X + iconPadding, cursor.Y + framePadding.Y);
|
||||
|
||||
var dl = ImGui.GetWindowDrawList();
|
||||
|
||||
using (ImRaii.PushFont(UiBuilder.IconFont))
|
||||
{
|
||||
dl.AddText(iconPos, ImGui.GetColorU32(ImGuiCol.Text), icon.ToIconString());
|
||||
ImGui.PopFont();
|
||||
}
|
||||
|
||||
// Draw the text on the window drawlist
|
||||
var textPos = new Vector2(iconPos.X + iconSize.X + iconPadding, cursor.Y + ImGui.GetStyle().FramePadding.Y);
|
||||
dl.AddText(textPos, ImGui.GetColorU32(ImGuiCol.Text), text);
|
||||
|
||||
ImGui.PopID();
|
||||
|
||||
if (numColors > 0)
|
||||
ImGui.PopStyleColor(numColors);
|
||||
dl.AddText(textPos, ImGui.GetColorU32(ImGuiCol.Text), textStr);
|
||||
|
||||
return button;
|
||||
}
|
||||
|
|
@ -217,16 +272,15 @@ public static partial class ImGuiComponents
|
|||
/// <returns>Width.</returns>
|
||||
internal static float GetIconButtonWithTextWidth(FontAwesomeIcon icon, string text)
|
||||
{
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
using (ImRaii.PushFont(UiBuilder.IconFont))
|
||||
{
|
||||
var iconSize = ImGui.CalcTextSize(icon.ToIconString());
|
||||
ImGui.PopFont();
|
||||
|
||||
var textSize = ImGui.CalcTextSize(text);
|
||||
var dl = ImGui.GetWindowDrawList();
|
||||
var cursor = ImGui.GetCursorScreenPos();
|
||||
|
||||
var iconPadding = 3 * ImGuiHelpers.GlobalScale;
|
||||
|
||||
return iconSize.X + textSize.X + (ImGui.GetStyle().FramePadding.X * 2) + iconPadding;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
|
||||
using Dalamud.Interface.Utility;
|
||||
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.Components;
|
||||
|
||||
public static partial class ImGuiComponents
|
||||
{
|
||||
/// <summary>
|
||||
/// A radio-like input that uses icon buttons.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the value being set.</typeparam>
|
||||
/// <param name="label">Text that will be used to generate individual labels for the buttons.</param>
|
||||
/// <param name="val">The value to set.</param>
|
||||
/// <param name="optionIcons">The icons that will be displayed on each button.</param>
|
||||
/// <param name="optionValues">The options that each button will apply.</param>
|
||||
/// <param name="columns">Arranges the buttons in a grid with the given number of columns. 0 = ignored (all buttons drawn in one row).</param>
|
||||
/// <param name="buttonSize">Sets the size of all buttons. If either dimension is set to 0, that dimension will conform to the size of the icon.</param>
|
||||
/// <param name="defaultColor">The default color of the button range.</param>
|
||||
/// <param name="activeColor">The color of the actively-selected button.</param>
|
||||
/// <param name="hoveredColor">The color of the buttons when hovered.</param>
|
||||
/// <returns>True if any button is clicked.</returns>
|
||||
internal static bool IconButtonSelect<T>(string label, ref T val, IEnumerable<FontAwesomeIcon> optionIcons, IEnumerable<T> optionValues, uint columns = 0, Vector2? buttonSize = null, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null)
|
||||
{
|
||||
var options = optionIcons.Zip(optionValues, static (icon, value) => new KeyValuePair<FontAwesomeIcon, T>(icon, value));
|
||||
return IconButtonSelect(label, ref val, options, columns, buttonSize, defaultColor, activeColor, hoveredColor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A radio-like input that uses icon buttons.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the value being set.</typeparam>
|
||||
/// <param name="label">Text that will be used to generate individual labels for the buttons.</param>
|
||||
/// <param name="val">The value to set.</param>
|
||||
/// <param name="options">A list of all icon/option pairs.</param>
|
||||
/// <param name="columns">Arranges the buttons in a grid with the given number of columns. 0 = ignored (all buttons drawn in one row).</param>
|
||||
/// <param name="buttonSize">Sets the size of all buttons. If either dimension is set to 0, that dimension will conform to the size of the icon.</param>
|
||||
/// <param name="defaultColor">The default color of the button range.</param>
|
||||
/// <param name="activeColor">The color of the actively-selected button.</param>
|
||||
/// <param name="hoveredColor">The color of the buttons when hovered.</param>
|
||||
/// <returns>True if any button is clicked.</returns>
|
||||
internal static unsafe bool IconButtonSelect<T>(string label, ref T val, IEnumerable<KeyValuePair<FontAwesomeIcon, T>> options, uint columns = 0, Vector2? buttonSize = null, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null)
|
||||
{
|
||||
defaultColor ??= *ImGui.GetStyleColorVec4(ImGuiCol.Button);
|
||||
activeColor ??= *ImGui.GetStyleColorVec4(ImGuiCol.ButtonActive);
|
||||
hoveredColor ??= *ImGui.GetStyleColorVec4(ImGuiCol.ButtonHovered);
|
||||
|
||||
var result = false;
|
||||
|
||||
var innerSpacing = ImGui.GetStyle().ItemInnerSpacing;
|
||||
var y = ImGui.GetCursorPosY();
|
||||
|
||||
var optArr = options.ToArray();
|
||||
for (var i = 0; i < optArr.Length; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
if (columns == 0 || i % columns != 0)
|
||||
{
|
||||
ImGui.SameLine(0, innerSpacing.X);
|
||||
}
|
||||
else
|
||||
{
|
||||
y += (buttonSize is { Y: not 0 } ? buttonSize.Value.Y * ImGuiHelpers.GlobalScale : ImGui.GetFrameHeight()) + innerSpacing.Y;
|
||||
|
||||
ImGui.SetCursorPosY(y);
|
||||
}
|
||||
}
|
||||
|
||||
optArr[i].Deconstruct(out var icon, out var option);
|
||||
|
||||
var selected = val is not null && val.Equals(option);
|
||||
|
||||
if (IconButton($"{label}{option}{i}", icon, selected ? activeColor : defaultColor, activeColor, hoveredColor, buttonSize))
|
||||
{
|
||||
val = option;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
using Dalamud.Interface.Utility.Raii;
|
||||
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.Components;
|
||||
|
|
@ -24,7 +26,13 @@ public static partial class ImGuiComponents
|
|||
else
|
||||
{
|
||||
ImGui.Text(value + "*");
|
||||
if (ImGui.IsItemHovered()) ImGui.SetTooltip(hint);
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
using (ImRaii.Tooltip())
|
||||
{
|
||||
ImGui.TextUnformatted(hint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,9 +36,14 @@ public static partial class ImGuiComponents
|
|||
}
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
drawList.AddRectFilled(p, new Vector2(p.X + width, p.Y + height), ImGui.GetColorU32(!v ? colors[(int)ImGuiCol.ButtonActive] : new Vector4(0.78f, 0.78f, 0.78f, 1.0f)), height * 0.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
drawList.AddRectFilled(p, new Vector2(p.X + width, p.Y + height), ImGui.GetColorU32(!v ? colors[(int)ImGuiCol.Button] * 0.6f : new Vector4(0.35f, 0.35f, 0.35f, 1.0f)), height * 0.50f);
|
||||
}
|
||||
|
||||
drawList.AddCircleFilled(new Vector2(p.X + radius + ((v ? 1 : 0) * (width - (radius * 2.0f))), p.Y + radius), radius - 1.5f, ImGui.ColorConvertFloat4ToU32(new Vector4(1, 1, 1, 1)));
|
||||
|
||||
return changed;
|
||||
|
|
@ -62,7 +67,7 @@ public static partial class ImGuiComponents
|
|||
// TODO: animate
|
||||
ImGui.InvisibleButton(id, new Vector2(width, height));
|
||||
|
||||
var dimFactor = 0.5f;
|
||||
const float dimFactor = 0.5f;
|
||||
|
||||
drawList.AddRectFilled(p, new Vector2(p.X + width, p.Y + height), ImGui.GetColorU32(v ? colors[(int)ImGuiCol.Button] * dimFactor : new Vector4(0.55f, 0.55f, 0.55f, 1.0f) * dimFactor), height * 0.50f);
|
||||
drawList.AddCircleFilled(new Vector2(p.X + radius + ((v ? 1 : 0) * (width - (radius * 2.0f))), p.Y + radius), radius - 1.5f, ImGui.ColorConvertFloat4ToU32(new Vector4(1, 1, 1, 1) * dimFactor));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,124 @@
|
|||
using Dalamud.Interface.Internal.UiDebug2.Utility;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
using Dalamud.Memory;
|
||||
using Dalamud.Utility;
|
||||
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
|
||||
using ImGuiNET;
|
||||
|
||||
using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.ValueType;
|
||||
|
||||
namespace Dalamud.Interface.Internal.UiDebug2.Browsing;
|
||||
|
||||
public unsafe partial class AddonTree
|
||||
{
|
||||
/// <summary>
|
||||
/// Prints a table of AtkValues associated with a given addon.
|
||||
/// </summary>
|
||||
/// <param name="addon">The addon to look up.</param>
|
||||
internal static void PrintAtkValues(AtkUnitBase* addon)
|
||||
{
|
||||
var atkValue = addon->AtkValues;
|
||||
if (addon->AtkValuesCount > 0 && atkValue != null)
|
||||
{
|
||||
using var tree = ImRaii.TreeNode($"Atk Values [{addon->AtkValuesCount}]###atkValues_{addon->NameString}");
|
||||
if (tree)
|
||||
{
|
||||
using (ImRaii.Table(
|
||||
"atkUnitBase_atkValueTable",
|
||||
3,
|
||||
ImGuiTableFlags.Borders | ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg))
|
||||
{
|
||||
ImGui.TableSetupColumn("Index");
|
||||
ImGui.TableSetupColumn("Type");
|
||||
ImGui.TableSetupColumn("Value");
|
||||
ImGui.TableHeadersRow();
|
||||
|
||||
try
|
||||
{
|
||||
for (var i = 0; i < addon->AtkValuesCount; i++)
|
||||
{
|
||||
ImGui.TableNextColumn();
|
||||
if (atkValue->Type == 0)
|
||||
{
|
||||
ImGui.TextDisabled($"#{i}");
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.Text($"#{i}");
|
||||
}
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
if (atkValue->Type == 0)
|
||||
{
|
||||
ImGui.TextDisabled("Not Set");
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.Text($"{atkValue->Type}");
|
||||
}
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
|
||||
switch (atkValue->Type)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case ValueType.Int:
|
||||
case ValueType.UInt:
|
||||
{
|
||||
ImGui.TextUnformatted($"{atkValue->Int}");
|
||||
break;
|
||||
}
|
||||
|
||||
case ValueType.ManagedString:
|
||||
case ValueType.String8:
|
||||
case ValueType.String:
|
||||
{
|
||||
if (atkValue->String == null)
|
||||
{
|
||||
ImGui.TextDisabled("null");
|
||||
}
|
||||
else
|
||||
{
|
||||
var str = MemoryHelper.ReadSeStringNullTerminated(new nint(atkValue->String));
|
||||
Util.ShowStruct(str, (ulong)atkValue);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ValueType.Bool:
|
||||
{
|
||||
ImGui.TextUnformatted($"{atkValue->Byte != 0}");
|
||||
break;
|
||||
}
|
||||
|
||||
case ValueType.Pointer:
|
||||
ImGui.TextUnformatted($"{(nint)atkValue->Pointer}");
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
ImGui.TextDisabled("Unhandled Type");
|
||||
ImGui.SameLine();
|
||||
Util.ShowStruct(atkValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
atkValue++;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ImGui.TextColored(new(1, 0, 0, 1), $"{ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Gui.PaddedSeparator();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -23,6 +23,11 @@ public unsafe partial class AddonTree
|
|||
/// </summary>
|
||||
internal Dictionary<nint, List<string>> FieldNames { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the size of the addon according to its Attributes in FFXIVClientStructs.
|
||||
/// </summary>
|
||||
internal int AddonSize { get; set; }
|
||||
|
||||
private object? GetAddonObj(AtkUnitBase* addon)
|
||||
{
|
||||
if (addon == null)
|
||||
|
|
@ -42,6 +47,13 @@ public unsafe partial class AddonTree
|
|||
select t)
|
||||
{
|
||||
AddonTypeDict[this.AddonName] = t;
|
||||
|
||||
var size = t.StructLayoutAttribute?.Size;
|
||||
if (size != null)
|
||||
{
|
||||
this.AddonSize = size.Value;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using System.Linq;
|
|||
using System.Numerics;
|
||||
|
||||
using Dalamud.Interface.Components;
|
||||
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
using ImGuiNET;
|
||||
|
||||
|
|
@ -19,14 +20,12 @@ namespace Dalamud.Interface.Internal.UiDebug2.Browsing;
|
|||
/// </summary>
|
||||
public unsafe partial class AddonTree : IDisposable
|
||||
{
|
||||
private readonly nint initialPtr;
|
||||
|
||||
private AddonPopoutWindow? window;
|
||||
|
||||
private AddonTree(string name, nint ptr)
|
||||
{
|
||||
this.AddonName = name;
|
||||
this.initialPtr = ptr;
|
||||
this.InitialPtr = ptr;
|
||||
this.PopulateFieldNames(ptr);
|
||||
}
|
||||
|
||||
|
|
@ -35,6 +34,11 @@ public unsafe partial class AddonTree : IDisposable
|
|||
/// </summary>
|
||||
internal string AddonName { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the addon's pointer at the time this <see cref="AddonTree"/> was created.
|
||||
/// </summary>
|
||||
internal nint InitialPtr { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a collection of trees representing nodes within this addon.
|
||||
/// </summary>
|
||||
|
|
@ -81,7 +85,7 @@ public unsafe partial class AddonTree : IDisposable
|
|||
{
|
||||
if (AddonTrees.TryGetValue(name, out var tree))
|
||||
{
|
||||
if (tree.initialPtr == ptr)
|
||||
if (tree.InitialPtr == ptr)
|
||||
{
|
||||
return tree;
|
||||
}
|
||||
|
|
@ -143,34 +147,47 @@ public unsafe partial class AddonTree : IDisposable
|
|||
ImGui.SetTooltip("Toggle Popout Window");
|
||||
}
|
||||
|
||||
ImGui.Separator();
|
||||
|
||||
PrintFieldValuePair("Address", $"{(nint)addon:X}");
|
||||
PaddedSeparator(1);
|
||||
|
||||
var uldManager = addon->UldManager;
|
||||
|
||||
PrintFieldValuePair("Address", $"{(nint)addon:X}");
|
||||
PrintFieldValuePair("Agent", $"{GameGui.FindAgentInterface(addon):X}");
|
||||
|
||||
PrintFieldValuePairs(
|
||||
("X", $"{addon->X}"),
|
||||
("Y", $"{addon->X}"),
|
||||
("Y", $"{addon->Y}"),
|
||||
("Scale", $"{addon->Scale}"),
|
||||
("Widget Count", $"{uldManager.ObjectCount}"));
|
||||
|
||||
ImGui.Separator();
|
||||
|
||||
var addonObj = this.GetAddonObj(addon);
|
||||
if (addonObj != null)
|
||||
{
|
||||
PaddedSeparator();
|
||||
ShowStruct(addonObj, (ulong)addon);
|
||||
}
|
||||
|
||||
ImGui.Dummy(new(25 * ImGui.GetIO().FontGlobalScale));
|
||||
ImGui.Separator();
|
||||
PaddedSeparator();
|
||||
|
||||
ResNodeTree.PrintNodeList(uldManager.NodeList, uldManager.NodeListCount, this);
|
||||
PrintAtkValues(addon);
|
||||
|
||||
ImGui.Dummy(new(25 * ImGui.GetIO().FontGlobalScale));
|
||||
ImGui.Separator();
|
||||
if (addon->RootNode != null)
|
||||
{
|
||||
ResNodeTree.GetOrCreate(addon->RootNode, this).Print(0);
|
||||
PaddedSeparator();
|
||||
}
|
||||
|
||||
if (uldManager.NodeList != null)
|
||||
{
|
||||
var count = uldManager.NodeListCount;
|
||||
ResNodeTree.PrintNodeListAsTree(uldManager.NodeList, count, $"Node List [{count}]:", this, new(0, 0.85F, 1, 1));
|
||||
PaddedSeparator();
|
||||
}
|
||||
|
||||
if (addon->CollisionNodeList != null)
|
||||
{
|
||||
ResNodeTree.PrintNodeListAsTree(addon->CollisionNodeList, (int)addon->CollisionNodeListCount, "Collision List", this, new(0.5F, 0.7F, 1F, 1F));
|
||||
}
|
||||
|
||||
if (SearchResults.Length > 0 && Countdown <= 0)
|
||||
{
|
||||
|
|
@ -218,7 +235,7 @@ public unsafe partial class AddonTree : IDisposable
|
|||
private bool ValidateAddon(out AtkUnitBase* addon)
|
||||
{
|
||||
addon = (AtkUnitBase*)GameGui.GetAddonByName(this.AddonName);
|
||||
if (addon == null || (nint)addon != this.initialPtr)
|
||||
if (addon == null || (nint)addon != this.InitialPtr)
|
||||
{
|
||||
this.Dispose();
|
||||
return false;
|
||||
|
|
@ -231,7 +248,7 @@ public unsafe partial class AddonTree : IDisposable
|
|||
{
|
||||
if (this.window == null)
|
||||
{
|
||||
this.window = new AddonPopoutWindow(this, $"{this.AddonName}###addonPopout{this.initialPtr}");
|
||||
this.window = new AddonPopoutWindow(this, $"{this.AddonName}###addonPopout{this.InitialPtr}");
|
||||
PopoutWindows.AddWindow(this.window);
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
using Dalamud.Interface.Internal.UiDebug2.Utility;
|
||||
using System.Numerics;
|
||||
|
||||
using Dalamud.Interface.Utility;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
|
|
@ -56,9 +58,9 @@ public static class Events
|
|||
ImGui.TableNextColumn();
|
||||
ImGui.TextUnformatted($"{evt->State.UnkFlags1}");
|
||||
ImGui.TableNextColumn();
|
||||
Gui.ClickToCopyText($"{(nint)evt->Target:X}");
|
||||
ImGuiHelpers.ClickToCopyText($"{(nint)evt->Target:X}", null, new Vector4(0.6f, 0.6f, 0.6f, 1));
|
||||
ImGui.TableNextColumn();
|
||||
Gui.ClickToCopyText($"{(nint)evt->Listener:X}");
|
||||
ImGuiHelpers.ClickToCopyText($"{(nint)evt->Listener:X}", null, new Vector4(0.6f, 0.6f, 0.6f, 1));
|
||||
evt = evt->NextEvent;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,11 +34,13 @@ internal unsafe class ComponentNodeTree : ResNodeTree
|
|||
|
||||
private AtkUldManager* UldManager => &this.Component->UldManager;
|
||||
|
||||
private int? ComponentFieldOffset { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
private protected override string GetHeaderText()
|
||||
{
|
||||
var childCount = (int)this.UldManager->NodeListCount;
|
||||
return $"{this.componentType} Component Node{(childCount > 0 ? $" [+{childCount}]" : string.Empty)} (Node: {(nint)this.Node:X} / Comp: {(nint)this.Component:X})";
|
||||
return $"{this.componentType} Component Node{(childCount > 0 ? $" [+{childCount}]" : string.Empty)}";
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
|
@ -62,10 +64,10 @@ internal unsafe class ComponentNodeTree : ResNodeTree
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
private protected override void PrintFieldNames()
|
||||
private protected override void PrintFieldLabels()
|
||||
{
|
||||
this.PrintFieldName((nint)this.Node, new(0, 0.85F, 1, 1));
|
||||
this.PrintFieldName((nint)this.Component, new(0f, 0.5f, 0.8f, 1f));
|
||||
this.PrintFieldLabel((nint)this.Node, new(0, 0.85F, 1, 1), this.NodeFieldOffset);
|
||||
this.PrintFieldLabel((nint)this.Component, new(0f, 0.5f, 0.8f, 1f), this.ComponentFieldOffset);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
|
@ -108,6 +110,34 @@ internal unsafe class ComponentNodeTree : ResNodeTree
|
|||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
private protected override void GetFieldOffset()
|
||||
{
|
||||
var nodeFound = false;
|
||||
var componentFound = false;
|
||||
for (var i = 0; i < this.AddonTree.AddonSize; i += 0x8)
|
||||
{
|
||||
var readPtr = Marshal.ReadIntPtr(this.AddonTree.InitialPtr + i);
|
||||
|
||||
if (readPtr == (nint)this.Node)
|
||||
{
|
||||
this.NodeFieldOffset = i;
|
||||
nodeFound = true;
|
||||
}
|
||||
|
||||
if (readPtr == (nint)this.Component)
|
||||
{
|
||||
this.ComponentFieldOffset = i;
|
||||
componentFound = true;
|
||||
}
|
||||
|
||||
if (nodeFound && componentFound)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void PrintComponentObject()
|
||||
{
|
||||
PrintFieldValuePair("Component", $"{(nint)this.Component:X}");
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
|
||||
using Dalamud.Interface.Components;
|
||||
using Dalamud.Interface.Internal.UiDebug2.Utility;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
|
||||
|
|
@ -370,8 +371,8 @@ internal unsafe partial class TextNodeTree
|
|||
var hAlign = (int)alignment % 3;
|
||||
var vAlign = ((int)alignment - hAlign) / 3;
|
||||
|
||||
var hAlignInput = IconButtonSelect($"{label}H", ref hAlign, [0, 1, 2], [AlignLeft, AlignCenter, AlignRight]);
|
||||
var vAlignInput = IconButtonSelect($"{label}V", ref vAlign, [0, 1, 2], [ArrowsUpToLine, GripLines, ArrowsDownToLine]);
|
||||
var hAlignInput = ImGuiComponents.IconButtonSelect($"{label}H", ref hAlign, [AlignLeft, AlignCenter, AlignRight], [0, 1, 2], 3u, new(25, 0));
|
||||
var vAlignInput = ImGuiComponents.IconButtonSelect($"{label}V", ref vAlign, [ArrowsUpToLine, GripLines, ArrowsDownToLine], [0, 1, 2], 3u, new(25, 0));
|
||||
|
||||
if (hAlignInput || vAlignInput)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using Dalamud.Interface.Components;
|
||||
using Dalamud.Interface.Internal.UiDebug2.Utility;
|
||||
|
|
@ -60,6 +61,11 @@ internal unsafe partial class ResNodeTree : IDisposable
|
|||
/// </summary>
|
||||
private protected NodeType NodeType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the offset of this node within its parent Addon.
|
||||
/// </summary>
|
||||
private protected int? NodeFieldOffset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Clears this NodeTree's popout window, if it has one.
|
||||
/// </summary>
|
||||
|
|
@ -164,19 +170,26 @@ internal unsafe partial class ResNodeTree : IDisposable
|
|||
internal void WriteTreeHeading()
|
||||
{
|
||||
ImGui.TextUnformatted(this.GetHeaderText());
|
||||
this.PrintFieldNames();
|
||||
this.PrintFieldLabels();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the given pointer has been identified as a field within the addon struct, this method prints that field's name.
|
||||
/// If the given pointer is referenced with the addon struct, the offset within the addon will be printed. If the given pointer has been identified as a field within the addon struct, this method also prints that field's name.
|
||||
/// </summary>
|
||||
/// <param name="ptr">The pointer to check.</param>
|
||||
/// <param name="color">The text color to use.</param>
|
||||
private protected void PrintFieldName(nint ptr, Vector4 color)
|
||||
/// <param name="fieldOffset">The field offset of the pointer, if it was found in the addon.</param>
|
||||
private protected void PrintFieldLabel(nint ptr, Vector4 color, int? fieldOffset)
|
||||
{
|
||||
if (fieldOffset != null)
|
||||
{
|
||||
ImGui.SameLine(0, -1);
|
||||
ImGui.TextColored(color * 0.85f, $"[0x{fieldOffset:X}]");
|
||||
}
|
||||
|
||||
if (this.AddonTree.FieldNames.TryGetValue(ptr, out var result))
|
||||
{
|
||||
ImGui.SameLine();
|
||||
ImGui.SameLine(0, -1);
|
||||
ImGui.TextColored(color, string.Join(".", result));
|
||||
}
|
||||
}
|
||||
|
|
@ -188,7 +201,15 @@ internal unsafe partial class ResNodeTree : IDisposable
|
|||
private protected virtual string GetHeaderText()
|
||||
{
|
||||
var count = this.GetDirectChildCount();
|
||||
return $"{this.NodeType} Node{(count > 0 ? $" [+{count}]" : string.Empty)} ({(nint)this.Node:X})";
|
||||
return $"{this.NodeType} Node{(count > 0 ? $" [+{count}]" : string.Empty)}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prints any field names for the node.
|
||||
/// </summary>
|
||||
private protected virtual void PrintFieldLabels()
|
||||
{
|
||||
this.PrintFieldLabel((nint)this.Node, new(0, 0.85F, 1, 1), this.NodeFieldOffset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -201,11 +222,6 @@ internal unsafe partial class ResNodeTree : IDisposable
|
|||
ImGui.NewLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prints any field names for the node.
|
||||
/// </summary>
|
||||
private protected virtual void PrintFieldNames() => this.PrintFieldName((nint)this.Node, new(0, 0.85F, 1, 1));
|
||||
|
||||
/// <summary>
|
||||
/// Prints all direct children of this node.
|
||||
/// </summary>
|
||||
|
|
@ -227,6 +243,21 @@ internal unsafe partial class ResNodeTree : IDisposable
|
|||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to retrieve the field offset of the given pointer within the parent addon.
|
||||
/// </summary>
|
||||
private protected virtual void GetFieldOffset()
|
||||
{
|
||||
for (var i = 0; i < this.AddonTree.AddonSize; i += 0x8)
|
||||
{
|
||||
if (Marshal.ReadIntPtr(this.AddonTree.InitialPtr + i) == (nint)this.Node)
|
||||
{
|
||||
this.NodeFieldOffset = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int GetDirectChildCount()
|
||||
{
|
||||
var count = 0;
|
||||
|
|
@ -273,6 +304,8 @@ internal unsafe partial class ResNodeTree : IDisposable
|
|||
ImGui.SetNextItemOpen(true, ImGuiCond.Always);
|
||||
}
|
||||
|
||||
this.GetFieldOffset();
|
||||
|
||||
using var col = ImRaii.PushColor(Text, displayColor);
|
||||
using var tree = ImRaii.TreeNode(label, SpanFullWidth);
|
||||
|
||||
|
|
@ -281,7 +314,7 @@ internal unsafe partial class ResNodeTree : IDisposable
|
|||
new NodeBounds(this.Node).Draw(visible ? new(0.1f, 1f, 0.1f, 1f) : new(1f, 0f, 0.2f, 1f));
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.SameLine(0, -1);
|
||||
this.WriteTreeHeading();
|
||||
|
||||
col.Pop();
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ internal unsafe class ElementSelector : IDisposable
|
|||
/// </summary>
|
||||
internal void DrawInterface()
|
||||
{
|
||||
using (ImRaii.Child("###sidebar_elementSelector", new(250, 0), true))
|
||||
using (ImRaii.Child("###sidebar_elementSelector", new(250, -1), true))
|
||||
{
|
||||
using (ImRaii.PushFont(IconFont))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
|
||||
using Dalamud.Interface.Components;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics;
|
||||
|
|
@ -17,40 +16,6 @@ namespace Dalamud.Interface.Internal.UiDebug2.Utility;
|
|||
/// </summary>
|
||||
internal static class Gui
|
||||
{
|
||||
/// <summary>
|
||||
/// A radio-button-esque input that uses Fontawesome icon buttons.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of value being set.</typeparam>
|
||||
/// <param name="label">The label for the inputs.</param>
|
||||
/// <param name="val">The value being set.</param>
|
||||
/// <param name="options">A list of all options.</param>
|
||||
/// <param name="icons">A list of icons corresponding to the options.</param>
|
||||
/// <returns>true if a button is clicked.</returns>
|
||||
internal static unsafe bool IconButtonSelect<T>(string label, ref T val, List<T> options, List<FontAwesomeIcon> icons)
|
||||
{
|
||||
var ret = false;
|
||||
|
||||
for (var i = 0; i < options.Count; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.X);
|
||||
}
|
||||
|
||||
var option = options[i];
|
||||
var icon = icons.Count > i ? icons[i] : FontAwesomeIcon.Question;
|
||||
var color = *ImGui.GetStyleColorVec4(val is not null && val.Equals(option) ? ButtonActive : Button);
|
||||
|
||||
if (ImGuiComponents.IconButton($"{label}{option}{i}", icon, color))
|
||||
{
|
||||
val = option;
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prints field name and its value.
|
||||
/// </summary>
|
||||
|
|
@ -61,13 +26,14 @@ internal static class Gui
|
|||
{
|
||||
ImGui.TextUnformatted($"{fieldName}:");
|
||||
ImGui.SameLine();
|
||||
var grey60 = new Vector4(0.6f, 0.6f, 0.6f, 1);
|
||||
if (copy)
|
||||
{
|
||||
ClickToCopyText(value);
|
||||
ImGuiHelpers.ClickToCopyText(value, null, grey60);
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.TextColored(new(0.6f, 0.6f, 0.6f, 1), value);
|
||||
ImGui.TextColored(grey60, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -102,7 +68,10 @@ internal static class Gui
|
|||
/// <remarks>Colors the text itself either white or black, depending on the luminosity of the background color.</remarks>
|
||||
internal static void PrintColor(Vector4 color, string fmt)
|
||||
{
|
||||
using (new ImRaii.Color().Push(Text, Luminosity(color) < 0.5f ? new Vector4(1) : new(0, 0, 0, 1)).Push(Button, color).Push(ButtonActive, color).Push(ButtonHovered, color))
|
||||
using (new ImRaii.Color().Push(Text, Luminosity(color) < 0.5f ? new Vector4(1) : new(0, 0, 0, 1))
|
||||
.Push(Button, color)
|
||||
.Push(ButtonActive, color)
|
||||
.Push(ButtonHovered, color))
|
||||
{
|
||||
ImGui.SmallButton(fmt);
|
||||
}
|
||||
|
|
@ -117,39 +86,6 @@ internal static class Gui
|
|||
0.5f) * vector4.W;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Print out text that can be copied when clicked.
|
||||
/// </summary>
|
||||
/// <param name="text">The text to show.</param>
|
||||
/// <param name="textCopy">The text to copy when clicked.</param>
|
||||
internal static void ClickToCopyText(string text, string? textCopy = null)
|
||||
{
|
||||
using (ImRaii.PushColor(Text, new Vector4(0.6f, 0.6f, 0.6f, 1)))
|
||||
{
|
||||
textCopy ??= text;
|
||||
ImGui.TextUnformatted($"{text}");
|
||||
}
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
using (ImRaii.Tooltip())
|
||||
{
|
||||
using (ImRaii.PushFont(UiBuilder.IconFont))
|
||||
{
|
||||
ImGui.TextUnformatted(FontAwesomeIcon.Copy.ToIconString());
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted($"{textCopy}");
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui.IsItemClicked())
|
||||
{
|
||||
ImGui.SetClipboardText($"{textCopy}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a tooltip that changes based on the cursor's x-position within the hovered item.
|
||||
/// </summary>
|
||||
|
|
@ -176,4 +112,23 @@ internal static class Gui
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a separator with some padding above and below.
|
||||
/// </summary>
|
||||
/// <param name="mask">Governs whether to pad above, below, or both.</param>
|
||||
/// <param name="padding">The amount of padding.</param>
|
||||
internal static void PaddedSeparator(uint mask = 0b11, float padding = 5f)
|
||||
{
|
||||
if ((mask & 0b10) > 0)
|
||||
{
|
||||
ImGui.Dummy(new(padding * ImGui.GetIO().FontGlobalScale));
|
||||
}
|
||||
|
||||
ImGui.Separator();
|
||||
if ((mask & 0b01) > 0)
|
||||
{
|
||||
ImGui.Dummy(new(padding * ImGui.GetIO().FontGlobalScale));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ using Dalamud.Interface.Utility;
|
|||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
using ImGuiNET;
|
||||
|
||||
using static System.Math;
|
||||
using static System.MathF;
|
||||
using static Dalamud.Interface.ColorHelpers;
|
||||
|
||||
namespace Dalamud.Interface.Internal.UiDebug2.Utility;
|
||||
|
|
@ -133,7 +133,7 @@ public unsafe struct NodeBounds
|
|||
if (p.Y > Min(p1.Y, p2.Y) &&
|
||||
p.Y <= Max(p1.Y, p2.Y) &&
|
||||
p.X <= Max(p1.X, p2.X) &&
|
||||
(p1.X.Equals(p2.X) || p.X <= ((p.Y - p1.Y) * (p2.X - p1.X) / (p2.Y - p1.Y)) + p1.X))
|
||||
(p1.X.Equals(p2.X) || p.X <= (((p.Y - p1.Y) * (p2.X - p1.X)) / (p2.Y - p1.Y)) + p1.X))
|
||||
{
|
||||
inside = !inside;
|
||||
}
|
||||
|
|
@ -144,12 +144,12 @@ public unsafe struct NodeBounds
|
|||
|
||||
private static Vector2 TransformPoint(Vector2 p, Vector2 o, float r, Vector2 s)
|
||||
{
|
||||
var cosR = (float)Cos(r);
|
||||
var sinR = (float)Sin(r);
|
||||
var cosR = Cos(r);
|
||||
var sinR = Sin(r);
|
||||
var d = (p - o) * s;
|
||||
|
||||
return new(
|
||||
o.X + (d.X * cosR) - (d.Y * sinR),
|
||||
(o.X + (d.X * cosR)) - (d.Y * sinR),
|
||||
o.Y + (d.X * sinR) + (d.Y * cosR));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -167,17 +167,41 @@ public static class ImGuiHelpers
|
|||
/// </summary>
|
||||
/// <param name="text">The text to show.</param>
|
||||
/// <param name="textCopy">The text to copy when clicked.</param>
|
||||
public static void ClickToCopyText(string text, string? textCopy = null)
|
||||
/// <param name="color">The color of the text.</param>
|
||||
public static void ClickToCopyText(string text, string? textCopy = null, Vector4? color = null)
|
||||
{
|
||||
textCopy ??= text;
|
||||
ImGui.Text($"{text}");
|
||||
|
||||
using (var col = new ImRaii.Color())
|
||||
{
|
||||
if (color.HasValue)
|
||||
{
|
||||
col.Push(ImGuiCol.Text, color.Value);
|
||||
}
|
||||
|
||||
ImGui.TextUnformatted($"{text}");
|
||||
}
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
ImGui.SetMouseCursor(ImGuiMouseCursor.Hand);
|
||||
if (textCopy != text) ImGui.SetTooltip(textCopy);
|
||||
|
||||
using (ImRaii.Tooltip())
|
||||
{
|
||||
using (ImRaii.PushFont(UiBuilder.IconFont))
|
||||
{
|
||||
ImGui.TextUnformatted(FontAwesomeIcon.Copy.ToIconString());
|
||||
}
|
||||
|
||||
if (ImGui.IsItemClicked()) ImGui.SetClipboardText($"{textCopy}");
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted(textCopy);
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui.IsItemClicked())
|
||||
{
|
||||
ImGui.SetClipboardText(textCopy);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Draws a SeString.</summary>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue