Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ public class SerializationTreeChangeDetection {
[nameof(ProjectModuleTemplate.icon)] = typeof(FactorioObject),
[nameof(ProjectModuleTemplate.name)] = typeof(string),
[nameof(ProjectModuleTemplate.filterEntities)] = typeof(List<Entity>),
[nameof(ProjectModuleTemplate.autoApplyToNewRows)] = typeof(bool),
[nameof(ProjectModuleTemplate.autoApplyIfIncompatible)] = typeof(bool),
},
[typeof(ProjectPage)] = new() {
[nameof(ProjectPage.icon)] = typeof(FactorioObject),
Expand Down
2 changes: 2 additions & 0 deletions Yafc.Model/Model/ProductionTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,8 @@ public void AddRecipe(IObjectWithQuality<RecipeOrTechnology> recipe, IComparer<G
_ = recipeRow.variants.Add(variants.AutoSelect(ingredientVariantComparer)!); // null-forgiving: variants is never empty, and AutoSelect never returns null from a non-empty collection (of non-null items).
}
}

recipeRow.AutoApplyModuleTemplate(Project.current.sharedModuleTemplates);
}

private static EntityCrafter? GetSelectedFuelCrafter(RecipeOrTechnology recipe, IObjectWithQuality<Goods>? selectedFuel) =>
Expand Down
15 changes: 15 additions & 0 deletions Yafc.Model/Model/ProductionTableContent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,21 @@ public void Dispose() {
}
}

/// <summary>
/// Search through <paramref name="moduleTemplates"/> to find a module template that can be used on this recipe. Apply the first one found.
/// </summary>
/// <param name="moduleTemplates">The templates to potentially use for this row.</param>
public void AutoApplyModuleTemplate(List<ProjectModuleTemplate> moduleTemplates) {
foreach (ProjectModuleTemplate template in moduleTemplates) {
if (template.autoApplyToNewRows && template.AcceptsEntity(entity?.target)) {
if (template.autoApplyIfIncompatible || template.template.IsCompatibleWith(this)) {
modules = template.template;
return;
}
}
}
}

// To avoid leaking these variables/methods (or just the setter, for recipesPerSecond) into public context,
// these explicit interface implementations connect to internal members, instead of using implicit implementation via public members
RecipeParameters IRecipeRow.parameters { get => parameters; set => parameters = value; }
Expand Down
12 changes: 12 additions & 0 deletions Yafc.Model/Model/ProjectModuleTemplate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,16 @@ public ProjectModuleTemplate(Project owner, string name) : base(owner) {
public FactorioObject? icon { get; set; }
public string name { get; set; }
public List<Entity> filterEntities { get; } = [];
/// <summary>
/// If <see langword="true"/>, this template is a candidate for being applied to newly added recipe rows.
/// </summary>
public bool autoApplyToNewRows { get; set; }
/// <summary>
/// If this and <see cref="autoApplyToNewRows"/> are both <see langword="true"/>, this template is a candidate for being applied to newly
/// added recipe rows, even if it contains modules that are not compatible with that row (e.g. prod modules in a non-prod recipe)
/// </summary>
public bool autoApplyIfIncompatible { get; set; }

// null-forgiving: non-nullable collections are happy to report they don't contain null values.
internal bool AcceptsEntity(EntityCrafter? target) => filterEntities.Count == 0 || filterEntities.Contains(target!);
}
11 changes: 10 additions & 1 deletion Yafc.UI/ImGui/ImGuiUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -226,12 +226,21 @@ public static bool WithTooltip(this ButtonEvent evt, ImGui gui, string tooltip,
return evt;
}

public static bool BuildCheckBox(this ImGui gui, string text, bool value, out bool newValue, SchemeColor color = SchemeColor.None, RectAllocator allocator = RectAllocator.LeftRow) {
public static bool BuildCheckBox(this ImGui gui, string text, bool value, out bool newValue, SchemeColor color = SchemeColor.None,
RectAllocator allocator = RectAllocator.LeftRow, string? tooltip = null) {

using (gui.EnterRow(allocator: allocator)) {
gui.BuildIcon(value ? Icon.CheckBoxCheck : Icon.CheckBoxEmpty, 1.5f, color);
gui.BuildText(text, TextBlockDisplayStyle.Default(color));
}

if (tooltip != null) {
bool wasOver = gui.IsMouseOver(gui.lastContentRect);
if (gui.ConsumeMouseOver(gui.lastContentRect, RenderingUtils.cursorArrow) && !wasOver) {
gui.ShowTooltip(gui.lastContentRect, tooltip);
}
}

if (gui.enableDrawing && gui.OnClick(gui.lastRect)) {
newValue = !value;
return true;
Expand Down
10 changes: 10 additions & 0 deletions Yafc/Data/locale/en/yafc.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -671,11 +671,18 @@ module-customization-energy-cost-per-output=Energy cost per recipe output: __1__
module-customization-energy-usage-per-building=Energy usage: __1__ (__2__ per building)
partial-cancel=Cancel (partial)
module-customization-remove=Remove module customization
; In English, these two are drawn on the same line. They will be placed on separate lines if the text is too long to fit on a single line.
module-customization-auto-apply=Apply automatically
module-customization-auto-incompatible=Even if incompatible
module-customization-auto-apply-hint=If checked, newly added recipes may have this template automatically applied to them, provided the recipe and crafter are compatible.
module-customization-auto-incompatible-hint=If checked, this template will be used even if one or more modules can't be used.\nFor example, a template containing productivity modules can be selected for a recipe that disallows them.
select-beacon=Select beacon
select-module=Select module

; ModuleFillerParametersScreen.cs
; The icon for the selected beacon (with quality and milestone overlays) appears after this string
affected-by-M-beacons=Affected by __1__
; The icon for the selected module (with quality and milestone overlays) appears after this string
each-containing-N-modules=each containing __1__
module-filler-remove-current-override-hint=Click here to remove the current override.
select-beacon-module=Select beacon module
Expand All @@ -700,6 +707,9 @@ module-filler-select-overridden-crafter=Add exception(s) for:
; ModuleTemplateConfiguration.cs
module-templates=Module templates
create-new-template-hint=Create new template
module-templates-auto=Auto
module-templates-auto-enabled-hint=This template may be automatically applied to new recipes.
module-templates-auto-disabled-hint=This template will not be automatically applied to new recipes.

; ProductionLinkSummaryScreen.cs
link-summary-production=Production: __1__
Expand Down
27 changes: 27 additions & 0 deletions Yafc/Workspace/ProductionTable/ModuleCustomizationScreen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,33 @@ public override void Build(ImGui gui) {
}
}

float textLength = gui.GetTextDimensions(out _, LSs.ModuleCustomizationAutoApply).X
+ gui.GetTextDimensions(out _, LSs.ModuleCustomizationAutoIncompatible).X;
// 3 for the two checkboxes, and 1.3 for various extra padding:
bool singleRow = textLength < contents.width - 4.3f;

ImGui.Context row = default;
if (singleRow) {
// The text is short enough to draw in one row
row = gui.EnterRow();
}
if (gui.BuildCheckBox(LSs.ModuleCustomizationAutoApply, template.autoApplyToNewRows, out bool newValue,
tooltip: LSs.ModuleCustomizationAutoApplyHint)) {
template.RecordUndo().autoApplyToNewRows = newValue;
}
if (!singleRow) {
// Draw in two rows, nested
row = gui.EnterRow(1);
gui.AllocateSpacing();
}
if (gui.BuildCheckBox(LSs.ModuleCustomizationAutoIncompatible, template.autoApplyIfIncompatible, out newValue,
template.autoApplyToNewRows ? SchemeColor.None : SchemeColor.GreyAlt, tooltip: LSs.ModuleCustomizationAutoIncompatibleHint)
&& template.autoApplyToNewRows) {

template.RecordUndo().autoApplyIfIncompatible = newValue;
}
row.Dispose();

gui.BuildText(LSs.ModuleCustomizationFilterBuildings);
using var grid = gui.EnterInlineGrid(2f, 1f);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ private void Drawer(ImGui gui, ProjectModuleTemplate element, int index) {
ModuleCustomizationScreen.Show(element);
}

SchemeColor textColor = element.autoApplyToNewRows ? SchemeColor.PrimaryText : SchemeColor.PrimaryTextFaint;
using (gui.EnterGroup(ImGuiUtils.DefaultButtonPadding, textColor)) {
gui.BuildText(LSs.ModuleTemplatesAuto, TextBlockDisplayStyle.Centered);
}
LocalizableString0 tooltip = element.autoApplyToNewRows ? LSs.ModuleTemplatesAutoEnabledHint : LSs.ModuleTemplatesAutoDisabledHint;
if (gui.BuildButton(gui.lastRect, SchemeColor.None, SchemeColor.Grey).WithTooltip(gui, tooltip)) {
element.RecordUndo().autoApplyToNewRows = !element.autoApplyToNewRows;
}

gui.allocator = RectAllocator.LeftRow;
if (element.icon != null) {
gui.BuildFactorioObjectIcon(element.icon);
Expand Down
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
Version:
Date:
Features:
- Module templates can be automatically applied to new recipe rows, on a per-template basis.
Fixes:
- Personal equipment names are localized again.
----------------------------------------------------------------------------------------------------------------------
Expand Down