Adds (AMS) filament sync options: Only sync color / sync all (#12169)
Some checks are pending
Build all / Build Linux (push) Waiting to run
Build all / Build Non-Linux (push) Waiting to run
Build all / Unit Tests (push) Blocked by required conditions
Build all / Flatpak (push) Waiting to run

This PR adds a new filament sync mode setting for device-based filament synchronization.
Users can now choose between syncing both filament preset + color (current behavior) or syncing color only, so calibrated local filament profiles are preserved while still updating slot colors from the printer.
It also includes small UI improvements for the new preference entry and sync status messaging.

<img width="665" height="671" alt="image" src="https://github.com/user-attachments/assets/23980846-0113-48ab-84aa-adf5cdab8ab6" />
This commit is contained in:
Argo 2026-02-10 02:12:30 +01:00 committed by GitHub
parent cae1567726
commit ffc8a3e307
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 106 additions and 16 deletions

View file

@ -220,6 +220,8 @@ void AppConfig::set_defaults()
set_bool("enable_merge_color_by_sync_ams", false);
if (get("ams_sync_match_full_use_color_dist").empty())
set_bool("ams_sync_match_full_use_color_dist", false);
if (get("sync_ams_filament_mode").empty())
set("sync_ams_filament_mode", "0"); // 0: filament+color, 1: color only
if (get("camera_orbit_mult").empty())
set("camera_orbit_mult", "1.0");

View file

@ -2338,7 +2338,7 @@ void PresetBundle::get_ams_cobox_infos(AMSComboInfo& combox_info)
}
}
unsigned int PresetBundle::sync_ams_list(std::vector<std::pair<DynamicPrintConfig *,std::string>> &unknowns, bool use_map, std::map<int, AMSMapInfo> &maps,bool enable_append, MergeFilamentInfo &merge_info)
unsigned int PresetBundle::sync_ams_list(std::vector<std::pair<DynamicPrintConfig *,std::string>> &unknowns, bool use_map, std::map<int, AMSMapInfo> &maps, bool enable_append, MergeFilamentInfo &merge_info, bool color_only)
{
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "use_map:" << use_map << " enable_append:" << enable_append;
std::vector<std::string> ams_filament_presets;
@ -2489,7 +2489,71 @@ unsigned int PresetBundle::sync_ams_list(std::vector<std::pair<DynamicPrintConfi
ConfigOptionStrings *filament_color = project_config.option<ConfigOptionStrings>("filament_colour");
ConfigOptionStrings *filament_color_type = project_config.option<ConfigOptionStrings>("filament_colour_type");
ConfigOptionInts * filament_map = project_config.option<ConfigOptionInts>("filament_map");
if (use_map) {
if (color_only) {
auto get_map_index = [&ams_infos](const std::vector<AMSMapInfo> &infos, const AMSMapInfo &temp) {
for (int i = 0; i < infos.size(); i++) {
if (infos[i].slot_id == temp.slot_id && infos[i].ams_id == temp.ams_id) {
ams_infos[i].is_map = true;
return i;
}
}
return -1;
};
auto exist_colors = filament_color->values;
std::vector<std::vector<std::string>> exist_multi_color_filment(exist_colors.size());
for (size_t i = 0; i < exist_colors.size(); i++) {
exist_multi_color_filment[i] = {exist_colors[i]};
}
ConfigOptionStrings *project_multi_color = project_config.option<ConfigOptionStrings>("filament_multi_colour");
if (project_multi_color) {
for (size_t i = 0; i < std::min(exist_multi_color_filment.size(), project_multi_color->values.size()); i++) {
std::vector<std::string> colors = split_string(project_multi_color->values[i], ' ');
if (!colors.empty()) {
exist_multi_color_filment[i] = colors;
}
}
}
bool mapped_any = false;
if (use_map && !maps.empty()) {
for (size_t i = 0; i < exist_colors.size(); i++) {
if (maps.find(i) == maps.end()) {
continue;
}
int valid_index = get_map_index(ams_array_maps, maps[i]);
if (valid_index >= 0 && valid_index < int(ams_filament_colors.size()) && !ams_filament_colors[valid_index].empty()) {
exist_colors[i] = ams_filament_colors[valid_index];
mapped_any = true;
if (valid_index < int(ams_multi_color_filment.size()) && !ams_multi_color_filment[valid_index].empty()) {
exist_multi_color_filment[i] = ams_multi_color_filment[valid_index];
} else {
exist_multi_color_filment[i] = {ams_filament_colors[valid_index]};
}
}
}
}
// Fallback to index-based color sync if no mapping was applied.
if (!use_map || maps.empty() || !mapped_any) {
size_t sync_count = std::min(exist_colors.size(), ams_filament_colors.size());
for (size_t i = 0; i < sync_count; i++) {
if (ams_filament_colors[i].empty()) {
continue;
}
exist_colors[i] = ams_filament_colors[i];
if (i < ams_multi_color_filment.size() && !ams_multi_color_filment[i].empty()) {
exist_multi_color_filment[i] = ams_multi_color_filment[i];
} else {
exist_multi_color_filment[i] = {ams_filament_colors[i]};
}
}
}
filament_color->values = exist_colors;
ams_multi_color_filment = exist_multi_color_filment;
merge_info.merges.clear();
} else if (use_map) {
auto check_has_merge_info = [](std::map<int, AMSMapInfo> &maps, MergeFilamentInfo &merge_info, int exist_colors_size) {
std::set<int> done;
for (auto it_i = maps.begin(); it_i != maps.end(); ++it_i) {

View file

@ -173,7 +173,7 @@ public:
void update_num_filaments(unsigned int to_del_flament_id);
void get_ams_cobox_infos(AMSComboInfo &combox_info);
unsigned int sync_ams_list(std::vector<std::pair<DynamicPrintConfig *,std::string>> &unknowns, bool use_map, std::map<int, AMSMapInfo> &maps,bool enable_append, MergeFilamentInfo& merge_info);
unsigned int sync_ams_list(std::vector<std::pair<DynamicPrintConfig *,std::string>> &unknowns, bool use_map, std::map<int, AMSMapInfo> &maps, bool enable_append, MergeFilamentInfo &merge_info, bool color_only = false);
//BBS: check whether this is the only edited filament
bool is_the_only_edited_filament(unsigned int filament_index);

View file

@ -3464,8 +3464,9 @@ void Sidebar::sync_ams_list(bool is_from_big_sync_btn)
}
MergeFilamentInfo merge_info;
std::vector<std::pair<DynamicPrintConfig *,std::string>> unknowns;
auto enable_append = wxGetApp().app_config->get_bool("enable_append_color_by_sync_ams");
auto n = wxGetApp().preset_bundle->sync_ams_list(unknowns, !sync_result.direct_sync, sync_result.sync_maps, enable_append, merge_info);
auto enable_append = wxGetApp().app_config->get_bool("enable_append_color_by_sync_ams");
auto sync_color_only = wxGetApp().app_config->get("sync_ams_filament_mode") == "1";
auto n = wxGetApp().preset_bundle->sync_ams_list(unknowns, !sync_result.direct_sync, sync_result.sync_maps, enable_append, merge_info, sync_color_only);
wxString detail;
for (auto & uk : unknowns) {
auto tray_name = uk.first->opt_string("tray_name", 0u);
@ -3497,9 +3498,11 @@ void Sidebar::sync_ams_list(bool is_from_big_sync_btn)
_L("Sync filaments with AMS"), wxOK);
dlg.ShowModal();
}
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "on_filament_count_change";
wxGetApp().plater()->on_filament_count_change(n);
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "finish on_filament_count_change";
if (!sync_color_only) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "on_filament_count_change";
wxGetApp().plater()->on_filament_count_change(n);
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "finish on_filament_count_change";
}
for (auto& c : p->combos_filament)
c->update();
// Expand filament list
@ -3523,14 +3526,23 @@ void Sidebar::sync_ams_list(bool is_from_big_sync_btn)
}
Layout();
// Perform preset selection and list update first — these may rebuild combo widgets,
// which clears any badge state. Badges must be set AFTER these calls to persist.
wxGetApp().get_tab(Preset::TYPE_FILAMENT)->select_preset(wxGetApp().preset_bundle->filament_presets[0]);
wxGetApp().preset_bundle->export_selections(*wxGetApp().app_config);
update_dynamic_filament_list();
// For full sync, preset selection/list update may rebuild combo widgets.
// For color-only, keep current presets untouched and refresh colors only.
if (!sync_color_only) {
wxGetApp().get_tab(Preset::TYPE_FILAMENT)->select_preset(wxGetApp().preset_bundle->filament_presets[0]);
wxGetApp().preset_bundle->export_selections(*wxGetApp().app_config);
update_dynamic_filament_list();
} else {
wxGetApp().plater()->update_filament_colors_in_full_config();
for (auto &c : p->combos_filament)
c->update();
obj_list()->update_filament_colors();
update_dynamic_filament_list();
}
auto badge_combox_filament = [](PlaterPresetComboBox *c) {
auto tip = _L("Filament type and color information have been synchronized, but slot information is not included.");
auto badge_combox_filament = [sync_color_only](PlaterPresetComboBox *c) {
auto tip = sync_color_only ? _L("Only filament color information has been synchronized from printer.") :
_L("Filament type and color information have been synchronized, but slot information is not included.");
c->SetToolTip(tip);
c->ShowBadge(true);
};

View file

@ -1492,6 +1492,16 @@ void PreferencesDialog::create_items()
SETTING_USE_ENCRYPTED_TOKEN_FILE);
g_sizer->Add(item_token_storage);
//// ONLINE > Filament Sync Options
g_sizer->Add(create_item_title(_L("Filament Sync Options")), 1, wxEXPAND);
auto item_filament_sync_mode = create_item_combobox(
_L("Filament sync mode"),
_L("Choose whether sync updates both filament preset and color, or only color."),
"sync_ams_filament_mode",
{_L("Filament & Color"), _L("Color only")});
g_sizer->Add(item_filament_sync_mode);
//// ONLINE > Network plugin
g_sizer->Add(create_item_title(_L("Network plugin")), 1, wxEXPAND);

View file

@ -3337,7 +3337,9 @@ FinishSyncAmsDialog::FinishSyncAmsDialog(InputInfo &input_info)
310,
input_info.dialog_pos,
68,
_L("Successfully synchronized color and type of filament from printer."),
wxGetApp().app_config->get("sync_ams_filament_mode") == "1" ?
_L("Successfully synchronized filament color from printer.") :
_L("Successfully synchronized color and type of filament from printer."),
_CTX(L_CONTEXT("OK", "FinishSyncAms"), "FinishSyncAms"),
"",
DisappearanceMode::TimedDisappearance)