Merge branch 'main' into feature/filament_id

Brings in 560 commits (merge base 2026-07-04 .. origin/main af9fd10d7a).
19 conflicts resolved; the other 138 touched files auto-merged.

Conflict resolutions
- Snapmaker/Polymaker (7): main normalised JSON key order in #15039 while this
  branch inserted filament_id/filament_vendor. Took main's key order and kept
  this branch's values, inserting a single filament_id key rather than letting
  git's line merge leave duplicate "from"/"instantiation" keys.
- re3D rPETG @0.8/@1.75 nozzle (2): main renamed these from "re3D Greengate
  rPETG @*" and re-vendored GreenGate3D -> re3D (#15169). Git's rename-aware
  merge produced a file with two filament_vendor keys; took main's version
  wholesale instead. The id is reconciled by the tooling, not by hand.
- re3D rPP (1): kept main's inherits change (fdm_filament_pet -> fdm_filament_pp,
  local filament_type override dropped) and its widened compatible_printers.
  The flattened type is still PP, so the product triple and id OFfHGM1D are
  unchanged.
- re3D Greengate rPETG.json, Afinia {ABS+,ABS,PLA,TPU,Value ABS,Value PLA}.json
  (7 modify/delete): accepted main's deletions. The Afinia ids are not orphaned
  - the surviving @HS presets resolve the same triple and already carry the
  same ids, so nothing is retired.
- .github/workflows/check_profiles.yml: kept both main's new "validate slice"
  step and this branch's tree-wide filament-subtype check.
- tests/libslic3r/CMakeLists.txt: kept both test_filament_id_succession.cpp and
  main's test_preset_diff.cpp.

Verified
- No conflict markers; all 12795 profile JSONs parse with no duplicate keys.
- All branch artifacts (tooling, snapshot, ledger, doc, tests) intact and
  unmodified by the merge.
- The succession-ledger C++ call sites survived main's refactors; audited
  Preset.{cpp,hpp}, PresetBundle.cpp, DeviceManager.cpp, PresetComboBoxes.cpp,
  CaliHistoryDialog.cpp, MoonrakerPrinterAgent.cpp against base/ours/theirs.
- scripts/tests: 115/116 pass.

Known follow-up: assign_filament_ids.py --check reports 243 errors, all from
filament data main added in the last month (BBL/addnorth, Qidi X5/Plus 5,
Snapmaker U1, re3D). The single failing unit test is the live-tree conformance
test asserting that count is zero. Reconciliation lands separately.
This commit is contained in:
SoftFever
2026-08-08 02:05:37 +08:00
2224 changed files with 2621810 additions and 1287330 deletions
+37 -5
View File
@@ -3,6 +3,8 @@
#include <cstddef>
#include <vector>
#include <string>
#include <set>
#include <utility>
#include <algorithm>
#include <boost/algorithm/string.hpp>
@@ -510,8 +512,14 @@ bool PresetComboBox::add_ams_filaments(std::string selected, bool alias_name)
bool selected_in_ams = false;
bool is_bbl_vendor_preset = m_preset_bundle->is_bbl_vendor();
if (is_bbl_vendor_preset && !m_preset_bundle->filament_ams_list.empty()) {
// When a filament track switch is installed and calibrated, every AMS filament is reachable
// from both extruders, so present one deduplicated group instead of the Left/Right split.
bool fila_switch_ready = wxGetApp().sidebar().is_fila_switch_ready();
bool dual_extruder = (m_preset_bundle->filament_ams_list.begin()->first & 0x10000) == 0;
set_label_marker(Append(dual_extruder ? _L("Left filaments") : _L("AMS filament"), wxNullBitmap, DD_ITEM_STYLE_SPLIT_ITEM));
if (fila_switch_ready)
set_label_marker(Append(_L("AMS filaments"), wxNullBitmap, DD_ITEM_STYLE_SPLIT_ITEM));
else
set_label_marker(Append(dual_extruder ? _L("Left filaments") : _L("AMS filament"), wxNullBitmap, DD_ITEM_STYLE_SPLIT_ITEM));
m_first_ams_filament = GetCount();
auto &filaments = m_collection->get_presets();
@@ -523,8 +531,12 @@ bool PresetComboBox::add_ams_filaments(std::string selected, bool alias_name)
icon_width = 32;
}
// Deduplicate by (tray_name, filament_id) so a filament shared by both extruders is
// listed once when the switch is ready. Uses Orca's tray naming/lookup, not BBS's.
std::set<std::pair<std::string, std::string>> added_filaments;
for (auto &entry : m_preset_bundle->filament_ams_list) {
if (dual_extruder && (entry.first & 0x10000)) {
if (!fila_switch_ready && dual_extruder && (entry.first & 0x10000)) {
dual_extruder = false;
set_label_marker(Append(_L("Right filaments"), wxNullBitmap, DD_ITEM_STYLE_SPLIT_ITEM));
}
@@ -535,6 +547,13 @@ bool PresetComboBox::add_ams_filaments(std::string selected, bool alias_name)
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": %1% 's filament_id is empty.") % name;
continue;
}
if (fila_switch_ready) {
// skip the external spool and collapse duplicates shared across both extruders
if (name == "Ext")
continue;
if (!added_filaments.insert(std::make_pair(name, filament_id)).second)
continue;
}
auto iter = std::find_if(filaments.begin(), filaments.end(),
[&filament_id, this](auto &f) { return f.is_compatible && m_collection->get_preset_base(f) == &f && f.filament_id == filament_id; });
if (iter == filaments.end()) {
@@ -853,6 +872,9 @@ PlaterPresetComboBox::PlaterPresetComboBox(wxWindow *parent, Preset::Type preset
clr_picker = new wxBitmapButton(parent, wxID_ANY, {}, wxDefaultPosition, wxSize(FromDIP(20), FromDIP(20)), wxBU_EXACTFIT | wxBU_AUTODRAW | wxBORDER_NONE);
clr_picker->SetBackgroundColour(StateColor::darkModeColorFor(*wxWHITE));
clr_picker->SetToolTip(_L("Click to select filament color"));
#ifdef __WXGTK__
RemoveButtonBorder(clr_picker);
#endif
clr_picker->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) {
// Check if it's an official filament
auto fila_type = Preset::remove_suffix_modified(GetValue().ToUTF8().data());
@@ -1087,7 +1109,7 @@ void PlaterPresetComboBox::show_edit_menu()
#ifdef __linux__
// To edit extruder color from the sidebar
if (m_type == Preset::TYPE_FILAMENT) {
append_menu_item(menu, wxID_ANY, _devL("Change extruder color"), "",
append_menu_item(menu, wxID_ANY, _L("Change extruder color"), "",
[this](wxCommandEvent&) { this->change_extruder_color(); }, "blank_14", menu, []() { return true; }, wxGetApp().plater());
wxGetApp().plater()->PopupMenu(menu);
return;
@@ -1314,10 +1336,19 @@ void PlaterPresetComboBox::update()
bool selected_in_ams = false;
if (m_type == Preset::TYPE_FILAMENT) {
set_replace_text("Bambu", "BambuStudioBlack");
selected_in_ams = add_ams_filaments(into_u8(selected_user_preset.empty() ? selected_system_preset : selected_user_preset), true);
// Orca: selected_system/user_preset hold the FULL preset name because Orca keys the maps above by
// full name to avoid alias collisions (BBS keys by alias). add_ams_filaments() compares against
// get_preset_name() which returns the alias, so resolve the selection back to its alias here.
// Without this, e.g. "Bambu PLA Basic @BBL H2C" never equals the AMS tray alias "Bambu PLA Basic",
// so the FROM_AMS flag is never set and update_sync_status() wipes the AMS sync check mark on the
// filament cards for connected Bambu printers.
wxString selected_full = selected_user_preset.empty() ? selected_system_preset : selected_user_preset;
auto alias_it = preset_aliases.find(selected_full);
wxString selected_alias = alias_it != preset_aliases.end() ? from_u8(alias_it->second) : selected_full;
selected_in_ams = add_ams_filaments(into_u8(selected_alias), true);
}
std::vector<std::string> filament_orders = {"Bambu PLA Basic", "Bambu PLA Matte", "Bambu PETG HF", "Bambu ABS", "Bambu PLA Silk", "Bambu PLA-CF",
std::vector<wxString> filament_orders = {"Bambu PLA Basic", "Bambu PLA Matte", "Bambu PETG HF", "Bambu ABS", "Bambu PLA Silk", "Bambu PLA-CF",
"Bambu PLA Galaxy", "Bambu PLA Metal", "Bambu PLA Marble", "Bambu PETG-CF", "Bambu PETG Translucent", "Bambu ABS-GF"};
std::vector<std::string> first_vendors = {"", "Bambu", "Generic"}; // Empty vendor for non-system presets
std::vector<std::string> first_types = {"PLA", "PETG", "ABS", "TPU"};
@@ -1607,6 +1638,7 @@ TabPresetComboBox::TabPresetComboBox(wxWindow* parent, Preset::Type preset_type)
// BBS: new layout
PresetComboBox(parent, preset_type, wxSize(20 * wxGetApp().em_unit(), 30 * wxGetApp().em_unit() / 10))
{
GetDropDown().SetUseContentWidth(true,true);
}
void TabPresetComboBox::OnSelect(wxCommandEvent &evt)