Skip to content

Commit 4db2c39

Browse files
committed
feat: Add configurable icons for non-recipe rows.
1 parent f64d790 commit 4db2c39

File tree

8 files changed

+117
-10
lines changed

8 files changed

+117
-10
lines changed

Yafc.Model.Tests/Serialization/SerializationTreeChangeDetection.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ public class SerializationTreeChangeDetection {
5858
},
5959
[typeof(RecipeRow)] = new() {
6060
[nameof(RecipeRow.recipe)] = typeof(IObjectWithQuality<RecipeOrTechnology>),
61+
[nameof(RecipeRow.icon)] = typeof(FactorioObject),
62+
[nameof(RecipeRow.description)] = typeof(string),
6163
[nameof(RecipeRow.entity)] = typeof(IObjectWithQuality<EntityCrafter>),
6264
[nameof(RecipeRow.fuel)] = typeof(IObjectWithQuality<Goods>),
6365
[nameof(RecipeRow.fixedBuildings)] = typeof(float),

Yafc.Model/Model/ProductionTableContent.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,9 @@ public sealed class RecipeRow : ModelObject<ProductionTable>, IGroupedElement<Pr
311311
private ModuleTemplate? _modules;
312312

313313
public IObjectWithQuality<RecipeOrTechnology>? recipe { get; }
314+
public FactorioObject? icon { get; set; }
315+
public string? description { get; set; }
316+
314317
// Variable parameters
315318
public IObjectWithQuality<EntityCrafter>? entity {
316319
get => _entity;

Yafc/Data/locale/en/yafc.cfg

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,8 @@ select-icon=Select icon
363363
page-settings-icon-hint=And select icon
364364
page-settings-create-header=Create new page
365365
page-settings-edit-header=Edit page icon and name
366+
header-settings-create-header=Create new header
367+
header-settings-edit-header=Edit icon and name
366368
create=Create
367369
ok=OK
368370
cancel=Cancel
@@ -749,6 +751,7 @@ production-table-header-ingredients=Ingredients
749751
production-table-header-products=Products
750752
production-table-header-modules=Modules
751753
production-table-add-raw-recipe=Add raw recipe
754+
production-table-add-table-header=Add nested table header
752755
production-table-add-technology=Add technology
753756
production-table-export-to-blueprint=Export inputs and outputs to blueprint with constant combinators:
754757
production-table-export-entities-to-blueprint=Export entities to blueprint

Yafc/Widgets/ImmediateWidgets.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ public static Click BuildFactorioObjectButtonBackground(this ImGui gui, Rect rec
135135

136136
var evt = gui.BuildButton(rect, bgColor, overColor, button: 0, drawTransparent: drawTransparent);
137137

138-
if (evt == ButtonEvent.MouseOver && obj != null) {
138+
if (evt == ButtonEvent.MouseOver && obj != null && !tooltipOptions.Hide) {
139139
MainScreen.Instance.ShowTooltip(obj, gui, rect, tooltipOptions);
140140
}
141141
else if (evt == ButtonEvent.Click) {

Yafc/Widgets/ObjectTooltip.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,10 @@ public struct ObjectTooltipOptions {
741741
/// Gets or sets a value that, if not <see langword="null"/>, will be called after drawing the spoilage information.
742742
/// </summary>
743743
public GuiBuilder ExtraSpoilInformation { get; set; }
744+
/// <summary>
745+
/// If <see langword="true"/>, a tooltip will not be shown for this object.
746+
/// </summary>
747+
public bool Hide { get; set; }
744748

745749
// Reduce boilerplate by permitting unambiguous and relatively obvious implicit conversions.
746750
public static implicit operator ObjectTooltipOptions(HintLocations hintLocations) => new() { HintLocations = hintLocations };
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using System;
2+
using Yafc.I18n;
3+
using Yafc.Model;
4+
using Yafc.UI;
5+
6+
namespace Yafc;
7+
8+
public class HeaderRowSettingsPanel : PseudoScreen {
9+
private readonly RecipeRow? editingRow;
10+
private string? description;
11+
private FactorioObject? icon;
12+
private readonly Action<string?, FactorioObject?>? callback;
13+
14+
private bool CanSave => !string.IsNullOrEmpty(description) || icon != null;
15+
16+
private HeaderRowSettingsPanel(RecipeRow? editingRow, Action<string?, FactorioObject?>? callback) {
17+
this.editingRow = editingRow;
18+
description = editingRow?.description;
19+
icon = editingRow?.icon;
20+
this.callback = callback;
21+
}
22+
23+
private void Build(ImGui gui, Action<FactorioObject?> setIcon) {
24+
_ = gui.BuildTextInput(description, out description, LSs.PageSettingsNameHint, setKeyboardFocus: editingRow == null ? SetKeyboardFocus.OnFirstPanelDraw : SetKeyboardFocus.No);
25+
if (gui.BuildFactorioObjectButton(icon, new ButtonDisplayStyle(4f, MilestoneDisplay.None, SchemeColor.Grey) with { UseScaleSetting = false }) == Click.Left) {
26+
SelectSingleObjectPanel.Select(Database.objects.all, new(LSs.SelectIcon), setIcon);
27+
}
28+
29+
if (icon == null && gui.isBuilding) {
30+
gui.DrawText(gui.lastRect, LSs.PageSettingsIconHint, RectAlignment.Middle);
31+
}
32+
}
33+
34+
public static void Show(RecipeRow? row, Action<string?, FactorioObject?>? callback = null) => _ = MainScreen.Instance.ShowPseudoScreen(new HeaderRowSettingsPanel(row, callback));
35+
36+
public override void Build(ImGui gui) {
37+
gui.spacing = 3f;
38+
BuildHeader(gui, editingRow == null ? LSs.HeaderSettingsCreateHeader : LSs.HeaderSettingsEditHeader);
39+
Build(gui, s => {
40+
icon = s;
41+
Rebuild();
42+
});
43+
44+
using (gui.EnterRow(0.5f, RectAllocator.RightRow)) {
45+
if (editingRow == null && gui.BuildButton(LSs.Create, active: CanSave)) {
46+
ReturnPressed();
47+
}
48+
49+
if (editingRow != null && gui.BuildButton(LSs.Ok, active: CanSave)) {
50+
ReturnPressed();
51+
}
52+
53+
if (gui.BuildButton(LSs.Cancel, SchemeColor.Grey)) {
54+
Close();
55+
}
56+
}
57+
}
58+
59+
protected override void ReturnPressed() {
60+
if (!CanSave) {
61+
// Prevent closing with empty information
62+
return;
63+
}
64+
if (editingRow is null) {
65+
callback?.Invoke(description, icon);
66+
}
67+
else if (editingRow.description != description || editingRow.icon != icon) {
68+
editingRow.RecordUndo(true).description = description;
69+
editingRow.icon = icon;
70+
}
71+
Close();
72+
}
73+
}

Yafc/Workspace/ProductionTable/ProductionTableView.cs

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,18 @@ private static void BuildRowMarker(ImGui gui, RecipeRow row) {
120120
private class RecipeColumn(ProductionTableView view) : ProductionTableDataColumn(view, LSs.ProductionTableHeaderRecipe, 13f, 13f, 30f, widthStorage: nameof(Preferences.recipeColumnWidth)) {
121121
public override void BuildElement(ImGui gui, RecipeRow recipe) {
122122
gui.spacing = 0.5f;
123-
switch (gui.BuildFactorioObjectButton(recipe.recipe, ButtonDisplayStyle.ProductionTableUnscaled)) {
124-
case Click.Left when recipe.recipe != null:
123+
IFactorioObjectWrapper? display = (IFactorioObjectWrapper?)recipe.recipe ?? recipe.icon;
124+
ObjectTooltipOptions tooltip = new() { Hide = recipe.recipe == null };
125+
126+
switch (gui.BuildFactorioObjectButton(display, ButtonDisplayStyle.ProductionTableUnscaled, tooltip)) {
127+
case Click.Left:
125128
gui.ShowDropDown(delegate (ImGui imgui) {
126129
DrawRecipeTagSelect(imgui, recipe);
127130

131+
if (recipe.recipe == null && imgui.BuildButton(LSs.EditPageProperties) && imgui.CloseDropdown()) {
132+
HeaderRowSettingsPanel.Show(recipe);
133+
}
134+
128135
if (recipe.subgroup == null && imgui.BuildButton(LSs.ProductionTableCreateNested) && imgui.CloseDropdown()) {
129136
recipe.RecordUndo().subgroup = new ProductionTable(recipe);
130137
}
@@ -134,7 +141,7 @@ public override void BuildElement(ImGui gui, RecipeRow recipe) {
134141
}
135142

136143
if (recipe.subgroup != null) {
137-
BuildRecipeButton(imgui, recipe.subgroup);
144+
BuildRecipeButtons(imgui, recipe.subgroup);
138145
}
139146

140147
if (recipe.subgroup != null && imgui.BuildButton(LSs.ProductionTableUnpackNested).WithTooltip(imgui, recipe.subgroup.expanded ? LSs.ProductionTableShortcutRightClick : LSs.ProductionTableShortcutExpandAndRightClick) && imgui.CloseDropdown()) {
@@ -145,15 +152,17 @@ public override void BuildElement(ImGui gui, RecipeRow recipe) {
145152
view.BuildShoppingList(recipe);
146153
}
147154

148-
if (imgui.BuildCheckBox(LSs.ProductionTableShowTotalIo, recipe.showTotalIO, out bool newShowTotalIO)) {
155+
if (recipe.recipe != null && imgui.BuildCheckBox(LSs.ProductionTableShowTotalIo, recipe.showTotalIO, out bool newShowTotalIO)) {
149156
recipe.RecordUndo().showTotalIO = newShowTotalIO;
150157
}
151158

152159
if (imgui.BuildCheckBox(LSs.Enabled, recipe.enabled, out bool newEnabled)) {
153160
recipe.RecordUndo().enabled = newEnabled;
154161
}
155162

156-
BuildFavorites(imgui, recipe.recipe.target, LSs.AddRecipeToFavorites);
163+
if (recipe.recipe != null) {
164+
BuildFavorites(imgui, recipe.recipe.target, LSs.AddRecipeToFavorites);
165+
}
157166

158167
if (recipe.subgroup != null && imgui.BuildRedButton(LSs.ProductionTableDeleteNested).WithTooltip(imgui, recipe.subgroup.expanded ? LSs.ProductionTableShortcutCollapseAndRightClick : LSs.ProductionTableShortcutRightClick) && imgui.CloseDropdown()) {
159168
_ = recipe.owner.RecordUndo().recipes.Remove(recipe);
@@ -182,7 +191,7 @@ public override void BuildElement(ImGui gui, RecipeRow recipe) {
182191
gui.textColor = recipe.hierarchyEnabled ? SchemeColor.BackgroundText : SchemeColor.BackgroundTextFaint;
183192
}
184193

185-
gui.BuildText(recipe.recipe?.target.locName, TextBlockDisplayStyle.WrappedText);
194+
gui.BuildText(recipe.recipe?.target.locName ?? recipe.description, recipe.recipe != null || recipe.isOverviewMode ? TextBlockDisplayStyle.WrappedText : TextBlockDisplayStyle.Default());
186195

187196
void unpackNestedTable() {
188197
var evacuate = recipe.subgroup.recipes;
@@ -209,7 +218,7 @@ private static void RemoveZeroRecipes(ProductionTable productionTable) {
209218
}
210219

211220
public override void BuildMenu(ImGui gui) {
212-
BuildRecipeButton(gui, view.model);
221+
BuildRecipeButtons(gui, view.model);
213222

214223
gui.BuildText(LSs.ProductionTableExportToBlueprint, TextBlockDisplayStyle.WrappedText);
215224
using (gui.EnterRow()) {
@@ -263,10 +272,10 @@ public override void BuildMenu(ImGui gui) {
263272
}
264273

265274
/// <summary>
266-
/// Build the "Add raw recipe" button and handle its clicks.
275+
/// Build the "Add raw recipe" and "Add table header" buttons and handle their clicks.
267276
/// </summary>
268277
/// <param name="table">The table that will receive the new recipes or technologies, if any are selected</param>
269-
private static void BuildRecipeButton(ImGui gui, ProductionTable table) {
278+
private static void BuildRecipeButtons(ImGui gui, ProductionTable table) {
270279
if (gui.BuildButton(LSs.ProductionTableAddRawRecipe).WithTooltip(gui, LSs.ProductionTableAddTechnologyHint) && gui.CloseDropdown()) {
271280
if (InputSystem.Instance.control) {
272281
SelectMultiObjectPanel.Select(Database.technologies.all, new(LSs.ProductionTableAddTechnology, Multiple: true,
@@ -279,6 +288,17 @@ private static void BuildRecipeButton(ImGui gui, ProductionTable table) {
279288
r => table.AddRecipe(r, DefaultVariantOrdering));
280289
}
281290
}
291+
292+
if (gui.BuildButton(LSs.ProductionTableAddTableHeader) && gui.CloseDropdown()) {
293+
HeaderRowSettingsPanel.Show(null, (description, icon) => {
294+
RecipeRow newRow = new(table, null) {
295+
description = description,
296+
icon = icon,
297+
};
298+
newRow.subgroup = new(newRow);
299+
table.RecordUndo().recipes.Add(newRow);
300+
});
301+
}
282302
}
283303

284304
private void ExportIo(float multiplier) {

changelog.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
----------------------------------------------------------------------------------------------------------------------
2222
Version:
2323
Date:
24+
Features:
25+
- Support tables without a header recipe.
2426
Fixes:
2527
- Support craft-fluid and scripted research triggers.
2628
- Consider quality restrictions when analyzing craft-item or build-item technology triggers.

0 commit comments

Comments
 (0)