Fix deleting mixed filaments from the sidebar

This commit is contained in:
SoftFever
2026-08-22 15:32:19 +08:00
parent b2e1870a14
commit 6745a33d53
2 changed files with 68 additions and 45 deletions

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");

View File

@@ -5294,43 +5294,44 @@ 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)
choices[0]->GetDropDown().Invalidate();
if (choices.size() == 1) wxWindowUpdateLocker noUpdates_scrolled_panel(this);
choices[0]->GetDropDown().Invalidate();
wxWindowUpdateLocker noUpdates_scrolled_panel(this); // delete UI item
{
const int last = p->combos_filament.size() - 1;
auto sizer_filaments = this->p->sizer_filaments->GetItem(last % 2)->GetSizer();
sizer_filaments->Remove(last / 2);
// delete UI item PlaterPresetComboBox* to_delete_combox = p->combos_filament[filament_id];
if (filament_id < p->combos_filament.size()) { (*p->combos_filament[last]).Destroy();
const int last = p->combos_filament.size() - 1; p->combos_filament.pop_back();
auto sizer_filaments = this->p->sizer_filaments->GetItem(last % 2)->GetSizer();
sizer_filaments->Remove(last / 2);
PlaterPresetComboBox* to_delete_combox = p->combos_filament[filament_id]; // BBS: filament double columns
(*p->combos_filament[last]).Destroy(); auto sizer_filaments0 = this->p->sizer_filaments->GetItem((size_t) 0)->GetSizer();
p->combos_filament.pop_back(); auto sizer_filaments1 = this->p->sizer_filaments->GetItem(1)->GetSizer();
if (p->combos_filament.size() < 2) {
// BBS: filament double columns sizer_filaments1->Clear();
auto sizer_filaments0 = this->p->sizer_filaments->GetItem((size_t) 0)->GetSizer(); } else {
auto sizer_filaments1 = this->p->sizer_filaments->GetItem(1)->GetSizer(); size_t c0 = sizer_filaments0->GetChildren().GetCount();
if (p->combos_filament.size() < 2) { size_t c1 = sizer_filaments1->GetChildren().GetCount();
sizer_filaments1->Clear(); if (c0 < c1)
} else { sizer_filaments1->Remove(c1 - 1);
size_t c0 = sizer_filaments0->GetChildren().GetCount(); else if (c0 > c1)
size_t c1 = sizer_filaments1->GetChildren().GetCount(); sizer_filaments1->AddStretchSpacer(1);
if (c0 < c1) }
sizer_filaments1->Remove(c1 - 1);
else if (c0 > c1)
sizer_filaments1->AddStretchSpacer(1);
} }
}
show_SEMM_buttons(); // ORCA show_SEMM_buttons(); // ORCA
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
@@ -5368,15 +5369,22 @@ 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;
if (wxGetApp().preset_bundle->is_the_only_edited_filament(filament_id) || (filament_id == 0)) { bool is_mixed = (filament_id >= p->combos_filament.size());
wxGetApp().get_tab(Preset::TYPE_FILAMENT)->select_preset(wxGetApp().preset_bundle->filament_presets[0], false, "", true);
}
if (p->editing_filament == filament_id || p->editing_filament >= filament_count) { if (!is_mixed) {
p->editing_filament = -1; 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);
}
if (p->editing_filament == filament_id || p->editing_filament >= filament_count) {
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,
@@ -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) {