From cb66867768f72d04570654b6999fc0f1c94a8d2b Mon Sep 17 00:00:00 2001 From: Clifford Garwood Date: Thu, 14 May 2026 13:25:37 -0400 Subject: [PATCH] feat(imex): topology-aware Tool 0 Position dropdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For single-gantry IMEX setups, front/rear is meaningless — only left/right matters. Collapse the imex_tool_layout dropdown to two items ("Left" / "Right", mapped to front-left/front-right internally) when imex_gantry_count == 1, and show all four corner items otherwise. Normalize stored rear-* selections to their front-* equivalents on the transition so the displayed selection always matches the persisted value. Also rename the field label "Tool 0 Corner" → "Tool 0 Position" so it reads correctly in both single- and dual-gantry contexts, with a tooltip that explains the IDEX/IQEX distinction. Co-Authored-By: Claude Opus 4.7 --- src/libslic3r/PrintConfig.cpp | 8 ++++--- src/slic3r/GUI/Tab.cpp | 43 +++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 3ee62be297..9107ee6c7c 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -5821,10 +5821,12 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionInt(2)); def = this->add("imex_tool_layout", coEnum); - def->label = L("Tool 0 Corner"); - def->tooltip = L("Physical corner of the bed where tool T0 (index 0) is located. " + def->label = L("Tool 0 Position"); + def->tooltip = L("Physical position on the bed where tool T0 (index 0) is located. " "Determines how tool indices map to bed zones. " - "front = lower Y (near the operator), rear = higher Y (back of machine)."); + "For single-gantry setups (IDEX) only left/right matters; " + "for dual-gantry setups (IQEX) all four corners are selectable " + "(front = lower Y / near the operator, rear = higher Y / back of machine)."); def->mode = comAdvanced; def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); def->enum_values.push_back("front-left"); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 2f77290117..779690270e 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -6141,6 +6141,49 @@ void TabPrinter::toggle_options() toggle_option("imex_viz_theme", is_imex); toggle_option("imex_firmware_managed_zones", is_imex); if (m_imex_modes_ctrl) m_imex_modes_ctrl->Show(is_imex); + + // IDEX/IQEX: the tool_layout dropdown carries 4 corner values + // (front-left / front-right / rear-left / rear-right) in storage, but front/rear + // is meaningless on single-gantry setups. Collapse the dropdown to just two + // items ("Left" / "Right") when imex_gantry_count == 1 — mapped to front-left + // and front-right internally — and normalize any stored rear-* selection to its + // front-* equivalent so the displayed selection always matches the stored value. + if (is_imex) { + if (Field* layout_field = get_field("imex_tool_layout"); layout_field) { + if (auto* choice = dynamic_cast(layout_field); choice) { + const int gantry_count = m_config->opt_int("imex_gantry_count"); + int current_val = 0; + if (auto* o = m_config->option>("imex_tool_layout")) + current_val = static_cast(o->value); + + // Normalize rear-* → front-* when collapsing to 1 gantry. + if (gantry_count == 1 && (current_val == static_cast(ImexToolLayout::RearLeft) + || current_val == static_cast(ImexToolLayout::RearRight))) { + ImexToolLayout normalized = (current_val == static_cast(ImexToolLayout::RearLeft)) + ? ImexToolLayout::FrontLeft + : ImexToolLayout::FrontRight; + DynamicPrintConfig new_conf = *m_config; + new_conf.set_key_value("imex_tool_layout", + new ConfigOptionEnum(normalized)); + load_config(new_conf); + current_val = static_cast(normalized); + } + + wxArrayString items; + if (gantry_count >= 2) { + items.Add(_L("Front-left")); + items.Add(_L("Front-right")); + items.Add(_L("Rear-left")); + items.Add(_L("Rear-right")); + } else { + items.Add(_L("Left")); + items.Add(_L("Right")); + } + choice->set_values(items); + choice->set_value(boost::any(current_val), false); + } + } + } } wxString extruder_number; long val = 1;