pickTopAtScene function
Node?
pickTopAtScene(
- CanvasSceneDocument doc,
- Vec2 worldPos, {
- required ComputedScene computed,
- bool includeLocked = false,
- bool selectLeaf = false,
- Set<
NodeId> ignoreIds = const {}, - NodeHitTest? extraFilter,
- double viewportZoom = 1.0,
- double minPathHitSlopScreenPx = 6.0,
Pick the topmost node at worldPos (canvas/world space).
Selection rule:
- default: select nearest group ancestor (LogoNode/GroupNode) if selectable
- selectLeaf=true: select the leaf if selectable (else fallback to group)
Filtering:
- locked filtering applies to what you RETURN (unless includeLocked=true)
- ignoreIds is subtree-aware via DrawItem.groupStack
Picking semantics:
- fill-area hit follows path geometry; open subpaths are treated as implicitly closed for containment
- vector picking is selection-oriented and may be more permissive than exact painted output
- paths/icons also use outline proximity
- thin strokes get a minimum screen-space hit slop
Implementation
Node? pickTopAtScene(
CanvasSceneDocument doc, // kept for API symmetry; not used internally
Vec2 worldPos, {
required ComputedScene computed,
bool includeLocked = false,
bool selectLeaf = false,
Set<NodeId> ignoreIds = const {},
NodeHitTest? extraFilter,
double viewportZoom = 1.0,
double minPathHitSlopScreenPx = 6.0,
}) {
final drawList = computed.drawList;
// Topmost first: drawList is back-to-front paint order.
for (var i = drawList.length - 1; i >= 0; i--) {
final item = drawList[i];
final leafId = item.leafId;
// Subtree-aware ignore: if any ancestor group is ignored, skip this leaf.
if (_anyGroupIgnored(item, ignoreIds)) continue;
if (ignoreIds.contains(leafId)) continue;
final leaf = computed.nodeById[leafId];
if (leaf == null) continue;
if (!includeLocked && leaf.locked) continue;
if (extraFilter != null && !extraFilter(leaf)) continue;
if (!_hitLeafAt(
leafId,
leaf,
worldPos,
computed,
viewportZoom: viewportZoom,
minPathHitSlopScreenPx: minPathHitSlopScreenPx,
)) {
continue;
}
final picked = _choosePickedNode(
leaf: leaf,
groupStack: item.groupStack,
computed: computed,
ignoreIds: ignoreIds,
includeLocked: includeLocked,
preferLeaf: selectLeaf,
);
if (picked != null) return picked;
}
return null;
}