(ctx, w, h)
| 40 | } |
| 41 | |
| 42 | function paint(ctx, w, h) { |
| 43 | // Cream paper background + vignette. |
| 44 | ctx.fillStyle = theme.widget_base; |
| 45 | ctx.fillRect(0, 0, w, h); |
| 46 | |
| 47 | if (datasets.length === 0) return; |
| 48 | |
| 49 | // Header. |
| 50 | ctx.fillStyle = theme.widget_text; |
| 51 | ctx.font = "bold 11px sans-serif"; |
| 52 | ctx.textAlign = "start"; |
| 53 | ctx.fillText("7-SEGMENT READOUT", 14, 18); |
| 54 | ctx.fillStyle = theme.placeholder_text; |
| 55 | ctx.font = "10px sans-serif"; |
| 56 | ctx.textAlign = "end"; |
| 57 | ctx.fillText(datasets.length + (datasets.length === 1 ? " channel" : " channels"), |
| 58 | w - 14, 18); |
| 59 | ctx.fillStyle = theme.widget_border; |
| 60 | ctx.fillRect(14, 22, w - 28, 1); |
| 61 | |
| 62 | // Per-row stacked layout. |
| 63 | const padX = 14; |
| 64 | const padTop = 32; |
| 65 | const padBot = 14; |
| 66 | const gap = 8; |
| 67 | const rowH = (h - padTop - padBot - gap * (datasets.length - 1)) / datasets.length; |
| 68 | |
| 69 | for (let i = 0; i < datasets.length; ++i) { |
| 70 | const ds = datasets[i]; |
| 71 | const y0 = padTop + i * (rowH + gap); |
| 72 | const v = Number.isFinite(ds.value) ? ds.value : 0; |
| 73 | const txt = v.toFixed(1).padStart(6, " "); |
| 74 | |
| 75 | // "Screen" panel (mint background simulating a backlit LCD). |
| 76 | ctx.fillStyle = theme.widget_border; |
| 77 | ctx.fillRect(padX + 1, y0 + 2, w - padX * 2, rowH); |
| 78 | ctx.fillStyle = theme.alternate_base; |
| 79 | ctx.fillRect(padX, y0, w - padX * 2, rowH); |
| 80 | ctx.strokeStyle = theme.widget_border; |
| 81 | ctx.lineWidth = 1; |
| 82 | ctx.strokeRect(padX + 0.5, y0 + 0.5, w - padX * 2 - 1, rowH - 1); |
| 83 | |
| 84 | // Title strip. |
| 85 | ctx.fillStyle = theme.widget_text; |
| 86 | ctx.font = "bold 9px sans-serif"; |
| 87 | ctx.textAlign = "start"; |
| 88 | ctx.textBaseline = "alphabetic"; |
| 89 | ctx.fillText((ds.title || ("CH " + (i + 1))).toUpperCase(), |
| 90 | padX + 8, y0 + 12); |
| 91 | if (ds.units) { |
| 92 | ctx.fillStyle = theme.placeholder_text; |
| 93 | ctx.font = "9px sans-serif"; |
| 94 | ctx.textAlign = "end"; |
| 95 | ctx.fillText(ds.units, w - padX - 8, y0 + 12); |
| 96 | } |
| 97 | |
| 98 | // Digits. |
| 99 | const dh = Math.max(12, rowH - 22); |
nothing calls this directly
no test coverage detected