From 1241dd552189d90b12e749cc4b90fc623940ab05 Mon Sep 17 00:00:00 2001 From: Kiss Lorand <50251547+kisslorand@users.noreply.github.com> Date: Sat, 3 Oct 2026 03:02:36 +0300 Subject: [PATCH] Fix per-plate bed type handling (#15916) --- src/slic3r/GUI/GUI_App.cpp | 4 +- src/slic3r/GUI/MainFrame.cpp | 2 + src/slic3r/GUI/ParamsDialog.cpp | 23 ++++++++++- src/slic3r/GUI/ParamsDialog.hpp | 1 + src/slic3r/GUI/PlateSettingsDialog.cpp | 5 ++- src/slic3r/GUI/Plater.cpp | 54 ++++++++++++++++++++++++-- src/slic3r/GUI/Plater.hpp | 1 + src/slic3r/GUI/Tab.cpp | 15 +++++++ src/slic3r/GUI/WebGuideDialog.cpp | 3 ++ 9 files changed, 101 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 6bd0797ac9..94ef20e9fd 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -6735,8 +6735,10 @@ void GUI_App::reload_settings() tab->reload_config(); tab->update_changed_ui(); } - if (plater_) + if (plater_) { plater_->sidebar().update_all_preset_comboboxes(); + plater_->normalize_bed_types(false); + } }; if (is_main_thread_active()) refresh_synced_ui(); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 53507edfb3..07d51f9f0c 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -3870,6 +3870,8 @@ bool MainFrame::load_config_file(const std::string &path) return false; } wxGetApp().load_current_presets(); + if (Plater *plater = wxGetApp().plater()) + plater->normalize_bed_types(false); return true; } diff --git a/src/slic3r/GUI/ParamsDialog.cpp b/src/slic3r/GUI/ParamsDialog.cpp index 87888848a6..008f71d6d1 100644 --- a/src/slic3r/GUI/ParamsDialog.cpp +++ b/src/slic3r/GUI/ParamsDialog.cpp @@ -3,6 +3,7 @@ #include "ParamsPanel.hpp" #include "GUI_App.hpp" #include "MainFrame.hpp" +#include "Plater.hpp" #include "Tab.hpp" #include "libslic3r/Utils.hpp" @@ -70,6 +71,18 @@ ParamsDialog::ParamsDialog(wxWindow * parent) } Hide(); + if (tab && tab->type() == Preset::TYPE_PRINTER) { + // Normalize only after the dialog closes, when the final capability is known. + auto &preset_bundle = *wxGetApp().preset_bundle; + const bool supports_multiple_bed_types = preset_bundle.is_bbl_vendor() || + preset_bundle.printers.get_edited_preset().config.opt_bool("support_multi_bed_types"); + if (m_initial_multi_bed_types != supports_multiple_bed_types) { + wxGetApp().plater()->normalize_bed_types(true); + if (auto *plate_tab = dynamic_cast(wxGetApp().get_plate_tab())) + plate_tab->update_model_config(); + } + } + if (!m_editing_filament_id.empty()) { Filamentinformation *filament_info = new Filamentinformation(); filament_info->filament_id = m_editing_filament_id; @@ -93,7 +106,15 @@ void ParamsDialog::Popup() if (m_panel && m_panel->get_current_tab()) { bool just_edit = false; if (!m_editing_filament_id.empty()) just_edit = true; - dynamic_cast(m_panel->get_current_tab())->set_just_edit(just_edit); + auto *tab = dynamic_cast(m_panel->get_current_tab()); + tab->set_just_edit(just_edit); + if (tab->type() == Preset::TYPE_PRINTER) { + // Remember the initial capability and compare it when the dialog closes. + // Bambu profiles support multiple bed types even when this option is unset. + auto &preset_bundle = *wxGetApp().preset_bundle; + m_initial_multi_bed_types = preset_bundle.is_bbl_vendor() || + preset_bundle.printers.get_edited_preset().config.opt_bool("support_multi_bed_types"); + } } Show(); } diff --git a/src/slic3r/GUI/ParamsDialog.hpp b/src/slic3r/GUI/ParamsDialog.hpp index 9ad34e165e..80c9c3d2fe 100644 --- a/src/slic3r/GUI/ParamsDialog.hpp +++ b/src/slic3r/GUI/ParamsDialog.hpp @@ -43,6 +43,7 @@ protected: private: std::string m_editing_filament_id; + bool m_initial_multi_bed_types = false; ParamsPanel * m_panel; wxWindowDisabler *m_winDisabler = nullptr; }; diff --git a/src/slic3r/GUI/PlateSettingsDialog.cpp b/src/slic3r/GUI/PlateSettingsDialog.cpp index b640b2cb84..31b8367774 100644 --- a/src/slic3r/GUI/PlateSettingsDialog.cpp +++ b/src/slic3r/GUI/PlateSettingsDialog.cpp @@ -431,8 +431,9 @@ PlateSettingsDialog::PlateSettingsDialog(wxWindow* parent, const wxString& title } } - if (!wxGetApp().preset_bundle->is_bbl_vendor()) - m_bed_type_choice->Disable(); + auto &preset_bundle = *wxGetApp().preset_bundle; + const auto &printer_config = preset_bundle.printers.get_edited_preset().config; + m_bed_type_choice->Enable(preset_bundle.is_bbl_vendor() || printer_config.opt_bool("support_multi_bed_types")); wxStaticText* m_bed_type_txt = new wxStaticText(this, wxID_ANY, _L("Bed type")); m_bed_type_txt->SetFont(Label::Body_14); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 89616345eb..43a8b9a6a1 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -7401,7 +7401,8 @@ struct Plater::priv std::vector load_files(const std::vector& input_files, LoadStrategy strategy, bool ask_multi = false, - bool* published_out = nullptr); + bool* published_out = nullptr, + bool* config_loaded_out = nullptr); std::vector load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z = false, bool split_object = false, bool auto_drop = true); // Texture-to-color import: a mesh loaded with UVs + a texture map gets its faces clustered @@ -8872,8 +8873,12 @@ void read_binary_stl(const std::string& filename, std::string& model_id, std::st std::vector Plater::priv::load_files(const std::vector& input_files, LoadStrategy strategy, bool ask_multi, - bool* published_out) + bool* published_out, + bool* config_loaded_out) { + if (config_loaded_out != nullptr) + *config_loaded_out = false; + std::vector empty_result; bool dlg_cont = true; bool is_user_cancel = false; @@ -9558,6 +9563,8 @@ std::vector Plater::priv::load_files(const std::vector& input_ id = agent->to_orca_filament_id(id); } preset_bundle->load_config_model(filename.string(), std::move(config), file_version, &published_config); + if (config_loaded_out != nullptr) + *config_loaded_out = true; // Mixed-filament definitions that collided with one of the // receiver's real slots were relocated during the preset load. @@ -12780,6 +12787,8 @@ void Plater::priv::on_select_bed_type(wxCommandEvent &evt) // update plater with new config q->on_config_change(wxGetApp().preset_bundle->full_config()); + if (auto *plate_tab = dynamic_cast(wxGetApp().get_plate_tab())) + plate_tab->update_model_config(); // update app_config AppConfig* app_config = wxGetApp().app_config; @@ -15479,6 +15488,38 @@ void Plater::reset_project_dirty_initial_presets() { p->reset_project_dirty_init void Plater::render_project_state_debug_window() const { p->render_project_state_debug_window(); } #endif // ENABLE_PROJECT_DIRTY_STATE_DEBUG_WINDOW +void Plater::normalize_bed_types(bool printer_setting_changed) +{ + if (only_gcode_mode() || is_gcode_3mf()) + return; + + auto &preset_bundle = *wxGetApp().preset_bundle; + // Keep FFF plate settings intact while an SLA printer is selected. + if (preset_bundle.printers.get_edited_preset().printer_technology() != ptFFF) + return; + + const auto &printer_config = preset_bundle.printers.get_edited_preset().config; + + const bool supports_multiple_bed_types = + preset_bundle.is_bbl_vendor() || printer_config.opt_bool("support_multi_bed_types"); + // Clear local overrides for single-bed printers. + const bool overrides_reset = !supports_multiple_bed_types && + !p->partplate_list.check_all_plate_local_bed_type({}); + + if (overrides_reset) { + set_plater_dirty(true); + show_info(this, + _L("The selected printer does not support multiple bed types.\nBed type overrides were reset to the global bed type."), + _L("Plate bed types reset")); + } + + // Refresh the controls after a capability change, even when no override was reset. + if (printer_setting_changed || overrides_reset) { + sidebar().update_all_preset_comboboxes(); + wxGetApp().obj_list()->update_and_show_object_settings_item(); + } +} + std::vector Plater::mixed_filament_config_indices() const { std::vector indices; @@ -16059,6 +16100,9 @@ void Plater::load_project(wxString const& filename2, p->dirty_state.update_from_undo_redo_stack(true); up_to_date(true, true); + // Clear plate overrides that are incompatible with the selected printer. + normalize_bed_types(false); + wxGetApp().params_panel()->switch_to_object_if_has_object_configs(); auto has_modify = is_flush_config_modified(); @@ -17691,7 +17735,11 @@ std::vector Plater::load_files(const std::vector& input_files, p->m_slice_all_only_has_gcode = false; //BBS: wish to reset all plates stats item selected state when load a new file p->preview->get_canvas3d()->reset_select_plate_toolbar_selection(); - return p->load_files(input_files, strategy, ask_multi, published_out); + bool config_loaded = false; + std::vector result = p->load_files(input_files, strategy, ask_multi, published_out, &config_loaded); + if (config_loaded && !is_loading_project()) + normalize_bed_types(false); + return result; } bool Plater::preview_zip_archive(const boost::filesystem::path& archive_path) diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index a887805f8a..17534ebf7d 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -343,6 +343,7 @@ public: bool is_presets_dirty() const; void set_plater_dirty(bool is_dirty); void update_project_dirty_from_presets(); + void normalize_bed_types(bool printer_setting_changed); int save_project_if_dirty(const wxString& reason); void reset_project_dirty_after_save(); void reset_project_dirty_initial_presets(); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index c60566d5c7..3050830d56 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -87,6 +87,7 @@ #include "slic3r/plugin/PluginConfig.hpp" #include "slic3r/plugin/PluginManager.hpp" #include "Plater.hpp" +#include "ParamsDialog.hpp" #include "MainFrame.hpp" #include "format.hpp" #include "UnsavedChangesDialog.hpp" @@ -3302,6 +3303,11 @@ void TabPrint::toggle_options() m_config_manipulation.toggle_print_fff_options(m_config, int(intptr_t(m_extruder_switch->GetClientData())), m_type < Preset::TYPE_COUNT); + if (m_type == Preset::TYPE_PLATE) { + const auto &printer_config = m_preset_bundle->printers.get_edited_preset().config; + toggle_option("curr_bed_type", m_preset_bundle->is_bbl_vendor() || printer_config.opt_bool("support_multi_bed_types")); + } + Field *field = m_active_page->get_field("support_style"); auto support_type = m_config->opt_enum("support_type"); if (auto choice = dynamic_cast(field)) { @@ -7024,6 +7030,15 @@ bool Tab::select_preset( } load_current_preset(); + // Wait for the settings dialog to close; its edits are still provisional. + if (printer_tab && is_selected) { + Plater *plater = wxGetApp().plater(); + ParamsDialog *dialog = wxGetApp().params_dialog(); + if (plater && !plater->is_loading_project() && + (!dialog || !dialog->IsShown())) + plater->normalize_bed_types(false); + } + { Slic3r::LifecycleEventContext ctx; ctx.name = preset_name; diff --git a/src/slic3r/GUI/WebGuideDialog.cpp b/src/slic3r/GUI/WebGuideDialog.cpp index 4f1998ae94..350dd9d4be 100644 --- a/src/slic3r/GUI/WebGuideDialog.cpp +++ b/src/slic3r/GUI/WebGuideDialog.cpp @@ -71,6 +71,7 @@ #include #include "MainFrame.hpp" +#include "Plater.hpp" #include #include #include @@ -1161,6 +1162,8 @@ bool GuideFrame::run() app.app_config->set_legacy_datadir(false); app.update_mode(); + if (Plater *plater = app.plater()) + plater->normalize_bed_types(false); // BBS //app.obj_manipul()->update_ui_from_settings(); BOOST_LOG_TRIVIAL(info) << "GuideFrame applied";