mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-10 17:21:10 +00:00
Revert "feat(imex): Split mode rendering + modes editor Type column"
This reverts commit 4370cca4c9.
This commit is contained in:
@@ -605,7 +605,6 @@ void PartPlate::calc_imex_zones()
|
|||||||
// Look up secondary tool indices (active in mode, but NOT the primary tool)
|
// Look up secondary tool indices (active in mode, but NOT the primary tool)
|
||||||
auto* names_opt = printer_cfg.option<ConfigOptionStrings>("imex_mode_names");
|
auto* names_opt = printer_cfg.option<ConfigOptionStrings>("imex_mode_names");
|
||||||
auto* tools_opt = printer_cfg.option<ConfigOptionStrings>("imex_mode_active_tools");
|
auto* tools_opt = printer_cfg.option<ConfigOptionStrings>("imex_mode_active_tools");
|
||||||
auto* types_opt = printer_cfg.option<ConfigOptionStrings>("imex_mode_types");
|
|
||||||
std::string active_tools_str;
|
std::string active_tools_str;
|
||||||
if (names_opt && tools_opt) {
|
if (names_opt && tools_opt) {
|
||||||
for (size_t i = 0; i < names_opt->values.size(); ++i) {
|
for (size_t i = 0; i < names_opt->values.size(); ++i) {
|
||||||
@@ -615,14 +614,6 @@ void PartPlate::calc_imex_zones()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Mode topology tag — Split modes aggregate per-gantry (one zone covering the
|
|
||||||
// full gantry rail) rather than per-tool. Falls through to "primary"/"copy"/
|
|
||||||
// "mirror" inference when imex_mode_types is empty (legacy presets).
|
|
||||||
const std::vector<std::string> empty_types;
|
|
||||||
const std::string mode_type = imex_mode_type_for(
|
|
||||||
active_mode,
|
|
||||||
names_opt ? names_opt->values : empty_types,
|
|
||||||
types_opt ? types_opt->values : empty_types);
|
|
||||||
|
|
||||||
// Parse "phys_idx:P/C/M" format → map<phys_idx, state> (1=Primary, 2=Copy, 3=Mirror).
|
// Parse "phys_idx:P/C/M" format → map<phys_idx, state> (1=Primary, 2=Copy, 3=Mirror).
|
||||||
// imex_primary_tool_for_mode handles the Primary slot (bare legacy token → Primary);
|
// imex_primary_tool_for_mode handles the Primary slot (bare legacy token → Primary);
|
||||||
@@ -718,26 +709,6 @@ void PartPlate::calc_imex_zones()
|
|||||||
if (sc != pri_col) has_col_sep = true;
|
if (sc != pri_col) has_col_sep = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Split-mode aggregation: each non-primary gantry renders as ONE zone covering
|
|
||||||
// its full Y band rather than per-tool quadrants. Achieved by collapsing the
|
|
||||||
// copy/mirror cell sets so all entries share primary's column (suppresses
|
|
||||||
// col-sep), then forcing has_col_sep = false so make_boxes takes its
|
|
||||||
// full-X-row branch. The role color (copy vs mirror) is preserved per gantry.
|
|
||||||
if (mode_type == kImexModeTypeSplit && has_row_sep) {
|
|
||||||
auto aggregate_per_gantry = [&](std::set<std::pair<int,int>>& cells) {
|
|
||||||
std::set<int> rows;
|
|
||||||
for (const auto& [c, r] : cells) rows.insert(r);
|
|
||||||
cells.clear();
|
|
||||||
for (int r : rows) cells.insert({pri_col, r});
|
|
||||||
};
|
|
||||||
aggregate_per_gantry(copy_cells);
|
|
||||||
aggregate_per_gantry(mirror_cells);
|
|
||||||
all_secondary.clear();
|
|
||||||
for (const auto& p : copy_cells) all_secondary.insert(p);
|
|
||||||
for (const auto& p : mirror_cells) all_secondary.insert(p);
|
|
||||||
has_col_sep = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Primary zone extent (the clear printable area):
|
// Primary zone extent (the clear printable area):
|
||||||
// row-sep only → full bed width × primary row's Y band
|
// row-sep only → full bed width × primary row's Y band
|
||||||
// col-sep only → primary col's X band × full bed height
|
// col-sep only → primary col's X band × full bed height
|
||||||
@@ -1085,34 +1056,6 @@ void PartPlate::calc_imex_ghosts()
|
|||||||
|
|
||||||
const auto heads = parse_imex_active_tools(active_tools_str);
|
const auto heads = parse_imex_active_tools(active_tools_str);
|
||||||
|
|
||||||
// Split-mode aggregation: collapse the per-tool ghost emission down to one ghost
|
|
||||||
// per non-primary gantry. The "canonical" head for a gantry is the tool whose
|
|
||||||
// physical column matches primary's (the spatial Y-mirror partner); falls back
|
|
||||||
// to the first head encountered on that gantry if no col-match exists.
|
|
||||||
const DynamicPrintConfig& gh_printer_cfg = wxGetApp().preset_bundle->printers.get_edited_preset().config;
|
|
||||||
auto* gh_names_opt = gh_printer_cfg.option<ConfigOptionStrings>("imex_mode_names");
|
|
||||||
auto* gh_types_opt = gh_printer_cfg.option<ConfigOptionStrings>("imex_mode_types");
|
|
||||||
auto* gh_tpg_opt = gh_printer_cfg.option<ConfigOptionInt>("imex_tools_per_gantry");
|
|
||||||
const std::vector<std::string> gh_empty_strings;
|
|
||||||
const std::string gh_mode_type = imex_mode_type_for(
|
|
||||||
get_imex_mode(),
|
|
||||||
gh_names_opt ? gh_names_opt->values : gh_empty_strings,
|
|
||||||
gh_types_opt ? gh_types_opt->values : gh_empty_strings);
|
|
||||||
const int gh_tpg = gh_tpg_opt ? std::max(1, gh_tpg_opt->value) : 1;
|
|
||||||
const int gh_primary_col = primary_phys % gh_tpg;
|
|
||||||
std::map<int, int> canonical_head_per_gantry; // gantry idx → physical head we emit
|
|
||||||
if (gh_mode_type == kImexModeTypeSplit) {
|
|
||||||
for (const auto& [phys, role] : heads) {
|
|
||||||
if (phys == primary_phys) continue;
|
|
||||||
if (phys >= IMEX_GHOST_MAX_HEADS) continue;
|
|
||||||
const int gantry = phys / gh_tpg;
|
|
||||||
const int col = phys % gh_tpg;
|
|
||||||
auto it = canonical_head_per_gantry.find(gantry);
|
|
||||||
if (it == canonical_head_per_gantry.end() || col == gh_primary_col)
|
|
||||||
canonical_head_per_gantry[gantry] = phys;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Zone centers are the source of truth for ghost placement: they come from the
|
// Zone centers are the source of truth for ghost placement: they come from the
|
||||||
// same grid math that paints the colored secondary zones, so a ghost always lands
|
// same grid math that paints the colored secondary zones, so a ghost always lands
|
||||||
// in its own tool's zone. extruder_offset is physical-nozzle data and is left at
|
// in its own tool's zone. extruder_offset is physical-nozzle data and is left at
|
||||||
@@ -1158,13 +1101,6 @@ void PartPlate::calc_imex_ghosts()
|
|||||||
for (const auto& [phys, role] : heads) {
|
for (const auto& [phys, role] : heads) {
|
||||||
if (phys == primary_phys) continue;
|
if (phys == primary_phys) continue;
|
||||||
if (phys >= IMEX_GHOST_MAX_HEADS) continue;
|
if (phys >= IMEX_GHOST_MAX_HEADS) continue;
|
||||||
// Split mode: skip non-canonical tools on a gantry — only the gantry's
|
|
||||||
// representative tool (col-paired with primary, fallback first-seen)
|
|
||||||
// emits a ghost so the user sees one aggregate per non-primary gantry.
|
|
||||||
if (gh_mode_type == kImexModeTypeSplit) {
|
|
||||||
auto it = canonical_head_per_gantry.find(phys / gh_tpg);
|
|
||||||
if (it == canonical_head_per_gantry.end() || it->second != phys) continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Vec2d gantry = center_for(phys) - primary_off;
|
const Vec2d gantry = center_for(phys) - primary_off;
|
||||||
// Mirror reflects about the zone-boundary plane through the primary zone
|
// Mirror reflects about the zone-boundary plane through the primary zone
|
||||||
|
|||||||
+17
-100
@@ -4457,22 +4457,17 @@ public:
|
|||||||
info_panel->SetSizer(info_sizer);
|
info_panel->SetSizer(info_sizer);
|
||||||
|
|
||||||
// Column header row — spacers sized to align with the mode-row fields below.
|
// Column header row — spacers sized to align with the mode-row fields below.
|
||||||
// Name field: FromDIP(130) + FromDIP(6) gap; type col: FromDIP(80) + FromDIP(6) gap;
|
// Name field: FromDIP(130) + FromDIP(6) gap; tool grid: n_cols*(FromDIP(36)+FromDIP(2))-FromDIP(2) + FromDIP(6) gap.
|
||||||
// tool grid: n_cols*(FromDIP(36)+FromDIP(2))-FromDIP(2) + FromDIP(6) gap.
|
|
||||||
auto* hdr_panel = new wxPanel(this, wxID_ANY);
|
auto* hdr_panel = new wxPanel(this, wxID_ANY);
|
||||||
hdr_panel->SetBackgroundColour(GetBackgroundColour());
|
hdr_panel->SetBackgroundColour(GetBackgroundColour());
|
||||||
auto* hdr_sizer = new wxBoxSizer(wxHORIZONTAL);
|
auto* hdr_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
auto* hdr_name = new wxStaticText(hdr_panel, wxID_ANY, _L("Name"));
|
auto* hdr_name = new wxStaticText(hdr_panel, wxID_ANY, _L("Name"));
|
||||||
auto* hdr_type = new wxStaticText(hdr_panel, wxID_ANY, _L("Type"));
|
|
||||||
auto* hdr_tools = new wxStaticText(hdr_panel, wxID_ANY, _L("Tools"));
|
auto* hdr_tools = new wxStaticText(hdr_panel, wxID_ANY, _L("Tools"));
|
||||||
auto* hdr_gcode = new wxStaticText(hdr_panel, wxID_ANY, _L("G-code"));
|
auto* hdr_gcode = new wxStaticText(hdr_panel, wxID_ANY, _L("G-code"));
|
||||||
const int grid_px = m_n_cols * FromDIP(38) - FromDIP(2); // approx grid panel width
|
const int grid_px = m_n_cols * FromDIP(38) - FromDIP(2); // approx grid panel width
|
||||||
const int name_col_px = FromDIP(136);
|
const int name_col_px = FromDIP(136);
|
||||||
const int type_col_px = FromDIP(86);
|
|
||||||
hdr_sizer->Add(hdr_name, 0, wxALIGN_CENTER_VERTICAL);
|
hdr_sizer->Add(hdr_name, 0, wxALIGN_CENTER_VERTICAL);
|
||||||
hdr_sizer->AddSpacer(std::max(0, name_col_px - hdr_name->GetBestSize().x));
|
hdr_sizer->AddSpacer(std::max(0, name_col_px - hdr_name->GetBestSize().x));
|
||||||
hdr_sizer->Add(hdr_type, 0, wxALIGN_CENTER_VERTICAL);
|
|
||||||
hdr_sizer->AddSpacer(std::max(0, type_col_px - hdr_type->GetBestSize().x));
|
|
||||||
hdr_sizer->Add(hdr_tools, 0, wxALIGN_CENTER_VERTICAL);
|
hdr_sizer->Add(hdr_tools, 0, wxALIGN_CENTER_VERTICAL);
|
||||||
hdr_sizer->AddSpacer(std::max(0, grid_px + FromDIP(6) - hdr_tools->GetBestSize().x));
|
hdr_sizer->AddSpacer(std::max(0, grid_px + FromDIP(6) - hdr_tools->GetBestSize().x));
|
||||||
hdr_sizer->Add(hdr_gcode, 1, wxALIGN_CENTER_VERTICAL);
|
hdr_sizer->Add(hdr_gcode, 1, wxALIGN_CENTER_VERTICAL);
|
||||||
@@ -4495,15 +4490,13 @@ public:
|
|||||||
n_rows = std::max(1, n_rows);
|
n_rows = std::max(1, n_rows);
|
||||||
if (layout < 0) layout = m_layout;
|
if (layout < 0) layout = m_layout;
|
||||||
if (n_cols == m_n_cols && n_rows == m_n_rows && layout == m_layout) return;
|
if (n_cols == m_n_cols && n_rows == m_n_rows && layout == m_layout) return;
|
||||||
auto [names, tools, gcodes, types] = get_mode_data();
|
auto [names, tools, gcodes] = get_mode_data();
|
||||||
clear_rows();
|
clear_rows();
|
||||||
m_n_cols = n_cols;
|
m_n_cols = n_cols;
|
||||||
m_n_rows = n_rows;
|
m_n_rows = n_rows;
|
||||||
m_layout = layout;
|
m_layout = layout;
|
||||||
for (size_t i = 0; i < names.size(); ++i) {
|
for (size_t i = 0; i < names.size(); ++i)
|
||||||
const std::string t = (i < types.size() && !types[i].empty()) ? types[i] : kImexModeTypeCopy;
|
add_row(names[i], tools[i], gcodes[i], /*is_primary=*/(names[i] == kImexPrimaryMode));
|
||||||
add_row(names[i], tools[i], gcodes[i], t, /*is_primary=*/(names[i] == kImexPrimaryMode));
|
|
||||||
}
|
|
||||||
Layout();
|
Layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4512,17 +4505,6 @@ public:
|
|||||||
auto* names = cfg.option<ConfigOptionStrings>("imex_mode_names");
|
auto* names = cfg.option<ConfigOptionStrings>("imex_mode_names");
|
||||||
auto* tools = cfg.option<ConfigOptionStrings>("imex_mode_active_tools");
|
auto* tools = cfg.option<ConfigOptionStrings>("imex_mode_active_tools");
|
||||||
auto* gcodes = cfg.option<ConfigOptionStrings>("imex_mode_gcodes");
|
auto* gcodes = cfg.option<ConfigOptionStrings>("imex_mode_gcodes");
|
||||||
auto* types = cfg.option<ConfigOptionStrings>("imex_mode_types");
|
|
||||||
|
|
||||||
// Resolve a row's type using imex_mode_type_for so legacy presets without
|
|
||||||
// imex_mode_types still infer copy/mirror/split from their mode name.
|
|
||||||
const std::vector<std::string> empty_strings;
|
|
||||||
auto resolve_type = [&](const std::string& mode_name) -> std::string {
|
|
||||||
return imex_mode_type_for(
|
|
||||||
mode_name,
|
|
||||||
names ? names->values : empty_strings,
|
|
||||||
types ? types->values : empty_strings);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Primary row is always first and non-deletable. Look for an existing
|
// Primary row is always first and non-deletable. Look for an existing
|
||||||
// "primary" entry in the config (present in configs saved after #8 was
|
// "primary" entry in the config (present in configs saved after #8 was
|
||||||
@@ -4539,48 +4521,39 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
add_row(kImexPrimaryMode, primary_tools, primary_gcode, kImexModeTypePrimary, /*is_primary=*/true);
|
add_row(kImexPrimaryMode, primary_tools, primary_gcode, /*is_primary=*/true);
|
||||||
|
|
||||||
size_t n = names ? names->values.size() : 0;
|
size_t n = names ? names->values.size() : 0;
|
||||||
for (size_t i = 0; i < n; ++i) {
|
for (size_t i = 0; i < n; ++i) {
|
||||||
if (i == primary_cfg_idx) continue; // already added above
|
if (i == primary_cfg_idx) continue; // already added above
|
||||||
add_row(names->values[i],
|
add_row(names->values[i],
|
||||||
(tools && i < tools->values.size()) ? tools->values[i] : "",
|
(tools && i < tools->values.size()) ? tools->values[i] : "",
|
||||||
(gcodes && i < gcodes->values.size()) ? gcodes->values[i] : "",
|
(gcodes && i < gcodes->values.size()) ? gcodes->values[i] : "");
|
||||||
resolve_type(names->values[i]));
|
|
||||||
}
|
}
|
||||||
refresh_reset_buttons();
|
refresh_reset_buttons();
|
||||||
Layout();
|
Layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<std::vector<std::string>, std::vector<std::string>, std::vector<std::string>, std::vector<std::string>>
|
std::tuple<std::vector<std::string>, std::vector<std::string>, std::vector<std::string>>
|
||||||
get_mode_data() const {
|
get_mode_data() const {
|
||||||
std::vector<std::string> names, tools, gcodes, types;
|
std::vector<std::string> names, tools, gcodes;
|
||||||
for (auto& r : m_rows) {
|
for (auto& r : m_rows) {
|
||||||
std::string nm = r.is_primary ? std::string(kImexPrimaryMode) : r.name->GetValue().ToStdString();
|
std::string nm = r.is_primary ? std::string(kImexPrimaryMode) : r.name->GetValue().ToStdString();
|
||||||
if (nm.empty()) continue;
|
if (nm.empty()) continue;
|
||||||
names.push_back(nm);
|
names.push_back(nm);
|
||||||
tools.push_back(active_tools_string(r));
|
tools.push_back(active_tools_string(r));
|
||||||
gcodes.push_back(r.gcode->GetValue().ToStdString());
|
gcodes.push_back(r.gcode->GetValue().ToStdString());
|
||||||
// Primary row's type is sentinel-fixed; non-primary rows read from the dropdown.
|
|
||||||
if (r.is_primary || !r.type_choice) {
|
|
||||||
types.push_back(kImexModeTypePrimary);
|
|
||||||
} else {
|
|
||||||
const int idx = r.type_choice->GetSelection();
|
|
||||||
const auto& choices = type_choices();
|
|
||||||
types.push_back((idx >= 0 && idx < (int)choices.size()) ? choices[idx].second : kImexModeTypeCopy);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return {names, tools, gcodes, types};
|
return {names, tools, gcodes};
|
||||||
}
|
}
|
||||||
|
|
||||||
// True when the widget's current rows already mirror the four IMEX-mode option
|
// True when the widget's current rows already mirror the three IMEX-mode option
|
||||||
// vectors in cfg. Used by TabPrinter::update_fff() to skip a destroy-and-rebuild
|
// vectors in cfg. Used by TabPrinter::update_fff() to skip a destroy-and-rebuild
|
||||||
// pass when the only thing that just changed was the widget itself writing back
|
// pass when the only thing that just changed was the widget itself writing back
|
||||||
// to config — without this guard, every keystroke in the gcode textbox triggers
|
// to config — without this guard, every keystroke in the gcode textbox triggers
|
||||||
// a load_from_config() that detaches the textbox the user is typing in.
|
// a load_from_config() that detaches the textbox the user is typing in.
|
||||||
bool matches_config(const DynamicPrintConfig& cfg) const {
|
bool matches_config(const DynamicPrintConfig& cfg) const {
|
||||||
auto [names, tools, gcodes, types] = get_mode_data();
|
auto [names, tools, gcodes] = get_mode_data();
|
||||||
auto cfg_strings = [&cfg](const char* key) {
|
auto cfg_strings = [&cfg](const char* key) {
|
||||||
std::vector<std::string> v;
|
std::vector<std::string> v;
|
||||||
if (auto* o = cfg.option<ConfigOptionStrings>(key)) v = o->values;
|
if (auto* o = cfg.option<ConfigOptionStrings>(key)) v = o->values;
|
||||||
@@ -4588,8 +4561,7 @@ public:
|
|||||||
};
|
};
|
||||||
return names == cfg_strings("imex_mode_names")
|
return names == cfg_strings("imex_mode_names")
|
||||||
&& tools == cfg_strings("imex_mode_active_tools")
|
&& tools == cfg_strings("imex_mode_active_tools")
|
||||||
&& gcodes == cfg_strings("imex_mode_gcodes")
|
&& gcodes == cfg_strings("imex_mode_gcodes");
|
||||||
&& types == cfg_strings("imex_mode_types");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse "idx:P,idx:C,idx:M" → map<tool_idx, state>
|
// Parse "idx:P,idx:C,idx:M" → map<tool_idx, state>
|
||||||
@@ -4649,7 +4621,6 @@ private:
|
|||||||
wxPanel* panel;
|
wxPanel* panel;
|
||||||
wxTextCtrl* name; // nullptr for primary row (name is fixed)
|
wxTextCtrl* name; // nullptr for primary row (name is fixed)
|
||||||
wxTextCtrl* gcode;
|
wxTextCtrl* gcode;
|
||||||
wxChoice* type_choice {nullptr}; // nullptr for primary row (type is fixed)
|
|
||||||
std::vector<wxButton*> btns;
|
std::vector<wxButton*> btns;
|
||||||
std::vector<int> btn_states;
|
std::vector<int> btn_states;
|
||||||
std::vector<int> btn_tool_idx;
|
std::vector<int> btn_tool_idx;
|
||||||
@@ -4659,37 +4630,13 @@ private:
|
|||||||
bool reset_dirty_cached {false};
|
bool reset_dirty_cached {false};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Type-column dropdown indices match this static array. Wire-format strings
|
|
||||||
// (kImexModeType*) are what get written to imex_mode_types serialization.
|
|
||||||
static const std::vector<std::pair<wxString, std::string>>& type_choices() {
|
|
||||||
static const std::vector<std::pair<wxString, std::string>> v = {
|
|
||||||
{ _L("Copy"), kImexModeTypeCopy },
|
|
||||||
{ _L("Mirror"), kImexModeTypeMirror },
|
|
||||||
{ _L("Split"), kImexModeTypeSplit },
|
|
||||||
};
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
static int type_choice_index(const std::string& type) {
|
|
||||||
const auto& choices = type_choices();
|
|
||||||
for (size_t i = 0; i < choices.size(); ++i)
|
|
||||||
if (choices[i].second == type) return (int)i;
|
|
||||||
return 0; // default to Copy
|
|
||||||
}
|
|
||||||
|
|
||||||
// Snapshot of row content as it would be saved (matches get_mode_data() per-row).
|
// Snapshot of row content as it would be saved (matches get_mode_data() per-row).
|
||||||
struct RowSnapshot { std::string name, tools, gcode, type; };
|
struct RowSnapshot { std::string name, tools, gcode; };
|
||||||
RowSnapshot snapshot_row(const Row& r) const {
|
RowSnapshot snapshot_row(const Row& r) const {
|
||||||
RowSnapshot s;
|
RowSnapshot s;
|
||||||
s.name = r.is_primary ? std::string(kImexPrimaryMode) : r.name->GetValue().ToStdString();
|
s.name = r.is_primary ? std::string(kImexPrimaryMode) : r.name->GetValue().ToStdString();
|
||||||
s.tools = active_tools_string(r);
|
s.tools = active_tools_string(r);
|
||||||
s.gcode = r.gcode->GetValue().ToStdString();
|
s.gcode = r.gcode->GetValue().ToStdString();
|
||||||
if (r.is_primary || !r.type_choice) {
|
|
||||||
s.type = kImexModeTypePrimary;
|
|
||||||
} else {
|
|
||||||
const int idx = r.type_choice->GetSelection();
|
|
||||||
const auto& choices = type_choices();
|
|
||||||
s.type = (idx >= 0 && idx < (int)choices.size()) ? choices[idx].second : kImexModeTypeCopy;
|
|
||||||
}
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4705,14 +4652,12 @@ private:
|
|||||||
auto* p_names = parent->option<ConfigOptionStrings>("imex_mode_names");
|
auto* p_names = parent->option<ConfigOptionStrings>("imex_mode_names");
|
||||||
auto* p_tools = parent->option<ConfigOptionStrings>("imex_mode_active_tools");
|
auto* p_tools = parent->option<ConfigOptionStrings>("imex_mode_active_tools");
|
||||||
auto* p_gcodes = parent->option<ConfigOptionStrings>("imex_mode_gcodes");
|
auto* p_gcodes = parent->option<ConfigOptionStrings>("imex_mode_gcodes");
|
||||||
auto* p_types = parent->option<ConfigOptionStrings>("imex_mode_types");
|
|
||||||
if (!p_names || row_idx < 0 || row_idx >= (int)p_names->values.size()) return false;
|
if (!p_names || row_idx < 0 || row_idx >= (int)p_names->values.size()) return false;
|
||||||
const Row& r = m_rows[row_idx];
|
const Row& r = m_rows[row_idx];
|
||||||
const RowSnapshot s = snapshot_row(r);
|
const RowSnapshot s = snapshot_row(r);
|
||||||
if (!r.is_primary && s.name != p_names->values[row_idx]) return true;
|
if (!r.is_primary && s.name != p_names->values[row_idx]) return true;
|
||||||
if (p_tools && row_idx < (int)p_tools->values.size() && s.tools != p_tools->values[row_idx]) return true;
|
if (p_tools && row_idx < (int)p_tools->values.size() && s.tools != p_tools->values[row_idx]) return true;
|
||||||
if (p_gcodes && row_idx < (int)p_gcodes->values.size() && s.gcode != p_gcodes->values[row_idx]) return true;
|
if (p_gcodes && row_idx < (int)p_gcodes->values.size() && s.gcode != p_gcodes->values[row_idx]) return true;
|
||||||
if (!r.is_primary && p_types && row_idx < (int)p_types->values.size() && s.type != p_types->values[row_idx]) return true;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4729,7 +4674,6 @@ private:
|
|||||||
void add_row(const std::string& name = "",
|
void add_row(const std::string& name = "",
|
||||||
const std::string& active_tools = "",
|
const std::string& active_tools = "",
|
||||||
const std::string& gcode = "",
|
const std::string& gcode = "",
|
||||||
const std::string& type = kImexModeTypeCopy,
|
|
||||||
bool is_primary = false)
|
bool is_primary = false)
|
||||||
{
|
{
|
||||||
Row r;
|
Row r;
|
||||||
@@ -4746,26 +4690,9 @@ private:
|
|||||||
f.SetWeight(wxFONTWEIGHT_BOLD);
|
f.SetWeight(wxFONTWEIGHT_BOLD);
|
||||||
lbl->SetFont(f);
|
lbl->SetFont(f);
|
||||||
sizer->Add(lbl, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(6));
|
sizer->Add(lbl, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(6));
|
||||||
// Primary row gets a static "Primary" type label in the type column
|
|
||||||
// (the type is sentinel-fixed; no choice to offer).
|
|
||||||
auto* type_lbl = new wxStaticText(r.panel, wxID_ANY, _L("Primary"),
|
|
||||||
wxDefaultPosition, FromDIP(wxSize(80, -1)));
|
|
||||||
sizer->Add(type_lbl, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(6));
|
|
||||||
} else {
|
} else {
|
||||||
r.name = new wxTextCtrl(r.panel, wxID_ANY, name, wxDefaultPosition, FromDIP(wxSize(130, -1)));
|
r.name = new wxTextCtrl(r.panel, wxID_ANY, name, wxDefaultPosition, FromDIP(wxSize(130, -1)));
|
||||||
r.name->Bind(wxEVT_TEXT, [this](wxCommandEvent&) { notify(); });
|
r.name->Bind(wxEVT_TEXT, [this](wxCommandEvent&) { notify(); });
|
||||||
sizer->Add(r.name, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(6));
|
|
||||||
|
|
||||||
// Type column: per-row dropdown to select Copy / Mirror / Split. Drives
|
|
||||||
// the topology interpretation (zone/ghost aggregation, multi-color
|
|
||||||
// validation) — see imex_mode_type_for and consumers.
|
|
||||||
wxArrayString choice_labels;
|
|
||||||
for (const auto& [label, _key] : type_choices()) choice_labels.Add(label);
|
|
||||||
r.type_choice = new wxChoice(r.panel, wxID_ANY, wxDefaultPosition,
|
|
||||||
FromDIP(wxSize(80, -1)), choice_labels);
|
|
||||||
r.type_choice->SetSelection(type_choice_index(type));
|
|
||||||
r.type_choice->Bind(wxEVT_CHOICE, [this](wxCommandEvent&) { notify(); });
|
|
||||||
sizer->Add(r.type_choice, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(6));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* grid_panel = new wxPanel(r.panel, wxID_ANY);
|
auto* grid_panel = new wxPanel(r.panel, wxID_ANY);
|
||||||
@@ -4861,9 +4788,9 @@ private:
|
|||||||
wxDefaultPosition, FromDIP(wxSize(220, 54)), wxTE_MULTILINE);
|
wxDefaultPosition, FromDIP(wxSize(220, 54)), wxTE_MULTILINE);
|
||||||
r.gcode->Bind(wxEVT_TEXT, [this](wxCommandEvent&) { notify(); });
|
r.gcode->Bind(wxEVT_TEXT, [this](wxCommandEvent&) { notify(); });
|
||||||
|
|
||||||
// r.name and r.type_choice were added to the sizer in the non-primary branch
|
if (!is_primary) {
|
||||||
// above (right after creation, alongside the type dropdown). Here we add the
|
sizer->Add(r.name, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(6));
|
||||||
// tool grid and gcode columns common to every row.
|
}
|
||||||
sizer->Add(grid_panel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(6));
|
sizer->Add(grid_panel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(6));
|
||||||
sizer->Add(r.gcode, 1, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(4));
|
sizer->Add(r.gcode, 1, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(4));
|
||||||
|
|
||||||
@@ -4980,8 +4907,6 @@ private:
|
|||||||
auto* p_names = parent->option<ConfigOptionStrings>("imex_mode_names");
|
auto* p_names = parent->option<ConfigOptionStrings>("imex_mode_names");
|
||||||
auto* p_tools = parent->option<ConfigOptionStrings>("imex_mode_active_tools");
|
auto* p_tools = parent->option<ConfigOptionStrings>("imex_mode_active_tools");
|
||||||
auto* p_gcodes = parent->option<ConfigOptionStrings>("imex_mode_gcodes");
|
auto* p_gcodes = parent->option<ConfigOptionStrings>("imex_mode_gcodes");
|
||||||
auto* p_types = parent->option<ConfigOptionStrings>("imex_mode_types");
|
|
||||||
const std::vector<std::string> empty_strings;
|
|
||||||
for (size_t i = 0; i < m_rows.size(); ++i) {
|
for (size_t i = 0; i < m_rows.size(); ++i) {
|
||||||
Row& r = m_rows[i];
|
Row& r = m_rows[i];
|
||||||
if (r.panel != panel) continue;
|
if (r.panel != panel) continue;
|
||||||
@@ -4990,13 +4915,6 @@ private:
|
|||||||
r.name->ChangeValue(from_u8(p_names->values[i]));
|
r.name->ChangeValue(from_u8(p_names->values[i]));
|
||||||
if (p_gcodes && i < p_gcodes->values.size())
|
if (p_gcodes && i < p_gcodes->values.size())
|
||||||
r.gcode->ChangeValue(from_u8(p_gcodes->values[i]));
|
r.gcode->ChangeValue(from_u8(p_gcodes->values[i]));
|
||||||
if (!r.is_primary && r.type_choice) {
|
|
||||||
const std::string parent_type = imex_mode_type_for(
|
|
||||||
p_names->values[i],
|
|
||||||
p_names->values,
|
|
||||||
p_types ? p_types->values : empty_strings);
|
|
||||||
r.type_choice->SetSelection(type_choice_index(parent_type));
|
|
||||||
}
|
|
||||||
if (p_tools && i < p_tools->values.size()) {
|
if (p_tools && i < p_tools->values.size()) {
|
||||||
// Reapply tool states from the parent's serialized form. all_tool_states
|
// Reapply tool states from the parent's serialized form. all_tool_states
|
||||||
// is the source of truth for round-tripping; rebuild it then re-paint
|
// is the source of truth for round-tripping; rebuild it then re-paint
|
||||||
@@ -5677,11 +5595,10 @@ if (is_marlin_flavor)
|
|||||||
});
|
});
|
||||||
m_imex_modes_ctrl->load_from_config(*m_config);
|
m_imex_modes_ctrl->load_from_config(*m_config);
|
||||||
m_imex_modes_ctrl->on_change = [this]() {
|
m_imex_modes_ctrl->on_change = [this]() {
|
||||||
auto [names, tools, gcodes, types] = m_imex_modes_ctrl->get_mode_data();
|
auto [names, tools, gcodes] = m_imex_modes_ctrl->get_mode_data();
|
||||||
m_config->set_key_value("imex_mode_names", new ConfigOptionStrings(names));
|
m_config->set_key_value("imex_mode_names", new ConfigOptionStrings(names));
|
||||||
m_config->set_key_value("imex_mode_active_tools", new ConfigOptionStrings(tools));
|
m_config->set_key_value("imex_mode_active_tools", new ConfigOptionStrings(tools));
|
||||||
m_config->set_key_value("imex_mode_gcodes", new ConfigOptionStrings(gcodes));
|
m_config->set_key_value("imex_mode_gcodes", new ConfigOptionStrings(gcodes));
|
||||||
m_config->set_key_value("imex_mode_types", new ConfigOptionStrings(types));
|
|
||||||
update_dirty();
|
update_dirty();
|
||||||
on_value_change("imex_mode_names", std::string(""));
|
on_value_change("imex_mode_names", std::string(""));
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user