From 1aa9bb8d93b3036d69a3570a5cfa308063ed56f8 Mon Sep 17 00:00:00 2001 From: Clifford Garwood Date: Thu, 27 Aug 2026 10:36:15 -0400 Subject: [PATCH] fix(imex): make the plate badge count filaments the way validate does The badge is meant to predict whether slicing will be refused, and it delegates to the same helper for that reason. It was feeding that helper a different filament list. get_extruders(true) resolves a mixed slot into its physical components -- right for AMS mapping, which has to know what is actually loaded -- while Print::validate counts the slot itself. So a plate holding one two-component blend reads as two filaments to the badge and one to validate. The badge sees two, decides the plate is fine, and stays silent; the slice is then refused. It also runs the other way: a plate the user sees as a single colour draws a multi-material warning, because the expansion made it look like two. Give get_extruders an expand_mixed flag, defaulted so every existing caller keeps the resolved list, and have the badge ask for the authored one. The badge was also only mirroring validate's multi-color rule, not its first one -- a mixed filament is unsupported in a parallel mode outright. Without it the badge stays quiet on exactly the plate validate refuses first. Co-Authored-By: Claude Opus 5 (1M context) --- src/slic3r/GUI/PartPlate.cpp | 22 +++++++++++++++++++--- src/slic3r/GUI/PartPlate.hpp | 5 ++++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index 42cdea99b1..3d968012f6 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -1549,11 +1549,27 @@ bool PartPlate::has_imex_multimaterial_conflict() const } // Convert PartPlate's 1-based extruder list to the 0-based form the helper expects. - const std::vector used_1b = get_extruders(true); + // + // get_extruders(true) expands a mixed slot into its physical components, which is right for + // AMS mapping but wrong here: Print::validate counts the slot itself, so an expanded list + // makes the badge disagree with the thing it is previewing. A plate holding one 2-component + // blend reads as 2 filaments to the badge and 1 to validate -- the badge stays silent and + // the slice is then refused, or it warns about "multi-material objects" on a plate the user + // sees as single-colour. Undo the expansion so both sides count the same way. + const std::vector used_1b = get_extruders(true, /*expand_mixed=*/false); std::vector used_0b; used_0b.reserve(used_1b.size()); for (int e : used_1b) if (e > 0) used_0b.push_back(e - 1); + // validate()'s first rule: a mixed filament is unsupported in a parallel mode outright, + // ahead of any multi-color reasoning. The badge has to agree or it under-reports. + if (auto* is_mixed_opt = wxGetApp().preset_bundle->project_config.option("filament_is_mixed")) { + const auto& is_mixed = is_mixed_opt->values; + if (std::any_of(used_0b.begin(), used_0b.end(), + [&](int slot) { return slot >= 0 && slot < (int) is_mixed.size() && is_mixed[slot]; })) + return true; + } + return !imex_multicolor_block_reason(mode, active_tools_str, tpg_opt->value, used_0b, *pem_opt).empty(); } @@ -2761,7 +2777,7 @@ int PartPlate::picking_id_component(int idx) const return this->m_plate_index * GRABBER_COUNT + idx; } -std::vector PartPlate::get_extruders(bool conside_custom_gcode) const +std::vector PartPlate::get_extruders(bool conside_custom_gcode, bool expand_mixed) const { std::vector plate_extruders; if (check_objects_empty_and_gcode3mf(plate_extruders)) { @@ -2920,7 +2936,7 @@ std::vector PartPlate::get_extruders(bool conside_custom_gcode) const auto& project_config = wxGetApp().preset_bundle->project_config; auto* is_mixed_opt = project_config.option("filament_is_mixed"); auto* comp_strs_opt = project_config.option("filament_mixed_components"); - if (is_mixed_opt && comp_strs_opt && has_any_mixed_filament(is_mixed_opt->values)) { + if (expand_mixed && is_mixed_opt && comp_strs_opt && has_any_mixed_filament(is_mixed_opt->values)) { std::vector ext_0based; for (int e : plate_extruders) if (e >= 1) ext_0based.push_back((unsigned int)(e - 1)); diff --git a/src/slic3r/GUI/PartPlate.hpp b/src/slic3r/GUI/PartPlate.hpp index 7c6c8cd475..a5de5bbbd2 100644 --- a/src/slic3r/GUI/PartPlate.hpp +++ b/src/slic3r/GUI/PartPlate.hpp @@ -433,7 +433,10 @@ public: arrangement::ArrangePolygon estimate_wipe_tower_polygon(const DynamicPrintConfig & config, int plate_index, Vec3d& wt_pos, Vec3d& wt_size, int extruder_count = 1, int plate_extruder_size = 0, bool use_global_objects = false) const; bool check_objects_empty_and_gcode3mf(std::vector &result) const; // get used filaments from config, 1 based idx - std::vector get_extruders(bool conside_custom_gcode = false) const; + // expand_mixed=false returns the plate's filament slots as authored, without resolving a + // mixed slot into its components. Callers that mirror Print::validate need that form -- + // validate counts the mixed slot itself, so an expanded list makes the two disagree. + std::vector get_extruders(bool conside_custom_gcode = false, bool expand_mixed = true) const; std::vector get_extruders_under_cli(bool conside_custom_gcode, DynamicPrintConfig& full_config) const; std::vector get_extruders_without_support(bool conside_custom_gcode = false) const; // get used filaments from gcode result, 1 based idx