From 25e451f719e07962403aa65bf93225b7ec2583f3 Mon Sep 17 00:00:00 2001 From: Dale McCoy <21223975+DaleStan@users.noreply.github.com> Date: Fri, 26 Jul 2024 18:30:34 -0400 Subject: [PATCH] Add tooltips for the building count buttons in the select crafter menu. It is also now relatively easy to add a help icon to the end of any row. --- Yafc.UI/Core/Rect.cs | 1 + Yafc.UI/ImGui/ImGuiUtils.cs | 35 ++++++++ Yafc/Widgets/ImmediateWidgets.cs | 2 +- Yafc/Windows/PreferencesScreen.cs | 41 ++++------ .../ProductionTable/ProductionTableView.cs | 81 ++++++++++--------- changelog.txt | 1 + 6 files changed, 97 insertions(+), 64 deletions(-) diff --git a/Yafc.UI/Core/Rect.cs b/Yafc.UI/Core/Rect.cs index 8bc87d55..e85188c1 100644 --- a/Yafc.UI/Core/Rect.cs +++ b/Yafc.UI/Core/Rect.cs @@ -126,5 +126,6 @@ public override int GetHashCode() { public readonly Rect Expand(float amount) => new Rect(X - amount, Y - amount, Width + (2 * amount), Height + (2 * amount)); public static Rect Square(Vector2 center, float side) => new Rect(center.X - (side * 0.5f), center.Y - (side * 0.5f), side, side); + public static Rect Square(float centerX, float centerY, float side) => new Rect(centerX - (side * 0.5f), centerY - (side * 0.5f), side, side); } } diff --git a/Yafc.UI/ImGui/ImGuiUtils.cs b/Yafc.UI/ImGui/ImGuiUtils.cs index fee18335..b88f70dd 100644 --- a/Yafc.UI/ImGui/ImGuiUtils.cs +++ b/Yafc.UI/ImGui/ImGuiUtils.cs @@ -382,5 +382,40 @@ public static bool CloseDropdown(this ImGui gui) { gui.PropagateMessage(default); return true; } + + /// + /// Draws a row with a (?) help icon at its right side, and a tooltip when the user hovers over the icon. + /// + /// The tooltip that should be displayed when the user hovers over the (?) icon. + public static IDisposable EnterRowWithHelpIcon(this ImGui gui, string tooltip) => new RowWithHelpIcon(gui, tooltip); + + /// + /// The class that sets up and stores the state needed to build a row with a help icon. + /// + private sealed class RowWithHelpIcon : IDisposable { + private readonly ImGui gui; + private readonly string tooltip; + private readonly ImGui.Context row; + private readonly float helpCenterX; + private readonly ImGui.Context group; + + public RowWithHelpIcon(ImGui gui, string tooltip) { + this.gui = gui; + this.tooltip = tooltip; + row = gui.EnterRow(); // using (gui.EnterRow()) { + gui.allocator = RectAllocator.RightRow; + helpCenterX = gui.AllocateRect(1, 1).Center.X; + group = gui.EnterGroup(new Padding(), RectAllocator.RemainingRow); // using (gui.EnterGroup(...)) { // Required to produce the expected spacing/padding behavior. + gui.allocator = RectAllocator.LeftRow; + } + + public void Dispose() { + group.Dispose(); // end using block for EnterGroup + Rect rect = Rect.Square(helpCenterX, gui.lastRect.Center.Y, 1.25f); + gui.DrawIcon(rect, Icon.Help, SchemeColor.BackgroundText); + gui.BuildButton(rect, SchemeColor.None, SchemeColor.Grey).WithTooltip(gui, tooltip, rect); + row.Dispose(); // end using block for EnterRow + } + } } } diff --git a/Yafc/Widgets/ImmediateWidgets.cs b/Yafc/Widgets/ImmediateWidgets.cs index 86ba82ae..7befb7d3 100644 --- a/Yafc/Widgets/ImmediateWidgets.cs +++ b/Yafc/Widgets/ImmediateWidgets.cs @@ -156,7 +156,7 @@ public static bool BuildInlineObjectList(this ImGui gui, IEnumerable list, } if (checkMark != null && gui.isBuilding && checkMark(elem)) { - gui.DrawIcon(Rect.Square(new Vector2(gui.lastRect.Right - 1f, gui.lastRect.Center.Y), 1.5f), Icon.Check, SchemeColor.Green); + gui.DrawIcon(Rect.Square(gui.lastRect.Right - 1f, gui.lastRect.Center.Y, 1.5f), Icon.Check, SchemeColor.Green); } } diff --git a/Yafc/Windows/PreferencesScreen.cs b/Yafc/Windows/PreferencesScreen.cs index bc95fee3..c2b993b5 100644 --- a/Yafc/Windows/PreferencesScreen.cs +++ b/Yafc/Windows/PreferencesScreen.cs @@ -38,21 +38,21 @@ public override void Build(ImGui gui) { gui.BuildText("Fluid production/consumption:", Font.subheader); BuildUnitPerTime(gui, true, prefs); - drawInputRowWithTooltip(gui, "Pollution cost modifier", "0 for off, 100% for old default", - gui => { - if (gui.BuildFloatInput(settings.PollutionCostModifier, out float pollutionCostModifier, UnitOfMeasure.Percent, new Padding(0.5f))) { - settings.RecordUndo().PollutionCostModifier = pollutionCostModifier; - gui.Rebuild(); - } - }); + using (gui.EnterRowWithHelpIcon("0 for off, 100% for old default")) { + gui.BuildText("Pollution cost modifier", topOffset: 0.5f); + if (gui.BuildFloatInput(settings.PollutionCostModifier, out float pollutionCostModifier, UnitOfMeasure.Percent, new Padding(0.5f))) { + settings.RecordUndo().PollutionCostModifier = pollutionCostModifier; + gui.Rebuild(); + } + } - drawInputRowWithTooltip(gui, "Display scale for linkable icons", "Some mod icons have little or no transparency, hiding the background color. This setting reduces the size of icons that could hide link information.", - gui => { - if (gui.BuildFloatInput(prefs.iconScale, out float iconScale, UnitOfMeasure.Percent, new Padding(0.5f)) && iconScale > 0 && iconScale <= 1) { - prefs.RecordUndo().iconScale = iconScale; - gui.Rebuild(); - } - }); + using (gui.EnterRowWithHelpIcon("Some mod icons have little or no transparency, hiding the background color. This setting reduces the size of icons that could hide link information.")) { + gui.BuildText("Display scale for linkable icons", topOffset: 0.5f); + if (gui.BuildFloatInput(prefs.iconScale, out float iconScale, UnitOfMeasure.Percent, new Padding(0.5f)) && iconScale > 0 && iconScale <= 1) { + prefs.RecordUndo().iconScale = iconScale; + gui.Rebuild(); + } + } ChooseObject(gui, "Default belt:", Database.allBelts, prefs.defaultBelt, s => { prefs.RecordUndo().defaultBelt = s; @@ -100,19 +100,6 @@ public override void Build(ImGui gui) { if (settings.justChanged) { Project.current.RecalculateDisplayPages(); } - - static void drawInputRowWithTooltip(ImGui gui, string text, string tooltip, Action handleInput) { - using (gui.EnterRow()) { - gui.BuildText(text, topOffset: 0.5f); - gui.AllocateSpacing(); - gui.allocator = RectAllocator.RightRow; - var rect = gui.AllocateRect(1, 1); - handleInput(gui); - rect = new Rect(rect.Center.X, gui.lastRect.Center.Y, 0, 0).Expand(.625f); - gui.DrawIcon(rect, Icon.Help, SchemeColor.BackgroundText); - gui.BuildButton(rect, SchemeColor.None, SchemeColor.Grey).WithTooltip(gui, tooltip, rect); - } - } } protected override void ReturnPressed() => Close(); diff --git a/Yafc/Workspace/ProductionTable/ProductionTableView.cs b/Yafc/Workspace/ProductionTable/ProductionTableView.cs index 8d46db24..99bf725d 100644 --- a/Yafc/Workspace/ProductionTable/ProductionTableView.cs +++ b/Yafc/Workspace/ProductionTable/ProductionTableView.cs @@ -367,57 +367,66 @@ private static void ShowEntityDropdown(ImGui imgui, RecipeRow recipe) => imgui.S } }, "Select crafting entity", extra: x => DataUtils.FormatAmount(x.craftingSpeed, UnitOfMeasure.Percent)); - if (recipe.fixedBuildings > 0f) { - ButtonEvent evt = gui.BuildButton("Clear fixed building count"); - if (willResetFixed) { - evt.WithTooltip(gui, "Shortcut: right-click"); - } - if (evt && gui.CloseDropdown()) { - recipe.RecordUndo().fixedBuildings = 0f; + gui.AllocateSpacing(0.5f); + + using (gui.EnterRowWithHelpIcon("Tell YAFC how many buildings it must use when solving this page.\nUse this to ask questions like 'What does it take to handle the output of ten miners?'")) { + gui.allocator = RectAllocator.RemainingRow; + if (recipe.fixedBuildings > 0f) { + ButtonEvent evt = gui.BuildButton("Clear fixed building count"); + if (willResetFixed) { + evt.WithTooltip(gui, "Shortcut: right-click"); + } + if (evt && gui.CloseDropdown()) { + recipe.RecordUndo().fixedBuildings = 0f; + } } - } - else { - if (gui.BuildButton("Set fixed building count") && gui.CloseDropdown()) { + else if (gui.BuildButton("Set fixed building count") && gui.CloseDropdown()) { recipe.RecordUndo().fixedBuildings = recipe.buildingCount <= 0f ? 1f : recipe.buildingCount; } } - if (recipe.builtBuildings != null) { - ButtonEvent evt = gui.BuildButton("Clear built building count"); - if (willResetBuilt) { - evt.WithTooltip(gui, "Shortcut: right-click"); - } - if (evt && gui.CloseDropdown()) { - recipe.RecordUndo().builtBuildings = null; + using (gui.EnterRowWithHelpIcon("Tell YAFC how many of these buildings you have in your factory.\nYAFC will warn you if you need to build more buildings.")) { + gui.allocator = RectAllocator.RemainingRow; + if (recipe.builtBuildings != null) { + ButtonEvent evt = gui.BuildButton("Clear built building count"); + if (willResetBuilt) { + evt.WithTooltip(gui, "Shortcut: right-click"); + } + if (evt && gui.CloseDropdown()) { + recipe.RecordUndo().builtBuildings = null; + } } - } - else { - if (gui.BuildButton("Set built building count") && gui.CloseDropdown()) { + else if (gui.BuildButton("Set built building count") && gui.CloseDropdown()) { recipe.RecordUndo().builtBuildings = Math.Max(0, Convert.ToInt32(Math.Ceiling(recipe.buildingCount))); } } - if (recipe.entity != null && gui.BuildButton("Create single building blueprint") && gui.CloseDropdown()) { - BlueprintEntity entity = new BlueprintEntity { index = 1, name = recipe.entity.name }; - if (recipe.recipe is not Mechanics) { - entity.recipe = recipe.recipe.name; - } + if (recipe.entity != null) { + using (gui.EnterRowWithHelpIcon("Generate a blueprint for one of these buildings, with the recipe and internal modules set.")) { + gui.allocator = RectAllocator.RemainingRow; + if (gui.BuildButton("Create single building blueprint") && gui.CloseDropdown()) { + BlueprintEntity entity = new BlueprintEntity { index = 1, name = recipe.entity.name }; + if (recipe.recipe is not Mechanics) { + entity.recipe = recipe.recipe.name; + } - var modules = recipe.parameters.modules.modules; - if (modules != null) { - entity.items = []; - foreach (var (module, count, beacon) in modules) { - if (!beacon) { - entity.items[module.name] = count; + var modules = recipe.parameters.modules.modules; + if (modules != null) { + entity.items = []; + foreach (var (module, count, beacon) in modules) { + if (!beacon) { + entity.items[module.name] = count; + } + } } + BlueprintString bp = new BlueprintString(recipe.recipe.locName) { blueprint = { entities = { entity } } }; + _ = SDL.SDL_SetClipboardText(bp.ToBpString()); } } - BlueprintString bp = new BlueprintString(recipe.recipe.locName) { blueprint = { entities = { entity } } }; - _ = SDL.SDL_SetClipboardText(bp.ToBpString()); - } - if (recipe.recipe.crafters.Length > 1) { - BuildFavorites(gui, recipe.entity, "Add building to favorites"); + if (recipe.recipe.crafters.Length > 1) { + BuildFavorites(gui, recipe.entity, "Add building to favorites"); + } } }); diff --git a/changelog.txt b/changelog.txt index 65f8d559..2ec19594 100644 --- a/changelog.txt +++ b/changelog.txt @@ -16,6 +16,7 @@ Date: Features: - Autofocus the project name field when you create a new project - When opening the main window, use the same column widths as when it was last closed. + - Add explanatory tips for the buttons in the building dropdown. Bugfixes: - Sometimes, deleting and/or right-click resetting modules would not work. ----------------------------------------------------------------------------------------------------------------------