87 lines
3.6 KiB
Text
87 lines
3.6 KiB
Text
# pointer_events.ludic - on-pointerdown, on-pointermove, on-pointerup, on-wheel and on-drag on any
|
|
# element, with event.x / event.y inside it, event.dx / event.dy, event.button and event.wheel; a
|
|
# native takes the same through ui_native_input. A press captures the pointer until it is let go.
|
|
export property UiPointer {
|
|
kind: string = "" # pointerdown, pointermove, pointerup, wheel or drag
|
|
x: float = 0.0 # inside the element
|
|
y: float = 0.0
|
|
dx: float = 0.0 # how far the pointer moved this frame
|
|
dy: float = 0.0
|
|
button: int = 0 # 0 the left button, 1 the right, 2 the middle
|
|
wheel: float = 0.0
|
|
}
|
|
const PE_NAMES: string = " pointerdown pointermove pointerup wheel drag "
|
|
function pe_wants(n: UiNode, wheel: bool) -> bool {
|
|
if n.kind == UI_NATIVE and n.native != null and n.native.input != null { return true }
|
|
if n.on_names == null { return false }
|
|
for i in 0 .. len(n.on_names) {
|
|
if wheel and n.on_names[i] == "wheel" { return true }
|
|
if not wheel and lk_in(PE_NAMES, n.on_names[i]) { return true }
|
|
}
|
|
return false
|
|
}
|
|
# the pointer's events this frame: to what captured it, else to what it is over
|
|
function pe_frame(ui_st: mut UiState, root: UiNode, scope: UiNode) -> void {
|
|
let i = ui_st.in_now
|
|
let p = ui_st.in_last
|
|
let moved = p.x >= 0.0 and (i.x != p.x or i.y != p.y)
|
|
var over: UiNode = null
|
|
if fr_in(scope, i.x, i.y) { over = fr_pick(scope, i.x, i.y, PK_POINTER) }
|
|
if ui_st.pe_key != "" {
|
|
let c = fr_node(root, ui_st.pe_key)
|
|
if c != null and moved { pe_send(ui_st, c, "pointermove", ui_st.pe_btn) }
|
|
if c != null and moved { pe_send(ui_st, c, "drag", ui_st.pe_btn) }
|
|
if not (i.down or i.down_right or i.down_middle) {
|
|
if c != null { pe_send(ui_st, c, "pointerup", ui_st.pe_btn) }
|
|
ui_st.pe_key = ""
|
|
}
|
|
} else if over != null {
|
|
let b = pe_pressed(i, p)
|
|
if b >= 0 { pe_down(ui_st, over, b) } else if moved { pe_send(ui_st, over, "pointermove", 0) }
|
|
}
|
|
if i.wheel != 0.0 and over != null { pe_send(ui_st, over, "wheel", 0) }
|
|
}
|
|
function pe_pressed(i: UiInput, p: UiInput) -> int {
|
|
if i.down and not p.down { return 0 }
|
|
if i.down_right and not p.down_right { return 1 }
|
|
if i.down_middle and not p.down_middle { return 2 }
|
|
return -1
|
|
}
|
|
function pe_down(ui_st: mut UiState, n: UiNode, b: int) -> void {
|
|
ui_st.pe_key = n.key
|
|
ui_st.pe_btn = b
|
|
if not pe_send(ui_st, n, "pointerdown", b) { ui_st.pe_key = "" }
|
|
}
|
|
# one event: a native's input answers at once (false: not its to take); an element's on-<kind> runs
|
|
# once the frame is drawn, with the pointer's fields on `event`
|
|
function pe_send(ui_st: mut UiState, n: UiNode, kind: string, b: int) -> bool {
|
|
let e = ui_st.pe_evs[ui_st.pe_at]
|
|
let v = ui_st.pe_vals[ui_st.pe_at]
|
|
ui_st.pe_at = (ui_st.pe_at + 1) % PE_RING
|
|
e.dx = 0.0
|
|
e.dy = 0.0
|
|
e.kind = kind
|
|
e.x = ui_st.in_now.x - n.x
|
|
e.y = ui_st.in_now.y - n.y
|
|
if ui_st.in_last.x >= 0.0 {
|
|
e.dx = ui_st.in_now.x - ui_st.in_last.x
|
|
e.dy = ui_st.in_now.y - ui_st.in_last.y
|
|
}
|
|
e.button = b
|
|
e.wheel = ui_st.in_now.wheel
|
|
if n.kind == UI_NATIVE and n.native != null and n.native.input != null { return n.native.input(n, e) }
|
|
Value.be_float(Value.get(v, "x"), e.x)
|
|
Value.be_float(Value.get(v, "y"), e.y)
|
|
Value.be_float(Value.get(v, "dx"), e.dx)
|
|
Value.be_float(Value.get(v, "dy"), e.dy)
|
|
Value.be_int(Value.get(v, "button"), b)
|
|
Value.be_float(Value.get(v, "wheel"), e.wheel)
|
|
ui_fire(ui_st, n, kind, v)
|
|
return true
|
|
}
|
|
# a scroll box leaves the wheel to what is under the pointer inside it and takes it itself
|
|
function pe_takes_wheel(box: UiNode, px: float, py: float) -> bool {
|
|
let t = fr_pick(box, px, py, PK_WHEEL)
|
|
return t != null and t != box
|
|
}
|
|
|