Modification of extruders filaments for support XL multitool (#36)

* Fix for SPE-1659 : Wrong filaments update, when templates are allowed/suppressed

* Per Extruder Filaments (related to SPE 1599)

* Implemented compatibility for each extruder separately
* Update of the filaments compatibility is extracted to separate function update_filaments_compatible()
* Fixed synchronization of config.ini with the current selections, when preset is changed from sidebar.

* Filament Settings Tab improvements:
* Added extruder combobox to select active extruder
* PresetCombobox is updated in respect to compatibility for active extruder
* For MM printer: Cog icon near the filament will switch to Filament Settings for selected filament

* Bug fixing for https://dev.prusa3d.com/browse/SPE-1599

* Next round of bugfixing for https://dev.prusa3d.com/browse/SPE-1599

* Fixed crashes from https://dev.prusa3d.com/browse/SPE-1599
+ code refactoring for Tab:save_preset()
This commit is contained in:
Oleksandra Yushchenko 2023-05-11 12:17:59 +02:00 committed by GitHub
parent 989cbeceb1
commit 9e4859ebbf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 769 additions and 246 deletions

View File

@ -403,7 +403,9 @@ void Preset::set_visible_from_appconfig(const AppConfig &app_config)
is_visible = app_config.get_variant(vendor->id, model, variant);
} else if (type == TYPE_FILAMENT || type == TYPE_SLA_MATERIAL) {
const std::string &section_name = (type == TYPE_FILAMENT) ? AppConfig::SECTION_FILAMENTS : AppConfig::SECTION_MATERIALS;
if (app_config.has_section(section_name)) {
if (type == TYPE_FILAMENT && app_config.get_bool("no_templates") && vendor && vendor->templates_profile)
is_visible = false;
else if (app_config.has_section(section_name)) {
// Check whether this profile is marked as "installed" in PrusaSlicer.ini,
// or whether a profile is marked as "installed", which this profile may have been renamed from.
const std::map<std::string, std::string> &installed = app_config.get_section(section_name);
@ -896,8 +898,9 @@ Preset& PresetCollection::load_preset(const std::string &path, const std::string
return preset;
}
void PresetCollection::save_current_preset(const std::string &new_name, bool detach)
bool PresetCollection::save_current_preset(const std::string &new_name, bool detach)
{
bool is_saved_as_new{ false };
// 1) Find the preset with a new_name or create a new one,
// initialize it with the edited config.
auto it = this->find_preset_internal(new_name);
@ -906,7 +909,7 @@ void PresetCollection::save_current_preset(const std::string &new_name, bool det
Preset &preset = *it;
if (preset.is_default || preset.is_external || preset.is_system)
// Cannot overwrite the default preset.
return;
return false;
// Overwriting an existing preset.
preset.config = std::move(m_edited_preset.config);
// The newly saved preset will be activated -> make it visible.
@ -919,6 +922,7 @@ void PresetCollection::save_current_preset(const std::string &new_name, bool det
preset.renamed_from.clear();
}
} else {
is_saved_as_new = true;
// Creating a new preset.
Preset &preset = *m_presets.insert(it, m_edited_preset);
std::string &inherits = preset.inherits();
@ -953,6 +957,8 @@ void PresetCollection::save_current_preset(const std::string &new_name, bool det
this->select_preset_by_name(new_name, true);
// 2) Store the active preset to disk.
this->get_selected_preset().save();
return is_saved_as_new;
}
Preset& PresetCollection::get_preset_with_name(const std::string& new_name, const Preset* initial_preset)
@ -1212,7 +1218,13 @@ size_t PresetCollection::update_compatible_internal(const PresetWithVendorProfil
if (selected)
preset_selected.is_compatible = preset_edited.is_compatible;
if (preset_edited.vendor && preset_edited.vendor->templates_profile) {
indices_of_template_presets.push_back(idx_preset);
if (preset_selected.is_visible)
indices_of_template_presets.push_back(idx_preset);
else {
preset_selected.is_compatible = false;
if (selected)
m_idx_selected = size_t(-1);
}
}
}
// filter out template profiles where profile with same alias and compability exists
@ -2092,6 +2104,136 @@ bool PhysicalPrinterCollection::is_selected(PhysicalPrinterCollection::ConstIter
m_selected_preset == preset_name;
}
ExtruderFilaments::ExtruderFilaments(PresetCollection* filaments_collection, size_t extruder_id, std::string selected_name/* = std::string()*/)
: m_filaments (filaments_collection)
, m_extruder_id(extruder_id)
{
const std::deque<Preset>& presets = m_filaments->get_presets();
for (size_t id = 0; id < presets.size(); id ++)
m_extr_filaments.emplace_back(&(presets[id]));
select_filament(selected_name.empty() ? m_filaments->get_selected_preset_name() : selected_name);
}
const std::string& ExtruderFilaments::get_preset_name_by_alias(const std::string& alias) const
{
const auto& aliases_map = m_filaments->map_alias_to_profile_name();
for (
// Find the 1st profile name with the alias.
auto it = Slic3r::lower_bound_by_predicate(aliases_map.begin(), aliases_map.end(), [&alias](auto& l) { return l.first < alias; });
// Continue over all profile names with the same alias.
it != aliases_map.end() && it->first == alias; ++it)
if (auto it_filament = find_filament_internal(it->second);
it_filament != m_extr_filaments.end() && it_filament->preset->name == it->second &&
it_filament->preset->is_visible && (it_filament->is_compatible || size_t(it_filament - m_extr_filaments.begin()) == m_idx_selected))
return it_filament->preset->name;
return alias;
}
bool ExtruderFilaments::select_filament(const std::string &name_w_suffix, bool force/*= false*/)
{
std::string name = Preset::remove_suffix_modified(name_w_suffix);
// 1) Try to find the preset by its name.
auto it = this->find_filament_internal(name);
size_t idx = 0;
if (it != m_extr_filaments.end() && it->preset->name == name && it->preset->is_visible)
// Preset found by its name and it is visible.
idx = it - m_extr_filaments.begin();
else {
// Find the first visible preset.
for (size_t i = 0; i < m_extr_filaments.size(); ++i)
if (m_extr_filaments[i].preset->is_visible/* && m_extr_filaments[i].is_compatible*/) {
idx = i;
break;
}
// If the first visible preset was not found, return the 0th element, which is the default preset.
}
// 2) Select the new preset.
if (m_idx_selected != idx || force) {
this->select_filament(idx);
return true;
}
return false;
}
size_t ExtruderFilaments::update_compatible_internal(const PresetWithVendorProfile &active_printer,
const PresetWithVendorProfile *active_print,
PresetSelectCompatibleType unselect_if_incompatible)
{
DynamicPrintConfig config;
config.set_key_value("printer_preset", new ConfigOptionString(active_printer.preset.name));
const ConfigOption* opt = active_printer.preset.config.option("nozzle_diameter");
if (opt)
config.set_key_value("num_extruders", new ConfigOptionInt((int)static_cast<const ConfigOptionFloats*>(opt)->values.size()));
bool some_compatible = false;
// Adjust printer preset config to the first extruder from m_extruder_id
Preset printer_preset_adjusted = active_printer.preset;
if (m_extruder_id > 0 && !printer_preset_adjusted.config.opt_bool("single_extruder_multi_material")) {
DynamicPrintConfig& active_printer_config = printer_preset_adjusted.config;
for (const std::string& key : print_config_def.extruder_option_keys()) {
if (key == "default_filament_profile")
continue;// Ignore this field, because this parameter is not related to the extruder but to whole printer.
auto* opt = active_printer_config.option(key, false);
if (opt != nullptr && opt->is_vector())
static_cast<ConfigOptionVectorBase*>(opt)->set_at(opt, 0, m_extruder_id);
}
}
PresetWithVendorProfile active_printer_adjusted(printer_preset_adjusted, active_printer.vendor);
std::vector<size_t> indices_of_template_presets;
indices_of_template_presets.reserve(m_extr_filaments.size());
size_t num_default_presets = m_filaments->num_default_presets();
for (size_t idx_preset = num_default_presets; idx_preset < m_extr_filaments.size(); ++idx_preset) {
const bool is_selected = idx_preset == m_idx_selected;
const Preset* preset = m_extr_filaments[idx_preset].preset;
Filament& extr_filament = m_extr_filaments[idx_preset];
const PresetWithVendorProfile this_preset_with_vendor_profile = m_filaments->get_preset_with_vendor_profile(*preset);
bool was_compatible = extr_filament.is_compatible;
extr_filament.is_compatible = is_compatible_with_printer(this_preset_with_vendor_profile, active_printer_adjusted, &config);
some_compatible |= extr_filament.is_compatible;
if (active_print != nullptr)
extr_filament.is_compatible &= is_compatible_with_print(this_preset_with_vendor_profile, *active_print, active_printer_adjusted);
if (!extr_filament.is_compatible && is_selected &&
(unselect_if_incompatible == PresetSelectCompatibleType::Always || (unselect_if_incompatible == PresetSelectCompatibleType::OnlyIfWasCompatible && was_compatible)))
m_idx_selected = size_t(-1);
if (preset->vendor && preset->vendor->templates_profile) {
if (preset->is_visible)
indices_of_template_presets.push_back(idx_preset);
else {
extr_filament.is_compatible = false;
if (is_selected)
m_idx_selected = size_t(-1);
}
}
}
// filter out template profiles where profile with same alias and compability exists
if (!indices_of_template_presets.empty()) {
for (size_t idx = num_default_presets; idx < m_extr_filaments.size(); ++idx) {
const Filament& filament = m_extr_filaments[idx];
const VendorProfile* vendor = filament.preset->vendor;
if (vendor && !vendor->templates_profile && filament.is_compatible) {
const std::string& preset_alias = filament.preset->alias;
for (const auto& template_idx : indices_of_template_presets) {
if (m_extr_filaments[template_idx].preset->alias == preset_alias) {
m_extr_filaments[template_idx].is_compatible = false;
// unselect selected template filament if there is non-template alias compatible
if (template_idx == m_idx_selected && (unselect_if_incompatible != PresetSelectCompatibleType::Never))
m_idx_selected = size_t(-1);
break;
}
}
}
}
}
return m_idx_selected;
}
namespace PresetUtils {
const VendorProfile::PrinterModel* system_printer_model(const Preset &preset)

View File

@ -341,7 +341,8 @@ public:
// Save the preset under a new name. If the name is different from the old one,
// a new preset is stored into the list of presets.
// All presets are marked as not modified and the new preset is activated.
void save_current_preset(const std::string &new_name, bool detach = false);
// return true, if new preset is stored
bool save_current_preset(const std::string &new_name, bool detach = false);
// Find the preset with a new_name or create a new one,
// initialize it with the initial_preset config.
@ -507,7 +508,7 @@ public:
// Generate a file path from a profile name. Add the ".ini" suffix if it is missing.
std::string path_from_name(const std::string &new_name) const;
size_t num_default_presets() { return m_num_default_presets; }
size_t num_default_presets() const { return m_num_default_presets; }
protected:
PresetCollection() = default;
@ -566,6 +567,8 @@ public:
static bool is_dirty(const Preset *edited, const Preset *reference);
static std::vector<std::string> dirty_options(const Preset *edited, const Preset *reference, const bool deep_compare = false);
static bool is_independent_from_extruder_number_option(const std::string& opt_key);
const std::vector<std::pair<std::string, std::string>>& map_alias_to_profile_name() { return m_map_alias_to_profile_name; }
private:
// Type of this PresetCollection: TYPE_PRINT, TYPE_FILAMENT or TYPE_PRINTER.
Preset::Type m_type;
@ -827,6 +830,142 @@ private:
};
// ---------------------------------
// *** ExtruderFilaments ***
// ---------------------------------
class Filament
{
public:
Filament(const Preset* preset) : preset(preset) {}
// Sort lexicographically by a preset name. The preset name shall be unique across a single PresetCollection.
bool operator<(const Filament& other) const { return this->preset->name < other.preset->name; }
const Preset* preset;
bool is_compatible{ true };
};
// Collections of filaments for extruder
class ExtruderFilaments
{
PresetCollection* m_filaments{ nullptr };
// Selected filament.
size_t m_idx_selected{ size_t(-1) };
// List of filaments for this extruder
std::deque<Filament> m_extr_filaments;
size_t m_extruder_id;
std::string m_cached_selected_name{ std::string() };
public:
ExtruderFilaments(PresetCollection* filaments_collection, size_t extruder_id = 0, std::string selected_name = std::string());
typedef std::deque<Filament>::iterator Iterator;
typedef std::deque<Filament>::const_iterator ConstIterator;
Iterator begin() { return m_extr_filaments.begin(); }
ConstIterator begin() const { return m_extr_filaments.cbegin(); }
ConstIterator cbegin() const { return m_extr_filaments.cbegin(); }
Iterator end() { return m_extr_filaments.end(); }
ConstIterator end() const { return m_extr_filaments.cend(); }
ConstIterator cend() const { return m_extr_filaments.cend(); }
bool empty() const { return m_extr_filaments.empty(); }
const std::deque<Filament>& operator()() const { return m_extr_filaments; }
// Return a filament by an index. If the filament is active, a temporary copy is returned.
Filament& filament(size_t idx) { return m_extr_filaments[idx]; }
const Filament& filament(size_t idx) const { return const_cast<ExtruderFilaments*>(this)->filament(idx); }
// Select filament by the full filament name, which contains name of filament, separator and name of selected preset
// If full_name doesn't contain name of selected preset, then select first preset in the list for this filament
bool select_filament(const std::string& name, bool force = false);
void select_filament(size_t idx) { m_idx_selected = idx; }
std::string get_selected_preset_name() const { return m_idx_selected == size_t(-1) ? std::string() : m_extr_filaments[m_idx_selected].preset->name; }
const Preset* get_selected_preset() const { return m_idx_selected == size_t(-1) ? nullptr : m_extr_filaments[m_idx_selected].preset; }
const Filament* get_selected_filament() const { return m_idx_selected == size_t(-1) ? nullptr : &m_extr_filaments[m_idx_selected]; }
size_t get_selected_idx() const { return m_idx_selected; }
friend class PresetBundle;
ExtruderFilaments() = default;
ExtruderFilaments& operator=(const ExtruderFilaments& other) = default;
private:
// Find a preset position in the sorted list of presets.
// The "-- default -- " preset is always the first, so it needs
// to be handled differently.
// If a preset does not exist, an iterator is returned indicating where to insert a preset with the same name.
std::deque<Filament>::iterator find_filament_internal(const std::string& name)
{
return Slic3r::lower_bound_by_predicate(m_extr_filaments.begin(), m_extr_filaments.end(), [&name](const auto& l) {
return l.preset->name < name;
});
}
std::deque<Filament>::const_iterator find_filament_internal(const std::string& name) const
{
return const_cast<ExtruderFilaments*>(this)->find_filament_internal(name);
}
void cache_selected_name() { m_cached_selected_name = get_selected_preset_name(); }
std::string get_cached_selected_name() const { return m_cached_selected_name; }
// 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<typename PreferedCondition>
size_t first_compatible_idx(PreferedCondition prefered_condition) const
{
size_t i = m_filaments->is_default_suppressed() ? m_filaments->num_default_presets() : 0;
size_t n = m_extr_filaments.size();
size_t i_compatible = n;
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_extr_filaments[i].is_compatible && m_filaments->preset(i).is_visible) {
int this_match_quality = prefered_condition(*(m_extr_filaments[i].preset));
if (this_match_quality > match_quality) {
if (match_quality == std::numeric_limits<int>::max())
// Better match will not be found.
return i;
// Store the first compatible profile with highest match quality into i_compatible.
i_compatible = i;
match_quality = this_match_quality;
}
}
return (i_compatible == n) ?
// No compatible preset found, return the default preset.
0 :
// Compatible preset found.
i_compatible;
}
// Return index of the first compatible preset. Certainly at least the '- default -' preset shall be compatible.
size_t first_compatible_idx() const { return this->first_compatible_idx([](const /*Filament*/Preset&) -> int { return 0; }); }
template<typename PreferedCondition>
const Preset* first_compatible(PreferedCondition prefered_condition) { return m_extr_filaments[this->first_compatible_idx(prefered_condition)].preset;}
const Preset* first_compatible() { return m_extr_filaments[this->first_compatible_idx()].preset; }
const std::string& get_preset_name_by_alias(const std::string& alias) const;
size_t update_compatible_internal(const PresetWithVendorProfile& active_printer, const PresetWithVendorProfile* active_print, PresetSelectCompatibleType unselect_if_incompatible);
// For Print / Filament presets, disable those, which are not compatible with the printer.
template<typename PreferedCondition>
void update_compatible(const PresetWithVendorProfile& active_printer, const PresetWithVendorProfile* active_print, PresetSelectCompatibleType select_other_if_incompatible, PreferedCondition prefered_condition)
{
if (this->update_compatible_internal(active_printer, active_print, select_other_if_incompatible) == (size_t)-1)
// Find some other compatible preset, or the "-- default --" preset.
this->select_filament(this->first_compatible_idx(prefered_condition));
}
void update_compatible(const PresetWithVendorProfile& active_printer, const PresetWithVendorProfile* active_print, PresetSelectCompatibleType select_other_if_incompatible)
{
this->update_compatible(active_printer, active_print, select_other_if_incompatible, [](const /*Filament*/Preset&) -> int { return 0; });
}
};
} // namespace Slic3r
#endif /* slic3r_Preset_hpp_ */

View File

@ -119,7 +119,7 @@ PresetBundle& PresetBundle::operator=(const PresetBundle &rhs)
printers = rhs.printers;
physical_printers = rhs.physical_printers;
filament_presets = rhs.filament_presets;
extruders_filaments = rhs.extruders_filaments;
project_config = rhs.project_config;
vendors = rhs.vendors;
obsolete_presets = rhs.obsolete_presets;
@ -143,8 +143,7 @@ void PresetBundle::reset(bool delete_files)
this->filaments .reset(delete_files);
this->sla_materials.reset(delete_files);
this->printers .reset(delete_files);
this->filament_presets.clear();
this->filament_presets.emplace_back(this->filaments.get_selected_preset_name());
this->extruders_filaments.clear();
this->obsolete_presets.prints.clear();
this->obsolete_presets.sla_prints.clear();
this->obsolete_presets.filaments.clear();
@ -426,7 +425,26 @@ void PresetBundle::load_installed_printers(const AppConfig &config)
preset.set_visible_from_appconfig(config);
}
PresetCollection& PresetBundle::get_presets(Preset::Type type)
void PresetBundle::cache_extruder_filaments_names()
{
for (ExtruderFilaments& extr_filaments : extruders_filaments)
extr_filaments.cache_selected_name();
}
void PresetBundle::reset_extruder_filaments()
{
// save previously cached selected names
std::vector<std::string> names;
for (const ExtruderFilaments& extr_filaments : extruders_filaments)
names.push_back(extr_filaments.get_cached_selected_name());
// Reset extruder_filaments and set names
this->extruders_filaments.clear();
for (size_t id = 0; id < names.size(); ++id)
this->extruders_filaments.emplace_back(ExtruderFilaments(&filaments, id, names[id]));
}
PresetCollection&PresetBundle::get_presets(Preset::Type type)
{
assert(type >= Preset::TYPE_PRINT && type <= Preset::TYPE_PRINTER);
@ -437,12 +455,15 @@ PresetCollection& PresetBundle::get_presets(Preset::Type type)
}
const std::string& PresetBundle::get_preset_name_by_alias( const Preset::Type& preset_type, const std::string& alias)
const std::string& PresetBundle::get_preset_name_by_alias( const Preset::Type& preset_type, const std::string& alias, int extruder_id /*= -1*/)
{
// there are not aliases for Printers profiles
if (preset_type == Preset::TYPE_PRINTER || preset_type == Preset::TYPE_INVALID)
return alias;
if (preset_type == Preset::TYPE_FILAMENT)
return extruders_filaments[extruder_id].get_preset_name_by_alias(alias);
const PresetCollection& presets = get_presets(preset_type);
return presets.get_preset_name_by_alias(alias);
@ -462,8 +483,11 @@ void PresetBundle::save_changes_for_preset(const std::string& new_name, Preset::
if (type == Preset::TYPE_PRINTER)
copy_bed_model_and_texture_if_needed(presets.get_edited_preset().config);
if (type == Preset::TYPE_FILAMENT)
cache_extruder_filaments_names();
// Save the preset into Slic3r::data_dir / presets / section_name / preset_name.ini
presets.save_current_preset(new_name);
if (presets.save_current_preset(new_name) && type == Preset::TYPE_FILAMENT)
reset_extruder_filaments();
// Mark the print & filament enabled if they are compatible with the currently selected preset.
// If saving the preset changes compatibility with other presets, keep the now incompatible dependent presets selected, however with a "red flag" icon showing that they are no more compatible.
update_compatible(PresetSelectCompatibleType::Never);
@ -602,35 +626,37 @@ void PresetBundle::load_selections(AppConfig &config, const PresetPreferences& p
// Load it even if the current printer technology is SLA.
// The possibly excessive filament names will be later removed with this->update_multi_material_filament_presets()
// once the FFF technology gets selected.
this->filament_presets = { filaments.get_selected_preset_name() };
this->extruders_filaments.clear();
this->extruders_filaments.emplace_back(ExtruderFilaments(&filaments));
for (unsigned int i = 1; i < 1000; ++ i) {
char name[64];
sprintf(name, "filament_%u", i);
if (! config.has("presets", name))
break;
this->filament_presets.emplace_back(remove_ini_suffix(config.get("presets", name)));
this->extruders_filaments.emplace_back(ExtruderFilaments(&filaments, i, remove_ini_suffix(config.get("presets", name))));
}
// ! update MM filaments presets before update compatibility
this->update_multi_material_filament_presets();
// Update visibility of presets based on their compatibility with the active printer.
// Always try to select a compatible print and filament preset to the current printer preset,
// as the application may have been closed with an active "external" preset, which does not
// exist.
this->update_compatible(PresetSelectCompatibleType::Always);
this->update_multi_material_filament_presets();
if (initial_printer != nullptr && (preferred_printer == nullptr || initial_printer == preferred_printer)) {
// Don't run the following code, as we want to activate default filament / SLA material profiles when installing and selecting a new printer.
// Only run this code if just a filament / SLA material was installed by Config Wizard for an active Printer.
auto printer_technology = printers.get_selected_preset().printer_technology();
if (printer_technology == ptFFF && ! preferred_selection.filament.empty()) {
std::string preferred_preset_name = get_preset_name_by_alias(Preset::Type::TYPE_FILAMENT, preferred_selection.filament);
const std::string& preferred_preset_name = get_preset_name_by_alias(Preset::Type::TYPE_FILAMENT, preferred_selection.filament, 0);
if (auto it = filaments.find_preset_internal(preferred_preset_name);
it != filaments.end() && it->is_visible && it->is_compatible) {
filaments.select_preset_by_name_strict(preferred_preset_name);
this->filament_presets.front() = filaments.get_selected_preset_name();
this->extruders_filaments.front().select_filament(filaments.get_selected_preset_name());
}
} else if (printer_technology == ptSLA && ! preferred_selection.sla_material.empty()) {
std::string preferred_preset_name = get_preset_name_by_alias(Preset::Type::TYPE_SLA_MATERIAL, preferred_selection.sla_material);
const std::string& preferred_preset_name = get_preset_name_by_alias(Preset::Type::TYPE_SLA_MATERIAL, preferred_selection.sla_material);
if (auto it = sla_materials.find_preset_internal(preferred_preset_name);
it != sla_materials.end() && it->is_visible && it->is_compatible)
sla_materials.select_preset_by_name_strict(preferred_preset_name);
@ -648,15 +674,15 @@ void PresetBundle::load_selections(AppConfig &config, const PresetPreferences& p
// Export selections (current print, current filaments, current printer) into config.ini
void PresetBundle::export_selections(AppConfig &config)
{
assert(this->printers.get_edited_preset().printer_technology() != ptFFF || filament_presets.size() >= 1);
assert(this->printers.get_edited_preset().printer_technology() != ptFFF || filament_presets.size() > 1 || filaments.get_selected_preset_name() == filament_presets.front());
assert(this->printers.get_edited_preset().printer_technology() != ptFFF || extruders_filaments.size() >= 1);
assert(this->printers.get_edited_preset().printer_technology() != ptFFF || extruders_filaments.size() > 1 || filaments.get_selected_preset().alias == extruders_filaments.front().get_selected_preset()->alias);
config.clear_section("presets");
config.set("presets", "print", prints.get_selected_preset_name());
config.set("presets", "filament", filament_presets.front());
for (unsigned i = 1; i < filament_presets.size(); ++i) {
config.set("presets", "filament", extruders_filaments.front().get_selected_preset_name());
for (unsigned i = 1; i < extruders_filaments.size(); ++i) {
char name[64];
sprintf(name, "filament_%u", i);
config.set("presets", name, filament_presets[i]);
config.set("presets", name, extruders_filaments[i].get_selected_preset_name());
}
config.set("presets", "sla_print", sla_prints.get_selected_preset_name());
@ -711,8 +737,8 @@ DynamicPrintConfig PresetBundle::full_fff_config() const
// First collect the filament configurations based on the user selection of this->filament_presets.
// Here this->filaments.find_preset() and this->filaments.first_visible() return the edited copy of the preset if active.
std::vector<const DynamicPrintConfig*> filament_configs;
for (const std::string &filament_preset_name : this->filament_presets)
filament_configs.emplace_back(&this->filaments.find_preset(filament_preset_name, true)->config);
for (const auto& extr_filaments : this->extruders_filaments)
filament_configs.emplace_back(&this->filaments.find_preset(extr_filaments.get_selected_preset_name(), true)->config);
while (filament_configs.size() < num_extruders)
filament_configs.emplace_back(&this->filaments.first_visible().config);
for (const DynamicPrintConfig *cfg : filament_configs) {
@ -763,7 +789,10 @@ DynamicPrintConfig PresetBundle::full_fff_config() const
}
out.option<ConfigOptionString >("print_settings_id", true)->value = this->prints.get_selected_preset_name();
out.option<ConfigOptionStrings>("filament_settings_id", true)->values = this->filament_presets;
auto& filament_settings_id = out.option<ConfigOptionStrings>("filament_settings_id", true)->values;
filament_settings_id.clear();
for (const auto& extr_filaments : this->extruders_filaments)
filament_settings_id.emplace_back(extr_filaments.get_selected_preset_name());
out.option<ConfigOptionString >("printer_settings_id", true)->value = this->printers.get_selected_preset_name();
out.option<ConfigOptionString >("physical_printer_settings_id", true)->value = this->physical_printers.get_selected_printer_name();
@ -981,6 +1010,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
auto old_filament_profile_names = config.option<ConfigOptionStrings>("filament_settings_id", true);
old_filament_profile_names->values.resize(num_extruders, std::string());
this->extruders_filaments.clear();
if (num_extruders <= 1) {
// Split the "compatible_printers_condition" and "inherits" from the cummulative vectors to separate filament presets.
inherits = inherits_values[1];
@ -994,8 +1024,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
loaded= &this->filaments.load_preset(this->filaments.path_from_name(name), name, config);
loaded->save();
}
this->filament_presets.clear();
this->filament_presets.emplace_back(loaded->name);
this->extruders_filaments.emplace_back(ExtruderFilaments(&filaments));
} else {
assert(is_external);
// Split the filament presets, load each of them separately.
@ -1014,7 +1043,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
}
}
// Load the configs into this->filaments and make them active.
this->filament_presets = std::vector<std::string>(configs.size());
std::vector<std::string> extr_names = std::vector<std::string>(configs.size());
// To avoid incorrect selection of the first filament preset (means a value of Preset->m_idx_selected)
// in a case when next added preset take a place of previosly selected preset,
// we should add presets from last to first
@ -1035,8 +1064,11 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
PresetCollection::LoadAndSelect::Never :
PresetCollection::LoadAndSelect::OnlyIfModified);
any_modified |= modified;
this->filament_presets[i] = loaded->name;
extr_names[i] = loaded->name;
}
// create extruders_filaments only when all filaments are loaded
for (size_t id = 0; id < extr_names.size(); ++id)
this->extruders_filaments.emplace_back(ExtruderFilaments(&filaments, id, extr_names[id]));
}
// 4) Load the project config values (the per extruder wipe matrix etc).
@ -1137,9 +1169,11 @@ ConfigSubstitutions PresetBundle::load_config_file_config_bundle(
load_one(this->filaments, tmp_bundle.filaments, tmp_bundle.filaments .get_selected_preset_name(), true);
load_one(this->sla_materials, tmp_bundle.sla_materials, tmp_bundle.sla_materials.get_selected_preset_name(), true);
load_one(this->printers, tmp_bundle.printers, tmp_bundle.printers .get_selected_preset_name(), true);
this->extruders_filaments.clear();
this->update_multi_material_filament_presets();
for (size_t i = 1; i < std::min(tmp_bundle.filament_presets.size(), this->filament_presets.size()); ++ i)
this->filament_presets[i] = load_one(this->filaments, tmp_bundle.filaments, tmp_bundle.filament_presets[i], false);
for (size_t i = 1; i < std::min(tmp_bundle.extruders_filaments.size(), this->extruders_filaments.size()); ++i)
this->extruders_filaments[i].select_filament(load_one(this->filaments, tmp_bundle.filaments, tmp_bundle.extruders_filaments[i].get_selected_preset_name(), false));
this->update_compatible(PresetSelectCompatibleType::Never);
@ -1622,9 +1656,12 @@ std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_configbundle(
// Activate the first filament preset.
if (! active_filaments.empty() && ! active_filaments.front().empty())
filaments.select_preset_by_name(active_filaments.front(), true);
// Extruder_filaments have to be recreated with new loaded filaments
this->extruders_filaments.clear();
this->update_multi_material_filament_presets();
for (size_t i = 0; i < std::min(this->filament_presets.size(), active_filaments.size()); ++ i)
this->filament_presets[i] = filaments.find_preset(active_filaments[i], true)->name;
for (size_t i = 0; i < std::min(this->extruders_filaments.size(), active_filaments.size()); ++ i)
this->extruders_filaments[i].select_filament(filaments.find_preset(active_filaments[i], true)->name);
this->update_compatible(PresetSelectCompatibleType::Never);
}
@ -1640,10 +1677,15 @@ void PresetBundle::update_multi_material_filament_presets()
auto *nozzle_diameter = static_cast<const ConfigOptionFloats*>(printers.get_edited_preset().config.option("nozzle_diameter"));
size_t num_extruders = nozzle_diameter->values.size();
// Verify validity of the current filament presets.
for (size_t i = 0; i < std::min(this->filament_presets.size(), num_extruders); ++ i)
this->filament_presets[i] = this->filaments.find_preset(this->filament_presets[i], true)->name;
// Append the rest of filament presets.
this->filament_presets.resize(num_extruders, this->filament_presets.empty() ? this->filaments.first_visible().name : this->filament_presets.back());
for (size_t i = 0; i < std::min(this->extruders_filaments.size(), num_extruders); ++i)
this->extruders_filaments[i].select_filament(this->filaments.find_preset(this->extruders_filaments[i].get_selected_preset_name(), true)->name);
if (this->extruders_filaments.size() > num_extruders)
this->extruders_filaments.resize(num_extruders);
else
// Append the rest of filament presets.
for (size_t id = extruders_filaments.size(); id < num_extruders; id++)
extruders_filaments.emplace_back(ExtruderFilaments(&filaments, id, id == 0 ? filaments.first_visible().name : extruders_filaments[id - 1].get_selected_preset_name()));
// Now verify if wiping_volumes_matrix has proper size (it is used to deduce number of extruders in wipe tower generator):
std::vector<double> old_matrix = this->project_config.option<ConfigOptionFloats>("wiping_volumes_matrix")->values;
@ -1673,6 +1715,99 @@ void PresetBundle::update_multi_material_filament_presets()
}
}
void PresetBundle::update_filaments_compatible(PresetSelectCompatibleType select_other_filament_if_incompatible, int extruder_idx/* = -1*/)
{
const Preset& printer_preset = this->printers.get_edited_preset();
const PresetWithVendorProfile printer_preset_with_vendor_profile = this->printers.get_preset_with_vendor_profile(printer_preset);
const PresetWithVendorProfile print_preset_with_vendor_profile = this->prints.get_edited_preset_with_vendor_profile();
const std::vector<std::string>& prefered_filament_profiles = printer_preset.config.option<ConfigOptionStrings>("default_filament_profile")->values;
class PreferedFilamentsProfileMatch
{
public:
PreferedFilamentsProfileMatch(const Preset* preset, const std::vector<std::string>& prefered_names, int extruder_id = 0) :
m_extruder_id(extruder_id),
m_prefered_alias(preset ? preset->alias : std::string()),
m_prefered_filament_type(preset ? preset->config.opt_string("filament_type", extruder_id) : std::string()),
m_prefered_names(prefered_names) {}
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)
return 0;
if (!m_prefered_alias.empty() && m_prefered_alias == preset.alias)
// Matching an alias, always take this preset with priority.
return std::numeric_limits<int>::max();
int match_quality = (std::find(m_prefered_names.begin(), m_prefered_names.end(), preset.name) != m_prefered_names.end()) + 1;
if (!m_prefered_filament_type.empty() && m_prefered_filament_type == preset.config.opt_string("filament_type", m_extruder_id))
match_quality *= 10;
return match_quality;
}
private:
int m_extruder_id;
const std::string m_prefered_alias;
const std::string m_prefered_filament_type;
const std::vector<std::string>& m_prefered_names;
};
//! ysFIXME - delete after testing
//!// First select a first compatible profile for the preset editor.
//!this->filaments.update_compatible(printer_preset_with_vendor_profile, &print_preset_with_vendor_profile, select_other_filament_if_incompatible,
//! PreferedFilamentsProfileMatch(this->filaments.get_selected_idx() == size_t(-1) ? nullptr : &this->filaments.get_edited_preset(), prefered_filament_profiles));
// Update compatible for extruder filaments
auto update_filament_compatible = [this, select_other_filament_if_incompatible, printer_preset_with_vendor_profile, print_preset_with_vendor_profile, prefered_filament_profiles](int idx)
{
ExtruderFilaments& extr_filaments = extruders_filaments[idx];
// Remember whether the filament profiles were compatible before updating the filament compatibility.
bool filament_preset_was_compatible = false;
const Filament* filament_old = extr_filaments.get_selected_filament();
if (select_other_filament_if_incompatible != PresetSelectCompatibleType::Never)
filament_preset_was_compatible = filament_old && filament_old->is_compatible;
extr_filaments.update_compatible(printer_preset_with_vendor_profile, &print_preset_with_vendor_profile, select_other_filament_if_incompatible,
PreferedFilamentsProfileMatch(filament_old ? filament_old->preset : nullptr, prefered_filament_profiles, idx));
const Filament* filament = extr_filaments.get_selected_filament();
const bool is_compatible = filament && filament->is_compatible;
if (is_compatible || select_other_filament_if_incompatible == PresetSelectCompatibleType::Never)
return;
// Verify validity of the current filament presets.
if (this->extruders_filaments.size() == 1) {
// The compatible profile should have been already selected for the preset editor. Just use it.
if (select_other_filament_if_incompatible == PresetSelectCompatibleType::Always || filament_preset_was_compatible)
extr_filaments.select_filament(this->filaments.get_edited_preset().name);
}
else {
const std::string filament_name = extr_filaments.get_selected_preset_name();
if (!filament || (!is_compatible && (select_other_filament_if_incompatible == PresetSelectCompatibleType::Always || filament_preset_was_compatible))) {
// Pick a compatible profile. If there are prefered_filament_profiles, use them.
std::string compat_filament_name = extr_filaments.first_compatible(PreferedFilamentsProfileMatch(filament->preset, prefered_filament_profiles, idx))->name;
if (filament_name != compat_filament_name)
extr_filaments.select_filament(compat_filament_name);
}
}
};
if (extruder_idx < 0) {
// update compatibility for all extruders
const size_t num_extruders = static_cast<const ConfigOptionFloats*>(printer_preset.config.option("nozzle_diameter"))->values.size();
for (size_t idx = 0; idx < std::min(this->extruders_filaments.size(), num_extruders); idx++)
update_filament_compatible(idx);
}
else
update_filament_compatible(extruder_idx);
if (this->filaments.get_idx_selected() == size_t(-1))
this->filaments.select_preset(extruders_filaments[0].get_selected_idx());
}
void PresetBundle::update_compatible(PresetSelectCompatibleType select_other_print_if_incompatible, PresetSelectCompatibleType select_other_filament_if_incompatible)
{
const Preset &printer_preset = this->printers.get_edited_preset();
@ -1727,99 +1862,18 @@ void PresetBundle::update_compatible(PresetSelectCompatibleType select_other_pri
const double m_prefered_layer_height;
};
// Matching by the layer height in addition.
class PreferedFilamentProfileMatch : public PreferedProfileMatch
{
public:
PreferedFilamentProfileMatch(const Preset *preset, const std::string &prefered_name) :
PreferedProfileMatch(preset ? preset->alias : std::string(), prefered_name),
m_prefered_filament_type(preset ? preset->config.opt_string("filament_type", 0) : std::string()) {}
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)
return 0;
int match_quality = PreferedProfileMatch::operator()(preset);
if (match_quality < std::numeric_limits<int>::max()) {
match_quality += 1;
if (! m_prefered_filament_type.empty() && m_prefered_filament_type == preset.config.opt_string("filament_type", 0))
match_quality *= 10;
}
return match_quality;
}
private:
const std::string m_prefered_filament_type;
};
// Matching by the layer height in addition.
class PreferedFilamentsProfileMatch
{
public:
PreferedFilamentsProfileMatch(const Preset *preset, const std::vector<std::string> &prefered_names) :
m_prefered_alias(preset ? preset->alias : std::string()),
m_prefered_filament_type(preset ? preset->config.opt_string("filament_type", 0) : std::string()),
m_prefered_names(prefered_names)
{}
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)
return 0;
if (! m_prefered_alias.empty() && m_prefered_alias == preset.alias)
// Matching an alias, always take this preset with priority.
return std::numeric_limits<int>::max();
int match_quality = (std::find(m_prefered_names.begin(), m_prefered_names.end(), preset.name) != m_prefered_names.end()) + 1;
if (! m_prefered_filament_type.empty() && m_prefered_filament_type == preset.config.opt_string("filament_type", 0))
match_quality *= 10;
return match_quality;
}
private:
const std::string m_prefered_alias;
const std::string m_prefered_filament_type;
const std::vector<std::string> &m_prefered_names;
};
switch (printer_preset.printer_technology()) {
case ptFFF:
{
assert(printer_preset.config.has("default_print_profile"));
assert(printer_preset.config.has("default_filament_profile"));
const std::vector<std::string> &prefered_filament_profiles = printer_preset.config.option<ConfigOptionStrings>("default_filament_profile")->values;
this->prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_print_if_incompatible,
PreferedPrintProfileMatch(this->prints.get_selected_idx() == size_t(-1) ? nullptr : &this->prints.get_edited_preset(), printer_preset.config.opt_string("default_print_profile")));
const PresetWithVendorProfile print_preset_with_vendor_profile = this->prints.get_edited_preset_with_vendor_profile();
// Remember whether the filament profiles were compatible before updating the filament compatibility.
std::vector<char> filament_preset_was_compatible(this->filament_presets.size(), false);
for (size_t idx = 0; idx < this->filament_presets.size(); ++ idx) {
Preset *preset = this->filaments.find_preset(this->filament_presets[idx], false);
filament_preset_was_compatible[idx] = preset != nullptr && preset->is_compatible;
}
// First select a first compatible profile for the preset editor.
this->filaments.update_compatible(printer_preset_with_vendor_profile, &print_preset_with_vendor_profile, select_other_filament_if_incompatible,
PreferedFilamentsProfileMatch(this->filaments.get_selected_idx() == size_t(-1) ? nullptr : &this->filaments.get_edited_preset(), prefered_filament_profiles));
if (select_other_filament_if_incompatible != PresetSelectCompatibleType::Never) {
// Verify validity of the current filament presets.
const std::string prefered_filament_profile = prefered_filament_profiles.empty() ? std::string() : prefered_filament_profiles.front();
if (this->filament_presets.size() == 1) {
// The compatible profile should have been already selected for the preset editor. Just use it.
if (select_other_filament_if_incompatible == PresetSelectCompatibleType::Always || filament_preset_was_compatible.front())
this->filament_presets.front() = this->filaments.get_edited_preset().name;
} else {
for (size_t idx = 0; idx < this->filament_presets.size(); ++ idx) {
std::string &filament_name = this->filament_presets[idx];
Preset *preset = this->filaments.find_preset(filament_name, false);
if (preset == nullptr || (! preset->is_compatible && (select_other_filament_if_incompatible == PresetSelectCompatibleType::Always || filament_preset_was_compatible[idx])))
// Pick a compatible profile. If there are prefered_filament_profiles, use them.
filament_name = this->filaments.first_compatible(
PreferedFilamentProfileMatch(preset,
(idx < prefered_filament_profiles.size()) ? prefered_filament_profiles[idx] : prefered_filament_profile)).name;
}
}
}
// Update compatibility for all currently existent extruder_filaments.
update_filaments_compatible(select_other_filament_if_incompatible);
break;
}
case ptSLA:
@ -1875,13 +1929,13 @@ void PresetBundle::export_configbundle(const std::string &path, bool export_syst
c << "sla_print = " << this->sla_prints.get_selected_preset_name() << std::endl;
c << "sla_material = " << this->sla_materials.get_selected_preset_name() << std::endl;
c << "printer = " << this->printers.get_selected_preset_name() << std::endl;
for (size_t i = 0; i < this->filament_presets.size(); ++ i) {
for (size_t i = 0; i < this->extruders_filaments.size(); ++ i) {
char suffix[64];
if (i > 0)
sprintf(suffix, "_%d", (int)i);
else
suffix[0] = 0;
c << "filament" << suffix << " = " << this->filament_presets[i] << std::endl;
c << "filament" << suffix << " = " << this->extruders_filaments[i].get_selected_preset_name() << std::endl;
}
if (export_physical_printers && this->physical_printers.get_selected_idx() >= 0)
@ -1901,9 +1955,11 @@ void PresetBundle::export_configbundle(const std::string &path, bool export_syst
// an optional "(modified)" suffix will be removed from the filament name.
void PresetBundle::set_filament_preset(size_t idx, const std::string &name)
{
if (idx >= filament_presets.size())
filament_presets.resize(idx + 1, filaments.default_preset().name);
filament_presets[idx] = Preset::remove_suffix_modified(name);
if (idx >= extruders_filaments.size()) {
for (size_t id = extruders_filaments.size(); id < idx; id++)
extruders_filaments.emplace_back(ExtruderFilaments(&filaments, id, filaments.default_preset().name));
}
extruders_filaments[idx].select_filament(Preset::remove_suffix_modified(name));
}
void PresetBundle::set_default_suppressed(bool default_suppressed)

View File

@ -51,9 +51,12 @@ public:
const PresetCollection& materials(PrinterTechnology pt) const { return pt == ptFFF ? this->filaments : this->sla_materials; }
PrinterPresetCollection printers;
PhysicalPrinterCollection physical_printers;
// Filament preset names for a multi-extruder or multi-material print.
// extruders.size() should be the same as printers.get_edited_preset().config.nozzle_diameter.size()
std::vector<std::string> filament_presets;
// Filament presets per extruder for a multi-extruder or multi-material print.
// extruders_filaments.size() should be the same as printers.get_edited_preset().config.nozzle_diameter.size()
std::vector<ExtruderFilaments> extruders_filaments;
void cache_extruder_filaments_names();
void reset_extruder_filaments();
PresetCollection& get_presets(Preset::Type preset_type);
@ -132,6 +135,8 @@ public:
// update size and content of filament_presets.
void update_multi_material_filament_presets();
void update_filaments_compatible(PresetSelectCompatibleType select_other_filament_if_incompatible, int extruder_idx = -1);
// Update the is_compatible flag of all print and filament presets depending on whether they are marked
// as compatible with the currently selected printer (and print in case of filament presets).
// Also updates the is_visible flag of each preset.
@ -145,7 +150,7 @@ public:
// If the "vendor" section is missing, enable all models and variants of the particular vendor.
void load_installed_printers(const AppConfig &config);
const std::string& get_preset_name_by_alias(const Preset::Type& preset_type, const std::string& alias);
const std::string& get_preset_name_by_alias(const Preset::Type& preset_type, const std::string& alias, int extruder_id = -1);
// Save current preset of a provided type under a new name. If the name is different from the old one,
// Unselected option would be reverted to the beginning values

View File

@ -1068,12 +1068,6 @@ void Sidebar::update_presets(Preset::Type preset_type)
dynamic_cast<ConfigOptionFloats*>(preset_bundle.printers.get_edited_preset().config.option("nozzle_diameter"))->values.size();
const size_t filament_cnt = p->combos_filament.size() > extruder_cnt ? extruder_cnt : p->combos_filament.size();
if (filament_cnt == 1) {
// Single filament printer, synchronize the filament presets.
const std::string &name = preset_bundle.filaments.get_selected_preset_name();
preset_bundle.set_filament_preset(0, name);
}
for (size_t i = 0; i < filament_cnt; i++)
p->combos_filament[i]->update();
@ -1417,14 +1411,14 @@ void Sidebar::update_sliced_info_sizer()
new_label = _L("Used Filament (g)");
info_text = wxString::Format("%.2f", ps.total_weight);
const std::vector<std::string>& filament_presets = wxGetApp().preset_bundle->filament_presets;
const auto& extruders_filaments = wxGetApp().preset_bundle->extruders_filaments;
const PresetCollection& filaments = wxGetApp().preset_bundle->filaments;
if (ps.filament_stats.size() > 1)
new_label += ":";
for (auto filament : ps.filament_stats) {
const Preset* filament_preset = filaments.find_preset(filament_presets[filament.first], false);
const Preset* filament_preset = filaments.find_preset(extruders_filaments[filament.first].get_selected_preset_name(), false);
if (filament_preset) {
double filament_weight;
if (ps.filament_stats.size() == 1)
@ -2405,8 +2399,8 @@ void Plater::check_selected_presets_visibility(PrinterTechnology loaded_printer_
PresetBundle* preset_bundle = wxGetApp().preset_bundle;
if (loaded_printer_technology == ptFFF) {
update_selected_preset_visibility(preset_bundle->prints, names);
for (const std::string& filament : preset_bundle->filament_presets) {
Preset* preset = preset_bundle->filaments.find_preset(filament);
for (const auto& extruder_filaments : preset_bundle->extruders_filaments) {
Preset* preset = preset_bundle->filaments.find_preset(extruder_filaments.get_selected_preset_name());
if (preset && !preset->is_visible) {
preset->is_visible = true;
names.emplace_back(preset->name);
@ -4018,19 +4012,25 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt)
//! combo->GetStringSelection().ToUTF8().data());
std::string preset_name = wxGetApp().preset_bundle->get_preset_name_by_alias(preset_type,
Preset::remove_suffix_modified(combo->GetString(selection).ToUTF8().data()));
if (preset_type == Preset::TYPE_FILAMENT) {
wxGetApp().preset_bundle->set_filament_preset(idx, preset_name);
}
Preset::remove_suffix_modified(into_u8(combo->GetString(selection))), idx);
std::string last_selected_ph_printer_name = combo->get_selected_ph_printer_name();
bool select_preset = !combo->selection_is_changed_according_to_physical_printers();
// TODO: ?
if (preset_type == Preset::TYPE_FILAMENT && sidebar->is_multifilament()) {
// Only update the plater UI for the 2nd and other filaments.
combo->update();
if (preset_type == Preset::TYPE_FILAMENT) {
wxGetApp().preset_bundle->set_filament_preset(idx, preset_name);
TabFilament* tab = dynamic_cast<TabFilament*>(wxGetApp().get_tab(Preset::TYPE_FILAMENT));
if (tab && combo->get_extruder_idx() == tab->get_active_extruder() && !tab->select_preset(preset_name)) {
// revert previously selection
const std::string& old_name = wxGetApp().preset_bundle->filaments.get_edited_preset().name;
wxGetApp().preset_bundle->set_filament_preset(idx, old_name);
combo->update();
}
else
// Synchronize config.ini with the current selections.
wxGetApp().preset_bundle->export_selections(*wxGetApp().app_config);
}
else if (select_preset) {
wxWindowUpdateLocker noUpdates(sidebar->presets_panel());
@ -6886,6 +6886,8 @@ void Plater::on_extruders_change(size_t num_extruders)
if (num_extruders == choices.size())
return;
dynamic_cast<TabFilament*>(wxGetApp().get_tab(Preset::TYPE_FILAMENT))->update_extruder_combobox();
wxWindowUpdateLocker noUpdates_scrolled_panel(&sidebar()/*.scrolled_panel()*/);
size_t i = choices.size();
@ -6912,16 +6914,16 @@ bool Plater::update_filament_colors_in_full_config()
// There is a case, when we use filament_color instead of extruder_color (when extruder_color == "").
// Thus plater config option "filament_colour" should be filled with filament_presets values.
// Otherwise, on 3dScene will be used last edited filament color for all volumes with extruder_color == "".
const std::vector<std::string> filament_presets = wxGetApp().preset_bundle->filament_presets;
if (filament_presets.size() == 1 || !p->config->has("filament_colour"))
const auto& extruders_filaments = wxGetApp().preset_bundle->extruders_filaments;
if (extruders_filaments.size() == 1 || !p->config->has("filament_colour"))
return false;
const PresetCollection& filaments = wxGetApp().preset_bundle->filaments;
std::vector<std::string> filament_colors;
filament_colors.reserve(filament_presets.size());
filament_colors.reserve(extruders_filaments.size());
for (const std::string& filament_preset : filament_presets)
filament_colors.push_back(filaments.find_preset(filament_preset, true)->config.opt_string("filament_colour", (unsigned)0));
for (const auto& extr_filaments : extruders_filaments)
filament_colors.push_back(filaments.find_preset(extr_filaments.get_selected_preset_name(), true)->config.opt_string("filament_colour", (unsigned)0));
p->config->option<ConfigOptionStrings>("filament_colour")->values = filament_colors;
return true;
@ -7016,16 +7018,17 @@ void Plater::force_filament_colors_update()
{
bool update_scheduled = false;
DynamicPrintConfig* config = p->config;
const std::vector<std::string> filament_presets = wxGetApp().preset_bundle->filament_presets;
if (filament_presets.size() > 1 &&
p->config->option<ConfigOptionStrings>("filament_colour")->values.size() == filament_presets.size())
const auto& extruders_filaments = wxGetApp().preset_bundle->extruders_filaments;
if (extruders_filaments.size() > 1 &&
p->config->option<ConfigOptionStrings>("filament_colour")->values.size() == extruders_filaments.size())
{
const PresetCollection& filaments = wxGetApp().preset_bundle->filaments;
std::vector<std::string> filament_colors;
filament_colors.reserve(filament_presets.size());
filament_colors.reserve(extruders_filaments.size());
for (const std::string& filament_preset : filament_presets)
filament_colors.push_back(filaments.find_preset(filament_preset, true)->config.opt_string("filament_colour", (unsigned)0));
for (const auto& extr_filaments : extruders_filaments)
filament_colors.push_back(extr_filaments.get_selected_preset()->config.opt_string("filament_colour", (unsigned)0));
if (config->option<ConfigOptionStrings>("filament_colour")->values != filament_colors) {
config->option<ConfigOptionStrings>("filament_colour")->values = filament_colors;
@ -7042,6 +7045,20 @@ void Plater::force_filament_colors_update()
this->p->schedule_background_process();
}
void Plater::force_filament_cb_update()
{
// Update visibility for templates presets according to app_config
PresetCollection& filaments = wxGetApp().preset_bundle->filaments;
AppConfig& config = *wxGetApp().app_config;
for (Preset& preset : filaments)
preset.set_visible_from_appconfig(config);
wxGetApp().preset_bundle->update_compatible(PresetSelectCompatibleType::Never, PresetSelectCompatibleType::OnlyIfWasCompatible);
// Update preset comboboxes on sidebar and filaments tab
p->sidebar->update_presets(Preset::TYPE_FILAMENT);
wxGetApp().get_tab(Preset::TYPE_FILAMENT)->select_preset(wxGetApp().preset_bundle->filaments.get_selected_preset_name());
}
void Plater::force_print_bed_update()
{
// Fill in the printer model key with something which cannot possibly be valid, so that Plater::on_config_change() will update the print bed

View File

@ -308,6 +308,7 @@ public:
bool update_filament_colors_in_full_config();
void on_config_change(const DynamicPrintConfig &config);
void force_filament_colors_update();
void force_filament_cb_update();
void force_print_bed_update();
// On activating the parent window.
void on_activate();

View File

@ -694,8 +694,6 @@ void PreferencesDialog::accept(wxEvent&)
#endif // __linux__
}
bool update_filament_sidebar = (m_values.find("no_templates") != m_values.end());
std::vector<std::string> options_to_recreate_GUI = { "no_defaults", "tabs_as_menu", "sys_menu_enabled", "font_size" };
for (const std::string& option : options_to_recreate_GUI) {
@ -761,12 +759,12 @@ void PreferencesDialog::accept(wxEvent&)
wxGetApp().force_menu_update();
#endif //_MSW_DARK_MODE
#endif // _WIN32
if (m_values.find("no_templates") != m_values.end())
wxGetApp().plater()->force_filament_cb_update();
wxGetApp().update_ui_from_settings();
clear_cache();
if (update_filament_sidebar)
wxGetApp().plater()->sidebar().update_presets(Preset::Type::TYPE_FILAMENT);
}
void PreferencesDialog::revert(wxEvent&)

View File

@ -585,10 +585,10 @@ PlaterPresetComboBox::PlaterPresetComboBox(wxWindow *parent, Preset::Type preset
if (m_type == Preset::TYPE_FILAMENT)
{
Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &event) {
const Preset* selected_preset = m_collection->find_preset(m_preset_bundle->filament_presets[m_extruder_idx]);
const Filament* selected_filament = m_preset_bundle->extruders_filaments[m_extruder_idx].get_selected_filament();
// Wide icons are shown if the currently selected preset is not compatible with the current printer,
// and red flag is drown in front of the selected preset.
bool wide_icons = selected_preset && !selected_preset->is_compatible;
const bool wide_icons = selected_filament && !selected_filament->is_compatible;
float scale = m_em_unit*0.1f;
int shifl_Left = wide_icons ? int(scale * 16 + 0.5) : 0;
@ -686,22 +686,16 @@ void PlaterPresetComboBox::switch_to_tab()
if (int page_id = wxGetApp().tab_panel()->FindPage(tab); page_id != wxNOT_FOUND)
{
//In a case of a multi-material printing, for editing another Filament Preset
//it's needed to select this preset for the "Filament settings" Tab
if (m_type == Preset::TYPE_FILAMENT && wxGetApp().extruders_edited_cnt() > 1 &&
!dynamic_cast<TabFilament*>(wxGetApp().get_tab(m_type))->set_active_extruder(m_extruder_idx))
// do nothing, if we can't set new extruder and select new preset
return;
wxGetApp().tab_panel()->SetSelection(page_id);
// Switch to Settings NotePad
wxGetApp().mainframe->select_tab();
//In a case of a multi-material printing, for editing another Filament Preset
//it's needed to select this preset for the "Filament settings" Tab
if (m_type == Preset::TYPE_FILAMENT && wxGetApp().extruders_edited_cnt() > 1)
{
const std::string& selected_preset = GetString(GetSelection()).ToUTF8().data();
// Call select_preset() only if there is new preset and not just modified
if (!boost::algorithm::ends_with(selected_preset, Preset::suffix_modified()))
{
const std::string& preset_name = wxGetApp().preset_bundle->filaments.get_preset_name_by_alias(selected_preset);
wxGetApp().get_tab(m_type)->select_preset(preset_name);
}
}
}
}
@ -808,7 +802,7 @@ void PlaterPresetComboBox::update()
{
if (m_type == Preset::TYPE_FILAMENT &&
(m_preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA ||
m_preset_bundle->filament_presets.size() <= (size_t)m_extruder_idx) )
m_preset_bundle->extruders_filaments.size() <= (size_t)m_extruder_idx) )
return;
// Otherwise fill in the list from scratch.
@ -816,6 +810,8 @@ void PlaterPresetComboBox::update()
this->Clear();
invalidate_selection();
const ExtruderFilaments& extruder_filaments = m_preset_bundle->extruders_filaments[m_extruder_idx >= 0 ? m_extruder_idx : 0];
const Preset* selected_filament_preset = nullptr;
std::string extruder_color;
if (m_type == Preset::TYPE_FILAMENT) {
@ -823,21 +819,23 @@ void PlaterPresetComboBox::update()
if (!can_decode_color(extruder_color))
// Extruder color is not defined.
extruder_color.clear();
selected_filament_preset = m_collection->find_preset(m_preset_bundle->filament_presets[m_extruder_idx]);
selected_filament_preset = extruder_filaments.get_selected_preset();
assert(selected_filament_preset);
}
bool has_selection = m_collection->get_selected_idx() != size_t(-1);
const Preset* selected_preset = m_type == Preset::TYPE_FILAMENT ? selected_filament_preset : has_selection ? &m_collection->get_selected_preset() : nullptr;
// Show wide icons if the currently selected preset is not compatible with the current printer,
// and draw a red flag in front of the selected preset.
bool wide_icons = selected_preset && !selected_preset->is_compatible;
bool wide_icons = m_type == Preset::TYPE_FILAMENT ?
extruder_filaments.get_selected_filament() && !extruder_filaments.get_selected_filament()->is_compatible :
m_collection->get_selected_idx() != size_t(-1) && !m_collection->get_selected_preset().is_compatible;
null_icon_width = (wide_icons ? 3 : 2) * norm_icon_width + thin_space_icon_width + wide_space_icon_width;
std::map<wxString, wxBitmapBundle*> nonsys_presets;
std::map<wxString, wxBitmapBundle*> template_presets;
const bool allow_templates = !wxGetApp().app_config->get_bool("no_templates");
wxString selected_user_preset;
wxString tooltip;
const std::deque<Preset>& presets = m_collection->get_presets();
@ -848,13 +846,15 @@ void PlaterPresetComboBox::update()
for (size_t i = presets.front().is_visible ? 0 : m_collection->num_default_presets(); i < presets.size(); ++i)
{
const Preset& preset = presets[i];
bool is_selected = m_type == Preset::TYPE_FILAMENT ?
m_preset_bundle->filament_presets[m_extruder_idx] == preset.name :
const bool is_selected = m_type == Preset::TYPE_FILAMENT ?
selected_filament_preset->name == preset.name :
// The case, when some physical printer is selected
m_type == Preset::TYPE_PRINTER && m_preset_bundle->physical_printers.has_selection() ? false :
i == m_collection->get_selected_idx();
if (!preset.is_visible || (!preset.is_compatible && !is_selected))
const bool is_compatible = m_type == Preset::TYPE_FILAMENT ? extruder_filaments.filament(i).is_compatible : preset.is_compatible;
if (!preset.is_visible || (!is_compatible && !is_selected))
continue;
std::string bitmap_key, filament_rgb, extruder_rgb, material_rgb;
@ -878,17 +878,19 @@ void PlaterPresetComboBox::update()
}
auto bmp = get_bmp(bitmap_key, wide_icons, bitmap_type_name,
preset.is_compatible, preset.is_system || preset.is_default,
is_compatible, preset.is_system || preset.is_default,
single_bar, filament_rgb, extruder_rgb, material_rgb);
assert(bmp);
const std::string name = preset.alias.empty() ? preset.name : preset.alias;
if (preset.is_default || preset.is_system) {
if (preset.vendor && preset.vendor->templates_profile) {
template_presets.emplace(get_preset_name(preset), bmp);
if (is_selected) {
selected_user_preset = get_preset_name(preset);
tooltip = from_u8(preset.name);
if (allow_templates) {
template_presets.emplace(get_preset_name(preset), bmp);
if (is_selected) {
selected_user_preset = get_preset_name(preset);
tooltip = from_u8(preset.name);
}
}
} else {
Append(get_preset_name(preset), *bmp);
@ -919,8 +921,7 @@ void PlaterPresetComboBox::update()
}
}
const AppConfig* app_config = wxGetApp().app_config;
if (!template_presets.empty() && app_config->get("no_templates") == "0") {
if (!template_presets.empty()) {
set_label_marker(Append(separator(L("Template presets")), wxNullBitmap));
for (std::map<wxString, wxBitmapBundle*>::iterator it = template_presets.begin(); it != template_presets.end(); ++it) {
Append(it->first, *it->second);
@ -1063,15 +1064,19 @@ void TabPresetComboBox::update()
Clear();
invalidate_selection();
const ExtruderFilaments& extruder_filaments = m_preset_bundle->extruders_filaments[m_active_extruder_idx];
const std::deque<Preset>& presets = m_collection->get_presets();
std::map<wxString, std::pair<wxBitmapBundle*, bool>> nonsys_presets;
std::map<wxString, std::pair<wxBitmapBundle*, bool>> template_presets;
const bool allow_templates = !wxGetApp().app_config->get_bool("no_templates");
wxString selected = "";
if (!presets.front().is_visible)
set_label_marker(Append(separator(L("System presets")), NullBitmapBndl()));
size_t idx_selected = m_collection->get_selected_idx();
size_t idx_selected = m_type == Preset::TYPE_FILAMENT ? extruder_filaments.get_selected_idx() : m_collection->get_selected_idx();
if (m_type == Preset::TYPE_PRINTER && m_preset_bundle->physical_printers.has_selection()) {
std::string sel_preset_name = m_preset_bundle->physical_printers.get_selected_printer_preset_name();
@ -1083,7 +1088,10 @@ void TabPresetComboBox::update()
for (size_t i = presets.front().is_visible ? 0 : m_collection->num_default_presets(); i < presets.size(); ++i)
{
const Preset& preset = presets[i];
if (!preset.is_visible || (!show_incompatible && !preset.is_compatible && i != idx_selected))
const bool is_compatible = m_type == Preset::TYPE_FILAMENT ? extruder_filaments.filament(i).is_compatible : preset.is_compatible;
if (!preset.is_visible || (!show_incompatible && !is_compatible && i != idx_selected))
continue;
// marker used for disable incompatible printer models for the selected physical printer
@ -1097,14 +1105,16 @@ void TabPresetComboBox::update()
}
std::string main_icon_name = m_type == Preset::TYPE_PRINTER && preset.printer_technology() == ptSLA ? "sla_printer" : m_main_bitmap_name;
auto bmp = get_bmp(bitmap_key, main_icon_name, "lock_closed", is_enabled, preset.is_compatible, preset.is_system || preset.is_default);
auto bmp = get_bmp(bitmap_key, main_icon_name, "lock_closed", is_enabled, is_compatible, preset.is_system || preset.is_default);
assert(bmp);
if (preset.is_default || preset.is_system) {
if (preset.is_default || preset.is_system) {
if (preset.vendor && preset.vendor->templates_profile) {
template_presets.emplace(get_preset_name(preset), std::pair<wxBitmapBundle*, bool>(bmp, is_enabled));
if (i == idx_selected)
selected = get_preset_name(preset);
if (allow_templates) {
template_presets.emplace(get_preset_name(preset), std::pair<wxBitmapBundle*, bool>(bmp, is_enabled));
if (i == idx_selected)
selected = get_preset_name(preset);
}
} else {
int item_id = Append(get_preset_name(preset), *bmp);
if (!is_enabled)
@ -1136,9 +1146,8 @@ void TabPresetComboBox::update()
validate_selection(it->first == selected);
}
}
const AppConfig* app_config = wxGetApp().app_config;
if (!template_presets.empty() && app_config->get("no_templates") == "0") {
if (!template_presets.empty()) {
set_label_marker(Append(separator(L("Template presets")), wxNullBitmap));
for (std::map<wxString, std::pair<wxBitmapBundle*, bool>>::iterator it = template_presets.begin(); it != template_presets.end(); ++it) {
int item_id = Append(it->first, *it->second.first);

View File

@ -179,6 +179,8 @@ class TabPresetComboBox : public PresetComboBox
{
bool show_incompatible {false};
bool m_enable_all {false};
// This parameter is used by FilamentSettings tab to show filament setting related to the active extruder
int m_active_extruder_idx {0};
public:
TabPresetComboBox(wxWindow *parent, Preset::Type preset_type);
@ -197,6 +199,9 @@ public:
PresetCollection* presets() const { return m_collection; }
Preset::Type type() const { return m_type; }
// used by Filaments tab to update preset list according to the particular extruder
void set_active_extruder(int extruder_idx) { m_active_extruder_idx = extruder_idx; }
};
} // namespace GUI

View File

@ -75,9 +75,9 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle
{
// Find out, to which nozzle index is the current filament profile assigned.
int idx_extruder = 0;
int num_extruders = (int)preset_bundle.filament_presets.size();
int num_extruders = (int)preset_bundle.extruders_filaments.size();
for (; idx_extruder < num_extruders; ++ idx_extruder)
if (preset_bundle.filament_presets[idx_extruder] == preset_bundle.filaments.get_selected_preset_name())
if (preset_bundle.extruders_filaments[idx_extruder].get_selected_preset_name() == preset_bundle.filaments.get_selected_preset_name())
break;
if (idx_extruder == num_extruders)
// The current filament preset is not active for any extruder.

View File

@ -1236,7 +1236,8 @@ void Tab::on_presets_changed()
m_dependent_tabs.clear();
// Update Project dirty state, update application title bar.
wxGetApp().plater()->update_project_dirty_from_presets();
if (wxGetApp().mainframe)
wxGetApp().plater()->update_project_dirty_from_presets();
}
void Tab::build_preset_description_line(ConfigOptionsGroup* optgroup)
@ -1933,8 +1934,64 @@ void TabFilament::update_filament_overrides_page()
}
}
void TabFilament::create_extruder_combobox()
{
m_extruders_cb = new BitmapComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(12 * m_em_unit, -1), 0, nullptr, wxCB_READONLY);
m_extruders_cb->Hide();
m_extruders_cb->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent&) {
set_active_extruder(m_extruders_cb->GetSelection());
});
m_h_buttons_sizer->AddSpacer(3*em_unit(this));
m_h_buttons_sizer->Add(m_extruders_cb, 0, wxALIGN_CENTER_VERTICAL);
}
void TabFilament::update_extruder_combobox()
{
const size_t extruder_cnt = static_cast<const ConfigOptionFloats*>(m_preset_bundle->printers.get_edited_preset().config.option("nozzle_diameter"))->values.size();
m_extruders_cb->Show(extruder_cnt > 1);
if (extruder_cnt != m_extruders_cb->GetCount()) {
m_extruders_cb->Clear();
for (size_t id = 1; id <= extruder_cnt; id++)
m_extruders_cb->Append(format_wxstr("%1% %2%", _L("Extruder"), id), *get_bmp_bundle("funnel"));
}
if (m_active_extruder >= int(extruder_cnt))
m_active_extruder = 0;
m_extruders_cb->SetSelection(m_active_extruder);
}
bool TabFilament::set_active_extruder(int new_selected_extruder)
{
if (m_active_extruder == new_selected_extruder)
return true;
const int old_extruder_id = m_active_extruder;
m_active_extruder = new_selected_extruder;
m_presets_choice->set_active_extruder(m_active_extruder);
if (!select_preset(m_preset_bundle->extruders_filaments[m_active_extruder].get_selected_preset_name())) {
m_active_extruder = old_extruder_id;
m_presets_choice->set_active_extruder(m_active_extruder);
m_extruders_cb->SetSelection(m_active_extruder);
return false;
}
if (m_active_extruder != m_extruders_cb->GetSelection())
m_extruders_cb->Select(m_active_extruder);
return true;
}
void TabFilament::build()
{
// add extruder combobox
create_extruder_combobox();
m_presets = &m_preset_bundle->filaments;
load_initial_data();
@ -2189,7 +2246,7 @@ void TabFilament::update()
m_update_cnt--;
if (m_update_cnt == 0)
if (m_update_cnt == 0 && wxGetApp().mainframe)
wxGetApp().mainframe->on_config_changed(m_config);
}
@ -2210,6 +2267,44 @@ void TabFilament::msw_rescale()
Tab::msw_rescale();
}
void TabFilament::load_current_preset()
{
assert(m_active_extruder >= 0 && m_active_extruder < m_preset_bundle->extruders_filaments.size());
const std::string& selected_extr_filament_name = m_preset_bundle->extruders_filaments[m_active_extruder].get_selected_preset_name();
const std::string& selected_filament_name = m_presets->get_selected_preset_name();
if (selected_extr_filament_name != selected_filament_name)
m_presets->select_preset_by_name(selected_extr_filament_name, false);
Tab::load_current_preset();
}
bool TabFilament::select_preset_by_name(const std::string &name_w_suffix, bool force)
{
const bool is_selected_filament = Tab::select_preset_by_name(name_w_suffix, force);
const bool is_selected_extr_filament = m_preset_bundle->extruders_filaments[m_active_extruder].select_filament(name_w_suffix, force);
return is_selected_filament && is_selected_extr_filament;
}
bool TabFilament::save_current_preset(const std::string &new_name, bool detach)
{
m_preset_bundle->cache_extruder_filaments_names();
const bool is_saved = Tab::save_current_preset(new_name, detach);
if (is_saved) {
m_preset_bundle->reset_extruder_filaments();
m_preset_bundle->extruders_filaments[m_active_extruder].select_filament(m_presets->get_idx_selected());
}
return is_saved;
}
bool TabFilament::delete_current_preset()
{
m_preset_bundle->cache_extruder_filaments_names();
const bool is_deleted = Tab::delete_current_preset();
if (is_deleted)
m_preset_bundle->reset_extruder_filaments();
return is_deleted;
}
wxSizer* Tab::description_line_widget(wxWindow* parent, ogStaticText* *StaticText, wxString text /*= wxEmptyString*/)
{
*StaticText = new ogStaticText(parent, text);
@ -2339,7 +2434,6 @@ void TabPrinter::build_fff()
const wxString msg_text = _(L("Single Extruder Multi Material is selected, \n"
"and all extruders must have the same diameter.\n"
"Do you want to change the diameter for all extruders to first extruder nozzle diameter value?"));
//wxMessageDialog dialog(parent(), msg_text, _(L("Nozzle diameter")), wxICON_WARNING | wxYES_NO);
MessageDialog dialog(parent(), msg_text, _(L("Nozzle diameter")), wxICON_WARNING | wxYES_NO);
DynamicPrintConfig new_conf = *m_config;
@ -2357,6 +2451,14 @@ void TabPrinter::build_fff()
}
}
}
m_preset_bundle->update_compatible(PresetSelectCompatibleType::Never);
// Upadte related comboboxes on Sidebar and Tabs
Sidebar& sidebar = wxGetApp().plater()->sidebar();
for (const Preset::Type& type : {Preset::TYPE_PRINT, Preset::TYPE_FILAMENT}) {
sidebar.update_presets(type);
wxGetApp().get_tab(type)->update_tab_ui();
}
}
}
else {
@ -2625,15 +2727,21 @@ void TabPrinter::build_sla()
void TabPrinter::extruders_count_changed(size_t extruders_count)
{
bool is_count_changed = false;
bool is_updated_mm_filament_presets = false;
if (m_extruders_count != extruders_count) {
m_extruders_count = extruders_count;
m_preset_bundle->printers.get_edited_preset().set_num_extruders(extruders_count);
m_preset_bundle->update_multi_material_filament_presets();
is_count_changed = true;
is_count_changed = is_updated_mm_filament_presets = true;
}
else if (m_extruders_count == 1 &&
m_preset_bundle->project_config.option<ConfigOptionFloats>("wiping_volumes_matrix")->values.size()>1)
m_preset_bundle->project_config.option<ConfigOptionFloats>("wiping_volumes_matrix")->values.size()>1) {
is_updated_mm_filament_presets = true;
}
if (is_updated_mm_filament_presets) {
m_preset_bundle->update_multi_material_filament_presets();
m_preset_bundle->update_filaments_compatible(PresetSelectCompatibleType::OnlyIfWasCompatible);
}
/* This function should be call in any case because of correct updating/rebuilding
* of unregular pages of a Printer Settings
@ -2768,7 +2876,10 @@ void TabPrinter::build_extruder_pages(size_t n_before_extruders)
optgroup->m_on_change = [this, extruder_idx](const t_config_option_key&opt_key, boost::any value)
{
if (m_config->opt_bool("single_extruder_multi_material") && m_extruders_count > 1 && opt_key.find_first_of("nozzle_diameter") != std::string::npos)
const bool is_single_extruder_MM = m_config->opt_bool("single_extruder_multi_material");
const bool is_nozzle_diameter_changed = opt_key.find_first_of("nozzle_diameter") != std::string::npos;
if (is_single_extruder_MM && m_extruders_count > 1 && is_nozzle_diameter_changed)
{
SuppressBackgroundProcessingUpdate sbpu;
const double new_nd = boost::any_cast<double>(value);
@ -2798,6 +2909,15 @@ void TabPrinter::build_extruder_pages(size_t n_before_extruders)
}
}
if (is_nozzle_diameter_changed) {
if (extruder_idx == 0)
// Mark the print & filament enabled if they are compatible with the currently selected preset.
// If saving the preset changes compatibility with other presets, keep the now incompatible dependent presets selected, however with a "red flag" icon showing that they are no more compatible.
m_preset_bundle->update_compatible(PresetSelectCompatibleType::Never);
else
m_preset_bundle->update_filaments_compatible(PresetSelectCompatibleType::Never, extruder_idx);
}
update_dirty();
update();
};
@ -3040,6 +3160,7 @@ void TabPrinter::update_pages()
if (m_extruders_count > 1)
{
m_preset_bundle->update_multi_material_filament_presets();
m_preset_bundle->update_filaments_compatible(PresetSelectCompatibleType::OnlyIfWasCompatible);
on_value_change("extruders_count", m_extruders_count);
}
}
@ -3392,7 +3513,7 @@ void Tab::update_preset_choice()
// Called by the UI combo box when the user switches profiles, and also to delete the current profile.
// Select a preset by a name.If !defined(name), then the default preset is selected.
// If the current profile is modified, user is asked to save the changes.
void Tab::select_preset(std::string preset_name, bool delete_current /*=false*/, const std::string& last_selected_ph_printer_name/* =""*/)
bool Tab::select_preset(std::string preset_name, bool delete_current /*=false*/, const std::string& last_selected_ph_printer_name/* =""*/)
{
if (preset_name.empty()) {
if (delete_current) {
@ -3492,7 +3613,8 @@ void Tab::select_preset(std::string preset_name, bool delete_current /*=false*/,
// It does not matter which preset will be made active as the preset will be re-selected from the preset_name variable.
// The 'external' presets will only be removed from the preset list, their files will not be deleted.
try {
m_presets->delete_current_preset();
// cache previously selected names
delete_current_preset();
} catch (const std::exception & /* e */) {
//FIXME add some error reporting!
canceled = true;
@ -3513,7 +3635,7 @@ void Tab::select_preset(std::string preset_name, bool delete_current /*=false*/,
}
}
update_tab_ui();
// update_tab_ui(); //! ysFIXME delete after testing
// Trigger the on_presets_changed event so that we also restore the previous value in the plater selector,
// if this action was initiated from the plater.
@ -3522,7 +3644,7 @@ void Tab::select_preset(std::string preset_name, bool delete_current /*=false*/,
if (current_dirty)
m_presets->discard_current_changes();
const bool is_selected = m_presets->select_preset_by_name(preset_name, false) || delete_current;
const bool is_selected = select_preset_by_name(preset_name, false) || delete_current;
assert(m_presets->get_edited_preset().name == preset_name || ! is_selected);
// Mark the print & filament enabled if they are compatible with the currently selected preset.
// The following method should not discard changes of current print or filament presets on change of a printer profile,
@ -3565,6 +3687,8 @@ void Tab::select_preset(std::string preset_name, bool delete_current /*=false*/,
if (technology_changed)
wxGetApp().mainframe->technology_changed();
return !canceled;
}
// If the current preset is dirty, the user is asked whether the changes may be discarded.
@ -3812,16 +3936,12 @@ void Tab::save_preset(std::string name /*= ""*/, bool detach)
// focus currently.is there anything better than this ?
//! m_treectrl->OnSetFocus();
auto& old_preset = m_presets->get_edited_preset();
Preset& edited_preset = m_presets->get_edited_preset();
bool from_template = false;
std::string edited_printer;
if (m_type == Preset::TYPE_FILAMENT && old_preset.vendor && old_preset.vendor->templates_profile)
{
//TODO: is this really the best way to get "printer_model" option of currently edited printer?
edited_printer = wxGetApp().preset_bundle->printers.get_edited_preset().config.opt<ConfigOptionString>("printer_model")->serialize();
if (!edited_printer.empty())
from_template = true;
if (m_type == Preset::TYPE_FILAMENT && edited_preset.vendor && edited_preset.vendor->templates_profile) {
edited_printer = wxGetApp().preset_bundle->printers.get_edited_preset().config.opt_string("printer_model");
from_template = !edited_printer.empty();
}
if (name.empty()) {
@ -3836,24 +3956,21 @@ void Tab::save_preset(std::string name /*= ""*/, bool detach)
if (detach && m_type == Preset::TYPE_PRINTER)
m_config->opt_string("printer_model", true) = "";
// Update compatible printers
if (from_template && !edited_printer.empty()) {
std::string cond = edited_preset.compatible_printers_condition();
if (!cond.empty())
cond += " and ";
cond += "printer_model == \"" + edited_printer + "\"";
edited_preset.config.opt_string("compatible_printers_condition") = cond;
}
// Save the preset into Slic3r::data_dir / presets / section_name / preset_name.ini
m_presets->save_current_preset(name, detach);
save_current_preset(name, detach);
if (detach && m_type == Preset::TYPE_PRINTER)
wxGetApp().mainframe->on_config_changed(m_config);
// Update compatible printers
if (from_template && !edited_printer.empty()) {
auto& new_preset = m_presets->get_edited_preset();
std::string cond = new_preset.compatible_printers_condition();
if (!cond.empty())
cond += " and ";
cond += "printer_model == \""+edited_printer+"\"";
new_preset.config.set("compatible_printers_condition", cond);
new_preset.save();
m_presets->save_current_preset(name, detach);
load_current_preset();
}
// Mark the print & filament enabled if they are compatible with the currently selected preset.
// If saving the preset changes compatibility with other presets, keep the now incompatible dependent presets selected, however with a "red flag" icon showing that they are no more compatible.
@ -3980,7 +4097,7 @@ void Tab::rename_preset()
// sort presets after renaming
std::sort(m_presets->begin(), m_presets->end());
// update selection
m_presets->select_preset_by_name(new_name, true);
select_preset_by_name(new_name, true);
m_presets_choice->update();
on_presets_changed();
@ -4675,6 +4792,21 @@ void Tab::set_tooltips_text()
"Click to reset current value to the last saved preset."));
}
bool Tab::select_preset_by_name(const std::string &name_w_suffix, bool force)
{
return m_presets->select_preset_by_name(name_w_suffix, force);
}
bool Tab::save_current_preset(const std::string& new_name, bool detach)
{
return m_presets->save_current_preset(new_name, detach);
}
bool Tab::delete_current_preset()
{
return m_presets->delete_current_preset();
}
Page::Page(wxWindow* parent, const wxString& title, int iconID) :
m_parent(parent),
m_title(title),

View File

@ -307,12 +307,13 @@ public:
long style = wxBU_EXACTFIT | wxNO_BORDER);
void add_scaled_bitmap(wxWindow* parent, ScalableBitmap& btn, const std::string& icon_name);
void update_ui_items_related_on_parent_preset(const Preset* selected_preset_parent);
void load_current_preset();
virtual void load_current_preset();
void rebuild_page_tree();
void update_btns_enabling();
void update_preset_choice();
// Select a new preset, possibly delete the current one.
void select_preset(std::string preset_name = "", bool delete_current = false, const std::string& last_selected_ph_printer_name = "");
// return false, if action was canceled
bool select_preset(std::string preset_name = "", bool delete_current = false, const std::string& last_selected_ph_printer_name = "");
bool may_discard_current_dirty_preset(PresetCollection* presets = nullptr, const std::string& new_printer_name = "");
virtual void clear_pages();
@ -402,6 +403,10 @@ protected:
void fill_icon_descriptions();
void set_tooltips_text();
virtual bool select_preset_by_name(const std::string& name_w_suffix, bool force);
virtual bool save_current_preset(const std::string& new_name, bool detach);
virtual bool delete_current_preset();
ConfigManipulation m_config_manipulation;
ConfigManipulation get_config_manipulation();
};
@ -432,7 +437,8 @@ private:
class TabFilament : public Tab
{
private:
BitmapComboBox* m_extruders_cb {nullptr};
int m_active_extruder {0};
ogStaticText* m_volumetric_speed_description_line {nullptr};
ogStaticText* m_cooling_description_line {nullptr};
@ -440,6 +446,7 @@ private:
void update_line_with_near_label_widget(ConfigOptionsGroupShp optgroup, const std::string &opt_key, int opt_index = 0, bool is_checked = true);
void add_filament_overrides_page();
void update_filament_overrides_page();
void create_extruder_combobox();
void update_volumetric_flow_preset_hints();
std::map<std::string, wxCheckBox*> m_overrides_options;
@ -455,6 +462,18 @@ public:
void clear_pages() override;
void msw_rescale() override;
bool supports_printer_technology(const PrinterTechnology tech) const override { return tech == ptFFF; }
void load_current_preset() override;
// set actiev extruder and update preset combobox if needed
// return false, if new preset wasn't selected
bool set_active_extruder(int new_selected_extruder);
void update_extruder_combobox();
int get_active_extruder() const { return m_active_extruder; }
protected:
bool select_preset_by_name(const std::string& name_w_suffix, bool force) override;
bool save_current_preset(const std::string& new_name, bool detach) override;
bool delete_current_preset() override;
};
class TabPrinter : public Tab