Fix deleting mixed filaments from the sidebar

This commit is contained in:
SoftFever
2026-08-23 22:11:49 +08:00
parent b2e1870a14
commit 6745a33d53
2 changed files with 68 additions and 45 deletions
+12 -3
View File
@@ -2669,9 +2669,18 @@ void ModelVolume::update_extruder_count_when_delete_filament(size_t extruder_cou
// Same stale-assignment cleanup as update_extruder_count, for the filament-delete path. // Same stale-assignment cleanup as update_extruder_count, for the filament-delete path.
// Ported from BambuStudio (STUDIO-15763). // Ported from BambuStudio (STUDIO-15763).
size_t eid = extruder_id(); size_t eid = extruder_id();
if (eid > extruder_count) { // Judge out-of-range against the post-remap id, mirroring update_filament_values_for_items_when_delete_filament.
// A mixed-color slot is virtual and legitimately sits past the physical filament count, // Using the pre-remap eid would wrongly erase a high extruder that should remap (e.g. 5 -> 4 after
// so an assignment to one is not stale and must survive the delete. // deleting filament 1); update_filament_values_for_items_when_delete_filament would then skip it
// (!has("extruder")) and the volume would fall back to the object default color.
size_t remapped = eid;
if (eid == filament_id)
remapped = (replace_filament_id > 0) ? (size_t)replace_filament_id : 1;
else if (eid > filament_id)
remapped = eid - 1;
if (remapped > extruder_count) {
// filament_is_mixed is the pre-delete snapshot; index it with the ORIGINAL eid (1-based),
// not remapped, so we check whether this volume's current slot is a mixed slot.
bool is_mixed = !filament_is_mixed.empty() && eid >= 1 && (eid - 1) < filament_is_mixed.size() && filament_is_mixed[eid - 1]; bool is_mixed = !filament_is_mixed.empty() && eid >= 1 && (eid - 1) < filament_is_mixed.size() && filament_is_mixed[eid - 1];
if (!is_mixed) if (!is_mixed)
this->config.erase("extruder"); this->config.erase("extruder");
+25 -11
View File
@@ -5294,16 +5294,16 @@ void Sidebar::on_filaments_delete(size_t filament_id)
{ {
auto &choices = combos_filament(); auto &choices = combos_filament();
if (filament_id >= choices.size()) // A mixed (virtual) slot has no combo of its own, so there is no combo UI to remove —
return; // but the shared refresh below must still run so the mixed filament panel drops its row.
if (filament_id < choices.size()) {
if (choices.size() == 1) if (choices.size() == 1)
choices[0]->GetDropDown().Invalidate(); choices[0]->GetDropDown().Invalidate();
wxWindowUpdateLocker noUpdates_scrolled_panel(this); wxWindowUpdateLocker noUpdates_scrolled_panel(this);
// delete UI item // delete UI item
if (filament_id < p->combos_filament.size()) { {
const int last = p->combos_filament.size() - 1; const int last = p->combos_filament.size() - 1;
auto sizer_filaments = this->p->sizer_filaments->GetItem(last % 2)->GetSizer(); auto sizer_filaments = this->p->sizer_filaments->GetItem(last % 2)->GetSizer();
sizer_filaments->Remove(last / 2); sizer_filaments->Remove(last / 2);
@@ -5332,6 +5332,7 @@ void Sidebar::on_filaments_delete(size_t filament_id)
for (size_t idx = filament_id ; idx < p->combos_filament.size(); ++idx) { for (size_t idx = filament_id ; idx < p->combos_filament.size(); ++idx) {
p->combos_filament[idx]->update(); p->combos_filament[idx]->update();
} }
}
update_filaments_area_height(); // ORCA update_filaments_area_height(); // ORCA
recalc_filament_scroll_sizes(); recalc_filament_scroll_sizes();
@@ -5368,9 +5369,15 @@ void Sidebar::delete_filament(size_t filament_id, int replace_filament_id) {
filament_id = filament_count; filament_id = filament_count;
} }
if (filament_id > filament_count) // Mixed (virtual) slots have no combo of their own, so their config index lies past
// filament_count; bound explicit ids by the total slot count instead.
size_t total_filaments = wxGetApp().preset_bundle->filament_presets.size();
if (filament_id > filament_count && filament_id >= total_filaments)
return; return;
bool is_mixed = (filament_id >= p->combos_filament.size());
if (!is_mixed) {
if (wxGetApp().preset_bundle->is_the_only_edited_filament(filament_id) || (filament_id == 0)) { if (wxGetApp().preset_bundle->is_the_only_edited_filament(filament_id) || (filament_id == 0)) {
wxGetApp().get_tab(Preset::TYPE_FILAMENT)->select_preset(wxGetApp().preset_bundle->filament_presets[0], false, "", true); wxGetApp().get_tab(Preset::TYPE_FILAMENT)->select_preset(wxGetApp().preset_bundle->filament_presets[0], false, "", true);
} }
@@ -5378,6 +5385,7 @@ void Sidebar::delete_filament(size_t filament_id, int replace_filament_id) {
if (p->editing_filament == filament_id || p->editing_filament >= filament_count) { if (p->editing_filament == filament_id || p->editing_filament >= filament_count) {
p->editing_filament = -1; p->editing_filament = -1;
} }
}
// update_num_filaments() shrinks filament_is_mixed along with the other per-filament arrays, // update_num_filaments() shrinks filament_is_mixed along with the other per-filament arrays,
// so snapshot it first — the paint cleanup below needs to know which slots were mixed // so snapshot it first — the paint cleanup below needs to know which slots were mixed
@@ -5387,8 +5395,12 @@ void Sidebar::delete_filament(size_t filament_id, int replace_filament_id) {
is_mixed_snapshot = opt->values; is_mixed_snapshot = opt->values;
wxGetApp().preset_bundle->update_num_filaments(filament_id); wxGetApp().preset_bundle->update_num_filaments(filament_id);
wxGetApp().plater()->get_partplate_list().on_filament_deleted(filament_count, filament_id);
wxGetApp().plater()->on_filaments_delete(filament_count, filament_id, replace_filament_id > (int)filament_id ? (replace_filament_id - 1) : replace_filament_id, is_mixed_snapshot); // filament_count only counts physical combos, so with mixed slots present it is not the
// new number of slots; recompute from the shrunk preset list for the downstream updates.
size_t total_after_delete = wxGetApp().preset_bundle->filament_presets.size();
wxGetApp().plater()->get_partplate_list().on_filament_deleted(total_after_delete, filament_id);
wxGetApp().plater()->on_filaments_delete(total_after_delete, filament_id, replace_filament_id > (int)filament_id ? (replace_filament_id - 1) : replace_filament_id, is_mixed_snapshot);
wxGetApp().get_tab(Preset::TYPE_PRINT)->update(); wxGetApp().get_tab(Preset::TYPE_PRINT)->update();
wxGetApp().preset_bundle->export_selections(*wxGetApp().app_config); wxGetApp().preset_bundle->export_selections(*wxGetApp().app_config);
@@ -19495,8 +19507,10 @@ void Plater::on_filaments_delete(size_t num_filaments, size_t filament_id, int r
} }
} }
// update UI // update object/volume/support(object and volume) filament id
sidebar().on_filaments_delete(filament_id); // Must run before UI update which triggers update_mixed_filament_list() →
// update_objects_list_filament_column() that clips extruders above total count.
sidebar().obj_list()->update_objects_list_filament_column_when_delete_filament(filament_id, num_filaments, replace_filament_id);
// update global support filament // update global support filament
static const char *keys[] = {"support_filament", "support_interface_filament"}; static const char *keys[] = {"support_filament", "support_interface_filament"};
@@ -19510,8 +19524,8 @@ void Plater::on_filaments_delete(size_t num_filaments, size_t filament_id, int r
} }
} }
// update object/volume/support(object and volume) filament id // update UI — runs after remap so update_mixed_filament_list() won't clip remapped extruder IDs
sidebar().obj_list()->update_objects_list_filament_column_when_delete_filament(filament_id, num_filaments, replace_filament_id); sidebar().on_filaments_delete(filament_id);
// update customize gcode // update customize gcode
for (auto item = p->model.plates_custom_gcodes.begin(); item != p->model.plates_custom_gcodes.end(); ++item) { for (auto item = p->model.plates_custom_gcodes.begin(); item != p->model.plates_custom_gcodes.end(); ++item) {