diff options
| author | Danilo M. <danix@danix.xyz> | 2026-09-17 09:38:12 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-09-17 09:38:12 +0200 |
| commit | 4985439eb2feb15757c3c8056cbeb5ae2abe1442 (patch) | |
| tree | 77bc603b39eef6feafc045bfa5237d49dffb3fd3 | |
| parent | 5a4c0c0de6cb5ed544773a9aa056ac2b3e5b486b (diff) | |
| download | conky-theme-udt-4985439eb2feb15757c3c8056cbeb5ae2abe1442.tar.gz conky-theme-udt-4985439eb2feb15757c3c8056cbeb5ae2abe1442.zip | |
feat: make the clock fill whatever cell it is given
The numerals scaled off the cell but the date block sat at a fixed drop
below them, so a tall cell left a dead band under the date and a short
one would have collided. Now the date pins to the bottom edge, the
numerals take everything above it, and both type sizes derive from the
width, so the slack of a tall cell falls in the middle of the card where
it belongs.
Type scales off width for the same reason the weather card does: height
is what changes when a row is added to the grid, and a widget that
shrinks its text whenever its cell gets shorter reads as broken next to
its neighbours.
Checked at 1x3, 1x6, 2x2, 2x4 and 3x3 on an 8x6 grid before restarting
conky. The 1x6 case stays width-bound and leaves room below the
numerals, which is correct for a cell far taller than it is wide.
The README now states the convention, since it applies to every widget
added later: derive offsets from the rect, scale off width, decide where
the slack goes, and drop an element that would otherwise overlap.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
| -rw-r--r-- | README.md | 27 | ||||
| -rw-r--r-- | widgets/clock.lua | 41 |
2 files changed, 58 insertions, 10 deletions
@@ -100,6 +100,33 @@ bug here: ink width ignores leading and trailing spaces, so `' / '` measures 6px of ink against a 14px advance, and stepping a cursor by the ink width renders the date as `16 /SEP /2026`. +### Widgets are fluid + +A widget is handed a rectangle and must fill it, whatever shape the grid makes +it. That is what lets you retune `COLS`/`ROWS` or move a card without touching +widget code. Three rules, all learned by getting them wrong: + +**Derive every size and offset from the rect.** No fixed pixel drops between +elements. A fixed `+34` under a numeral that scales leaves a dead band in a tall +cell and overlaps in a short one. + +**Scale type off the WIDTH, not the height.** Height is what changes when you +add a row to the grid, and a card that shrinks its text every time its cell gets +shorter reads as broken beside its neighbours. Width is also usually what +constrains the text, since rows run edge to edge. Clamp it: `math.max(lo, +math.min(hi, inner.w * k))`. + +**Decide where the slack goes, and let one element absorb it.** The clock pins +its date block to the bottom and gives the numerals everything above. The +weather card stacks from the top and lets the arc take the remainder. Either is +fine; what fails is leaving the slack wherever it lands. + +An element that cannot shrink below some size should drop out rather than +overlap. The weather arc does this: below 70px it is not drawn at all, because a +curve crossing the stat rows is worse than no curve. Check a widget at several +spans before believing it is fluid, which the offscreen renderer above makes +cheap. + ## Development Run it in the foreground to see Lua output, which is the only debugging channel: diff --git a/widgets/clock.lua b/widgets/clock.lua index 978715e..c3e9712 100644 --- a/widgets/clock.lua +++ b/widgets/clock.lua @@ -1,18 +1,37 @@ -- Clock: hour stacked over minute, weekday, slashed date. -- -- Shape follows idea2.png; every colour comes from the palette. +-- +-- Fluid: every size and offset derives from the rect it is handed, and the +-- date block pins to the bottom so the slack in a tall cell falls between the +-- numerals and the date rather than piling up under everything. A widget is +-- given a rectangle and should fill it, whatever shape the grid makes it. local card = require 'lib.card' local M = {} +local function clamp(v, lo, hi) return math.max(lo, math.min(hi, v)) end + function M.draw(cr, rect, colors) local inner = card.card(cr, rect, colors) + local x = inner.x + local bottom = inner.y + inner.h - -- Numeral size is derived from the cell, not fixed, so the same widget fills - -- a 1x2 cell on either monitor instead of needing a per-screen constant. - -- Two stacked numerals plus the date block: allow 40% of the height each. - local size = math.min(inner.h * 0.40, inner.w * 0.95) + -- The date block is sized first, because the numerals get whatever is left. + -- Both scale off the WIDTH: height changes with the grid, and a widget that + -- shrinks its type every time its cell gets shorter reads as broken next to + -- its neighbours. Width is also what actually constrains the date line, + -- which runs edge to edge. + local day_size = clamp(inner.w * 0.055, 12, 26) + local date_size = clamp(inner.w * 0.050, 11, 24) + local date_band = day_size * 1.6 + date_size * 1.8 + + -- Two stacked numerals fill the space above the date band. Whichever of + -- height and width binds first wins, so a wide short cell is limited by its + -- height and a narrow tall one by its width, and neither overflows. + local avail = (bottom - date_band) - inner.y + local size = math.min(avail * 0.46, inner.w * 0.95) card.font(cr, card.FONT_HEAVY, size, false) card.rgba(cr, colors.body) @@ -20,7 +39,6 @@ function M.draw(cr, rect, colors) -- Baselines. Cairo's y is the baseline, so the first sits one cap-height -- down; 0.78 of the font size approximates cap height for Noto Sans and -- avoids measuring every frame. - local x = inner.x local y1 = inner.y + size * 0.78 -- Tight leading, as in the mockup: the numerals nearly touch. local y2 = y1 + size * 0.92 @@ -28,16 +46,19 @@ function M.draw(cr, rect, colors) card.text(cr, x, y1, os.date('%H')) card.text(cr, x, y2, os.date('%M')) - -- Weekday, small caps. - card.font(cr, card.FONT_UI, 15, true) + -- Weekday and date sit against the bottom edge, not at a fixed drop from the + -- numerals. That is what puts the slack of a tall cell in the middle of the + -- card instead of leaving a dead band under the date. + local dy = bottom - date_size * 0.3 + local wy = dy - date_size * 1.8 + + card.font(cr, card.FONT_UI, day_size, true) card.rgba(cr, colors.body) - local wy = y2 + 34 card.text(cr, x, wy, os.date('%A'):upper()) -- Date as "16 / SEP / 2026". The slashes take the dimmer label colour so the -- numerals read first, which is what gives the mockup's date line its rhythm. - card.font(cr, card.FONT_UI, 14, true) - local dy = wy + 24 + card.font(cr, card.FONT_UI, date_size, true) local parts = { { os.date('%d'), colors.value }, { ' / ', colors.label }, |
