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/theme.ling
# theme.ling — LingStation "Black" palette, fonts and text helpers.
# Colours are packed 0xRRGGBB numbers. Text helpers take a baseline;
# px_text itself wants the top of the line box.
bind C_BG = hex_to_number("000000")
bind C_BG_DEEP = hex_to_number("020203")
bind C_PANEL = hex_to_number("060607")
bind C_SIDE = hex_to_number("08090b")
bind C_ROW_HOVER = hex_to_number("0e1014")
bind C_ROW_ACTIVE = hex_to_number("101216")
bind C_LINE = hex_to_number("3c3c3c")
bind C_LINE_SOFT = hex_to_number("2a2c32")
bind C_LINE_FAINT = hex_to_number("16171b")
bind C_TEXT = hex_to_number("cdd0d8")
bind C_TEXT_DIM = hex_to_number("8c9098")
bind C_TEXT_FAINT = hex_to_number("5a5e66")
bind C_TEXT_STRONG = hex_to_number("f5f5f5")
bind C_SEL = hex_to_number("005c80")
bind C_QR_PLATE = hex_to_number("e9ebf0")
bind C_QR_DARK = hex_to_number("050608")
bind C_RED = hex_to_number("ed4a37")
bind C_ORANGE = hex_to_number("f7941e")
bind C_YELLOW = hex_to_number("f7d846")
bind C_GREEN = hex_to_number("45c870")
bind C_BLUE = hex_to_number("3baaeb")
bind C_INDIGO = hex_to_number("4a64d8")
bind C_VIOLET = hex_to_number("9a53d6")
bind C_METER_G = hex_to_number("5ad278")
bind C_METER_Y = hex_to_number("fac850")
bind C_METER_R = hex_to_number("ff5a40")
# Layout rhythm.
bind SIDE_W = 224
bind TOP_H = 56
bind PAD = 24
# Font slots, loaded in this order by fonts_load() so the handles equal the slots.
bind F_UI = 0
bind F_HEAD = 1
bind F_MONO = 2
bind F_LOGO = 3
# Ascender and cap height per slot, in em (from the fonts' OS/2 tables).
bind FONT_ASC = [0.93, 1.011, 0.8, 0.75]
bind FONT_CAP = [0.643, 0.72, 0.56, 0.7]
fn fonts_load() {
# Font file names, loaded in order into slots 0..3. We try two base dirs so
# the app finds its fonts whether the working directory is the ling/ folder
# (dev: `lingfu run`) or the folder beside a packed exe (a desktop build run
# from dist/, where the assets sit under ling/assets/). This mirrors how
# install_seeds() locates the shipped seed list in real_backend.ling.
bind names = ["Rajdhani.ttf", "Orbitron.ttf", "VT323-Regular.ttf", "Daemon.otf"]
bind bases = ["assets/fonts/", "ling/assets/fonts/"]
bind i = 0
bind good = true
while i < len(names) {
bind h = 0 - 1
bind b = 0
while b < len(bases) && h != i {
bind h = font_load(list_get(bases, b) + list_get(names, i))
bind b = b + 1
}
if h != i {
println("font missing: ", list_get(names, i))
bind good = false
}
bind i = i + 1
}
return good
}
fn roygbiv(i) {
bind k = floor(i) % 7
if k == 0 { return C_RED }
if k == 1 { return C_ORANGE }
if k == 2 { return C_YELLOW }
if k == 3 { return C_GREEN }
if k == 4 { return C_BLUE }
if k == 5 { return C_INDIGO }
return C_VIOLET
}
fn c_r(c) { return floor(c / 65536) }
fn c_g(c) { return floor(c / 256) % 256 }
fn c_b(c) { return c % 256 }
fn c_rgb(r, g, b) { return round(r) * 65536 + round(g) * 256 + round(b) }
fn mix(a, b, t) {
bind k = clampf(t, 0, 1)
return c_rgb(c_r(a) + (c_r(b) - c_r(a)) * k, c_g(a) + (c_g(b) - c_g(a)) * k, c_b(a) + (c_b(b) - c_b(a)) * k)
}
# LingStation lifts accents toward white so line work reads on black.
fn lift(c, t) { return mix(c, 16777215, t) }
fn shade(c, t) { return mix(c, 0, t) }
fn sel(cond, a, b) {
if cond { return a }
return b
}
fn clampf(v, lo, hi) {
if v < lo { return lo }
if v > hi { return hi }
return v
}
# Text drawn with its baseline at `base`; returns the advance.
fn t_text(f, size, x, base, s, col) {
if s == "" { return 0 }
px_text(f, x, base - list_get(FONT_ASC, f) * size, size, col, s)
return font_width(f, size, s)
}
fn t_w(f, size, s) { return font_width(f, size, s) }
fn t_cap(f, size) { return round(list_get(FONT_CAP, f) * size) }
# Letter-spaced text (one glyph per call, so keep it to short strings).
fn t_text_sp(f, size, x, base, s, col, sp) {
bind top = base - list_get(FONT_ASC, f) * size
bind n = str_len(s)
bind px = x
bind i = 0
while i < n {
bind ch = substr(s, i, 1)
if ch != " " { px_text(f, px, top, size, col, ch) }
bind px = px + font_width(f, size, ch) + sp
bind i = i + 1
}
if n > 0 { return px - x - sp }
return 0
}
fn t_w_sp(f, size, s, sp) {
bind n = str_len(s)
if n == 0 { return 0 }
return font_width(f, size, s) + sp * (n - 1)
}
# Vertically centred on `mid` by cap height.
fn t_mid(f, size, x, mid, s, col) { return t_text(f, size, x, mid + t_cap(f, size) / 2, s, col) }
fn t_right(f, size, xr, base, s, col) {
bind w = font_width(f, size, s)
t_text(f, size, xr - w, base, s, col)
return w
}
fn t_center(f, size, x, y, w, h, s, col) {
bind tw = font_width(f, size, s)
t_mid(f, size, x + round((w - tw) / 2), y + round(h / 2), s, col)
}
# Small-caps label: uppercase Rajdhani 13 px with 1.4 px tracking.
fn label(x, base, s, col) { return t_text_sp(F_UI, 13, x, base, str_upper(s), col, 1.4) }
fn label_w(s) { return t_w_sp(F_UI, 13, str_upper(s), 1.4) }
fn label_r(xr, base, s, col) {
bind w = label_w(s)
label(xr - w, base, s, col)
return w
}
# Shorten with ".." so it fits maxw. px_fit re-measures once per dropped char,
# so cut long strings (key bundles) to what could ever fit first: no glyph is
# narrower than 0.1 em.
fn t_fit(f, size, maxw, s) {
bind cap = ceil(maxw / max(1, size * 0.1)) + 2
if str_len(s) > cap { return px_fit(f, size, maxw, substr(s, 0, cap)) }
return px_fit(f, size, maxw, s)
}
# Greedy word wrap; returns a list of lines.
fn t_wrap(f, size, s, maxw) {
bind out = []
bind paras = str_split(s, "\n")
bind p = 0
while p < len(paras) {
bind words = str_split(list_get(paras, p), " ")
bind cur = ""
bind i = 0
while i < len(words) {
bind wd = list_get(words, i)
if wd != "" {
bind trial = sel(cur == "", wd, cur + " " + wd)
if cur != "" && font_width(f, size, trial) > maxw {
bind out = list_push(out, cur)
bind cur = wd
} else {
bind cur = trial
}
}
bind i = i + 1
}
bind out = list_push(out, cur)
bind p = p + 1
}
return out
}
# Wrapped paragraph whose first line's cap top sits at `top`; returns the height used.
fn t_para(f, size, x, top, maxw, lh, s, col) {
bind lines = t_wrap(f, size, s, maxw)
bind cap = t_cap(f, size)
bind i = 0
while i < len(lines) {
t_text(f, size, x, top + cap + i * lh, list_get(lines, i), col)
bind i = i + 1
}
return len(lines) * lh
}
# Index of a string in a list, or -1.
fn index_of(l, v) {
bind i = 0
bind found = 0 - 1
while i < len(l) {
if found < 0 && list_get(l, i) == v { bind found = i }
bind i = i + 1
}
return found
}