mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-05-17 02:22:17 +00:00
X2D Support (#13388)
# Description Adresses #13294 - Adds the X2D printer definition, machine presets, process presets, filament presets, BBL profile index entries, CLI config entries, filament blacklist updates, and printer/load/calibration/cover assets. - Updates dual-nozzle handling to use configured toolhead labels and match Bambu X2D hotend placeholders. - Adds X2D-specific wipe tower cooling placeholder support and 3MF filament/nozzle change sequence metadata import/export plumbing. # Note I own a P2S and an X2D. That's all. I frankly have no idea if my changes cause regression on other printers, and have no capability to test. I know that for my X2D, which runs an AMS, .2mm nozzles, SuperTack, and in LAN mode, this has been working without issue. # Screenshots/Recordings/Graphs <img width="606" height="380" alt="Dual nozzle control" src="https://github.com/user-attachments/assets/0d1c1063-4621-4097-b97c-d739557bf18c" /> *Dual nozzle control* <img width="726" height="260" alt="image" src="https://github.com/user-attachments/assets/270355b7-ca67-4ca3-ad19-582b8f11411b" /> *Multi nozzle filament override* <img width="416" height="202" alt="X2D Machine config and dual nozzle support" src="https://github.com/user-attachments/assets/6a5c07b2-0d20-4819-8f42-d60731313249" /> *X2D Machine config and dual nozzle support* <img width="397" height="142" alt="Filament for Supports test prints" src="https://github.com/user-attachments/assets/3c7546bd-0e27-4d56-89b7-d9ca18c976f9" /> *Filament for Supports has been used in over 20 hours of test prints* <img width="210" height="263" alt="Left vs Right filament distinction" src="https://github.com/user-attachments/assets/03322268-b669-4f14-8d77-c4d96843d219" /> *Left vs Right filament distinction* <img width="557" height="327" alt="Custom filament mapping" src="https://github.com/user-attachments/assets/c1c4396f-7359-474e-80bd-78fec22f9c82" /> *Custom filament mapping* <img width="556" height="314" alt="Auto map" src="https://github.com/user-attachments/assets/d83e3217-edce-4340-886e-043962003a30" /> *Auto map* <img width="689" height="664" alt="LAN mode send print with X2D preview and no errors" src="https://github.com/user-attachments/assets/76009bbf-31d3-4a6c-979c-8643b487c824" /> *LAN mode send print with X2D preview and no errors, dual nozzle selection* ## Tests - 20 hours of dual-nozzle printing. - 100% CTest tests passed - Validated 208 changed JSON files. <!-- > A guide for users on how to download the artifacts from this PR. --> [How to Download Pull Requests Artifacts for Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts) Fix #13294
This commit is contained in:
@@ -61,6 +61,7 @@
|
||||
#endif // WIN32
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@@ -499,6 +500,22 @@ void Tab::create_preset_tab()
|
||||
}
|
||||
#endif
|
||||
|
||||
if (dynamic_cast<TabFilament *>(this)) {
|
||||
m_variant_combo = new MultiSwitchButton(panel);
|
||||
m_variant_combo->Bind(wxCUSTOMEVT_MULTISWITCH_SELECTION, [this](auto &evt) {
|
||||
evt.Skip();
|
||||
switch_excluder(evt.GetInt());
|
||||
reload_config();
|
||||
update_changed_ui();
|
||||
toggle_options();
|
||||
if (m_active_page)
|
||||
m_active_page->update_visibility(m_mode, true);
|
||||
m_page_view->GetParent()->Layout();
|
||||
});
|
||||
m_variant_combo->Hide();
|
||||
m_main_sizer->Add(m_variant_combo, 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, m_em_unit);
|
||||
}
|
||||
|
||||
this->SetSizer(m_main_sizer);
|
||||
//this->Layout();
|
||||
m_page_view = m_parent->get_paged_view();
|
||||
@@ -1295,6 +1312,8 @@ void Tab::msw_rescale()
|
||||
{
|
||||
m_mode_view->Rescale();
|
||||
}
|
||||
if (m_variant_combo)
|
||||
m_variant_combo->Rescale();
|
||||
|
||||
if (m_detach_preset_btn)
|
||||
m_detach_preset_btn->msw_rescale();
|
||||
@@ -1360,6 +1379,8 @@ void Tab::sys_color_changed()
|
||||
m_active_page->sys_color_changed();
|
||||
if (m_extruder_switch)
|
||||
m_extruder_switch->Rescale();
|
||||
if (m_variant_combo)
|
||||
m_variant_combo->Rescale();
|
||||
|
||||
//BBS: GUI refactor
|
||||
//Layout();
|
||||
@@ -3747,7 +3768,7 @@ void TabFilament::update_filament_overrides_page(const DynamicPrintConfig* print
|
||||
// "filament_seam_gap"
|
||||
};
|
||||
|
||||
const int selection = 0; //m_variant_combo->GetSelection(); // TODO: Orca hack
|
||||
const int selection = m_variant_combo ? m_variant_combo->GetSelection() : 0;
|
||||
auto opt = dynamic_cast<ConfigOptionVectorBase *>(m_config->option("filament_retraction_length"));
|
||||
const int extruder_idx = selection < 0 || selection >= static_cast<int>(opt->size()) ? 0 : selection;
|
||||
|
||||
@@ -4277,9 +4298,11 @@ void TabFilament::toggle_options()
|
||||
|
||||
toggle_line("activate_chamber_temp_control", printer_cfg.opt_bool("support_chamber_temp_control"));
|
||||
|
||||
std::string volumetric_speed_cos = m_config->opt_string("volumetric_speed_coefficients", 0u);
|
||||
const int selection = m_variant_combo ? m_variant_combo->GetSelection() : 0;
|
||||
const unsigned int variant_idx = (unsigned int) std::max(selection, 0);
|
||||
std::string volumetric_speed_cos = m_config->opt_string("volumetric_speed_coefficients", variant_idx);
|
||||
bool enable_fit = volumetric_speed_cos != "0 0 0 0 0 0";
|
||||
toggle_option("filament_adaptive_volumetric_speed", enable_fit, 256 + 0u);
|
||||
toggle_option("filament_adaptive_volumetric_speed", enable_fit, 256 + variant_idx);
|
||||
}
|
||||
|
||||
if (m_active_page->title() == L("Setting Overrides"))
|
||||
@@ -4297,7 +4320,8 @@ void TabFilament::toggle_options()
|
||||
toggle_option("filament_multitool_ramming_flow", multitool_ramming);
|
||||
|
||||
bool is_BBL_multi_extruder = is_BBL_printer && printer_cfg.option<ConfigOptionFloats>("nozzle_diameter")->size() > 1;
|
||||
const int extruder_idx = 0; // m_variant_combo->GetSelection(); // TODO: Orca hack
|
||||
const int selection = m_variant_combo ? m_variant_combo->GetSelection() : 0;
|
||||
const int extruder_idx = std::max(selection, 0);
|
||||
toggle_line("long_retractions_when_ec", is_BBL_multi_extruder, 256 + extruder_idx);
|
||||
toggle_line("retraction_distances_when_ec", is_BBL_multi_extruder && m_config->opt_bool("long_retractions_when_ec", extruder_idx), 256 + extruder_idx);
|
||||
}
|
||||
@@ -6306,6 +6330,9 @@ bool Tab::tree_sel_change_delayed(wxCommandEvent& event)
|
||||
if (m_extruder_switch) {
|
||||
m_main_sizer->Show(m_extruder_switch, !m_active_page->m_opt_id_map.empty());
|
||||
GetParent()->Layout();
|
||||
} else if (m_variant_combo) {
|
||||
m_main_sizer->Show(m_variant_combo, m_variant_combo->IsEnabled() && !m_active_page->m_opt_id_map.empty());
|
||||
GetParent()->Layout();
|
||||
}
|
||||
|
||||
auto throw_if_canceled = std::function<void()>([this](){
|
||||
@@ -6976,6 +7003,41 @@ void Tab::set_just_edit(bool just_edit)
|
||||
/// </summary>
|
||||
/// <param name="extruder_id"></param>
|
||||
|
||||
std::vector<wxString> Tab::generate_extruder_options()
|
||||
{
|
||||
std::vector<wxString> options;
|
||||
if (m_type != Preset::TYPE_FILAMENT)
|
||||
return options;
|
||||
|
||||
auto *variants = m_config->option<ConfigOptionStrings>("filament_extruder_variant");
|
||||
if (!variants)
|
||||
return options;
|
||||
|
||||
const std::vector<std::string> known_nozzle_types = {
|
||||
get_nozzle_volume_type_string(NozzleVolumeType::nvtHighFlow),
|
||||
get_nozzle_volume_type_string(NozzleVolumeType::nvtStandard),
|
||||
};
|
||||
|
||||
for (const std::string &variant : variants->values) {
|
||||
std::string drive;
|
||||
std::string nozzle;
|
||||
|
||||
for (const std::string &nozzle_type : known_nozzle_types) {
|
||||
if (variant.size() > nozzle_type.size() &&
|
||||
variant.substr(variant.size() - nozzle_type.size()) == nozzle_type &&
|
||||
variant[variant.size() - nozzle_type.size() - 1] == ' ') {
|
||||
drive = variant.substr(0, variant.size() - nozzle_type.size() - 1);
|
||||
nozzle = nozzle_type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
options.push_back(nozzle.empty() ? from_u8(variant) : wxString::Format(wxT("%s: %s"), from_u8(drive), from_u8(nozzle)));
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
void Tab::update_extruder_variants(int extruder_id)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << extruder_id;
|
||||
@@ -7000,11 +7062,26 @@ void Tab::update_extruder_variants(int extruder_id)
|
||||
GetParent()->Layout();
|
||||
return;
|
||||
}
|
||||
} else if (m_variant_combo) {
|
||||
if (extruder_id >= 0)
|
||||
return;
|
||||
|
||||
const int selection = m_variant_combo->GetSelection();
|
||||
auto options = generate_extruder_options();
|
||||
m_variant_combo->SetOptions(options);
|
||||
|
||||
if (!options.empty())
|
||||
m_variant_combo->SetSelection(selection < 0 || selection >= (int) options.size() ? 0 : selection);
|
||||
|
||||
m_variant_combo->Enable(options.size() > 1);
|
||||
}
|
||||
switch_excluder(extruder_id);
|
||||
if (m_extruder_switch) {
|
||||
m_main_sizer->Show(m_extruder_switch, m_active_page && !m_active_page->m_opt_id_map.empty());
|
||||
GetParent()->Layout();
|
||||
} else if (m_variant_combo) {
|
||||
m_main_sizer->Show(m_variant_combo, m_variant_combo->IsEnabled() && m_active_page && !m_active_page->m_opt_id_map.empty());
|
||||
GetParent()->Layout();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7018,7 +7095,7 @@ void Tab::switch_excluder(int extruder_id)
|
||||
{}, {"", "filament_extruder_variant"}, // Preset::TYPE_FILAMENT filament don't use id anymore
|
||||
{}, {"printer_extruder_id", "printer_extruder_variant"}, // Preset::TYPE_PRINTER
|
||||
};
|
||||
if (extruder_id >= nozzle_volumes->size() || extruder_id >= extruders->size())
|
||||
if (!m_variant_combo && (extruder_id >= nozzle_volumes->size() || extruder_id >= extruders->size()))
|
||||
extruder_id = 0;
|
||||
if (m_extruder_switch && m_type != Preset::TYPE_PRINTER) {
|
||||
int current_extruder = m_extruder_switch->GetValue() ? 1 : 0;
|
||||
@@ -7026,15 +7103,25 @@ void Tab::switch_excluder(int extruder_id)
|
||||
extruder_id = current_extruder;
|
||||
else if (extruder_id != current_extruder)
|
||||
return;
|
||||
} else if (m_variant_combo) {
|
||||
int current_variant = m_variant_combo->GetSelection();
|
||||
if (current_variant < 0)
|
||||
current_variant = 0;
|
||||
if (extruder_id == -1)
|
||||
extruder_id = current_variant;
|
||||
else if (extruder_id != current_variant)
|
||||
return;
|
||||
}
|
||||
auto get_index_for_extruder =
|
||||
[this, &extruders, &nozzle_volumes, variant_keys = variant_keys[m_type >= Preset::TYPE_COUNT ? Preset::TYPE_PRINT : m_type]](int extruder_id, int stride = 1) {
|
||||
return m_config->get_index_for_extruder(extruder_id + 1, variant_keys.first,
|
||||
ExtruderType(extruders->values[extruder_id]), NozzleVolumeType(nozzle_volumes->values[extruder_id]), variant_keys.second, stride);
|
||||
};
|
||||
auto index = get_index_for_extruder(extruder_id == -1 ? 0 : extruder_id);
|
||||
auto index = m_variant_combo ? extruder_id : get_index_for_extruder(extruder_id == -1 ? 0 : extruder_id);
|
||||
if (index < 0)
|
||||
return;
|
||||
if (m_variant_combo)
|
||||
m_variant_combo->SetClientData(reinterpret_cast<void *>(static_cast<std::uintptr_t>(index)));
|
||||
for (auto page : m_pages) {
|
||||
bool is_extruder = false;
|
||||
if (m_type == Preset::TYPE_PRINTER) {
|
||||
|
||||
Reference in New Issue
Block a user