mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-10 17:21:10 +00:00
Resolve the IMEX mode the same way everywhere it is read
A plate can carry its own parallel mode, or leave it on Primary and inherit the process preset's. set_imex_mode() erases the key on Primary precisely so the preset's value survives the config merge, and the slicer honors it: Print::validate() and the G-code path both read the merged object config, so such a plate slices, and emits, in the preset's mode. Three places that describe that plate did not resolve it the same way. They read the plate's own value and stopped, so on a plate left at Primary: the multi-material conflict badge stayed dark on a plate validate() will refuse, which is the one invariant the comment above it claims to keep; the bed-temperature and filament-type warnings never ran, so the job went out in copy or mirror with a mismatched bed and no notice; the plate tooltip reported Primary for a plate about to print in another mode. The geometric badge beside the first of those already resolved correctly, because it goes through the zone layout, so one badge fired while its neighbour stayed dark on the same plate. The fallback had been written out by hand four times. Three are now collapsed onto one accessor, get_effective_imex_mode(); the fourth is in libslic3r, which cannot call a GUI method and resolves the two modes itself from arguments. The remaining callers of the raw get_imex_mode() want the raw value and keep it: the accessor itself, the zone layout call that passes both modes separately, the mode menu and the left-click cycle, which act on what the plate stores, and the reset that looks for plates whose own mode was removed. The tooltip is the one place the two readings meet. It headlines the stored mode, because it sits on the button whose menu and click act on that value, and names the inherited mode after it when they differ -- so one control no longer says three different things while still telling the user what will actually print. Reachability, honestly: nothing in the UI writes the process preset's copy today, so this needs a hand-edited preset, a vendor process profile or a project that carries one. It is latent rather than live -- and it stops being latent the moment a process-level mode selector exists. Note the key lives in the process preset, so one value there would govern every Primary plate in every project using it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
8350bac123
commit
a3eccdc8b7
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<ConfigOptionString>("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<ConfigOptionBool>("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<ConfigOptionString>("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<ConfigOptionBool>("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<ConfigOptionString>("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<ConfigOptionBool>("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.
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -13352,7 +13352,9 @@ static std::vector<wxString> 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;
|
||||
|
||||
Reference in New Issue
Block a user