Add wipe_tower_type printer setting (#12781)

# Description

Previously, wipe tower behavior was determined by the printer model.  
In this PR, we introduced an option that lets users choose which wipe
tower type to use.
BBL printers remain hardcoded to Type 1. Qidi profiles default to Type
1.

This may be useful for users with a filament-cutter-based system
(similar to Bambu printers) who want to use similar configurations—they
can select the "Type 1" wipe tower. That said, Wipe Tower Type 2 is
generally recommended for all printers, whether they use a typical MMU
setup, a filament cutter, or a tool changer.

# Screenshots/Recordings/Graphs

<img width="1307" height="854" alt="Screenshot 2026-03-15 at 22 27 29"
src="https://github.com/user-attachments/assets/04bc5c42-88c4-458a-a933-a22f8408b6a8"
/>

## Tests

<!--
> Please describe the tests that you have conducted to verify the
changes made in this PR.
-->
This commit is contained in:
SoftFever
2026-03-16 18:57:02 +08:00
committed by GitHub
18 changed files with 61 additions and 39 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "Qidi",
"version": "02.03.02.51",
"version": "02.03.02.52",
"force_update": "0",
"description": "Qidi configurations",
"machine_model_list": [

View File

@@ -64,6 +64,7 @@
"scan_first_layer": "0",
"silent_mode": "0",
"single_extruder_multi_material": "1",
"wipe_tower_type": "type1",
"support_air_filtration": ["1"],
"support_box_temp_control": "1",
"support_chamber_temp_control": "1",

View File

@@ -128,6 +128,7 @@
"scan_first_layer": "0",
"silent_mode": "0",
"single_extruder_multi_material": "1",
"wipe_tower_type": "type1",
"support_air_filtration": [
"1"
],

View File

@@ -118,6 +118,7 @@
],
"silent_mode": "0",
"single_extruder_multi_material": "1",
"wipe_tower_type": "type1",
"change_filament_gcode": "",
"machine_pause_gcode": "M25 ;pause print",
"wipe": [

View File

@@ -9,6 +9,7 @@
"change_filament_gcode": "",
"machine_pause_gcode": "M0",
"support_chamber_temp_control": "1",
"wipe_tower_type": "type1",
"filament_tower_interface_pre_extrusion_dist": ["10"],
"filament_tower_interface_pre_extrusion_length": ["0"],
"filament_tower_ironing_area": ["4"],

View File

@@ -1456,7 +1456,7 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
std::string WipeTowerIntegration::prime(GCode &gcodegen)
{
std::string gcode;
if (!gcodegen.is_BBL_Printer() && !gcodegen.is_QIDI_Printer()) {
if (gcodegen.wipe_tower_type() == WipeTowerType::Type2) {
for (const WipeTower::ToolChangeResult &tcr : m_priming) {
if (!tcr.extrusions.empty())
gcode += append_tcr2(gcodegen, tcr, tcr.new_tool);
@@ -1472,7 +1472,7 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
assert(m_layer_idx >= 0);
if (m_layer_idx >= (int) m_tool_changes.size())
return gcode;
if (!gcodegen.is_BBL_Printer() && !gcodegen.is_QIDI_Printer()) {
if (gcodegen.wipe_tower_type() == WipeTowerType::Type2) {
if (gcodegen.writer().need_toolchange(extruder_id) || finish_layer) {
if (m_layer_idx < (int) m_tool_changes.size()) {
if (!(size_t(m_tool_change_idx) < m_tool_changes[m_layer_idx].size()))
@@ -1561,7 +1561,7 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
std::string WipeTowerIntegration::finalize(GCode &gcodegen)
{
std::string gcode;
if (!gcodegen.is_BBL_Printer() && !gcodegen.is_QIDI_Printer()) {
if (gcodegen.wipe_tower_type() == WipeTowerType::Type2) {
if (std::abs(gcodegen.writer().get_position().z() - m_final_purge.print_z) > EPSILON)
gcode += gcodegen.change_layer(m_final_purge.print_z);
gcode += append_tcr2(gcodegen, m_final_purge, -1);
@@ -1983,11 +1983,11 @@ bool GCode::is_BBL_Printer()
return false;
}
bool GCode::is_QIDI_Printer()
WipeTowerType GCode::wipe_tower_type()
{
if (m_curr_print)
return m_curr_print->is_QIDI_printer();
return false;
return m_curr_print->wipe_tower_type();
return WipeTowerType::Type2;
}
void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* result, ThumbnailsGeneratorCallback thumbnail_cb)
@@ -2400,7 +2400,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
// modifies m_silent_time_estimator_enabled
DoExport::init_gcode_processor(print.config(), m_processor, m_silent_time_estimator_enabled);
const bool is_bbl_printers = print.is_BBL_printer();
const bool is_qidi_printers = print.is_QIDI_printer();
const WipeTowerType wipe_tower_type = print.wipe_tower_type();
m_calib_config.clear();
// resets analyzer's tracking data
m_last_height = 0.f;
@@ -2701,7 +2701,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
throw Slic3r::SlicingError(_(L("No object can be printed. Maybe too small")));
has_wipe_tower = print.has_wipe_tower() && tool_ordering.has_wipe_tower();
// Orca: support all extruder priming
initial_extruder_id = (!is_bbl_printers && has_wipe_tower && !print.config().single_extruder_multi_material_priming && !is_qidi_printers) ?
initial_extruder_id = (wipe_tower_type == WipeTowerType::Type2 && has_wipe_tower && !print.config().single_extruder_multi_material_priming) ?
// The priming towers will be skipped.
tool_ordering.all_extruders().back() :
// Don't skip the priming towers.
@@ -2814,7 +2814,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
this->placeholder_parser().set("current_object_idx", 0);
// For the start / end G-code to do the priming and final filament pull in case there is no wipe tower provided.
this->placeholder_parser().set("has_wipe_tower", has_wipe_tower);
this->placeholder_parser().set("has_single_extruder_multi_material_priming", !is_bbl_printers && has_wipe_tower && print.config().single_extruder_multi_material_priming);
this->placeholder_parser().set("has_single_extruder_multi_material_priming", wipe_tower_type == WipeTowerType::Type2 && has_wipe_tower && print.config().single_extruder_multi_material_priming);
this->placeholder_parser().set("total_toolchanges", std::max(0, print.wipe_tower_data().number_of_toolchanges)); // Check for negative toolchanges (single extruder mode) and set to 0 (no tool change).
this->placeholder_parser().set("num_extruders", int(print.config().nozzle_diameter.values.size()));
this->placeholder_parser().set("retract_length", new ConfigOptionFloats(print.config().retraction_length));
@@ -3134,7 +3134,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
}
// Orca: support extruder priming
if (is_bbl_printers || ! (has_wipe_tower && print.config().single_extruder_multi_material_priming))
if (wipe_tower_type != WipeTowerType::Type2 || ! (has_wipe_tower && print.config().single_extruder_multi_material_priming))
{
// Set initial extruder only after custom start G-code.
// Ugly hack: Do not set the initial extruder if the extruder is primed using the MMU priming towers at the edge of the print bed.
@@ -3290,7 +3290,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
//BBS
file.write(m_writer.travel_to_z(initial_layer_print_height + m_config.z_offset.value, "Move to the first layer height"));
if (!is_bbl_printers && print.config().single_extruder_multi_material_priming) {
if (wipe_tower_type == WipeTowerType::Type2 && print.config().single_extruder_multi_material_priming) {
file.write(m_wipe_tower->prime(*this));
// Verify, whether the print overaps the priming extrusions.
BoundingBoxf bbox_print(get_print_extrusions_extents(print));

View File

@@ -251,7 +251,7 @@ public:
std::string unretract() { return m_writer.unlift() + m_writer.unretract(); }
std::string set_extruder(unsigned int extruder_id, double print_z, bool by_object=false, int toolchange_temp_override = -1);
bool is_BBL_Printer();
bool is_QIDI_Printer();
WipeTowerType wipe_tower_type();
// SoftFever
std::string set_object_info(Print* print);

View File

@@ -381,7 +381,6 @@ void ToolOrdering::sort_and_build_data(const PrintObject& object , unsigned int
// (print->config().print_sequence == PrintSequence::ByObject is true).
ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extruder, bool prime_multi_material)
{
m_is_BBL_printer = object.print()->is_BBL_printer();
m_print_full_config = &object.print()->full_print_config();
m_print_object_ptr = &object;
m_print = const_cast<Print*>(object.print());
@@ -427,7 +426,6 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude
// (print->config().print_sequence == PrintSequence::ByObject is false).
ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool prime_multi_material)
{
m_is_BBL_printer = print.is_BBL_printer();
m_print_full_config = &print.full_print_config();
m_print = const_cast<Print *>(&print); // for update the context of print
m_print_config_ptr = &print.config();
@@ -1222,12 +1220,13 @@ void ToolOrdering::reorder_extruders_for_minimum_flush_volume(bool reorder_first
using FlushMatrix = std::vector<std::vector<float>>;
size_t nozzle_nums = print_config->nozzle_diameter.values.size();
const auto wipe_tower_type = m_print->wipe_tower_type();
std::vector<FlushMatrix> nozzle_flush_mtx;
for (size_t nozzle_id = 0; nozzle_id < nozzle_nums; ++nozzle_id) {
std::vector<float> flush_matrix(cast<float>(get_flush_volumes_matrix(print_config->flush_volumes_matrix.values, nozzle_id, nozzle_nums)));
std::vector<std::vector<float>> wipe_volumes;
if ((print_config->purge_in_prime_tower && print_config->single_extruder_multi_material) || m_is_BBL_printer) {
if ((print_config->purge_in_prime_tower && print_config->single_extruder_multi_material) || wipe_tower_type == WipeTowerType::Type1) {
for (unsigned int i = 0; i < number_of_extruders; ++i)
wipe_volumes.push_back(std::vector<float>(flush_matrix.begin() + i * number_of_extruders, flush_matrix.begin() + (i + 1) * number_of_extruders));
} else {

View File

@@ -279,7 +279,6 @@ private:
const PrintObject* m_print_object_ptr = nullptr;
Print* m_print;
bool m_sorted = false;
bool m_is_BBL_printer = false;
FilamentChangeStats m_stats_by_single_extruder;
FilamentChangeStats m_stats_by_multi_extruder_curr;

View File

@@ -1028,7 +1028,7 @@ static std::vector<std::string> s_Preset_printer_options {
"use_relative_e_distances", "extruder_type", "use_firmware_retraction", "printer_notes",
"grab_length", "support_object_skip_flush", "physical_extruder_map",
"cooling_tube_retraction",
"cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "purge_in_prime_tower", "enable_filament_ramming",
"cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "wipe_tower_type", "purge_in_prime_tower", "enable_filament_ramming",
"z_offset",
"disable_m73", "preferred_orientation", "emit_machine_limits_to_gcode", "pellet_modded_printer", "support_multi_bed_types", "default_bed_type", "bed_mesh_min","bed_mesh_max","bed_mesh_probe_distance", "adaptive_bed_mesh_margin", "enable_long_retraction_when_cut","long_retractions_when_cut","retraction_distances_when_cut",
"bed_temperature_formula", "nozzle_flush_dataset"

View File

@@ -145,7 +145,6 @@ public:
VendorType get_current_vendor_type();
// Vendor related handy functions
bool is_bbl_vendor() { return get_current_vendor_type() == VendorType::Marlin_BBL; }
bool is_qidi_vendor() { return get_current_vendor_type() == VendorType::Klipper_Qidi; }
// Whether using bbl network for print upload
bool use_bbl_network();

View File

@@ -315,6 +315,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|| opt_key == "prime_tower_enable_framework"
|| opt_key == "prime_tower_width"
|| opt_key == "prime_tower_brim_width"
|| opt_key == "wipe_tower_type"
|| opt_key == "prime_tower_skip_points"
|| opt_key == "prime_tower_flat_ironing"
|| opt_key == "enable_tower_interface_features"
@@ -3127,10 +3128,10 @@ void Print::_make_wipe_tower()
// BBS
const unsigned int number_of_extruders = (unsigned int)(m_config.filament_colour.values.size());
const auto bUseWipeTower2 = is_BBL_printer() || is_QIDI_printer() ? false : true;
const bool is_wipe_tower_type2 = this->wipe_tower_type() == WipeTowerType::Type2;
// Let the ToolOrdering class know there will be initial priming extrusions at the start of the print.
m_wipe_tower_data.tool_ordering = ToolOrdering(*this, (unsigned int) -1, bUseWipeTower2 ? true : false);
m_wipe_tower_data.tool_ordering.sort_and_build_data(*this, (unsigned int)-1, bUseWipeTower2 ? true : false);
m_wipe_tower_data.tool_ordering = ToolOrdering(*this, (unsigned int) -1, is_wipe_tower_type2);
m_wipe_tower_data.tool_ordering.sort_and_build_data(*this, (unsigned int)-1, is_wipe_tower_type2);
if (!m_wipe_tower_data.tool_ordering.has_wipe_tower())
// Don't generate any wipe tower.
@@ -3173,7 +3174,7 @@ void Print::_make_wipe_tower()
}
this->throw_if_canceled();
if (!bUseWipeTower2) {
if (!is_wipe_tower_type2) {
// in BBL machine, wipe tower is only use to prime extruder. So just use a global wipe volume.
WipeTower wipe_tower(m_config, m_plate_index, m_origin, m_wipe_tower_data.tool_ordering.first_extruder(),
m_wipe_tower_data.tool_ordering.empty() ? 0.f : m_wipe_tower_data.tool_ordering.back().print_z, m_wipe_tower_data.tool_ordering.all_extruders());
@@ -3311,7 +3312,7 @@ void Print::_make_wipe_tower()
wipe_volumes.push_back(std::vector<float>(flush_matrix.begin()+i*number_of_extruders, flush_matrix.begin()+(i+1)*number_of_extruders));
// Orca: itertate over wipe_volumes and change the non-zero values to the prime_volume
if ((!m_config.purge_in_prime_tower || !m_config.single_extruder_multi_material) && !is_BBL_printer() && !is_QIDI_printer()) {
if ((!m_config.purge_in_prime_tower || !m_config.single_extruder_multi_material) && is_wipe_tower_type2) {
for (unsigned int i = 0; i < number_of_extruders; ++i) {
for (unsigned int j = 0; j < number_of_extruders; ++j) {
if (wipe_volumes[i][j] > 0) {

View File

@@ -1066,8 +1066,7 @@ public:
//SoftFever
bool &is_BBL_printer() { return m_isBBLPrinter; }
const bool is_BBL_printer() const { return m_isBBLPrinter; }
bool &is_QIDI_printer() { return m_isQIDIPrinter; }
const bool is_QIDI_printer() const { return m_isQIDIPrinter; }
WipeTowerType wipe_tower_type() const { return is_BBL_printer() ? WipeTowerType::Type1 : m_config.wipe_tower_type.value; }
CalibMode& calib_mode() { return m_calib_params.mode; }
const CalibMode calib_mode() const { return m_calib_params.mode; }
void set_calib_params(const Calib_Params& params);
@@ -1135,7 +1134,6 @@ private:
//SoftFever
bool m_isBBLPrinter;
bool m_isQIDIPrinter;
// Ordered collections of extrusion paths to build skirt loops and brim.
ExtrusionEntityCollection m_skirt;

View File

@@ -187,6 +187,12 @@ static t_config_enum_values s_keys_map_NoiseType {
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(NoiseType)
static t_config_enum_values s_keys_map_WipeTowerType {
{ "type1", int(WipeTowerType::Type1) },
{ "type2", int(WipeTowerType::Type2) }
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(WipeTowerType)
static t_config_enum_values s_keys_map_FuzzySkinMode {
{ "displacement", int(FuzzySkinMode::Displacement) },
{ "extrusion", int(FuzzySkinMode::Extrusion) },
@@ -5484,6 +5490,17 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false));
def = this->add("wipe_tower_type", coEnum);
def->label = L("Wipe tower type");
def->tooltip = L("Choose the wipe tower implementation for multi-material prints. Type 1 is recommended for Bambu and Qidi printers with a filament cutter. Type 2 offers better compatibility with multi-tool and MMU printers and provide overall better compatibility.");
def->enum_keys_map = &ConfigOptionEnum<WipeTowerType>::get_enum_values();
def->enum_values.emplace_back("type1");
def->enum_values.emplace_back("type2");
def->enum_labels.emplace_back(L("Type 1"));
def->enum_labels.emplace_back(L("Type 2"));
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionEnum<WipeTowerType>(WipeTowerType::Type2));
def = this->add("purge_in_prime_tower", coBool);
def->label = L("Purge in prime tower");
def->tooltip = L("Purge remaining filament into prime tower.");

View File

@@ -58,6 +58,11 @@ enum class NoiseType {
Voronoi,
};
enum class WipeTowerType {
Type1,
Type2,
};
enum PrintHostType {
htPrusaLink, htPrusaConnect, htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier, htMKS, htESP3D, htCrealityPrint, htObico, htFlashforge, htSimplyPrint, htElegooLink
};
@@ -490,6 +495,7 @@ CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(PrinterTechnology)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(GCodeFlavor)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(FuzzySkinType)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(FuzzySkinMode)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(WipeTowerType)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(NoiseType)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(InfillPattern)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(IroningType)
@@ -1388,6 +1394,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloats, filament_multitool_ramming_flow))
((ConfigOptionFloats, filament_stamping_loading_speed))
((ConfigOptionFloats, filament_stamping_distance))
((ConfigOptionEnum<WipeTowerType>, wipe_tower_type))
((ConfigOptionBool, purge_in_prime_tower))
((ConfigOptionBool, enable_filament_ramming))
((ConfigOptionBool, support_multi_bed_types))

View File

@@ -681,7 +681,6 @@ StringObjectException BackgroundSlicingProcess::validate(StringObjectException *
assert(m_print == m_fff_print);
m_fff_print->is_BBL_printer() = wxGetApp().preset_bundle->is_bbl_vendor();
m_fff_print->is_QIDI_printer() = wxGetApp().preset_bundle->is_qidi_vendor();
return m_print->validate(warning, collison_polygons, height_polygons);
}

View File

@@ -807,6 +807,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
toggle_field("single_extruder_multi_material", !is_BBL_Printer);
auto bSEMM = preset_bundle->printers.get_edited_preset().config.opt_bool("single_extruder_multi_material");
const bool supports_wipe_tower_2 = !is_BBL_Printer && preset_bundle->printers.get_edited_preset().config.opt_enum<WipeTowerType>("wipe_tower_type") == WipeTowerType::Type2;
toggle_field("ooze_prevention", !bSEMM);
bool have_ooze_prevention = config->opt_bool("ooze_prevention");
@@ -831,17 +832,17 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
"wipe_tower_extra_spacing", "wipe_tower_max_purge_speed",
"wipe_tower_bridging", "wipe_tower_extra_flow",
"wipe_tower_no_sparse_layers"})
toggle_line(el, have_prime_tower && !is_BBL_Printer);
toggle_line(el, have_prime_tower && supports_wipe_tower_2);
WipeTowerWallType wipe_tower_wall_type = config->opt_enum<WipeTowerWallType>("wipe_tower_wall_type");
bool have_rib_wall = (wipe_tower_wall_type == WipeTowerWallType::wtwRib)&&have_prime_tower;
toggle_line("wipe_tower_cone_angle", have_prime_tower && !is_BBL_Printer && wipe_tower_wall_type == WipeTowerWallType::wtwCone);
toggle_line("wipe_tower_cone_angle", have_prime_tower && supports_wipe_tower_2 && wipe_tower_wall_type == WipeTowerWallType::wtwCone);
toggle_line("wipe_tower_extra_rib_length", have_rib_wall);
toggle_line("wipe_tower_rib_width", have_rib_wall);
toggle_line("wipe_tower_fillet_wall", have_rib_wall);
toggle_field("prime_tower_width", have_prime_tower && !(is_BBL_Printer && have_rib_wall));
toggle_field("prime_tower_width", have_prime_tower && (supports_wipe_tower_2 || have_rib_wall));
toggle_line("single_extruder_multi_material_priming", !bSEMM && have_prime_tower && !is_BBL_Printer);
toggle_line("single_extruder_multi_material_priming", !bSEMM && have_prime_tower && supports_wipe_tower_2);
toggle_line("prime_volume",have_prime_tower && (!purge_in_primetower || !bSEMM));

View File

@@ -4911,6 +4911,7 @@ if (is_marlin_flavor)
optgroup->append_single_option_line("bed_temperature_formula", "printer_basic_information_advanced#bed-temperature-type");
optgroup = page->new_optgroup(L("Wipe tower"), "param_tower");
optgroup->append_single_option_line("wipe_tower_type", "printer_multimaterial_wipe_tower");
optgroup->append_single_option_line("purge_in_prime_tower", "printer_multimaterial_wipe_tower#purge-in-prime-tower");
optgroup->append_single_option_line("enable_filament_ramming", "printer_multimaterial_wipe_tower#enable-filament-ramming");
@@ -5204,11 +5205,6 @@ void TabPrinter::toggle_options()
is_BBL_printer = wxGetApp().preset_bundle->is_bbl_vendor();
}
bool is_QIDI_printer = false;
if (m_preset_bundle) {
is_QIDI_printer = wxGetApp().preset_bundle->is_qidi_vendor();
}
bool have_multiple_extruders = true;
//m_extruders_count > 1;
//if (m_active_page->title() == "Custom G-code") {
@@ -5236,6 +5232,8 @@ void TabPrinter::toggle_options()
}
if (m_active_page->title() == L("Multimaterial")) {
const bool supports_wipe_tower_2 = !is_BBL_printer && m_config->opt_enum<WipeTowerType>("wipe_tower_type") == WipeTowerType::Type2;
toggle_line("wipe_tower_type", !is_BBL_printer);
// SoftFever: hide specific settings for BBL printer
for (auto el : {
"enable_filament_ramming",
@@ -5245,7 +5243,7 @@ void TabPrinter::toggle_options()
"extra_loading_move",
"high_current_on_filament_swap",
})
toggle_option(el, !is_BBL_printer && !is_QIDI_printer);
toggle_option(el, supports_wipe_tower_2);
auto bSEMM = m_config->opt_bool("single_extruder_multi_material");
if (!bSEMM && m_config->opt_bool("manual_filament_change")) {
@@ -5255,7 +5253,7 @@ void TabPrinter::toggle_options()
}
toggle_option("extruders_count", !bSEMM);
toggle_option("manual_filament_change", bSEMM);
toggle_option("purge_in_prime_tower", bSEMM && (!is_BBL_printer && !is_QIDI_printer));
toggle_option("purge_in_prime_tower", bSEMM && supports_wipe_tower_2);
}
wxString extruder_number;
long val = 1;