95c42af5b8
- Combo highlight: configurable color, glow, line style (solid/dashed/dotted), thickness - Tooltips: font selection, scaling slider, improved wrap/cramping handling - Nameplates: custom quest icons with config, position smoothing fix for jitter - Hotbars: hide keybinds on empty slots, combo highlight within icon bounds - HudHelper: restore default nameplates on plugin disable Co-authored-by: Cursor <cursoragent@cursor.com>
309 lines
10 KiB
C#
309 lines
10 KiB
C#
using Dalamud.Interface;
|
|
using Dalamud.Interface.Utility;
|
|
using HSUI.Config;
|
|
using HSUI.Config.Attributes;
|
|
using HSUI.Interface.GeneralElements;
|
|
using Dalamud.Bindings.ImGui;
|
|
using System;
|
|
using System.Numerics;
|
|
|
|
namespace HSUI.Helpers
|
|
{
|
|
public class TooltipsHelper : IDisposable
|
|
{
|
|
#region Singleton
|
|
private TooltipsHelper()
|
|
{
|
|
}
|
|
|
|
public static void Initialize() { Instance = new TooltipsHelper(); }
|
|
|
|
public static TooltipsHelper Instance { get; private set; } = null!;
|
|
|
|
~TooltipsHelper()
|
|
{
|
|
Dispose(false);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
protected void Dispose(bool disposing)
|
|
{
|
|
if (!disposing)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Instance = null!;
|
|
}
|
|
#endregion
|
|
|
|
private float MaxWidth => Math.Max(160, 340 * ImGuiHelpers.GlobalScale * _config.TooltipScale);
|
|
private float Margin => Math.Max(4, 5 * ImGuiHelpers.GlobalScale * _config.TooltipScale);
|
|
|
|
private TooltipsConfig _config => ConfigurationManager.Instance.GetConfigObject<TooltipsConfig>();
|
|
|
|
private string? _currentTooltipText = null;
|
|
private Vector2 _textSize;
|
|
private string? _currentTooltipTitle = null;
|
|
private Vector2 _titleSize;
|
|
private string? _previousRawText = null;
|
|
|
|
private Vector2 _position;
|
|
private Vector2 _size;
|
|
|
|
private bool _dataIsValid = false;
|
|
|
|
public void ShowTooltipOnCursor(string text, string? title = null, uint id = 0, string name = "")
|
|
{
|
|
ShowTooltip(text, ImGui.GetMousePos(), title, id, name);
|
|
}
|
|
|
|
public void ShowTooltip(string text, Vector2 position, string? title = null, uint id = 0, string name = "")
|
|
{
|
|
if (text == null)
|
|
{
|
|
if (_config.DebugTooltips)
|
|
Plugin.Logger.Information("[HSUI Tooltip DBG] ShowTooltip skipped: text is null");
|
|
return;
|
|
}
|
|
|
|
// remove styling tags from text
|
|
if (_previousRawText != text)
|
|
{
|
|
_currentTooltipText = text;
|
|
_previousRawText = text;
|
|
}
|
|
|
|
// calcualte title size
|
|
_titleSize = Vector2.Zero;
|
|
if (title != null)
|
|
{
|
|
_currentTooltipTitle = title;
|
|
|
|
if (_config.ShowSourceName && name.Length > 0)
|
|
{
|
|
_currentTooltipTitle += $" ({name})";
|
|
}
|
|
|
|
if (_config.ShowStatusIDs)
|
|
{
|
|
_currentTooltipTitle += " (ID: " + id + ")";
|
|
}
|
|
|
|
string fontId = _config.FontID ?? FontsConfig.DefaultSmallFontKey;
|
|
using (FontsManager.Instance.PushFont(fontId))
|
|
{
|
|
_titleSize = ImGui.CalcTextSize(_currentTooltipTitle, false, MaxWidth);
|
|
_titleSize.Y += Margin;
|
|
}
|
|
}
|
|
|
|
// calculate text size
|
|
string fontIdForText = _config.FontID ?? FontsConfig.DefaultSmallFontKey;
|
|
using (FontsManager.Instance.PushFont(fontIdForText))
|
|
{
|
|
_textSize = ImGui.CalcTextSize(_currentTooltipText, false, MaxWidth);
|
|
}
|
|
|
|
_size = new Vector2(Math.Max(_titleSize.X, _textSize.X) + Margin * 2, _titleSize.Y + _textSize.Y + Margin * 2);
|
|
|
|
// position tooltip using the given coordinates as bottom center
|
|
position.X = position.X - _size.X / 2f;
|
|
position.Y = position.Y - _size.Y;
|
|
|
|
// correct tooltips off screen
|
|
_position = ConstrainPosition(position, _size);
|
|
|
|
_dataIsValid = true;
|
|
if (_config.DebugTooltips)
|
|
Plugin.Logger.Information($"[HSUI Tooltip DBG] ShowTooltip: title='{title}' textLen={text?.Length ?? 0} textPreview='{(text != null && text.Length > 80 ? text[..80] + "..." : text ?? "")}' pos=({_position.X:F0},{_position.Y:F0})");
|
|
}
|
|
|
|
public void RemoveTooltip()
|
|
{
|
|
_dataIsValid = false;
|
|
}
|
|
|
|
public void Draw()
|
|
{
|
|
if (!_dataIsValid)
|
|
return;
|
|
if (ConfigurationManager.Instance.ShowingModalWindow)
|
|
{
|
|
if (_config.DebugTooltips)
|
|
Plugin.Logger.Information("[HSUI Tooltip DBG] Draw SKIPPED: ShowingModalWindow=true");
|
|
return;
|
|
}
|
|
|
|
// bg
|
|
ImGuiWindowFlags windowFlags =
|
|
ImGuiWindowFlags.NoTitleBar
|
|
| ImGuiWindowFlags.NoMove
|
|
| ImGuiWindowFlags.NoDecoration
|
|
| ImGuiWindowFlags.NoBackground
|
|
| ImGuiWindowFlags.NoInputs
|
|
| ImGuiWindowFlags.NoSavedSettings
|
|
| ImGuiWindowFlags.NoFocusOnAppearing;
|
|
|
|
// imgui clips the left and right borders inside windows for some reason
|
|
// we make the window bigger so the actual drawable size is the expected one
|
|
var windowMargin = new Vector2(4, 0);
|
|
var windowPos = _position - windowMargin;
|
|
|
|
ImGui.SetNextWindowPos(windowPos, ImGuiCond.Always);
|
|
ImGui.SetNextWindowSize(_size + windowMargin * 2);
|
|
|
|
ImGui.PushStyleVar(ImGuiStyleVar.WindowRounding, 0);
|
|
ImGui.Begin("DelvUI_tooltip", windowFlags);
|
|
var drawList = ImGui.GetWindowDrawList();
|
|
|
|
drawList.AddRectFilled(_position, _position + _size, _config.BackgroundColor.Base);
|
|
|
|
if (_config.BorderConfig.Enabled)
|
|
{
|
|
drawList.AddRect(_position, _position + _size, _config.BorderConfig.Color.Base, 0, ImDrawFlags.None, _config.BorderConfig.Thickness);
|
|
}
|
|
|
|
// no idea why i have to do this
|
|
float globalScaleCorrection = -15 + 15 * ImGuiHelpers.GlobalScale;
|
|
|
|
string fontId = _config.FontID ?? FontsConfig.DefaultSmallFontKey;
|
|
float wrapWidth = Math.Max(_titleSize.X, _textSize.X) + Margin;
|
|
if (_currentTooltipTitle != null)
|
|
{
|
|
// title
|
|
Vector2 cursorPos;
|
|
using (FontsManager.Instance.PushFont(fontId))
|
|
{
|
|
cursorPos = new Vector2(windowMargin.X + _size.X / 2f - _titleSize.X / 2f, Margin);
|
|
ImGui.SetCursorPos(cursorPos);
|
|
ImGui.PushTextWrapPos(cursorPos.X + wrapWidth + globalScaleCorrection);
|
|
ImGui.TextColored(_config.TitleColor.Vector, _currentTooltipTitle);
|
|
ImGui.PopTextWrapPos();
|
|
}
|
|
|
|
// text
|
|
using (FontsManager.Instance.PushFont(fontId))
|
|
{
|
|
cursorPos = new Vector2(windowMargin.X + _size.X / 2f - _textSize.X / 2f, Margin + _titleSize.Y);
|
|
ImGui.SetCursorPos(cursorPos);
|
|
ImGui.PushTextWrapPos(cursorPos.X + wrapWidth + globalScaleCorrection);
|
|
ImGui.TextColored(_config.TextColor.Vector, _currentTooltipText);
|
|
ImGui.PopTextWrapPos();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// text
|
|
using (FontsManager.Instance.PushFont(fontId))
|
|
{
|
|
var cursorPos = windowMargin + new Vector2(Margin, Margin);
|
|
var textWidth = _size.X - Margin * 2;
|
|
|
|
ImGui.SetCursorPos(cursorPos);
|
|
ImGui.PushTextWrapPos(cursorPos.X + textWidth + globalScaleCorrection);
|
|
ImGui.TextColored(_config.TextColor.Vector, _currentTooltipText);
|
|
ImGui.PopTextWrapPos();
|
|
}
|
|
}
|
|
|
|
ImGui.End();
|
|
ImGui.PopStyleVar();
|
|
|
|
if (_config.DebugTooltips)
|
|
Plugin.Logger.Information($"[HSUI Tooltip DBG] Draw rendered tooltip at ({_position.X:F0},{_position.Y:F0})");
|
|
RemoveTooltip();
|
|
}
|
|
|
|
private Vector2 ConstrainPosition(Vector2 position, Vector2 size)
|
|
{
|
|
var screenSize = ImGui.GetWindowViewport().Size;
|
|
|
|
if (position.X < 0)
|
|
{
|
|
position.X = Margin;
|
|
}
|
|
else if (position.X + size.X > screenSize.X)
|
|
{
|
|
position.X = screenSize.X - size.X - Margin;
|
|
}
|
|
|
|
if (position.Y < 0)
|
|
{
|
|
position.Y = Margin;
|
|
}
|
|
|
|
return position;
|
|
}
|
|
}
|
|
|
|
[Section("Misc")]
|
|
[SubSection("Tooltips", 0)]
|
|
public class TooltipsConfig : PluginConfigObject
|
|
{
|
|
public new static TooltipsConfig DefaultConfig() { return new TooltipsConfig(); }
|
|
|
|
[Checkbox("Debug Tooltips")]
|
|
[Order(3)]
|
|
public bool DebugTooltips = false;
|
|
|
|
[Font]
|
|
[Order(4)]
|
|
public string? FontID = null;
|
|
|
|
[DragFloat("Tooltip Scale", min = 0.5f, max = 2f, help = "Scale the tooltip window size. Useful for large resolutions.")]
|
|
[Order(6)]
|
|
public float TooltipScale = 1f;
|
|
|
|
[Checkbox("Show Status Effects IDs")]
|
|
[Order(7)]
|
|
public bool ShowStatusIDs = false;
|
|
|
|
[Checkbox("Show Source Name")]
|
|
[Order(10)]
|
|
public bool ShowSourceName = false;
|
|
|
|
[ColorEdit4("Background Color")]
|
|
[Order(15)]
|
|
public PluginConfigColor BackgroundColor = new PluginConfigColor(new(19f / 255f, 19f / 255f, 19f / 255f, 190f / 250f));
|
|
|
|
[ColorEdit4("Title Color")]
|
|
[Order(20)]
|
|
public PluginConfigColor TitleColor = new PluginConfigColor(new(255f / 255f, 210f / 255f, 31f / 255f, 100f / 100f));
|
|
|
|
[ColorEdit4("Text Color")]
|
|
[Order(35)]
|
|
public PluginConfigColor TextColor = new PluginConfigColor(new(255f / 255f, 255f / 255f, 255f / 255f, 100f / 100f));
|
|
|
|
[NestedConfig("Border", 40, separator = false, spacing = true, collapsingHeader = false)]
|
|
public TooltipBorderConfig BorderConfig = new();
|
|
}
|
|
|
|
[Exportable(false)]
|
|
public class TooltipBorderConfig : PluginConfigObject
|
|
{
|
|
[ColorEdit4("Color")]
|
|
[Order(5)]
|
|
public PluginConfigColor Color = new(new Vector4(10f / 255f, 10f / 255f, 10f / 255f, 160f / 255f));
|
|
|
|
[DragInt("Thickness", min = 1, max = 100)]
|
|
[Order(10)]
|
|
public int Thickness = 4;
|
|
|
|
public TooltipBorderConfig()
|
|
{
|
|
}
|
|
|
|
public TooltipBorderConfig(PluginConfigColor color, int thickness)
|
|
{
|
|
Color = color;
|
|
Thickness = thickness;
|
|
}
|
|
}
|
|
}
|