灵符lingfu
L

ling-wallet

↓ 0 downloads

Ling Wallet: a post-quantum privacy-coin wallet, full node and HyperTorus miner for LNG

Windows · x86-64 ✕Linux · x86-64 ✕LingOS · x86-64LingOS · Pi 5 ARM64 ✕
Keywords wallet, cryptocurrency, lng, node, miner, ling
lingfu install ling-wallet
LicenseMIT
Authorsling-lin
READMECode / FilesVersionsDependency GraphDependentsSecurityBuildsSettings

Code / 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)
}

← Back to index