M3.86: Alt-click the mask thumbnail to view only the mask

transparency.viewOpacityMask {on?, id?} shows only the opacity mask on the
canvas as greyscale coverage (luminance, clip and invert applied; the rest of
the art hidden) and enters mask editing; called again it shows the artwork and
keeps editing. The Transparency panel's mask thumbnail runs it on Alt-click and
is outlined in the accent colour while the mask is viewed. The state is
DocState.mask_view (shown while that mask is edited: DocState::shown_mask) and
reaches the renderer as RenderOptions.mask_view.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bflatastic
2026-10-05 03:11:04 +07:00
co-authored by Claude Opus 5.5
parent cbdef4ea1f
commit 03571affbd
9 changed files with 241 additions and 30 deletions
+11
View File
@@ -101,6 +101,9 @@ pub struct DocState {
pub last_selection_cmd: Option<(String, Value)>,
/// Process-unique id of this open document (tab indices shift when tabs close).
pub uid: u64,
/// View Opacity Mask (Alt-click the mask thumbnail): the masked object whose mask the canvas
/// shows alone, in greyscale, while that mask is edited (see [`DocState::shown_mask`]).
pub mask_view: Option<NodeId>,
}
static NEXT_DOC_UID: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(1);
@@ -122,6 +125,7 @@ impl DocState {
last_transform: None,
last_selection_cmd: None,
uid: NEXT_DOC_UID.fetch_add(1, std::sync::atomic::Ordering::Relaxed),
mask_view: None,
}
}
/// Unsaved changes: the document differs from the saved one (selection changes don't count).
@@ -154,6 +158,11 @@ impl DocState {
}
self.active_layer.filter(|l| self.doc.node(*l).is_some_and(|n| n.is_layer() && !n.locked)).or_else(|| self.doc.default_layer())
}
/// The object whose opacity mask View Opacity Mask shows ([`DocState::mask_view`]): only while
/// its mask is being edited, so leaving editing by any route (undo, deleting the object) ends it.
pub fn shown_mask(&self) -> Option<NodeId> {
self.mask_view.filter(|id| self.doc.mask_edit.is_some_and(|m| m.object == *id))
}
}
/// Coordinates beyond this (points) are rejected: ~1,400 m, far past Illustrator's large canvas.
@@ -827,6 +836,8 @@ mod tests_linked_stops;
#[cfg(test)]
mod tests_live;
#[cfg(test)]
mod tests_maskview;
#[cfg(test)]
mod tests_menucmds;
#[cfg(test)]
mod tests_opacitymask;