Merge upstream main: Python plugins, Bambu device rework, macOS fixes

Resolved 4 conflicts:
- PrintConfig.hpp / Preset.cpp: upstream restored calib_flowrate_topinfill_special_order
  (removed in the prior merge, now re-added and re-registered); kept it alongside our
  IMEX options (imex_parallel_mode, imex_head_filament_map).
- Plater.cpp: kept our <sstream> include plus upstream's <optional> and plugin includes.
- tests/fff_print/test_gcodewriter.cpp: both sides appended disjoint scenarios after a
  shared base. Reconstructed as upstream's full file (base + its 3 toolchange/H2C
  scenarios + the boost/filesystem include its helper needs) followed by our 10
  set_pressure_advance / set_temperature scenarios. 22 scenarios total, no duplicates.
This commit is contained in:
Clifford Garwood committed 2026-07-19 18:33:58 -04:00
commit 58b4a68a10
730 files changed
+2322299 -1241524

No files matched your search

+53 -17
View File
@@ -1076,6 +1076,28 @@ void add_correct_opts_to_options_list(const std::string &opt_key, std::map<std::
map.emplace(opt_key + "#0", value);
}
std::string Tab::options_list_storage_key(const std::string& opt_key) const
{
if (opt_key == "printable_area" || opt_key == "bed_exclude_area" || opt_key == "compatible_prints" ||
opt_key == "compatible_printers" || opt_key == "thumbnails" || opt_key == "wrapping_exclude_area")
return opt_key;
if (m_config == nullptr || !m_config->has(opt_key))
return opt_key;
const ConfigOption* option = m_config->option(opt_key);
if (option == nullptr || !option->is_vector())
return opt_key;
const ConfigOptionDef* def = m_config->def()->get(opt_key);
if (def == nullptr)
return opt_key;
const bool serialized = def->gui_flags == "serialized";
const bool is_plugin_field = def->gui_type == ConfigOptionDef::GUIType::plugin_picker;
return (serialized || is_plugin_field) ? opt_key : opt_key + "#0";
}
void Tab::update_all_extruder_options_status()
{
if (!m_extruder_switch && !m_variant_combo) {
@@ -1244,23 +1266,14 @@ void Tab::check_extruder_options_status(int index, bool &sys_extruder, bool &mod
}
}
}
void Tab::init_options_list()
{
if (!m_options_list.empty())
m_options_list.clear();
for (const std::string& opt_key : m_config->keys())
{
if (opt_key == "printable_area" || opt_key == "bed_exclude_area" || opt_key == "compatible_prints" || opt_key == "compatible_printers" || opt_key == "thumbnails" || opt_key == "wrapping_exclude_area") {
m_options_list.emplace(opt_key, m_opt_status_value);
continue;
}
const ConfigOptionDef* opt_def = m_config->def()->get(opt_key);
if (m_config->option(opt_key)->is_vector() && !(opt_def && opt_def->gui_flags == "serialized"))
m_options_list.emplace(opt_key + "#0", m_opt_status_value);
else
m_options_list.emplace(opt_key, m_opt_status_value);
}
m_options_list.emplace(options_list_storage_key(opt_key), m_opt_status_value);
}
void TabPrinter::init_options_list()
@@ -1782,6 +1795,12 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
return;
}
// Keep this preset's "plugins" manifest in sync when a plugin picker changes, so full_config() and
// save_to_json() always find resolved "name;uuid;capability" references and rebuild it nowhere else.
if (const ConfigOptionDef* opt_def = m_config->def()->get(opt_key);
opt_def && opt_def->is_plugin_backed())
m_config->update_plugin_manifest();
if (opt_key == "gcode_flavor" && m_type == Preset::TYPE_PRINTER) {
if (auto printer_tab = dynamic_cast<TabPrinter*>(this))
printer_tab->on_gcode_flavor_changed();
@@ -2073,7 +2092,7 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
bool is_safe_to_rotate = _sparse_infill_pattern == ipRectilinear || _sparse_infill_pattern == ipLine ||
_sparse_infill_pattern == ipZigZag || _sparse_infill_pattern == ipCrossZag ||
_sparse_infill_pattern == ipLockedZag;
auto new_value = boost::any_cast<std::string>(value);
is_safe_to_rotate = is_safe_to_rotate || new_value.empty();
const bool had_previous_value = !m_last_sparse_infill_rotate_template_value.empty();
@@ -3099,6 +3118,17 @@ void TabPrint::build()
option.opt.height = 15;
optgroup->append_single_option_line(option, "others_settings_post_processing_scripts");
optgroup = page->new_optgroup(L("Slicing Pipeline Plugin"), L"param_gcode", 0);
optgroup->hide_labels();
option = optgroup->get_option("slicing_pipeline_plugin");
option.opt.full_width = true;
optgroup->append_single_option_line(option, "others_settings_plugin_picker");
// Its own group: the one above hides its labels, and this row needs its label — and the revert
// arrow beside it — to show. No label-width override either, as a 0 there means "no label column".
optgroup = page->new_optgroup(L("Plugin Configuration"), L"param_gcode");
optgroup->append_single_option_line("plugin_config_overrides");
optgroup = page->new_optgroup(L("Notes"), "note", 0);
option = optgroup->get_option("notes");
option.opt.full_width = true;
@@ -4182,7 +4212,7 @@ void TabFilament::update_filament_overrides_page(const DynamicPrintConfig* print
if (og_ironing_it != page->m_optgroups.end())
{
ConfigOptionsGroupShp ironing_optgroup = *og_ironing_it;
std::vector<std::string> ironing_opt_keys = {
"filament_ironing_flow",
"filament_ironing_spacing",
@@ -4194,7 +4224,7 @@ void TabFilament::update_filament_overrides_page(const DynamicPrintConfig* print
{
if (m_overrides_options.find(opt_key) == m_overrides_options.end())
continue;
bool is_checked = !dynamic_cast<ConfigOptionVectorBase*>(m_config->option(opt_key))->is_nil(extruder_idx);
m_overrides_options[opt_key]->Enable(true);
m_overrides_options[opt_key]->SetValue(is_checked);
@@ -4500,6 +4530,9 @@ void TabFilament::build()
option.opt.height = gcode_field_height;// 150;
optgroup->append_single_option_line(option);
optgroup = page->new_optgroup(L("Plugin Configuration"), L"param_gcode");
optgroup->append_single_option_line("plugin_config_overrides");
page = add_options_page(L("Multimaterial"), "custom-gcode_multi_material"); // ORCA: icon only visible on placeholders
optgroup = page->new_optgroup(L("Wipe tower parameters"), "param_tower");
optgroup->append_single_option_line("filament_minimal_purge_on_wipe_tower", "material_multimaterial#multimaterial-wipe-tower-parameters");
@@ -4508,7 +4541,7 @@ void TabFilament::build()
optgroup->append_single_option_line("filament_tower_ironing_area", "material_multimaterial#multimaterial-wipe-tower-parameters");
optgroup->append_single_option_line("filament_tower_interface_purge_volume", "material_multimaterial#multimaterial-wipe-tower-parameters");
optgroup->append_single_option_line("filament_tower_interface_print_temp", "material_multimaterial#multimaterial-wipe-tower-parameters");
optgroup = page->new_optgroup(L("Multi Filament"));
// optgroup->append_single_option_line("filament_flush_temp", "", 0);
// optgroup->append_single_option_line("filament_flush_volumetric_speed", "", 0);
@@ -5596,6 +5629,9 @@ void TabPrinter::build_fff()
// optgroup->append_single_option_line("spaghetti_detector");
optgroup->append_single_option_line("time_cost", "printer_basic_information_advanced#time-cost");
optgroup = page->new_optgroup(L("Plugin Configuration"), L"param_gcode");
optgroup->append_single_option_line("plugin_config_overrides");
optgroup = page->new_optgroup(L("Cooling Fan"), "param_cooling_fan");
Line line = Line{ L("Fan speed-up time"), optgroup->get_option("fan_speedup_time").opt.tooltip };
line.label_path = "printer_basic_information_cooling_fan#fan-speed-up-time";
@@ -6672,7 +6708,7 @@ void TabPrinter::toggle_options()
toggle_line("support_air_filtration", !m_config->opt_bool("support_cooling_filter"));
toggle_line("cooling_filter_enabled", m_config->opt_bool("support_cooling_filter"));
}
if (m_active_page->title() == L("Machine G-code")) {
PresetBundle *preset_bundle = wxGetApp().preset_bundle;
@@ -8636,7 +8672,7 @@ bool Tab::validate_filament_temperature_pairs()
if (delta <= rule.max_delta)
continue;
const wxString deg_c = wxString::FromUTF8("°C");
const wxString deg_c = wxString::FromUTF8("℃");
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);