-
Notifications
You must be signed in to change notification settings - Fork 39
refactor(model,ui): Decouple Yafc.UI.Icon From Yafc.Model via Integer Handle #587
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -230,9 +230,10 @@ private void RenderIcons() { | |||||
| cache[(".", digit.ToString())] = SDL_image.IMG_Load("Data/Digits/" + digit + ".png"); | ||||||
| } | ||||||
|
|
||||||
| DataUtils.NoFuelIcon = CreateSimpleIcon(cache, "fuel-icon-red"); | ||||||
| DataUtils.WarningIcon = CreateSimpleIcon(cache, "warning-icon"); | ||||||
| DataUtils.HandIcon = CreateSimpleIcon(cache, "hand"); | ||||||
| SystemIcons.Initialize( | ||||||
| noFuelIcon: CreateSimpleIcon(cache, "fuel-icon-red"), | ||||||
| warningIcon: CreateSimpleIcon(cache, "warning-icon"), | ||||||
| handIcon: CreateSimpleIcon(cache, "hand")); | ||||||
|
|
||||||
| Dictionary<string, Icon> simpleSpritesCache = []; | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| int rendered = 0; | ||||||
|
|
@@ -246,23 +247,23 @@ private void RenderIcons() { | |||||
| bool simpleSprite = o.iconSpec.Length == 1 && o.iconSpec[0].IsSimple(); | ||||||
|
|
||||||
| if (simpleSprite && simpleSpritesCache.TryGetValue(o.iconSpec[0].path, out var icon)) { | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| o.icon = icon; | ||||||
| o.iconId = (int)icon; | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| continue; | ||||||
| } | ||||||
|
|
||||||
| try { | ||||||
| o.icon = CreateIconFromSpec(cache, o.iconSpec); | ||||||
| o.iconId = (int)CreateIconFromSpec(cache, o.iconSpec); | ||||||
|
|
||||||
| if (simpleSprite) { | ||||||
| simpleSpritesCache[o.iconSpec[0].path] = o.icon; | ||||||
| simpleSpritesCache[o.iconSpec[0].path] = (Icon)o.iconId; | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| } | ||||||
| } | ||||||
| catch (Exception ex) { | ||||||
| Console.Error.WriteException(ex); | ||||||
| } | ||||||
| } | ||||||
| else if (o is Recipe recipe && recipe.mainProduct != null) { | ||||||
| o.icon = recipe.mainProduct.icon; | ||||||
| o.iconId = recipe.mainProduct.iconId; | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| namespace Yafc.UI; | ||
|
|
||
| /// <summary> | ||
| /// Holds the set of game-sourced system icons (e.g. fuel, warning, hand) that are | ||
| /// rendered from Factorio's own sprite files during the data loading phase. | ||
| /// These are distinct from the built-in YAFC vector icons defined in <see cref="Icon"/>. | ||
| /// </summary> | ||
| public static class SystemIcons { | ||
| /// <summary> | ||
| /// The icon used to indicate a missing or invalid fuel source. | ||
| /// Set during data loading; no UI consumer yet (pre-existing). | ||
| /// </summary> | ||
| public static Icon NoFuelIcon { get; private set; } | ||
|
|
||
| /// <summary> | ||
| /// The icon used to display a general warning. | ||
| /// Set during data loading; no UI consumer yet (pre-existing). | ||
| /// </summary> | ||
| public static Icon WarningIcon { get; private set; } | ||
|
|
||
| /// <summary>The hand/grab icon used to mark certain special goods (e.g. void energy).</summary> | ||
| public static Icon HandIcon { get; private set; } | ||
|
|
||
| /// <summary> | ||
| /// Initializes the set of game-sourced system icons after they are rendered from Factorio assets. | ||
| /// </summary> | ||
| public static void Initialize(Icon noFuelIcon, Icon warningIcon, Icon handIcon) { | ||
| NoFuelIcon = noFuelIcon; | ||
| WarningIcon = warningIcon; | ||
| HandIcon = handIcon; | ||
| } | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| using Yafc.Model; | ||
| using Yafc.UI; | ||
|
|
||
| namespace Yafc; | ||
|
|
||
| /// <summary> | ||
| /// Extension methods that bridge domain objects (<see cref="FactorioObject"/>) to their | ||
| /// UI representation (<see cref="Icon"/>), keeping the domain layer free of UI concerns. | ||
| /// This bridge currently lives in the app layer because <c>Yafc.UI</c> does not reference | ||
| /// <c>Yafc.Model</c>; move it once dependency boundaries are reworked. | ||
| /// </summary> | ||
| public static class FactorioObjectIconExtensions { | ||
| /// <summary> | ||
| /// Returns the <see cref="Icon"/> value associated with this <see cref="FactorioObject"/>. | ||
| /// The domain object stores this as an integer handle (<see cref="FactorioObject.iconId"/>); | ||
| /// this method converts it to the <see cref="Icon"/> enum for rendering. | ||
| /// </summary> | ||
| public static Icon GetIcon(this FactorioObject obj) => (Icon)obj.iconId; | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -30,9 +30,10 @@ public override void BuildHeader(ImGui gui) { } | |||||
| public override void BuildElement(ImGui gui, ProductionSummaryEntry row) { | ||||||
| gui.allocator = RectAllocator.Center; | ||||||
| gui.spacing = 0f; | ||||||
| if (row.subgroup != null) { | ||||||
| if (gui.BuildButton(row.subgroup.expanded ? Icon.ChevronDown : Icon.ChevronRight)) { | ||||||
| row.subgroup.RecordChange().expanded = !row.subgroup.expanded; | ||||||
| if (row.IsSubgroup) { | ||||||
| var subgroup = row.subgroup!; // IsSubgroup guarantees subgroup != null | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| if (gui.BuildButton(subgroup.expanded ? Icon.ChevronDown : Icon.ChevronRight)) { | ||||||
| subgroup.RecordChange().expanded = !subgroup.expanded; | ||||||
| view.flatHierarchy.SetData(view.model.group); | ||||||
| } | ||||||
| } | ||||||
|
|
@@ -75,21 +76,22 @@ private GuiBuilder AddProductionTableDropdown(SearchableList<ProjectPage> pagesD | |||||
| public override void BuildElement(ImGui gui, ProductionSummaryEntry entry) { | ||||||
| gui.allocator = RectAllocator.LeftAlign; | ||||||
|
|
||||||
| if (entry.subgroup != null) { | ||||||
| if (entry.subgroup.expanded) { | ||||||
| BuildButtons(gui, 1.5f, entry.subgroup); | ||||||
| if (entry.IsSubgroup) { | ||||||
| var subgroup = entry.subgroup!; // IsSubgroup guarantees subgroup != null | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| if (subgroup.expanded) { | ||||||
| BuildButtons(gui, 1.5f, subgroup); | ||||||
| } | ||||||
| else { | ||||||
| if (gui.BuildTextInput(entry.subgroup.name, out string newText, LSs.LegacySummaryGroupNameHint, delayed: true)) { | ||||||
| entry.subgroup.RecordUndo().name = newText; | ||||||
| if (gui.BuildTextInput(subgroup.name, out string newText, LSs.LegacySummaryGroupNameHint, delayed: true)) { | ||||||
| subgroup.RecordUndo().name = newText; | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| else if (entry.page != null) { // The constructor should have thrown if this check fails, but it helps the nullability analysis | ||||||
| using (gui.EnterGroup(new Padding(0.3f), RectAllocator.LeftRow, SchemeColor.None, 0.2f)) { | ||||||
| var icon = entry.icon; | ||||||
| Icon icon = entry.IsMissingPage ? Icon.Warning : entry.page.page!.icon?.GetIcon() ?? Icon.None; | ||||||
| if (icon != Icon.None) { | ||||||
| gui.BuildIcon(entry.icon); | ||||||
| gui.BuildIcon(icon); | ||||||
| } | ||||||
|
|
||||||
| gui.BuildText(entry.name); | ||||||
|
|
@@ -129,7 +131,7 @@ public override void BuildElement(ImGui gui, ProductionSummaryEntry entry) { | |||||
| private static VirtualScrollList<ProjectPage>.Drawer PagesDropdownDrawer(ProductionSummaryGroup group) => (gui, element, _) => { | ||||||
| using (gui.EnterGroup(new Padding(1f, 0.25f), RectAllocator.LeftRow)) { | ||||||
| if (element.icon != null) { | ||||||
| gui.BuildIcon(element.icon.icon); | ||||||
| gui.BuildIcon(element.icon.GetIcon()); | ||||||
| } | ||||||
|
|
||||||
| gui.RemainingRow().BuildText(element.name, TextBlockDisplayStyle.Default(element.visible ? SchemeColor.BackgroundText : SchemeColor.BackgroundTextFaint)); | ||||||
|
|
@@ -189,7 +191,7 @@ public override void BuildElement(ImGui gui, ProductionSummaryEntry data) { | |||||
|
|
||||||
| if (!view.model.columnsExist.Contains(goods)) { | ||||||
| grid.Next(); | ||||||
| var evt = gui.BuildButton(goods.target.icon, amount > 0f ? SchemeColor.Green : SchemeColor.None, size: 1.5f); | ||||||
| var evt = gui.BuildButton(goods.target.GetIcon(), amount > 0f ? SchemeColor.Green : SchemeColor.None, size: 1.5f); | ||||||
| if (evt == ButtonEvent.Click) { | ||||||
| view.AddOrRemoveColumn(goods); | ||||||
| } | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Note that this also needs an additional
usingdirective.)