Add multi-variant support to the app

This commit is contained in:
SoftFever
2026-09-28 19:08:35 +08:00
parent 2ccabb5695
commit 71bb400e46
27 changed files with 846 additions and 195 deletions
+41 -12
View File
@@ -506,7 +506,7 @@ void Tab::create_preset_tab()
if (dynamic_cast<TabPrinter *>(this) || dynamic_cast<TabPrint *>(this)) {
m_extruder_switch = new MultiSwitchButton(panel);
m_extruder_switch->SetMaxSize({em_unit(this) * 40, -1});
m_extruder_switch->SetFitToOptions();
m_extruder_switch->Bind(wxCUSTOMEVT_MULTISWITCH_SELECTION, [this](auto &evt) {
evt.Skip();
int selection = evt.GetInt();
@@ -539,7 +539,8 @@ void Tab::create_preset_tab()
auto right_sizer = new wxBoxSizer(wxHORIZONTAL);
m_variant_sizer->AddStretchSpacer(1);
m_variant_sizer->Add(m_extruder_switch, 0, wxALIGN_CENTER, 0);
// Orca: proportion 1 lets a narrow row squeeze the switch, which then scrolls its buttons.
m_variant_sizer->Add(m_extruder_switch, 1, wxALIGN_CENTER, 0);
m_variant_sizer->Add(right_sizer, 1, wxALIGN_CENTER);
right_sizer->AddStretchSpacer(1);
right_sizer->Add(m_extruder_sync_box, 0, wxALIGN_CENTER | wxRIGHT, m_em_unit);
@@ -8172,7 +8173,7 @@ void Tab::update_extruder_variants(int extruder_id, bool reload)
// Orca: a non-Bambu dual-nozzle printer has two extruders but a single variant column, so
// the nozzle switch and sync button have nothing to act on. Only enable with real variants.
if (extruder_nums == 2 && m_preset_bundle->support_different_extruders()) {
if (extruder_nums >= 2 && m_preset_bundle->support_different_extruders()) {
auto options = generate_extruder_options();
m_extruder_switch->SetOptions(options);
@@ -8219,6 +8220,23 @@ void Tab::update_extruder_variants(int extruder_id, bool reload)
}
}
// The variant switch tags are the narrowest place a volume type is named, so they abbreviate it;
// the flow combo boxes and the Printer tab's parameter labels keep the full names.
static wxString short_nozzle_volume_name(const std::string &volume_name)
{
// Hybrid has no entry on purpose: it is never a variant string, and the switch lists its two
// sub-nozzle types as separate tags (see generate_extruder_options).
if (volume_name == "Standard")
return "SF";
if (volume_name == "High Flow")
return "HF";
if (volume_name == "TPU High Flow")
return "TPU HF";
if (volume_name == "E3D High Flow")
return "E3D HF";
return from_u8(volume_name);
}
std::vector<wxString> Tab::generate_extruder_options()
{
std::vector<wxString> options;
@@ -8259,7 +8277,7 @@ std::vector<wxString> Tab::generate_extruder_options()
nozzle = "";
}
}
options.push_back(wxString::Format(_L("%s: %s"), _L(drive), _L(nozzle)));
options.push_back(wxString::Format(_L("%s: %s"), _L(drive), short_nozzle_volume_name(nozzle)));
}
return options;
}
@@ -8273,18 +8291,22 @@ std::vector<wxString> Tab::generate_extruder_options()
}
std::string pt = m_preset_bundle->printers.get_edited_preset().get_printer_type(m_preset_bundle);
// Orca: the main/deputy toolhead names describe a dual-nozzle printer, where extruder 0 is the
// left (deputy) and extruder 1 the right (main) nozzle. From three extruders on the tools are
// interchangeable, so name them by index instead of repeating one side.
for (int i = 0; i < extruder_nums; ++i) {
int ext_id = (i == 0) ? DEPUTY_EXTRUDER_ID : MAIN_EXTRUDER_ID;
wxString extruder_name = _L(DevPrinterConfigUtil::get_toolhead_display_name(
pt, ext_id, ToolHeadComponent::Nozzle, ToolHeadNameCase::TitleCase, true));
wxString extruder_name = extruder_nums > 2 ? wxString::Format("T%d", i + 1) :
_L(DevPrinterConfigUtil::get_toolhead_display_name(
pt, (i == 0) ? DEPUTY_EXTRUDER_ID : MAIN_EXTRUDER_ID,
ToolHeadComponent::Nozzle, ToolHeadNameCase::TitleCase, true));
NozzleVolumeType volume_type = NozzleVolumeType(nozzle_volumes->values[i]);
if (volume_type == NozzleVolumeType::nvtHybrid) {
options.push_back(wxString::Format(_L("%s: %s"), extruder_name, _L("Standard")));
options.push_back(wxString::Format(_L("%s: %s"), extruder_name, _L("High Flow")));
options.push_back(wxString::Format(_L("%s: %s"), extruder_name, short_nozzle_volume_name(get_nozzle_volume_type_string(NozzleVolumeType::nvtStandard))));
options.push_back(wxString::Format(_L("%s: %s"), extruder_name, short_nozzle_volume_name(get_nozzle_volume_type_string(NozzleVolumeType::nvtHighFlow))));
} else {
wxString volume_name = get_nozzle_volume_type_name(volume_type);
options.push_back(wxString::Format(_L("%s: %s"), extruder_name, volume_name));
options.push_back(wxString::Format(_L("%s: %s"), extruder_name,
short_nozzle_volume_name(get_nozzle_volume_type_string(volume_type))));
}
}
return options;
@@ -8315,7 +8337,10 @@ bool Tab::get_extruder_sync_enable_state(int extruder_id)
Preset& printer_preset = m_preset_bundle->printers.get_edited_preset();
auto nozzle_volumes = m_preset_bundle->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type");
auto extruders = printer_preset.config.option<ConfigOptionEnumsGeneric>("extruder_type");
if (nozzle_volumes->values.size() < 2 || extruders->values.size() < 2) {
// Orca: every rule below describes the two toolheads of a dual-nozzle printer as left/right.
// A printer with any other extruder count has no single counterpart to copy to, so it gets no
// sync button (a toolchanger would need a target to be chosen).
if (nozzle_volumes->values.size() != 2 || extruders->values.size() != 2) {
return false;
}
@@ -8456,6 +8481,10 @@ void Tab::sync_excluder()
ExtruderType(extruders->values[extruder_id]), nozzle_type, variant_keys.second, stride);
};
int active_index = get_current_active_extruder();
// The button copies to the other toolhead, so it is only offered when that other one exists;
// without this the `1 - active_index` below would index an extruder that is not there.
if (!get_extruder_sync_enable_state(active_index))
return;
auto active_nozzle = get_actual_nozzle_volume_type(active_index);
int from_index = get_index_for_extruder(active_index, active_nozzle);
int dest_index = get_index_for_extruder(1 - active_index, active_nozzle);