Skip to content

fix(slicer): invalidate slice result when instance printability toggles#10892

Open
adele-with-a-b wants to merge 1 commit into
bambulab:masterfrom
adele-with-a-b:fix/printable-toggle-invalidation
Open

fix(slicer): invalidate slice result when instance printability toggles#10892
adele-with-a-b wants to merge 1 commit into
bambulab:masterfrom
adele-with-a-b:fix/printable-toggle-invalidation

Conversation

@adele-with-a-b

@adele-with-a-b adele-with-a-b commented May 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Fix a regression where toggling an object instance's "Printable" flag leaves the slice button grayed out, requiring an unrelated change to the project before the user can re-slice.

Closes #10891

Root cause

Print::apply()'s instance synchronization branch (src/libslic3r/PrintApply.cpp ~line 1757) updates each instance's printable flag but only invalidates Print steps when is_printable_filament_changed() detects a filament-set change. A pure printability toggle leaves the filament assignment unchanged, so this loop produces no invalidation.

Section 4 of Print::apply does fire invalidate_all_steps() for the toggled object, but in the affected workflow the print steps are already in INVALID state from earlier background-process activity, so invalidate_all_steps() returns false and the overall apply_status caps at APPLY_STATUS_CHANGED (1) instead of APPLY_STATUS_INVALIDATED (2).

Plater::priv::update_background_process only calls update_slice_result_valid_state(false) on APPLY_STATUS_INVALIDATED (Plater.cpp:10210). With APPLY_STATUS_CHANGED, the cached slice result stays valid, so MainFrame::get_enable_slice_status() returns false (button disabled) because PartPlate::is_slice_result_valid() is still true.

Regression

Introduced by e22d328f ("ENH: Optimizing the shape invalid condition for wipe tower of multi-extruder", May 2025), which replaced an unconditional invalidation in the set_instances path with a narrower convex-hull-based check. The optimization was correct for translation/rotation cases, but printability toggles do not change geometry, so they fall through both the new and old checks in this loop.

Fix

Invalidate {psSkirtBrim, psWipeTower, psGCodeExport} whenever old_instance->printable != new_instance->printable. The triplet matches the one used elsewhere in PrintApply.cpp (line 1852) and in PrintObject::set_instances (PrintObject.cpp:116).

Skirt/brim is included because the set of PrintInstances feeding Print::_make_skirt is filtered upstream by ModelInstance::is_printable() at PrintApply.cpp:147 — when printability toggles, the cached skirt geometry is stale.

The diff is 4 lines.

Test plan

  • Verified with BBL_INTERNAL_TESTING=1 build that pre-patch toggle produces apply_status=1 (CHANGED) and enable_slice=0, while post-patch the same toggle produces apply_status=2 (INVALIDATED) and enable_slice=1.
  • Toggle off, slice button enables, slice; toggle on, slice button enables, slice. Confirmed across 7 toggle events on a multi-object plate.
  • No regression in the non-toggling case: translation/rotation/transform changes still take the is_printable_filament_changed path and behave as e22d328f intended.
  • Verified on multi-extruder H2C profile (the configuration where the bug was originally reported).

@BenJule

BenJule commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Heads-up: this build failure doesn't come from this PR. The Build All (macos-*) / Build Deps jobs fail while building dep_Assimp, not on your slicer change.

Assimp bundles an old zlib (contrib/zlib) whose K&R-style function declarations no longer parse against the macOS 15+/26 SDK, so the deps build currently breaks on every macOS PR. I've proposed a one-line fix in #11051 (use the system zlib for Assimp on macOS/Linux). Once that lands, a rebase or re-run here should go green.

When a user toggles an object instance's 'Printable' flag, the slice
button stays grayed out and clicking it has no effect, even though the
toggle visually registers in the object list.

Root cause: Plater::priv::update_background_process only calls
update_slice_result_valid_state(false) when Print::apply() returns
APPLY_STATUS_INVALIDATED — APPLY_STATUS_CHANGED is not enough
(Plater.cpp:10210).

In Print::apply()'s instance synchronization branch (PrintApply.cpp
~line 1757), the loop updates each instance's printable flag but
only invalidates Print steps when is_printable_filament_changed()
detects a filament-set change. A pure printability toggle that does
not alter the filament assignment produces no invalidation in this
loop. Section 4's PrintObject reconciliation does eventually fire
invalidate_all_steps() for objects whose printable instance count
changed — but in the affected workflow the print steps are already
in INVALID state from earlier background-process activity, so
invalidate_all_steps() returns false and the overall apply_status
caps at APPLY_STATUS_CHANGED (1) rather than rising to
APPLY_STATUS_INVALIDATED (2). Result:

1. update_slice_result_valid_state(false) is NOT called.
2. PartPlate::is_slice_result_valid() stays true.
3. MainFrame::get_enable_slice_status() returns false (button stays
   disabled) because the plate's slice result is still considered
   valid and there is nothing new to slice.
4. The user sees a grayed-out slice button after toggling.

Reproducible with logs: every printability toggle in the affected
configuration produces 'background process apply result=1'
(APPLY_STATUS_CHANGED) followed by enable_slice=0 in
update_slice_print_status. After the patch the same toggle produces
'apply result=2' (APPLY_STATUS_INVALIDATED) and enable_slice=1.

Regression context: e22d328 ('ENH: Optimizing the shape invalid
condition for wipe tower of multi-extruder', May 2025) replaced an
unconditional invalidation in the set_instances path with a narrower
convex-hull-based check. The optimization was correct for
translation/rotation cases, but printability toggles do not change
geometry, so they fall through both the new and old checks in this
loop.

Fix: invalidate {psSkirtBrim, psWipeTower, psGCodeExport} whenever
old_instance->printable != new_instance->printable. This matches the
triplet used elsewhere in PrintApply.cpp (line 1852) and in
PrintObject::set_instances (PrintObject.cpp:116). Skirt/brim is
included because the set of PrintInstances feeding Print::_make_skirt
is filtered upstream by ModelInstance::is_printable() at
PrintApply.cpp:147 — when printability toggles, the cached skirt
geometry is stale and must be recomputed.

When the loop's invalidation actually flips a step from VALID to
INVALID (the typical case after a fresh slice), this lifts
apply_status to APPLY_STATUS_INVALIDATED and the cached slice result
is correctly marked stale, re-enabling the slice button.
@adele-with-a-b adele-with-a-b force-pushed the fix/printable-toggle-invalidation branch from b6906c7 to 8f4f0e8 Compare June 9, 2026 02:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Slice button stays grayed out after toggling object Printable flag

2 participants