mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-05-14 00:52:04 +00:00
Fix: generic filaments not showing on list (#13037)
This commit is contained in:
@@ -653,7 +653,7 @@ public:
|
||||
int match_quality = -1;
|
||||
for (; i < n; ++i)
|
||||
// Since we use the filament selection from Wizard, it's needed to control the preset visibility too
|
||||
if (m_presets[i].is_compatible) {
|
||||
if (m_presets[i].is_compatible && m_presets[i].is_visible) {
|
||||
int this_match_quality = prefered_condition(m_presets[i]);
|
||||
if (this_match_quality > match_quality) {
|
||||
if (match_quality == std::numeric_limits<int>::max())
|
||||
|
||||
@@ -734,10 +734,17 @@ void PresetBundle::reset_project_embedded_presets()
|
||||
Preset& current_printer = this->printers.get_selected_preset();
|
||||
const std::vector<std::string> &prefered_filament_profiles = current_printer.config.option<ConfigOptionStrings>("default_filament_profile")->values;
|
||||
const std::string prefered_filament_profile = prefered_filament_profiles.empty() ? std::string() : prefered_filament_profiles.front();
|
||||
if (!prefered_filament_profile.empty())
|
||||
filament_presets[i] = prefered_filament_profile;
|
||||
else
|
||||
filament_presets[i] = this->filaments.first_visible().name;
|
||||
if (!prefered_filament_profile.empty()) {
|
||||
// Check if preferred filament exists and is visible
|
||||
const Preset* preferred_preset = this->filaments.find_preset(prefered_filament_profile, false);
|
||||
if (preferred_preset && preferred_preset->is_visible) {
|
||||
filament_presets[i] = prefered_filament_profile;
|
||||
} else {
|
||||
// Fall back to first visible filament
|
||||
filament_presets[i] = this->filaments.first_visible().name;
|
||||
}
|
||||
} else
|
||||
filament_presets[i] = this->filaments.first_visible().name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1970,8 +1977,14 @@ void PresetBundle::load_selections(AppConfig &config, const PresetPreferences& p
|
||||
initial_print_profile_name = prefered_print_profile;
|
||||
|
||||
const std::vector<std::string>& prefered_filament_profiles = preferred_printer->config.option<ConfigOptionStrings>("default_filament_profile")->values;
|
||||
if ((!initial_filament_profile_name.compare("Default Filament")) && (prefered_filament_profiles.size() > 0))
|
||||
initial_filament_profile_name = prefered_filament_profiles[0];
|
||||
if ((!initial_filament_profile_name.compare("Default Filament")) && (prefered_filament_profiles.size() > 0)) {
|
||||
// Check if preferred filament is visible
|
||||
const Preset* preferred_preset = this->filaments.find_preset(prefered_filament_profiles[0], false);
|
||||
if (preferred_preset && preferred_preset->is_visible) {
|
||||
initial_filament_profile_name = prefered_filament_profiles[0];
|
||||
}
|
||||
// If not visible, keep the default "Default Filament" which will be resolved later
|
||||
}
|
||||
}
|
||||
|
||||
// Selects the profile, leaves it to -1 if the initial profile name is empty or if it was not found.
|
||||
@@ -4452,7 +4465,7 @@ void PresetBundle::update_compatible(PresetSelectCompatibleType select_other_pri
|
||||
int operator()(const Preset &preset) const
|
||||
{
|
||||
// Don't match any properties of the "-- default --" profile or the external profiles when switching printer profile.
|
||||
if (preset.is_default || preset.is_external)
|
||||
if (preset.is_default || preset.is_external || !preset.is_visible)
|
||||
return 0;
|
||||
if (! m_prefered_alias.empty() && m_prefered_alias == preset.alias)
|
||||
// Matching an alias, always take this preset with priority.
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <string.h>
|
||||
#include "I18N.hpp"
|
||||
#include "libslic3r/AppConfig.hpp"
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "slic3r/GUI/wxExtensions.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
@@ -438,6 +439,50 @@ void GuideFrame::OnScriptMessage(wxWebViewEvent &evt)
|
||||
wxString s2 = OneSelect["model"];
|
||||
if (s1.compare(s2) == 0) {
|
||||
m_ProfileJson["model"][m]["nozzle_selected"] = m_ProfileJson["model"][m]["nozzle_diameter"];
|
||||
|
||||
// Automatically select default materials for this printer model
|
||||
// This mirrors the behavior of the old ConfigWizard::select_default_materials_for_printer_model()
|
||||
if (TmpModel.contains("materials") && !TmpModel["materials"].is_null()) {
|
||||
std::string materials_str;
|
||||
|
||||
// Handle both string and JSON array formats for materials
|
||||
if (TmpModel["materials"].is_string()) {
|
||||
materials_str = TmpModel["materials"].get<std::string>();
|
||||
} else if (TmpModel["materials"].is_array()) {
|
||||
// Convert JSON array to semicolon-separated string for unescape_strings_cstyle
|
||||
for (const auto& material : TmpModel["materials"]) {
|
||||
if (!materials_str.empty()) materials_str += ";";
|
||||
materials_str += material.get<std::string>();
|
||||
}
|
||||
} else {
|
||||
materials_str = "";
|
||||
}
|
||||
|
||||
boost::trim(materials_str);
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Processing default_materials for printer: " << s1.ToStdString() << " - materials: " << materials_str;
|
||||
|
||||
// Use the same parsing logic as ConfigWizard::select_default_materials_for_printer_model()
|
||||
// This calls unescape_strings_cstyle() just like Preset.cpp:298 does
|
||||
std::vector<std::string> materials;
|
||||
if (Slic3r::unescape_strings_cstyle(materials_str, materials)) {
|
||||
for (const std::string& material : materials) {
|
||||
if (!material.empty()) {
|
||||
// Mark this filament as selected if it exists in our filament list
|
||||
// This mirrors appconfig_new.set(section, material, "true") from ConfigWizard.cpp:2150
|
||||
if (m_ProfileJson["filament"].contains(material)) {
|
||||
m_ProfileJson["filament"][material]["selected"] = 1;
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Automatically selected default filament: " << material;
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << " Default filament '" << material << "' not found in available filaments for printer: " << s1.ToStdString();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " Malformed default_materials field: " << materials_str << " for printer: " << s1.ToStdString();
|
||||
}
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " No default_materials defined for printer: " << s1.ToStdString();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -838,45 +883,8 @@ bool GuideFrame::apply_config(AppConfig *app_config, PresetBundle *preset_bundle
|
||||
// Not switch filament
|
||||
//get_first_added_material_preset(AppConfig::SECTION_FILAMENTS, first_added_filament);
|
||||
|
||||
// For each @System filament, check if a vendor-specific override exists
|
||||
// in the loaded profiles. If so, replace the @System variant with the
|
||||
// override (e.g. replace "Generic ABS @System" with BBL "Generic ABS").
|
||||
// When printers from the default bundle are also selected, keep @System
|
||||
// too since those printers need it.
|
||||
static const std::string system_suffix = " @System";
|
||||
auto it_default = enabled_vendors.find(PresetBundle::ORCA_DEFAULT_BUNDLE);
|
||||
bool has_default_bundle_printer = it_default != enabled_vendors.end() && !it_default->second.empty();
|
||||
bool has_filament_profiles = m_ProfileJson.contains("filament");
|
||||
|
||||
// Check if any non-default vendor has selected printers
|
||||
bool has_vendor_printer = false;
|
||||
for (const auto& [vendor, models] : enabled_vendors) {
|
||||
if (vendor != PresetBundle::ORCA_DEFAULT_BUNDLE && !models.empty()) {
|
||||
has_vendor_printer = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> supplemented_filaments;
|
||||
for (const auto& [name, value] : enabled_filaments) {
|
||||
if (name.size() > system_suffix.size() &&
|
||||
name.compare(name.size() - system_suffix.size(), system_suffix.size(), system_suffix) == 0) {
|
||||
std::string short_name = name.substr(0, name.size() - system_suffix.size());
|
||||
if (has_vendor_printer && has_filament_profiles && m_ProfileJson["filament"].contains(short_name)) {
|
||||
supplemented_filaments[short_name] = value;
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Replacing @System filament: '" << name << "' -> '" << short_name << "'";
|
||||
if (has_default_bundle_printer) {
|
||||
supplemented_filaments[name] = value;
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Also keeping '" << name << "' for default bundle printers";
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
supplemented_filaments[name] = value;
|
||||
}
|
||||
|
||||
//update the app_config
|
||||
app_config->set_section(AppConfig::SECTION_FILAMENTS, supplemented_filaments);
|
||||
app_config->set_section(AppConfig::SECTION_FILAMENTS, enabled_filaments);
|
||||
app_config->set_vendors(m_appconfig_new);
|
||||
|
||||
if (check_unsaved_preset_changes)
|
||||
@@ -886,10 +894,10 @@ bool GuideFrame::apply_config(AppConfig *app_config, PresetBundle *preset_bundle
|
||||
// If the active filament is not in the wizard-selected filaments, switch to the first
|
||||
// compatible wizard-selected filament. This handles the first-run case where load_presets
|
||||
// falls back to "Generic PLA" even though the user selected a different filament.
|
||||
bool active_filament_selected = supplemented_filaments.empty()
|
||||
|| supplemented_filaments.count(preset_bundle->filament_presets.front()) > 0;
|
||||
bool active_filament_selected = enabled_filaments.empty()
|
||||
|| enabled_filaments.count(preset_bundle->filament_presets.front()) > 0;
|
||||
if (!active_filament_selected) {
|
||||
for (const auto& [filament_name, _] : supplemented_filaments) {
|
||||
for (const auto& [filament_name, _] : enabled_filaments) {
|
||||
const Preset* preset = preset_bundle->filaments.find_preset(filament_name);
|
||||
if (preset && preset->is_visible && preset->is_compatible) {
|
||||
preset_bundle->filaments.select_preset_by_name(filament_name, true);
|
||||
@@ -1124,21 +1132,23 @@ int GuideFrame::LoadProfileData()
|
||||
return 0;
|
||||
}
|
||||
|
||||
//sync to web
|
||||
std::string strAll = m_ProfileJson.dump(-1, ' ', false, json::error_handler_t::ignore);
|
||||
wxGetApp().CallAfter([this] {
|
||||
if (!m_destroy) {
|
||||
//sync to appconfig first to populate current selections
|
||||
SaveProfileData();
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", finished, json contents: " << std::endl << strAll;
|
||||
json m_Res = json::object();
|
||||
m_Res["command"] = "userguide_profile_load_finish";
|
||||
m_Res["sequence_id"] = "10001";
|
||||
wxString strJS = wxString::Format("HandleStudio(%s)", m_Res.dump(-1, ' ', true));
|
||||
if (!m_destroy)
|
||||
wxGetApp().CallAfter([this, strJS] { RunScript(strJS); });
|
||||
//sync to web after selections are populated
|
||||
std::string strAll = m_ProfileJson.dump(-1, ' ', false, json::error_handler_t::ignore);
|
||||
|
||||
//sync to appconfig
|
||||
if (!m_destroy)
|
||||
wxGetApp().CallAfter([this] { SaveProfileData(); });
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", finished, json contents: " << std::endl << strAll;
|
||||
json m_Res = json::object();
|
||||
m_Res["command"] = "userguide_profile_load_finish";
|
||||
m_Res["sequence_id"] = "10001";
|
||||
wxString strJS = wxString::Format("HandleStudio(%s)", m_Res.dump(-1, ' ', true));
|
||||
|
||||
RunScript(strJS);
|
||||
}
|
||||
});
|
||||
} catch (std::exception& e) {
|
||||
// wxLogMessage("GUIDE: load_profile_error %s ", e.what());
|
||||
// wxMessageBox(e.what(), "", MB_OK);
|
||||
|
||||
@@ -420,7 +420,9 @@ int DropDown::hoverIndex()
|
||||
{
|
||||
if (hover_item < 0)
|
||||
return -1;
|
||||
if (count == items.size())
|
||||
// BUG FIX: Can't take the shortcut if subDropDown exists (which means there are groups)
|
||||
// because we need to detect group headers which return negative indices
|
||||
if (count == items.size() && subDropDown == nullptr)
|
||||
return hover_item;
|
||||
int index = -1;
|
||||
std::set<wxString> groups;
|
||||
@@ -448,7 +450,9 @@ int DropDown::selectedItem()
|
||||
{
|
||||
if (selection < 0)
|
||||
return -1;
|
||||
if (count == items.size())
|
||||
// BUG FIX: Can't take the shortcut if subDropDown exists (which means there are groups)
|
||||
// because the visual position differs from the actual item index when groups are shown
|
||||
if (count == items.size() && subDropDown == nullptr)
|
||||
return selection;
|
||||
auto & sel = items[selection];
|
||||
if (group.IsEmpty() ? !sel.group.IsEmpty() : sel.group != group)
|
||||
|
||||
Reference in New Issue
Block a user