diff options
Diffstat (limited to 'colitur-mu.c')
| -rw-r--r-- | colitur-mu.c | 232 |
1 files changed, 0 insertions, 232 deletions
diff --git a/colitur-mu.c b/colitur-mu.c deleted file mode 100644 index 1907274..0000000 --- a/colitur-mu.c +++ /dev/null @@ -1,232 +0,0 @@ -/* colitur-mu -- an editable microui front-end for colitur. - * - * Unlike colitur-x, which only renders, this one lets you CHANGE the - * settings colitur was invoked with -- language, book-name form, numbering - * tradition, year -- and re-runs it. It never reimplements any calendar - * logic: every value on screen came out of `colitur emit --format csv`. - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ -#define _POSIX_C_SOURCE 200809L -#include <X11/Xlib.h> -#include <X11/keysym.h> -#include <X11/Xutil.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> - -#include "vendor/microui.h" -#include "mu_x11.h" -#include "config.h" - -#define MAXDAYS 400 -#define F 16 - -typedef struct { char *raw; char *f[F]; } Row; - -static Row rows[MAXDAYS]; -static int nrows, sel; -static char status[256] = "ready"; - -/* --- settings the UI edits ---------------------------------------------- */ -static int year = 2027; -static const char *langs[] = { "la", "en" }; -static const char *books[] = { "abbr", "full" }; -static const char *traditions[] = { "vulgate", "modern" }; -static int lang_i, book_i, trad_i; - -static int split(char *line, char **out) -{ - int n = 0; char *p = line; - while (n < F) { - if (*p == '"') { - out[n++] = ++p; - while (*p && *p != '"') p++; - if (*p) *p++ = 0; - if (*p == ',') p++; - } else { - out[n++] = p; - while (*p && *p != ',') p++; - if (*p) *p++ = 0; else break; - } - } - return n; -} - -/* Shell out to colitur with the current settings. This is the whole point: - the front-end owns no calendar logic, only the invocation. */ -static void reload(void) -{ - for (int i = 0; i < nrows; i++) free(rows[i].raw); - nrows = 0; sel = 0; - - char cmd[512]; - snprintf(cmd, sizeof cmd, - "colitur emit --format csv --from %d --to %d " - "--lang %s --sigla-book %s --sigla-tradition %s 2>&1", - year, year, langs[lang_i], books[book_i], traditions[trad_i]); - - FILE *p = popen(cmd, "r"); - if (!p) { snprintf(status, sizeof status, "cannot run colitur"); return; } - - char buf[4096]; - if (!fgets(buf, sizeof buf, p)) { pclose(p); snprintf(status, sizeof status, "no output"); return; } - if (strncmp(buf, "date,", 5)) { /* colitur printed an error */ - buf[strcspn(buf, "\n")] = 0; - snprintf(status, sizeof status, "%.200s", buf); - pclose(p); return; - } - while (nrows < MAXDAYS && fgets(buf, sizeof buf, p)) { - buf[strcspn(buf, "\n")] = 0; - char *d = strdup(buf); - if (!d) break; - rows[nrows].raw = d; - if (split(d, rows[nrows].f) >= 12) nrows++; else free(d); - } - pclose(p); - snprintf(status, sizeof status, "%d days ยท %s", nrows, cmd + 8); -} - -/* --- one frame ---------------------------------------------------------- */ -/* One frame. NOTE the explicit row heights: mu_layout_row's height - argument is stored verbatim as the row size, so passing 0 lays every - control out zero pixels tall -- they are "drawn", invisibly, and the - result looks like a layout bug rather than a height bug. */ -static void frame(mu_Context *ctx, int W, int H) -{ - /* 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[] = { 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(); } - if (mu_button(ctx, "+")) { year++; reload(); } - char y[16]; snprintf(y, sizeof y, "%d", year); - mu_label(ctx, y); - mu_label(ctx, ""); - - 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 }, - { "Numbering", traditions, &trad_i }, - }; - for (size_t r = 0; r < sizeof sets / sizeof *sets; r++) { - mu_layout_row(ctx, 4, w4, RH); - mu_label(ctx, sets[r].cap); - for (int i = 0; i < 2; i++) { - char lbl[48]; - snprintf(lbl, sizeof lbl, "%s%s", - *sets[r].idx == i ? "\xe2\x97\x8f " : " ", sets[r].opts[i]); - if (mu_button_ex(ctx, lbl, 0, MU_OPT_ALIGNCENTER)) { - *sets[r].idx = i; reload(); - } - } - mu_label(ctx, ""); - } - - int w1[] = { -1 }; - mu_layout_row(ctx, 1, w1, RH); - mu_label(ctx, status); - - 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[] = { 11*ch, 11*ch, 34*ch, -1 }; - for (int i = 0; i < nrows; i++) { - 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]); - char cit[160]; - snprintf(cit, sizeof cit, "%s %s", rows[i].f[13], rows[i].f[14]); - mu_label(ctx, cit); - } - mu_end_panel(ctx); - - if (nrows) { - char d[600]; - mu_layout_row(ctx, 1, w1, RH); - snprintf(d, sizeof d, "%s %s", rows[sel].f[0], rows[sel].f[6]); - mu_label(ctx, d); - mu_layout_row(ctx, 1, w1, RH); - snprintf(d, sizeof d, "%s %s %s Epistola %s Evangelium %s", - rows[sel].f[3], rows[sel].f[9], rows[sel].f[11], - rows[sel].f[13], rows[sel].f[14]); - mu_label(ctx, d); - } - mu_end_window(ctx); -} - -int main(void) -{ - Display *dpy = XOpenDisplay(NULL); - if (!dpy) { fputs("cannot open display\n", stderr); return 1; } - int scr = DefaultScreen(dpy); - int W = 1000, H = 700; - Window win = XCreateSimpleWindow(dpy, RootWindow(dpy, scr), 0, 0, W, H, 0, - BlackPixel(dpy, scr), BlackPixel(dpy, scr)); - XStoreName(dpy, win, "colitur-mu"); - XSelectInput(dpy, win, ExposureMask | KeyPressMask | KeyReleaseMask | - ButtonPressMask | ButtonReleaseMask | PointerMotionMask | - StructureNotifyMask); - XMapWindow(dpy, win); - mux_init(dpy, win, font); - - mu_Context *ctx = malloc(sizeof *ctx); - mu_init(ctx); - ctx->text_width = mux_text_width; - ctx->text_height = mux_text_height; - - reload(); - - /* An immediate-mode UI is a RENDER LOOP, not an event handler. Drawing - only in response to an X event is wrong twice over: microui's first - frame merely creates its containers and the second is what lays them - out, and a container's scroll state settles a frame late. Drain the - queue, then always draw. */ - for (int running = 1; running;) { - while (XPending(dpy)) { - XEvent ev; - XNextEvent(dpy, &ev); - switch (ev.type) { - case ConfigureNotify: W = ev.xconfigure.width; H = ev.xconfigure.height; break; - case MotionNotify: mu_input_mousemove(ctx, ev.xmotion.x, ev.xmotion.y); break; - case ButtonPress: - if (ev.xbutton.button == 4) mu_input_scroll(ctx, 0, -30); - else if (ev.xbutton.button == 5) mu_input_scroll(ctx, 0, 30); - else mu_input_mousedown(ctx, ev.xbutton.x, ev.xbutton.y, MU_MOUSE_LEFT); - break; - case ButtonRelease: - if (ev.xbutton.button < 4) - mu_input_mouseup(ctx, ev.xbutton.x, ev.xbutton.y, MU_MOUSE_LEFT); - break; - case KeyPress: { - KeySym k = XLookupKeysym(&ev.xkey, 0); - if (k == XK_q) running = 0; - if (k == XK_Down && sel < nrows - 1) sel++; - if (k == XK_Up && sel > 0) sel--; - break; - } - } - } - mu_begin(ctx); - frame(ctx, W, H); - mu_end(ctx); - mux_present(ctx, W, H, mu_color(20, 20, 20, 255)); - XFlush(dpy); - nanosleep(&(struct timespec){ 0, 16000000 }, NULL); /* ~60 Hz */ - } - XCloseDisplay(dpy); - return 0; -} |
