From cad12e4b8a2bab4d461a7534e802929c705e93a6 Mon Sep 17 00:00:00 2001 From: Kiss Lorand <50251547+kisslorand@users.noreply.github.com> Date: Sun, 10 May 2026 10:14:35 +0300 Subject: [PATCH] Warn user for abnormal temperature differences for nozzle and bed (first layer vs other layers) (#12345) Warn for first and other layers big temperature delta Warn user if temperature differences (first layer vs other layers) for nozzle and plates are above a certain delta. Co-authored-by: SoftFever --- src/slic3r/GUI/ParamsDialog.cpp | 8 +++ src/slic3r/GUI/Tab.cpp | 105 +++++++++++++++++++++++++++++++- src/slic3r/GUI/Tab.hpp | 1 + 3 files changed, 113 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/ParamsDialog.cpp b/src/slic3r/GUI/ParamsDialog.cpp index 02d56298b0..740df52049 100644 --- a/src/slic3r/GUI/ParamsDialog.cpp +++ b/src/slic3r/GUI/ParamsDialog.cpp @@ -51,6 +51,14 @@ ParamsDialog::ParamsDialog(wxWindow * parent) Hide(); } #else + auto tab = dynamic_cast(m_panel->get_current_tab()); + // ORCA: Validate filament temperature pairs before closing the material settings dialog. + if (tab && !tab->validate_filament_temperature_pairs()) { + if (event.CanVeto()) + event.Veto(); + return; + } + Hide(); if (!m_editing_filament_id.empty()) { Filamentinformation *filament_info = new Filamentinformation(); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 025b9cf687..206a83eab5 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -61,7 +61,8 @@ #endif // WIN32 #include -#include +#include +#include namespace Slic3r { @@ -6430,6 +6431,10 @@ void Tab::transfer_options(const std::string &name_from, const std::string &name //BBS: add project embedded preset relate logic void Tab::save_preset(std::string name /*= ""*/, bool detach, bool save_to_project, bool from_input, std::string input_name ) { + // ORCA: Validate before opening any save-name UI for filament presets. + if (!validate_filament_temperature_pairs()) + return; + // since buttons(and choices too) don't get focus on Mac, we set focus manually // to the treectrl so that the EVT_* events are fired for the input field having // focus currently.is there anything better than this ? @@ -6984,6 +6989,104 @@ bool Tab::validate_custom_gcodes() return valid; } +// ORCA: Session-only suppression keys for temperature-pair safety warnings. +static std::unordered_set s_filament_temp_pair_warning_suppressed_for_session; + +// ORCA: Validate that first-layer and other-layer temperature pairs are within safety limits, and warn the user if not. +bool Tab::validate_filament_temperature_pairs() +{ + if (m_type != Preset::TYPE_FILAMENT || m_presets == nullptr) + return true; + + // Warn only for newly edited state, not for unchanged presets. + if (!m_presets->current_is_dirty()) + return true; + + Preset& edited_preset = m_presets->get_edited_preset(); + DynamicPrintConfig& config = edited_preset.config; + const std::string suppress_key = edited_preset.name; + // User opted out for this preset during current app session. + if (!suppress_key.empty() && s_filament_temp_pair_warning_suppressed_for_session.count(suppress_key) > 0) + return true; + + struct TempPairRule + { + wxString label; + std::string first_layer_key; + std::string other_layer_key; + int max_delta; + }; + + std::vector temp_pair_rules; + temp_pair_rules.push_back({_L("Nozzle"), "nozzle_temperature_initial_layer", "nozzle_temperature", 30}); + + // Derive bed labels/keys from curr_bed_type metadata (BedType order excludes btDefault). + if (const ConfigOptionDef* bed_type_def = print_config_def.get("curr_bed_type"); + bed_type_def != nullptr) { + for (int bt = static_cast(btPC); bt < static_cast(btCount); ++bt) { + const BedType bed_type = static_cast(bt); + const size_t label_idx = static_cast(bt - static_cast(btPC)); + const std::string first_key = get_bed_temp_1st_layer_key(bed_type); + const std::string other_key = get_bed_temp_key(bed_type); + if (first_key.empty() || other_key.empty()) + continue; + + wxString label = _(bed_type_def->enum_labels[label_idx]); + temp_pair_rules.push_back({label, first_key, other_key, 15}); + } + } + + wxString invalid_pairs; + int invalid_count = 0; + + for (const TempPairRule& rule : temp_pair_rules) { + if (!config.has(rule.first_layer_key) || !config.has(rule.other_layer_key)) + continue; + + const ConfigOptionInts* first_opt = config.option(rule.first_layer_key); + const ConfigOptionInts* other_opt = config.option(rule.other_layer_key); + if (first_opt == nullptr || other_opt == nullptr || first_opt->values.empty() || other_opt->values.empty()) + continue; + + const int first_temp = first_opt->get_at(0); + const int other_temp = other_opt->get_at(0); + + // Keep existing semantics: 0 means unsupported/off for these temperatures. + if (first_temp <= 0 || other_temp <= 0) + continue; + + const int delta = std::abs(first_temp - other_temp); + if (delta <= rule.max_delta) + continue; + + const wxString deg_c = wxString::FromUTF8("°C"); + const wxString bullet = wxString::FromUTF8("•"); + invalid_pairs += wxString::Format(_L(" - %s:\n %s first layer %d %s, other layers %d %s\n %s max delta %d %s, current delta %d %s\n"), + rule.label, bullet, first_temp, deg_c, other_temp, deg_c, bullet, rule.max_delta, deg_c, delta, deg_c); + ++invalid_count; + } + + if (invalid_count == 0) + return true; + + wxString msg_text = _L("Some first-layer and other-layer temperature pairs exceed safety limits.\n"); + msg_text += _L("\nInvalid pairs:\n"); + msg_text += invalid_pairs; + msg_text += _L("\nYou can go back to edit values, or continue if this is intentional."); + msg_text += _L("\n\nContinue anyway?"); + + RichMessageDialog dialog(parent(), msg_text, _L("Temperature Safety Check"), wxYES | wxNO | wxICON_WARNING); + dialog.SetButtonLabel(wxID_YES, _L("Continue"), true); + dialog.SetButtonLabel(wxID_NO, _L("Back")); + dialog.ShowCheckBox(_L("Don't warn again for this preset")); + const int answer = dialog.ShowModal(); + // Session-only suppression (does not modify/save filament preset data). + if (dialog.IsCheckBoxChecked() && !suppress_key.empty()) + s_filament_temp_pair_warning_suppressed_for_session.insert(suppress_key); + + return answer == wxID_YES; +} + void Tab::set_just_edit(bool just_edit) { m_just_edit = just_edit; diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 5a371fd245..e529ebaed0 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -419,6 +419,7 @@ public: static bool validate_custom_gcode(const wxString& title, const std::string& gcode); bool validate_custom_gcodes(); + bool validate_filament_temperature_pairs(); bool validate_custom_gcodes_was_shown{ false }; void set_just_edit(bool just_edit);