diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 16ae49bdc16..c5eea998727 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -3359,6 +3359,52 @@ std::string PresetCollection::filament_id_by_type(const std::string& filament_ty return preset(first_visible_idx_by_type(filament_type)).filament_id; } +std::string PresetCollection::filament_id_by_id_or_name(const std::string& id_or_name) const +{ + if (id_or_name.empty()) + return {}; + size_t start = m_default_suppressed ? m_num_default_presets : 0; + // First pass: match by filament_id (e.g. "GFL00") + for (size_t i = start; i < m_presets.size(); ++i) { + const auto& p = m_presets[i]; + if (p.is_visible && p.is_compatible && p.filament_id == id_or_name) + return p.filament_id; + } + // Second pass: match by setting_id (e.g. "OGFSA04") — most presets have this even without filament_id + for (size_t i = start; i < m_presets.size(); ++i) { + const auto& p = m_presets[i]; + if (p.is_visible && p.is_compatible && p.setting_id == id_or_name) + return p.filament_id.empty() ? p.setting_id : p.filament_id; + } + // Third pass: match by preset name — user presets may have neither filament_id nor setting_id, + // so return the name itself as the identifier for downstream name-based lookup. + for (size_t i = start; i < m_presets.size(); ++i) { + const auto& p = m_presets[i]; + if (p.is_visible && p.is_compatible && p.name == id_or_name) { + if (!p.filament_id.empty()) return p.filament_id; + if (!p.setting_id.empty()) return p.setting_id; + return p.name; + } + } + // Fourth pass: case-insensitive match against full name or base name before '@' + // (e.g. "Esun pla+" matches "eSUN PLA+ @System"). + std::string id_lower = boost::algorithm::to_lower_copy(id_or_name); + for (size_t i = start; i < m_presets.size(); ++i) { + const auto& p = m_presets[i]; + if (!p.is_visible || !p.is_compatible) continue; + std::string name_lower = boost::algorithm::to_lower_copy(p.name); + // Strip trailing " @..." suffix to get the base name. + auto at_pos = name_lower.find(" @"); + std::string base_lower = (at_pos != std::string::npos) ? name_lower.substr(0, at_pos) : name_lower; + if (name_lower == id_lower || base_lower == id_lower) { + if (!p.filament_id.empty()) return p.filament_id; + if (!p.setting_id.empty()) return p.setting_id; + return p.name; + } + } + return {}; +} + std::vector PresetCollection::diameters_of_selected_printer() { std::set diameters; diff --git a/src/libslic3r/Preset.hpp b/src/libslic3r/Preset.hpp index 8863f04672b..291d29f194b 100644 --- a/src/libslic3r/Preset.hpp +++ b/src/libslic3r/Preset.hpp @@ -707,6 +707,9 @@ class PresetCollection size_t first_visible_idx_by_type(const std::string& filament_type) const; // Return the filament_id of the best-matching visible preset for the given filament type. std::string filament_id_by_type(const std::string& filament_type) const; + // Return the filament_id of the first visible preset matching by filament_id or preset name. + // Returns empty string if no match found. + std::string filament_id_by_id_or_name(const std::string& id_or_name) const; // Return index of the first compatible preset. Certainly at least the '- default -' preset shall be compatible. // If one of the prefered_alternates is compatible, select it. template size_t first_compatible_idx(PreferedCondition prefered_condition) const diff --git a/src/libslic3r/PresetBundle.cpp b/src/libslic3r/PresetBundle.cpp index 01cbc43bc28..d411419b1e6 100644 --- a/src/libslic3r/PresetBundle.cpp +++ b/src/libslic3r/PresetBundle.cpp @@ -3205,6 +3205,10 @@ void PresetBundle::get_ams_cobox_infos(AMSComboInfo& combox_info) } auto iter = std::find_if(filaments.begin(), filaments.end(), [this, &filament_id](auto &f) { return f.is_compatible && filaments.get_preset_base(f) == &f && f.filament_id == filament_id; }); + // Also try matching by preset name for user presets that have no filament_id. + if (iter == filaments.end()) + iter = std::find_if(filaments.begin(), filaments.end(), + [&filament_id](auto &f) { return f.is_compatible && f.name == filament_id; }); if (iter == filaments.end()) { BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": filament_id %1% not found or system or compatible") % filament_id; auto filament_type = ams.opt_string("filament_type", 0u); @@ -3307,6 +3311,10 @@ unsigned int PresetBundle::sync_ams_list(std::vectorfilaments.filament_id_by_type(tray.tray_type) - : map_filament_type_to_generic_id(tray.tray_type); + // Try to match preset by filament_id, then setting_id from lane_data (spoolman-lane-sync + // stores the OrcaSlicer preset name/id in setting_id; filament_id may be a raw Spoolman DB id). + // Falls back to material-type matching if no preset found. + std::string lane_filament_id = safe_json_string(lane_obj, "filament_id"); + std::string lane_setting_id = safe_json_string(lane_obj, "setting_id"); + tray.tray_info_idx = ""; + if (!lane_filament_id.empty() && bundle) + tray.tray_info_idx = bundle->filaments.filament_id_by_id_or_name(lane_filament_id); + if (tray.tray_info_idx.empty() && !lane_setting_id.empty() && bundle) + tray.tray_info_idx = bundle->filaments.filament_id_by_id_or_name(lane_setting_id); + if (tray.tray_info_idx.empty()) + tray.tray_info_idx = bundle + ? bundle->filaments.filament_id_by_type(tray.tray_type) + : map_filament_type_to_generic_id(tray.tray_type); max_lane_index = std::max(max_lane_index, lane_index); trays.push_back(tray);