diff --git a/src/libslic3r/PresetBundle.cpp b/src/libslic3r/PresetBundle.cpp index 02c61b8181..c4895a5af7 100644 --- a/src/libslic3r/PresetBundle.cpp +++ b/src/libslic3r/PresetBundle.cpp @@ -4054,6 +4054,9 @@ std::vector> PresetBundle::get_extruder_filament return filament_infos; } +// ORCA TODO: currently, this function assumes the printer name follows the pattern of " ", e.g. +// printer_type: "Bambu Lab X2D", nozzle_diameter_str: "0.4 nozzle" => printer_name: "Bambu Lab X2D 0.4 nozzle". If the printer name does +// not follow this pattern, the function may not work correctly. std::set PresetBundle::get_printer_names_by_printer_type_and_nozzle(const std::string &printer_type, std::string nozzle_diameter_str, bool system_only) { std::set printer_names; @@ -4084,6 +4087,40 @@ std::set PresetBundle::get_printer_names_by_printer_type_and_nozzle return printer_names; } +std::vector PresetBundle::get_filament_presets_for_machine(const std::string &printer_type, + const std::string &nozzle_diameter_str, + bool include_user_presets) +{ + // Printer model plus nozzle diameter is expected to resolve to a single system printer preset; + // get_printer_names_by_printer_type_and_nozzle asserts as much in debug builds. + const std::set printer_names = get_printer_names_by_printer_type_and_nozzle(printer_type, nozzle_diameter_str); + const Preset *printer = printer_names.empty() ? nullptr : printers.find_preset(*printer_names.begin()); + if (printer == nullptr) + return {}; + + // Preset::is_visible is deliberately not consulted: it tracks what the Configuration Wizard + // installed, while the caller identifies a physically connected machine the user may never + // have installed - gating on it would empty the list for exactly those machines. + const PresetWithVendorProfile active_printer = printers.get_preset_with_vendor_profile(*printer); + // Loop invariant - the two argument is_compatible_with_printer() would rebuild it per preset. + DynamicPrintConfig printer_config; + printer_config.set_key_value("printer_preset", new ConfigOptionString(printer->name)); + if (const ConfigOption *opt = printer->config.option("nozzle_diameter")) + printer_config.set_key_value("num_extruders", new ConfigOptionInt((int) static_cast(opt)->values.size())); + + std::vector compatible; + for (Preset &preset : filaments) { + /* The situation where the preset is not offered is as follows: + 1. Not a root preset + 2. Not a system preset and the printer firmware does not support user presets */ + if (filaments.get_preset_base(preset) != &preset || (!preset.is_system && !include_user_presets)) + continue; + if (is_compatible_with_printer(filaments.get_preset_with_vendor_profile(preset), active_printer, &printer_config)) + compatible.push_back(&preset); + } + return compatible; +} + bool PresetBundle::check_filament_temp_equation_by_printer_type_and_nozzle_for_mas_tray( const std::string &printer_type, std::string& nozzle_diameter_str, std::string &setting_id, std::string &tag_uid, std::string &nozzle_temp_min, std::string &nozzle_temp_max, std::string& preset_setting_id) { diff --git a/src/libslic3r/PresetBundle.hpp b/src/libslic3r/PresetBundle.hpp index 6e7e07b26e..b927c5ee6f 100644 --- a/src/libslic3r/PresetBundle.hpp +++ b/src/libslic3r/PresetBundle.hpp @@ -350,6 +350,13 @@ public: std::vector> get_extruder_filament_info() const; std::set get_printer_names_by_printer_type_and_nozzle(const std::string &printer_type, std::string nozzle_diameter_str, bool system_only = true); + // Orca: the root filament presets a connected machine can use, resolved with the rule the rest + // of the app applies (is_compatible_with_printer): an empty compatible_printers means every + // printer, minus the alias shadowing exclusions the Orca Filament Library records in + // Preset::m_excluded_from. + std::vector get_filament_presets_for_machine(const std::string &printer_type, + const std::string &nozzle_diameter_str, + bool include_user_presets); bool check_filament_temp_equation_by_printer_type_and_nozzle_for_mas_tray(const std::string &printer_type, std::string & nozzle_diameter_str, std::string & setting_id, diff --git a/src/slic3r/GUI/AMSDryControl.cpp b/src/slic3r/GUI/AMSDryControl.cpp index ddd3380975..dae84cda71 100644 --- a/src/slic3r/GUI/AMSDryControl.cpp +++ b/src/slic3r/GUI/AMSDryControl.cpp @@ -1594,39 +1594,21 @@ int AMSDryCtrWin::update_filament_list(DevAms* dev_ams, MachineObject* obj) } stream << std::fixed << std::setprecision(1) << obj->GetExtderSystem()->GetNozzleDiameter(extruder_id); std::string nozzle_diameter_str = stream.str(); - std::set printer_names = preset_bundle->get_printer_names_by_printer_type_and_nozzle( - DevPrinterConfigUtil::get_printer_display_name(obj->printer_type), nozzle_diameter_str); - for (auto filament_it = filaments.begin(); filament_it != filaments.end(); ++filament_it) { - Preset& preset = *filament_it; - // Filter by system preset: root preset and (system preset or user preset is supported) - if (filaments.get_preset_base(*filament_it) != &preset || (!filament_it->is_system && !obj->is_support_user_preset)) { + for (Preset *filament_it : preset_bundle->get_filament_presets_for_machine( + DevPrinterConfigUtil::get_printer_display_name(obj->printer_type), nozzle_diameter_str, obj->is_support_user_preset)) { + if (!filament_id_set.insert(filament_it->filament_id).second) + continue; + const std::string filament_alias = filaments.get_preset_alias(*filament_it, true); + if (filament_alias.empty()) + continue; + auto opt_info = preset_bundle->get_filament_by_filament_id(filament_it->filament_id); + if (!opt_info.has_value()) continue; - } - ConfigOption * printer_opt = filament_it->config.option("compatible_printers"); - ConfigOptionStrings *printer_strs = dynamic_cast(printer_opt); - if (!printer_strs) continue; - - for (auto printer_str : printer_strs->values) { - if (printer_names.find(printer_str) != printer_names.end()) { - if (filament_id_set.find(filament_it->filament_id) != filament_id_set.end()) { - continue; - } - - filament_id_set.insert(filament_it->filament_id); - auto filament_alias = filaments.get_preset_alias(*filament_it, true); - if (!filament_alias.empty()) { - auto opt_info = preset_bundle->get_filament_by_filament_id(filament_it->filament_id); - if (opt_info.has_value()) { - auto real_info = opt_info.value(); - real_info.filament_name = filament_alias; - m_tray_ids.push_back(std::move(real_info)); - m_trays_combo->Append(wxString::FromUTF8(filament_alias)); - } - } - } - } + opt_info->filament_name = filament_alias; + m_tray_ids.push_back(std::move(*opt_info)); + m_trays_combo->Append(wxString::FromUTF8(filament_alias)); } if (m_tray_ids.empty()) { diff --git a/src/slic3r/GUI/AMSMaterialsSetting.cpp b/src/slic3r/GUI/AMSMaterialsSetting.cpp index 2e436e8462..a2adf3ea5b 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.cpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.cpp @@ -932,7 +932,6 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi m_input_k_val->GetTextCtrl()->SetValue(k); m_input_n_val->GetTextCtrl()->SetValue(n); - int idx = 0; wxArrayString filament_items; wxString bambu_filament_name; wxString hint_filament_name; // the hint type to be selected @@ -940,6 +939,9 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi std::unordered_map query_filament_types; // std::set filament_id_set; + // The alias keyed map has to start empty: it is a member, so a stale alias left by an earlier + // popup (a different printer, a different nozzle) would resolve to that printer's filament_id. + map_filament_items.clear(); PresetBundle * preset_bundle = wxGetApp().preset_bundle; std::ostringstream stream; // Defensive: this dialog is opened only from StatusPanel (BBL-only) today, so the fallback fires @@ -952,83 +954,48 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi } stream << std::fixed << std::setprecision(1) << machine_diameter; std::string nozzle_diameter_str = stream.str(); - std::set printer_names = preset_bundle->get_printer_names_by_printer_type_and_nozzle(DevPrinterConfigUtil::get_printer_display_name(obj->printer_type), nozzle_diameter_str); if (preset_bundle) { BOOST_LOG_TRIVIAL(trace) << "system_preset_bundle filament number=" << preset_bundle->filaments.size(); - for (auto filament_it = preset_bundle->filaments.begin(); filament_it != preset_bundle->filaments.end(); filament_it++) { - //filter by system preset - Preset& preset = *filament_it; - /*The situation where the user preset is not displayed is as follows: - 1. Not a root preset - 2. Not system preset and the printer firmware does not support user preset */ - if (preset_bundle->filaments.get_preset_base(*filament_it) != &preset || (!filament_it->is_system && !obj->is_support_user_preset)) { + for (Preset *filament_it : preset_bundle->get_filament_presets_for_machine( + DevPrinterConfigUtil::get_printer_display_name(obj->printer_type), nozzle_diameter_str, obj->is_support_user_preset)) { + if (!filament_id_set.insert(filament_it->filament_id).second) + continue; + const std::string alias = preset_bundle->filaments.get_preset_alias(*filament_it, true); + if (alias.empty()) continue; - } - ConfigOption * printer_opt = filament_it->config.option("compatible_printers"); - ConfigOptionStrings *printer_strs = dynamic_cast(printer_opt); - for (auto printer_str : printer_strs->values) { - if (printer_names.find(printer_str) != printer_names.end()) { - if (filament_id_set.find(filament_it->filament_id) != filament_id_set.end()) { - continue; - } else { - filament_id_set.insert(filament_it->filament_id); - // name matched - if (filament_it->is_system) { - filament_items.push_back(filament_it->alias); - _collect_filament_info(filament_it->alias, preset, query_filament_vendors, query_filament_types); + filament_items.push_back(alias); + _collect_filament_info(alias, *filament_it, query_filament_vendors, query_filament_types); - FilamentInfos filament_infos; - filament_infos.filament_id = filament_it->filament_id; - filament_infos.setting_id = filament_it->setting_id; - map_filament_items[filament_it->alias] = filament_infos; - } else { - char target = '@'; - size_t pos = filament_it->name.find(target); - if (pos != std::string::npos) { - std::string user_preset_alias = filament_it->name.substr(0, pos - 1); - wxString wx_user_preset_alias = wxString(user_preset_alias.c_str(), wxConvUTF8); - user_preset_alias = wx_user_preset_alias.ToStdString(); + FilamentInfos filament_infos; + filament_infos.filament_id = filament_it->filament_id; + filament_infos.setting_id = filament_it->setting_id; + map_filament_items[alias] = filament_infos; - filament_items.push_back(user_preset_alias); - _collect_filament_info(user_preset_alias, preset, query_filament_vendors, query_filament_types); - - FilamentInfos filament_infos; - filament_infos.filament_id = filament_it->filament_id; - filament_infos.setting_id = filament_it->setting_id; - map_filament_items[user_preset_alias] = filament_infos; - } - } - - if (filament_it->filament_id == ams_filament_id) { - hint_filament_name = from_u8(filament_it->alias); - bambu_filament_name = from_u8(filament_it->alias); + if (filament_it->filament_id == ams_filament_id) { + hint_filament_name = from_u8(alias); + bambu_filament_name = from_u8(alias); - // update if nozzle_temperature_range is found - ConfigOption *opt_min = filament_it->config.option("nozzle_temperature_range_low"); - if (opt_min) { - ConfigOptionInts *opt_min_ints = dynamic_cast(opt_min); - if (opt_min_ints) { - wxString text_nozzle_temp_min = wxString::Format("%d", opt_min_ints->get_at(0)); - m_input_nozzle_min->GetTextCtrl()->SetValue(text_nozzle_temp_min); - } - } - ConfigOption *opt_max = filament_it->config.option("nozzle_temperature_range_high"); - if (opt_max) { - ConfigOptionInts *opt_max_ints = dynamic_cast(opt_max); - if (opt_max_ints) { - wxString text_nozzle_temp_max = wxString::Format("%d", opt_max_ints->get_at(0)); - m_input_nozzle_max->GetTextCtrl()->SetValue(text_nozzle_temp_max); - } - } - } - idx++; + // update if nozzle_temperature_range is found + ConfigOption *opt_min = filament_it->config.option("nozzle_temperature_range_low"); + if (opt_min) { + ConfigOptionInts *opt_min_ints = dynamic_cast(opt_min); + if (opt_min_ints) { + wxString text_nozzle_temp_min = wxString::Format("%d", opt_min_ints->get_at(0)); + m_input_nozzle_min->GetTextCtrl()->SetValue(text_nozzle_temp_min); + } + } + ConfigOption *opt_max = filament_it->config.option("nozzle_temperature_range_high"); + if (opt_max) { + ConfigOptionInts *opt_max_ints = dynamic_cast(opt_max); + if (opt_max_ints) { + wxString text_nozzle_temp_max = wxString::Format("%d", opt_max_ints->get_at(0)); + m_input_nozzle_max->GetTextCtrl()->SetValue(text_nozzle_temp_max); } } } - } } @@ -1251,56 +1218,47 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt) stream << std::fixed << std::setprecision(1) << machine_diameter; } std::string nozzle_diameter_str = stream.str(); - std::set printer_names = preset_bundle->get_printer_names_by_printer_type_and_nozzle(DevPrinterConfigUtil::get_printer_display_name(obj->printer_type), - nozzle_diameter_str); - for (auto it = preset_bundle->filaments.begin(); it != preset_bundle->filaments.end(); it++) { - if (!m_comboBox_filament->GetValue().IsEmpty()) { - auto filament_item = map_filament_items[m_comboBox_filament->GetValue().ToStdString()]; - std::string filament_id = filament_item.filament_id; - if (it->filament_id.compare(filament_id) == 0) { - ConfigOption * printer_opt = it->config.option("compatible_printers"); - ConfigOptionStrings *printer_strs = dynamic_cast(printer_opt); - bool has_compatible_printer = false; - for (auto printer_str : printer_strs->values) { - if (printer_names.find(printer_str) != printer_names.end()) { - has_compatible_printer = true; - break; - } + // Resolve the selection against the same list Popup() built the dropdown from, so the two + // halves of the dialog cannot disagree about which filaments this machine can use. + const std::string selected = m_comboBox_filament->GetValue().ToStdString(); + if (!selected.empty()) { + const std::string filament_id = map_filament_items[selected].filament_id; + for (Preset *it : preset_bundle->get_filament_presets_for_machine( + DevPrinterConfigUtil::get_printer_display_name(obj->printer_type), nozzle_diameter_str, obj->is_support_user_preset)) { + if (it->filament_id != filament_id) + continue; + // ) if nozzle_temperature_range is found + ConfigOption* opt_min = it->config.option("nozzle_temperature_range_low"); + if (opt_min) { + ConfigOptionInts* opt_min_ints = dynamic_cast(opt_min); + if (opt_min_ints) { + wxString text_nozzle_temp_min = wxString::Format("%d", opt_min_ints->get_at(0)); + m_input_nozzle_min->GetTextCtrl()->SetValue(text_nozzle_temp_min); } - if (!it->is_system && !has_compatible_printer) continue; - // ) if nozzle_temperature_range is found - ConfigOption* opt_min = it->config.option("nozzle_temperature_range_low"); - if (opt_min) { - ConfigOptionInts* opt_min_ints = dynamic_cast(opt_min); - if (opt_min_ints) { - wxString text_nozzle_temp_min = wxString::Format("%d", opt_min_ints->get_at(0)); - m_input_nozzle_min->GetTextCtrl()->SetValue(text_nozzle_temp_min); - } - } - ConfigOption* opt_max = it->config.option("nozzle_temperature_range_high"); - if (opt_max) { - ConfigOptionInts* opt_max_ints = dynamic_cast(opt_max); - if (opt_max_ints) { - wxString text_nozzle_temp_max = wxString::Format("%d", opt_max_ints->get_at(0)); - m_input_nozzle_max->GetTextCtrl()->SetValue(text_nozzle_temp_max); - } - } - ConfigOption* opt_type = it->config.option("filament_type"); - bool found_filament_type = false; - if (opt_type) { - ConfigOptionStrings* opt_type_strs = dynamic_cast(opt_type); - if (opt_type_strs) { - found_filament_type = true; - //m_filament_type = opt_type_strs->get_at(0); - std::string display_filament_type; - m_filament_type = it->config.get_filament_type(display_filament_type); - } - } - if (!found_filament_type) - m_filament_type = ""; - - break; } + ConfigOption* opt_max = it->config.option("nozzle_temperature_range_high"); + if (opt_max) { + ConfigOptionInts* opt_max_ints = dynamic_cast(opt_max); + if (opt_max_ints) { + wxString text_nozzle_temp_max = wxString::Format("%d", opt_max_ints->get_at(0)); + m_input_nozzle_max->GetTextCtrl()->SetValue(text_nozzle_temp_max); + } + } + ConfigOption* opt_type = it->config.option("filament_type"); + bool found_filament_type = false; + if (opt_type) { + ConfigOptionStrings* opt_type_strs = dynamic_cast(opt_type); + if (opt_type_strs) { + found_filament_type = true; + //m_filament_type = opt_type_strs->get_at(0); + std::string display_filament_type; + m_filament_type = it->config.get_filament_type(display_filament_type); + } + } + if (!found_filament_type) + m_filament_type = ""; + + break; } } } diff --git a/src/slic3r/GUI/CaliHistoryDialog.cpp b/src/slic3r/GUI/CaliHistoryDialog.cpp index 297a70018d..3668d76929 100644 --- a/src/slic3r/GUI/CaliHistoryDialog.cpp +++ b/src/slic3r/GUI/CaliHistoryDialog.cpp @@ -708,7 +708,6 @@ wxArrayString NewCalibrationHistoryDialog::get_all_filaments(const MachineObject wxArrayString filament_items; std::set filament_id_set; - std::set printer_names; std::ostringstream stream; // If the machine didn't report a nozzle diameter (0.0 = unknown), fall back to the currently // selected printer preset so the filament list isn't empty. @@ -720,67 +719,21 @@ wxArrayString NewCalibrationHistoryDialog::get_all_filaments(const MachineObject stream << std::fixed << std::setprecision(1) << machine_diameter; std::string nozzle_diameter_str = stream.str(); - for (auto printer_it = preset_bundle->printers.begin(); printer_it != preset_bundle->printers.end(); printer_it++) { - // filter by system preset - if (!printer_it->is_system) - continue; - // get printer_model - ConfigOption * printer_model_opt = printer_it->config.option("printer_model"); - ConfigOptionString *printer_model_str = dynamic_cast(printer_model_opt); - if (!printer_model_str) - continue; - - // use printer_model as printer type - if (printer_model_str->value != DevPrinterConfigUtil::get_printer_display_name(obj->printer_type)) - continue; - - if (printer_it->name.find(nozzle_diameter_str) != std::string::npos) - printer_names.insert(printer_it->name); - } - if (preset_bundle) { BOOST_LOG_TRIVIAL(trace) << "system_preset_bundle filament number=" << preset_bundle->filaments.size(); - for (auto filament_it = preset_bundle->filaments.begin(); filament_it != preset_bundle->filaments.end(); filament_it++) { - // filter by system preset - Preset &preset = *filament_it; - /*The situation where the user preset is not displayed is as follows: - 1. Not a root preset - 2. Not system preset and the printer firmware does not support user preset */ - if (preset_bundle->filaments.get_preset_base(*filament_it) != &preset || (!filament_it->is_system && ! obj->is_support_user_preset)) { continue; } + for (Preset *filament_it : preset_bundle->get_filament_presets_for_machine( + DevPrinterConfigUtil::get_printer_display_name(obj->printer_type), nozzle_diameter_str, obj->is_support_user_preset)) { + if (!filament_id_set.insert(filament_it->filament_id).second) + continue; + const std::string alias = preset_bundle->filaments.get_preset_alias(*filament_it, true); + if (alias.empty()) + continue; - ConfigOption * printer_opt = filament_it->config.option("compatible_printers"); - ConfigOptionStrings *printer_strs = dynamic_cast(printer_opt); - for (auto printer_str : printer_strs->values) { - if (printer_names.find(printer_str) != printer_names.end()) { - if (filament_id_set.find(filament_it->filament_id) != filament_id_set.end()) { - continue; - } else { - filament_id_set.insert(filament_it->filament_id); - // name matched - if (filament_it->is_system) { - filament_items.push_back(filament_it->alias); - FilamentInfos filament_infos; - filament_infos.filament_id = filament_it->filament_id; - filament_infos.setting_id = filament_it->setting_id; - map_filament_items[filament_it->alias] = filament_infos; - } else { - char target = '@'; - size_t pos = filament_it->name.find(target); - if (pos != std::string::npos) { - std::string user_preset_alias = filament_it->name.substr(0, pos - 1); - wxString wx_user_preset_alias = wxString(user_preset_alias.c_str(), wxConvUTF8); - user_preset_alias = wx_user_preset_alias.ToStdString(); - - filament_items.push_back(user_preset_alias); - FilamentInfos filament_infos; - filament_infos.filament_id = filament_it->filament_id; - filament_infos.setting_id = filament_it->setting_id; - map_filament_items[user_preset_alias] = filament_infos; - } - } - } - } - } + filament_items.push_back(alias); + FilamentInfos filament_infos; + filament_infos.filament_id = filament_it->filament_id; + filament_infos.setting_id = filament_it->setting_id; + map_filament_items[alias] = filament_infos; } } return filament_items; diff --git a/src/slic3r/GUI/ExtrusionCalibration.cpp b/src/slic3r/GUI/ExtrusionCalibration.cpp index cd7f5990a7..933e2ac211 100644 --- a/src/slic3r/GUI/ExtrusionCalibration.cpp +++ b/src/slic3r/GUI/ExtrusionCalibration.cpp @@ -2,6 +2,7 @@ #include "GUI_App.hpp" #include "MsgDialog.hpp" #include "libslic3r/Preset.hpp" +#include #include "I18N.hpp" #include #include @@ -599,8 +600,10 @@ void ExtrusionCalibration::update_combobox_filaments() PresetBundle* preset_bundle = wxGetApp().preset_bundle; if (preset_bundle && obj) { BOOST_LOG_TRIVIAL(trace) << "system_preset_bundle filament number=" << preset_bundle->filaments.size(); - std::string printer_type = obj->printer_type; - std::set printer_preset_list; + double nozzle_value = 0.4; + m_comboBox_nozzle_dia->GetValue().ToDouble(&nozzle_value); + + std::vector printer_profiles; for (auto printer_it = preset_bundle->printers.begin(); printer_it != preset_bundle->printers.end(); printer_it++) { // only use system printer preset if (!printer_it->is_system) continue; @@ -610,49 +613,42 @@ void ExtrusionCalibration::update_combobox_filaments() ConfigOptionFloats* printer_nozzle_vals = nullptr; if (printer_nozzle_opt) printer_nozzle_vals = dynamic_cast(printer_nozzle_opt); - double nozzle_value = 0.4; - wxString nozzle_value_str = m_comboBox_nozzle_dia->GetValue(); - try { - nozzle_value_str.ToDouble(&nozzle_value); - } catch(...) { - ; - } if (!model_id.empty() && model_id.compare(obj->printer_type) == 0 && printer_nozzle_vals && abs(printer_nozzle_vals->get_at(0) - nozzle_value) < 1e-3) { - printer_preset_list.insert(printer_it->name); + printer_profiles.push_back(preset_bundle->printers.get_preset_with_vendor_profile(*printer_it)); BOOST_LOG_TRIVIAL(trace) << "extrusion_cali: printer_model = " << model_id; } else { BOOST_LOG_TRIVIAL(error) << "extrusion_cali: printer_model = " << model_id; } } + // Unlike the AMS dialogs this one offers every matching preset by full name rather than one + // root preset per alias, so it filters the collection itself instead of calling + // PresetBundle::get_filament_presets_for_machine(). for (auto filament_it = preset_bundle->filaments.begin(); filament_it != preset_bundle->filaments.end(); filament_it++) { - ConfigOption* printer_opt = filament_it->config.option("compatible_printers"); - ConfigOptionStrings* printer_strs = dynamic_cast(printer_opt); - for (auto printer_str : printer_strs->values) { - if (printer_preset_list.find(printer_str) != printer_preset_list.end()) { - user_filaments.push_back(&(*filament_it)); + const PresetWithVendorProfile filament = preset_bundle->filaments.get_preset_with_vendor_profile(*filament_it); + if (std::none_of(printer_profiles.begin(), printer_profiles.end(), + [&filament](const PresetWithVendorProfile &printer) { return is_compatible_with_printer(filament, printer); })) + continue; - // set default filament id - filament_index++; - if (filament_it->is_system - && !ams_filament_id.empty() - && filament_it->filament_id == ams_filament_id - ) { - curr_selection = filament_index; - } + user_filaments.push_back(&(*filament_it)); - if (filament_it->name == obj->extrusion_cali_filament_name && !obj->extrusion_cali_filament_name.empty()) - { - curr_selection = filament_index; - } - - wxString filament_name = wxString::FromUTF8(filament_it->name); - filament_items.Add(filament_name); - break; - } + // set default filament id + filament_index++; + if (filament_it->is_system + && !ams_filament_id.empty() + && filament_it->filament_id == ams_filament_id + ) { + curr_selection = filament_index; } + + if (filament_it->name == obj->extrusion_cali_filament_name && !obj->extrusion_cali_filament_name.empty()) + { + curr_selection = filament_index; + } + + filament_items.Add(wxString::FromUTF8(filament_it->name)); } m_comboBox_filament->Set(filament_items); m_comboBox_filament->SetSelection(curr_selection); diff --git a/tests/libslic3r/test_preset_bundle_loading.cpp b/tests/libslic3r/test_preset_bundle_loading.cpp index 55c18bfa9e..09f89eb9eb 100644 --- a/tests/libslic3r/test_preset_bundle_loading.cpp +++ b/tests/libslic3r/test_preset_bundle_loading.cpp @@ -1,5 +1,6 @@ #include +#include #include #include @@ -567,6 +568,88 @@ TEST_CASE("A printer specific filament supersedes the generic library filament w } +namespace { + +// One system printer plus the filament presets a machine facing dialog has to choose between: +// an Orca Filament Library generic with no compatible_printers, a same alias vendor filament +// that names the printer, a library filament with no vendor twin, and a vendor filament that +// belongs to a different printer. +struct MachineFilaments +{ + PresetBundle bundle; + VendorProfile library{PresetBundle::ORCA_FILAMENT_LIBRARY}; + VendorProfile vendor{"Vendor"}; + + MachineFilaments() + { + // VendorProfile's constructor takes an id; the library rule keys off the name. + library.name = PresetBundle::ORCA_FILAMENT_LIBRARY; + vendor.name = "Vendor"; + + Preset &printer = add_inmemory_preset(bundle.printers, "Printer A 0.4 nozzle"); + printer.is_system = true; + printer.vendor = &vendor; + printer.config.option("printer_model", true)->value = "Printer A"; + + add_filament(library, "Generic ABS @System", "Generic ABS", {}); + add_filament(vendor, "Generic ABS @Printer A", "Generic ABS", { "Printer A 0.4 nozzle" }); + add_filament(library, "FilAr ABS @System", "FilAr ABS", {}); + add_filament(vendor, "Vendor PLA @Printer B", "Vendor PLA", { "Printer B 0.4 nozzle" }); + + // update_library_profile_excluded_from() is protected and has its own test above; record + // the exclusion it derives from the same alias vendor filament. + Preset *shadowed = bundle.filaments.find_preset("Generic ABS @System"); + REQUIRE(shadowed != nullptr); + shadowed->m_excluded_from.insert("Printer A 0.4 nozzle"); + } + + void add_filament(const VendorProfile &owner, const std::string &name, const std::string &alias, + std::vector compatible_printers) + { + Preset &preset = add_inmemory_preset(bundle.filaments, name); + preset.is_system = true; + preset.alias = alias; + preset.vendor = &owner; + compatible_list(bundle.filaments, name, "compatible_printers") = std::move(compatible_printers); + } + + bool offers(const std::string &preset_name, bool include_user_presets = false) + { + const std::vector offered = + bundle.get_filament_presets_for_machine("Printer A", "0.4", include_user_presets); + return std::any_of(offered.begin(), offered.end(), + [&preset_name](const Preset *p) { return p->name == preset_name; }); + } +}; + +} // namespace + +TEST_CASE("Filaments offered for a machine follow the app's compatibility rule", "[Preset][Bundle]") +{ + MachineFilaments f; + + SECTION("a library filament with no compatible_printers is offered") { + CHECK(f.offers("FilAr ABS @System")); + } + + SECTION("a same alias vendor filament shadows the library generic") { + CHECK(f.offers("Generic ABS @Printer A")); + CHECK_FALSE(f.offers("Generic ABS @System")); + } + + SECTION("a filament naming a different printer is not offered") { + CHECK_FALSE(f.offers("Vendor PLA @Printer B")); + } + + SECTION("a user filament is offered only when the printer supports user presets") { + add_inmemory_preset(f.bundle.filaments, "My PLA"); + + CHECK_FALSE(f.offers("My PLA", /*include_user_presets=*/false)); + CHECK(f.offers("My PLA", /*include_user_presets=*/true)); + } +} + + namespace { const char *kMixedKeys[] = {