- `popover`: a top layer that keeps the pointer and the keyboard, closed by a press outside or Esc. - `title` tooltips after half a second's rest, styled by .ui-tooltip. - `<progress>` and `<meter>`. - Atlases take rows and number cells, and importing ludic.ui/render3d.ludic is enough to draw with render3d. - The compiler reports two declarations of one name before it type-checks, so a package global clashing with a program's reads as that, not as 29 type errors. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
59 lines
2.2 KiB
Text
59 lines
2.2 KiB
Text
# pointer.ludic - the pointer: what it is over is :hover (the element and all around it, as in CSS),
|
|
# a press on a control focuses it and makes it :active, and letting go over it is a click. The
|
|
# control being dragged (a range's thumb, a scrollbar) keeps the pointer until it is let go.
|
|
var fr_hover: []string = new []string
|
|
var fr_press_key: string = ""
|
|
var fr_down_now: bool = false
|
|
function fr_was_hovered(key: string) -> bool { return sel_has(fr_hover, key) }
|
|
function fr_pointer(root: UiNode) -> void {
|
|
let i = in_now
|
|
fr_down_now = i.down
|
|
let keys = new []string
|
|
let top = pp_top(root)
|
|
var scope = root
|
|
if top != null { scope = top }
|
|
fr_under(scope, i.x, i.y, keys)
|
|
fr_hover = keys
|
|
tt_track(scope, i.x, i.y)
|
|
if top != null and pp_pointer(top) { return }
|
|
let hit = fr_hit(scope, i.x, i.y)
|
|
if i.down and not in_was_down {
|
|
fr_press_key = ""
|
|
if hit != null {
|
|
fr_press_key = hit.key
|
|
if hit.focusable { ui_focus(hit.key) }
|
|
ct_press(hit, i.x, i.y)
|
|
}
|
|
}
|
|
if i.down and fr_press_key != "" { ct_drag(root, fr_press_key, i.x, i.y) }
|
|
if not i.down and in_was_down {
|
|
if hit != null and hit.key == fr_press_key and hit.enabled { ct_activate(hit) }
|
|
fr_press_key = ""
|
|
}
|
|
}
|
|
function fr_under(n: UiNode, px: float, py: float, keys: []string) -> void {
|
|
if px < n.x or py < n.y or px >= n.x + n.cw or py >= n.y + n.ch { return }
|
|
if n.key != "" { push(keys, n.key) }
|
|
for i in 0 .. len(n.children) { fr_under(n.children[i], px, py, keys) }
|
|
}
|
|
# the deepest control (or pressable element) under the pointer
|
|
function fr_hit(n: UiNode, px: float, py: float) -> UiNode {
|
|
if px < n.x or py < n.y or px >= n.x + n.cw or py >= n.y + n.ch { return null }
|
|
var i = len(n.children) - 1
|
|
while i >= 0 {
|
|
let h = fr_hit(n.children[i], px, py)
|
|
if h != null { return h }
|
|
i -= 1
|
|
}
|
|
if n.focusable or n.act != null { return n }
|
|
return null
|
|
}
|
|
export function ui_hit(root: UiNode, px: float, py: float) -> UiNode { return fr_hit(root, px, py) }
|
|
function fr_node(n: UiNode, key: string) -> UiNode {
|
|
if n.key == key { return n }
|
|
for i in 0 .. len(n.children) {
|
|
let f = fr_node(n.children[i], key)
|
|
if f != null { return f }
|
|
}
|
|
return null
|
|
}
|