L
ling-wallet
↓ 0 downloadsLing Wallet: a post-quantum privacy-coin wallet, full node and HyperTorus miner for LNG
Keywords wallet, cryptocurrency, lng, node, miner, ling
lingfu install ling-walletCode / Files (116)
ling/ui/input.ling
# input.ling — per-frame input, focus + Tab order, clip stack, clipboard,
# toasts and tooltips. All state lives in the st_* store.
bind KEY_NAMES = ["tab", "enter", "escape", "v", "a", "c", "l", "1", "2", "3", "4", "5", "6", "7"]
fn u_begin(t) {
bind mx = mouse_x()
bind my = mouse_y()
bind dn = sel(mouse_down(), 1, 0)
bind scr = mouse_scroll()
if st_get("shot", 0) > 0 {
bind mx = 0 - 1000
bind my = 0 - 1000
bind dn = 0
bind scr = 0
}
bind prev = st_get("md", 0)
bind moved = mx != st_get("mx", 0) || my != st_get("my", 0)
st_set("mp", sel(dn > 0 && prev < 1, 1, 0))
st_set("md", dn)
st_set("mx", mx)
st_set("my", my)
st_set("scroll", scr)
bind ctrl = key_down("lctrl") || key_down("rctrl")
bind shift = key_down("lshift") || key_down("rshift")
st_set("ctrl", sel(ctrl, 1, 0))
st_set("shift", sel(shift, 1, 0))
bind any = false
bind i = 0
while i < len(KEY_NAMES) {
bind k = list_get(KEY_NAMES, i)
bind p = key_pressed(k)
st_set("k_" + k, sel(p, 1, 0))
if p { bind any = true }
bind i = i + 1
}
if st_get("shot", 0) > 0 {
bind any = false
bind j = 0
while j < len(KEY_NAMES) {
st_set("k_" + list_get(KEY_NAMES, j), 0)
bind j = j + 1
}
}
if key_down("backspace") && st_get("shot", 0) < 1 { bind any = true }
# Fold typed keys into the text buffer every loop, not only on frames that
# redraw: keys from an unpolled frame are lost, and a change has to count
# as input or the field only repaints on the 0.3 s caret tick.
if st_get("text_owner", "") != "" {
bind tb = text_poll()
if tb != st_get("tb_last", "") {
st_set("tb_last", tb)
bind any = true
}
}
st_set("now", t)
st_lclear("order")
st_set("focus_claimed", 0)
st_set("tip", "")
st_set("clip_n", 0)
px_unclip()
if dn < 1 && st_get("mp", 0) < 1 { st_set("active", "") }
bind input = moved || dn > 0 || scr != 0 || any
if input { st_set("activity_t", t) }
return input
}
fn u_now() { return st_get("now", 0) }
fn u_mx() { return st_get("mx", 0) }
fn u_my() { return st_get("my", 0) }
fn u_pressed() { return st_get("mp", 0) > 0 }
fn u_down() { return st_get("md", 0) > 0 }
fn u_ctrl() { return st_get("ctrl", 0) > 0 }
fn u_shift() { return st_get("shift", 0) > 0 }
# A key pressed this frame and not yet consumed by a widget.
fn u_key(k) { return st_get("k_" + k, 0) > 0 }
fn u_eat(k) { st_set("k_" + k, 0) }
fn u_hover(x, y, w, h) {
if st_get("active", "") != "" { return false }
if !in_rect(u_mx(), u_my(), x, y, w, h) { return false }
if st_get("clip_n", 0) > 0 {
return in_rect(u_mx(), u_my(), st_get("clip_x", 0), st_get("clip_y", 0), st_get("clip_w", 0), st_get("clip_h", 0))
}
return true
}
# Wheel delta in px while the pointer is over the rect.
fn u_scroll_in(x, y, w, h) {
if in_rect(u_mx(), u_my(), x, y, w, h) { return round(0 - st_get("scroll", 0) * 40) }
return 0
}
fn u_blink() {
if st_get("shot", 0) > 0 { return true }
bind t = u_now() * 1.8
return t - floor(t) < 0.6
}
# Nested clipping: each push intersects with the current clip.
fn clip_push(x, y, w, h) {
bind n = st_get("clip_n", 0)
bind cx = x
bind cy = y
bind cw = w
bind ch = h
if n > 0 {
bind px0 = st_get("clip_x", 0)
bind py0 = st_get("clip_y", 0)
bind px1 = px0 + st_get("clip_w", 0)
bind py1 = py0 + st_get("clip_h", 0)
bind cx = max(x, px0)
bind cy = max(y, py0)
bind cw = max(0, min(x + w, px1) - cx)
bind ch = max(0, min(y + h, py1) - cy)
}
st_lset("clip_stack", n * 4, st_get("clip_x", 0))
st_lset("clip_stack", n * 4 + 1, st_get("clip_y", 0))
st_lset("clip_stack", n * 4 + 2, st_get("clip_w", 0))
st_lset("clip_stack", n * 4 + 3, st_get("clip_h", 0))
st_set("clip_n", n + 1)
st_set("clip_x", cx)
st_set("clip_y", cy)
st_set("clip_w", cw)
st_set("clip_h", ch)
px_clip(cx, cy, max(cw, 0), max(ch, 0))
}
fn clip_pop() {
bind n = st_get("clip_n", 0) - 1
if n < 0 { return () }
st_set("clip_n", n)
if n == 0 {
px_unclip()
return ()
}
bind x = st_lget("clip_stack", n * 4)
bind y = st_lget("clip_stack", n * 4 + 1)
bind w = st_lget("clip_stack", n * 4 + 2)
bind h = st_lget("clip_stack", n * 4 + 3)
st_set("clip_x", x)
st_set("clip_y", y)
st_set("clip_w", w)
st_set("clip_h", h)
px_clip(x, y, w, h)
}
# Focus: every field registers in the Tab order as it is drawn.
fn focus_get() { return st_get("focus", "") }
fn focus_set(id) { st_set("focus", id) }
fn focus_next_frame() {
st_set("autofocus", 1)
st_set("focus", "")
}
fn u_end() {
bind n = st_llen("order")
if u_key("tab") && n > 0 {
bind f = focus_get()
bind pos = 0 - 1
bind i = 0
while i < n {
if st_lget("order", i) == f { bind pos = i }
bind i = i + 1
}
bind next = 0
if pos >= 0 {
bind next = sel(u_shift(), (pos + n - 1) % n, (pos + 1) % n)
}
focus_set(st_lget("order", next))
}
if u_pressed() && st_get("focus_claimed", 0) < 1 { focus_set("") }
bind f2 = focus_get()
if f2 != "" {
bind found = false
bind j = 0
while j < n {
if st_lget("order", j) == f2 { bind found = true }
bind j = j + 1
}
if !found { focus_set("") }
}
if st_get("autofocus", 0) > 0 && n > 0 {
if focus_get() == "" { focus_set(st_lget("order", 0)) }
st_set("autofocus", 0)
}
if focus_get() == "" { st_set("text_owner", "") }
px_unclip()
st_set("clip_n", 0)
draw_tip()
draw_toast()
}
# Clipboard and toasts.
fn clip_copy(text, what) {
daw_clipboard_set(text)
toast(what + " copied to clipboard")
}
fn clip_paste() { return str_trim(str_replace(str_replace(daw_clipboard_get(), "\r", " "), "\n", " ")) }
fn toast(msg) {
st_set("toast", msg)
st_set("toast_t", u_now())
}
fn toast_live() { return st_get("toast", "") != "" }
fn draw_toast() {
bind msg = st_get("toast", "")
if msg == "" { return () }
bind age = u_now() - st_get("toast_t", 0)
if age > 1.8 && st_get("shot", 0) < 1 {
st_set("toast", "")
return ()
}
bind a = sel(age > 1.4 && st_get("shot", 0) < 1, (1.8 - age) / 0.4, 1)
bind w = round(t_w(F_UI, 16, msg)) + 40
bind sw = get_width()
bind x = round((sw - w) / 2) + 112
bind y = get_height() - 64
fill_a(x, y, w, 36, hex_to_number("0a0c10"), a)
outline(x, y, w, 36, C_GREEN, a)
brackets(x, y, w, 36, 6, lift(C_GREEN, 0.3), a)
t_mid(F_UI, 16, x + 20, y + 18, msg, C_TEXT_STRONG)
}
fn u_tip(x, y, w, h, s) {
if u_hover(x, y, w, h) {
st_set("tip", s)
st_set("tip_x", u_mx())
st_set("tip_y", u_my())
}
}
fn draw_tip() {
bind s = st_get("tip", "")
if s == "" { return () }
bind w = round(t_w(F_UI, 15, s)) + 20
bind x = max(8, min(st_get("tip_x", 0), get_width() - w - 8))
bind y = st_get("tip_y", 0) + 20
fill(x, y, w, 28, hex_to_number("0c0d10"))
outline(x, y, w, 28, C_LINE, 1)
t_mid(F_UI, 15, x + 10, y + 14, s, C_TEXT)
}