using System.Collections.Generic; using Cthangover.Core.Bootstrap; using Cthangover.Core.Factories.Impls; using Cthangover.Core.Mods; using Cthangover.Core.Scenes; using Cthangover.Core.UI; using Cthangover.Core.UI.Theming; using Cthangover.Core.Utils; using Godot; using Cthangover.Mods.Interface.Theming; using Cthangover.Core.UI.Tool; namespace Cthangover.Mods.Interface.Tool { /// /// Main toolbar/HUD container (the TopView shell node). It no longer /// knows any concrete panel: buttons for mod-provided panels are handed to it /// by from , and /// pressing one calls . Tool buttons /// (/) remain a separate, /// self-registering mechanism and are added alongside the panel buttons. /// public partial class ToolBox : Control, IToolbarHost, ISaveIconHost { /// Side of a toolbar button and its icon: the icons are 64 px pixel-art sprites (scaled x4), so a /// 64 px slot shows every sprite pixel; at 60 px the nearest filter dropped rows of them. private const int SlotSize = 64; private HBoxContainer _buttons; private TextureRect _saveIcon; /// Wires the save icon visibility and appends the dev-tool buttons registered in . public override void _Ready() { _buttons = GetNodeOrNull("Buttons"); _saveIcon = GetNodeOrNull("CenterTools/Save"); UpdateSaveIconVisibility(); AddToolButtons(_buttons); } /// /// Materializes a toolbar button for every entry. Called once per shell by /// ; entries arrive pre-sorted by the registry /// (button index, then mod load order, then id). /// public void ApplyPanelButtons(IReadOnlyList entries) { if (_buttons == null || entries == null) return; foreach (var entry in entries) _buttons.AddChild(CreatePanelButton(entry)); } private static BaseButton CreatePanelButton(UiEntry entry) { var title = TranslationServer.Translate(entry.Button.Locale); var icon = UIIconFactory.Instance.Get(entry.Button.Icon); var button = CreateToolbarButton(title, icon); var id = entry.Id; button.Pressed += () => AppServices.Current.Ui.ToggleEntry(id); return button; } private static BaseButton CreateToolbarButton(string title, Texture2D icon) { var button = new Button { CustomMinimumSize = new Vector2(SlotSize, SlotSize), SizeFlagsVertical = SizeFlags.ShrinkCenter, TooltipText = title, }; if (icon != null) { var iconRect = UiKit.Icon(icon, SlotSize); button.AddChild(iconRect); iconRect.SetAnchorsAndOffsetsPreset(LayoutPreset.FullRect); } else { button.Text = title; } button.AddThemeStyleboxOverride("normal", UiKit.Frame(UiTokens.RadiusSm, UiTokens.Surface0, UiTokens.Line)); button.AddThemeStyleboxOverride("hover", UiKit.Frame(UiTokens.RadiusSm, UiTokens.Surface1, UiTokens.AccentLine)); button.AddThemeStyleboxOverride("pressed", UiKit.Frame(UiTokens.RadiusSm, UiTokens.Surface1, UiTokens.AccentLineStrong)); button.AddThemeStyleboxOverride("disabled", UiKit.Frame(UiTokens.RadiusSm, UiTokens.Surface0, UiTokens.LineDisabled)); button.AddThemeStyleboxOverride("focus", new StyleBoxEmpty()); return button; } /// /// Adds one "tools" toolbar button whose popup lists every visible /// . Tools used to get a text button each, /// which did not fit the square icon row and overlapped its icons; a /// single icon keeps the HUD row uniform no matter how many tools are /// installed. Nothing is added when no tool button is visible. /// private void AddToolButtons(HBoxContainer container) { if (container == null) return; var visible = new List(ToolBoxButtonFactory.Instance.GetVisible()); if (visible.Count == 0) return; visible.Sort((a, b) => string.Compare( TranslationServer.Translate(a.LocaleKey), TranslationServer.Translate(b.LocaleKey), System.StringComparison.CurrentCulture)); var btn = CreateToolbarButton(TranslationServer.Translate("tools/menu_title"), UIIconFactory.Instance.Get("tools")); var menu = new PopupMenu { Theme = ToolTheme.Get() }; foreach (var buttonDef in visible) menu.AddItem(TranslationServer.Translate(buttonDef.LocaleKey)); menu.IndexPressed += index => OpenTool(visible[(int)index].ToolId); btn.AddChild(menu); btn.Pressed += () => { var rect = btn.GetGlobalRect(); menu.Position = new Vector2I((int)rect.Position.X, (int)rect.End.Y + UiTokens.Space1); menu.Popup(); }; container.AddChild(btn); } private static void OpenTool(string toolId) { var tool = ToolFactory.Instance.Get(toolId); if (tool != null) ToolWindow.ShowWindow(tool.CreateWindow()); } /// /// Shows or hides the save icon based on . /// Call after scene transitions to reflect the new scene's save policy. /// public void UpdateSaveIconVisibility() { if (_saveIcon == null) return; _saveIcon.Visible = SceneManager.IsSaveAllowedForCurrentScene(); } } }