From 31db51d7fb782c8e79bf1df067dadc1a8be63255 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Fri, 21 Aug 2026 10:09:04 +0200 Subject: config: Terminus by default, and stop hiding knobs in the source config.h now carries everything a reader would reasonably want to change: both fonts, the liturgical palette and the fallback for an unlisted colour, the selection rings, geometry, weekday headings, the detail-pane labels, the window title, and which rank earns a badge and what it says. Several of those were literals buried in colitur-x.c. Default font is Terminus:pixelsize=20:antialias=false, matching st. Terminus is a bitmap face, so it exists only at fixed pixelsizes -- the list is in the comment, because asking for one it lacks silently gets a substitute rather than an error. Layout metrics now come from the font instead of magic numbers: line height and the badge from XftFont ascent/descent in colitur-x, column widths in characters rather than pixels in colitur-mu. Before this, changing the font size left a 13px line height and a 110px date column that quietly truncated their contents. --- colitur-mu | Bin 47040 -> 47040 bytes colitur-mu.c | 17 ++++++++----- colitur-x | Bin 27024 -> 27032 bytes colitur-x.c | 33 +++++++++++++------------- config.h | 76 +++++++++++++++++++++++++++++++++++++++++++---------------- 5 files changed, 84 insertions(+), 42 deletions(-) diff --git a/colitur-mu b/colitur-mu index eeaf02c..577f98c 100755 Binary files a/colitur-mu and b/colitur-mu differ diff --git a/colitur-mu.c b/colitur-mu.c index d76152d..1907274 100644 --- a/colitur-mu.c +++ b/colitur-mu.c @@ -95,12 +95,17 @@ static void reload(void) result looks like a layout bug rather than a height bug. */ static void frame(mu_Context *ctx, int W, int H) { - enum { RH = 24 }; + /* Column widths in CHARACTERS, not pixels. Hardcoded pixel widths are + silently wrong the moment config.h names a different font size: at + Terminus 20 a 110px "date" column truncates an ISO date. Row height + likewise follows the font. */ + int ch = mux_text_width(NULL, "0", 1); + int RH = mux_text_height(NULL) + 10; if (!mu_begin_window_ex(ctx, "colitur", mu_rect(0, 0, W, H), MU_OPT_NOTITLE | MU_OPT_NORESIZE | MU_OPT_NOCLOSE)) return; - int wy[] = { 120, 40, 40, 90, -1 }; + int wy[] = { 11*ch, 3*ch, 3*ch, 7*ch, -1 }; mu_layout_row(ctx, 5, wy, RH); mu_label(ctx, "Year"); if (mu_button(ctx, "-")) { year--; reload(); } @@ -109,7 +114,7 @@ static void frame(mu_Context *ctx, int W, int H) mu_label(ctx, y); mu_label(ctx, ""); - int w4[] = { 120, 90, 90, -1 }; + int w4[] = { 11*ch, 9*ch, 9*ch, -1 }; struct { const char *cap; const char **opts; int *idx; } sets[] = { { "Language", langs, &lang_i }, { "Book names", books, &book_i }, @@ -133,13 +138,13 @@ static void frame(mu_Context *ctx, int W, int H) mu_layout_row(ctx, 1, w1, RH); mu_label(ctx, status); - int listh = H - 7 * RH - 90; + int listh = H - 7 * RH - 4 * RH; if (listh < 100) listh = 100; mu_layout_row(ctx, 1, w1, listh); mu_begin_panel(ctx, "days"); - int wrow[] = { 110, 100, 330, -1 }; + int wrow[] = { 11*ch, 11*ch, 34*ch, -1 }; for (int i = 0; i < nrows; i++) { - mu_layout_row(ctx, 4, wrow, 22); + mu_layout_row(ctx, 4, wrow, RH - 2); if (mu_button(ctx, rows[i].f[0])) sel = i; mu_label(ctx, rows[i].f[9]); mu_label(ctx, rows[i].f[6]); diff --git a/colitur-x b/colitur-x index a49ed72..0865757 100755 Binary files a/colitur-x and b/colitur-x differ diff --git a/colitur-x.c b/colitur-x.c index 03e2793..5307c24 100644 --- a/colitur-x.c +++ b/colitur-x.c @@ -113,7 +113,7 @@ static void colours_for(const char *name, XftColor *bg, XftColor *fg) alloc(palette[i].fg, fg); return; } - alloc("#808080", bg); alloc("#ffffff", fg); + alloc(col_unknown_bg, bg); alloc(col_unknown_fg, fg); } static void text(XftColor *c, XftFont *f, int x, int y, const char *s, int maxw) @@ -209,9 +209,8 @@ static void redraw(void) rows[cur].f[0], mon, rows[cur].f[3]); text(&head, fnt_big, PAD, 26, title, wa.width - 2*PAD); - static const char *dows[] = {"Dom","Fer II","Fer III","Fer IV","Fer V","Fer VI","Sab"}; for (int c = 0; c < 7; c++) - text(&head, fnt, PAD + c*CELL_W + 4, HEAD_H - 6, dows[c], CELL_W - 8); + text(&head, fnt, PAD + c*CELL_W + 4, HEAD_H - 6, dow_headings[c], CELL_W - 8); /* first row index of this month, and where it starts in the week */ int first = 0; @@ -233,30 +232,32 @@ static void redraw(void) CELL_W - 2 - 2*SEL_RING, CELL_H - 2 - 2*SEL_RING, SEL_RING); } + int lh = fnt->ascent + fnt->descent; /* body line height */ + int bigh = fnt_big->ascent + fnt_big->descent; char d[8]; snprintf(d, sizeof d, "%d", dom_of(i)); - text(&fg, fnt_big, x + 6, y + 20, d, 40); - if (!strcmp(rows[i].f[8], "class-1")) { + text(&fg, fnt_big, x + 6, y + fnt_big->ascent + 4, d, CELL_W / 3); + if (!strcmp(rows[i].f[8], badge_rank)) { /* badge: filled with the cell's FOREGROUND, glyph in its BACKGROUND, so it inverts against any liturgical colour */ - int gw = 0, bw2, bx, by = y + 5, bh2 = 17; + int gw = 0, bw2, bx, by = y + 4, bh2 = lh + 2; XGlyphInfo gi; - XftTextExtentsUtf8(dpy, fnt, (FcChar8 *)rank1_glyph, - strlen(rank1_glyph), &gi); + XftTextExtentsUtf8(dpy, fnt, (FcChar8 *)badge_glyph, + strlen(badge_glyph), &gi); gw = gi.xOff; bw2 = gw + 10; bx = x + CELL_W - 4 - bw2; XftDrawRect(xd, &fg, bx, by, bw2, bh2); - XftDrawStringUtf8(xd, &bg, fnt, bx + 5, by + 13, - (FcChar8 *)rank1_glyph, strlen(rank1_glyph)); + XftDrawStringUtf8(xd, &bg, fnt, bx + 5, by + 1 + fnt->ascent, + (FcChar8 *)badge_glyph, strlen(badge_glyph)); } /* Feast name over up to three lines, breaking on spaces that fit the cell. Measured with XftTextExtents rather than guessed at a character count, so it is right for any font in config.h. */ const char *nm = rows[i].f[6]; - int avail = CELL_W - 12, ty = y + 36; + int avail = CELL_W - 12, ty = y + bigh + 8 + fnt->ascent; const char *p = nm; - for (int ln = 0; ln < 3 && *p; ln++) { + for (int ln = 0; ln < NAME_LINES && *p; ln++) { size_t take = strlen(p), best = 0; XGlyphInfo gi; for (size_t k = 1; k <= take; k++) { @@ -272,7 +273,7 @@ static void redraw(void) } } XftDrawStringUtf8(xd, &fg, fnt, x + 6, ty, (FcChar8 *)p, best); - ty += 13; + ty += lh; p += best; while (*p == ' ') p++; } @@ -285,9 +286,9 @@ static void redraw(void) text(&detail, fnt_big, PAD, dy + 22, line, wa.width - 2*PAD); snprintf(line, sizeof line, "%s ยท %s", rows[cur].f[9], rows[cur].f[11]); text(&head, fnt, PAD, dy + 42, line, wa.width - 2*PAD); - snprintf(line, sizeof line, "Epistola %s", rows[cur].f[13]); + snprintf(line, sizeof line, "%-10s %s", label_epistle, rows[cur].f[13]); text(&detail, fnt, PAD, dy + 62, line, wa.width - 2*PAD); - snprintf(line, sizeof line, "Evangelium %s", rows[cur].f[14]); + snprintf(line, sizeof line, "%-10s %s", label_gospel, rows[cur].f[14]); text(&detail, fnt, PAD, dy + 80, line, wa.width - 2*PAD); XCopyArea(dpy, buf, win, gc, 0, 0, wa.width, wa.height, 0, 0); @@ -311,7 +312,7 @@ int main(void) int w = PAD*2 + 7*CELL_W, h = HEAD_H + 6*CELL_H + DETAIL_H; win = XCreateSimpleWindow(dpy, RootWindow(dpy, scr), 0, 0, w, h, 0, BlackPixel(dpy, scr), BlackPixel(dpy, scr)); - XStoreName(dpy, win, "colitur"); + XStoreName(dpy, win, window_title); { /* Ask the window manager for exactly the grid we drew. Without this a tiling or maximising WM picks its own size and the grid floats in a field of background. */ diff --git a/config.h b/config.h index 6fe5857..36fe3cd 100644 --- a/config.h +++ b/config.h @@ -1,10 +1,20 @@ -/* colitur-x -- compile-time configuration, suckless style. - * Edit, `make`, done. There is no runtime config file by design. */ +/* colitur-x / colitur-mu -- compile-time configuration, suckless style. + * Edit, `make`, `make install`. There is no runtime config file: colitur + * itself owns the CALENDAR's configuration (language, sigla, overlays); + * this file owns only how it is painted. + */ -static const char *font = "monospace:size=10"; -static const char *font_big = "monospace:size=14:bold"; +/* ------------------------------------------------------------------ fonts */ +/* Any fontconfig name. Terminus is a bitmap font, so it exists only at + fixed pixelsizes (12 14 16 18 20 22 24 28 32) and wants antialias=false; + asking for a size it does not have silently gets you a substitute. */ +static const char *font = "Terminus:pixelsize=20:antialias=false"; +static const char *font_big = "Terminus:pixelsize=20:style=Bold:antialias=false"; -/* Liturgical colours, as the engine names them -> what to paint. */ +/* ---------------------------------------------------------------- colours */ +/* Liturgical colours, keyed by the name colitur emits in the `colour` + column. bg is the cell, fg is its text; every other marker is derived + from these two so it cannot become invisible against an odd combination. */ static const struct { const char *name, *bg, *fg; } palette[] = { { "white", "#f7f5ef", "#1a1a1a" }, { "red", "#b03030", "#ffffff" }, @@ -13,23 +23,49 @@ static const struct { const char *name, *bg, *fg; } palette[] = { { "black", "#202020", "#e0e0e0" }, { "rose", "#d9a0b0", "#1a1a1a" }, }; +static const char *col_unknown_bg = "#808080"; /* a colour not listed above */ +static const char *col_unknown_fg = "#ffffff"; -static const char *col_bg = "#141414"; /* window background */ -static const char *col_grid = "#3a3a3a"; /* cell borders */ -static const char *col_head = "#8a8a8a"; /* weekday headings */ -static const char *col_detail = "#e8e8e8"; /* detail pane text */ -/* The selected day is ringed TWICE: a dark ring outside a bright one, so - the marker survives on a white cell and on a red one alike. A single - bright ring vanishes against white; a single dark one vanishes against - black. */ +static const char *col_bg = "#141414"; /* window background */ +static const char *col_grid = "#3a3a3a"; /* rule above the detail pane */ +static const char *col_head = "#8a8a8a"; /* title and weekday row */ +static const char *col_detail = "#e8e8e8"; /* detail pane text */ + +/* The selected day is ringed TWICE, dark outside and bright inside, so it + survives on a white cell and on a red one alike. A single bright ring + vanishes against white; a single dark one vanishes against black. */ static const char *col_sel_dark = "#1a1a1a"; static const char *col_sel_light = "#ffd24a"; -enum { SEL_RING = 3 }; /* px per ring */ +enum { SEL_RING = 3 }; /* px per ring */ + +/* --------------------------------------------------------------- geometry */ +/* CELL_W/CELL_H must suit the font: a cell holds the day number plus + NAME_LINES lines of `font`. Line height itself is taken from the font at + runtime, so only these two need revisiting when you change size. + Rough guide: CELL_W >= 10 * (widest name chars you want), CELL_H >= + big-font height + NAME_LINES * font height + 12. */ +enum { + CELL_W = 196, + CELL_H = 116, + PAD = 10, /* margin around the grid */ + HEAD_H = 62, /* title + weekday headings */ + DETAIL_H = 116, /* the pane under the grid */ + NAME_LINES = 3, /* how many lines a feast name gets */ +}; -/* A I-class day is marked with a BADGE, not coloured text: the badge is - filled with the cell's own foreground and the glyph drawn in its - background, so it inverts against whatever the day's colour is. Gold on - white -- the first attempt -- was very nearly invisible. */ -static const char *rank1_glyph = "I"; +/* ------------------------------------------------------------------ labels */ +/* Weekday headings, Sunday first. These are the VIEWER's own text, not + colitur's: the day names inside each cell come from the CSV and follow + whatever --lang produced it. Set these to match. */ +static const char *dow_headings[7] = { + "Dom", "Fer II", "Fer III", "Fer IV", "Fer V", "Fer VI", "Sab" +}; +static const char *label_epistle = "Epistola"; +static const char *label_gospel = "Evangelium"; +static const char *window_title = "colitur"; -enum { CELL_W = 122, CELL_H = 74, PAD = 10, HEAD_H = 46, DETAIL_H = 92 }; +/* Which rank gets a badge, and what the badge says. The value is compared + against colitur's own `rank` column (class-1 | class-2 | class-3 | + class-4), so "class-2" here would mark second-class feasts instead. */ +static const char *badge_rank = "class-1"; +static const char *badge_glyph = "I"; -- cgit v1.3