v1.0.8.23: Main Menu bar; Duty List transparent background

Made-with: Cursor
This commit is contained in:
2026-03-04 01:38:48 -05:00
parent 9f9d5e1781
commit 293f83dc36
15 changed files with 744 additions and 20 deletions
+190
View File
@@ -0,0 +1,190 @@
using Dalamud.Bindings.ImGui;
using HSUI.Config;
using HSUI.Helpers;
using HSUI.Interface;
using System;
using System.Collections.Generic;
using System.Numerics;
namespace HSUI.Interface.GeneralElements
{
public class MainMenuHud : DraggableHudElement, IHudElementWithVisibilityConfig
{
private const float BarPadding = 0f;
private const float BackgroundRounding = 6f;
/// <summary>Extra padding around content when drawing the background so the bar doesn't extend past the icons.</summary>
private const float BackgroundEdgePad = 2f;
private MainMenuConfig Config => (MainMenuConfig)_config;
public VisibilityConfig VisibilityConfig => Config.VisibilityConfig;
/// <summary>When set, the context menu with these entries should be shown (same frame or next). Cleared when popup closes.</summary>
private List<(uint CommandId, string Name)>? _contextMenuEntries = null;
public MainMenuHud(MainMenuConfig config, string displayName)
: base(config, displayName) { }
protected override (List<Vector2>, List<Vector2>) ChildrenPositionsAndSizes()
{
return (new List<Vector2> { Config.Position }, new List<Vector2> { Config.Size });
}
public override (Vector2 min, Vector2 max) GetScreenBounds(Vector2 origin)
{
Vector2 topLeft = Utils.GetAnchoredPosition(origin + ParentPos() + Config.Position, Config.Size, Config.Anchor);
return (topLeft, topLeft + Config.Size);
}
public override void DrawChildren(Vector2 origin)
{
if (!Config.Enabled)
return;
var entries = MainMenuHelper.GetEnabledMainCommands();
if (entries.Count == 0)
return;
Vector2 basePos = Utils.GetAnchoredPosition(origin + Config.Position, Config.Size, Config.Anchor);
Vector2 iconSize = new Vector2(Config.IconSize, Config.IconSize);
bool horizontal = Config.LayoutDirection == 0;
AddDrawAction(Config.StrataLevel, () =>
{
DrawHelper.DrawInWindow(ID, basePos, Config.Size, true, (drawListParam) =>
{
var drawList = ImGui.GetWindowDrawList();
// Compute total content size and starting position so icons are centered in the bar
int count = entries.Count;
float contentW, contentH;
if (horizontal)
{
contentW = count * iconSize.X + (count > 0 ? (count - 1) * Config.Spacing : 0);
if (Config.ShowLabels)
{
for (int i = 0; i < count; i++)
contentW += ImGui.CalcTextSize(entries[i].Name).X + Config.Spacing;
}
contentH = iconSize.Y;
}
else
{
contentW = iconSize.X;
contentH = 0;
foreach (var e in entries)
{
float h = iconSize.Y + Config.Spacing;
if (Config.ShowLabels && !string.IsNullOrEmpty(e.Name))
h += ImGui.CalcTextSize(e.Name).Y + 2;
contentH += h;
}
if (contentH > 0) contentH -= Config.Spacing;
}
float startX = basePos.X + BarPadding + Math.Max(0, (Config.Size.X - 2f * BarPadding - contentW) / 2f);
float startY = basePos.Y + BarPadding + Math.Max(0, (Config.Size.Y - 2f * BarPadding - contentH) / 2f);
// Draw background only over the content area so no gray bar shows on left/right
Vector2 bgMin = new Vector2(startX - BackgroundEdgePad, basePos.Y);
Vector2 bgMax = new Vector2(startX + contentW + BackgroundEdgePad, basePos.Y + Config.Size.Y);
if (!horizontal)
{
bgMin = new Vector2(basePos.X, startY - BackgroundEdgePad);
bgMax = new Vector2(basePos.X + Config.Size.X, startY + contentH + BackgroundEdgePad);
}
drawList.AddRectFilled(bgMin, bgMax, Config.BackgroundColor.Base, BackgroundRounding);
drawList.PushClipRect(basePos, basePos + Config.Size, true);
float x = startX;
float y = startY;
int index = 0;
foreach (var entry in entries)
{
Vector2 iconPos = horizontal
? new Vector2(x, basePos.Y + (Config.Size.Y - iconSize.Y) / 2f)
: new Vector2(basePos.X + (Config.Size.X - iconSize.X) / 2f, y);
Vector2 iconEnd = iconPos + iconSize;
// Use InvisibleButton so ImGui tracks hover/click for this icon
ImGui.SetCursorScreenPos(iconPos);
ImGui.InvisibleButton($"##mainmenu_icon_{ID}_{index}", iconSize);
bool hovered = ImGui.IsItemHovered();
uint tint = Config.IconTint.Base;
if (hovered)
{
tint = Config.HoverTint.Base;
TooltipsHelper.Instance.NotifyMouseOverHudElement();
TooltipsHelper.Instance.ShowTooltipOnCursor(entry.Name);
}
if (ImGui.IsItemClicked(ImGuiMouseButton.Left) || ImGui.IsItemClicked(ImGuiMouseButton.Right))
{
var subEntries = MainMenuHelper.GetSubCommandEntries(entry.CommandId);
if (subEntries != null && subEntries.Count > 0)
{
_contextMenuEntries = subEntries;
ImGui.OpenPopup("HSUI_MainMenu_Context");
ImGui.SetNextWindowPos(ImGui.GetMousePos());
}
else
{
MainMenuHelper.ExecuteMainCommand(entry.CommandId);
}
}
if (entry.IconId != 0)
DrawHelper.DrawIcon(entry.IconId, iconPos, iconSize, false, tint, drawList);
float labelH = 0;
if (Config.ShowLabels && !string.IsNullOrEmpty(entry.Name))
{
float labelW = ImGui.CalcTextSize(entry.Name).X;
labelH = ImGui.CalcTextSize(entry.Name).Y;
Vector2 labelPos = horizontal
? new Vector2(iconPos.X + iconSize.X + Config.Spacing, basePos.Y + (Config.Size.Y - labelH) / 2f)
: new Vector2(basePos.X + (Config.Size.X - labelW) / 2f, iconPos.Y + iconSize.Y + 2);
drawList.AddText(labelPos, Config.IconTint.Base, entry.Name);
}
if (horizontal)
{
float advance = iconSize.X + Config.Spacing;
if (Config.ShowLabels) advance += ImGui.CalcTextSize(entry.Name).X + Config.Spacing;
x += advance;
}
else
{
y += iconSize.Y + 2 + labelH + Config.Spacing;
}
index++;
}
drawList.PopClipRect();
// Draw context menu popup (same options as default main menu bar)
if (ImGui.BeginPopup("HSUI_MainMenu_Context", ImGuiWindowFlags.NoMove))
{
if (_contextMenuEntries != null)
{
foreach (var (cmdId, name) in _contextMenuEntries)
{
if (ImGui.Selectable(name))
{
uint commandId = cmdId;
Plugin.Framework.RunOnFrameworkThread(() => MainMenuHelper.ExecuteMainCommand(commandId));
ImGui.CloseCurrentPopup();
}
}
}
ImGui.EndPopup();
}
else
{
_contextMenuEntries = null;
}
}, true);
});
}
}
}