Take the dodge/burn mask tint off the canvas while a mask is adjusted - #888
Merged
Merged
Conversation
The tint that shows a mask's extent sits exactly over the area its Burn, Feather and Grade sliders change, so the change was judged through a yellow or blue veil. The fill now steps aside for the gesture: press a slider or grab a vertex and it goes, release and it comes back. Outlines and handles stay, so the mask is still findable while the picture under it is clear. Every mask whose tinted area meets the one being worked on drops its fill too. Stacked tints hide the area worst, and adjusting a mask that lies on top of an existing one was the case with nothing to see through. overlapping_masks() rasterises each mask on a coarse grid in raw-normalised space, through the same rasteriser the render, the canvas tint and the printing-notes map already share. That keeps the awkward shapes honest for free: a card edge covers its whole exposed side, an inverted mask covers its surround, and a polygon's area is its smoothed outline, which bulges about a tenth of an edge past the control points. Raw space also makes the answer rotation-, zoom- and pan-invariant, since geometry moves every mask together. The set is fixed when the gesture starts rather than recomputed per frame: a vertex dragged across a neighbour would otherwise make it blink. A tint counts as present above alpha 0.25, so masks sharing a feather tail mute together while ones a clear gap apart do not — at the default feather that boundary sits between a gap of 0.05 and 0.20 of the frame. Drawing a brand-new mask over an existing one is not covered: there is no selected mask yet and an unclosed polygon has no area to intersect. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Icodextrin
marked this pull request as ready for review
August 18, 2026 16:05
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The canvas tint that shows a Dodge & Burn mask's extent now mutes for the duration of an edit gesture. This also applies to any other masks that overlap with the mask being modified.
Why
The previous workflow required manually hiding the mask, tweaking the values, then revealing the mask if you needed to change the area again. This change makes dodge and burn tweaks more ergonomic.
How overlap is decided
overlapping_masks()(negpy/features/local/logic.py) rasterises each mask on a coarse grid in raw-normalised space, through the samerasterise()that the render, the canvas tint and the printing-notes map already share. Consequences worth noting:Reviewer notes
_try_start_vertex_editwas restructured to a single exit so the mute and the repaint happen once instead of being duplicated across its two branches. Behaviour is unchanged: the insert branch is polygon-only, so the oval-center anchor still resolves toNonethere.docs/PIPELINE.mdchange.docs/USER_GUIDE.mdgains one bullet in the Dodge & Burn section.Testing
tests/test_local_overlap.pycovers the pure overlap function: symmetry, feather reach in both directions, card edge, invert, and unfinished/missing masks.tests/test_local_overlay.pyrebuilt around three masks (selected / crossing / clear) and asserts through a real paint onto a QImage that the first two go to alpha 0 while the third keeps its tint — for both a slider drag and a vertex drag.tests/test_local_sidebar.pyasserts all three sliders emit the drag signal on grab and release.make allclean: lint, types, 4285 passed / 11 skipped.