2670 lines
135 KiB
Text
2670 lines
135 KiB
Text
use mod.prelude.widgets_internal.*
|
|
|
|
// Art nouveau. The ground is aged cream parchment, its fibre and a faint warm
|
|
// mottle drawn at the device pixel; the window is held in a frame of deep
|
|
// teal enamel bands edged with bronze-gold wire, the panes set in it with
|
|
// rounded corners, and the only ornament (lilies, leaves, whiplash stems and
|
|
// tendrils, all drawn as curves) grows in the frame's corners and the
|
|
// corners of the big surfaces, never behind words or controls.
|
|
// A control is an ENAMEL face set in a bronze CLOISON: a raised wire of
|
|
// bronze-gold round a flat matte enamel (teal for the working colour, ochre
|
|
// for the primary action, terracotta for the one that deletes, ivory or
|
|
// parchment for the quiet ones), or a WELL of ivory sunk into the parchment
|
|
// behind the same wire. Knobs and thumbs are bronze, lamps are cabochons of
|
|
// coloured glass in bronze settings, screens deep teal glass with amber
|
|
// figures. The light falls from the upper left.
|
|
|
|
// A ROW OF FIELDS IS ONE HEIGHT. The box metrics are stated once here and
|
|
// handed to each field below, so the search box, the number beside it and
|
|
// the drop-down after it stand at one height.
|
|
let field_height = 28.0
|
|
let field_pad_v = mod.theme.mspace_1.top
|
|
let field_radius = 8.0
|
|
// A hairline, for the few stock fields the faces below do not redraw.
|
|
let field_border = 0.5
|
|
|
|
let field_room = fn(w) {
|
|
w.min_height = field_height
|
|
w.padding.top = field_pad_v
|
|
w.padding.bottom = field_pad_v
|
|
}
|
|
let field_face = fn(d) {
|
|
d.border_radius = field_radius
|
|
d.border_size = field_border
|
|
}
|
|
// A field that lays its own parts out inside a frame: only the height.
|
|
let field_frame = fn(w) {
|
|
w.min_height = field_height
|
|
}
|
|
|
|
field_room(mod.widgets.TextInput)
|
|
field_face(mod.widgets.TextInput.draw_bg)
|
|
field_room(mod.widgets.TextInputFlat)
|
|
field_room(mod.widgets.ComboBox)
|
|
field_face(mod.widgets.ComboBox.draw_bg)
|
|
field_room(mod.widgets.DropDown)
|
|
field_face(mod.widgets.DropDown.draw_bg)
|
|
field_room(mod.widgets.DropDown2)
|
|
field_face(mod.widgets.DropDown2.draw_bg)
|
|
field_room(mod.widgets.FieldWell)
|
|
field_face(mod.widgets.FieldWell.draw_bg)
|
|
field_room(mod.widgets.TagField)
|
|
field_face(mod.widgets.TagField.draw_bg)
|
|
field_frame(mod.widgets.NumberField)
|
|
mod.widgets.NumberField.draw_bg.border_radius = field_radius
|
|
field_frame(mod.widgets.ValueInput)
|
|
field_frame(mod.widgets.DateField)
|
|
field_frame(mod.widgets.TimeField)
|
|
field_frame(mod.widgets.DatePicker)
|
|
field_frame(mod.widgets.DateRangePicker)
|
|
mod.widgets.WellInput.min_height = 0.0
|
|
mod.widgets.Window.pass.clear_color = #d8c29c
|
|
|
|
// Plain views stop clipping, so a shadow or a lip may fall into the gap
|
|
// beside its control. Scroll views keep their own clip.
|
|
mod.widgets.View.clip_x = false
|
|
mod.widgets.View.clip_y = false
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SHARED PARTS. Distances in points, negative inside, y down; `px` is one
|
|
// device pixel in points.
|
|
|
|
let g3 = fn(v: float) -> vec3 {
|
|
return vec3(v, v, v)
|
|
}
|
|
|
|
// The palette.
|
|
let an_ink = fn() -> vec3 {
|
|
return vec3(0.165, 0.129, 0.086)
|
|
}
|
|
let an_ivory = fn() -> vec3 {
|
|
return vec3(0.953, 0.910, 0.812)
|
|
}
|
|
let an_parch_c = fn() -> vec3 {
|
|
return vec3(0.847, 0.761, 0.612)
|
|
}
|
|
let an_well_c = fn() -> vec3 {
|
|
return vec3(0.922, 0.875, 0.769)
|
|
}
|
|
let an_teal = fn() -> vec3 {
|
|
return vec3(0.275, 0.388, 0.353)
|
|
}
|
|
let an_teal_dk = fn() -> vec3 {
|
|
return vec3(0.184, 0.282, 0.259)
|
|
}
|
|
let an_teal_lt = fn() -> vec3 {
|
|
return vec3(0.420, 0.545, 0.490)
|
|
}
|
|
let an_ochre = fn() -> vec3 {
|
|
return vec3(0.851, 0.659, 0.341)
|
|
}
|
|
let an_terra = fn() -> vec3 {
|
|
return vec3(0.627, 0.290, 0.212)
|
|
}
|
|
let an_sage = fn() -> vec3 {
|
|
return vec3(0.776, 0.784, 0.678)
|
|
}
|
|
let an_bronze_c = fn() -> vec3 {
|
|
return vec3(0.776, 0.608, 0.318)
|
|
}
|
|
let an_bronze_dk = fn() -> vec3 {
|
|
return vec3(0.380, 0.270, 0.110)
|
|
}
|
|
let an_gold_hi = fn() -> vec3 {
|
|
return vec3(0.988, 0.894, 0.643)
|
|
}
|
|
let an_line_c = fn() -> vec3 {
|
|
return vec3(0.690, 0.510, 0.220)
|
|
}
|
|
let an_shade = fn() -> vec3 {
|
|
return vec3(0.180, 0.120, 0.050)
|
|
}
|
|
let an_glass_c = fn() -> vec3 {
|
|
return vec3(0.129, 0.208, 0.188)
|
|
}
|
|
|
|
// A rounded box, true radius.
|
|
let md_rbox = fn(p: vec2, c: vec2, h: vec2, r: float) -> float {
|
|
let rr = clamp(r, 0.0, min(h.x, h.y))
|
|
let q = abs(p - c) - h + vec2(rr, rr)
|
|
return min(max(q.x, q.y), 0.0) + length(max(q, vec2(0.0, 0.0))) - rr
|
|
}
|
|
|
|
// A rounded box with a radius per corner (tl, tr, br, bl).
|
|
let md_r4 = fn(p: vec2, c: vec2, h: vec2, r4: vec4) -> float {
|
|
let q0 = p - c
|
|
let rt = mix(r4.y, r4.x, step(q0.x, 0.0))
|
|
let rb = mix(r4.z, r4.w, step(q0.x, 0.0))
|
|
return clamp(mix(rb, rt, step(q0.y, 0.0)), 0.0, min(h.x, h.y))
|
|
}
|
|
let md_rbox4 = fn(p: vec2, c: vec2, h: vec2, r4: vec4) -> float {
|
|
return md_rbox(p, c, h, md_r4(p, c, h, r4))
|
|
}
|
|
|
|
// The outward normal of a rounded box at `p`.
|
|
let an_nrm = fn(p: vec2, c: vec2, h: vec2, r: float) -> vec2 {
|
|
let q0 = p - c
|
|
let sx = mix(-1.0, 1.0, step(0.0, q0.x))
|
|
let sy = mix(-1.0, 1.0, step(0.0, q0.y))
|
|
let rr = clamp(r, 0.0, min(h.x, h.y))
|
|
let q = abs(q0) - h + vec2(rr, rr)
|
|
var n = vec2(0.0, 1.0)
|
|
if q.x > 0.0 && q.y > 0.0 {
|
|
n = q / max(length(q), 0.0001)
|
|
} else {
|
|
if q.x > q.y {
|
|
n = vec2(1.0, 0.0)
|
|
}
|
|
}
|
|
return vec2(n.x * sx, n.y * sy)
|
|
}
|
|
|
|
// The corners a button group asks for: a corner written as 0 is a square
|
|
// join, any other the family's radius.
|
|
let md_corners = fn(tl: float, tr: float, br: float, bl: float, r: float) -> vec4 {
|
|
return vec4(mix(r, step(0.5, tl) * r, step(0.0, tl)), mix(r, step(0.5, tr) * r, step(0.0, tr)), mix(r, step(0.5, br) * r, step(0.0, br)), mix(r, step(0.5, bl) * r, step(0.0, bl)))
|
|
}
|
|
|
|
let md_seg = fn(p: vec2, a: vec2, b: vec2) -> float {
|
|
let pa = p - a
|
|
let ba = b - a
|
|
let k = clamp(dot(pa, ba) / max(dot(ba, ba), 0.0001), 0.0, 1.0)
|
|
return length(pa - ba * k)
|
|
}
|
|
|
|
let md_grow = fn(rp: vec2, rs: vec2, m: float) -> vec4 {
|
|
return vec4(rp.x - m, rp.y - m, rs.x + 2.0 * m, rs.y + 2.0 * m)
|
|
}
|
|
|
|
// THE PARCHMENT at a point `w` (points) in the surface's own space: a faint
|
|
// warm mottle in two slow octaves (a few per cent, wide and soft, so no
|
|
// stain reads as a blotch), sparse short fibres -- a darker and a paler set,
|
|
// each the contour of a stretched noise, so they wander -- and a grain of
|
|
// one device pixel.
|
|
let an_parch = fn(w: vec2, px: float, base: vec3) -> vec3 {
|
|
let m = Finish.noise(w * 0.0065) * 0.6 + Finish.noise(w * 0.019 + vec2(3.1, 7.7)) * 0.4 - 0.5
|
|
var col = base * (1.0 + 0.055 * m) + vec3(0.010, 0.002, -0.012) * m
|
|
let n1 = Finish.noise(vec2(w.x * 0.055 + w.y * 0.012, w.y * 0.42 - w.x * 0.05))
|
|
let k1 = Finish.noise(w * 0.035 + vec2(9.0, 2.0))
|
|
let f1 = (1.0 - smoothstep(0.0, 0.016, abs(n1 - 0.5))) * smoothstep(0.6, 0.8, k1)
|
|
let n2 = Finish.noise(vec2(w.y * 0.06 - w.x * 0.02, w.x * 0.38 + w.y * 0.07) + vec2(17.0, 5.0))
|
|
let k2 = Finish.noise(w * 0.03 + vec2(1.0, 13.0))
|
|
let f2 = (1.0 - smoothstep(0.0, 0.014, abs(n2 - 0.5))) * smoothstep(0.64, 0.82, k2)
|
|
col = mix(col, col * 0.88, f1 * 0.32)
|
|
col = mix(col, min(col * 1.03 + vec3(0.01, 0.01, 0.008), vec3(1.0, 1.0, 1.0)), f2 * 0.22)
|
|
// the tooth of the skin: a fine streaky noise across the grain
|
|
let tooth = Finish.noise(vec2(w.x * 0.9 + w.y * 0.3, w.y * 0.22 - w.x * 0.08)) - 0.5
|
|
col = col * (1.0 + tooth * 0.022)
|
|
return col + g3(Finish.grain(w / px, 0.010))
|
|
}
|
|
|
|
// A RAISED BRONZE WIRE `w` points wide lying just inside an edge: `d` the
|
|
// edge's distance (negative inside), `n` its outward normal. Lit from the
|
|
// upper left: the half of the wire that faces the light catches a warm
|
|
// highlight, the other half falls toward dark bronze; a dark hairline at
|
|
// both of its edges keeps it crisp on any ground. Premultiplied.
|
|
let an_wire = fn(d: float, n: vec2, w: float, px: float, glint: float) -> vec4 {
|
|
let u = clamp(-d / max(w, 0.01), 0.0, 1.0)
|
|
let k = 1.0 - 2.0 * u
|
|
let bulge = sqrt(max(1.0 - k * k, 0.0))
|
|
let facing = dot(n * k, vec2(-0.42, -0.91))
|
|
var col = mix(an_bronze_dk(), an_bronze_c(), 0.35 + 0.65 * bulge)
|
|
col = col * (0.80 + 0.32 * facing)
|
|
col = mix(col, an_gold_hi(), smoothstep(0.2, 0.85, facing * 0.8 + 0.3 * bulge) * 0.6 * glint)
|
|
let e = Finish.band(d, 0.0, px, px) + Finish.band(d, w - px, w, px)
|
|
col = mix(col, an_bronze_dk() * 0.75, clamp(e, 0.0, 1.0) * 0.5)
|
|
let a = Finish.band(d, 0.0, w, px)
|
|
return vec4(col * a, a)
|
|
}
|
|
|
|
// A fine gold line `lw` wide at `d` = -`at` (inside an edge): the inner line
|
|
// of a frame within a frame.
|
|
let an_fine = fn(d: float, at: float, lw: float, px: float, amt: float) -> vec4 {
|
|
let a = Finish.band(d, at, at + lw, px) * amt
|
|
let col = mix(an_line_c(), an_gold_hi(), 0.35)
|
|
return vec4(col * a, a)
|
|
}
|
|
|
|
// The soft shadow a raised part throws on the parchment, straight down and
|
|
// a little to the right, in warm sepia. Premultiplied.
|
|
let an_drop = fn(p: vec2, c: vec2, h: vec2, r: float, amt: float) -> vec4 {
|
|
let t = Finish.drop(p, c, h, r, vec2(0.3, 0.9), 0.6) * 0.30 * amt
|
|
let s = Finish.drop(p, c, h, r, vec2(0.5, 1.7), 1.5) * 0.14 * amt
|
|
let a = t + s * (1.0 - t)
|
|
return vec4(an_shade() * a, a)
|
|
}
|
|
|
|
// The tight contact shadow of a part with no room round it for the soft
|
|
// one: gone a point and a half under its edge.
|
|
let an_contact = fn(p: vec2, c: vec2, h: vec2, r: float, amt: float) -> vec4 {
|
|
let a = Finish.drop(p, c, h, r, vec2(0.0, 0.45), 0.3) * 0.28 * amt
|
|
return vec4(an_shade() * a, a)
|
|
}
|
|
|
|
// A FLAT MATTE ENAMEL face inside its cloison (`c`, `h`, `r` the enamel's
|
|
// own box): a broad soft light across its upper part, a faint unevenness of
|
|
// the paint, and the shade the wire throws into it under the top edge.
|
|
// Lifted a shade under the pointer; pressed, it sinks: darker, with the
|
|
// wire's shade deeper.
|
|
let an_enamel = fn(p: vec2, c: vec2, h: vec2, r: float, base: vec3, hover: float, press: float) -> vec3 {
|
|
let t = clamp((p.y - (c.y - h.y)) / max(2.0 * h.y, 1.0), 0.0, 1.0)
|
|
var col = base * (1.05 - 0.10 * t)
|
|
col = mix(col, Finish.lift(col, 0.10), (1.0 - smoothstep(0.05, 0.6, t)) * 0.55 * (1.0 - press))
|
|
let mott = (Finish.noise(p * 0.7 + vec2(5.0, 1.0)) - 0.5) * 0.022 + (Finish.noise(p * 0.09 + vec2(2.0, 8.0)) - 0.5) * 0.012
|
|
col = col * (1.0 + mott)
|
|
col = Finish.lift(col, 0.15 * hover * (1.0 - press))
|
|
col = mix(col, col * 0.82, press)
|
|
let sh = clamp(Finish.inset(p, c, h, r, vec2(0.0, 0.8 + 1.2 * press), 0.8 + 0.6 * press), 0.0, 1.0)
|
|
col = mix(col, an_shade(), sh * (0.24 + 0.26 * press))
|
|
return col
|
|
}
|
|
|
|
// Focus: a teal ring of a device pixel and a half, two points outside.
|
|
let md_focus = fn(d: float, px: float, focus: float) -> vec4 {
|
|
let f = Finish.ring_out(d, 1.5, 1.5 + 1.5 * px, px) * 0.9 * focus
|
|
let c = vec3(0.184, 0.435, 0.384)
|
|
return vec4(c * f, f)
|
|
}
|
|
|
|
// A SUNK IVORY WELL behind its wire: the fill, the shade falling in under
|
|
// the top edge, the bronze wire round it and a light lip on the parchment
|
|
// under its foot. `fill` its colour; `wire` the wire's width.
|
|
let an_well = fn(p: vec2, c: vec2, h: vec2, r: float, px: float, fill: vec3, shade: float, wire: float, dis: float) -> vec4 {
|
|
let d = md_rbox(p, c, h, r)
|
|
let n = an_nrm(p, c, h, r)
|
|
let hi = h - vec2(wire, wire)
|
|
var col = fill
|
|
let sh = clamp(Finish.inset(p, c, hi, max(r - wire, 0.0), vec2(0.0, 1.4), 1.2), 0.0, 1.0)
|
|
col = mix(col, an_shade(), sh * shade)
|
|
let a = Finish.cover(d, px)
|
|
var out = vec4(0.0, 0.0, 0.0, 0.0)
|
|
let lip = Finish.ring_out(d, 0.0, px, px) * smoothstep(0.0, h.y * 0.8, p.y - c.y) * 0.45
|
|
out = Finish.over(out, vec4(vec3(0.98, 0.95, 0.88) * lip, lip))
|
|
out = Finish.over(out, vec4(col * a, a))
|
|
let wv = an_wire(d, n, wire, px, 1.0 - dis)
|
|
return Finish.over(out, wv * mix(1.0, 0.55, dis))
|
|
}
|
|
|
|
// An indicator jewel set in a cap: used where a stock face carries a lamp.
|
|
let md_led = fn(p: vec2, lc: vec2, rad: float, px: float, ink: vec3, lit: float, glow: float) -> vec4 {
|
|
let q = p - lc
|
|
let d = length(q) - rad
|
|
let k = clamp(length(q) / max(rad, 0.001), 0.0, 1.0)
|
|
let on = mix(Finish.lift(ink, 0.25), ink * 0.85, smoothstep(0.2, 1.0, k))
|
|
let off = vec3(0.12, 0.13, 0.11)
|
|
var col = mix(off, on, lit)
|
|
col = mix(col, an_bronze_c(), Finish.band(d, 0.0, max(px, 0.6), px))
|
|
let a = Finish.cover(d, px)
|
|
let ha = glow * lit * exp(-max(d, 0.0) / 0.7) * step(0.0, d) * (1.0 - a)
|
|
var out = vec4(ink * ha, ha)
|
|
return Finish.over(out, vec4(col * a, a))
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// THE BOTANICAL ORNAMENT. Every part is a curve, drawn at the device pixel.
|
|
|
|
// A leaf or a petal: a lens `len` long from its base `b` along the unit
|
|
// direction `dir`, `wid` wide either side of its midline at its widest, the
|
|
// midline bowed by `bend` points. Returns the signed distance, the side
|
|
// across it (-1..1) and the way along it (0..1).
|
|
let an_leaf = fn(p: vec2, b: vec2, dir: vec2, len: float, wid: float, bend: float) -> vec4 {
|
|
let q = p - b
|
|
let u = dot(q, dir)
|
|
let t = clamp(u / max(len, 0.01), 0.0, 1.0)
|
|
let v = dot(q, vec2(0.0 - dir.y, dir.x)) - bend * 4.0 * t * (1.0 - t)
|
|
let hw = wid * 4.0 * t * (1.0 - t) * (1.15 - 0.3 * t)
|
|
let slope = wid * 4.0 * (1.0 - 2.0 * t) / max(len, 0.01)
|
|
let dv = (abs(v) - hw) / sqrt(1.0 + slope * slope)
|
|
let du = max(0.0 - u, u - len)
|
|
return vec4(max(dv, du), v / max(hw, 0.3), t, 0.0)
|
|
}
|
|
|
|
// The distance to a quadratic curve from `a` through the pull of `b` to `c`
|
|
// (.x), and how far along it the nearest point lies (.y, 0..1).
|
|
let an_bez = fn(pos: vec2, A: vec2, B: vec2, C: vec2) -> vec2 {
|
|
let a = B - A
|
|
let b = A - 2.0 * B + C
|
|
let c = a * 2.0
|
|
let d = A - pos
|
|
let kk = 1.0 / max(dot(b, b), 0.0001)
|
|
let kx = kk * dot(a, b)
|
|
let ky = kk * (2.0 * dot(a, a) + dot(d, b)) / 3.0
|
|
let kz = kk * dot(d, a)
|
|
let p = ky - kx * kx
|
|
let p3 = p * p * p
|
|
let q = kx * (2.0 * kx * kx - 3.0 * ky) + kz
|
|
var h = q * q + 4.0 * p3
|
|
var res = 0.0
|
|
var tt = 0.0
|
|
if h >= 0.0 {
|
|
h = sqrt(h)
|
|
let x0 = (h - q) * 0.5
|
|
let x1 = (0.0 - h - q) * 0.5
|
|
let u0 = sign(x0) * pow(abs(x0), 1.0 / 3.0)
|
|
let u1 = sign(x1) * pow(abs(x1), 1.0 / 3.0)
|
|
tt = clamp(u0 + u1 - kx, 0.0, 1.0)
|
|
let e = d + (c + b * tt) * tt
|
|
res = dot(e, e)
|
|
} else {
|
|
let z = sqrt(0.0 - p)
|
|
let v = acos(clamp(q / (p * z * 2.0), -1.0, 1.0)) / 3.0
|
|
let m = cos(v)
|
|
let n = sin(v) * 1.732050808
|
|
let t0 = clamp((m + m) * z - kx, 0.0, 1.0)
|
|
let t1 = clamp((0.0 - n - m) * z - kx, 0.0, 1.0)
|
|
let e0 = d + (c + b * t0) * t0
|
|
let e1 = d + (c + b * t1) * t1
|
|
let r0 = dot(e0, e0)
|
|
let r1 = dot(e1, e1)
|
|
res = min(r0, r1)
|
|
tt = mix(t1, t0, step(r0, r1))
|
|
}
|
|
return vec2(sqrt(res), tt)
|
|
}
|
|
|
|
// An open spiral, a tendril's curl: `pitch` points between its turns,
|
|
// `turns` of them out from its eye `c`, its outer end at the angle `rot`.
|
|
let an_spiral = fn(p: vec2, c: vec2, pitch: float, turns: float, rot: float) -> float {
|
|
let q = p - c
|
|
let r = length(q)
|
|
var th = atan2(q.y, q.x) - rot
|
|
th = (th - floor(th / (2.0 * PI)) * 2.0 * PI) / (2.0 * PI)
|
|
let k = clamp(floor(r / pitch - th + 0.5), 0.0, turns - 1.0)
|
|
return abs(r - pitch * (th + k))
|
|
}
|
|
|
|
// Lays a filled shape of distance `d` over `dst`: its fill, and a
|
|
// bronze-gold outline `lw` points wide inside its edge.
|
|
let an_lay = fn(dst: vec4, d: float, fill: vec3, lw: float, px: float) -> vec4 {
|
|
let a = Finish.cover(d, px)
|
|
let l = Finish.band(d, 0.0, lw, px)
|
|
let col = mix(fill, an_line_c(), clamp(l / max(a, 0.001), 0.0, 1.0) * 0.9)
|
|
return Finish.over(dst, vec4(col * a, a))
|
|
}
|
|
|
|
// A leaf laid with its two halves in two greens (the half toward the light
|
|
// paler), a gold midrib, a gold outline.
|
|
let an_lay_leaf = fn(dst: vec4, l: vec4, dark: vec3, light: vec3, lw: float, px: float) -> vec4 {
|
|
var fill = mix(dark, light, smoothstep(-0.15, 0.15, l.y))
|
|
fill = mix(fill, fill * 0.85, smoothstep(0.6, 1.0, l.z) * 0.4)
|
|
let rib = (1.0 - smoothstep(0.05, 0.16, abs(l.y))) * step(l.z, 0.88) * 0.6
|
|
fill = mix(fill, an_line_c(), rib)
|
|
return an_lay(dst, l.x, fill, lw, px)
|
|
}
|
|
|
|
// A petal: from a dusty rose throat to a cream tip.
|
|
let an_lay_petal = fn(dst: vec4, l: vec4, root: vec3, tip: vec3, lw: float, px: float) -> vec4 {
|
|
var fill = mix(root, tip, smoothstep(0.1, 0.75, l.z))
|
|
fill = mix(fill, fill * 0.88, smoothstep(0.2, 1.0, abs(l.y)) * 0.35)
|
|
return an_lay(dst, l.x, fill, lw, px)
|
|
}
|
|
|
|
// A stem: a tapering stroke along a curve, green with gold edges.
|
|
let an_lay_stem = fn(dst: vec4, b: vec2, w0: float, w1: float, fill: vec3, px: float) -> vec4 {
|
|
let d = b.x - mix(w0, w1, b.y)
|
|
return an_lay(dst, d, fill, min(0.6, mix(w0, w1, b.y) * 0.5), px)
|
|
}
|
|
|
|
let an_dir = fn(a: float) -> vec2 {
|
|
return vec2(cos(a), sin(a))
|
|
}
|
|
|
|
// A LILY seen from the front: three long petals behind, three shorter ones
|
|
// before them, curling back at their tips, a throat of `root` and three
|
|
// gold stamens. `s` its size; `rose` 0 for cream and ochre petals, 1 for
|
|
// dusty rose ones.
|
|
let an_lily = fn(dst: vec4, p: vec2, c: vec2, s: float, rot: float, px: float, rose: float) -> vec4 {
|
|
var out = dst
|
|
let root = mix(vec3(0.788, 0.553, 0.478), vec3(0.62, 0.40, 0.44), rose)
|
|
let tip = mix(vec3(0.965, 0.886, 0.690), vec3(0.88, 0.70, 0.68), rose)
|
|
let fr = mix(vec3(0.925, 0.733, 0.420), vec3(0.80, 0.55, 0.54), rose)
|
|
let lw = max(0.45, s * 0.045)
|
|
out = an_lay_petal(out, an_leaf(p, c, an_dir(rot), s, s * 0.26, s * 0.10), root, tip, lw, px)
|
|
out = an_lay_petal(out, an_leaf(p, c, an_dir(rot + 2.094), s, s * 0.26, s * 0.10), root, tip, lw, px)
|
|
out = an_lay_petal(out, an_leaf(p, c, an_dir(rot + 4.189), s, s * 0.26, s * 0.10), root, tip, lw, px)
|
|
out = an_lay_petal(out, an_leaf(p, c, an_dir(rot + 1.047), s * 0.82, s * 0.24, 0.0 - s * 0.08), root, fr, lw, px)
|
|
out = an_lay_petal(out, an_leaf(p, c, an_dir(rot + 3.142), s * 0.82, s * 0.24, 0.0 - s * 0.08), root, fr, lw, px)
|
|
out = an_lay_petal(out, an_leaf(p, c, an_dir(rot + 5.236), s * 0.82, s * 0.24, 0.0 - s * 0.08), root, fr, lw, px)
|
|
// the stamens
|
|
var st = 1000.0
|
|
st = min(st, md_seg(p, c, c + an_dir(rot + 0.5) * s * 0.58))
|
|
st = min(st, md_seg(p, c, c + an_dir(rot + 2.6) * s * 0.58))
|
|
st = min(st, md_seg(p, c, c + an_dir(rot + 4.7) * s * 0.58))
|
|
let sa = Finish.cover(st - max(0.3, s * 0.02), px)
|
|
out = Finish.over(out, vec4(an_line_c() * sa, sa))
|
|
var dots = 1000.0
|
|
dots = min(dots, length(p - (c + an_dir(rot + 0.5) * s * 0.58)))
|
|
dots = min(dots, length(p - (c + an_dir(rot + 2.6) * s * 0.58)))
|
|
dots = min(dots, length(p - (c + an_dir(rot + 4.7) * s * 0.58)))
|
|
out = an_lay(out, dots - max(0.6, s * 0.06), vec3(0.50, 0.27, 0.15), 0.0, px)
|
|
out = an_lay(out, length(p - c) - s * 0.11, vec3(0.70, 0.50, 0.22), lw, px)
|
|
return out
|
|
}
|
|
|
|
// A BUD: a closed petal in its two green sepals, on the end of a stem.
|
|
let an_bud = fn(dst: vec4, p: vec2, b: vec2, dir: vec2, s: float, px: float) -> vec4 {
|
|
var out = dst
|
|
let lw = max(0.45, s * 0.06)
|
|
out = an_lay_petal(out, an_leaf(p, b, dir, s, s * 0.30, 0.0), vec3(0.80, 0.55, 0.45), vec3(0.95, 0.80, 0.55), lw, px)
|
|
let side = vec2(0.0 - dir.y, dir.x)
|
|
out = an_lay_leaf(out, an_leaf(p, b, normalize(dir + side * 0.35), s * 0.55, s * 0.12, 0.0), vec3(0.24, 0.38, 0.32), vec3(0.42, 0.58, 0.48), lw, px)
|
|
out = an_lay_leaf(out, an_leaf(p, b, normalize(dir - side * 0.35), s * 0.55, s * 0.12, 0.0), vec3(0.24, 0.38, 0.32), vec3(0.42, 0.58, 0.48), lw, px)
|
|
return out
|
|
}
|
|
|
|
// A SPRIG for a surface's corner, in the corner's own frame: `p` in points
|
|
// from the corner along its two edges, both into the surface. It is drawn
|
|
// the same about the corner's diagonal, so it sits in any of the four: a
|
|
// whiplash stem bowed round the corner like a bracket, curling at both of
|
|
// its ends, a leaf on each arm, a larger pair at the corner and an ochre bud
|
|
// between them. `s` scales it (1 is about 38 points along each edge).
|
|
let an_sprig = fn(dst: vec4, p: vec2, s: float, px: float) -> vec4 {
|
|
var out = dst
|
|
let q = p / s
|
|
let pxs = px / s
|
|
let dk = vec3(0.220, 0.357, 0.306)
|
|
let lt = vec3(0.427, 0.580, 0.494)
|
|
let stem = vec3(0.290, 0.420, 0.357)
|
|
// fold onto one side of the diagonal for the mirrored arms
|
|
let m = vec2(min(q.x, q.y), max(q.x, q.y))
|
|
out = an_lay(out, an_spiral(m, vec2(4.6, 33.0), 1.5, 2.0, 0.0 - 1.4) - 0.42, stem, 0.25, pxs)
|
|
out = an_lay_stem(out, an_bez(m, vec2(3.0, 4.0), vec2(1.5, 18.0), vec2(5.1, 30.0)), 1.0, 0.45, stem, pxs)
|
|
out = an_lay_leaf(out, an_leaf(m, vec2(2.6, 15.0), normalize(vec2(1.0, 0.55)), 11.0, 2.4, 1.2), dk, lt, 0.38, pxs)
|
|
out = an_lay_leaf(out, an_leaf(q, vec2(3.0, 3.0), normalize(vec2(1.0, 0.45)), 16.0, 3.2, 2.2), dk, lt, 0.4, pxs)
|
|
out = an_lay_leaf(out, an_leaf(q, vec2(3.0, 3.0), normalize(vec2(0.45, 1.0)), 16.0, 3.2, -2.2), dk, lt, 0.4, pxs)
|
|
out = an_bud(out, q, vec2(3.5, 3.5), normalize(vec2(1.0, 1.0)), 11.0, pxs)
|
|
return out
|
|
}
|
|
|
|
// The sprig set into a box's corner `k` (0 top left, 1 top right, 2 bottom
|
|
// right, 3 bottom left), `ins` points in from its edges.
|
|
let an_corner = fn(dst: vec4, p: vec2, lo: vec2, hi: vec2, k: float, ins: float, s: float, px: float) -> vec4 {
|
|
let right = step(0.5, k) * step(k, 2.5)
|
|
let bottom = step(1.5, k)
|
|
let x = mix(p.x - lo.x, hi.x - p.x, right) - ins
|
|
let y = mix(p.y - lo.y, hi.y - p.y, bottom) - ins
|
|
if x > -2.0 && y > -2.0 && x < 42.0 * s && y < 42.0 * s {
|
|
return an_sprig(dst, vec2(x, y), s, px)
|
|
}
|
|
return dst
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// BUTTONS. One face for the family: an enamel pill in its bronze wire, a
|
|
// fine gold line inside the wire on the filled ones, a soft sepia shadow
|
|
// under it. `kind`: 0 teal enamel, 1 ochre (primary), 2 a peacock teal
|
|
// (secondary), 3 pale sage (tertiary), 4 terracotta (danger), 5 the outline
|
|
// (the parchment shows, a bronze wire and a teal line inside it), 6 bare
|
|
// until touched (flatter), 7 an ivory pill (the plain button). Pressed, the
|
|
// enamel sinks; the quad is grown by `m` for the shadow and the focus ring.
|
|
let an_kind_c = fn(kind: float) -> vec3 {
|
|
var c = an_teal()
|
|
c = mix(c, an_ochre(), step(0.5, kind) * step(kind, 1.5))
|
|
c = mix(c, vec3(0.224, 0.400, 0.420), step(1.5, kind) * step(kind, 2.5))
|
|
c = mix(c, an_sage(), step(2.5, kind) * step(kind, 3.5))
|
|
c = mix(c, an_terra(), step(3.5, kind) * step(kind, 4.5))
|
|
c = mix(c, vec3(0.906, 0.851, 0.737), step(4.5, kind))
|
|
return c
|
|
}
|
|
let an_button = fn(pos: vec2, size: vec2, o: vec2, px: float, hover: float, down: float, focus: float, dis: float, loading: float, anim: float, r4: vec4, kind: float, m: float) -> vec4 {
|
|
let p = pos * (size + vec2(2.0 * m, 2.0 * m)) - vec2(m, m)
|
|
let live = 1.0 - dis
|
|
let press = down * live
|
|
let lo = vec2(Finish.snap(o.x, px), Finish.snap(o.y, px)) - o
|
|
let hi = vec2(Finish.snap(o.x + size.x, px), Finish.snap(o.y + size.y, px)) - o
|
|
let c = (lo + hi) * 0.5
|
|
let h = (hi - lo) * 0.5
|
|
let r = md_r4(p, c, h, r4)
|
|
let d = md_rbox(p, c, h, r)
|
|
let n = an_nrm(p, c, h, r)
|
|
let wire = 1.6
|
|
let outline = step(4.5, kind) * step(kind, 5.5)
|
|
let bare = step(5.5, kind) * step(kind, 6.5)
|
|
let show = mix(1.0, clamp(hover * live * 0.8 + press, 0.0, 1.0), bare)
|
|
var out = an_drop(p, c, h, r, (1.0 - 0.65 * press) * mix(1.0, 0.45, dis) * (1.0 - outline) * show)
|
|
var base = an_kind_c(kind)
|
|
base = mix(base, mix(base, vec3(0.70, 0.69, 0.60), 0.62) * 1.08, dis)
|
|
let hf = h - vec2(wire, wire)
|
|
var face = an_enamel(p, c, hf, max(r - wire, 0.0), base, hover * live, press)
|
|
let fa = Finish.cover(d + wire * 0.5, px) * (1.0 - outline * (1.0 - max(press * 0.5, hover * live * 0.35)))
|
|
out = Finish.over(out, vec4(face * fa, fa) * show)
|
|
// the fine line inside the wire, on the filled enamels
|
|
let filled = 1.0 - step(4.5, kind)
|
|
out = Finish.over(out, an_fine(d, wire + 1.2, max(px, 0.55), px, 0.55 * filled * mix(1.0, 0.4, dis)))
|
|
// the outline's teal line inside the wire
|
|
let tl = Finish.band(d, wire + 0.8, wire + 0.8 + max(px, 0.6), px) * outline * mix(0.85, 0.4, dis)
|
|
out = Finish.over(out, vec4(an_teal_dk() * tl, tl))
|
|
let wv = an_wire(d, n, wire, px, mix(1.0, 0.3, dis) * (1.0 + 0.4 * hover * live))
|
|
out = Finish.over(out, wv * mix(1.0, 0.55, dis) * show)
|
|
out = Finish.over(out, md_focus(d, px, focus * live))
|
|
if loading > 0.0 {
|
|
let sdf = Sdf2d.viewport(p)
|
|
let rr = max(min(h.x, h.y) - 5.0, 2.0)
|
|
let a0 = anim * 2.0 * PI
|
|
sdf.arc_round_caps(c.x, c.y, rr, a0, a0 + 1.5 * PI, 1.2)
|
|
sdf.fill(vec4(0.165, 0.129, 0.086, loading))
|
|
out = Finish.over(out, sdf.result)
|
|
}
|
|
return out
|
|
}
|
|
|
|
// Every button template: the plain root (and the sizes, which share its draw
|
|
// object) wears the ivory pill; the roles are specialised below.
|
|
mod.widgets.ButtonFlat.clip_x = false
|
|
mod.widgets.ButtonFlat.clip_y = false
|
|
mod.widgets.ButtonFlat.draw_bg.vertex = fn() {
|
|
let g = md_grow(self.rect_pos, self.rect_size, 8.0)
|
|
self.vertex_pos = self.clip_and_transform_vertex(g.xy, g.zw)
|
|
}
|
|
mod.widgets.ButtonFlat.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
return self.host_over(an_button(self.pos, self.rect_size, self.rect_pos, px, self.hover, self.down, self.focus, self.disabled, self.loading, self.anim_time, md_corners(self.border_radius_tl, self.border_radius_tr, self.border_radius_br, self.border_radius_bl, 99.0), 7.0, 8.0), 8.0)
|
|
}
|
|
mod.widgets.Button.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
return self.host_over(an_button(self.pos, self.rect_size, self.rect_pos, px, self.hover, self.down, self.focus, self.disabled, self.loading, self.anim_time, md_corners(self.border_radius_tl, self.border_radius_tr, self.border_radius_br, self.border_radius_bl, 99.0), 0.0, 8.0), 8.0)
|
|
}
|
|
mod.widgets.ButtonPrimary.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
return self.host_over(an_button(self.pos, self.rect_size, self.rect_pos, px, self.hover, self.down, self.focus, self.disabled, self.loading, self.anim_time, md_corners(self.border_radius_tl, self.border_radius_tr, self.border_radius_br, self.border_radius_bl, 99.0), 1.0, 8.0), 8.0)
|
|
}
|
|
mod.widgets.ButtonSecondary.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
return self.host_over(an_button(self.pos, self.rect_size, self.rect_pos, px, self.hover, self.down, self.focus, self.disabled, self.loading, self.anim_time, md_corners(self.border_radius_tl, self.border_radius_tr, self.border_radius_br, self.border_radius_bl, 99.0), 2.0, 8.0), 8.0)
|
|
}
|
|
mod.widgets.ButtonTertiary.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
return self.host_over(an_button(self.pos, self.rect_size, self.rect_pos, px, self.hover, self.down, self.focus, self.disabled, self.loading, self.anim_time, md_corners(self.border_radius_tl, self.border_radius_tr, self.border_radius_br, self.border_radius_bl, 99.0), 3.0, 8.0), 8.0)
|
|
}
|
|
mod.widgets.ButtonDanger.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
return self.host_over(an_button(self.pos, self.rect_size, self.rect_pos, px, self.hover, self.down, self.focus, self.disabled, self.loading, self.anim_time, md_corners(self.border_radius_tl, self.border_radius_tr, self.border_radius_br, self.border_radius_bl, 99.0), 4.0, 8.0), 8.0)
|
|
}
|
|
mod.widgets.ButtonOutline.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
return self.host_over(an_button(self.pos, self.rect_size, self.rect_pos, px, self.hover, self.down, self.focus, self.disabled, self.loading, self.anim_time, md_corners(self.border_radius_tl, self.border_radius_tr, self.border_radius_br, self.border_radius_bl, 99.0), 5.0, 8.0), 8.0)
|
|
}
|
|
mod.widgets.ButtonFlatter.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
return self.host_over(an_button(self.pos, self.rect_size, self.rect_pos, px, self.hover, self.down, self.focus, self.disabled, self.loading, self.anim_time, md_corners(self.border_radius_tl, self.border_radius_tr, self.border_radius_br, self.border_radius_bl, 99.0), 6.0, 8.0), 8.0)
|
|
}
|
|
// The large button is the teal one, as in the pictures.
|
|
mod.widgets.ButtonLg.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
return self.host_over(an_button(self.pos, self.rect_size, self.rect_pos, px, self.hover, self.down, self.focus, self.disabled, self.loading, self.anim_time, md_corners(self.border_radius_tl, self.border_radius_tr, self.border_radius_br, self.border_radius_bl, 99.0), 0.0, 8.0), 8.0)
|
|
}
|
|
|
|
// Templates that draw a face of their own on top of these roots keep the
|
|
// plain quad: the grown one is only for the faces written here.
|
|
mod.widgets.CloseButton.draw_bg.vertex = fn() {
|
|
self.vertex_pos = self.clip_and_transform_vertex(self.rect_pos, self.rect_size)
|
|
}
|
|
mod.widgets.CopyButton.draw_bg.vertex = fn() {
|
|
self.vertex_pos = self.clip_and_transform_vertex(self.rect_pos, self.rect_size)
|
|
}
|
|
mod.widgets.BurgerButton.draw_bg.vertex = fn() {
|
|
self.vertex_pos = self.clip_and_transform_vertex(self.rect_pos, self.rect_size)
|
|
}
|
|
mod.widgets.ButtonFloating.draw_bg.vertex = fn() {
|
|
self.vertex_pos = self.clip_and_transform_vertex(self.rect_pos, self.rect_size)
|
|
}
|
|
mod.widgets.ButtonFloatingSm.draw_bg.vertex = fn() {
|
|
self.vertex_pos = self.clip_and_transform_vertex(self.rect_pos, self.rect_size)
|
|
}
|
|
mod.widgets.glass.CutButton.draw_bg.vertex = fn() {
|
|
self.vertex_pos = self.clip_and_transform_vertex(self.rect_pos, self.rect_size)
|
|
}
|
|
|
|
// Geometry: one 26 point row, 14 points either side of the word.
|
|
mod.widgets.ButtonFlat.padding = mod.turtle.Inset{left: 14.0 right: 14.0 top: 4.0 bottom: 4.0}
|
|
mod.widgets.Button.padding = mod.turtle.Inset{left: 14.0 right: 14.0 top: 4.0 bottom: 4.0}
|
|
mod.widgets.ButtonPrimary.padding = mod.turtle.Inset{left: 14.0 right: 14.0 top: 4.0 bottom: 4.0}
|
|
mod.widgets.ButtonSecondary.padding = mod.turtle.Inset{left: 14.0 right: 14.0 top: 4.0 bottom: 4.0}
|
|
mod.widgets.ButtonDanger.padding = mod.turtle.Inset{left: 14.0 right: 14.0 top: 4.0 bottom: 4.0}
|
|
mod.widgets.ButtonTertiary.padding = mod.turtle.Inset{left: 14.0 right: 14.0 top: 4.0 bottom: 4.0}
|
|
mod.widgets.ButtonOutline.padding = mod.turtle.Inset{left: 14.0 right: 14.0 top: 4.0 bottom: 4.0}
|
|
mod.widgets.ButtonIcon.padding = mod.turtle.Inset{left: 8.0 right: 8.0 top: 4.0 bottom: 4.0}
|
|
mod.widgets.Button.icon_walk = mod.turtle.Walk{width: 14.0 height: Fit}
|
|
mod.widgets.ButtonFlat.min_height = 26.0
|
|
mod.widgets.Button.min_height = 26.0
|
|
mod.widgets.ButtonXs.min_height = 0.0
|
|
mod.widgets.ButtonXs.padding = mod.turtle.Inset{left: 7.0 right: 7.0 top: 0.0 bottom: 0.0}
|
|
mod.widgets.ButtonXs.draw_text.text_style.font_size = 7.5
|
|
mod.widgets.ButtonSm.min_height = 0.0
|
|
|
|
// Words on the buttons: Cormorant semibold; ivory on the dark enamels, the
|
|
// sepia ink on the pale ones.
|
|
mod.widgets.ButtonFlat.draw_text.text_style.font_family = mod.theme.font_label.font_family
|
|
mod.widgets.ButtonFlat.draw_text.text_style.font_size = 10.5
|
|
mod.widgets.ButtonFlat.draw_text.color = #2a2116
|
|
mod.widgets.ButtonFlat.draw_text.color_hover = #1f180f
|
|
mod.widgets.ButtonFlat.draw_text.color_down = #1f180f
|
|
mod.widgets.ButtonFlat.draw_text.color_focus = #2a2116
|
|
mod.widgets.ButtonFlat.draw_text.color_disabled = #8c7a5c
|
|
mod.widgets.Button.draw_text.color = #f3e8cf
|
|
mod.widgets.Button.draw_text.color_hover = #fbf3e0
|
|
mod.widgets.Button.draw_text.color_down = #e6dac0
|
|
mod.widgets.Button.draw_text.color_focus = #f3e8cf
|
|
mod.widgets.Button.draw_text.color_disabled = #e8e2d0
|
|
// The icon on a teal button is ivory, whatever colour its caller asked for
|
|
// (the catalogue asks for the working ink, which a teal face would swallow).
|
|
mod.widgets.Button.draw_icon.get_color = fn() {
|
|
let base = self.eval_gradient()
|
|
let k = vec3(0.953, 0.910, 0.812)
|
|
return vec4(k * base.a, base.a) * self.opacity
|
|
}
|
|
mod.widgets.ButtonLg.draw_text.color = #f3e8cf
|
|
mod.widgets.ButtonLg.draw_text.color_hover = #fbf3e0
|
|
mod.widgets.ButtonLg.draw_text.color_down = #e6dac0
|
|
mod.widgets.ButtonLg.draw_text.color_focus = #f3e8cf
|
|
mod.widgets.ButtonLg.draw_text.text_style.font_size = 12.0
|
|
mod.widgets.ButtonPrimary.draw_text.color = #2a2116
|
|
mod.widgets.ButtonPrimary.draw_text.color_hover = #1f180f
|
|
mod.widgets.ButtonPrimary.draw_text.color_down = #1f180f
|
|
mod.widgets.ButtonPrimary.draw_text.color_focus = #2a2116
|
|
mod.widgets.ButtonPrimary.draw_text.color_disabled = #8c7a5c
|
|
mod.widgets.ButtonPrimary.draw_icon.color = #2a2116
|
|
mod.widgets.ButtonPrimary.draw_text.text_style = mod.theme.font_bold{font_size: 10.5}
|
|
mod.widgets.ButtonSecondary.draw_text.color = #f3e8cf
|
|
mod.widgets.ButtonSecondary.draw_text.color_hover = #fbf3e0
|
|
mod.widgets.ButtonSecondary.draw_text.color_down = #e6dac0
|
|
mod.widgets.ButtonSecondary.draw_text.color_focus = #f3e8cf
|
|
mod.widgets.ButtonSecondary.draw_icon.color = #f3e8cf
|
|
mod.widgets.ButtonSecondary.draw_text.text_style = mod.theme.font_label{font_size: 10.5}
|
|
mod.widgets.ButtonTertiary.draw_text.color = #24342f
|
|
mod.widgets.ButtonTertiary.draw_text.color_hover = #1a2622
|
|
mod.widgets.ButtonTertiary.draw_text.color_down = #1a2622
|
|
mod.widgets.ButtonTertiary.draw_text.color_focus = #24342f
|
|
mod.widgets.ButtonTertiary.draw_icon.color = #24342f
|
|
mod.widgets.ButtonTertiary.draw_text.text_style = mod.theme.font_label{font_size: 10.5}
|
|
mod.widgets.ButtonDanger.draw_text.color = #f3e8cf
|
|
mod.widgets.ButtonDanger.draw_text.color_hover = #fbf3e0
|
|
mod.widgets.ButtonDanger.draw_text.color_down = #e6dac0
|
|
mod.widgets.ButtonDanger.draw_text.color_focus = #f3e8cf
|
|
mod.widgets.ButtonDanger.draw_icon.color = #f3e8cf
|
|
mod.widgets.ButtonDanger.draw_text.text_style = mod.theme.font_bold{font_size: 10.5}
|
|
mod.widgets.ButtonOutline.draw_text.color = #24342f
|
|
mod.widgets.ButtonOutline.draw_text.color_hover = #1a2622
|
|
mod.widgets.ButtonOutline.draw_text.color_down = #1a2622
|
|
mod.widgets.ButtonOutline.draw_text.color_focus = #24342f
|
|
mod.widgets.ButtonOutline.draw_text.color_disabled = #8c7a5c
|
|
mod.widgets.ButtonOutline.draw_icon.color = #24342f
|
|
mod.widgets.ButtonFlat.draw_bg.loading_color = #2a2116
|
|
|
|
// The window's own buttons stand on the teal band: ivory strokes.
|
|
mod.widgets.DesktopButton.draw_bg.color = uniform(#f3e8cf)
|
|
mod.widgets.DesktopButton.draw_bg.color_hover = uniform(#fffaf0)
|
|
mod.widgets.DesktopButton.draw_bg.color_down = uniform(#e8dcc0)
|
|
mod.widgets.DesktopButton.draw_bg.bg_color_hover = uniform(#f3e8cf26)
|
|
mod.widgets.DesktopButton.draw_bg.bg_color_down = uniform(#f3e8cf40)
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// CHECK BOXES. A 14 point box with rounded corners in its bronze wire: clear,
|
|
// a sunk ivory well; set, teal enamel with an ivory check; mixed, teal with
|
|
// an ivory dash.
|
|
mod.widgets.CheckBoxFlat.clip_x = false
|
|
mod.widgets.CheckBoxFlat.clip_y = false
|
|
mod.widgets.CheckBoxFlat.draw_bg.vertex = fn() {
|
|
let g = md_grow(self.rect_pos, self.rect_size, 4.0)
|
|
self.vertex_pos = self.clip_and_transform_vertex(g.xy, g.zw)
|
|
}
|
|
mod.widgets.CheckBoxCustom.draw_bg.vertex = fn() {
|
|
self.vertex_pos = self.clip_and_transform_vertex(self.rect_pos, self.rect_size)
|
|
}
|
|
mod.widgets.CheckBoxFlat.padding = mod.turtle.Inset{left: 0.0 right: 3.0 top: 3.0 bottom: 3.0}
|
|
mod.widgets.CheckBoxFlat.label_walk.margin = mod.turtle.Inset{left: 22.0 right: 3.0 top: 0.0 bottom: 0.0}
|
|
mod.widgets.CheckBoxFlat.draw_bg.size = uniform(14.0)
|
|
mod.widgets.CheckBoxFlat.min_height = 24.0
|
|
mod.widgets.CheckBoxFlat.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let m = 4.0
|
|
let size = self.rect_size
|
|
let p = self.pos * (size + vec2(2.0 * m, 2.0 * m)) - vec2(m, m)
|
|
let o = self.rect_pos
|
|
let sz = self.size
|
|
let live = 1.0 - self.disabled
|
|
let x0 = mix(1.0, size.x - sz - 1.0, self.mark_at_end)
|
|
let lo = vec2(Finish.snap(o.x + x0, px), Finish.snap(o.y + (size.y - sz) * 0.5, px)) - o
|
|
let h = vec2(sz * 0.5, sz * 0.5)
|
|
let c = lo + h
|
|
let r = mix(3.5, h.y, step(20.0, self.border_radius))
|
|
let d = md_rbox(p, c, h, r)
|
|
let on = max(self.active, self.mixed)
|
|
let press = self.down * live
|
|
var fill = Finish.lift(an_well_c(), 0.6 * self.hover * live)
|
|
fill = mix(fill, mix(an_well_c(), an_parch_c(), 0.6), self.disabled)
|
|
var out = an_well(p, c, h, r, px, fill, 0.30 - 0.12 * self.hover * live, 1.3, self.disabled)
|
|
// the teal enamel when set
|
|
let hf = h - vec2(1.3, 1.3)
|
|
var tcol = an_enamel(p, c, hf, max(r - 1.3, 0.0), mix(an_teal(), vec3(0.62, 0.63, 0.55), self.disabled), self.hover * live, press)
|
|
let ta = Finish.cover(md_rbox(p, c, hf, max(r - 1.3, 0.0)), px) * on
|
|
out = Finish.over(out, vec4(tcol * ta, ta))
|
|
let k = sz / 14.0
|
|
let m0 = lo + vec2(3.6, 7.3) * k
|
|
let m1 = lo + vec2(6.0, 9.8) * k
|
|
let m2 = lo + vec2(10.6, 4.3) * k
|
|
let ck = min(md_seg(p, m0, m1), md_seg(p, m1, m2)) - 0.85 * k
|
|
let d0 = lo + vec2(4.0, 7.0) * k
|
|
let d1 = lo + vec2(10.0, 7.0) * k
|
|
let dash = md_seg(p, d0, d1) - 0.85 * k
|
|
let show_ck = self.active * (1.0 - self.mixed)
|
|
let mk = mix(Finish.cover(ck, px) * show_ck, Finish.cover(dash, px), self.mixed)
|
|
let ink = mix(an_ivory(), vec3(0.85, 0.82, 0.74), self.disabled)
|
|
out = Finish.over(out, vec4(ink * mk, mk))
|
|
let err = Finish.band(d, 0.0, 2.0 * px, px) * self.error
|
|
out = Finish.over(out, vec4(vec3(0.60, 0.20, 0.15) * err, err))
|
|
return Finish.over(out, md_focus(d, px, self.focus * live))
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// TOGGLES. A 38 by 16 point pill sunk in its wire: parchment-sage while off,
|
|
// teal enamel while on; riding in it a 12 point ivory disc in a bronze ring,
|
|
// a teal jewel at its middle, with its own small shadow.
|
|
let an_toggle = fn(pos: vec2, size: vec2, o: vec2, px: float, active: float, drag_pos: float, drag: float, hover: float, down: float, focus: float, dis: float, err: float, at_end: float, metal: float) -> vec4 {
|
|
let m = 4.0
|
|
let p = pos * (size + vec2(2.0 * m, 2.0 * m)) - vec2(m, m)
|
|
let live = 1.0 - dis
|
|
let tw = 38.0
|
|
let th = 16.0
|
|
let x0 = mix(1.0, size.x - tw - 1.0, at_end)
|
|
let lo = vec2(Finish.snap(o.x + x0, px), Finish.snap(o.y + (size.y - th) * 0.5, px)) - o
|
|
let c = lo + vec2(tw * 0.5, th * 0.5)
|
|
let h = vec2(tw * 0.5, th * 0.5)
|
|
let r = h.y
|
|
let d = md_rbox(p, c, h, r)
|
|
let on = active
|
|
var fill = mix(vec3(0.788, 0.769, 0.639), an_teal(), on)
|
|
fill = Finish.lift(fill, 0.10 * hover * live)
|
|
fill = mix(fill, mix(fill, vec3(0.80, 0.78, 0.70), 0.6), dis)
|
|
var out = an_well(p, c, h, r, px, fill, mix(0.38, 0.45, on), 1.3, dis)
|
|
let ea = Finish.band(d, 0.0, 2.0 * px, px) * err
|
|
out = Finish.over(out, vec4(vec3(0.60, 0.20, 0.15) * ea, ea))
|
|
// the disc
|
|
let kt = clamp(mix(on, drag_pos, drag), 0.0, 1.0)
|
|
let kr = 6.0
|
|
let kx = Finish.snap(o.x + lo.x + 2.0 + kr + kt * (tw - 4.0 - 2.0 * kr), px) - o.x
|
|
let kc = vec2(kx, c.y)
|
|
let press = down * live
|
|
out = Finish.over(out, an_drop(p, kc, vec2(kr, kr), kr, (0.9 - 0.5 * press) * mix(1.0, 0.4, dis)))
|
|
let q = p - kc
|
|
let kd = length(q) - kr
|
|
let kn = q / max(length(q), 0.001)
|
|
// the ivory (or, on the rocker, bronze) face, domed toward the light
|
|
let lit = clamp(0.5 - 0.5 * dot(q / kr, vec2(0.45, 0.85)), 0.0, 1.0)
|
|
var face = mix(mix(vec3(0.80, 0.74, 0.60), an_ivory(), lit), mix(an_bronze_dk(), an_gold_hi(), lit * 0.9), metal)
|
|
face = Finish.lift(face, 0.12 * hover * live * (1.0 - press))
|
|
face = mix(face, face * 0.9, press)
|
|
face = mix(face, mix(face, vec3(0.80, 0.78, 0.72), 0.6), dis)
|
|
let ka = Finish.cover(kd, px)
|
|
out = Finish.over(out, vec4(face * ka, ka))
|
|
out = Finish.over(out, an_wire(kd, kn, 1.3, px, live) * mix(1.0, 0.5, dis))
|
|
// the jewel: teal when on, a dark bead when off
|
|
let jd = length(q) - 2.0
|
|
var jc = mix(vec3(0.20, 0.22, 0.18), vec3(0.30, 0.62, 0.53), on * live)
|
|
jc = mix(jc, an_ivory(), (1.0 - smoothstep(0.0, 1.2, length(q - vec2(-0.6, -0.7)))) * 0.6)
|
|
out = an_lay(out, jd, jc, 0.4, px)
|
|
return Finish.over(out, md_focus(d, px, focus * live))
|
|
}
|
|
mod.widgets.ToggleFlat.label_walk.margin = mod.turtle.Inset{left: 46.0 right: 3.0 top: 0.0 bottom: 0.0}
|
|
mod.widgets.ToggleFlat.draw_bg.size = 14.0
|
|
mod.widgets.ToggleFlat.min_height = 24.0
|
|
mod.widgets.ToggleFlat.draw_bg.pill_aspect = 2.7143
|
|
mod.widgets.ToggleFlat.draw_bg.knob_inset = 7.0
|
|
mod.widgets.ToggleFlat.clip_x = false
|
|
mod.widgets.ToggleFlat.clip_y = false
|
|
mod.widgets.ToggleFlat.draw_bg.vertex = fn() {
|
|
let g = md_grow(self.rect_pos, self.rect_size, 4.0)
|
|
self.vertex_pos = self.clip_and_transform_vertex(g.xy, g.zw)
|
|
}
|
|
mod.widgets.ToggleFlat.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
return an_toggle(self.pos, self.rect_size, self.rect_pos, px, self.active, self.drag_pos, self.drag, self.hover, self.down, self.focus, self.disabled, self.error, self.mark_at_end, 0.0)
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// RADIOS. A round ivory well in its wire; chosen, a teal enamel disc fills
|
|
// it with an ivory pip at its middle.
|
|
let md_radio = fn(p: vec2, c: vec2, rad: float, px: float, hover: float, down: float, focus: float, active: float, dis: float) -> vec4 {
|
|
let live = 1.0 - dis
|
|
let q = p - c
|
|
let d = length(q) - rad
|
|
var fill = Finish.lift(an_well_c(), 0.6 * hover * live)
|
|
fill = mix(fill, mix(an_well_c(), an_parch_c(), 0.6), dis)
|
|
var out = an_well(p, c, vec2(rad, rad), rad, px, fill, 0.30 - 0.12 * hover * live, 1.3, dis)
|
|
let ir = rad - 2.6
|
|
let tcol = an_enamel(p, c, vec2(ir, ir), ir, mix(an_teal(), vec3(0.62, 0.63, 0.55), dis), hover * live, down * live)
|
|
let ta = Finish.cover(length(q) - ir, px) * active
|
|
out = Finish.over(out, vec4(tcol * ta, ta))
|
|
let pa = Finish.cover(length(q) - rad * 0.26, px) * active
|
|
out = Finish.over(out, vec4(mix(an_ivory(), vec3(0.85, 0.82, 0.74), dis) * pa, pa))
|
|
return Finish.over(out, md_focus(d, px, focus * live))
|
|
}
|
|
|
|
mod.widgets.RadioButtonFlat.clip_x = false
|
|
mod.widgets.RadioButtonFlat.clip_y = false
|
|
mod.widgets.RadioButtonFlat.draw_bg.vertex = fn() {
|
|
let g = md_grow(self.rect_pos, self.rect_size, 4.0)
|
|
self.vertex_pos = self.clip_and_transform_vertex(g.xy, g.zw)
|
|
}
|
|
mod.widgets.glass.RadioButton.draw_bg.vertex = fn() {
|
|
self.vertex_pos = self.clip_and_transform_vertex(self.rect_pos, self.rect_size)
|
|
}
|
|
mod.widgets.RadioButtonFlat.padding = mod.turtle.Inset{left: 0.0 right: 3.0 top: 3.0 bottom: 3.0}
|
|
mod.widgets.RadioButtonFlat.label_walk.margin = mod.turtle.Inset{left: 22.0 right: 3.0 top: 0.0 bottom: 0.0}
|
|
mod.widgets.RadioButtonFlat.draw_bg.size = uniform(14.0)
|
|
mod.widgets.RadioButtonFlat.min_height = 24.0
|
|
mod.widgets.RadioButtonFlat.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let m = 4.0
|
|
let p = self.pos * (self.rect_size + vec2(2.0 * m, 2.0 * m)) - vec2(m, m)
|
|
let o = self.rect_pos
|
|
let sz = self.size
|
|
let lo = vec2(Finish.snap(o.x + 1.0, px), Finish.snap(o.y + (self.rect_size.y - sz) * 0.5, px)) - o
|
|
let c = lo + vec2(sz * 0.5, sz * 0.5)
|
|
return md_radio(p, c, sz * 0.5, px, self.hover, self.down, self.focus, self.active, self.disabled)
|
|
}
|
|
// The flatter radio is its word alone: chosen, the word sits on a small
|
|
// ochre enamel pill; under the pointer a faint wash.
|
|
mod.widgets.RadioButtonFlatter.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let m = 4.0
|
|
let p = self.pos * (self.rect_size + vec2(2.0 * m, 2.0 * m)) - vec2(m, m)
|
|
let o = self.rect_pos
|
|
let live = 1.0 - self.disabled
|
|
let lo = vec2(Finish.snap(o.x - 3.0, px), Finish.snap(o.y + 1.0, px)) - o
|
|
let hi = vec2(Finish.snap(o.x + self.rect_size.x + 3.0, px), Finish.snap(o.y + self.rect_size.y - 1.0, px)) - o
|
|
let h = (hi - lo) * 0.5
|
|
let c = lo + h
|
|
let d = md_rbox(p, c, h, h.y)
|
|
let wash = Finish.cover(d, px) * 0.15 * self.hover * live * (1.0 - self.active)
|
|
var out = vec4(an_ochre() * wash, wash)
|
|
let face = an_enamel(p, c, h - vec2(1.2, 1.2), h.y, an_ochre(), 0.0, 0.0)
|
|
let a = Finish.cover(d, px) * self.active
|
|
out = Finish.over(out, vec4(face * a, a))
|
|
out = Finish.over(out, an_wire(d, an_nrm(p, c, h, h.y), 1.2, px, 1.0) * self.active)
|
|
return Finish.over(out, md_focus(d, px, self.focus * live))
|
|
}
|
|
|
|
// Radio tabs (the catalogue's Docs, Controls, Actions, Theme): ivory pills
|
|
// in their wire; the chosen one teal enamel, pressed in, its word ivory.
|
|
mod.widgets.RadioButtonTabFlat.padding = mod.turtle.Inset{left: 14.0 right: 14.0 top: 6.0 bottom: 2.0}
|
|
mod.widgets.RadioButtonTabFlat.label_walk.margin = mod.turtle.Inset{left: 0.0 right: 0.0 top: 0.0 bottom: 0.0}
|
|
mod.widgets.RadioButtonTabFlat.min_height = 26.0
|
|
mod.widgets.RadioButtonTabFlat.clip_x = false
|
|
mod.widgets.RadioButtonTabFlat.clip_y = false
|
|
mod.widgets.RadioButtonTabFlat.draw_bg.vertex = fn() {
|
|
let g = md_grow(self.rect_pos, self.rect_size, 6.0)
|
|
self.vertex_pos = self.clip_and_transform_vertex(g.xy, g.zw)
|
|
}
|
|
mod.widgets.RadioButtonTabFlat.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let ivory = an_button(self.pos, self.rect_size, self.rect_pos, px, self.hover, self.down, self.focus, self.disabled, 0.0, 0.0, vec4(99.0, 99.0, 99.0, 99.0), 7.0, 6.0)
|
|
let teal = an_button(self.pos, self.rect_size, self.rect_pos, px, self.hover * 0.5, 0.55, self.focus, self.disabled, 0.0, 0.0, vec4(99.0, 99.0, 99.0, 99.0), 0.0, 6.0)
|
|
return mix(ivory, teal, self.active)
|
|
}
|
|
mod.widgets.RadioButtonTabFlat.draw_text.color = #2a2116
|
|
mod.widgets.RadioButtonTabFlat.draw_text.color_active = #f3e8cf
|
|
mod.widgets.RadioButtonTabFlat.draw_text.color_disabled = #8c7a5c
|
|
mod.widgets.RadioButtonTabFlat.draw_text.text_style = mod.theme.font_label{font_size: 10.5}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SLIDERS. A fine bronze channel: a 4 point groove behind its wire, dark
|
|
// parchment where it is empty and teal enamel where the value fills it. The
|
|
// thumb is a bronze coin with a teal leaf on its face, riding with its own
|
|
// shadow. Every slider's quad grows six points for the coin, its shadow and
|
|
// the focus ring.
|
|
let an_coin = fn(p: vec2, c: vec2, rad: float, px: float, hover: float, press: float, dis: float) -> vec4 {
|
|
let live = 1.0 - dis
|
|
var out = an_drop(p, c, vec2(rad, rad), rad, (1.0 - 0.5 * press) * mix(1.0, 0.4, dis))
|
|
let q = p - c
|
|
let d = length(q) - rad
|
|
let n = q / max(length(q), 0.001)
|
|
let rr = clamp(length(q) / rad, 0.0, 1.0)
|
|
// the coin's face: a polished dome, light from the upper left
|
|
let lit = clamp(0.5 - 0.6 * dot(q / rad, vec2(0.45, 0.85)), 0.0, 1.0)
|
|
var face = mix(an_bronze_dk(), an_bronze_c(), 0.45 + 0.55 * lit)
|
|
face = mix(face, an_gold_hi(), smoothstep(0.55, 1.0, lit) * 0.55)
|
|
face = Finish.lift(face, 0.14 * hover * live * (1.0 - press))
|
|
face = mix(face, face * 0.88, press)
|
|
face = mix(face, mix(face, vec3(0.75, 0.72, 0.64), 0.55), dis)
|
|
let a = Finish.cover(d, px)
|
|
out = Finish.over(out, vec4(face * a, a))
|
|
// an engraved ring a little inside the rim
|
|
let ring = Finish.band(d, rad * 0.24, rad * 0.24 + max(px, 0.5), px)
|
|
out = Finish.over(out, vec4(an_bronze_dk() * ring * 0.8, ring * 0.8))
|
|
let ringl = Finish.band(d, rad * 0.24 + max(px, 0.5), rad * 0.24 + 2.0 * max(px, 0.5), px) * 0.6
|
|
out = Finish.over(out, vec4(an_gold_hi() * ringl, ringl))
|
|
// the leaf on its face
|
|
let lf = an_leaf(p, c + vec2(-0.42, 0.42) * rad * 0.62, normalize(vec2(1.0, -1.0)), rad * 1.24, rad * 0.30, rad * 0.10)
|
|
out = an_lay_leaf(out, lf, mix(vec3(0.16, 0.30, 0.25), vec3(0.5, 0.5, 0.45), dis), mix(vec3(0.33, 0.52, 0.44), vec3(0.6, 0.6, 0.55), dis), 0.35, px)
|
|
out = Finish.over(out, an_wire(d, n, max(1.0, rad * 0.16), px, live))
|
|
return out
|
|
}
|
|
|
|
let an_groove = fn(p: vec2, c: vec2, h: vec2, px: float, f0: float, f1: float, dis: float, hover: float) -> vec4 {
|
|
let r = h.y
|
|
let d = md_rbox(p, c, h, r)
|
|
var empty = mix(vec3(0.765, 0.682, 0.541), vec3(0.80, 0.74, 0.62), dis)
|
|
empty = Finish.lift(empty, 0.08 * hover)
|
|
var out = an_well(p, c, h, r, px, empty, 0.4, 1.0, dis)
|
|
let fh = vec2(max((f1 - f0) * 0.5, 0.0), h.y - 1.0)
|
|
let fc = vec2((f0 + f1) * 0.5, c.y)
|
|
let fd = md_rbox(p, fc, fh, fh.y)
|
|
let fcol = an_enamel(p, fc, fh, fh.y, mix(an_teal_lt(), vec3(0.66, 0.67, 0.60), dis), hover, 0.0)
|
|
let fa = Finish.cover(fd, px) * step(0.01, f1 - f0) * Finish.cover(d + 1.0, px)
|
|
return Finish.over(out, vec4(fcol * fa, fa))
|
|
}
|
|
|
|
mod.widgets.SliderFlat.height = 32.0
|
|
mod.widgets.SliderFlat.clip_x = false
|
|
mod.widgets.SliderFlat.clip_y = false
|
|
mod.widgets.SliderFlat.draw_bg.vertex = fn() {
|
|
let g = md_grow(self.rect_pos, self.rect_size, 6.0)
|
|
self.vertex_pos = self.clip_and_transform_vertex(g.xy, g.zw)
|
|
}
|
|
mod.widgets.SliderFlat.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let m = 6.0
|
|
let size = self.rect_size
|
|
let p = self.pos * (size + vec2(2.0 * m, 2.0 * m)) - vec2(m, m)
|
|
let o = self.rect_pos
|
|
let live = 1.0 - self.disabled
|
|
let cy = Finish.snap(o.y + size.y - 8.0, px) - o.y
|
|
let x0 = Finish.snap(o.x + 1.0, px) - o.x
|
|
let x1 = Finish.snap(o.x + size.x - 1.0, px) - o.x
|
|
let w = x1 - x0
|
|
let span = w - 18.0
|
|
let kx = x0 + 9.0 + self.slide_pos * span
|
|
let ox = x0 + 9.0 + self.origin_pos * span
|
|
let f0 = mix(x0 + 2.0, min(ox, kx), self.arc_origin)
|
|
let f1 = mix(kx, max(ox, kx), self.arc_origin)
|
|
var out = an_groove(p, vec2((x0 + x1) * 0.5, cy), vec2(w * 0.5, 2.5), px, f0, f1, self.disabled, max(self.hover, self.drag) * live)
|
|
let kc = vec2(Finish.snap(o.x + kx, px) - o.x, cy)
|
|
out = Finish.over(out, an_coin(p, kc, 7.5, px, max(self.hover, self.focus * 0.5), self.drag * live, self.disabled))
|
|
return Finish.over(out, md_focus(length(p - kc) - 7.5, px, self.focus * live))
|
|
}
|
|
mod.widgets.SliderFlat.text_input.draw_text.text_style = mod.theme.font_regular{font_size: 9.5}
|
|
|
|
// The range slider: the same channel, teal between the two ends, a round
|
|
// coin on each end, pressed while it is the one held.
|
|
mod.widgets.RangeSliderFlat.handle_size = 16.0
|
|
mod.widgets.RangeSliderFlat.track_inset = 1.0
|
|
mod.widgets.RangeSliderFlat.clip_x = false
|
|
mod.widgets.RangeSliderFlat.clip_y = false
|
|
mod.widgets.RangeSliderFlat.draw_bg.vertex = fn() {
|
|
let g = md_grow(self.rect_pos, self.rect_size, 6.0)
|
|
self.vertex_pos = self.clip_and_transform_vertex(g.xy, g.zw)
|
|
}
|
|
mod.widgets.RangeSliderFlat.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let m = 6.0
|
|
let size = self.rect_size
|
|
let p = self.pos * (size + vec2(2.0 * m, 2.0 * m)) - vec2(m, m)
|
|
let o = self.rect_pos
|
|
let live = 1.0 - self.disabled
|
|
let top = self.label_px
|
|
let cy = Finish.snap(o.y + top + (size.y - top) * 0.5, px) - o.y
|
|
let x0 = Finish.snap(o.x + 1.0, px) - o.x
|
|
let x1 = Finish.snap(o.x + size.x - 1.0, px) - o.x
|
|
let w = x1 - x0
|
|
let span = max(size.x - self.inset_px * 2.0 - self.handle_px, 1.0)
|
|
let sx = self.inset_px + self.handle_px * 0.5 + self.start_pos * span
|
|
let ex = self.inset_px + self.handle_px * 0.5 + self.end_pos * span
|
|
var out = an_groove(p, vec2((x0 + x1) * 0.5, cy), vec2(w * 0.5, 2.5), px, sx, ex, self.disabled, max(self.hover, self.drag) * live)
|
|
let k0 = vec2(Finish.snap(o.x + sx, px) - o.x, cy)
|
|
let k1 = vec2(Finish.snap(o.x + ex, px) - o.x, cy)
|
|
out = Finish.over(out, an_coin(p, k0, 7.0, px, max(self.hot_start, self.focus * 0.5) * live, self.drag * self.hot_start * live, self.disabled))
|
|
out = Finish.over(out, an_coin(p, k1, 7.0, px, max(self.hot_end, self.focus * 0.5) * live, self.drag * self.hot_end * live, self.disabled))
|
|
return out
|
|
}
|
|
|
|
// The minimal slider: a bronze hairline (a dark device pixel over a gold
|
|
// one), a teal thread along it to the thumb, and a bronze drop riding on
|
|
// it, its point upward, a teal jewel in its round.
|
|
mod.widgets.SliderMinimal.clip_x = false
|
|
mod.widgets.SliderMinimal.clip_y = false
|
|
mod.widgets.SliderMinimal.draw_bg.vertex = fn() {
|
|
let g = md_grow(self.rect_pos, self.rect_size, 6.0)
|
|
self.vertex_pos = self.clip_and_transform_vertex(g.xy, g.zw)
|
|
}
|
|
mod.widgets.SliderMinimal.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let m = 6.0
|
|
let size = self.rect_size
|
|
let p = self.pos * (size + vec2(2.0 * m, 2.0 * m)) - vec2(m, m)
|
|
let o = self.rect_pos
|
|
let live = 1.0 - self.disabled
|
|
let cy = Finish.snap(o.y + size.y - 6.0, px) - o.y
|
|
let kr = 5.0
|
|
let kx = kr + self.slide_pos * (size.x - 2.0 * kr)
|
|
let inx = step(0.0, p.x) * step(p.x, size.x)
|
|
let dark = step(cy - px, p.y) * step(p.y, cy) * inx
|
|
let light = step(cy, p.y) * step(p.y, cy + px) * inx
|
|
let thread = step(cy - 2.0 * px, p.y) * step(p.y, cy + px) * step(p.x, kx) * inx
|
|
var out = vec4(0.0, 0.0, 0.0, 0.0)
|
|
let la = light * 0.8
|
|
out = Finish.over(out, vec4(an_gold_hi() * la, la))
|
|
let da = dark * 0.85 * mix(1.0, 0.5, self.disabled)
|
|
out = Finish.over(out, vec4(an_bronze_dk() * da, da))
|
|
let tcol = mix(an_teal(), vec3(0.66, 0.67, 0.60), self.disabled)
|
|
out = Finish.over(out, vec4(tcol * thread, thread))
|
|
// the drop: a round body on the line, a point rising from it
|
|
let kc = vec2(Finish.snap(o.x + kx, px) - o.x, cy)
|
|
let q = p - kc
|
|
let body = length(q) - kr
|
|
let ty = q.y + kr * 1.9
|
|
let cone = max((abs(q.x) - ty * 0.618) * 0.851, 0.0 - ty)
|
|
let dd = min(body, max(cone, q.y))
|
|
let press = self.drag * live
|
|
out = Finish.over(out, an_drop(p, kc, vec2(kr, kr), kr, (1.0 - 0.5 * press) * mix(1.0, 0.4, self.disabled)))
|
|
let lit = clamp(0.5 - 0.6 * dot(q / (kr * 1.6), vec2(0.45, 0.85)), 0.0, 1.0)
|
|
var face = mix(an_bronze_dk(), an_bronze_c(), 0.45 + 0.55 * lit)
|
|
face = mix(face, an_gold_hi(), smoothstep(0.55, 1.0, lit) * 0.55)
|
|
face = Finish.lift(face, 0.14 * self.hover * live * (1.0 - press))
|
|
face = mix(face, mix(face, vec3(0.75, 0.72, 0.64), 0.55), self.disabled)
|
|
let a = Finish.cover(dd, px)
|
|
out = Finish.over(out, vec4(face * a, a))
|
|
let e = Finish.band(dd, 0.0, max(px, 0.55), px)
|
|
out = Finish.over(out, vec4(an_bronze_dk() * e * 0.85, e * 0.85))
|
|
let jd = length(q - vec2(0.0, 0.3)) - kr * 0.45
|
|
out = an_lay(out, jd, mix(vec3(0.26, 0.52, 0.45), vec3(0.6, 0.6, 0.55), self.disabled), 0.35, px)
|
|
return Finish.over(out, md_focus(body, px, self.focus * live))
|
|
}
|
|
mod.widgets.SliderMinimal.text_input.draw_text.text_style = mod.theme.font_regular{font_size: 9.5}
|
|
|
|
// The round slider: a teal-lined channel beside its label, a teal capsule in
|
|
// it and a bronze coin on the capsule's end; the value reads past it.
|
|
mod.widgets.SliderRoundFlat.height = 18.0
|
|
mod.widgets.SliderRoundFlat.clip_x = false
|
|
mod.widgets.SliderRoundFlat.clip_y = false
|
|
mod.widgets.SliderRoundFlat.draw_bg.vertex = fn() {
|
|
let g = md_grow(self.rect_pos, self.rect_size, 6.0)
|
|
self.vertex_pos = self.clip_and_transform_vertex(g.xy, g.zw)
|
|
}
|
|
mod.widgets.SliderRoundFlat.text_input.margin = mod.turtle.Inset{left: 0.0 right: 8.0 top: 0.0 bottom: 0.0}
|
|
mod.widgets.SliderRoundFlat.text_input.width = 30.0
|
|
mod.widgets.SliderRoundFlat.text_input.min_height = 0.0
|
|
mod.widgets.SliderRoundFlat.text_input.padding = mod.turtle.Inset{left: 0.0 right: 0.0 top: 0.0 bottom: 0.0}
|
|
mod.widgets.SliderRoundFlat.text_input.draw_text.text_style = mod.theme.font_regular{font_size: 9.5}
|
|
mod.widgets.SliderRoundFlat.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let m = 6.0
|
|
let size = self.rect_size
|
|
let p = self.pos * (size + vec2(2.0 * m, 2.0 * m)) - vec2(m, m)
|
|
let o = self.rect_pos
|
|
let live = 1.0 - self.disabled
|
|
let x0 = Finish.snap(o.x + self.label_size, px) - o.x
|
|
let y0 = Finish.snap(o.y + 1.0, px) - o.y
|
|
let x1 = Finish.snap(o.x + size.x - 44.0, px) - o.x
|
|
let y1 = Finish.snap(o.y + size.y - 1.0, px) - o.y
|
|
let h = vec2((x1 - x0) * 0.5, (y1 - y0) * 0.5)
|
|
let c = vec2(x0, y0) + h
|
|
let ins = 2.0
|
|
let kr = h.y - ins + 0.5
|
|
let kx = x0 + ins + kr + self.slide_pos * (2.0 * h.x - 2.0 * ins - 2.0 * kr)
|
|
var out = an_groove(p, c, h, px, x0 + ins, kx, self.disabled, self.hover * live)
|
|
let kc = vec2(Finish.snap(o.x + kx, px) - o.x, c.y)
|
|
out = Finish.over(out, an_coin(p, kc, kr, px, self.hover, self.drag * live, self.disabled))
|
|
return Finish.over(out, md_focus(md_rbox(p, c, h, h.y), px, self.focus * live))
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// FADERS. A deep teal slot four points wide in its bronze wire, bronze ticks
|
|
// either side, a gold thread in the slot for the value, and a cap: a teal
|
|
// enamel plaque 22 points across in a bronze wire, a gold line across its
|
|
// middle and a small bronze lozenge on it.
|
|
mod.widgets.SliderFader.cap_size = 13.0
|
|
mod.widgets.SliderFader.clip_x = false
|
|
mod.widgets.SliderFader.clip_y = false
|
|
mod.widgets.SliderFader.draw_bg.vertex = fn() {
|
|
let g = md_grow(self.rect_pos, self.rect_size, 5.0)
|
|
self.vertex_pos = self.clip_and_transform_vertex(g.xy, g.zw)
|
|
}
|
|
mod.widgets.SliderFader.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let m = 5.0
|
|
let size = self.rect_size
|
|
let p = self.pos * (size + vec2(2.0 * m, 2.0 * m)) - vec2(m, m)
|
|
let o = self.rect_pos
|
|
let live = 1.0 - self.disabled
|
|
let vert = self.is_vertical
|
|
let a = mix(p.x, size.y - p.y, vert)
|
|
let b = mix(p.y, p.x, vert)
|
|
let along = mix(size.x, size.y, vert)
|
|
let across = mix(size.y, size.x, vert)
|
|
let travel = max(along - self.inset_px * 2.0 - self.cap_px, 1.0)
|
|
let foot = self.inset_px + self.cap_px * 0.5
|
|
let mid = floor(across * 0.5 / px) * px
|
|
// the slot, in screen space
|
|
let sw = 5.0
|
|
let sc = mix(vec2(along * 0.5, mid), vec2(mid, size.y - along * 0.5), vert)
|
|
let sh = mix(vec2(along * 0.5 - self.inset_px, sw * 0.5), vec2(sw * 0.5, along * 0.5 - self.inset_px), vert)
|
|
var out = an_well(p, sc, sh, sw * 0.5, px, mix(an_teal_dk() * 0.8, vec3(0.6, 0.6, 0.55), self.disabled), 0.5, 1.0, self.disabled)
|
|
// the value: a gold thread in the slot, from the origin (or the foot) to
|
|
// the cap
|
|
let va0 = foot + self.fill_lo * travel
|
|
let va1 = foot + self.fill_hi * travel
|
|
let vl = step(va0, a) * step(a, va1) * (1.0 - smoothstep(0.55, 0.55 + px, abs(b - mid))) * live
|
|
out = Finish.over(out, vec4(an_gold_hi() * 0.9 * vl, vl * 0.9))
|
|
// ticks: a long one every quarter of the travel, short ones between
|
|
let nt = 16.0
|
|
let f = (a - foot) / travel * nt
|
|
let fi = floor(f + 0.5)
|
|
let da = abs(a - (foot + fi / nt * travel))
|
|
let major = 1.0 - step(0.1, abs(fi * 0.25 - floor(fi * 0.25 + 0.5)))
|
|
let tl = mix(2.5, 4.5, major)
|
|
let off = abs(b - mid) - sw * 0.5 - 2.5
|
|
let in_rng = step(-0.5, fi) * step(fi, nt + 0.5)
|
|
let tk = (1.0 - smoothstep(px * 0.6, px * 0.6 + 0.01 + px * 0.4, da)) * step(0.0, off) * step(off, tl) * in_rng * 0.8 * mix(1.0, 0.5, self.disabled)
|
|
out = Finish.over(out, vec4(an_line_c() * 0.8 * tk, tk))
|
|
// the cap
|
|
let at = foot + self.slide_pos * travel
|
|
let cw = min(22.0, across)
|
|
let cs = mix(vec2(at, mid), vec2(mid, size.y - at), vert)
|
|
let ch = mix(vec2(self.cap_px * 0.5, cw * 0.5), vec2(cw * 0.5, self.cap_px * 0.5), vert)
|
|
let cc = vec2(Finish.snap(o.x + cs.x, px) - o.x, Finish.snap(o.y + cs.y, px) - o.y)
|
|
let cr = 4.0
|
|
let cd = md_rbox(p, cc, ch, cr)
|
|
let press = self.drag * live
|
|
out = Finish.over(out, an_drop(p, cc, ch, cr, (1.0 - press * 0.5) * mix(1.0, 0.4, self.disabled)))
|
|
let hf = ch - vec2(1.4, 1.4)
|
|
let face = an_enamel(p, cc, hf, cr - 1.4, mix(an_teal(), vec3(0.62, 0.63, 0.55), self.disabled), max(self.hover, self.focus * 0.5) * live, press)
|
|
let fa = Finish.cover(cd, px)
|
|
out = Finish.over(out, vec4(face * fa, fa))
|
|
// the gold line across the cap
|
|
let ln = mix(abs(p.y - cc.y), abs(p.x - cc.x), 1.0 - vert)
|
|
let lin = (1.0 - smoothstep(0.4, 0.4 + px, ln)) * Finish.cover(cd + 2.0, px)
|
|
out = Finish.over(out, vec4(an_gold_hi() * 0.9 * lin, lin * 0.9))
|
|
// the lozenge
|
|
let lq = abs(p - cc)
|
|
let lz = (lq.x + lq.y) - 3.2
|
|
out = an_lay(out, lz, mix(an_bronze_c(), an_gold_hi(), 0.3), 0.5, px)
|
|
out = Finish.over(out, an_wire(cd, an_nrm(p, cc, ch, cr), 1.4, px, live) * mix(1.0, 0.5, self.disabled))
|
|
return Finish.over(out, md_focus(cd, px, self.focus * live))
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// KNOBS. A polished bronze disc, lit from the upper left, two rings engraved
|
|
// in it (a dark cut with a bright edge under it); in its middle a medallion
|
|
// of teal enamel with a spray of three leaves rising from its foot; the
|
|
// pointer a gold spear from a bronze boss out to the rim, turning with the
|
|
// value. Round it a fine bronze track and the value in gold.
|
|
let an_engrave = fn(d: float, at: float, px: float, amt: float) -> vec4 {
|
|
let w = max(px, 0.5)
|
|
let dk = Finish.band(d, at, at + w, px) * 0.75 * amt
|
|
let lt = Finish.band(d, at + w, at + 2.0 * w, px) * 0.6 * amt
|
|
var out = vec4(an_bronze_dk() * 0.7 * dk, dk)
|
|
return Finish.over(out, vec4(an_gold_hi() * lt, lt))
|
|
}
|
|
let an_knob = fn(p: vec2, c: vec2, rad: float, px: float, ang: float, hover: float, press: float, dis: float) -> vec4 {
|
|
let live = 1.0 - dis
|
|
var out = an_drop(p, c, vec2(rad, rad), rad, (1.0 - 0.4 * press) * mix(1.0, 0.4, dis))
|
|
let q = p - c
|
|
let d = length(q) - rad
|
|
let n = q / max(length(q), 0.001)
|
|
// the bronze disc: a dome, its light pooled on the upper left, a broad
|
|
// soft sheen and a darker foot
|
|
let lit = clamp(0.5 - 0.62 * dot(q / rad, vec2(0.45, 0.85)), 0.0, 1.0)
|
|
var face = mix(an_bronze_dk(), an_bronze_c(), 0.30 + 0.70 * lit)
|
|
face = mix(face, an_gold_hi(), smoothstep(0.62, 1.0, lit) * 0.55)
|
|
face = Finish.lift(face, 0.12 * hover * live * (1.0 - press))
|
|
face = mix(face, face * 0.9, press)
|
|
face = mix(face, mix(face, vec3(0.75, 0.72, 0.64), 0.55), dis)
|
|
let a = Finish.cover(d, px)
|
|
out = Finish.over(out, vec4(face * a, a))
|
|
out = Finish.over(out, an_engrave(d, rad * 0.10, px, live * 0.9 + 0.1))
|
|
// the medallion
|
|
let mr = rad * 0.70
|
|
let md = length(q) - mr
|
|
let mcol = an_enamel(p, c, vec2(mr, mr), mr, mix(an_teal(), vec3(0.62, 0.63, 0.55), dis), hover * live, press * 0.4) * (0.9 + 0.2 * lit)
|
|
let ma = Finish.cover(md, px)
|
|
out = Finish.over(out, vec4(mcol * ma, ma))
|
|
// three leaves rising from the medallion's foot, fixed (the medallion
|
|
// is the knob's face, the pointer turns over it)
|
|
let ldk = mix(vec3(0.235, 0.369, 0.322), vec3(0.56, 0.57, 0.51), dis)
|
|
let llt = mix(vec3(0.459, 0.604, 0.525), vec3(0.67, 0.67, 0.61), dis)
|
|
let lw = max(0.3, rad * 0.02)
|
|
let lb = c + vec2(0.0, mr * 0.80)
|
|
if md < 1.0 {
|
|
out = an_lay_leaf(out, an_leaf(p, lb, normalize(vec2(-0.62, -1.0)), mr * 1.25, mr * 0.20, mr * 0.14), ldk, llt, lw, px)
|
|
out = an_lay_leaf(out, an_leaf(p, lb, normalize(vec2(0.62, -1.0)), mr * 1.25, mr * 0.20, mr * -0.14), ldk, llt, lw, px)
|
|
out = an_lay_leaf(out, an_leaf(p, lb, vec2(0.0, -1.0), mr * 1.45, mr * 0.17, 0.0), ldk, llt, lw, px)
|
|
}
|
|
// the medallion's wire
|
|
out = Finish.over(out, an_wire(md, n, max(0.9, rad * 0.07), px, live) * mix(1.0, 0.55, dis))
|
|
// the spear: a long lozenge from the boss to the rim
|
|
let dir = vec2(0.0 - sin(ang), cos(ang))
|
|
let sl = an_leaf(p, c - dir * rad * 0.10, dir, rad * 1.0, max(0.9, rad * 0.085), 0.0)
|
|
let sfill = mix(mix(an_bronze_c(), an_gold_hi(), smoothstep(-0.3, 0.3, sl.y) * 0.85), vec3(0.8, 0.78, 0.7), dis)
|
|
out = an_lay(out, sl.x, sfill, max(0.35, rad * 0.025), px)
|
|
// the boss
|
|
let br = max(1.6, rad * 0.15)
|
|
let bd = length(q) - br
|
|
let bl = clamp(0.5 - 0.6 * dot(q / br, vec2(0.45, 0.85)), 0.0, 1.0)
|
|
out = an_lay(out, bd, mix(an_bronze_dk(), an_gold_hi(), bl), max(0.35, rad * 0.02), px)
|
|
// the rim
|
|
out = Finish.over(out, an_wire(d, n, max(1.2, rad * 0.08), px, live) * mix(1.0, 0.55, dis))
|
|
return out
|
|
}
|
|
|
|
// The value arc round a knob: `ar` its middle radius, `aw` its width; the
|
|
// gap centred at the bottom, the value clockwise from its left end, or from
|
|
// the origin when the knob is bipolar. The track a fine bronze line, the
|
|
// value gold with a dark edge.
|
|
let md_arc = fn(p: vec2, c: vec2, ar: float, aw: float, px: float, v0: float, v1: float, gap: float, dis: float) -> vec4 {
|
|
let start = gap * 0.5
|
|
let sweep = 2.0 * PI - gap
|
|
let q = p - c
|
|
var ang = atan2(0.0 - q.x, q.y)
|
|
if ang < 0.0 {
|
|
ang = ang + 2.0 * PI
|
|
}
|
|
let rd = abs(length(q) - ar) - aw * 0.5
|
|
let rt = abs(length(q) - ar) - max(px, 0.45)
|
|
let in_arc = step(start, ang) * step(ang, start + sweep)
|
|
let e0 = c + vec2(0.0 - sin(start), cos(start)) * ar
|
|
let e1 = c + vec2(0.0 - sin(start + sweep), cos(start + sweep)) * ar
|
|
let track_d = min(mix(1000.0, rt, in_arc), min(length(p - e0), length(p - e1)) - aw * 0.6)
|
|
let a0 = start + sweep * v0
|
|
let a1 = start + sweep * v1
|
|
let l0 = c + vec2(0.0 - sin(a0), cos(a0)) * ar
|
|
let l1 = c + vec2(0.0 - sin(a1), cos(a1)) * ar
|
|
let lit_in = step(a0, ang) * step(ang, a1)
|
|
let lit_d = min(mix(1000.0, rd, lit_in), min(length(p - l0), length(p - l1)) - aw * 0.5)
|
|
let ta = Finish.cover(track_d, px) * 0.7
|
|
var out = vec4(an_line_c() * ta, ta)
|
|
let la = Finish.cover(lit_d, px)
|
|
let ink = mix(mix(an_bronze_c(), an_gold_hi(), 0.55), vec3(0.75, 0.72, 0.64), dis)
|
|
out = Finish.over(out, vec4(ink * la, la))
|
|
let le = Finish.band(lit_d, 0.0, max(px, 0.4), px) * 0.6
|
|
return Finish.over(out, vec4(an_bronze_dk() * le, le))
|
|
}
|
|
|
|
mod.widgets.RotaryKnob.clip_x = false
|
|
mod.widgets.RotaryKnob.clip_y = false
|
|
mod.widgets.RotaryKnob.draw_bg.vertex = fn() {
|
|
let g = md_grow(self.rect_pos, self.rect_size, 5.0)
|
|
self.vertex_pos = self.clip_and_transform_vertex(g.xy, g.zw)
|
|
}
|
|
mod.widgets.RotaryKnob.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let m = 5.0
|
|
let size = self.rect_size
|
|
let p = self.pos * (size + vec2(2.0 * m, 2.0 * m)) - vec2(m, m)
|
|
let o = self.rect_pos
|
|
let live = 1.0 - self.disabled
|
|
let dia = min(size.x, size.y)
|
|
let rr = dia * 0.5 - 1.0
|
|
let c = vec2(Finish.snap(o.x + size.x * 0.5, px) - o.x, Finish.snap(o.y + size.y - dia * 0.5, px) - o.y)
|
|
let gap = self.gap * PI / 180.0
|
|
let aw = 1.8
|
|
let ar = floor((rr - aw * 0.5) / px) * px
|
|
let rad = floor((ar - aw * 0.5 - 2.4) / px) * px
|
|
let lo = min(self.origin_pos, self.slide_pos)
|
|
let hi = max(self.origin_pos, self.slide_pos)
|
|
let v0 = mix(0.0, lo, self.arc_origin)
|
|
let v1 = mix(self.slide_pos, hi, self.arc_origin)
|
|
var out = md_arc(p, c, ar, aw, px, v0, v1, gap, self.disabled)
|
|
let ang = gap * 0.5 + (2.0 * PI - gap) * self.slide_pos
|
|
out = Finish.over(out, an_knob(p, c, rad, px, ang, max(self.hover, self.focus * 0.5), self.drag * live, self.disabled))
|
|
return Finish.over(out, md_focus(length(p - c) - ar - aw * 0.5, px, self.focus * live))
|
|
}
|
|
// Knob captions are small engraved words in the sepia ink.
|
|
mod.widgets.RotaryKnob.draw_text.color = #3a2e1f
|
|
mod.widgets.RotaryKnob.draw_text.text_style = mod.theme.font_bold{font_size: 9.0}
|
|
|
|
// The dial: the knob above set in a deep teal bezel ring between two bronze
|
|
// wires, gold pips on the bezel every thirtieth of a turn, the value in gold
|
|
// round the bezel.
|
|
mod.widgets.RotaryFlat.clip_x = false
|
|
mod.widgets.RotaryFlat.clip_y = false
|
|
mod.widgets.RotaryFlat.draw_bg.vertex = fn() {
|
|
let g = md_grow(self.rect_pos, self.rect_size, 5.0)
|
|
self.vertex_pos = self.clip_and_transform_vertex(g.xy, g.zw)
|
|
}
|
|
mod.widgets.RotaryFlat.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let m = 5.0
|
|
let size = self.rect_size
|
|
let p = self.pos * (size + vec2(2.0 * m, 2.0 * m)) - vec2(m, m)
|
|
let o = self.rect_pos
|
|
let live = 1.0 - self.disabled
|
|
let room = vec2(size.x, size.y - 24.0)
|
|
let dia = min(room.x, room.y)
|
|
let rr = dia * 0.5 - 1.0
|
|
let c = vec2(Finish.snap(o.x + size.x * 0.5, px) - o.x, Finish.snap(o.y + 24.0 + room.y * 0.5, px) - o.y)
|
|
let gap = self.gap * PI / 180.0
|
|
let lo = min(self.origin_pos, self.slide_pos)
|
|
let hi = max(self.origin_pos, self.slide_pos)
|
|
let v0 = mix(0.0, lo, self.arc_origin)
|
|
let v1 = mix(self.slide_pos, hi, self.arc_origin)
|
|
// the bezel: a teal ring between two wires
|
|
let q = p - c
|
|
let n = q / max(length(q), 0.001)
|
|
let bw = max(5.0, rr * 0.20)
|
|
let d_out = length(q) - rr
|
|
let d_in = length(q) - (rr - bw)
|
|
var out = an_drop(p, c, vec2(rr, rr), rr, mix(1.0, 0.4, self.disabled))
|
|
let ba = Finish.cover(d_out, px)
|
|
let bcol = an_enamel(p, c, vec2(rr, rr), rr, mix(an_teal_dk(), vec3(0.6, 0.6, 0.55), self.disabled), 0.0, 0.0)
|
|
out = Finish.over(out, vec4(bcol * ba, ba))
|
|
// the value round the bezel
|
|
let ar = rr - bw * 0.5
|
|
out = Finish.over(out, md_arc(p, c, ar, bw * 0.38, px, v0, v1, gap, self.disabled))
|
|
// the pips
|
|
var ang = atan2(0.0 - q.x, q.y)
|
|
if ang < 0.0 {
|
|
ang = ang + 2.0 * PI
|
|
}
|
|
let st = 2.0 * PI / 24.0
|
|
let ai = floor(ang / st + 0.5) * st
|
|
let pc = c + vec2(0.0 - sin(ai), cos(ai)) * ar
|
|
let on_track = step(gap * 0.5 - 0.01, ai) * step(ai, 2.0 * PI - gap * 0.5 + 0.01)
|
|
let pd = length(p - pc) - max(0.7, bw * 0.12)
|
|
let pa = Finish.cover(pd, px) * on_track * 0.85
|
|
out = Finish.over(out, vec4(an_gold_hi() * pa, pa))
|
|
out = Finish.over(out, an_wire(d_out, n, 1.6, px, live) * mix(1.0, 0.55, self.disabled))
|
|
out = Finish.over(out, an_wire(0.0 - d_in - 1.4, n * -1.0, 1.4, px, live) * mix(1.0, 0.55, self.disabled) * Finish.cover(d_out, px))
|
|
let rad = rr - bw - 1.5
|
|
let kang = gap * 0.5 + (2.0 * PI - gap) * self.slide_pos
|
|
out = Finish.over(out, an_knob(p, c, rad, px, kang, max(self.hover, self.focus * 0.5), self.drag * live, self.disabled))
|
|
return Finish.over(out, md_focus(d_out, px, self.focus * live))
|
|
}
|
|
|
|
// The dial's readout: a small pill of the screens' deep teal glass in its
|
|
// bronze wire, amber figures.
|
|
let md_lcd = fn(p: vec2, size: vec2, o: vec2, px: float) -> vec4 {
|
|
let lo = vec2(Finish.snap(o.x, px), Finish.snap(o.y, px)) - o + vec2(0.0, px)
|
|
let hi = vec2(Finish.snap(o.x + size.x, px), Finish.snap(o.y + size.y, px)) - o - vec2(0.0, 2.0 * px)
|
|
let h = (hi - lo) * 0.5
|
|
let c = lo + h
|
|
let r = h.y
|
|
let d = md_rbox(p, c, h, r)
|
|
let t = clamp((p.y - lo.y) / max(2.0 * h.y, 1.0), 0.0, 1.0)
|
|
var col = an_glass_c() * (1.12 - 0.2 * t)
|
|
col = mix(col, an_shade(), clamp(Finish.inset(p, c, h, r, vec2(0.0, 1.2), 1.0), 0.0, 1.0) * 0.5)
|
|
let a = Finish.cover(d, px)
|
|
var out = an_drop(p, c, h, r, 0.6)
|
|
out = Finish.over(out, vec4(col * a, a))
|
|
return Finish.over(out, an_wire(d, an_nrm(p, c, h, r), 1.3, px, 1.0))
|
|
}
|
|
mod.widgets.RotaryFlat.text_input.padding = mod.turtle.Inset{left: 7.0 right: 7.0 top: 2.0 bottom: 2.0}
|
|
mod.widgets.RotaryFlat.text_input.min_height = 20.0
|
|
mod.widgets.RotaryFlat.text_input.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
return md_lcd(self.pos * self.rect_size, self.rect_size, self.rect_pos, px)
|
|
}
|
|
mod.widgets.RotaryFlat.text_input.draw_text.color = #ecc77c
|
|
mod.widgets.RotaryFlat.text_input.draw_text.color_hover = #f4d692
|
|
mod.widgets.RotaryFlat.text_input.draw_text.color_focus = #f4d692
|
|
mod.widgets.RotaryFlat.text_input.draw_text.color_empty = #a89060
|
|
mod.widgets.RotaryFlat.text_input.draw_text.text_style = mod.theme.font_label{font_size: 10.0}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// TEXT FIELDS. A sunk ivory well in its bronze wire, its corners rounded
|
|
// half way to a pill; focused, a teal line inside the wire and the ivory
|
|
// takes a breath of sage. Read only, the well is a deeper parchment.
|
|
let md_field = fn(p: vec2, size: vec2, o: vec2, px: float, hover: float, focus: float, dis: float, r: float) -> vec4 {
|
|
let ins = 1.5
|
|
let lo = vec2(Finish.snap(o.x + ins, px), Finish.snap(o.y + ins, px)) - o
|
|
let hi = vec2(Finish.snap(o.x + size.x - ins, px), Finish.snap(o.y + size.y - ins, px)) - o - vec2(0.0, px)
|
|
let h = (hi - lo) * 0.5
|
|
let c = lo + h
|
|
let rr = min(r, h.y)
|
|
let d = md_rbox(p, c, h, rr)
|
|
var fill = Finish.lift(an_well_c(), 0.30 * hover * (1.0 - dis))
|
|
fill = mix(fill, vec3(0.855, 0.867, 0.773), focus * 0.6)
|
|
fill = mix(fill, vec3(0.827, 0.749, 0.600), dis)
|
|
var out = an_well(p, c, h, rr, px, fill, mix(0.32, 0.18, dis), 1.3, dis)
|
|
let il = Finish.band(d, 2.0, 2.0 + max(px, 0.5), px) * mix(0.55, 0.25, dis) * (1.0 - focus)
|
|
out = Finish.over(out, vec4(an_teal_dk() * il, il))
|
|
let fl = Finish.band(d, 1.3, 1.3 + 1.2 * max(px, 0.75), px) * focus * (1.0 - dis)
|
|
return Finish.over(out, vec4(vec3(0.184, 0.435, 0.384) * fl, fl))
|
|
}
|
|
|
|
mod.widgets.TextInputFlat.padding = mod.turtle.Inset{left: 10.0 right: 10.0 top: 4.0 bottom: 4.0}
|
|
mod.widgets.TextInputFlat.draw_bg.pixel = fn() {
|
|
if self.color.a < 0.01 {
|
|
return vec4(0.0, 0.0, 0.0, 0.0)
|
|
}
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
return md_field(self.pos * self.rect_size, self.rect_size, self.rect_pos, px, self.hover, self.focus, self.disabled, 14.0)
|
|
}
|
|
mod.widgets.TextInputFlat.draw_text.color_empty = #6a5940
|
|
mod.widgets.TextInputFlat.draw_text.color_disabled = #7a6a50
|
|
mod.widgets.TextInputFlat.draw_cursor.color = #2a2116
|
|
|
|
// NUMBER FIELDS. The ivory well, and on its right a column split by a fine
|
|
// bronze line, a small chevron in each half; the half under the pointer
|
|
// lifts, the held half darkens.
|
|
mod.widgets.NumberField.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
return md_field(self.pos * self.rect_size, self.rect_size, self.rect_pos, px, self.hover, self.focus, self.disabled, 14.0)
|
|
}
|
|
mod.widgets.NumberField.pad_left = 10.0
|
|
mod.widgets.NumberSpin.width = 16.0
|
|
mod.widgets.NumberSpin.draw_text.color = #00000000
|
|
mod.widgets.NumberSpin.draw_text.color_disabled = #00000000
|
|
let an_chev = fn(p: vec2, c: vec2, hw: float, hh: float, dir: float) -> float {
|
|
// a chevron hw either side, hh tall, pointing up (dir -1) or down (1)
|
|
let a = c + vec2(0.0 - hw, 0.0 - hh * dir * 0.5)
|
|
let b = c + vec2(0.0, hh * dir * 0.5)
|
|
let e = c + vec2(hw, 0.0 - hh * dir * 0.5)
|
|
return min(md_seg(p, a, b), md_seg(p, b, e))
|
|
}
|
|
mod.widgets.NumberSpin.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let p = self.pos * self.rect_size
|
|
let o = self.rect_pos
|
|
let live = 1.0 - self.disabled
|
|
let lo = vec2(Finish.snap(o.x, px), Finish.snap(o.y + 3.0, px)) - o
|
|
let hi = vec2(Finish.snap(o.x + self.rect_size.x - 3.0, px), Finish.snap(o.y + self.rect_size.y - 3.0, px)) - o
|
|
let mid = Finish.snap(o.y + (lo.y + hi.y) * 0.5, px) - o.y
|
|
let upper = step(p.y, mid)
|
|
let hot = mix(max(0.0, 0.0 - self.hot), max(0.0, self.hot), upper) * live
|
|
let dn = mix(max(0.0, 0.0 - self.down), max(0.0, self.down), upper) * live
|
|
let inx = step(lo.x, p.x) * step(p.x, hi.x) * step(lo.y, p.y) * step(p.y, hi.y)
|
|
let wash = inx * (0.10 * hot + 0.12 * dn)
|
|
var out = vec4(mix(vec3(1.0, 0.97, 0.9), an_shade(), step(0.01, dn)) * wash, wash)
|
|
// the fine bronze line down its left and across its middle
|
|
let vl = step(lo.x, p.x) * step(p.x, lo.x + max(px, 0.6)) * step(lo.y, p.y) * step(p.y, hi.y) * 0.8
|
|
let hl = step(abs(p.y - mid), max(px, 0.6) * 0.5) * step(lo.x, p.x) * step(p.x, hi.x) * 0.6
|
|
let la = max(vl, hl)
|
|
out = Finish.over(out, vec4(an_line_c() * la, la))
|
|
let cx = (lo.x + hi.x) * 0.5 + 0.5
|
|
let cu = an_chev(p, vec2(cx, (lo.y + mid) * 0.5), 2.8, 2.6, -1.0) - 0.55
|
|
let cd = an_chev(p, vec2(cx, (mid + hi.y) * 0.5), 2.8, 2.6, 1.0) - 0.55
|
|
let ti = Finish.cover(min(cu, cd), px)
|
|
let ink = mix(an_ink(), vec3(0.6, 0.53, 0.42), self.disabled)
|
|
return Finish.over(out, vec4(ink * ti, ti))
|
|
}
|
|
|
|
// The drag-number: the ivory well, its track a pale teal wash behind the
|
|
// ink.
|
|
mod.widgets.ValueInput.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let p = self.pos * self.rect_size
|
|
var out = md_field(p, self.rect_size, self.rect_pos, px, max(self.hover, self.drag), self.focus, 0.0, 14.0)
|
|
let d = md_rbox(p, self.rect_size * 0.5, self.rect_size * 0.5 - vec2(3.0, 3.0), 6.0)
|
|
let wx = 3.0 + (self.rect_size.x - 6.0) * max(self.fill, 0.0)
|
|
let wash = step(0.0, self.fill) * step(p.x, wx) * Finish.cover(d, px) * 0.22
|
|
return Finish.over(out, vec4(an_teal_lt() * wash, wash))
|
|
}
|
|
mod.widgets.ValueInput.draw_text.color = #2a2116
|
|
mod.widgets.ValueInput.draw_text.text_style = mod.theme.font_label{font_size: 10.0 line_spacing: 1.0}
|
|
mod.widgets.ValueInput.arrow_color = #5a4a34
|
|
mod.widgets.ValueInput.text_input.draw_bg.color = #00000000
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// DROP-DOWNS. The ivory pill with a chevron on the right, set off by a fine
|
|
// bronze line. Open, the pill is held pressed in.
|
|
let md_dropdown = fn(pos0: vec2, size0: vec2, o0: vec2, px: float, hover: float, held: float, focus: float, dis: float, ins: float) -> vec4 {
|
|
let m = 6.0
|
|
let p = pos0 * (size0 + vec2(2.0 * m, 2.0 * m)) - vec2(m, m) - vec2(0.0, ins)
|
|
let size = size0 - vec2(0.0, 2.0 * ins)
|
|
let o = o0 + vec2(0.0, ins)
|
|
let pos = (p + vec2(m, m)) / (size + vec2(2.0 * m, 2.0 * m))
|
|
var out = an_button(pos, size, o, px, hover, held, focus, dis, 0.0, 0.0, vec4(99.0, 99.0, 99.0, 99.0), 7.0, m)
|
|
let live = 1.0 - dis
|
|
let dx = Finish.snap(o.x + size.x - 24.0, px) - o.x
|
|
let in_y = step(size.y * 0.22, p.y) * step(p.y, size.y * 0.78)
|
|
let dl = step(dx - max(px, 0.6) * 0.5, p.x) * step(p.x, dx + max(px, 0.6) * 0.5) * in_y * mix(0.8, 0.4, dis)
|
|
out = Finish.over(out, vec4(an_line_c() * dl, dl))
|
|
let cc = vec2(Finish.snap(o.x + size.x - 12.5, px) - o.x, size.y * 0.5 + held * live * px)
|
|
let ch = an_chev(p, cc, 3.4, 3.2, 1.0) - 0.65
|
|
let tri = Finish.cover(ch, px)
|
|
let ink = mix(an_ink(), vec3(0.6, 0.53, 0.42), dis)
|
|
return Finish.over(out, vec4(ink * tri, tri))
|
|
}
|
|
|
|
mod.widgets.DropDownFlat.padding = mod.turtle.Inset{left: 12.0 right: 32.0 top: 4.0 bottom: 4.0}
|
|
mod.widgets.DropDown.padding = mod.turtle.Inset{left: 12.0 right: 32.0 top: 4.0 bottom: 4.0}
|
|
mod.widgets.DropDownFlat.clip_x = false
|
|
mod.widgets.DropDownFlat.clip_y = false
|
|
mod.widgets.DropDownFlat.draw_bg.vertex = fn() {
|
|
let g = md_grow(self.rect_pos, self.rect_size, 6.0)
|
|
self.vertex_pos = self.clip_and_transform_vertex(g.xy, g.zw)
|
|
}
|
|
mod.widgets.DropDownFlat.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
return md_dropdown(self.pos, self.rect_size, self.rect_pos, px, self.hover, max(self.down, self.active), self.focus, self.disabled, 1.0)
|
|
}
|
|
mod.widgets.DropDownFlat.draw_text.text_style = mod.theme.font_label{font_size: 10.5}
|
|
|
|
mod.widgets.Select.clip_x = false
|
|
mod.widgets.Select.clip_y = false
|
|
mod.widgets.MultiSelect.clip_x = false
|
|
mod.widgets.MultiSelect.clip_y = false
|
|
mod.widgets.Select.face.clip_x = false
|
|
mod.widgets.Select.face.clip_y = false
|
|
mod.widgets.MultiSelect.face.clip_x = false
|
|
mod.widgets.MultiSelect.face.clip_y = false
|
|
mod.widgets.Select.face.draw_bg.vertex = fn() {
|
|
let g = md_grow(self.rect_pos, self.rect_size, 6.0)
|
|
self.vertex_pos = self.clip_and_transform_vertex(g.xy, g.zw)
|
|
}
|
|
mod.widgets.MultiSelect.face.draw_bg.vertex = fn() {
|
|
let g = md_grow(self.rect_pos, self.rect_size, 6.0)
|
|
self.vertex_pos = self.clip_and_transform_vertex(g.xy, g.zw)
|
|
}
|
|
mod.widgets.Select.face.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
return md_dropdown(self.pos, self.rect_size, self.rect_pos, px, self.hover, self.down, self.focus, self.disabled, 0.0)
|
|
}
|
|
mod.widgets.MultiSelect.face.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
return md_dropdown(self.pos, self.rect_size, self.rect_pos, px, self.hover, self.down, self.focus, self.disabled, 0.0)
|
|
}
|
|
mod.widgets.Select.face.padding.right = 32.0
|
|
mod.widgets.MultiSelect.face.padding.right = 32.0
|
|
|
|
// The combo box: the ivory well one types into, its chevron behind a fine
|
|
// bronze line at the right end.
|
|
mod.widgets.ComboBox.padding = mod.turtle.Inset{left: 10.0 right: 32.0 top: 4.0 bottom: 4.0}
|
|
mod.widgets.ComboBox.input.min_height = 0.0
|
|
mod.widgets.ComboBox.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let p = self.pos * self.rect_size
|
|
let size = self.rect_size
|
|
let o = self.rect_pos
|
|
let live = 1.0 - self.disabled
|
|
var out = md_field(p, size, o, px, self.hover, self.focus, self.disabled, 14.0)
|
|
let dx = Finish.snap(o.x + size.x - 24.0, px) - o.x
|
|
let in_y = step(size.y * 0.25, p.y) * step(p.y, size.y * 0.75)
|
|
let dl = step(dx - max(px, 0.6) * 0.5, p.x) * step(p.x, dx + max(px, 0.6) * 0.5) * in_y * mix(0.8, 0.4, self.disabled)
|
|
out = Finish.over(out, vec4(an_line_c() * dl, dl))
|
|
let held = self.down * self.hover * live
|
|
let cc = vec2(Finish.snap(o.x + size.x - 12.5, px) - o.x, size.y * 0.5 + held * px)
|
|
let tri = Finish.cover(an_chev(p, cc, 3.4, 3.2, 1.0) - 0.65, px)
|
|
let ink = mix(an_ink(), vec3(0.6, 0.53, 0.42), self.disabled)
|
|
return Finish.over(out, vec4(ink * tri, tri))
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SEGMENTS AND TABS. One ivory pill across the strip in its wire; the chosen
|
|
// segment is a teal enamel pill pressed into it, its word ivory.
|
|
let md_strip = fn(p: vec2, size: vec2, o: vec2, px: float) -> vec4 {
|
|
let lo = vec2(Finish.snap(o.x, px), Finish.snap(o.y, px)) - o
|
|
let hi = vec2(Finish.snap(o.x + size.x, px), Finish.snap(o.y + size.y, px)) - o
|
|
let c = (lo + hi) * 0.5
|
|
let h = (hi - lo) * 0.5
|
|
let d = md_rbox(p, c, h, h.y)
|
|
var out = an_drop(p, c, h, h.y, 0.7)
|
|
let hf = h - vec2(1.5, 1.5)
|
|
let face = an_enamel(p, c, hf, hf.y, vec3(0.906, 0.851, 0.737), 0.0, 0.0)
|
|
let fa = Finish.cover(d + 0.75, px)
|
|
out = Finish.over(out, vec4(face * fa, fa))
|
|
return Finish.over(out, an_wire(d, an_nrm(p, c, h, h.y), 1.5, px, 1.0))
|
|
}
|
|
// The chosen cell of a strip: an enamel pill of `base` inside the cell,
|
|
// pressed in, in a wire of its own.
|
|
let md_cell = fn(p: vec2, lo: vec2, hi: vec2, px: float, base: vec3) -> vec4 {
|
|
let c = (lo + hi) * 0.5
|
|
let h = (hi - lo) * 0.5
|
|
let d = md_rbox(p, c, h, h.y)
|
|
let hf = h - vec2(1.2, 1.2)
|
|
let face = an_enamel(p, c, hf, hf.y, base, 0.0, 0.6)
|
|
let a = Finish.cover(d + 0.6, px)
|
|
var out = vec4(face * a, a)
|
|
return Finish.over(out, an_wire(d, an_nrm(p, c, h, h.y), 1.2, px, 1.0))
|
|
}
|
|
|
|
mod.widgets.SegmentedControlFlat.segment_height = 22.0
|
|
mod.widgets.SegmentedControlFlat.draw_bg.vertex = fn() {
|
|
let g = md_grow(self.rect_pos, self.rect_size, 5.0)
|
|
self.vertex_pos = self.clip_and_transform_vertex(g.xy, g.zw)
|
|
}
|
|
mod.widgets.SegmentedControlFlat.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let m = 5.0
|
|
let p = self.pos * (self.rect_size + vec2(2.0 * m, 2.0 * m)) - vec2(m, m)
|
|
return md_strip(p, self.rect_size, self.rect_pos, px)
|
|
}
|
|
// The pill is the segment's own box: its quad grows a point each way so the
|
|
// chosen pill stands just inside the strip's wire.
|
|
mod.widgets.SegmentedControlFlat.draw_pill.vertex = fn() {
|
|
self.vertex_pos = self.clip_and_transform_vertex(self.rect_pos - vec2(1.0, 1.0), self.rect_size + vec2(2.0, 2.0))
|
|
}
|
|
mod.widgets.SegmentedControlFlat.draw_pill.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let o = self.rect_pos
|
|
let size = self.rect_size
|
|
let p = self.pos * (size + vec2(2.0, 2.0)) - vec2(1.0, 1.0)
|
|
let lo = vec2(Finish.snap(o.x - 0.5, px), Finish.snap(o.y - 0.5, px)) - o
|
|
let hi = vec2(Finish.snap(o.x + size.x + 0.5, px), Finish.snap(o.y + size.y + 0.5, px)) - o
|
|
return md_cell(p, lo, hi, px, an_teal())
|
|
}
|
|
mod.widgets.SegmentedControlFlat.draw_text.color = #3a2e1f
|
|
mod.widgets.SegmentedControlFlat.draw_text_selected.color = #f6eedb
|
|
mod.widgets.SegmentedControlFlat.palette.on_neutral_container = #f6eedb
|
|
mod.widgets.SegmentedControlFlat.draw_text.text_style = mod.theme.font_label{font_size: 10.5}
|
|
mod.widgets.SegmentedControlFlat.draw_text_selected.text_style = mod.theme.font_label{font_size: 10.5}
|
|
|
|
// The tab strip: the same pill; the tab in use an ochre enamel pill pressed
|
|
// into it, a hovered tab lifts a little, the quiet ones parted by a fine
|
|
// bronze line with a gold dot at its middle.
|
|
mod.widgets.Tabs.height = 26.0
|
|
mod.widgets.Tabs.tab_min_width = 46.0
|
|
mod.widgets.Tabs.clip_x = false
|
|
mod.widgets.Tabs.clip_y = false
|
|
mod.widgets.Tabs.draw_bg.vertex = fn() {
|
|
let g = md_grow(self.rect_pos, self.rect_size, 5.0)
|
|
self.vertex_pos = self.clip_and_transform_vertex(g.xy, g.zw)
|
|
}
|
|
mod.widgets.Tabs.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let m = 5.0
|
|
let p = self.pos * (self.rect_size + vec2(2.0 * m, 2.0 * m)) - vec2(m, m)
|
|
return md_strip(p, self.rect_size, self.rect_pos, px)
|
|
}
|
|
mod.widgets.Tabs.draw_tab.pixel = fn() {
|
|
return vec4(0.0, 0.0, 0.0, 0.0)
|
|
}
|
|
mod.widgets.Tabs.draw_tab_hover.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let p = self.pos * self.rect_size
|
|
let h = self.rect_size * 0.5 - vec2(2.0, 2.5)
|
|
let d = md_rbox(p, self.rect_size * 0.5, h, h.y)
|
|
let a = Finish.cover(d, px) * 0.35
|
|
return vec4(vec3(1.0, 0.98, 0.92) * a, a)
|
|
}
|
|
mod.widgets.Tabs.draw_tab_active.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let o = self.rect_pos
|
|
let size = self.rect_size
|
|
let lo = vec2(Finish.snap(o.x + 1.0, px), Finish.snap(o.y + 1.5, px)) - o
|
|
let hi = vec2(Finish.snap(o.x + size.x - 1.0, px), Finish.snap(o.y + size.y - 1.5, px)) - o
|
|
return md_cell(self.pos * size, lo, hi, px, an_ochre())
|
|
}
|
|
mod.widgets.Tabs.draw_sep.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let p = self.pos * self.rect_size
|
|
let x = self.rect_size.x * 0.5
|
|
let y = self.rect_size.y * 0.5
|
|
let ln = step(abs(p.x - x), max(px, 0.6) * 0.5) * step(abs(p.y - y), self.rect_size.y * 0.28) * 0.7
|
|
let dot = Finish.cover(length(p - vec2(x, y)) - 1.2, px)
|
|
let a = max(ln, dot)
|
|
return vec4(mix(an_line_c(), an_gold_hi(), dot * 0.4) * a, a)
|
|
}
|
|
mod.widgets.Tabs.draw_mark.color = #3a2e1f
|
|
mod.widgets.Tabs.draw_mark.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let p = self.pos * self.rect_size
|
|
let o = self.rect_pos
|
|
let c = vec2(Finish.snap(o.x + self.rect_size.x * 0.5, px), Finish.snap(o.y + self.rect_size.y * 0.5, px)) - o
|
|
// the add mark a plus in the middle of its room; the close mark a small
|
|
// cross tucked into the top right of its room, clear of the word
|
|
let a = mix(0.7853981634, 0.0, self.plus)
|
|
let r = mix(2.0, 3.6, self.plus)
|
|
let cm = mix(vec2(self.rect_size.x - 3.0, 4.5), c, self.plus)
|
|
let u = vec2(cos(a), sin(a)) * r
|
|
let v = vec2(0.0 - sin(a), cos(a)) * r
|
|
let dd = min(md_seg(p, cm - u, cm + u), md_seg(p, cm - v, cm + v)) - mix(0.5, 0.6, self.plus)
|
|
let k = Finish.cover(dd, px) * self.color.a
|
|
return vec4(self.color.rgb * k, k)
|
|
}
|
|
mod.widgets.Tabs.draw_text.color = #3a2e1f
|
|
mod.widgets.Tabs.draw_text_active.color = #1f180f
|
|
mod.widgets.Tabs.draw_text.text_style = mod.theme.font_label{font_size: 9.0 top_drop: 0.22}
|
|
mod.widgets.Tabs.draw_text_active.text_style = mod.theme.font_label{font_size: 9.0 top_drop: 0.22}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// PROGRESS. A channel of deep teal glass in its bronze wire; the value a
|
|
// sage-teal enamel combed with the fine veins of a long feather-like leaf,
|
|
// a gold midrib down it. The unknown value is a still run of leaves across
|
|
// the whole channel: a face may not run a clock.
|
|
mod.widgets.ProgressBarFlat.height = 12.0
|
|
mod.widgets.ProgressBarFlat.draw_bg.thickness = uniform(12.0)
|
|
mod.widgets.ProgressBarFlat.clip_x = false
|
|
mod.widgets.ProgressBarFlat.clip_y = false
|
|
mod.widgets.ProgressBarFlat.draw_bg.vertex = fn() {
|
|
let g = md_grow(self.rect_pos, self.rect_size, 3.0)
|
|
self.vertex_pos = self.clip_and_transform_vertex(g.xy, g.zw)
|
|
}
|
|
mod.widgets.ProgressBarFlat.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let m = 3.0
|
|
let size = self.rect_size
|
|
let p = self.pos * (size + vec2(2.0 * m, 2.0 * m)) - vec2(m, m)
|
|
let o = self.rect_pos
|
|
let th = min(self.thickness, size.y)
|
|
let top = Finish.snap(o.y + (size.y - th) * 0.5, px) - o.y
|
|
let bot = Finish.snap(o.y + (size.y + th) * 0.5, px) - o.y
|
|
let x0 = Finish.snap(o.x + size.x * self.start, px) - o.x
|
|
let x1 = Finish.snap(o.x + size.x * self.end, px) - o.x
|
|
let h = vec2((x1 - x0) * 0.5, (bot - top) * 0.5)
|
|
let c = vec2(x0, top) + h
|
|
let r = h.y
|
|
let d = md_rbox(p, c, h, r)
|
|
let dis = step(4.5, self.intent)
|
|
var out = an_well(p, c, h, r, px, mix(vec3(0.150, 0.235, 0.212), vec3(0.62, 0.62, 0.56), dis), 0.55, 1.3, dis)
|
|
var v1 = x0 + (x1 - x0) * clamp(self.value, 0.0, 1.0)
|
|
var unknown = 0.0
|
|
if self.value < 0.0 {
|
|
v1 = x1
|
|
unknown = 1.0
|
|
}
|
|
let fh = vec2(max((v1 - x0) * 0.5 - 1.3, 0.0), h.y - 1.3)
|
|
let fc = vec2((x0 + v1) * 0.5, c.y)
|
|
let fd = md_rbox(p, fc, fh, min(fh.y, fh.x + fh.y))
|
|
var base = vec3(0.447, 0.616, 0.537)
|
|
if self.intent > 0.5 {
|
|
base = self.fill_color().rgb
|
|
}
|
|
base = mix(base, vec3(0.70, 0.69, 0.60), dis)
|
|
var fcol = an_enamel(p, fc, fh, fh.y, base, 0.0, 0.0)
|
|
// the veins: fine pale strokes slanting back from the leading edge,
|
|
// wavering a little so no two run alike
|
|
let vy = (p.y - c.y) / max(h.y, 1.0)
|
|
let vx = p.x - abs(vy) * 6.0 + (Finish.noise(vec2(p.x * 0.15, 3.0)) - 0.5) * 2.0
|
|
let fv = abs(fract(vx / 3.6) - 0.5) * 3.6
|
|
let vln = (1.0 - smoothstep(0.3, 0.3 + px * 1.5, fv)) * 0.30
|
|
fcol = mix(fcol, Finish.lift(fcol, 0.45), vln)
|
|
fcol = mix(fcol, fcol * 0.8, smoothstep(0.35, 1.0, abs(vy)) * 0.5)
|
|
// the midrib along the value
|
|
let rib = (1.0 - smoothstep(0.3, 0.3 + px, abs(p.y - c.y))) * 0.35
|
|
fcol = mix(fcol, an_gold_hi(), rib)
|
|
// the unknown value: leaves laid end to end
|
|
if unknown > 0.5 {
|
|
let cell = 12.0
|
|
let lx = p.x - floor(p.x / cell) * cell
|
|
let lf = an_leaf(vec2(lx, p.y), vec2(1.0, c.y + 1.5), normalize(vec2(1.0, -0.25)), cell - 2.0, h.y * 0.55, 0.0)
|
|
let la = Finish.cover(lf.x, px)
|
|
fcol = mix(vec3(0.150, 0.235, 0.212), mix(vec3(0.30, 0.46, 0.40), vec3(0.50, 0.66, 0.57), smoothstep(-0.2, 0.2, lf.y)), la)
|
|
fcol = mix(fcol, an_line_c(), Finish.band(lf.x, 0.0, max(px, 0.45), px))
|
|
}
|
|
let fa = Finish.cover(fd, px) * step(0.01, v1 - x0)
|
|
out = Finish.over(out, vec4(fcol * fa, fa))
|
|
return out * self.track * self.opacity
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// LEVEL METERS. A dark teal well of cells four points long with a point
|
|
// between: unlit cells the deep teal glass, lit ones a sage green, ochre from
|
|
// 70 % and terracotta from 90 %; the hold an ivory line; the over lamp a
|
|
// small jewel.
|
|
mod.widgets.LevelMeter.height = 8.0
|
|
mod.widgets.LevelMeterColumn.width = 8.0
|
|
mod.widgets.LevelMeter.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let p = self.pos * self.rect_size
|
|
let vert = self.vertical
|
|
let along = mix(self.rect_size.x, self.rect_size.y, vert)
|
|
let across = mix(self.rect_size.y, self.rect_size.x, vert)
|
|
let a = mix(p.x, self.rect_size.y - p.y, vert)
|
|
let b = mix(p.y, p.x, vert)
|
|
let q = vec2(a, b)
|
|
let th = min(7.0, across)
|
|
let lamp_room = self.lamp * (th + 4.0)
|
|
let bar = max(4.0, along - lamp_room)
|
|
let h = vec2(bar * 0.5, th * 0.5)
|
|
let c = vec2(h.x, across * 0.5)
|
|
let r = 2.0
|
|
let d = md_rbox(q, c, h, r)
|
|
let pad = 1.5
|
|
let span = max(1.0, bar - pad * 2.0)
|
|
let share = clamp((a - pad) / span, 0.0, 1.0)
|
|
let pitch = 5.0
|
|
let cell = fract((a - pad) / pitch)
|
|
let in_cell = step(cell, 4.0 / pitch)
|
|
let lit = step(a, pad + span * self.level) * step(pad, a) * in_cell
|
|
let ramp = mix(mix(mix(vec3(0.45, 0.66, 0.52), vec3(0.70, 0.76, 0.44), smoothstep(0.0, 0.7, share)), vec3(0.92, 0.72, 0.34), step(0.7, share)), vec3(0.86, 0.40, 0.27), step(0.9, share))
|
|
let well = vec3(0.12, 0.19, 0.17)
|
|
var fill = mix(well, ramp, lit)
|
|
let cell_row = in_cell * step(pad, a) * step(a, pad + span)
|
|
fill = mix(fill, mix(well, vec3(0.2, 0.3, 0.27), 0.5), (1.0 - lit) * cell_row * step(1.2, abs(b - c.y) + 1.2))
|
|
let bt = b - (c.y - h.y)
|
|
fill = mix(fill, vec3(1.0, 0.97, 0.88), lit * step(1.0, bt) * step(bt, 1.0 + px) * 0.3)
|
|
if self.hold > 0.002 {
|
|
let at = pad + span * self.hold
|
|
let hm = step(abs(a - at), px) * step(abs(b - c.y), h.y)
|
|
fill = mix(fill, an_ivory(), hm)
|
|
}
|
|
let ca = Finish.cover(d, px)
|
|
var out = vec4(fill * ca, ca)
|
|
let e = Finish.band(d, 0.0, max(px, 0.7), px)
|
|
out = Finish.over(out, vec4(an_line_c() * e, e))
|
|
if self.lamp > 0.5 {
|
|
let la = bar + 2.0 + th * 0.5 + 1.0
|
|
let lc = vec2(mix(la, across * 0.5, vert), mix(across * 0.5, self.rect_size.y - la, vert))
|
|
out = Finish.over(out, md_led(p, lc, 2.6, px, vec3(0.90, 0.30, 0.20), step(0.5, self.over), 0.3))
|
|
}
|
|
return out * self.opacity
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SCROLL BARS. A bronze hairline down the length of the view and a slim teal
|
|
// enamel pill riding on it in its own wire.
|
|
mod.widgets.ScrollBar.bar_size = 10.0
|
|
mod.widgets.ScrollBar.bar_side_margin = 0.0
|
|
mod.widgets.ScrollBar.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let p = self.pos * self.rect_size
|
|
let vert = self.is_vertical
|
|
let a = mix(p.x, p.y, vert)
|
|
let b = mix(p.y, p.x, vert)
|
|
let along = mix(self.rect_size.x, self.rect_size.y, vert)
|
|
let across = mix(self.rect_size.y, self.rect_size.x, vert)
|
|
let q = vec2(a, b)
|
|
let mid = across * 0.5
|
|
let rail = (1.0 - smoothstep(0.35, 0.35 + px, abs(b - mid))) * 0.55
|
|
var out = vec4(an_line_c() * rail, rail)
|
|
let t0 = along * self.norm_scroll
|
|
let tl = along * self.norm_handle
|
|
let th = vec2(max(tl * 0.5 - 1.0, 4.0), 3.5)
|
|
let tc = vec2(t0 + tl * 0.5, mid)
|
|
let td = md_rbox(q, tc, th, th.y)
|
|
let hf = th - vec2(1.0, 1.0)
|
|
let face = an_enamel(q, tc, hf, hf.y, Finish.lift(an_teal(), 0.12 * self.hover), 0.0, 0.3 * self.drag)
|
|
let ta = Finish.cover(td, px)
|
|
out = Finish.over(out, vec4(face * ta, ta))
|
|
let e = Finish.band(td, 0.0, 1.0, px)
|
|
out = Finish.over(out, vec4(mix(an_bronze_c(), an_gold_hi(), 0.3) * e, e))
|
|
return out * self.opacity
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// VIEWS AND PANELS. A raised panel is sage enamel in a bronze wire with a
|
|
// fine gold line inside it, a sprig of leaves and a bud in its top right and
|
|
// bottom right corners; the sunken one a well of deeper parchment under the
|
|
// same wire, sprigs at its bottom corners. The words on both keep the sepia
|
|
// ink, at better than 6:1.
|
|
let md_plate = fn(p: vec2, size: vec2, o: vec2, px: float, r: float, sunken: float) -> vec4 {
|
|
let lo = vec2(Finish.snap(o.x, px), Finish.snap(o.y, px)) - o
|
|
let hi = vec2(Finish.snap(o.x + size.x, px), Finish.snap(o.y + size.y, px)) - o
|
|
let h = (hi - lo) * 0.5
|
|
let c = lo + h
|
|
let d = md_rbox(p, c, h, r)
|
|
let n = an_nrm(p, c, h, r)
|
|
var out = vec4(0.0, 0.0, 0.0, 0.0)
|
|
let s = clamp(min(size.x, size.y) / 80.0, 0.55, 1.1)
|
|
if sunken > 0.5 {
|
|
var face = an_parch(p, px, vec3(0.545, 0.616, 0.561))
|
|
let sh = clamp(Finish.inset(p, c, h - vec2(1.6, 1.6), r - 1.6, vec2(0.0, 2.0), 2.4), 0.0, 1.0)
|
|
face = mix(face, an_shade(), sh * 0.38)
|
|
let a = Finish.cover(d, px)
|
|
let lip = Finish.ring_out(d, 0.0, px, px) * smoothstep(0.0, h.y, p.y - c.y) * 0.5
|
|
out = Finish.over(out, vec4(vec3(0.98, 0.95, 0.88) * lip, lip))
|
|
out = Finish.over(out, vec4(face * a, a))
|
|
out = an_corner(out, p, lo, hi, 1.0, 3.5, s * 0.8, px)
|
|
out = an_corner(out, p, lo, hi, 2.0, 3.5, s, px)
|
|
out = Finish.over(out, an_fine(d, 3.4, max(px, 0.6), px, 0.6))
|
|
return Finish.over(out, an_wire(d, n, 1.6, px, 1.0))
|
|
}
|
|
out = an_drop(p, c, h, r, 1.0)
|
|
var face = an_enamel(p, c, h - vec2(1.6, 1.6), r - 1.6, vec3(0.580, 0.663, 0.596), 0.0, 0.0)
|
|
face = face + g3(Finish.grain(p / px, 0.008))
|
|
let a = Finish.cover(d, px)
|
|
out = Finish.over(out, vec4(face * a, a))
|
|
out = an_corner(out, p, lo, hi, 1.0, 3.5, s * 0.8, px)
|
|
out = an_corner(out, p, lo, hi, 2.0, 3.5, s, px)
|
|
out = Finish.over(out, an_fine(d, 3.4, max(px, 0.6), px, 0.7))
|
|
return Finish.over(out, an_wire(d, n, 1.6, px, 1.0))
|
|
}
|
|
|
|
mod.widgets.PanelView.clip_x = false
|
|
mod.widgets.PanelView.clip_y = false
|
|
mod.widgets.PanelView.draw_bg.vertex = fn() {
|
|
let g = md_grow(self.rect_pos, self.rect_size, 5.0)
|
|
self.vertex_pos = self.clip_and_transform_vertex(g.xy, g.zw)
|
|
}
|
|
mod.widgets.PanelView.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let m = 5.0
|
|
let p = self.pos * (self.rect_size + vec2(2.0 * m, 2.0 * m)) - vec2(m, m)
|
|
return md_plate(p, self.rect_size, self.rect_pos, px, 10.0, self.sunken)
|
|
}
|
|
|
|
// The card is an ivory leaf of parchment in a bronze wire and a fine gold
|
|
// line, a sprig in its bottom right corner and a smaller one top right. It
|
|
// lifts a little under the pointer.
|
|
mod.widgets.Card.radius = 10.0
|
|
mod.widgets.Card.draw_bg.vertex = fn() {
|
|
let g = md_grow(self.rect_pos, self.rect_size, 5.0)
|
|
return self.clip_and_transform_vertex(g.xy, g.zw)
|
|
}
|
|
mod.widgets.Card.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let m = 5.0
|
|
let size = self.rect_size
|
|
let p = self.pos * (size + vec2(2.0 * m, 2.0 * m)) - vec2(m, m)
|
|
let o = self.rect_pos
|
|
let lo = vec2(Finish.snap(o.x, px), Finish.snap(o.y, px)) - o
|
|
let hi = vec2(Finish.snap(o.x + size.x, px), Finish.snap(o.y + size.y, px)) - o
|
|
let h = (hi - lo) * 0.5
|
|
let c = lo + h
|
|
let r = 10.0
|
|
let d = md_rbox(p, c, h, r)
|
|
var out = an_drop(p, c, h, r, 1.0 + 0.4 * self.hover)
|
|
var face = an_parch(p, px, vec3(0.925, 0.878, 0.776))
|
|
face = Finish.lift(face, 0.05 * self.hover - 0.0 * self.down)
|
|
let a = Finish.cover(d, px)
|
|
out = Finish.over(out, vec4(face * a, a))
|
|
let s = clamp(min(size.x, size.y) / 80.0, 0.55, 1.1)
|
|
out = an_corner(out, p, lo, hi, 1.0, 3.5, s * 0.8, px)
|
|
out = an_corner(out, p, lo, hi, 2.0, 3.5, s, px)
|
|
out = Finish.over(out, an_fine(d, 3.4, max(px, 0.6), px, 0.75))
|
|
return Finish.over(out, an_wire(d, an_nrm(p, c, h, r), 1.6, px, 1.0))
|
|
}
|
|
|
|
// The plain rounded view keeps the colours its caller gives it; the edge is
|
|
// a snapped hairline at the true radius.
|
|
mod.widgets.RoundedView.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let p = self.pos * self.rect_size
|
|
var fill = self.color
|
|
if self.color_2.x > -0.5 {
|
|
fill = mix(self.color, self.color_2, mix(self.pos.y, self.pos.x, self.gradient_fill_horizontal))
|
|
}
|
|
let lo = vec2(self.border_inset.x, self.border_inset.y)
|
|
let hi = self.rect_size - vec2(self.border_inset.z, self.border_inset.w)
|
|
let h = (hi - lo) * 0.5
|
|
let c = lo + h
|
|
let d = md_rbox(p, c, h, max(self.border_radius * 2.0, 1.0))
|
|
var col = fill
|
|
if self.border_size > 0.0 {
|
|
col = mix(col, self.border_color, Finish.band(d, 0.0, max(self.border_size, px), px) * self.border_color.a)
|
|
}
|
|
let a = Finish.cover(d, px) * col.a
|
|
return vec4(col.rgb * a, a)
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// LISTS. Rows of 22 points on the parchment, parted by a faint bronze
|
|
// hairline; a hovered row takes a breath of ochre; the chosen row is an
|
|
// ochre enamel pill in its bronze wire, ending short of the scroll bar.
|
|
mod.widgets.ListItemOne.height = 22.0
|
|
mod.widgets.ListItem.padding = mod.turtle.Inset{left: 12.0 right: 8.0 top: 0.0 bottom: 0.0}
|
|
mod.widgets.ListItem.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let p = self.pos * self.rect_size
|
|
let o = self.rect_pos
|
|
let live = 1.0 - self.disabled
|
|
let lo = vec2(Finish.snap(o.x, px), Finish.snap(o.y, px)) - o
|
|
let hi = vec2(Finish.snap(o.x + self.rect_size.x, px), Finish.snap(o.y + self.rect_size.y, px)) - o
|
|
let lay = (self.hover * 0.16 + self.down * 0.10) * live * (1.0 - self.selected)
|
|
let hd = md_rbox(p, (lo + hi) * 0.5 - vec2(3.0, 0.0), (hi - lo) * 0.5 - vec2(5.0, 1.5), 8.0)
|
|
let la = Finish.cover(hd, px) * lay
|
|
var out = vec4(an_ochre() * la, la)
|
|
if self.selected > 0.5 {
|
|
let h = vec2((hi.x - lo.x) * 0.5 - 6.0, (hi.y - lo.y) * 0.5 - 1.5)
|
|
let c = vec2(lo.x + h.x + 2.0, (lo.y + hi.y) * 0.5)
|
|
let r = h.y
|
|
let d = md_rbox(p, c, h, r)
|
|
out = Finish.over(out, an_contact(p, c, h, r, 1.0))
|
|
let face = an_enamel(p, c, h - vec2(1.3, 1.3), r - 1.3, an_ochre(), 0.0, 0.0)
|
|
let a = Finish.cover(d, px)
|
|
out = Finish.over(out, vec4(face * a, a))
|
|
out = Finish.over(out, an_wire(d, an_nrm(p, c, h, r), 1.3, px, 1.0))
|
|
}
|
|
let yb = hi.y
|
|
let dk = step(yb - max(px, 0.6), p.y) * step(p.y, yb) * step(lo.x + 4.0, p.x) * step(p.x, hi.x - 8.0) * 0.30 * (1.0 - self.selected)
|
|
out = Finish.over(out, vec4(an_line_c() * dk, dk))
|
|
return out
|
|
}
|
|
mod.widgets.ListItem.draw_text.color = #2a2116
|
|
|
|
// The open list of a drop-down: an ivory leaf in a bronze wire and a fine
|
|
// gold line, with a soft shadow; the row under the pointer an ochre wash,
|
|
// the chosen row a teal check.
|
|
mod.widgets.PopupMenuFlat.clip_x = false
|
|
mod.widgets.PopupMenuFlat.clip_y = false
|
|
mod.widgets.PopupMenuFlat.draw_bg.vertex = fn() {
|
|
let g = md_grow(self.rect_pos, self.rect_size, 10.0)
|
|
self.vertex_pos = self.clip_and_transform_vertex(g.xy, g.zw)
|
|
}
|
|
mod.widgets.PopupMenuFlat.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let m = 10.0
|
|
let size = self.rect_size
|
|
let p = self.pos * (size + vec2(2.0 * m, 2.0 * m)) - vec2(m, m)
|
|
let o = self.rect_pos
|
|
let lo = vec2(Finish.snap(o.x, px), Finish.snap(o.y, px)) - o
|
|
let hi = vec2(Finish.snap(o.x + size.x, px), Finish.snap(o.y + size.y, px)) - o
|
|
let h = (hi - lo) * 0.5
|
|
let c = lo + h
|
|
let r = 8.0
|
|
let d = md_rbox(p, c, h, r)
|
|
let sh = Finish.drop(p, c, h, r, vec2(0.5, 2.5), 2.2) * 0.22
|
|
var out = vec4(an_shade() * sh, sh)
|
|
let face = an_parch(p, px, vec3(0.925, 0.878, 0.776))
|
|
let a = Finish.cover(d, px)
|
|
out = Finish.over(out, vec4(face * a, a))
|
|
out = Finish.over(out, an_fine(d, 3.0, max(px, 0.6), px, 0.7))
|
|
return Finish.over(out, an_wire(d, an_nrm(p, c, h, r), 1.5, px, 1.0))
|
|
}
|
|
mod.widgets.PopupMenuItem.padding.left = 18.0
|
|
mod.widgets.PopupMenuItem.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let p = self.pos * self.rect_size
|
|
let c = self.rect_size * 0.5
|
|
let h = c - vec2(3.0, 0.5)
|
|
let d = md_rbox(p, c, h, h.y)
|
|
let live = 1.0 - self.disabled
|
|
let wa = Finish.cover(d, px) * self.hover * live * 0.45
|
|
var out = vec4(an_ochre() * wa, wa)
|
|
let m0 = vec2(5.0, c.y + 0.2)
|
|
let m1 = vec2(7.2, c.y + 2.4)
|
|
let m2 = vec2(10.6, c.y - 2.6)
|
|
let mk = Finish.cover(min(md_seg(p, m0, m1), md_seg(p, m1, m2)) - 0.75, px) * self.active
|
|
return Finish.over(out, vec4(an_teal_dk() * mk, mk))
|
|
}
|
|
|
|
// The dock's tabs: the bar is the parchment with a bronze line at its foot;
|
|
// the tab in use an ivory leaf rounded at the top in its wire, open at the
|
|
// foot where it joins the panel below; the others lift under the pointer.
|
|
mod.widgets.Tab.padding = mod.turtle.Inset{left: 12.0 right: 12.0 top: 4.0 bottom: 4.0}
|
|
mod.widgets.Tab.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let p = self.pos * self.rect_size
|
|
let o = self.rect_pos
|
|
let lo = vec2(Finish.snap(o.x, px), Finish.snap(o.y + 2.0, px)) - o
|
|
let hi = vec2(Finish.snap(o.x + self.rect_size.x, px), Finish.snap(o.y + self.rect_size.y, px)) - o + vec2(0.0, 8.0)
|
|
let h = (hi - lo) * 0.5
|
|
let c = lo + h
|
|
let r = 7.0
|
|
let d = md_rbox(p, c, h, r)
|
|
let face = an_parch(p, px, vec3(0.925, 0.878, 0.776))
|
|
let a = Finish.cover(d, px) * self.active
|
|
var out = vec4(face * a, a)
|
|
out = Finish.over(out, an_wire(d, an_nrm(p, c, h, r), 1.3, px, 1.0) * self.active)
|
|
let lift = Finish.cover(d, px) * 0.18 * self.hover * (1.0 - self.active)
|
|
return Finish.over(vec4(vec3(1.0, 0.97, 0.9) * lift, lift), out)
|
|
}
|
|
mod.widgets.TabBar.draw_fill.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let p = self.pos * self.rect_size
|
|
let yb = Finish.snap(self.rect_pos.y + self.rect_size.y, px) - self.rect_pos.y
|
|
let dk = step(yb - 1.3, p.y) * step(p.y, yb) * 0.9
|
|
return vec4(an_line_c() * dk, dk)
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// CHIPS AND BADGES. A chip is a small ivory pill (teal enamel while chosen);
|
|
// a badge a small teal enamel pill with ivory figures.
|
|
mod.widgets.ChipFlat.size = mod.widgets.ChipSize.Small
|
|
mod.widgets.Chip.size = mod.widgets.ChipSize.Small
|
|
mod.widgets.ChipFlat.draw_bg.vertex = fn() {
|
|
let g = md_grow(self.rect_pos, self.rect_size, 6.0)
|
|
self.vertex_pos = self.clip_and_transform_vertex(g.xy, g.zw)
|
|
}
|
|
mod.widgets.ChipFlat.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let m = 6.0
|
|
let ch = min(22.0, self.rect_size.y)
|
|
let dy = (self.rect_size.y - ch) * 0.5
|
|
let sz = vec2(self.rect_size.x, ch)
|
|
let p = self.pos * (self.rect_size + vec2(2.0 * m, 2.0 * m)) - vec2(m, m)
|
|
let pp = (p - vec2(0.0, dy) + vec2(m, m)) / (sz + vec2(2.0 * m, 2.0 * m))
|
|
let has_fill = step(0.05, self.color.a) * step(0.6, Finish.lum(self.ink.rgb))
|
|
let kind = mix(mix(6.0, 5.0, step(0.01, self.border_size)), 0.0, has_fill)
|
|
let kk = mix(7.0, kind, step(0.5, has_fill + step(0.01, self.border_size)))
|
|
return an_button(pp, sz, self.rect_pos + vec2(0.0, dy), px, self.hover, self.down, self.keyed, 0.0, 0.0, 0.0, vec4(99.0, 99.0, 99.0, 99.0), kk, m)
|
|
}
|
|
mod.widgets.ChipFlat.draw_text.text_style = mod.theme.font_label{font_size: 10.0}
|
|
mod.widgets.BadgePalette.neutral = #46635a
|
|
mod.widgets.BadgePalette.on_neutral = #f3e8cf
|
|
mod.widgets.BadgeFlat.draw_text.text_style = mod.theme.font_bold{font_size: 9.0}
|
|
mod.widgets.Badge.draw_text.text_style = mod.theme.font_bold{font_size: 9.0}
|
|
mod.widgets.BadgeFlat.clip_x = false
|
|
mod.widgets.BadgeFlat.clip_y = false
|
|
mod.widgets.BadgeFlat.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let p = self.pos * self.rect_size
|
|
let o = self.rect_pos
|
|
let bh = min(18.0, self.rect_size.y - 2.0)
|
|
let y0 = Finish.snap(o.y + (self.rect_size.y - bh) * 0.5, px) - o.y
|
|
let lo = vec2(Finish.snap(o.x + 1.0, px) - o.x, y0)
|
|
let hi = vec2(Finish.snap(o.x + self.rect_size.x - 1.0, px) - o.x, Finish.snap(o.y + y0 + bh, px) - o.y)
|
|
let h = (hi - lo) * 0.5
|
|
let c = lo + h
|
|
let r = h.y
|
|
let d = md_rbox(p, c, h, r)
|
|
var out = an_contact(p, c, h, r, 1.0)
|
|
let face = an_enamel(p, c, h - vec2(1.2, 1.2), r - 1.2, self.color.rgb, 0.0, 0.0)
|
|
let a = Finish.cover(d, px)
|
|
out = Finish.over(out, vec4(face * a, a))
|
|
out = Finish.over(out, an_wire(d, an_nrm(p, c, h, r), 1.2, px, 1.0))
|
|
return out * self.color.a
|
|
}
|
|
|
|
// The spinner keeps its stock turning face (it runs on the pass clock, which
|
|
// a face may not read), in teal on a faint track.
|
|
mod.widgets.SpinnerFlat.draw_bg.color = #46635a
|
|
mod.widgets.SpinnerFlat.draw_bg.stroke_width = 2.5
|
|
mod.widgets.SpinnerFlat.draw_bg.track_alpha = 0.25
|
|
|
|
// Rules between groups: a bronze-gold hairline with a small lozenge at its
|
|
// middle.
|
|
mod.widgets.Hr.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let p = self.pos * self.rect_size
|
|
let y = Finish.snap(self.rect_pos.y + self.rect_size.y * 0.5, px) - self.rect_pos.y
|
|
let ln = (1.0 - smoothstep(0.35, 0.35 + px, abs(p.y - y))) * 0.8
|
|
let lq = abs(p - vec2(self.rect_size.x * 0.5, y))
|
|
let lz = Finish.cover(lq.x * 0.6 + lq.y - 2.0, px)
|
|
let a = max(ln, lz)
|
|
return vec4(an_line_c() * a, a)
|
|
}
|
|
mod.widgets.Vr.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let p = self.pos * self.rect_size
|
|
let x = Finish.snap(self.rect_pos.x + self.rect_size.x * 0.5, px) - self.rect_pos.x
|
|
let a = (1.0 - smoothstep(0.35, 0.35 + px, abs(p.x - x))) * 0.8
|
|
return vec4(an_line_c() * a, a)
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// THE TREE. Its rows stand on the parchment, clear; the open row is an
|
|
// ochre enamel pill in its bronze wire, as the chosen row of a list.
|
|
mod.widgets.FileTreeNode.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let p = self.pos * self.rect_size
|
|
let lo = vec2(2.0, 1.5)
|
|
let hi = self.rect_size - vec2(4.0, 1.5)
|
|
let h = (hi - lo) * 0.5
|
|
let c = lo + h
|
|
let r = h.y
|
|
let d = md_rbox(p, c, h, r)
|
|
let face = an_enamel(p, c, h - vec2(1.2, 1.2), r - 1.2, an_ochre(), 0.0, 0.0)
|
|
let a = Finish.cover(d, px)
|
|
var out = vec4(face * a, a)
|
|
out = Finish.over(out, an_wire(d, an_nrm(p, c, h, r), 1.2, px, 1.0))
|
|
return out * self.active
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// STATES. Every held state is written as a plain value that cuts in at once:
|
|
// the library writes some as snap() values, which a state held as a default
|
|
// (the states page) never applies. Live, the cut is the same as the snap.
|
|
mod.widgets.ButtonFlat.animator.hover.on.from = {all: Snap}
|
|
mod.widgets.ButtonFlat.animator.hover.on.apply = {draw_bg: {down: 0.0 hover: 1.0} draw_text: {down: 0.0 hover: 1.0}}
|
|
mod.widgets.ButtonFlat.animator.hover.down.from = {all: Snap}
|
|
mod.widgets.ButtonFlat.animator.hover.down.apply = {draw_bg: {down: 1.0 hover: 1.0} draw_text: {down: 1.0 hover: 1.0}}
|
|
mod.widgets.CheckBoxFlat.animator.hover.on.from = {all: Snap}
|
|
mod.widgets.CheckBoxFlat.animator.hover.on.apply = {draw_bg: {down: 0.0 hover: 1.0} draw_text: {down: 0.0 hover: 1.0}}
|
|
mod.widgets.CheckBoxFlat.animator.hover.down.from = {all: Snap}
|
|
mod.widgets.CheckBoxFlat.animator.hover.down.apply = {draw_bg: {down: 1.0 hover: 1.0} draw_text: {down: 1.0 hover: 1.0}}
|
|
mod.widgets.ToggleFlat.animator.hover.on.from = {all: Snap}
|
|
mod.widgets.ToggleFlat.animator.hover.on.apply = {draw_bg: {down: 0.0 hover: 1.0} draw_text: {down: 0.0 hover: 1.0}}
|
|
mod.widgets.ToggleFlat.animator.hover.down.from = {all: Snap}
|
|
mod.widgets.ToggleFlat.animator.hover.down.apply = {draw_bg: {down: 1.0 hover: 1.0} draw_text: {down: 1.0 hover: 1.0}}
|
|
mod.widgets.RadioButtonFlat.animator.hover.on.from = {all: Snap}
|
|
mod.widgets.RadioButtonFlat.animator.hover.on.apply = {draw_bg: {down: 0.0 hover: 1.0} draw_text: {down: 0.0 hover: 1.0}}
|
|
mod.widgets.RadioButtonFlat.animator.hover.down.from = {all: Snap}
|
|
mod.widgets.RadioButtonFlat.animator.hover.down.apply = {draw_bg: {down: 1.0 hover: 1.0} draw_text: {down: 1.0 hover: 1.0}}
|
|
mod.widgets.TextInputFlat.animator.hover.on.from = {all: Snap}
|
|
mod.widgets.TextInputFlat.animator.hover.on.apply = {draw_bg: {down: 0.0 hover: 1.0} draw_text: {down: 0.0 hover: 1.0}}
|
|
mod.widgets.TextInputFlat.animator.hover.down.from = {all: Snap}
|
|
mod.widgets.TextInputFlat.animator.hover.down.apply = {draw_bg: {down: 1.0 hover: 1.0} draw_text: {down: 1.0 hover: 1.0}}
|
|
mod.widgets.DropDownFlat.animator.hover.on.from = {all: Snap}
|
|
mod.widgets.DropDownFlat.animator.hover.on.apply = {draw_bg: {down: 0.0 hover: 1.0} draw_text: {down: 0.0 hover: 1.0}}
|
|
mod.widgets.DropDownFlat.animator.hover.down.from = {all: Snap}
|
|
mod.widgets.DropDownFlat.animator.hover.down.apply = {draw_bg: {down: 1.0 hover: 1.0} draw_text: {down: 1.0 hover: 1.0}}
|
|
mod.widgets.SliderFlat.animator.hover.on.from = {all: Snap}
|
|
mod.widgets.SliderFlat.animator.hover.on.apply = {draw_bg: {hover: 1.0} draw_text: {hover: 1.0}}
|
|
mod.widgets.SliderFlat.animator.drag.on.from = {all: Snap}
|
|
mod.widgets.SliderFlat.animator.drag.on.apply = {draw_bg: {drag: 1.0} draw_text: {drag: 1.0}}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// THE WINDOW'S GROUND. Parchment, held in a frame of teal enamel bands edged
|
|
// with bronze-gold wire: a band along the top where the window's caption
|
|
// stands, with a parchment cartouche under the title and lily sprays in its
|
|
// two ends; a header of parchment under it where the catalogue's toolbar
|
|
// stands; a band under the header; the panes' parchment; and a band round
|
|
// the window's other three edges. Between the panes the splitters draw the
|
|
// same band. The heavy detail is all on the bands and in the corners; the
|
|
// panes are calm, only the faint mottle and the fibre.
|
|
|
|
// A lily spray along the top band, in the band's own frame: x along it from
|
|
// its anchor, y down from the window's top edge, about 250 points long. A
|
|
// whiplash stem in two arcs ending in a tendril's curl; a second stem with a
|
|
// bud on it; a short one carrying a small dusty rose lily; leaves along
|
|
// them, turned up and down by turns; a large lily at its root.
|
|
let an_band_spray = fn(dst: vec4, q: vec2, px: float) -> vec4 {
|
|
var out = dst
|
|
if q.x > 262.0 {
|
|
return out
|
|
}
|
|
let dk = vec3(0.420, 0.580, 0.486)
|
|
let lt = vec3(0.616, 0.737, 0.627)
|
|
let stem = vec3(0.500, 0.650, 0.560)
|
|
// the curl and the two arcs of the whiplash
|
|
out = an_lay(out, an_spiral(q, vec2(246.0, 12.0), 2.2, 2.0, PI) - 0.6, stem, 0.35, px)
|
|
out = an_lay_stem(out, an_bez(q, vec2(2.0, 29.0), vec2(46.0, 0.0), vec2(118.0, 15.0)), 1.7, 1.1, stem, px)
|
|
out = an_lay_stem(out, an_bez(q, vec2(118.0, 15.0), vec2(190.0, 30.0), vec2(241.6, 12.0)), 1.1, 0.6, stem, px)
|
|
// the second stem and its bud; the short stem with the rose lily
|
|
out = an_lay_stem(out, an_bez(q, vec2(58.0, 11.0), vec2(90.0, 31.0), vec2(150.0, 26.0)), 1.0, 0.6, stem, px)
|
|
out = an_lay_stem(out, an_bez(q, vec2(146.0, 21.5), vec2(156.0, 9.0), vec2(174.0, 12.0)), 0.9, 0.6, stem, px)
|
|
out = an_lay_leaf(out, an_leaf(q, vec2(28.0, 15.0), normalize(vec2(1.0, -0.42)), 21.0, 4.0, -1.8), dk, lt, 0.5, px)
|
|
out = an_lay_leaf(out, an_leaf(q, vec2(66.0, 8.5), normalize(vec2(1.0, 0.45)), 19.0, 3.6, 1.8), dk, lt, 0.5, px)
|
|
out = an_lay_leaf(out, an_leaf(q, vec2(96.0, 13.0), normalize(vec2(1.0, -0.55)), 16.0, 3.0, -1.4), dk, lt, 0.5, px)
|
|
out = an_lay_leaf(out, an_leaf(q, vec2(104.0, 25.5), normalize(vec2(1.0, 0.15)), 15.0, 2.8, 1.2), dk, lt, 0.5, px)
|
|
out = an_lay_leaf(out, an_leaf(q, vec2(136.0, 20.5), normalize(vec2(1.0, 0.42)), 17.0, 3.2, 1.6), dk, lt, 0.5, px)
|
|
out = an_lay_leaf(out, an_leaf(q, vec2(196.0, 23.5), normalize(vec2(1.0, -0.62)), 16.0, 3.0, -1.4), dk, lt, 0.5, px)
|
|
out = an_lay_leaf(out, an_leaf(q, vec2(214.0, 20.0), normalize(vec2(1.0, 0.5)), 12.0, 2.4, 1.0), dk, lt, 0.45, px)
|
|
out = an_lay_leaf(out, an_leaf(q, vec2(8.0, 23.0), normalize(vec2(0.6, 1.0)), 9.0, 2.6, 1.0), dk, lt, 0.5, px)
|
|
out = an_bud(out, q, vec2(150.0, 26.0), normalize(vec2(1.0, -0.1)), 9.0, px)
|
|
out = an_lily(out, q, vec2(175.0, 12.5), 8.5, 0.7, px, 1.0)
|
|
out = an_lily(out, q, vec2(16.0, 15.5), 13.0, 0.4, px, 0.0)
|
|
return out
|
|
}
|
|
|
|
// The small ornament in a bottom corner of the window, `q` in points from
|
|
// the corner along its two edges: a tendril's curl in the spandrel the
|
|
// panes' rounded corner leaves, a leaf running out along each edge from it
|
|
// and a gold bud on the diagonal. Nothing of it reaches the pane's hole.
|
|
let an_foot_corner = fn(dst: vec4, q: vec2, px: float) -> vec4 {
|
|
var out = dst
|
|
let dk = vec3(0.420, 0.580, 0.486)
|
|
let lt = vec3(0.616, 0.737, 0.627)
|
|
let stem = vec3(0.500, 0.650, 0.560)
|
|
out = an_lay_leaf(out, an_leaf(q, vec2(9.0, 3.0), vec2(1.0, 0.0), 30.0, 1.6, -0.5), dk, lt, 0.4, px)
|
|
out = an_lay_leaf(out, an_leaf(q, vec2(3.0, 9.0), vec2(0.0, 1.0), 30.0, 1.6, 0.5), dk, lt, 0.4, px)
|
|
out = an_lay(out, an_spiral(q, vec2(9.6, 9.6), 1.35, 2.0, PI * 1.25) - 0.45, stem, 0.3, px)
|
|
out = an_lay(out, length(q - vec2(4.6, 4.6)) - 1.5, mix(an_bronze_c(), an_gold_hi(), 0.5), 0.35, px)
|
|
return out
|
|
}
|
|
|
|
mod.widgets.Window.show_bg = true
|
|
mod.widgets.Window.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let p = self.pos * self.rect_size
|
|
let W = self.rect_size.x
|
|
let H = self.rect_size.y
|
|
var col = an_parch(p, px, an_parch_c())
|
|
// the two holes in the frame: the header and the panes
|
|
let hc = vec2(W * 0.5, 60.0)
|
|
let hh = vec2(W * 0.5 - 6.0, 27.0)
|
|
let pc = vec2(W * 0.5, (95.0 + H - 6.0) * 0.5)
|
|
let ph = vec2(W * 0.5 - 6.0, (H - 6.0 - 95.0) * 0.5)
|
|
let dh = md_rbox(p, hc, hh, 14.0)
|
|
// the panes' outer foot corners are wider arches: in the spandrels
|
|
// they leave the frame carries its foot ornaments
|
|
let pr = md_r4(p, pc, ph, vec4(12.0, 12.0, 26.0, 26.0))
|
|
let dp = md_rbox(p, pc, ph, pr)
|
|
var dhole = dp
|
|
var nh = an_nrm(p, pc, ph, pr)
|
|
if dh < dp {
|
|
dhole = dh
|
|
nh = an_nrm(p, hc, hh, 14.0)
|
|
}
|
|
// the header is a lighter leaf of parchment
|
|
col = mix(col, Finish.lift(col, 0.12), Finish.cover(dh, px))
|
|
// the parchment is aged toward the frame: a warm browning that fades
|
|
// out some thirty points in, never a stain in the middle
|
|
let age = 1.0 - smoothstep(0.0, 34.0, 0.0 - dhole)
|
|
col = mix(col, col * vec3(0.84, 0.77, 0.66), age * age * 0.55)
|
|
// the frame's shade on the parchment along each hole's upper and left
|
|
// edges, three points deep
|
|
let sh = (1.0 - smoothstep(0.0, 3.5, 0.0 - dhole)) * Finish.cover(dhole, px) * (0.5 + 0.5 * clamp(0.0 - nh.y - nh.x * 0.5, 0.0, 1.0))
|
|
col = mix(col, col * 0.80, sh * 0.6)
|
|
// the teal bands
|
|
let band = Finish.cover(0.0 - dhole, px)
|
|
var teal = an_teal() * (1.0 + (Finish.noise(p * 0.11) - 0.5) * 0.05) + g3(Finish.grain(p / px, 0.008))
|
|
teal = mix(teal, teal * 1.12, (1.0 - smoothstep(0.0, 33.0, p.y)) * 0.4)
|
|
col = mix(col, teal, band)
|
|
// the window's outer edge: a darker teal lip and a bronze wire
|
|
let dw = md_rbox(p, vec2(W, H) * 0.5, vec2(W, H) * 0.5, 0.0)
|
|
let nw = an_nrm(p, vec2(W, H) * 0.5, vec2(W, H) * 0.5, 0.0)
|
|
var out = vec4(col, 1.0)
|
|
// THE CARTOUCHE under the title, and its whiplash scrolls
|
|
let cc = vec2(W * 0.5, 16.0)
|
|
let ch = vec2(84.0, 12.5)
|
|
let cd = md_rbox(p, cc, ch, 12.5)
|
|
if abs(p.x - cc.x) < 140.0 && p.y < 35.0 {
|
|
let cw = an_parch(p, px, vec3(0.925, 0.878, 0.776))
|
|
out = an_lay(out, cd, cw, 0.0, px)
|
|
out = Finish.over(out, an_fine(cd, 2.6, max(px, 0.6), px, 0.7))
|
|
out = Finish.over(out, an_wire(cd, an_nrm(p, cc, ch, 12.5), 1.5, px, 1.0))
|
|
let sx = abs(p.x - cc.x)
|
|
let sq = vec2(sx, p.y)
|
|
out = an_lay(out, an_spiral(sq, vec2(ch.x + 22.0, 13.0), 2.0, 2.0, 2.6) - 0.7, mix(an_bronze_c(), an_gold_hi(), 0.3), 0.0, px)
|
|
out = an_lay_stem(out, an_bez(sq, vec2(ch.x - 2.0, 25.0), vec2(ch.x + 14.0, 30.0), vec2(ch.x + 18.6, 15.1)), 1.0, 0.6, mix(an_bronze_c(), an_gold_hi(), 0.3), px)
|
|
}
|
|
// THE SPRAYS in the top band's two ends, kept clear of the cartouche
|
|
if p.y < 35.0 && p.x < min(270.0, W * 0.5 - 122.0) {
|
|
out = an_band_spray(out, vec2(p.x - 6.0, p.y), px)
|
|
}
|
|
if p.y < 35.0 && p.x > max(W - 410.0, W * 0.5 + 122.0) && p.x < W - 138.0 {
|
|
out = an_band_spray(out, vec2(W - 138.0 - p.x, p.y), px)
|
|
}
|
|
// the foot corners
|
|
if p.y > H - 40.0 && (p.x < 40.0 || p.x > W - 40.0) {
|
|
out = an_foot_corner(out, vec2(min(p.x, W - p.x), H - p.y), px)
|
|
}
|
|
// the bronze wire along every hole's edge, on the band's side
|
|
out = Finish.over(out, an_wire(0.0 - dhole, nh * -1.0, 1.5, px, 1.0))
|
|
out = Finish.over(out, an_fine(0.0 - dhole, 2.6, max(px, 0.5), px, 0.35 * step(39.0, p.y)))
|
|
out = Finish.over(out, an_wire(dw, nw, 1.6, px, 1.0))
|
|
return vec4(out.rgb, 1.0)
|
|
}
|
|
|
|
// A splitter is the frame's teal band run down between two panes, ten
|
|
// points wide, its bronze wires turning into the header's band above and
|
|
// the foot band below with rounded corners, as the panes' corners are.
|
|
mod.widgets.Splitter.draw_bg.vertex = fn() {
|
|
let g = md_grow(self.rect_pos, self.rect_size, 14.0)
|
|
self.vertex_pos = self.clip_and_transform_vertex(g.xy, g.zw)
|
|
}
|
|
mod.widgets.Splitter.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let m = 14.0
|
|
let size = self.rect_size
|
|
let p = self.pos * (size + vec2(2.0 * m, 2.0 * m)) - vec2(m, m)
|
|
let v = self.is_vertical
|
|
// work in the bar's own frame: `a` along it, `b` across it
|
|
let a = mix(p.x, p.y, v)
|
|
let b = mix(p.y, p.x, v)
|
|
let along = mix(size.x, size.y, v)
|
|
let thick = mix(size.y, size.x, v)
|
|
let mid = thick * 0.5
|
|
let hw = 5.0
|
|
let r = 12.0
|
|
let a0 = 4.0
|
|
let a1 = along - 6.0
|
|
// the panes either side, as rounded boxes
|
|
let q = vec2(b, a)
|
|
let lc = vec2(mid - hw - 200.0, (a0 + a1) * 0.5)
|
|
let rc = vec2(mid + hw + 200.0, (a0 + a1) * 0.5)
|
|
let ph = vec2(200.0, (a1 - a0) * 0.5)
|
|
let dl = md_rbox(q, lc, ph, r)
|
|
let dr = md_rbox(q, rc, ph, r)
|
|
var dh = dl
|
|
var nh = an_nrm(q, lc, ph, r)
|
|
if dr < dl {
|
|
dh = dr
|
|
nh = an_nrm(q, rc, ph, r)
|
|
}
|
|
// the header above: everything before -4 along the bar
|
|
let dt = a + 4.0
|
|
if dt < dh {
|
|
dh = dt
|
|
nh = vec2(0.0, 1.0)
|
|
}
|
|
let inside = step(-8.0, a) * step(a, along - 1.6) * step(abs(b - mid), hw + r + 0.5)
|
|
let band = Finish.cover(0.0 - dh, px) * inside
|
|
var teal = an_teal() * (1.0 + (Finish.noise((p + self.rect_pos) * 0.11) - 0.5) * 0.05)
|
|
let act = max(max(self.hover, self.drag), self.focus)
|
|
teal = Finish.lift(teal, 0.08 * act)
|
|
var out = vec4(teal * band, band)
|
|
let nn = vec2(mix(nh.y, nh.x, v), mix(nh.x, nh.y, v))
|
|
out = Finish.over(out, an_wire(0.0 - dh, nn * -1.0, 1.5, px, 1.0) * inside)
|
|
// under the hand, a gold line down the middle of the grip
|
|
let inbar = 1.0 - smoothstep(self.bar_size * 0.5 - 2.0, self.bar_size * 0.5, abs(a - along * 0.5))
|
|
let gl = (1.0 - smoothstep(0.5, 0.5 + px, abs(b - mid))) * inbar * act
|
|
out = Finish.over(out, vec4(an_gold_hi() * gl, gl))
|
|
return out
|
|
}
|
|
|
|
// ---------------------------------------------------------------- switches and meter
|
|
|
|
// THE SWITCHES are the sheet's own toggle: the rocker carries a bronze disc
|
|
// (the metal of a lever), the slide switch the ivory one, both riding in the
|
|
// sunk pill, teal when on.
|
|
mod.widgets.ToggleRocker.label_walk.margin = mod.turtle.Inset{left: 46.0 right: 3.0 top: 0.0 bottom: 0.0}
|
|
mod.widgets.ToggleSlide.label_walk.margin = mod.turtle.Inset{left: 46.0 right: 3.0 top: 0.0 bottom: 0.0}
|
|
mod.widgets.ToggleRocker.draw_bg.size = 14.0
|
|
mod.widgets.ToggleSlide.draw_bg.size = 14.0
|
|
mod.widgets.ToggleRocker.min_height = 24.0
|
|
mod.widgets.ToggleSlide.min_height = 24.0
|
|
mod.widgets.ToggleRocker.draw_bg.pill_aspect = 2.7143
|
|
mod.widgets.ToggleSlide.draw_bg.pill_aspect = 2.7143
|
|
mod.widgets.ToggleRocker.draw_bg.knob_inset = 7.0
|
|
mod.widgets.ToggleSlide.draw_bg.knob_inset = 7.0
|
|
mod.widgets.ToggleRocker.clip_x = false
|
|
mod.widgets.ToggleRocker.clip_y = false
|
|
mod.widgets.ToggleSlide.clip_x = false
|
|
mod.widgets.ToggleSlide.clip_y = false
|
|
mod.widgets.ToggleRocker.draw_bg.vertex = mod.widgets.ToggleFlat.draw_bg.vertex
|
|
mod.widgets.ToggleSlide.draw_bg.vertex = mod.widgets.ToggleFlat.draw_bg.vertex
|
|
mod.widgets.ToggleRocker.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
return an_toggle(self.pos, self.rect_size, self.rect_pos, px, self.active, self.drag_pos, self.drag, self.hover, self.down, self.focus, self.disabled, self.error, self.mark_at_end, 1.0)
|
|
}
|
|
mod.widgets.ToggleSlide.draw_bg.pixel = fn() {
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
return an_toggle(self.pos, self.rect_size, self.rect_pos, px, self.active, self.drag_pos, self.drag, self.hover, self.down, self.focus, self.disabled, self.error, self.mark_at_end, 0.0)
|
|
}
|
|
|
|
// THE GLASS of the readouts, the screen and the meter: deep teal glass with
|
|
// the faint unevenness of cathedral glass and a soft sheen across its upper
|
|
// left, set behind a bronze wire, a dark gap and a fine gold line, its
|
|
// corners rounded; the surround's shade falls in under its top edge.
|
|
let an_glass = fn(p: vec2, lo: vec2, hi: vec2, r4: vec4, px: float, face: vec3) -> vec4 {
|
|
let h = (hi - lo) * 0.5
|
|
let c = lo + h
|
|
let r = md_r4(p, c, h, r4)
|
|
let d = md_rbox(p, c, h, r)
|
|
var out = an_drop(p, c, h, r, 0.8)
|
|
let hf = h - vec2(1.8, 1.8)
|
|
var g = face * (1.0 + (Finish.noise(p * 0.21 + vec2(4.0, 9.0)) - 0.5) * 0.035 + (Finish.noise(p * 0.6) - 0.5) * 0.025)
|
|
let u = (p - lo) / max(hi - lo, vec2(1.0, 1.0))
|
|
let diag = u.x * 0.8 + u.y
|
|
let sheen = smoothstep(0.0, 0.25, diag) * (1.0 - smoothstep(0.35, 0.75, diag)) * 0.06
|
|
g = g + vec3(0.95, 0.92, 0.80) * sheen
|
|
g = mix(g, vec3(0.03, 0.05, 0.04), clamp(Finish.inset(p, c, hf, max(r - 1.8, 0.0), vec2(0.0, 2.2), 2.0), 0.0, 1.0) * 0.55)
|
|
let a = Finish.cover(d, px)
|
|
out = Finish.over(out, vec4(g * a, a))
|
|
out = Finish.over(out, an_fine(d, 3.0, max(px, 0.55), px, 0.5))
|
|
return Finish.over(out, an_wire(d, an_nrm(p, c, h, r), 1.8, px, 1.0))
|
|
}
|
|
|
|
mod.widgets.ScreenView.clip_x = false
|
|
mod.widgets.ScreenView.clip_y = false
|
|
mod.widgets.ScreenView.padding = mod.turtle.Inset{top: 8.0 right: 11.0 bottom: 8.0 left: 11.0}
|
|
mod.widgets.ScreenView.draw_bg.vertex = fn() {
|
|
let g = md_grow(self.rect_pos, self.rect_size, 5.0)
|
|
self.vertex_pos = self.clip_and_transform_vertex(g.xy, g.zw)
|
|
}
|
|
mod.widgets.ScreenView.draw_bg.pixel = fn() {
|
|
let m = 5.0
|
|
let p = self.pos * (self.rect_size + vec2(2.0 * m, 2.0 * m)) - vec2(m, m)
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let lo = vec2(Finish.snap(self.rect_pos.x, px), Finish.snap(self.rect_pos.y, px)) - self.rect_pos
|
|
let hi = vec2(Finish.snap(self.rect_pos.x + self.rect_size.x, px), Finish.snap(self.rect_pos.y + self.rect_size.y, px) - px) - self.rect_pos
|
|
return an_glass(p, lo, hi, vec4(9.0, 9.0, 9.0, 9.0), px, self.color.rgb)
|
|
}
|
|
mod.widgets.ScreenView.bezel = 3.0
|
|
mod.widgets.ScreenView.sheen = 0.02
|
|
|
|
// THE METER sits in the same glass: its window arched at the top, the scale
|
|
// a fine gold arc with gold ticks, the colour band under it running sage to
|
|
// ochre to terracotta, the needle an ivory spear and its pivot a bronze boss.
|
|
mod.widgets.NeedleMeter.clip_x = false
|
|
mod.widgets.NeedleMeter.clip_y = false
|
|
mod.widgets.NeedleMeter.draw_bg.border_radius = uniform(9.0)
|
|
mod.widgets.NeedleMeter.draw_bg.color = uniform(#213530)
|
|
mod.widgets.NeedleMeter.draw_bg.color_needle = uniform(#xf3e8cf)
|
|
mod.widgets.NeedleMeter.draw_bg.color_zone = uniform(#xd0603f)
|
|
mod.widgets.NeedleMeter.draw_bg.color_scale = uniform(#xe6c47e)
|
|
mod.widgets.NeedleMeter.draw_bg.vertex = fn() {
|
|
let g = md_grow(self.rect_pos, self.rect_size, 5.0)
|
|
self.vertex_pos = self.clip_and_transform_vertex(g.xy, g.zw)
|
|
}
|
|
mod.widgets.NeedleMeter.draw_bg.pixel = fn() {
|
|
let m = 5.0
|
|
let p = self.pos * (self.rect_size + vec2(2.0 * m, 2.0 * m)) - vec2(m, m)
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let lo = vec2(Finish.snap(self.rect_pos.x, px), Finish.snap(self.rect_pos.y, px)) - self.rect_pos
|
|
let hi = vec2(Finish.snap(self.rect_pos.x + self.rect_size.x, px), Finish.snap(self.rect_pos.y + self.rect_size.y, px) - px) - self.rect_pos
|
|
let r = min(self.border_radius, min(hi.x - lo.x, hi.y - lo.y) * 0.5)
|
|
let rt = min(34.0, min(hi.x - lo.x, hi.y - lo.y) * 0.45)
|
|
var out = an_glass(p, lo, hi, vec4(rt, rt, r, r), px, an_glass_c())
|
|
let pv = self.pivot()
|
|
let rr = self.scale_radius()
|
|
let q = p - pv
|
|
let rq = length(q)
|
|
let ang = atan2(q.x, 0.0 - q.y)
|
|
let sweep = self.sweep * 0.017453293
|
|
let t = ang / sweep + 0.5
|
|
let on_scale = step(-0.0001, t) * step(t, 1.0001)
|
|
let inside = Finish.cover(md_rbox4(p, (lo + hi) * 0.5, (hi - lo) * 0.5 - vec2(2.0, 2.0), vec4(rt - 2.0, rt - 2.0, r - 2.0, r - 2.0)), px)
|
|
// the colour band under the scale
|
|
let bandr = Finish.cover(abs(rq - (rr - 2.6)) - 1.6, px) * on_scale
|
|
let ramp = mix(mix(vec3(0.47, 0.66, 0.53), vec3(0.88, 0.68, 0.33), smoothstep(0.35, 0.7, t)), self.color_zone.rgb, step(self.zone, t))
|
|
let ba = bandr * 0.85 * inside
|
|
out = Finish.over(out, vec4(ramp * ba, ba))
|
|
// the scale: a hairline arc and a tick at every division
|
|
let arc = Finish.cover(abs(rq - rr) - px * 0.6, px) * on_scale
|
|
let n = max(floor(self.majors + 0.5), 1.0) * max(floor(self.minors + 0.5), 1.0)
|
|
let k = floor(clamp(t, 0.0, 1.0) * n + 0.5)
|
|
let ak = (k / n - 0.5) * sweep
|
|
let perp = abs(q.x * cos(ak) + q.y * sin(ak))
|
|
let mn = max(floor(self.minors + 0.5), 1.0)
|
|
let major = 1.0 - step(0.5, k - mn * floor(k / mn + 0.0001))
|
|
let len = mix(self.tick_minor, self.tick_major, major)
|
|
let radial = max(rr - len - rq, rq - rr)
|
|
let tick = Finish.cover(perp - px * mix(0.55, 0.9, major), px) * Finish.cover(radial, px) * step(0.0, 0.0 - q.y * cos(ak) + q.x * sin(ak))
|
|
let sa = max(arc, tick) * inside
|
|
out = Finish.over(out, vec4(self.color_scale.rgb * sa, sa))
|
|
// the needle: a slim spear from under the pivot to just past the scale
|
|
let na = self.needle_angle(self.value)
|
|
let nd = vec2(sin(na), 0.0 - cos(na))
|
|
let sp = an_leaf(p, pv - nd * 3.0, nd, rr + 6.0, 1.4, 0.0)
|
|
let nf = mix(self.color_needle.rgb, an_gold_hi(), smoothstep(0.3, 1.0, sp.z) * 0.3)
|
|
out = an_lay(out, sp.x, nf * inside + self.color_needle.rgb * (1.0 - inside), 0.4, px)
|
|
let pd = rq - self.pivot_size - 0.8
|
|
let bl = clamp(0.5 - 0.6 * dot(q / max(self.pivot_size, 1.0), vec2(0.45, 0.85)), 0.0, 1.0)
|
|
out = an_lay(out, pd, mix(an_bronze_dk(), an_gold_hi(), bl), 0.5, px)
|
|
return out * self.color.a * self.opacity
|
|
}
|
|
mod.widgets.NeedleMeter.draw_label.color = #xe6c47e
|
|
|
|
// ---------------------------------------------------------------- lamps
|
|
// LAMPS: jewels of coloured glass, cabochons in polished bronze settings, as
|
|
// the stained glass of the period. The emitter is the light: at full current
|
|
// its middle burns toward white and its rim is its most saturated colour; at
|
|
// lower current the middle is no longer white, the colour deeper, the glow
|
|
// smaller; out, it is dark tinted glass, its colour barely there. Its light
|
|
// is added, never painted: a tight hot halo and a short bloom in its own
|
|
// hue, gone in about two radii; on the pale parchment its hue is also laid
|
|
// round it as a tint that keeps the ground's luminance. A bar is the same
|
|
// light drawn out into a short light pipe.
|
|
let md_led_lamp_add = fn(res: vec4, light: vec3, ground: vec3) -> vec4 {
|
|
let est = res.rgb + ground * (1.0 - res.a)
|
|
let add = (vec3(1.0, 1.0, 1.0) - exp(0.0 - light)) * max(vec3(1.0, 1.0, 1.0) - est, vec3(0.0, 0.0, 0.0))
|
|
return vec4(res.rgb + add, res.a)
|
|
}
|
|
let md_led_lamp_full = fn(ink: vec3) -> vec3 {
|
|
return ink / max(max(ink.x, max(ink.y, ink.z)), 0.01)
|
|
}
|
|
let md_led_lamp_hue = fn(ink: vec3, vivid: float) -> vec3 {
|
|
let f = md_led_lamp_full(ink)
|
|
let mn = min(f.x, min(f.y, f.z))
|
|
let ch = 1.0 - mn
|
|
let pure = (f - vec3(mn, mn, mn)) / max(ch, 0.001)
|
|
return mix(f, pure, clamp(vivid, 0.0, 1.0) * 0.72 * smoothstep(0.03, 0.12, ch))
|
|
}
|
|
let md_led_lamp = fn(dst: vec4, p: vec2, c: vec2, hb: vec2, lit: float, ink: vec3, vivid: float, px: float, ground: vec3, room: float) -> vec4 {
|
|
let rt = max(min(hb.x, hb.y), 0.4)
|
|
let d = Material.sd_box(p, c, hb, rt)
|
|
let bw = clamp(0.32 * rt, 0.8, 2.4)
|
|
let ds = d - bw
|
|
let L = clamp(lit, 0.0, 1.0)
|
|
let b = md_led_lamp_full(ink)
|
|
let hue = md_led_lamp_hue(ink, vivid)
|
|
let pw = L * sqrt(L)
|
|
let white = vec3(1.0, 1.0, 1.0)
|
|
let lum = vec3(0.2126, 0.7152, 0.0722)
|
|
var res = dst
|
|
let x = max(ds, 0.0)
|
|
let reach = max(room, 1.0)
|
|
let win = 1.0 - smoothstep(0.55 * reach, reach, x)
|
|
let ex = max(hb.x - hb.y, 0.0)
|
|
let ey = max(hb.y - hb.x, 0.0)
|
|
let qx = p.x - c.x
|
|
let qy = p.y - c.y
|
|
let q = vec2(qx - clamp(qx, 0.0 - ex, ex), qy - clamp(qy, 0.0 - ey, ey)) / rt
|
|
let t = clamp(length(q), 0.0, 1.0)
|
|
let nrm = q / max(length(q), 0.001)
|
|
// the setting's shadow on the parchment
|
|
let shd = Finish.drop(p, c, hb + vec2(bw, bw), rt + bw, vec2(0.15, 0.12 * rt + 0.3), 0.10 * rt + 0.5) * 0.32 * (1.0 - 0.6 * pw)
|
|
res = Finish.over(res, vec4(an_shade() * shd, shd))
|
|
if L > 0.001 {
|
|
// the tint on the pale ground: its hue laid over, never darker
|
|
let h = clamp(0.42 * pw * pow(2.0, 0.0 - x / max(0.4 * reach, 0.5)) * win, 0.0, 0.45)
|
|
let est = res.rgb + ground * (1.0 - res.a)
|
|
let w = clamp(dot(hue, lum) / max(dot(est, lum), 0.001), 0.0, 1.0)
|
|
res = Finish.over(res, vec4(hue * h * w, h * w))
|
|
}
|
|
// the bronze setting: a polished ring rounded over, lit from the upper
|
|
// left, a dark seat line where it holds the stone
|
|
let a_s = Finish.cover(ds, px)
|
|
let u = clamp(d / max(bw, 0.01), 0.0, 1.0)
|
|
let facing = dot(nrm * (u - 0.5) * 2.0, vec2(-0.45, -0.89))
|
|
var rc = an_bronze_c() * (0.92 + 0.45 * facing)
|
|
rc = mix(rc, an_gold_hi(), smoothstep(0.5, 0.95, facing) * 0.75)
|
|
rc = mix(rc, an_bronze_dk(), Finish.band(ds, 0.0, max(px, 0.45), px) * 0.7)
|
|
rc = mix(rc, an_bronze_dk() * 0.6, Finish.ring_out(d, 0.0, max(px, 0.45), px) * 0.8)
|
|
res = Finish.over(res, vec4(min(rc, white) * a_s, a_s))
|
|
if L > 0.001 {
|
|
let xl = max(d, 0.0)
|
|
let halo = exp(0.0 - xl / max(0.30 * rt, 0.4)) * 1.5 + exp(0.0 - xl / max(0.65 * rt, 0.7)) * 0.32
|
|
let hwin = 1.0 - smoothstep(1.1 * rt, 2.0 * rt + 1.0, xl)
|
|
res = md_led_lamp_add(res, mix(hue, white, 0.15 * pw) * halo * pw * hwin * win, ground)
|
|
}
|
|
// THE STONE: a glossy cabochon of coloured glass, deeper at the top,
|
|
// light pooling low inside; lit, its middle burns toward white at full
|
|
// current and its rim is its most saturated colour.
|
|
let top = smoothstep(-1.0, 0.6, q.y)
|
|
let pool = exp(0.0 - (q.y - 0.55) * (q.y - 0.55) / 0.09 - q.x * q.x / 0.30)
|
|
var on = mix(hue * mix(0.55, 0.8, L), mix(b, hue, 0.5), top)
|
|
on = mix(on, min(mix(b, hue, 0.4) + vec3(0.35, 0.35, 0.35), white), pool * 0.5)
|
|
on = mix(on, vec3(1.0, 0.99, 0.975), exp(0.0 - t * t / 0.20) * smoothstep(0.5, 1.0, L) * 0.85)
|
|
on = mix(on, hue * (0.82 + 0.18 * L), smoothstep(0.62, 1.0, t))
|
|
on = on * (0.42 + 0.58 * L)
|
|
// out: dark tinted glass, its colour barely there, a catch light along
|
|
// its lower rim
|
|
let offc = mix(vec3(0.075, 0.08, 0.07), b * 0.42, 0.24)
|
|
var off = mix(offc * 0.62, offc * 1.15, top)
|
|
off = mix(off, min(offc + vec3(0.18, 0.18, 0.18), white), pool * 0.35)
|
|
off = off * mix(1.0, 0.75, smoothstep(0.75, 1.0, t))
|
|
let catchl = smoothstep(0.62, 0.9, t) * (1.0 - smoothstep(0.9, 1.0, t)) * smoothstep(0.2, 0.9, nrm.y)
|
|
off = off + vec3(0.30, 0.28, 0.24) * catchl
|
|
var col = mix(off, min(on, white), smoothstep(0.0, 0.35, L))
|
|
let e = length(vec2(q.x / 0.62, (q.y + 0.46) / 0.30))
|
|
let spec = (1.0 - smoothstep(0.55, 1.0, e)) * mix(1.0, 0.3, clamp((q.y + 0.76) / 0.6, 0.0, 1.0))
|
|
col = mix(col, white, spec * mix(0.8, 0.55, L) * smoothstep(0.9, 2.2, rt))
|
|
col = min(col, white)
|
|
let a_l = Finish.cover(d, px)
|
|
return Finish.over(res, vec4(col * a_l, a_l))
|
|
}
|
|
|
|
// The Lamp widget and the bar lamp. A round jewel takes the middle of its
|
|
// cell; its halo's room is held in the cell (the library reserves a lens
|
|
// thickness either side once a halo is asked for), so the light is never cut
|
|
// at its edge and fades within half the gap. A bar is a short light pipe set
|
|
// at the left of its cell, six points thick and twice that long, its glow
|
|
// held to two and a half points round its setting -- the whole lamp takes
|
|
// the first twenty points of its cell and leaves the rest free.
|
|
mod.widgets.Lamp.halo = 0.3
|
|
mod.widgets.Lamp.size = 14.0
|
|
mod.widgets.Lamp.halo_reach = 0.3
|
|
mod.widgets.LampBar.size = 14.0
|
|
mod.widgets.LampBar.halo_reach = 0.3
|
|
mod.widgets.Lamp.draw_bg.color_accent = uniform(#xffa83a)
|
|
mod.widgets.Lamp.draw_bg.color_success = uniform(#x34c79c)
|
|
mod.widgets.Lamp.draw_bg.color_warning = uniform(#xf2c443)
|
|
mod.widgets.Lamp.draw_bg.color_error = uniform(#xe5483a)
|
|
mod.widgets.Lamp.draw_bg.color_plain = uniform(#xfff3d8)
|
|
mod.widgets.Lamp.draw_bg.vertex = fn() {
|
|
let m = 4.0
|
|
self.vertex_pos = self.clip_and_transform_vertex(self.rect_pos - vec2(m, m), self.rect_size + vec2(2.0 * m, 2.0 * m))
|
|
}
|
|
mod.widgets.Lamp.draw_bg.pixel = fn() {
|
|
let m = 4.0
|
|
let p = self.pos * (self.rect_size + vec2(2.0 * m, 2.0 * m)) - vec2(m, m)
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let reach = clamp(self.reach, 0.0, 1.0)
|
|
let t = min(self.rect_size.y / (1.0 + 2.0 * reach), 14.0)
|
|
let room = (self.rect_size.y - t) * 0.5
|
|
let tb = min(t, 6.0)
|
|
let lb = 14.0
|
|
let c = mix(self.rect_size * 0.5, vec2(1.6 + lb * 0.5, self.rect_size.y * 0.5), self.bar)
|
|
let hb = mix(vec2(t * 0.5, t * 0.5), vec2(lb * 0.5, tb * 0.5), self.bar)
|
|
let glow = mix(max(room - 2.5, 2.0), 2.2, self.bar)
|
|
let res = md_led_lamp(vec4(0.0, 0.0, 0.0, 0.0), p, c, hb, self.lit, self.intent_color().rgb, 1.0 - step(3.5, self.intent), px, an_parch_c(), glow)
|
|
return res * self.opacity
|
|
}
|
|
true
|