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.
// Ported from BambuStudio (STUDIO-15763).
size_t eid = extruder_id();
if (eid > extruder_count) {
// A mixed-color slot is virtual and legitimately sits past the physical filament count,
// so an assignment to one is not stale and must survive the delete.
// Judge out-of-range against the post-remap id, mirroring update_filament_values_for_items_when_delete_filament.
// Using the pre-remap eid would wrongly erase a high extruder that should remap (e.g. 5 -> 4 after
// 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];
if (!is_mixed)
this->config.erase("extruder");

View File

@@ -5294,43 +5294,44 @@ void Sidebar::on_filaments_delete(size_t filament_id)
{
auto &choices = combos_filament();
if (filament_id >= choices.size())
return;
// A mixed (virtual) slot has no combo of its own, so there is no combo UI to remove —
// 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)
choices[0]->GetDropDown().Invalidate();
wxWindowUpdateLocker noUpdates_scrolled_panel(this);
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
if (filament_id < p->combos_filament.size()) {
const int last = p->combos_filament.size() - 1;
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];
(*p->combos_filament[last]).Destroy();
p->combos_filament.pop_back();
PlaterPresetComboBox* to_delete_combox = p->combos_filament[filament_id];
(*p->combos_filament[last]).Destroy();
p->combos_filament.pop_back();
// BBS: filament double columns
auto sizer_filaments0 = this->p->sizer_filaments->GetItem((size_t) 0)->GetSizer();
auto sizer_filaments1 = this->p->sizer_filaments->GetItem(1)->GetSizer();
if (p->combos_filament.size() < 2) {
sizer_filaments1->Clear();
} else {
size_t c0 = sizer_filaments0->GetChildren().GetCount();
size_t c1 = sizer_filaments1->GetChildren().GetCount();
if (c0 < c1)
sizer_filaments1->Remove(c1 - 1);
else if (c0 > c1)
sizer_filaments1->AddStretchSpacer(1);
// BBS: filament double columns
auto sizer_filaments0 = this->p->sizer_filaments->GetItem((size_t) 0)->GetSizer();
auto sizer_filaments1 = this->p->sizer_filaments->GetItem(1)->GetSizer();
if (p->combos_filament.size() < 2) {
sizer_filaments1->Clear();
} else {
size_t c0 = sizer_filaments0->GetChildren().GetCount();
size_t c1 = sizer_filaments1->GetChildren().GetCount();
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) {
p->combos_filament[idx]->update();
for (size_t idx = filament_id ; idx < p->combos_filament.size(); ++idx) {
p->combos_filament[idx]->update();
}
}
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;
}
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;
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);
}
bool is_mixed = (filament_id >= p->combos_filament.size());
if (p->editing_filament == filament_id || p->editing_filament >= filament_count) {
p->editing_filament = -1;
if (!is_mixed) {
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,
@@ -5387,8 +5395,12 @@ void Sidebar::delete_filament(size_t filament_id, int replace_filament_id) {
is_mixed_snapshot = opt->values;
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().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
sidebar().on_filaments_delete(filament_id);
// update object/volume/support(object and volume) 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
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
sidebar().obj_list()->update_objects_list_filament_column_when_delete_filament(filament_id, num_filaments, replace_filament_id);
// update UI — runs after remap so update_mixed_filament_list() won't clip remapped extruder IDs
sidebar().on_filaments_delete(filament_id);
// update customize gcode
for (auto item = p->model.plates_custom_gcodes.begin(); item != p->model.plates_custom_gcodes.end(); ++item) {