mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-14 03:11:19 +00:00
Merge upstream/main into belt/rebase/may-18
Reconciles the belt-printer branch with upstream PRs through #13723. Six files had conflicts; three additional files needed manual follow-up fixes where the auto-merge produced code that referenced upstream-renamed fields or changed function signatures. Notable reconciliations: - TreeSupport.cpp: kept belt-floor early-exit branches around HEAD's drop-down logic, folded upstream's `(distance_to_top > 0 ? 1 : 0)` formula into the non-belt-floor path (upstream PR #11812). Dropped dead `roof_enabled`/`force_tip_to_roof` locals. - TreeSupport3D.cpp: combined upstream's safety-offset + remove_small changes with HEAD's belt-floor clip in the per-slice trim loop. Dropped HEAD's `else` block (superseded by upstream's rewritten bottom-contact propagation) and re-added the belt-floor clip into the new propagation loop. Gated the propagation on belt printers to prevent OOM when belt-floor clipping produces empty initial slices. - TriangleSelector.{cpp,hpp}: merged both new `select_patch` parameters (HEAD's `up_direction` and upstream's `select_partially`); body uses `dot(up_direction)` for the overhang angle check and forwards `select_partially` to `select_triangle`. - SupportMaterial.cpp: `slicing_params.soluble_interface` → `zero_gap_interface_bottom` in HEAD's `detect_belt_floor_bottom_contacts`, matching upstream's same-purpose rename at line 2495. - Custom.json, GCodeWriter.cpp: simple additive merges (kept entries / includes from both sides). Verified by building OrcaSlicer (RelWithDebInfo) after a full deps rebuild (Eigen v5.0.1, libigl v2.6.0 are now managed deps) and slicing a scaled Benchy on the NORMALIZER belt-printer profile without OOM. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+286
-13
@@ -40,7 +40,7 @@
|
||||
#include "UnsavedChangesDialog.hpp"
|
||||
#include "SavePresetDialog.hpp"
|
||||
#include "EditGCodeDialog.hpp"
|
||||
|
||||
#include "MultiChoiceDialog.hpp"
|
||||
#include "MsgDialog.hpp"
|
||||
#include "Notebook.hpp"
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
#include "Widgets/Label.hpp"
|
||||
#include "Widgets/SwitchButton.hpp"
|
||||
#include "Widgets/TabCtrl.hpp"
|
||||
#include "Widgets/ComboBox.hpp"
|
||||
#include "MarkdownTip.hpp"
|
||||
#include "Search.hpp"
|
||||
#include "BedShapeDialog.hpp"
|
||||
@@ -61,7 +62,8 @@
|
||||
#endif // WIN32
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@@ -1493,6 +1495,11 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
|
||||
return;
|
||||
}
|
||||
|
||||
if (opt_key == "gcode_flavor" && m_type == Preset::TYPE_PRINTER) {
|
||||
if (auto printer_tab = dynamic_cast<TabPrinter*>(this))
|
||||
printer_tab->on_gcode_flavor_changed();
|
||||
}
|
||||
|
||||
if (opt_key == "compatible_prints")
|
||||
this->compatible_widget_reload(m_compatible_prints);
|
||||
if (opt_key == "compatible_printers")
|
||||
@@ -1547,8 +1554,7 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
|
||||
|
||||
|
||||
if (opt_key == "single_extruder_multi_material" ){
|
||||
const auto bSEMM = m_config->opt_bool("single_extruder_multi_material");
|
||||
wxGetApp().sidebar().show_SEMM_buttons(bSEMM);
|
||||
wxGetApp().sidebar().show_SEMM_buttons();
|
||||
wxGetApp().get_tab(Preset::TYPE_PRINT)->update();
|
||||
}
|
||||
|
||||
@@ -1599,8 +1605,7 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
|
||||
|
||||
|
||||
if (opt_key == "single_extruder_multi_material" ){
|
||||
const auto bSEMM = m_config->opt_bool("single_extruder_multi_material");
|
||||
wxGetApp().sidebar().show_SEMM_buttons(bSEMM);
|
||||
wxGetApp().sidebar().show_SEMM_buttons();
|
||||
wxGetApp().get_tab(Preset::TYPE_PRINT)->update();
|
||||
}
|
||||
|
||||
@@ -4958,16 +4963,32 @@ PageShp TabPrinter::build_kinematics_page()
|
||||
optgroup->append_single_option_line("emit_machine_limits_to_gcode", "printer_motion_ability#emit-limits-to-g-code");
|
||||
|
||||
// resonance avoidance ported over from qidi slicer
|
||||
optgroup = page->new_optgroup(L("Resonance Avoidance"), "param_resonance_avoidance");
|
||||
optgroup = page->new_optgroup(L("Resonance Compensation"), "param_resonance_avoidance");
|
||||
optgroup->append_single_option_line("resonance_avoidance", "printer_motion_ability#resonance-avoidance");
|
||||
// Resonance‑avoidance speed inputs
|
||||
{
|
||||
Line resonance_line = {L("Resonance Avoidance Speed"), L""};
|
||||
resonance_line.label_path = "printer_motion_ability#resonance-avoidance-speed";
|
||||
resonance_line.label_path = "printer_motion_ability#resonance-avoidance";
|
||||
resonance_line.append_option(optgroup->get_option("min_resonance_avoidance_speed"));
|
||||
resonance_line.append_option(optgroup->get_option("max_resonance_avoidance_speed"));
|
||||
optgroup->append_line(resonance_line);
|
||||
}
|
||||
optgroup->append_single_option_line("input_shaping_emit", "printer_motion_ability#input-shaping");
|
||||
optgroup->append_single_option_line("input_shaping_type", "printer_motion_ability#input-shaping-type");
|
||||
{
|
||||
Line freq_line = {L("Frequency"), L("The frequency of the anti-vibration signal will correspond to the natural frequency of the frame.")};
|
||||
freq_line.label_path = "printer_motion_ability#input-shaping";
|
||||
freq_line.append_option(optgroup->get_option("input_shaping_freq_x"));
|
||||
freq_line.append_option(optgroup->get_option("input_shaping_freq_y"));
|
||||
optgroup->append_line(freq_line);
|
||||
}
|
||||
{
|
||||
Line damping_line = {L("Damping"), L("Damping ratio for the input shaping filter.")};
|
||||
damping_line.label_path = "printer_motion_ability#input-shaping";
|
||||
damping_line.append_option(optgroup->get_option("input_shaping_damp_x"));
|
||||
damping_line.append_option(optgroup->get_option("input_shaping_damp_y"));
|
||||
optgroup->append_line(damping_line);
|
||||
}
|
||||
|
||||
const std::vector<std::string> speed_axes{
|
||||
"machine_max_speed_x",
|
||||
@@ -5013,7 +5034,7 @@ void TabPrinter::build_unregular_pages(bool from_initial_build/* = false*/)
|
||||
{
|
||||
size_t n_before_extruders = 2; // Count of pages before Extruder pages
|
||||
auto flavor = m_config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor")->value;
|
||||
bool is_marlin_flavor = (flavor == gcfMarlinLegacy || flavor == gcfMarlinFirmware || flavor == gcfKlipper || flavor == gcfRepRapFirmware);
|
||||
bool is_marlin_flavor = (flavor == gcfMarlinLegacy || flavor == gcfMarlinFirmware || flavor == gcfKlipper || flavor == gcfRepRapFirmware || flavor == gcfRepetier);
|
||||
|
||||
/* ! Freeze/Thaw in this function is needed to avoid call OnPaint() for erased pages
|
||||
* and be cause of application crash, when try to change Preset in moment,
|
||||
@@ -5138,6 +5159,7 @@ if (is_marlin_flavor)
|
||||
optgroup->append_single_option_line("wipe_tower_type", "printer_multimaterial_wipe_tower");
|
||||
optgroup->append_single_option_line("purge_in_prime_tower", "printer_multimaterial_wipe_tower#purge-in-prime-tower");
|
||||
optgroup->append_single_option_line("enable_filament_ramming", "printer_multimaterial_wipe_tower#enable-filament-ramming");
|
||||
optgroup->append_single_option_line("tool_change_on_wipe_tower", "printer_multimaterial_wipe_tower#tool-change-on-wipe-tower");
|
||||
|
||||
|
||||
optgroup = page->new_optgroup(L("Single extruder multi-material parameters"), "param_settings");
|
||||
@@ -5410,6 +5432,115 @@ void TabPrinter::clear_pages()
|
||||
m_reset_to_filament_color = nullptr;
|
||||
}
|
||||
|
||||
std::vector<InputShaperType> input_shaper_types_for_flavor(GCodeFlavor flavor)
|
||||
{
|
||||
switch (flavor) {
|
||||
case GCodeFlavor::gcfKlipper:
|
||||
return {
|
||||
InputShaperType::Default,
|
||||
InputShaperType::ZV,
|
||||
InputShaperType::MZV,
|
||||
InputShaperType::ZVD,
|
||||
InputShaperType::EI,
|
||||
InputShaperType::TwoHumpEI,
|
||||
InputShaperType::ThreeHumpEI,
|
||||
InputShaperType::Disable
|
||||
};
|
||||
case GCodeFlavor::gcfRepRapFirmware:
|
||||
return {
|
||||
InputShaperType::Default,
|
||||
InputShaperType::MZV,
|
||||
InputShaperType::ZVD,
|
||||
InputShaperType::ZVDD,
|
||||
InputShaperType::ZVDDD,
|
||||
InputShaperType::EI2,
|
||||
InputShaperType::EI3,
|
||||
InputShaperType::DAA,
|
||||
InputShaperType::Disable
|
||||
};
|
||||
case GCodeFlavor::gcfMarlinFirmware:
|
||||
return {
|
||||
InputShaperType::ZV,
|
||||
InputShaperType::Disable
|
||||
};
|
||||
default:
|
||||
return {
|
||||
InputShaperType::Default,
|
||||
InputShaperType::Disable
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void TabPrinter::update_input_shaper_menu(GCodeFlavor flavor)
|
||||
{
|
||||
if (m_presets->get_edited_preset().printer_technology() != ptFFF)
|
||||
return;
|
||||
|
||||
const std::vector<InputShaperType> allowed = input_shaper_types_for_flavor(flavor);
|
||||
if (allowed.empty())
|
||||
return;
|
||||
|
||||
const InputShaperType current = m_config->opt_enum<InputShaperType>("input_shaping_type");
|
||||
const bool needs_reset = std::find(allowed.begin(), allowed.end(), current) == allowed.end();
|
||||
const InputShaperType desired = needs_reset ? allowed.front() : current;
|
||||
|
||||
if (needs_reset && current != desired) {
|
||||
DynamicPrintConfig new_conf = *m_config;
|
||||
new_conf.set_key_value("input_shaping_type", new ConfigOptionEnum<InputShaperType>(desired));
|
||||
m_config_manipulation.apply(m_config, &new_conf);
|
||||
}
|
||||
|
||||
Page* owning_page = nullptr;
|
||||
Field* field = get_field("input_shaping_type", &owning_page);
|
||||
if (field == nullptr)
|
||||
return;
|
||||
|
||||
auto choice_field = dynamic_cast<Choice*>(field);
|
||||
if (choice_field == nullptr)
|
||||
return;
|
||||
|
||||
auto combo = dynamic_cast<ComboBox*>(choice_field->getWindow());
|
||||
if (combo == nullptr)
|
||||
return;
|
||||
|
||||
const ConfigOptionDef* def = m_config->def()->get("input_shaping_type");
|
||||
if (def == nullptr)
|
||||
return;
|
||||
|
||||
const auto& labels = def->enum_labels;
|
||||
const auto& values = def->enum_values;
|
||||
|
||||
wxWindowUpdateLocker locker(combo);
|
||||
combo->Clear();
|
||||
|
||||
for (InputShaperType type : allowed) {
|
||||
const size_t idx = static_cast<size_t>(type);
|
||||
wxString label;
|
||||
if (idx < labels.size() && !labels[idx].empty())
|
||||
label = _(labels[idx]);
|
||||
else if (idx < values.size())
|
||||
label = wxString::FromUTF8(values[idx].c_str());
|
||||
else
|
||||
label = wxString::Format("%d", static_cast<int>(type));
|
||||
|
||||
combo->Append(label, wxNullBitmap,
|
||||
reinterpret_cast<void*>(static_cast<uintptr_t>(static_cast<int>(type))));
|
||||
}
|
||||
|
||||
if (combo->GetCount() == 0)
|
||||
return;
|
||||
|
||||
choice_field->set_value(static_cast<int>(desired), false);
|
||||
}
|
||||
|
||||
void TabPrinter::on_gcode_flavor_changed()
|
||||
{
|
||||
auto* flavor_option = m_config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor");
|
||||
if (!flavor_option)
|
||||
return;
|
||||
update_input_shaper_menu(flavor_option->value);
|
||||
}
|
||||
|
||||
void TabPrinter::toggle_options()
|
||||
{
|
||||
if (!m_active_page || m_presets->get_edited_preset().printer_technology() == ptSLA)
|
||||
@@ -5568,6 +5699,12 @@ void TabPrinter::toggle_options()
|
||||
toggle_option("extruders_count", !bSEMM);
|
||||
toggle_option("manual_filament_change", bSEMM);
|
||||
toggle_option("purge_in_prime_tower", bSEMM && supports_wipe_tower_2);
|
||||
|
||||
// Orca: "Tool change on wipe tower" only makes sense for multi-extruder (multi-toolhead) printers
|
||||
// using a Type 2 wipe tower. SEMM already always travels to the tower as part of the purge,
|
||||
// so the option is irrelevant there.
|
||||
const size_t extruders_count = m_config->option<ConfigOptionFloats>("nozzle_diameter")->size();
|
||||
toggle_option("tool_change_on_wipe_tower", !bSEMM && supports_wipe_tower_2 && extruders_count > 1);
|
||||
}
|
||||
wxString extruder_number;
|
||||
long val = 1;
|
||||
@@ -5652,6 +5789,7 @@ void TabPrinter::toggle_options()
|
||||
|
||||
if (m_active_page->title() == L("Motion ability")) {
|
||||
auto gcf = m_config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor")->value;
|
||||
update_input_shaper_menu(gcf);
|
||||
bool silent_mode = m_config->opt_bool("silent_mode");
|
||||
int max_field = silent_mode ? 2 : 1;
|
||||
for (int i = 0; i < max_field; ++i)
|
||||
@@ -5679,9 +5817,31 @@ void TabPrinter::toggle_options()
|
||||
toggle_option("machine_max_jerk_e", enable_jerk, i);
|
||||
}
|
||||
|
||||
bool emittable_limits = m_config->opt_enum<GCodeFlavor>("gcode_flavor") == GCodeFlavor::gcfMarlinLegacy || m_config->opt_enum<GCodeFlavor>("gcode_flavor") == GCodeFlavor::gcfMarlinFirmware || m_config->opt_enum<GCodeFlavor>("gcode_flavor") == GCodeFlavor::gcfRepRapFirmware;
|
||||
toggle_option("emit_machine_limits_to_gcode", emittable_limits);
|
||||
|
||||
bool resonance_avoidance = m_config->opt_bool("resonance_avoidance");
|
||||
toggle_option("min_resonance_avoidance_speed", resonance_avoidance);
|
||||
toggle_option("max_resonance_avoidance_speed", resonance_avoidance);
|
||||
|
||||
bool input_shaping_compatible = m_config->opt_enum<GCodeFlavor>("gcode_flavor") == GCodeFlavor::gcfMarlinFirmware || m_config->opt_enum<GCodeFlavor>("gcode_flavor") == GCodeFlavor::gcfRepRapFirmware;
|
||||
|
||||
for (auto is : {"input_shaping_emit", "input_shaping_type", "input_shaping_freq_x", "input_shaping_freq_y",
|
||||
"input_shaping_damp_x", "input_shaping_damp_y"})
|
||||
toggle_line(is, input_shaping_compatible);
|
||||
|
||||
if (input_shaping_compatible) {
|
||||
bool emit_machine_limits_to_gcode = m_config->opt_bool("emit_machine_limits_to_gcode");
|
||||
toggle_option("input_shaping_emit", emit_machine_limits_to_gcode);
|
||||
bool input_shaping_emit = emit_machine_limits_to_gcode && m_config->opt_bool("input_shaping_emit");
|
||||
bool reprap = m_config->opt_enum<GCodeFlavor>("gcode_flavor") == GCodeFlavor::gcfRepRapFirmware;
|
||||
toggle_option("input_shaping_type", input_shaping_emit);
|
||||
toggle_option("input_shaping_freq_x", input_shaping_emit);
|
||||
toggle_option("input_shaping_freq_y", input_shaping_emit && !reprap);
|
||||
toggle_option("input_shaping_damp_x", input_shaping_emit);
|
||||
toggle_option("input_shaping_damp_y", input_shaping_emit && !reprap);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6700,6 +6860,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 ?
|
||||
@@ -7108,7 +7272,15 @@ wxSizer* Tab::compatible_widget_create(wxWindow* parent, PresetDependencies &dep
|
||||
presets.Add(from_u8(preset.name));
|
||||
}
|
||||
|
||||
wxMultiChoiceDialog dlg(parent, deps.dialog_title, deps.dialog_label, presets);
|
||||
if(deps.type == Preset::TYPE_PRINTER){
|
||||
deps.dialog_title = "Compatible printers";
|
||||
deps.dialog_label = "Select printers";
|
||||
}else{
|
||||
deps.dialog_title = "Compatible process profiles";
|
||||
deps.dialog_label = "Select profiles";
|
||||
}
|
||||
|
||||
MultiChoiceDialog dlg(parent, deps.dialog_label, deps.dialog_title, presets);
|
||||
wxGetApp().UpdateDlgDarkUI(&dlg);
|
||||
// Collect and set indices of depending_presets marked as compatible.
|
||||
wxArrayInt selections;
|
||||
@@ -7121,13 +7293,16 @@ wxSizer* Tab::compatible_widget_create(wxWindow* parent, PresetDependencies &dep
|
||||
break;
|
||||
}
|
||||
dlg.SetSelections(selections);
|
||||
dlg.SetSize(FromDIP(wxSize(360, 480)));
|
||||
std::vector<std::string> value;
|
||||
// Show the dialog.
|
||||
if (dlg.ShowModal() == wxID_OK) {
|
||||
selections.Clear();
|
||||
selections = dlg.GetSelections();
|
||||
for (auto idx : selections)
|
||||
value.push_back(presets[idx].ToUTF8().data());
|
||||
// leave list empty if all items checked. this will check "All" checkbox automatically. also fixes unnecessary config change
|
||||
if(selections.GetCount() != presets.GetCount())
|
||||
for (auto idx : selections)
|
||||
value.push_back(presets[idx].ToUTF8().data());
|
||||
if (value.empty()) {
|
||||
deps.checkbox->SetValue(1);
|
||||
deps.btn->Disable();
|
||||
@@ -7254,6 +7429,104 @@ bool Tab::validate_custom_gcodes()
|
||||
return valid;
|
||||
}
|
||||
|
||||
// ORCA: Session-only suppression keys for temperature-pair safety warnings.
|
||||
static std::unordered_set<std::string> 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<TempPairRule> 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<int>(btPC); bt < static_cast<int>(btCount); ++bt) {
|
||||
const BedType bed_type = static_cast<BedType>(bt);
|
||||
const size_t label_idx = static_cast<size_t>(bt - static_cast<int>(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<ConfigOptionInts>(rule.first_layer_key);
|
||||
const ConfigOptionInts* other_opt = config.option<ConfigOptionInts>(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;
|
||||
@@ -7365,7 +7638,7 @@ void Tab::switch_excluder(int extruder_id)
|
||||
{}, {"", "filament_extruder_variant"}, // Preset::TYPE_FILAMENT filament don't use id anymore
|
||||
{}, {"printer_extruder_id", "printer_extruder_variant"}, // Preset::TYPE_PRINTER
|
||||
};
|
||||
if (!m_variant_combo && (extruder_id >= nozzle_volumes->size() || extruder_id >= extruders->size()))
|
||||
if (!m_variant_combo && (extruder_id >= (int)nozzle_volumes->size() || extruder_id >= (int)extruders->size()))
|
||||
extruder_id = 0;
|
||||
if (m_extruder_switch && m_type != Preset::TYPE_PRINTER) {
|
||||
int current_extruder = m_extruder_switch->GetValue() ? 1 : 0;
|
||||
|
||||
Reference in New Issue
Block a user