From 66f2cf3652900cf3e5208a96db6839b8bf6f7fea Mon Sep 17 00:00:00 2001 From: Dale McCoy <21223975+DaleStan@users.noreply.github.com> Date: Sat, 8 Jun 2024 16:23:45 -0400 Subject: [PATCH 1/3] feature: Allow additional data to be displayed in tooltips. --- Yafc/Widgets/ObjectTooltip.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Yafc/Widgets/ObjectTooltip.cs b/Yafc/Widgets/ObjectTooltip.cs index 8049ae1c..4584210c 100644 --- a/Yafc/Widgets/ObjectTooltip.cs +++ b/Yafc/Widgets/ObjectTooltip.cs @@ -145,6 +145,8 @@ protected override void BuildContents(ImGui gui) { private void BuildCommon(FactorioObject target, ImGui gui) { BuildHeader(gui); using (gui.EnterGroup(contentPadding)) { + tooltipOptions.DrawBelowHeader?.Invoke(gui); + if (InputSystem.Instance.control) { gui.BuildText(target.typeDotName); } @@ -545,8 +547,18 @@ public struct ObjectTooltipOptions { /// Gets or sets flags indicating where hints should be displayed in the tooltip. /// public HintLocations HintLocations { get; set; } + /// + /// Gets or sets a value that, if not null, will be called after drawing the tooltip header. + /// + public DrawBelowHeader? DrawBelowHeader { get; set; } // Reduce boilerplate by permitting unambiguous and relatively obvious implicit conversions. public static implicit operator ObjectTooltipOptions(HintLocations hintLocations) => new() { HintLocations = hintLocations }; + public static implicit operator ObjectTooltipOptions(DrawBelowHeader drawBelowHeader) => new() { DrawBelowHeader = drawBelowHeader }; } + + /// + /// Called to draw additional information in the tooltip after drawing the tooltip header. + /// + public delegate void DrawBelowHeader(ImGui gui); } From 145bc40121be7fcd13da6ad3c3050948a8c9ab4c Mon Sep 17 00:00:00 2001 From: Dale McCoy <21223975+DaleStan@users.noreply.github.com> Date: Mon, 9 Sep 2024 03:14:40 -0400 Subject: [PATCH 2/3] feature(#271): Show link warnings in tooltips, in addition to dropdowns. --- Yafc.Model/Model/ProductionTableContent.cs | 29 +++++++++++++ .../ProductionTable/ProductionTableView.cs | 41 ++++++++----------- changelog.txt | 10 ++--- 3 files changed, 51 insertions(+), 29 deletions(-) diff --git a/Yafc.Model/Model/ProductionTableContent.cs b/Yafc.Model/Model/ProductionTableContent.cs index f0060730..bd787d34 100644 --- a/Yafc.Model/Model/ProductionTableContent.cs +++ b/Yafc.Model/Model/ProductionTableContent.cs @@ -638,6 +638,35 @@ public enum Flags { [SkipSerialization] public HashSet capturedRecipes { get; } = []; internal int solverIndex; public float dualValue { get; internal set; } + + public IEnumerable LinkWarnings { + get { + if (!flags.HasFlags(Flags.HasProduction)) { + yield return "This link has no production (Link ignored)"; + } + + if (!flags.HasFlags(Flags.HasConsumption)) { + yield return "This link has no consumption (Link ignored)"; + } + + if (flags.HasFlags(Flags.ChildNotMatched)) { + yield return "Nested table link has unmatched production/consumption. These unmatched products are not captured by this link."; + } + + if (!flags.HasFlags(Flags.HasProductionAndConsumption) && owner.owner is RecipeRow recipeRow && recipeRow.FindLink(goods, out _)) { + yield return "Nested tables have their own set of links that DON'T connect to parent links. To connect this product to the outside, remove this link."; + } + + if (flags.HasFlags(Flags.LinkRecursiveNotMatched)) { + if (notMatchedFlow <= 0f) { + yield return "YAFC was unable to satisfy this link (Negative feedback loop). This doesn't mean that this link is the problem, but it is part of the loop."; + } + else { + yield return "YAFC was unable to satisfy this link (Overproduction). You can allow overproduction for this link to solve the error."; + } + } + } + } } public record RecipeRowIngredient(Goods? Goods, float Amount, ProductionLink? Link, Goods[]? Variants) { diff --git a/Yafc/Workspace/ProductionTable/ProductionTableView.cs b/Yafc/Workspace/ProductionTable/ProductionTableView.cs index 0d701d78..087ed9b5 100644 --- a/Yafc/Workspace/ProductionTable/ProductionTableView.cs +++ b/Yafc/Workspace/ProductionTable/ProductionTableView.cs @@ -777,29 +777,8 @@ void dropDownContent(ImGui gui) { } if (link != null) { - if (!link.flags.HasFlags(ProductionLink.Flags.HasProduction)) { - gui.BuildText("This link has no production (Link ignored)", TextBlockDisplayStyle.ErrorText); - } - - if (!link.flags.HasFlags(ProductionLink.Flags.HasConsumption)) { - gui.BuildText("This link has no consumption (Link ignored)", TextBlockDisplayStyle.ErrorText); - } - - if (link.flags.HasFlags(ProductionLink.Flags.ChildNotMatched)) { - gui.BuildText("Nested table link have unmatched production/consumption. These unmatched products are not captured by this link.", TextBlockDisplayStyle.ErrorText); - } - - if (!link.flags.HasFlags(ProductionLink.Flags.HasProductionAndConsumption) && link.owner.owner is RecipeRow recipeRow && recipeRow.FindLink(link.goods, out _)) { - gui.BuildText("Nested tables have their own set of links that DON'T connect to parent links. To connect this product to the outside, remove this link", TextBlockDisplayStyle.ErrorText); - } - - if (link.flags.HasFlags(ProductionLink.Flags.LinkRecursiveNotMatched)) { - if (link.notMatchedFlow <= 0f) { - gui.BuildText("YAFC was unable to satisfy this link (Negative feedback loop). This doesn't mean that this link is the problem, but it is part of the loop.", TextBlockDisplayStyle.ErrorText); - } - else { - gui.BuildText("YAFC was unable to satisfy this link (Overproduction). You can allow overproduction for this link to solve the error.", TextBlockDisplayStyle.ErrorText); - } + foreach (string warning in link.LinkWarnings) { + gui.BuildText(warning, TextBlockDisplayStyle.ErrorText); } } @@ -1017,6 +996,14 @@ private void DrawDesiredProduct(ImGui gui, ProductionLink element) { } ObjectTooltipOptions tooltipOptions = element.amount < 0 ? HintLocations.OnConsumingRecipes : HintLocations.OnProducingRecipes; + if (element.LinkWarnings is IEnumerable warnings) { + tooltipOptions.DrawBelowHeader = gui => { + foreach (string warning in warnings) { + gui.BuildText(warning, TextBlockDisplayStyle.ErrorText); + } + }; + } + DisplayAmount amount = new(element.amount, element.goods.flowUnitOfMeasure); switch (gui.BuildFactorioObjectWithEditableAmount(element.goods, amount, ButtonDisplayStyle.ProductionTableScaled(iconColor), tooltipOptions: tooltipOptions)) { case GoodsWithAmountEvent.LeftButtonClick: @@ -1075,6 +1062,14 @@ private void BuildGoodsIcon(ImGui gui, Goods? goods, ProductionLink? link, float GoodsWithAmountEvent evt; DisplayAmount displayAmount = new(amount, goods?.flowUnitOfMeasure ?? UnitOfMeasure.None); + if (link?.LinkWarnings is IEnumerable warnings) { + tooltipOptions.DrawBelowHeader += gui => { + foreach (string warning in warnings) { + gui.BuildText(warning, TextBlockDisplayStyle.ErrorText); + } + }; + } + if (recipe != null && recipe.fixedBuildings > 0 && ((dropdownType == ProductDropdownType.Fuel && recipe.fixedFuel) || (dropdownType == ProductDropdownType.Ingredient && recipe.fixedIngredient == goods) diff --git a/changelog.txt b/changelog.txt index 6773d5ae..ffa6ac1e 100644 --- a/changelog.txt +++ b/changelog.txt @@ -15,15 +15,13 @@ // Internal changes: // Changes to the code that do not affect the behavior of the program. ---------------------------------------------------------------------------------------------------------------------- -Version: 0.10.1 -Date: - Bugfixes: - - Fixed recipes now become accessible when their crafter does. ----------------------------------------------------------------------------------------------------------------------- Version: 0.10.0 Date: - Feature: + Features: - Add OSX-arm64 build. + - Display link warnings in both the tooltips and the dropdowns. + Bugfixes: + - Fixed recipes now become accessible when their crafter does. ---------------------------------------------------------------------------------------------------------------------- Version: 0.9.1 Date: September 8th 2024 From 3d1c00a62173d23b3bfe889adfc30a13a74adf8b Mon Sep 17 00:00:00 2001 From: Dale McCoy <21223975+DaleStan@users.noreply.github.com> Date: Mon, 9 Sep 2024 13:21:44 -0400 Subject: [PATCH 3/3] refactor: Rename "extendHeader" to "showTypeInHeader" --- Yafc/Widgets/ObjectTooltip.cs | 4 ++-- Yafc/Windows/DependencyExplorer.cs | 2 +- Yafc/Windows/SelectMultiObjectPanel.cs | 2 +- Yafc/Windows/SelectObjectPanel.cs | 6 +++--- Yafc/Windows/SelectSingleObjectPanel.cs | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Yafc/Widgets/ObjectTooltip.cs b/Yafc/Widgets/ObjectTooltip.cs index 4584210c..fd903a49 100644 --- a/Yafc/Widgets/ObjectTooltip.cs +++ b/Yafc/Widgets/ObjectTooltip.cs @@ -36,7 +36,7 @@ public ObjectTooltip() : base(new Padding(0f, 0f, 0f, 0.5f), 25f) { } private void BuildHeader(ImGui gui) { using (gui.EnterGroup(new Padding(1f, 0.5f), RectAllocator.LeftAlign, spacing: 0f)) { string name = target.text; - if (tooltipOptions.ExtendHeader && target is not Goods) { + if (tooltipOptions.ShowTypeInHeader && target is not Goods) { name = name + " (" + target.target.type + ")"; } @@ -542,7 +542,7 @@ public struct ObjectTooltipOptions { /// If and the target object is not a , this tooltip will specify the type of object. /// e.g. "Radar" is the item, "Radar (Recipe)" is the recipe, and "Radar (Entity)" is the building. /// - public bool ExtendHeader { get; set; } + public bool ShowTypeInHeader { get; set; } /// /// Gets or sets flags indicating where hints should be displayed in the tooltip. /// diff --git a/Yafc/Windows/DependencyExplorer.cs b/Yafc/Windows/DependencyExplorer.cs index 1f637fe4..9413ca35 100644 --- a/Yafc/Windows/DependencyExplorer.cs +++ b/Yafc/Windows/DependencyExplorer.cs @@ -45,7 +45,7 @@ private void DrawFactorioObject(ImGui gui, FactorioId id) { string text = fobj.locName + " (" + fobj.type + ")"; gui.RemainingRow(0.5f).BuildText(text, TextBlockDisplayStyle.WrappedText with { Color = fobj.IsAccessible() ? SchemeColor.BackgroundText : SchemeColor.BackgroundTextFaint }); } - if (gui.BuildFactorioObjectButtonBackground(gui.lastRect, fobj, tooltipOptions: new() { ExtendHeader = true }) == Click.Left) { + if (gui.BuildFactorioObjectButtonBackground(gui.lastRect, fobj, tooltipOptions: new() { ShowTypeInHeader = true }) == Click.Left) { Change(fobj); } } diff --git a/Yafc/Windows/SelectMultiObjectPanel.cs b/Yafc/Windows/SelectMultiObjectPanel.cs index 2ce3223c..a030208e 100644 --- a/Yafc/Windows/SelectMultiObjectPanel.cs +++ b/Yafc/Windows/SelectMultiObjectPanel.cs @@ -30,7 +30,7 @@ public static void Select(IEnumerable list, string header, Action selec protected override void NonNullElementDrawer(ImGui gui, FactorioObject element) { SchemeColor bgColor = results.Contains(element) ? SchemeColor.Primary : SchemeColor.None; - Click click = gui.BuildFactorioObjectButton(element, ButtonDisplayStyle.SelectObjectPanel(bgColor), new() { ExtendHeader = extendHeader }); + Click click = gui.BuildFactorioObjectButton(element, ButtonDisplayStyle.SelectObjectPanel(bgColor), new() { ShowTypeInHeader = showTypeInHeader }); if (checkMark(element)) { gui.DrawIcon(Rect.SideRect(gui.lastRect.TopLeft + new Vector2(1, 0), gui.lastRect.BottomRight - new Vector2(0, 1)), Icon.Check, SchemeColor.Green); diff --git a/Yafc/Windows/SelectObjectPanel.cs b/Yafc/Windows/SelectObjectPanel.cs index da120eb0..cdbc4191 100644 --- a/Yafc/Windows/SelectObjectPanel.cs +++ b/Yafc/Windows/SelectObjectPanel.cs @@ -17,9 +17,9 @@ public abstract class SelectObjectPanel : PseudoScreenWithResult { private string? noneTooltip; /// /// If and the object being hovered is not a , the should specify the type of object. - /// See also . + /// See also . /// - protected bool extendHeader { get; private set; } + protected bool showTypeInHeader { get; private set; } protected SelectObjectPanel() : base(40f) => list = new SearchableList(30, new Vector2(2.5f, 2.5f), ElementDrawer, ElementFilter); @@ -39,7 +39,7 @@ public abstract class SelectObjectPanel : PseudoScreenWithResult { protected void Select(IEnumerable list, string header, Action selectItem, IComparer? ordering, Action> mapResult, bool allowNone, string? noneTooltip = null) where U : FactorioObject { _ = MainScreen.Instance.ShowPseudoScreen(this); this.noneTooltip = noneTooltip; - extendHeader = typeof(U) == typeof(FactorioObject); + showTypeInHeader = typeof(U) == typeof(FactorioObject); List data = new List(list); ordering ??= DataUtils.DefaultOrdering; data.Sort(ordering!); // null-forgiving: We don't have any nulls in the list yet. diff --git a/Yafc/Windows/SelectSingleObjectPanel.cs b/Yafc/Windows/SelectSingleObjectPanel.cs index db1d9df6..3d1ba7ef 100644 --- a/Yafc/Windows/SelectSingleObjectPanel.cs +++ b/Yafc/Windows/SelectSingleObjectPanel.cs @@ -34,7 +34,7 @@ public static void SelectWithNone(IEnumerable list, string header, Action< => Instance.Select(list, header, selectItem, ordering, (obj, mappedAction) => mappedAction(obj), true, noneTooltip); protected override void NonNullElementDrawer(ImGui gui, FactorioObject element) { - if (gui.BuildFactorioObjectButton(element, ButtonDisplayStyle.SelectObjectPanel(SchemeColor.None), tooltipOptions: new() { ExtendHeader = extendHeader }) == Click.Left) { + if (gui.BuildFactorioObjectButton(element, ButtonDisplayStyle.SelectObjectPanel(SchemeColor.None), tooltipOptions: new() { ShowTypeInHeader = showTypeInHeader }) == Click.Left) { CloseWithResult(element); } }