From 25c5a8983436972764f7a866c3bd620273b87c6a Mon Sep 17 00:00:00 2001 From: apocdev Date: Mon, 4 Aug 2025 12:59:28 -0400 Subject: [PATCH 1/3] Add Ctrl+C blueprint copy feature to production table - Add Ctrl+C shortcut to copy building blueprint for hovered recipe - Add 'Copy blueprint' button to recipe dropdown menu - Add tooltip showing Ctrl+C hint when hovering over recipes with buildings - Use existing BlueprintUtilities.ExportRecipiesAsBlueprint() for proper encoding - Include complete blueprint data: entity, recipe, modules, and fuel filters --- .../ProductionTable/ProductionTableView.cs | 66 ++++++++++++++++++- changelog.txt | 4 +- 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/Yafc/Workspace/ProductionTable/ProductionTableView.cs b/Yafc/Workspace/ProductionTable/ProductionTableView.cs index 64666029..ca484ff1 100644 --- a/Yafc/Workspace/ProductionTable/ProductionTableView.cs +++ b/Yafc/Workspace/ProductionTable/ProductionTableView.cs @@ -12,6 +12,7 @@ namespace Yafc; public class ProductionTableView : ProjectPageView { private readonly FlatHierarchy flatHierarchyBuilder; + private RecipeRow? hoveredRecipe; public ProductionTableView() { DataGrid grid = new DataGrid(new RecipePadColumn(this), new RecipeColumn(this), new EntityColumn(this), @@ -120,7 +121,22 @@ private static void BuildRowMarker(ImGui gui, RecipeRow row) { private class RecipeColumn(ProductionTableView view) : ProductionTableDataColumn(view, LSs.ProductionTableHeaderRecipe, 13f, 13f, 30f, widthStorage: nameof(Preferences.recipeColumnWidth)) { public override void BuildElement(ImGui gui, RecipeRow recipe) { gui.spacing = 0.5f; - switch (gui.BuildFactorioObjectButton(recipe.recipe, ButtonDisplayStyle.ProductionTableUnscaled)) { + var buttonEvent = gui.BuildFactorioObjectButton(recipe.recipe, ButtonDisplayStyle.ProductionTableUnscaled); + + // Track hovered recipe for Ctrl+C functionality and show tooltip + if (gui.IsMouseOver(gui.lastRect)) { + view.hoveredRecipe = recipe; + + // Show tooltip with Ctrl+C hint if the recipe has an entity (can generate blueprint) + if (recipe.entity != null) { + gui.ShowTooltip(gui.lastRect, tooltip => { + tooltip.BuildText(recipe.recipe.target.locName, Font.subheader); + tooltip.BuildText("Press Ctrl+C to copy building blueprint", TextBlockDisplayStyle.WrappedText); + }); + } + } + + switch (buttonEvent) { case Click.Left: gui.ShowDropDown(delegate (ImGui imgui) { DrawRecipeTagSelect(imgui, recipe); @@ -145,6 +161,11 @@ public override void BuildElement(ImGui gui, RecipeRow recipe) { view.BuildShoppingList(recipe); } + // Add "Copy blueprint" button if recipe has an entity + if (recipe.entity != null && imgui.BuildButton("Copy blueprint") && imgui.CloseDropdown()) { + view.CopyRecipeBlueprint(recipe); + } + if (imgui.BuildCheckBox(LSs.ProductionTableShowTotalIo, recipe.showTotalIO, out bool newShowTotalIO)) { recipe.RecordUndo().showTotalIO = newShowTotalIO; } @@ -1657,4 +1678,47 @@ void initializeGrid(ImGui gui) { } } } + + public override bool ControlKey(SDL.SDL_Scancode code) { + // Handle Ctrl+C to copy blueprint for hovered recipe + if (code == SDL.SDL_Scancode.SDL_SCANCODE_C && hoveredRecipe?.entity != null) { + CopyRecipeBlueprint(hoveredRecipe); + return true; + } + + return base.ControlKey(code); + } + + private void CopyRecipeBlueprint(RecipeRow recipe) { + if (recipe.entity == null) return; + + BlueprintEntity entity = new BlueprintEntity { index = 1, name = recipe.entity.target.name }; + + if (!recipe.recipe.Is()) { + entity.recipe = recipe.recipe.target.name; + entity.recipe_quality = recipe.recipe.quality.name; + } + + var modules = recipe.usedModules.modules; + + if (modules != null) { + int idx = 0; + foreach (var (module, count, beacon) in modules) { + if (!beacon) { + BlueprintItem item = new BlueprintItem { id = { name = module.target.name, quality = module.quality.name } }; + item.items.inInventory.AddRange(Enumerable.Range(idx, count).Select(i => new BlueprintInventoryItem { stack = i })); + entity.items.Add(item); + idx += count; + } + } + } + + if (Preferences.Instance.exportEntitiesWithFuelFilter && recipe.fuel is not null && !recipe.fuel.target.isPower) { + entity.SetFuel(recipe.fuel.target.name, recipe.fuel.quality.name); + } + + // Use the existing utility function to generate and copy the blueprint + // This automatically handles proper base64 encoding + _ = BlueprintUtilities.ExportRecipiesAsBlueprint(recipe.recipe.target.locName, [recipe], Preferences.Instance.exportEntitiesWithFuelFilter); + } } diff --git a/changelog.txt b/changelog.txt index 2bcadb1c..43524854 100644 --- a/changelog.txt +++ b/changelog.txt @@ -19,7 +19,9 @@ Version: Date: Features: - + - Add Ctrl+C shortcut to copy building blueprint for hovered recipe in production table. + - Add "Copy blueprint" button to recipe dropdown menu in production table. + - Add tooltip showing Ctrl+C hint when hovering over recipes with buildings. Fixes: - Fix icon rendering. - Hide fluid temperature options when not part of a recipe or not accepted by that recipe. From c690fc815e3c97fd009c4198252c2ecb860f2e35 Mon Sep 17 00:00:00 2001 From: apocdev Date: Tue, 5 Aug 2025 11:33:11 -0400 Subject: [PATCH 2/3] docs: add tooltip and button for copying building blueprints --- Yafc/Data/locale/en/yafc.cfg | 2 ++ Yafc/Workspace/ProductionTable/ProductionTableView.cs | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Yafc/Data/locale/en/yafc.cfg b/Yafc/Data/locale/en/yafc.cfg index 5bfbaaf9..adfe8c89 100644 --- a/Yafc/Data/locale/en/yafc.cfg +++ b/Yafc/Data/locale/en/yafc.cfg @@ -135,6 +135,8 @@ tooltip-entity-absorbs-pollution=Absorption: __1__ __2__ per minute tooltip-entity-emits-pollution=Emission: __1__ __2__ per minute tooltip-entity-requires-heat=Requires __1__ heat on cold planets. tooltip-item-spoils=After __1__, spoils into +tooltip-copy-building-blueprint=Press Ctrl+C to copy building blueprint +button-copy-blueprint=Copy blueprint ; AboutScreen.cs about-yafc=About YAFC-CE diff --git a/Yafc/Workspace/ProductionTable/ProductionTableView.cs b/Yafc/Workspace/ProductionTable/ProductionTableView.cs index ca484ff1..3279aa3d 100644 --- a/Yafc/Workspace/ProductionTable/ProductionTableView.cs +++ b/Yafc/Workspace/ProductionTable/ProductionTableView.cs @@ -131,7 +131,7 @@ public override void BuildElement(ImGui gui, RecipeRow recipe) { if (recipe.entity != null) { gui.ShowTooltip(gui.lastRect, tooltip => { tooltip.BuildText(recipe.recipe.target.locName, Font.subheader); - tooltip.BuildText("Press Ctrl+C to copy building blueprint", TextBlockDisplayStyle.WrappedText); + tooltip.BuildText(LSs.TooltipCopyBuildingBlueprint, TextBlockDisplayStyle.WrappedText); }); } } @@ -162,7 +162,7 @@ public override void BuildElement(ImGui gui, RecipeRow recipe) { } // Add "Copy blueprint" button if recipe has an entity - if (recipe.entity != null && imgui.BuildButton("Copy blueprint") && imgui.CloseDropdown()) { + if (recipe.entity != null && imgui.BuildButton(LSs.ButtonCopyBlueprint) && imgui.CloseDropdown()) { view.CopyRecipeBlueprint(recipe); } From 40288188d3bc84fb5996b3ab01be303ffaddca81 Mon Sep 17 00:00:00 2001 From: apocdev Date: Fri, 17 Oct 2025 00:11:48 -0400 Subject: [PATCH 3/3] refactor: simplify blueprint copying logic in ProductionTableView --- .../ProductionTable/ProductionTableView.cs | 31 ++----------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/Yafc/Workspace/ProductionTable/ProductionTableView.cs b/Yafc/Workspace/ProductionTable/ProductionTableView.cs index 3279aa3d..9c088875 100644 --- a/Yafc/Workspace/ProductionTable/ProductionTableView.cs +++ b/Yafc/Workspace/ProductionTable/ProductionTableView.cs @@ -1691,34 +1691,7 @@ public override bool ControlKey(SDL.SDL_Scancode code) { private void CopyRecipeBlueprint(RecipeRow recipe) { if (recipe.entity == null) return; - - BlueprintEntity entity = new BlueprintEntity { index = 1, name = recipe.entity.target.name }; - - if (!recipe.recipe.Is()) { - entity.recipe = recipe.recipe.target.name; - entity.recipe_quality = recipe.recipe.quality.name; - } - - var modules = recipe.usedModules.modules; - - if (modules != null) { - int idx = 0; - foreach (var (module, count, beacon) in modules) { - if (!beacon) { - BlueprintItem item = new BlueprintItem { id = { name = module.target.name, quality = module.quality.name } }; - item.items.inInventory.AddRange(Enumerable.Range(idx, count).Select(i => new BlueprintInventoryItem { stack = i })); - entity.items.Add(item); - idx += count; - } - } - } - - if (Preferences.Instance.exportEntitiesWithFuelFilter && recipe.fuel is not null && !recipe.fuel.target.isPower) { - entity.SetFuel(recipe.fuel.target.name, recipe.fuel.quality.name); - } - - // Use the existing utility function to generate and copy the blueprint - // This automatically handles proper base64 encoding - _ = BlueprintUtilities.ExportRecipiesAsBlueprint(recipe.recipe.target.locName, [recipe], Preferences.Instance.exportEntitiesWithFuelFilter); + + BlueprintUtilities.ExportRecipiesAsBlueprint(recipe.recipe.target.locName, [recipe], Preferences.Instance.exportEntitiesWithFuelFilter); } }