diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 501e90edc7..290c1bf084 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -1967,7 +1967,8 @@ void GCodeViewer::render_scene(int canvas_width, int canvas_height) PartPlateList& plate_list = wxGetApp().plater()->get_partplate_list(); PartPlate* curr_plate = plate_list.get_curr_plate(); if (curr_plate) { - std::string plate_mode = curr_plate->get_imex_mode(); + // Same resolution the plate itself uses, rather than a fourth copy of it. + const std::string plate_mode = curr_plate->get_effective_imex_mode(); if (plate_mode != kImexPrimaryMode) mode = plate_mode; } diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index f4161bc32d..cad36c3ed4 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -400,6 +400,26 @@ std::string PartPlate::get_imex_mode() const return kImexPrimaryMode; } +std::string PartPlate::get_effective_imex_mode() const +{ + // Per-plate mode takes priority over the process preset; set_imex_mode() erases the + // key on Primary, which is what lets the preset's value survive the config merge and + // reach the slicer. Resolve it the same way here. + std::string mode = get_imex_mode(); + if (mode != kImexPrimaryMode) + return mode; + // wxGetApp() is not available headless -- see build_imex_cache_key, which guards on the + // same thing. Nothing calls this from the CLI today; this keeps that from being fatal. + if (!m_plater) + return mode; + if (auto* bundle = wxGetApp().preset_bundle) { + if (auto* opt = bundle->prints.get_edited_preset().config.option("imex_parallel_mode")) + if (!opt->value.empty()) + return opt->value; + } + return kImexPrimaryMode; +} + void PartPlate::set_imex_mode(const std::string& mode) { if (mode.empty() || mode == kImexPrimaryMode) { @@ -682,14 +702,7 @@ std::string PartPlate::build_imex_cache_key() const auto* is_imex_opt = printer_cfg.option("is_imex"); if (!is_imex_opt || !is_imex_opt->value) return ""; - // Per-plate mode takes priority over process preset. - std::string active_mode = get_imex_mode(); - if (active_mode == kImexPrimaryMode) { - const DynamicPrintConfig& process_cfg = wxGetApp().preset_bundle->prints.get_edited_preset().config; - auto* mode_opt = process_cfg.option("imex_parallel_mode"); - if (mode_opt && !mode_opt->value.empty()) - active_mode = mode_opt->value; - } + std::string active_mode = get_effective_imex_mode(); // Mode NAME alone is not printer identity: two presets can define the same mode // name with different tool rosters/primary, and imex_firmware_managed_zones // suppresses ghost generation entirely. Both shape the baked zone/ghost set, so @@ -792,13 +805,8 @@ bool PartPlate::resolve_active_mode_tools(std::string& out_tools_str, int& out_p auto* is_imex_opt = printer_cfg.option("is_imex"); if (!is_imex_opt || !is_imex_opt->value) return false; - std::string active_mode = get_imex_mode(); - if (active_mode == kImexPrimaryMode || active_mode.empty()) { - const DynamicPrintConfig& proc_cfg = wxGetApp().preset_bundle->prints.get_edited_preset().config; - if (auto* mo = proc_cfg.option("imex_parallel_mode")) - active_mode = mo->value; - } - if (active_mode.empty() || active_mode == kImexPrimaryMode) return false; + const std::string active_mode = get_effective_imex_mode(); + if (active_mode == kImexPrimaryMode) return false; const ImexMode mode = find_imex_mode(printer_cfg, active_mode); if (!mode.found()) return false; @@ -1201,7 +1209,9 @@ bool PartPlate::has_imex_multimaterial_conflict() const auto* is_imex_opt = printer_cfg.option("is_imex"); if (!is_imex_opt || !is_imex_opt->value) return false; - const std::string mode = get_imex_mode(); + // Resolved, not the raw plate value: a plate left on Primary still slices in the + // process preset's mode, and this badge has to fire wherever validate() would block. + const std::string mode = get_effective_imex_mode(); if (mode == kImexPrimaryMode) return false; // Both keys bail rather than defaulting through imex_cfg_int(), deliberately, and for the same @@ -2044,8 +2054,23 @@ void PartPlate::render_icons(bool bottom, bool only_name, int hover_id) std::string hover_tip; if (hover_id == (int)PLATE_IMEX_MODE_ID) { render_icon_texture(m_imex_mode_icon.model, m_partplate_list->m_imex_mode_hovered_texture); + // The stored value, not the resolved one: this line carries the click + // affordances, and the menu checkmark and the left-click cycle both act + // on what the plate stores. Reporting the inherited mode here would leave + // one control saying three different things. Where they differ -- a plate + // on Primary under a process preset that names a mode, which is what + // actually slices -- the inherited mode is named after it, so the tooltip + // still tells the user what this plate will print as. std::string cur = get_imex_mode(); + const std::string effective = get_effective_imex_mode(); if (cur == kImexPrimaryMode) cur = _u8L("Primary"); + if (effective != get_imex_mode()) { + try { + cur += (boost::format(_u8L(" (process preset: %1%)")) % effective).str(); + } catch (const std::exception&) { + cur += (boost::format(" (process preset: %1%)") % effective).str(); + } + } // One format string, not two catalog fragments concatenated around a // runtime value: translators need to move the mode name within the // sentence, and the space-padded fragments were untranslatable alone. diff --git a/src/slic3r/GUI/PartPlate.hpp b/src/slic3r/GUI/PartPlate.hpp index 3af49fa835..c716521f94 100644 --- a/src/slic3r/GUI/PartPlate.hpp +++ b/src/slic3r/GUI/PartPlate.hpp @@ -330,6 +330,11 @@ public: void set_spiral_vase_mode(bool spiral_mode, bool as_global); std::string get_imex_mode() const; + // The mode that actually governs this plate: its own override if it has one, + // otherwise the process preset's imex_parallel_mode. Zone computation, slicing + // and validation all resolve it this way, so anything that warns about a mode, + // or reports one, has to resolve it the same way or it describes a different plate. + std::string get_effective_imex_mode() const; void set_imex_mode(const std::string& mode); void reset_imex_mode(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index e9746fb8c3..236860ef99 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -13352,7 +13352,9 @@ static std::vector collect_imex_warnings(PartPlate* plate) // was dropped. Bed-temp + filament-type checks below remain useful soft // warnings — they catch user configurations that *will* slice but produce // problematic gcode. - const std::string mode = plate->get_imex_mode(); + // Resolved: a plate on Primary still slices in the process preset's mode, and these + // bed-temperature and filament-type warnings are the only notice the user gets. + const std::string mode = plate->get_effective_imex_mode(); if (mode == kImexPrimaryMode) return warnings; PresetBundle* bundle = wxGetApp().preset_bundle;