ludic/packages/ludic.ui/pointer_pick.ludic

53 lines
2 KiB
Text

# pointer_pick.ludic - what the pointer is on: the topmost element under it in painting order (a
# positioned one by its z-index over the flow), and from there out to the nearest element that wants
# what is asked - a control to press, or pointer events. pointer-events: none lets it through.
const PK_CONTROL: int = 0
const PK_POINTER: int = 1
const PK_WHEEL: int = 2
function fr_in(n: UiNode, px: float, py: float) -> bool {
if n.ex != null and n.ex.no_pointer { return false }
return px >= n.x and py >= n.y and px < n.x + n.cw and py < n.y + n.ch
}
# the nearest element that wants `kind`, out from the topmost one under the point: the children are
# walked the other way from how they are painted (positioned ones by z-index, highest first, then
# the flow, last first; a popover is on the top layer, not here), with no list made for it
function fr_pick(n: UiNode, px: float, py: float, kind: int) -> UiNode {
if n.children == null { return fr_wants(n, kind) }
var lo = 1000000
var hi = -1000000
for i in 0 .. len(n.children) {
let c = n.children[i]
if c.pos != 0 and not c.popover {
lo = Math.min(lo, c.z)
hi = Math.max(hi, c.z)
}
}
var z = hi
while z >= lo {
var i = len(n.children) - 1
while i >= 0 {
let c = n.children[i]
if c.pos != 0 and not c.popover and c.z == z and fr_in(c, px, py) { return fr_pick_in(n, c, px, py, kind) }
i -= 1
}
z -= 1
}
var k = len(n.children) - 1
while k >= 0 {
let c = n.children[k]
if c.pos == 0 and not c.popover and fr_in(c, px, py) { return fr_pick_in(n, c, px, py, kind) }
k -= 1
}
return fr_wants(n, kind)
}
function fr_pick_in(n: UiNode, c: UiNode, px: float, py: float, kind: int) -> UiNode {
let r = fr_pick(c, px, py, kind)
if r != null { return r }
return fr_wants(n, kind)
}
function fr_wants(n: UiNode, kind: int) -> UiNode {
if kind == PK_CONTROL and (n.focusable or n.act != null) { return n }
if kind == PK_POINTER and pe_wants(n, false) { return n }
if kind == PK_WHEEL and pe_wants(n, true) { return n }
return null
}