1package vulkan
2
3import (
4 "image"
5 "math"
6
7 "github.com/bnema/neferwl/internal/adapters/hintlabel"
8)
9
10// hintLabels draws the keyboard hint labels (ports.Scene.HintLabels) over
11// everything, after the capture indicators. Each label is rasterized on the CPU
12// (hintlabel) at the scene's scale and drawn from the SHM copy path: the GPU
13// buffer is cached under a key naming the label, so a label that stays the
14// same uploads once. Captures are rendered from scenes without labels.
15func (w *sceneWalk) hintLabels() {
16 if len(w.s.HintLabels) == 0 {
17 return
18 }
19 r := w.r
20 hs := w.s.HintStyle
21 bg, fg := hintlabel.Colors(w.s.Border.Active, hs.Background, hs.Foreground)
22 style := hintlabel.Style{FontPx: hintlabel.FontPixels(hs.Width, hs.Height, hs.PhysicalW, hs.PhysicalH, w.scale, hs.Size), Background: bg, Foreground: fg}
23 for _, l := range w.s.HintLabels {
24 pix, lw, lh := r.labels.Label(l.Text, l.Typed, w.scale, style)
25 if lw <= 0 || lh <= 0 {
26 continue
27 }
28 // Anchored outside the target's top-left corner, overlapping it by a
29 // quarter of the label height, then kept inside the output.
30 inset := int(math.Round(0.25 * float64(lh)))
31 x := min(max(w.phys(l.Rect.X)-lw+inset, w.bounds.Min.X), max(w.bounds.Max.X-lw, w.bounds.Min.X))
32 y := min(max(w.phys(l.Rect.Y)-lh+inset, w.bounds.Min.Y), max(w.bounds.Max.Y-lh, w.bounds.Min.Y))
33 rect := image.Rect(x, y, x+lw, y+lh)
34 if rect.Intersect(w.bounds).Empty() {
35 continue
36 }
37 key := shmKey{label: l.Text, typed: l.Typed, scale: w.scale, style: style}
38 st := shmState{w: lw, h: lh, seq: 1}
39 c := r.shmCached(key, st)
40 if c == nil {
41 var err error
42 if c, err = r.shmCopyFor(key, st, pix, 0, lw*4, nil); err != nil {
43 continue
44 }
45 }
46 dr := r.contentDraw(rect, rect, lw, lh, [4]float32{}, 0, modeBuffer, true)
47 dr.pc.color[3] = 1
48 dr.shm = c
49 dr.pc.buf = [4]uint32{0, uint32(lw), uint32(lh), 0}
50 w.draws = append(w.draws, dr)
51 }
52}