From 75c7d98955e7b16648325ddf9931476b89ebdc43 Mon Sep 17 00:00:00 2001 From: safronov Date: Fri, 11 Feb 2022 21:08:42 +0300 Subject: [PATCH] Work on ProductionSummary groups --- .../ProductionSummaryFlatHierarchy.cs | 18 -- .../ProductionSummaryView.cs | 178 ++++++++++++------ .../ProductionTableFlatHierarchy.cs | 62 +++--- .../ProductionTable/ProductionTableView.cs | 4 +- YAFCmodel/Model/ProductionSummary.cs | 98 ++++++---- YAFCmodel/Model/ProductionTable.cs | 7 +- YAFCmodel/Model/ProductionTableContent.cs | 22 ++- 7 files changed, 233 insertions(+), 156 deletions(-) delete mode 100644 YAFC/Workspace/ProductionSummary/ProductionSummaryFlatHierarchy.cs diff --git a/YAFC/Workspace/ProductionSummary/ProductionSummaryFlatHierarchy.cs b/YAFC/Workspace/ProductionSummary/ProductionSummaryFlatHierarchy.cs deleted file mode 100644 index 7d253a8a..00000000 --- a/YAFC/Workspace/ProductionSummary/ProductionSummaryFlatHierarchy.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using YAFC.Model; -using YAFC.UI; - -namespace YAFC -{ - public class ProductionSummaryFlatHierarchy : FlatHierarchy - { - public ProductionSummaryFlatHierarchy(DataGrid grid, Action drawTableHeader) : base(grid, drawTableHeader) {} - protected override bool Expanded(ProductionSummaryGroup group) => group.expanded; - protected override ProductionSummaryGroup Subgroup(ProductionSummaryEntry row) => row.group; - protected override List Elements(ProductionSummaryGroup @group) => group.list; - protected override void SetOwner(ProductionSummaryEntry row, ProductionSummaryGroup newOwner) => row.SetOwner(newOwner); - protected override bool Filter(ProductionSummaryEntry row) => row.filterMatch; - protected override string emptyGroupMessage => "This is an empty group"; - } -} \ No newline at end of file diff --git a/YAFC/Workspace/ProductionSummary/ProductionSummaryView.cs b/YAFC/Workspace/ProductionSummary/ProductionSummaryView.cs index 67a7e432..0ad35b33 100644 --- a/YAFC/Workspace/ProductionSummary/ProductionSummaryView.cs +++ b/YAFC/Workspace/ProductionSummary/ProductionSummaryView.cs @@ -10,72 +10,156 @@ namespace YAFC public class ProductionSummaryView : ProjectPageView { private readonly DataGrid grid; - private readonly ProductionSummaryFlatHierarchy flatHierarchy; - private readonly SearchableList pagesDropdown; - private SearchQuery searchQuery; + private readonly FlatHierarchy flatHierarchy; private Goods filteredGoods; - private Func filteredGoodsFilter; private readonly Dictionary goodsToColumn = new Dictionary(); + private readonly PaddingColumn padding; private readonly SummaryColumn firstColumn; private readonly RestGoodsColumn lastColumn; public ProductionSummaryView() { + padding = new PaddingColumn(this); firstColumn = new SummaryColumn(this); lastColumn = new RestGoodsColumn(this); - grid = new DataGrid(firstColumn, lastColumn) {headerHeight = 4.2f}; - flatHierarchy = new ProductionSummaryFlatHierarchy(grid, null); - pagesDropdown = new SearchableList(30f, new Vector2(20f, 2f), PagesDropdownDrawer, PagesDropdownFilter); + grid = new DataGrid(padding, firstColumn, lastColumn) {headerHeight = 4.2f}; + flatHierarchy = new FlatHierarchy(grid, null, buildExpandedGroupRows:true); + } + + private class PaddingColumn : DataColumn + { + private readonly ProductionSummaryView view; + + public PaddingColumn(ProductionSummaryView view) : base(3f) + { + this.view = view; + } + + 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.ShevronDown : Icon.ShevronRight)) + { + row.subgroup.RecordUndo(true).expanded = !row.subgroup.expanded; + view.flatHierarchy.SetData(view.model.group); + } + } + } } private class SummaryColumn : DataColumn { private readonly ProductionSummaryView view; + private SearchQuery productionTableSearchQuery; + private readonly SearchableList pagesDropdown; + private ProductionSummaryGroup selectedGroup; public SummaryColumn(ProductionSummaryView view) : base(20f, 10f, 30f) { this.view = view; + pagesDropdown = new SearchableList(30f, new Vector2(20f, 2f), PagesDropdownDrawer, PagesDropdownFilter); } public override void BuildHeader(ImGui gui) { - gui.allocator = RectAllocator.LeftAlign; - if (gui.BuildButton(Icon.Plus, SchemeColor.Primary, SchemeColor.PrimalyAlt, SchemeColor.PrimalyAlt, 2)) + BuildButtons(gui, 2f, view.model.group); + } + + private void BuildButtons(ImGui gui, float size, ProductionSummaryGroup group) + { + using (gui.EnterRow()) { - view.pagesDropdown.data = Project.current.pages.Where(x => x.content is ProductionTable).ToArray(); - view.pagesDropdown.filter = view.searchQuery = new SearchQuery(); - gui.ShowDropDown(view.AddProductionTableDropdown); + if (gui.BuildButton(Icon.Plus, SchemeColor.Primary, SchemeColor.PrimalyAlt, SchemeColor.PrimalyAlt, size)) + { + pagesDropdown.data = Project.current.pages.Where(x => x.content is ProductionTable).ToArray(); + pagesDropdown.filter = productionTableSearchQuery = new SearchQuery(); + selectedGroup = group; + gui.ShowDropDown(AddProductionTableDropdown); + } + + if (gui.BuildButton(Icon.Folder, SchemeColor.Primary, SchemeColor.PrimalyAlt, SchemeColor.PrimalyAlt, size)) + { + var entry = new ProductionSummaryEntry(view.model.group); + entry.subgroup = new ProductionSummaryGroup(entry); + view.model.group.RecordUndo().elements.Add(entry); + } } } + + private void AddProductionTableDropdown(ImGui gui) + { + using (gui.EnterGroup(new Padding(1f))) + { + if (gui.BuildSearchBox(productionTableSearchQuery, out productionTableSearchQuery)) + pagesDropdown.filter = productionTableSearchQuery; + } + pagesDropdown.Build(gui); + } public override void BuildElement(ImGui gui, ProductionSummaryEntry entry) { gui.allocator = RectAllocator.LeftAlign; - using (gui.EnterGroup(new Padding(0.3f), RectAllocator.LeftRow, SchemeColor.None, 0.2f)) + + if (entry.subgroup != null) { - var icon = entry.icon; - if (icon != Icon.None) - gui.BuildIcon(entry.icon); - gui.BuildText(entry.name); + if (entry.subgroup.expanded) + BuildButtons(gui, 1.5f, entry.subgroup); + else + { + if (gui.BuildTextInput(entry.subgroup.name, out var newText, "Group name", delayed: true)) + entry.subgroup.RecordUndo().name = newText; + } } - - var buttonEvent = gui.BuildButton(gui.lastRect, SchemeColor.None, SchemeColor.BackgroundAlt); - if (buttonEvent == ButtonEvent.MouseOver) - MainScreen.Instance.ShowTooltip(gui, entry.page.page, false, gui.lastRect); - else if (buttonEvent == ButtonEvent.Click) - gui.ShowDropDown(tgui => + else + { + using (gui.EnterGroup(new Padding(0.3f), RectAllocator.LeftRow, SchemeColor.None, 0.2f)) { - if (tgui.BuildButton("Go to page") && tgui.CloseDropdown()) - MainScreen.Instance.SetActivePage(entry.page.page); - if (tgui.BuildRedButton("Remove") && tgui.CloseDropdown()) - view.model.group.RecordUndo().list.Remove(entry); - }); + var icon = entry.icon; + if (icon != Icon.None) + gui.BuildIcon(entry.icon); + gui.BuildText(entry.name); + } + + var buttonEvent = gui.BuildButton(gui.lastRect, SchemeColor.None, SchemeColor.BackgroundAlt); + if (buttonEvent == ButtonEvent.MouseOver && entry.page != null) + MainScreen.Instance.ShowTooltip(gui, entry.page.page, false, gui.lastRect); + else if (buttonEvent == ButtonEvent.Click) + gui.ShowDropDown(tgui => + { + if (tgui.BuildButton("Go to page") && tgui.CloseDropdown()) + MainScreen.Instance.SetActivePage(entry.page.page); + if (tgui.BuildRedButton("Remove") && tgui.CloseDropdown()) + view.model.group.RecordUndo().elements.Remove(entry); + }); + } using (gui.EnterFixedPositioning(3f, 2f, default)) { gui.allocator = RectAllocator.LeftRow; gui.BuildText("x"); if (gui.BuildFloatInput(entry.multiplier, out var newMultiplier, UnitOfMeasure.None, default) && newMultiplier >= 0) - entry.RecordUndo().multiplier = newMultiplier; + entry.SetMultiplier(newMultiplier); + } + } + + private bool PagesDropdownFilter(ProjectPage data, SearchQuery searchtokens) => searchtokens.Match(data.name); + + private void PagesDropdownDrawer(ImGui gui, ProjectPage element, int index) + { + using (gui.EnterGroup(new Padding(1f, 0.25f), RectAllocator.LeftRow)) + { + if (element.icon != null) + gui.BuildIcon(element.icon.icon); + gui.RemainingRow().BuildText(element.name, color:element.visible ? SchemeColor.BackgroundText : SchemeColor.BackgroundTextFaint); + } + + if (gui.BuildButton(gui.lastRect, SchemeColor.BackgroundAlt, SchemeColor.Background)) + { + selectedGroup.RecordUndo().elements.Add(new ProductionSummaryEntry(selectedGroup) {page = new PageReference(element)}); } } } @@ -156,32 +240,15 @@ private void ApplyFilter(Goods goods) { var filter = filteredGoods == goods ? null : goods; filteredGoods = filter; - filteredGoodsFilter = filter == null ? null : (Func) (entry => entry.flow.TryGetValue(filter, out var amount) && amount != 0); + model.group.UpdateFilter(goods, default); Rebuild(); } - private bool PagesDropdownFilter(ProjectPage data, SearchQuery searchtokens) => searchtokens.Match(data.name); - - private void PagesDropdownDrawer(ImGui gui, ProjectPage element, int index) - { - using (gui.EnterGroup(new Padding(1f, 0.25f), RectAllocator.LeftRow)) - { - if (element.icon != null) - gui.BuildIcon(element.icon.icon); - gui.RemainingRow().BuildText(element.name, color:element.visible ? SchemeColor.BackgroundText : SchemeColor.BackgroundTextFaint); - } - - if (gui.BuildButton(gui.lastRect, SchemeColor.BackgroundAlt, SchemeColor.Background)) - { - model.group.RecordUndo().list.Add(new ProductionSummaryEntry(model.group, new PageReference(element))); - } - } - private bool IsColumnsSynced() { - if (grid.columns.Count != model.columns.Count + 2) + if (grid.columns.Count != model.columns.Count + 3) return false; - var index = 1; + var index = 2; foreach (var column in model.columns) { if (!(grid.columns[index++] is GoodsColumn goodsColumn) || goodsColumn.goods != column.goods) @@ -202,6 +269,7 @@ private void SyncGridHeaderWithColumns() var columns = grid.columns; var modelColumns = model.columns; columns.Clear(); + columns.Add(padding); columns.Add(firstColumn); foreach (var column in modelColumns) { @@ -253,7 +321,7 @@ protected override void BuildContent(ImGui gui) gui.AllocateSpacing(1f); using (gui.EnterGroup(new Padding(1))) { - if (model.group.list.Count == 0) + if (model.group.elements.Count == 0) gui.BuildText("Add your existing sheets here to keep track of what you have in your base and to see what shortages you may have"); else gui.BuildText("List of goods produced/consumed by added blocks. Click on any of these to add it to (or remove it from) the table."); using (var igrid = gui.EnterInlineGrid(3f, 1f)) @@ -276,16 +344,6 @@ public override void Rebuild(bool visuaOnly = false) base.Rebuild(visuaOnly); } - private void AddProductionTableDropdown(ImGui gui) - { - using (gui.EnterGroup(new Padding(1f))) - { - if (gui.BuildSearchBox(searchQuery, out searchQuery)) - pagesDropdown.filter = searchQuery; - } - pagesDropdown.Build(gui); - } - public override void CreateModelDropdown(ImGui gui, Type type, Project project) { if (gui.BuildContextMenuButton("Create production summary (Preview)") && gui.CloseDropdown()) diff --git a/YAFC/Workspace/ProductionTable/ProductionTableFlatHierarchy.cs b/YAFC/Workspace/ProductionTable/ProductionTableFlatHierarchy.cs index 7b161079..a026a73b 100644 --- a/YAFC/Workspace/ProductionTable/ProductionTableFlatHierarchy.cs +++ b/YAFC/Workspace/ProductionTable/ProductionTableFlatHierarchy.cs @@ -5,7 +5,7 @@ namespace YAFC { - public abstract class FlatHierarchy where TRow : ModelObject where TGroup:ModelObject + public class FlatHierarchy where TRow : ModelObject, IGroupedElement where TGroup:ModelObject, IElementGroup { private readonly DataGrid grid; private readonly List flatRecipes = new List(); @@ -14,18 +14,15 @@ public abstract class FlatHierarchy where TRow : ModelObject drawTableHeader; + private readonly string emptyGroupMessage; + private readonly bool buildExpandedGroupRows; - protected abstract bool Expanded(TGroup group); - protected abstract TGroup Subgroup(TRow row); - protected abstract List Elements(TGroup group); - protected abstract void SetOwner(TRow row, TGroup newOwner); - protected abstract bool Filter(TRow row); - protected abstract string emptyGroupMessage { get; } - - protected FlatHierarchy(DataGrid grid, Action drawTableHeader) + public FlatHierarchy(DataGrid grid, Action drawTableHeader, string emptyGroupMessage = "This is an empty group", bool buildExpandedGroupRows = true) { this.grid = grid; this.drawTableHeader = drawTableHeader; + this.emptyGroupMessage = emptyGroupMessage; + this.buildExpandedGroupRows = buildExpandedGroupRows; } public float width => grid.width; @@ -45,8 +42,8 @@ public void SetData(TGroup table) { if (flatRecipes[i] is TRow recipe) { - var group = Subgroup(recipe); - if (group != null && Expanded(group)) + var group = recipe.subgroup; + if (group != null && group.expanded) return (group, currentIndex); } else @@ -61,12 +58,12 @@ private void ActuallyMoveDraggingRecipe() var (parent, index) = FindDragginRecipeParentAndIndex(); if (parent == null) return; - if (draggingRecipe.owner == parent && Elements(parent)[index] == draggingRecipe) + if (draggingRecipe.owner == parent && parent.elements[index] == draggingRecipe) return; - Elements(draggingRecipe.owner.RecordUndo()).Remove(draggingRecipe); - SetOwner(draggingRecipe, parent); - Elements(parent.RecordUndo()).Insert(index, draggingRecipe); + draggingRecipe.owner.RecordUndo().elements.Remove(draggingRecipe); + draggingRecipe.SetOwner(parent); + parent.RecordUndo().elements.Insert(index, draggingRecipe); } private void MoveFlatHierarchy(TRow from, TRow to) @@ -111,7 +108,7 @@ public void Build(ImGui gui) var item = flatGroups[i]; if (recipe != null) { - if (!Filter(recipe)) + if (!recipe.visible) { if (item != null) i = flatGroups.LastIndexOf(item); @@ -126,14 +123,18 @@ public void Build(ImGui gui) if (gui.isBuilding) depthStart.Push(gui.statePosition.Bottom); } - var rect = grid.BuildRow(gui, recipe, depWidth); - if (item == null && gui.InitiateDrag(rect, rect, recipe, bgColor)) - draggingRecipe = recipe; - else if (gui.ConsumeDrag(rect.Center, recipe)) - MoveFlatHierarchy(gui.GetDraggingObject(), recipe); + + if (buildExpandedGroupRows || item == null) + { + var rect = grid.BuildRow(gui, recipe, depWidth); + if (item == null && gui.InitiateDrag(rect, rect, recipe, bgColor)) + draggingRecipe = recipe; + else if (gui.ConsumeDrag(rect.Center, recipe)) + MoveFlatHierarchy(gui.GetDraggingObject(), recipe); + } if (item != null) { - if (Elements(item).Count == 0) + if (item.elements.Count == 0) { using (gui.EnterGroup(new Padding(0.5f+depWidth, 0.5f, 0.5f, 0.5f))) { @@ -175,11 +176,11 @@ private void Rebuild() private void BuildFlatHierarchy(TGroup table) { - foreach (var recipe in Elements(table)) + foreach (var recipe in table.elements) { flatRecipes.Add(recipe); - var sub = Subgroup(recipe); - if (sub != null && Expanded(sub)) + var sub = recipe.subgroup; + if (sub != null && sub.expanded) { flatGroups.Add(sub); BuildFlatHierarchy(sub); @@ -195,15 +196,4 @@ public void BuildHeader(ImGui gui) grid.BuildHeader(gui); } } - - public class ProductionTableFlatHierarchy : FlatHierarchy - { - public ProductionTableFlatHierarchy(DataGrid grid, Action drawTableHeader) : base(grid, drawTableHeader) {} - protected override bool Expanded(ProductionTable group) => group.expanded; - protected override ProductionTable Subgroup(RecipeRow row) => row.subgroup; - protected override List Elements(ProductionTable @group) => group.recipes; - protected override void SetOwner(RecipeRow row, ProductionTable newOwner) => row.SetOwner(newOwner); - protected override bool Filter(RecipeRow row) => row.searchMatch; - protected override string emptyGroupMessage => "This is a nested group. You can drag&drop recipes here. Nested groups can have its own linked materials"; - } } \ No newline at end of file diff --git a/YAFC/Workspace/ProductionTable/ProductionTableView.cs b/YAFC/Workspace/ProductionTable/ProductionTableView.cs index ab2db6aa..2b3c115a 100644 --- a/YAFC/Workspace/ProductionTable/ProductionTableView.cs +++ b/YAFC/Workspace/ProductionTable/ProductionTableView.cs @@ -12,12 +12,12 @@ namespace YAFC { public class ProductionTableView : ProjectPageView { - private readonly ProductionTableFlatHierarchy flatHierarchyBuilder; + private readonly FlatHierarchy flatHierarchyBuilder; public ProductionTableView() { var grid = new DataGrid(new RecipePadColumn(this), new RecipeColumn(this), new EntityColumn(this), new IngredientsColumn(this), new ProductsColumn(this), new ModulesColumn(this)); - flatHierarchyBuilder = new ProductionTableFlatHierarchy(grid, BuildSummary); + flatHierarchyBuilder = new FlatHierarchy(grid, BuildSummary, "This is a nested group. You can drag&drop recipes here. Nested groups can have its own linked materials"); } private abstract class ProductionTableDataColumn : TextDataColumn diff --git a/YAFCmodel/Model/ProductionSummary.cs b/YAFCmodel/Model/ProductionSummary.cs index 98cc0b68..d9505805 100644 --- a/YAFCmodel/Model/ProductionSummary.cs +++ b/YAFCmodel/Model/ProductionSummary.cs @@ -5,59 +5,62 @@ namespace YAFC.Model { - public class ProductionSummaryGroup : ModelObject + public class ProductionSummaryGroup : ModelObject, IElementGroup { public ProductionSummaryGroup(ModelObject owner) : base(owner) {} - public List list { get; } = new List(); + public List elements { get; } = new List(); public bool expanded { get; set; } + public string name { get; set; } - public void CollectSolvingTasks(List listToFill) + public void Solve(Dictionary totalFlow, float multiplier) { - foreach (var element in list) - { - var solutionTask = element.SolveIfNessessary(); - if (solutionTask != null) - listToFill.Add(solutionTask); - if (element.group != null) - element.group.CollectSolvingTasks(listToFill); - } - } - - public void Solve(Dictionary totalFlow) - { - foreach (var element in list) + foreach (var element in elements) element.RefreshFlow(); totalFlow.Clear(); - foreach (var row in list) + foreach (var row in elements) { foreach (var (item, amount) in row.flow) { totalFlow.TryGetValue(item, out var prev); - totalFlow[item] = prev + amount; + totalFlow[item] = prev + amount * multiplier; } } } + + public void UpdateFilter(Goods filteredGoods, SearchQuery searchQuery) + { + foreach (var element in elements) + element.UpdateFilter(filteredGoods, searchQuery); + } } - public class ProductionSummaryEntry : ModelObject + public class ProductionSummaryEntry : ModelObject, IGroupedElement { - public ProductionSummaryEntry(ProductionSummaryGroup owner, PageReference page) : base(owner) + public ProductionSummaryEntry(ProductionSummaryGroup owner) : base(owner) {} + + protected internal override void AfterDeserialize() { - this.page = page ?? throw new ArgumentNullException(nameof(page), "Page reference does not exist"); + // Must be either page reference, or subgroup, not both + if (subgroup == null && page == null) + throw new NotSupportedException("Referenced page does not exist"); + if (subgroup != null && page != null) + page = null; + base.AfterDeserialize(); } public float multiplier { get; set; } = 1; - public PageReference page { get; } - public ProductionSummaryGroup group { get; set; } - + public PageReference page { get; set; } + public ProductionSummaryGroup subgroup { get; set; } + public bool visible { get; private set; } = true; [SkipSerialization] public Dictionary flow { get; } = new Dictionary(); private bool needRefreshFlow = true; - public bool filterMatch = true; public Icon icon { get { + if (subgroup != null) + return Icon.Folder; if (page.page == null) return Icon.Warning; return page.page.icon?.icon ?? Icon.None; @@ -73,6 +76,25 @@ public string name return "Broken entry"; } } + + public bool CollectSolvingTasks(List listToFill) + { + var solutionTask = SolveIfNessessary(); + if (solutionTask != null) + { + listToFill.Add(solutionTask); + needRefreshFlow = true; + } + + if (subgroup != null) + { + foreach (var element in subgroup.elements) + { + needRefreshFlow |= element.CollectSolvingTasks(listToFill); + } + } + return needRefreshFlow; + } public Task SolveIfNessessary() { @@ -80,10 +102,7 @@ public Task SolveIfNessessary() return null; var solutionPagepage = page.page; if (solutionPagepage != null && solutionPagepage.IsSolutionStale()) - { - needRefreshFlow = true; return solutionPagepage.ExternalSolve(); - } return null; } @@ -98,9 +117,9 @@ public void RefreshFlow() return; needRefreshFlow = false; flow.Clear(); - if (group != null) + if (subgroup != null) { - group.Solve(flow); + subgroup.Solve(flow, multiplier); } else { @@ -127,6 +146,20 @@ public void SetOwner(ProductionSummaryGroup newOwner) { owner = newOwner; } + + public void UpdateFilter(Goods goods, SearchQuery query) + { + visible = flow.ContainsKey(goods); + if (subgroup != null) + subgroup.UpdateFilter(goods, query); + } + + public void SetMultiplier(float newMultiplier) + { + this.RecordUndo(); + needRefreshFlow = true; + multiplier = newMultiplier; + } } public class ProductionSummaryColumn : ModelObject @@ -162,11 +195,12 @@ public override void InitNew() public override async Task Solve(ProjectPage page) { var taskList = new List(); - group.CollectSolvingTasks(taskList); + foreach (var element in group.elements) + element.CollectSolvingTasks(taskList); if (taskList.Count > 0) await Task.WhenAll(taskList); columnsExist.Clear(); - group.Solve(totalFlow); + group.Solve(totalFlow, 1); foreach (var column in columns) columnsExist.Add(column.goods); diff --git a/YAFCmodel/Model/ProductionTable.cs b/YAFCmodel/Model/ProductionTable.cs index cb403d8b..6228d8bd 100644 --- a/YAFCmodel/Model/ProductionTable.cs +++ b/YAFCmodel/Model/ProductionTable.cs @@ -21,9 +21,10 @@ public ProductionTableFlow(Goods goods, float amount, ProductionLink link) } } - public class ProductionTable : ProjectPageContents, IComparer + public class ProductionTable : ProjectPageContents, IComparer, IElementGroup { [SkipSerialization] public Dictionary linkMap { get; } = new Dictionary(); + List IElementGroup.elements => recipes; public bool expanded { get; set; } = true; public List links { get; } = new List(); public List recipes { get; } = new List(); @@ -106,7 +107,7 @@ public bool Search(SearchQuery query) foreach (var recipe in recipes) { - recipe.searchMatch = false; + recipe.visible = false; if (recipe.subgroup != null && recipe.subgroup.Search(query)) goto match; if (recipe.recipe.Match(query) || recipe.fuel.Match(query) || recipe.entity.Match(query)) @@ -125,7 +126,7 @@ public bool Search(SearchQuery query) continue; // no match; match: hasMatch = true; - recipe.searchMatch = true; + recipe.visible = true; } if (hasMatch) diff --git a/YAFCmodel/Model/ProductionTableContent.cs b/YAFCmodel/Model/ProductionTableContent.cs index 4e34e103..04419ad4 100644 --- a/YAFCmodel/Model/ProductionTableContent.cs +++ b/YAFCmodel/Model/ProductionTableContent.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.RegularExpressions; using Google.OrTools.LinearSolver; using YAFC.UI; @@ -156,7 +157,20 @@ public struct RecipeLinks public ProductionLink spentFuel; } - public class RecipeRow : ModelObject, IModuleFiller + public interface IElementGroup + { + List elements { get; } + bool expanded { get; set; } + } + + public interface IGroupedElement + { + void SetOwner(TGroup newOwner); + TGroup subgroup { get; } + bool visible { get; } + } + + public class RecipeRow : ModelObject, IModuleFiller, IGroupedElement { public Recipe recipe { get; } // Variable parameters @@ -195,9 +209,7 @@ public ModuleTemplate modules } public ProductionTable subgroup { get; set; } - public HashSet variants { get; } = new HashSet(); - public bool hasVisibleChildren => subgroup != null && subgroup.expanded; - public ModuleEffects moduleEffects; + public HashSet variants { get; } = new HashSet(); [SkipSerialization] public ProductionTable linkRoot => subgroup ?? owner; // Computed variables @@ -223,7 +235,7 @@ public void ChangeVariant(T was, T now) where T:FactorioObject } public bool isOverviewMode => subgroup != null && !subgroup.expanded; public float buildingCount => (float) recipesPerSecond * parameters.recipeTime; - public bool searchMatch { get; internal set; } = true; + public bool visible { get; internal set; } = true; public RecipeRow(ProductionTable owner, Recipe recipe) : base(owner) {