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; /// Extra padding around content when drawing the background so the bar doesn't extend past the icons. private const float BackgroundEdgePad = 2f; private MainMenuConfig Config => (MainMenuConfig)_config; public VisibilityConfig VisibilityConfig => Config.VisibilityConfig; /// When set, the context menu with these entries should be shown (same frame or next). Cleared when popup closes. private List<(uint CommandId, string Name)>? _contextMenuEntries = null; public MainMenuHud(MainMenuConfig config, string displayName) : base(config, displayName) { } protected override (List, List) ChildrenPositionsAndSizes() { return (new List { Config.Position }, new List { 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); }); } } }