# 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- 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 }