diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index e1973049f..269684454 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -754,7 +754,7 @@ Tab* GUI_App::get_tab(Preset::Type type) { for (Tab* tab: tabs_list) if (tab->type() == type) - return tab->complited() ? tab : nullptr; // To avoid actions with no-completed Tab + return tab->completed() ? tab : nullptr; // To avoid actions with no-completed Tab return nullptr; } diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index f5f554830..efb0dd0f9 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -3413,7 +3413,7 @@ bool ObjectList::check_last_selection(wxString& msg_str) (type & itInstance && !(m_selection_mode & smInstance)) ) { - // Inform user why selection isn't complited + // Inform user why selection isn't completed const wxString item_type = m_selection_mode & smInstance ? _(L("Object or Instance")) : m_selection_mode & smVolume ? _(L("Part")) : _(L("Layer")); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 704284d4a..fbc8778e4 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -262,6 +262,11 @@ PresetBitmapComboBox(parent, wxSize(15 * wxGetApp().em_unit(), -1)), m_em_unit(wxGetApp().em_unit()) { SetFont(wxGetApp().normal_font()); +#ifdef _WIN32 + // Workaround for ignoring CBN_EDITCHANGE events, which are processed after the content of the combo box changes, so that + // the index of the item inside CBN_EDITCHANGE may no more be valid. + EnableTextChangedEvents(false); +#endif /* _WIN32 */ Bind(wxEVT_COMBOBOX, [this](wxCommandEvent &evt) { auto selected_item = this->GetSelection(); diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index 94761a52a..252b39d14 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -313,9 +313,9 @@ std::string Preset::label() const return this->name + (this->is_dirty ? g_suffix_modified : ""); } -bool is_compatible_with_print(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_print) +bool is_compatible_with_print(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_print, const PresetWithVendorProfile &active_printer) { - if (preset.vendor != nullptr && preset.vendor != active_print.vendor) + if (preset.vendor != nullptr && preset.vendor != active_printer.vendor) // The current profile has a vendor assigned and it is different from the active print's vendor. return false; auto &condition = preset.preset.compatible_prints_condition(); @@ -1042,7 +1042,7 @@ void PresetCollection::set_default_suppressed(bool default_suppressed) } } -size_t PresetCollection::update_compatible_internal(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, bool unselect_if_incompatible) +size_t PresetCollection::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)); @@ -1054,10 +1054,12 @@ size_t PresetCollection::update_compatible_internal(const PresetWithVendorProfil Preset &preset_selected = m_presets[idx_preset]; Preset &preset_edited = selected ? m_edited_preset : preset_selected; const PresetWithVendorProfile this_preset_with_vendor_profile = this->get_preset_with_vendor_profile(preset_edited); + bool was_compatible = preset_edited.is_compatible; preset_edited.is_compatible = is_compatible_with_printer(this_preset_with_vendor_profile, active_printer, &config); if (active_print != nullptr) - preset_edited.is_compatible &= is_compatible_with_print(this_preset_with_vendor_profile, *active_print); - if (! preset_edited.is_compatible && selected && unselect_if_incompatible) + preset_edited.is_compatible &= is_compatible_with_print(this_preset_with_vendor_profile, *active_print, active_printer); + if (! preset_edited.is_compatible && selected && + (unselect_if_incompatible == PresetSelectCompatibleType::Always || (unselect_if_incompatible == PresetSelectCompatibleType::OnlyIfWasCompatible && was_compatible))) m_idx_selected = -1; if (selected) preset_selected.is_compatible = preset_edited.is_compatible; diff --git a/src/slic3r/GUI/Preset.hpp b/src/slic3r/GUI/Preset.hpp index 83970419c..46008eadb 100644 --- a/src/slic3r/GUI/Preset.hpp +++ b/src/slic3r/GUI/Preset.hpp @@ -247,10 +247,19 @@ protected: static std::string remove_suffix_modified(const std::string &name); }; -bool is_compatible_with_print (const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_print); +bool is_compatible_with_print (const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_print, const PresetWithVendorProfile &active_printer); bool is_compatible_with_printer(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_printer, const DynamicPrintConfig *extra_config); bool is_compatible_with_printer(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_printer); +enum class PresetSelectCompatibleType { + // Never select a compatible preset if the newly selected profile is not compatible. + Never, + // Only select a compatible preset if the active profile used to be compatible, but it is no more. + OnlyIfWasCompatible, + // Always select a compatible preset if the active profile is no more compatible. + Always +}; + // Collections of presets of the same type (one of the Print, Filament or Printer type). class PresetCollection { @@ -412,13 +421,13 @@ public: // For Print / Filament presets, disable those, which are not compatible with the printer. template - void update_compatible(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, bool select_other_if_incompatible, PreferedCondition prefered_condition) + 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_preset(this->first_compatible_idx(prefered_condition)); } - void update_compatible(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, bool select_other_if_incompatible) + 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 std::string&){return true;}); } size_t num_visible() const { return std::count_if(m_presets.begin(), m_presets.end(), [](const Preset &preset){return preset.is_visible;}); } @@ -515,7 +524,7 @@ private: std::deque::const_iterator find_preset_renamed(const std::string &name) const { return const_cast(this)->find_preset_renamed(name); } - size_t update_compatible_internal(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, bool unselect_if_incompatible); + size_t update_compatible_internal(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, PresetSelectCompatibleType unselect_if_incompatible); static std::vector dirty_options(const Preset *edited, const Preset *reference, const bool is_printer_type = false); diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index ebfe6e40e..70857e648 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -238,7 +238,7 @@ void PresetBundle::load_presets(AppConfig &config, const std::string &preferred_ errors_cummulative += err.what(); } this->update_multi_material_filament_presets(); - this->update_compatible(false); + this->update_compatible(PresetSelectCompatibleType::Never); if (! errors_cummulative.empty()) throw std::runtime_error(errors_cummulative); @@ -424,7 +424,7 @@ void PresetBundle::load_selections(AppConfig &config, const std::string &preferr // or from the preferred_model_id suggestion passed in by ConfigWizard. // If the printer profile enumerated by the config are not visible, select an alternate preset. // Do not select alternate profiles for the print / filament profiles as those presets - // will be selected by the following call of this->update_compatible(true). + // will be selected by the following call of this->update_compatible(PresetSelectCompatibleType::Always). const Preset *initial_printer = printers.find_preset(initial_printer_profile_name); const Preset *preferred_printer = printers.find_by_model_id(preferred_model_id); @@ -457,7 +457,7 @@ void PresetBundle::load_selections(AppConfig &config, const std::string &preferr // 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(true); + this->update_compatible(PresetSelectCompatibleType::Always); this->update_multi_material_filament_presets(); } @@ -889,7 +889,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool default: break; } - this->update_compatible(false); + this->update_compatible(PresetSelectCompatibleType::Never); } // Load the active configuration of a config bundle from a boost property_tree. This is a private method called from load_config_file. @@ -951,7 +951,7 @@ void PresetBundle::load_config_file_config_bundle(const std::string &path, const 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); - this->update_compatible(false); + this->update_compatible(PresetSelectCompatibleType::Never); } // Process the Config Bundle loaded as a Boost property tree. @@ -1351,7 +1351,7 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla 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; - this->update_compatible(false); + this->update_compatible(PresetSelectCompatibleType::Never); } return presets_loaded; @@ -1399,7 +1399,7 @@ void PresetBundle::update_multi_material_filament_presets() } } -void PresetBundle::update_compatible(bool select_other_if_incompatible) +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(); const PresetWithVendorProfile printer_preset_with_vendor_profile = this->printers.get_preset_with_vendor_profile(printer_preset); @@ -1412,25 +1412,32 @@ void PresetBundle::update_compatible(bool select_other_if_incompatible) const std::string &prefered_print_profile = printer_preset.config.opt_string("default_print_profile"); const std::vector &prefered_filament_profiles = printer_preset.config.option("default_filament_profile")->values; prefered_print_profile.empty() ? - this->prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_if_incompatible) : - this->prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_if_incompatible, + this->prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_print_if_incompatible) : + this->prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_print_if_incompatible, [&prefered_print_profile](const std::string& profile_name) { return profile_name == prefered_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 filament_preset_was_compatible(this->filament_presets.size(), false); + 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); + filament_preset_was_compatible[idx] = preset != nullptr && preset->is_compatible; + } prefered_filament_profiles.empty() ? - this->filaments.update_compatible(printer_preset_with_vendor_profile, &print_preset_with_vendor_profile, select_other_if_incompatible) : - this->filaments.update_compatible(printer_preset_with_vendor_profile, &print_preset_with_vendor_profile, select_other_if_incompatible, + this->filaments.update_compatible(printer_preset_with_vendor_profile, &print_preset_with_vendor_profile, select_other_filament_if_incompatible) : + this->filaments.update_compatible(printer_preset_with_vendor_profile, &print_preset_with_vendor_profile, select_other_filament_if_incompatible, [&prefered_filament_profiles](const std::string& profile_name) { return std::find(prefered_filament_profiles.begin(), prefered_filament_profiles.end(), profile_name) != prefered_filament_profiles.end(); }); - if (select_other_if_incompatible) { + if (select_other_filament_if_incompatible != PresetSelectCompatibleType::Never) { // Verify validity of the current filament presets. - if (this->filament_presets.size() == 1) - this->filament_presets.front() = this->filaments.get_edited_preset().name; - else - { - for (size_t idx = 0; idx < this->filament_presets.size(); ++idx) { + if (this->filament_presets.size() == 1) { + 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) { + 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. if (prefered_filament_profiles.empty()) filament_name = this->filaments.first_compatible().name; @@ -1453,13 +1460,13 @@ void PresetBundle::update_compatible(bool select_other_if_incompatible) const PresetWithVendorProfile sla_print_preset_with_vendor_profile = this->sla_prints.get_edited_preset_with_vendor_profile(); const std::string &prefered_sla_print_profile = printer_preset.config.opt_string("default_sla_print_profile"); (prefered_sla_print_profile.empty()) ? - this->sla_prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_if_incompatible) : - this->sla_prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_if_incompatible, + this->sla_prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_print_if_incompatible) : + this->sla_prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_print_if_incompatible, [&prefered_sla_print_profile](const std::string& profile_name){ return profile_name == prefered_sla_print_profile; }); const std::string &prefered_sla_material_profile = printer_preset.config.opt_string("default_sla_material_profile"); prefered_sla_material_profile.empty() ? - this->sla_materials.update_compatible(printer_preset_with_vendor_profile, &sla_print_preset_with_vendor_profile, select_other_if_incompatible) : - this->sla_materials.update_compatible(printer_preset_with_vendor_profile, &sla_print_preset_with_vendor_profile, select_other_if_incompatible, + this->sla_materials.update_compatible(printer_preset_with_vendor_profile, &sla_print_preset_with_vendor_profile, select_other_filament_if_incompatible) : + this->sla_materials.update_compatible(printer_preset_with_vendor_profile, &sla_print_preset_with_vendor_profile, select_other_filament_if_incompatible, [&prefered_sla_material_profile](const std::string& profile_name){ return profile_name == prefered_sla_material_profile; }); break; } diff --git a/src/slic3r/GUI/PresetBundle.hpp b/src/slic3r/GUI/PresetBundle.hpp index b81810733..33c9d5ff4 100644 --- a/src/slic3r/GUI/PresetBundle.hpp +++ b/src/slic3r/GUI/PresetBundle.hpp @@ -127,7 +127,8 @@ public: // Also updates the is_visible flag of each preset. // If select_other_if_incompatible is true, then the print or filament preset is switched to some compatible // preset if the current print or filament preset is not compatible. - void update_compatible(bool select_other_if_incompatible); + void update_compatible(PresetSelectCompatibleType select_other_print_if_incompatible, PresetSelectCompatibleType select_other_filament_if_incompatible); + void update_compatible(PresetSelectCompatibleType select_other_if_incompatible) { this->update_compatible(select_other_if_incompatible, select_other_if_incompatible); } void load_default_preset_bitmaps(); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index fefc8e113..19d085420 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -38,8 +38,6 @@ namespace GUI { wxDEFINE_EVENT(EVT_TAB_VALUE_CHANGED, wxCommandEvent); wxDEFINE_EVENT(EVT_TAB_PRESETS_CHANGED, SimpleEvent); -// Tab::Tab(wxNotebook* parent, const wxString& title, const char* name) : -// m_parent(parent), m_title(title), m_name(name) Tab::Tab(wxNotebook* parent, const wxString& title, Preset::Type type) : m_parent(parent), m_title(title), m_type(type) { @@ -264,7 +262,7 @@ void Tab::create_preset_tab() // Initialize the DynamicPrintConfig by default keys/values. build(); rebuild_page_tree(); - m_complited = true; + m_completed = true; } void Tab::add_scaled_button(wxWindow* parent, @@ -833,7 +831,7 @@ void Tab::load_key_value(const std::string& opt_key, const boost::any& value, bo // Mark the print & filament enabled if they are compatible with the currently selected preset. if (opt_key == "compatible_printers" || opt_key == "compatible_prints") { // Don't select another profile if this profile happens to become incompatible. - m_preset_bundle->update_compatible(false); + m_preset_bundle->update_compatible(PresetSelectCompatibleType::Never); } m_presets->update_dirty_ui(m_presets_choice); on_presets_changed(); @@ -2778,6 +2776,7 @@ void Tab::select_preset(std::string preset_name, bool delete_current) bool print_tab = m_presets->type() == Preset::TYPE_PRINT || m_presets->type() == Preset::TYPE_SLA_PRINT; bool printer_tab = m_presets->type() == Preset::TYPE_PRINTER; bool canceled = false; + bool technology_changed = false; m_dependent_tabs = {}; if (current_dirty && ! may_discard_current_dirty_preset()) { canceled = true; @@ -2786,10 +2785,12 @@ void Tab::select_preset(std::string preset_name, bool delete_current) // are compatible with the new print. // If it is not compatible and the current filament or SLA material are dirty, let user decide // whether to discard the changes or keep the current print selection. - PrinterTechnology printer_technology = m_preset_bundle->printers.get_edited_preset().printer_technology(); + PresetWithVendorProfile printer_profile = m_preset_bundle->printers.get_edited_preset_with_vendor_profile(); + PrinterTechnology printer_technology = printer_profile.preset.printer_technology(); PresetCollection &dependent = (printer_technology == ptFFF) ? m_preset_bundle->filaments : m_preset_bundle->sla_materials; bool old_preset_dirty = dependent.current_is_dirty(); - bool new_preset_compatible = is_compatible_with_print(dependent.get_edited_preset_with_vendor_profile(), m_presets->get_preset_with_vendor_profile(*m_presets->find_preset(preset_name, true))); + bool new_preset_compatible = is_compatible_with_print(dependent.get_edited_preset_with_vendor_profile(), + m_presets->get_preset_with_vendor_profile(*m_presets->find_preset(preset_name, true)), printer_profile); if (! canceled) canceled = old_preset_dirty && ! new_preset_compatible && ! may_discard_current_dirty_preset(&dependent, preset_name); if (! canceled) { @@ -2842,6 +2843,8 @@ void Tab::select_preset(std::string preset_name, bool delete_current) } } } + if (! canceled) + technology_changed = old_printer_technology != new_printer_technology; } if (! canceled && delete_current) { @@ -2870,8 +2873,15 @@ void Tab::select_preset(std::string preset_name, bool delete_current) // 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, // if they are compatible with the current printer. + auto update_compatible_type = [](bool technology_changed, bool on_page, bool show_incompatible_presets) { + return technology_changed ? PresetSelectCompatibleType::Always : + on_page ? PresetSelectCompatibleType::Never : + (show_incompatible_presets ? PresetSelectCompatibleType::OnlyIfWasCompatible : PresetSelectCompatibleType::Always); + }; if (current_dirty || delete_current || print_tab || printer_tab) - m_preset_bundle->update_compatible(true); + m_preset_bundle->update_compatible( + update_compatible_type(technology_changed, print_tab, (print_tab ? this : wxGetApp().get_tab(Preset::TYPE_PRINT))->m_show_incompatible_presets), + update_compatible_type(technology_changed, false, wxGetApp().get_tab(Preset::TYPE_FILAMENT)->m_show_incompatible_presets)); // Initialize the UI from the current preset. if (printer_tab) static_cast(this)->update_pages(); @@ -3084,7 +3094,7 @@ void Tab::save_preset(std::string name /*= ""*/) // Save the preset into Slic3r::data_dir / presets / section_name / preset_name.ini m_presets->save_current_preset(name); // Mark the print & filament enabled if they are compatible with the currently selected preset. - m_preset_bundle->update_compatible(false); + m_preset_bundle->update_compatible(PresetSelectCompatibleType::Never); // Add the new item into the UI component, remove dirty flags and activate the saved item. update_tab_ui(); // Update the selection boxes at the plater. diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 09662bf81..c3016fa04 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -218,7 +218,7 @@ protected: int m_em_unit; // To avoid actions with no-completed Tab - bool m_complited { false }; + bool m_completed { false }; ConfigOptionMode m_mode = comExpert; // to correct first Tab update_visibility() set mode to Expert public: @@ -244,7 +244,8 @@ public: // std::string name() const { return m_name; } std::string name() const { return m_presets->name(); } Preset::Type type() const { return m_type; } - bool complited() const { return m_complited; } + // The tab is already constructed. + bool completed() const { return m_completed; } virtual bool supports_printer_technology(const PrinterTechnology tech) = 0; void create_preset_tab();