diff options
| author | eunhhu <[email protected]> | 2026-10-18 20:54:17 +0100 |
|---|---|---|
| committer | eunhhu <[email protected]> | 2026-10-18 20:54:17 +0100 |
| commit | 4d9598e7d0d6d45bf3db9305d365bd2967481bcd (patch) | |
| tree | 59a1b7c945eef69bf9098523c33dc3b8c29c1312 | |
| parent | 991403f164bef7dcf07b053900367a8f0a60ae6c (diff) | |
| download | vega-4d9598e7d0d6d45bf3db9305d365bd2967481bcd.tar.gz vega-4d9598e7d0d6d45bf3db9305d365bd2967481bcd.zip | |
Send every input as a message (Pure 027's 4d): keys, text, timers, frames and pointing go to the inputs bound to them; a key's press then its release when a message takes it; vega_frame sends dt 1/60 to the frame input, deferring the save as frames were; a table's pointer is the input pointing at it, sent the item's position; a key's handler found by its input's number
| -rw-r--r-- | surfaces/access.c | 6 | ||||
| -rw-r--r-- | surfaces/draw.c | 4 | ||||
| -rw-r--r-- | surfaces/main.c | 14 | ||||
| -rw-r--r-- | surfaces/screen.c | 50 | ||||
| -rw-r--r-- | surfaces/vega.h | 7 | ||||
| -rw-r--r-- | surfaces/web.c | 8 |
6 files changed, 54 insertions, 35 deletions
diff --git a/surfaces/access.c b/surfaces/access.c index 9b5452b..24e3d00 100644 --- a/surfaces/access.c +++ b/surfaces/access.c @@ -76,7 +76,7 @@ static Object parse_path(const VegaAccess *a, const char *path) { if (o.kind == ROW && s->parts[o.part].kind == VEGA_FIELD) o.kind = NONE; if (o.kind == TITLE && s->title < 0) o.kind = NONE; if (o.kind == ENTRY && s->prompt < 0) o.kind = NONE; - if (o.kind == KEY && (o.key >= a->app->module->inputs || a->app->module->input[o.key].kind != PURE_KIND_KEY)) o.kind = NONE; + if (o.kind == KEY && (o.key >= a->app->module->inputs || a->app->module->input[o.key].binding != PURE_BIND_PRESS)) o.kind = NONE; return o; } @@ -98,9 +98,9 @@ static void path_of(const Object *o, char *out, size_t size) { /* The keys the screen answers: key inputs a handler takes. */ static bool bound_key(const PureModule *m, uint32_t input) { - if (m->input[input].kind != PURE_KIND_KEY) return false; + if (m->input[input].binding != PURE_BIND_PRESS) return false; for (uint32_t h = 0; h < m->handlers; ++h) - if (m->handler[h].event == 1 + 2 * input) return true; + if (m->handler[h].event == input) return true; return false; } diff --git a/surfaces/draw.c b/surfaces/draw.c index 3135705..e02a4ec 100644 --- a/surfaces/draw.c +++ b/surfaces/draw.c @@ -523,9 +523,9 @@ void vega_draw(VegaGrid *grid, PureApp *app, const VegaScreen *screen, const cha Pen help = pen_at(grid, bottom, 0, grid->width, VEGA_MUTED, false, false); if (screen->prompt >= 0) write_cstr(&help, typing ? "Tab keys " : "Tab type "); for (uint32_t i = 0; i < m->inputs; ++i) { - if (m->input[i].kind != PURE_KIND_KEY) continue; + if (m->input[i].binding != PURE_BIND_PRESS) continue; bool bound = false; - for (uint32_t h = 0; h < m->handlers && !bound; ++h) bound = m->handler[h].event == 1 + 2 * i; + for (uint32_t h = 0; h < m->handlers && !bound; ++h) bound = m->handler[h].event == i; if (!bound) continue; write_cstr(&help, key_symbol(m->input_keys[i])); write_cstr(&help, " "); diff --git a/surfaces/main.c b/surfaces/main.c index fc68d97..da0e4b8 100644 --- a/surfaces/main.c +++ b/surfaces/main.c @@ -533,7 +533,7 @@ static int interactive(void) { vega_draw(&grid, &app, &screen, line, shown_entry(line), typing); paint_terminal(&grid); struct pollfd wait = {STDIN_FILENO, POLLIN, 0}; - int timeout = screen.ticks ? 16 : watched ? 200 : -1; + int timeout = screen.frame >= 0 ? 16 : watched ? 200 : -1; if (due >= 0 && (timeout < 0 || due < timeout)) timeout = (int)due; if (pending_length) { /* a key begun waits for its rest (an escape: or is the Escape key) */ double left = pending_since + pending_wait() - vega_clock(); @@ -546,7 +546,7 @@ static int interactive(void) { !handle_input(NULL, 0, true)) break; if (ready == 0) { - if (screen.ticks) pure_app_frame(&app); + vega_frame(&app, &screen); if (module_changed()) vega_timers_start(&timers, app.module, vega_clock()); continue; } @@ -740,12 +740,12 @@ static int live(VegaInput *input, unsigned columns, unsigned rows, bool recorded unsigned count = open_input ? vega_input_fds(input, waits, 32) : 0; if (node) waits[count++] = (struct pollfd){node->changes, POLLIN, 0}; /* the node saved: draw again */ if (access) waits[count++] = (struct pollfd){vega_access_fd(access), POLLIN, 0}; /* a screen reader asks */ - int timeout = screen.ticks && !node ? 16 : -1; + int timeout = screen.frame >= 0 && !node ? 16 : -1; if (due >= 0 && (timeout < 0 || due < timeout)) timeout = (int)due; if (poll(waits, count, timeout) <= 0) { if (node) continue; app.now = vega_now(); - if (screen.ticks) pure_app_frame(&app), dirty = true; + if (screen.frame >= 0) vega_frame(&app, &screen), dirty = true; continue; } if (!node) app.now = vega_now(); @@ -848,17 +848,17 @@ static int script(Surface surface, unsigned width, unsigned height, bool paintin } else if (!strcmp(command, "tick")) { input = pure_module_input(app.module, argument); verb = "tick"; - if (input < 0 || app.module->input[input].kind != PURE_KIND_TIMER) { + if (input < 0 || app.module->input[input].binding != PURE_BIND_TIMER) { fprintf(stderr, "vega: no timer %s\n", argument); input = -1; ok = false; - } else ok = pure_app_tick(&app, (uint32_t)input) == PURE_OK; + } else ok = pure_app_message(&app, (uint32_t)input, (PureSpan){0}) == PURE_OK; } else if (!strcmp(command, "swap")) { acted = false; if (!swap(argument, read_module(argument))) fprintf(stderr, "vega: kept the running module\n"); } else if (!strcmp(command, "frame")) { long count = *argument ? strtol(argument, NULL, 10) : 1; - for (long i = 0; i < count && i < 600; ++i) ok = pure_app_frame(&app) == PURE_OK && ok; + for (long i = 0; i < count && i < 600; ++i) ok = (screen.frame < 0 || vega_frame(&app, &screen)) && ok; } else if (!strcmp(command, "show")) { acted = false; if (surface == SURFACE_CLI) vega_print(stdout, &app, &screen, color); diff --git a/surfaces/screen.c b/surfaces/screen.c index ed06c9d..6f5aeb7 100644 --- a/surfaces/screen.c +++ b/surfaces/screen.c @@ -20,17 +20,17 @@ double vega_clock(void) { void vega_timers_start(VegaTimers *timers, const PureModule *m, double clock) { for (uint32_t i = 0; i < m->inputs; ++i) - timers->next[i] = m->input[i].kind == PURE_KIND_TIMER ? clock + m->input[i].period : 0; + timers->next[i] = m->input[i].binding == PURE_BIND_TIMER ? clock + m->input[i].period : 0; } long vega_timers_run(VegaTimers *timers, PureApp *app, double clock, bool *ticked) { const PureModule *m = app->module; double soonest = -1; for (uint32_t i = 0; i < m->inputs; ++i) { - if (m->input[i].kind != PURE_KIND_TIMER) continue; + if (m->input[i].binding != PURE_BIND_TIMER) continue; if (timers->next[i] <= clock) { app->now = vega_now(); - pure_app_tick(app, i); /* a failed tick changes nothing, as any failed event */ + pure_app_message(app, i, (PureSpan){0}); /* a failed tick changes nothing, as any failed event */ *ticked = true; timers->next[i] = clock + m->input[i].period; } @@ -53,10 +53,11 @@ void vega_screen(VegaScreen *screen, const PureModule *m) { screen->module = m; screen->title = pure_module_view(m, "title"); if (screen->title >= 0 && m->view_type[screen->title] != PURE_VIEW_TEXT) screen->title = -1; - screen->prompt = -1; - for (uint32_t i = 0; i < m->inputs && screen->prompt < 0; ++i) - if (m->input[i].kind == PURE_KIND_TEXT) screen->prompt = (int)i; - for (uint32_t h = 0; h < m->handlers; ++h) screen->ticks = screen->ticks || m->handler[h].event == 0; + screen->prompt = screen->frame = -1; + for (uint32_t i = 0; i < m->inputs; ++i) { + if (m->input[i].binding == PURE_BIND_TEXT && screen->prompt < 0) screen->prompt = (int)i; + if (m->input[i].binding == PURE_BIND_FRAME) screen->frame = (int)i; + } /* A <table>_focus view belongs to its table, not to the fields. */ bool focus_view[PURE_MODULE_VIEWS] = {false}; for (uint32_t i = 0; i < m->views; ++i) { @@ -76,7 +77,8 @@ void vega_screen(VegaScreen *screen, const PureModule *m) { snprintf(name, sizeof(name), "%s_focus", m->view_names[i]); part->focus = pure_module_view(m, name); if (part->focus >= 0 && !focus_view[part->focus]) part->focus = -1; - part->pointer = part->focus >= 0 ? pure_module_position(m, (uint32_t)part->focus) : -1; + for (uint32_t k = 0; part->focus >= 0 && k < m->inputs; ++k) + if (m->input[k].binding == PURE_BIND_POINT && m->input[k].view == i) part->pointer = (int)k; part->label = column(m, i, "label", PURE_VIEW_TEXT); part->tone = column(m, i, "tone", PURE_VIEW_NUM); part->kind = part->label >= 0 ? VEGA_LIST : VEGA_TABLE; @@ -136,7 +138,7 @@ unsigned vega_check(const PureModule *m, void (*report)(void *, const char *name } int prompt = -1; for (uint32_t i = 0; i < m->inputs; ++i) { - if (m->input[i].kind != PURE_KIND_TEXT) continue; + if (m->input[i].binding != PURE_BIND_TEXT) continue; snprintf(name, sizeof(name), "%s", m->input_names[i]); if (prompt >= 0) FIND("only the first text input (%s) has a place to type into", m->input_names[prompt]); else prompt = (int)i; @@ -213,29 +215,43 @@ size_t vega_scroll(size_t first, size_t focus, size_t visible, size_t rows) { return first; } -int vega_key_input(const PureModule *m, const char *key) { +static int bound(const PureModule *m, uint8_t binding, const char *key) { for (uint32_t i = 0; i < m->inputs; ++i) - if (m->input[i].kind == PURE_KIND_KEY && !strcmp(m->input_keys[i], key)) return (int)i; + if (m->input[i].binding == binding && !strcmp(m->input_keys[i], key)) return (int)i; return -1; } +int vega_key_input(const PureModule *m, const char *key) { return bound(m, PURE_BIND_PRESS, key); } + bool vega_press(PureApp *app, const char *key) { - int input = vega_key_input(app->module, key); + int input = vega_key_input(app->module, key), up = bound(app->module, PURE_BIND_RELEASE, key); if (input < 0) return false; - bool ok = pure_app_input(app, (uint32_t)input, PURE_EDGE_DOWN) == PURE_OK; - pure_app_input(app, (uint32_t)input, PURE_EDGE_UP); + bool ok = pure_app_message(app, (uint32_t)input, (PureSpan){0}) == PURE_OK; + if (up >= 0) pure_app_message(app, (uint32_t)up, (PureSpan){0}); return ok; } bool vega_commit(PureApp *app, const VegaScreen *screen, const char *text, size_t length) { return screen->prompt >= 0 && - pure_app_text(app, (uint32_t)screen->prompt, (PureSpan){(const unsigned char *)text, length}) == PURE_OK; + pure_app_message(app, (uint32_t)screen->prompt, (PureSpan){(const unsigned char *)text, length}) == PURE_OK; } bool vega_point(PureApp *app, const VegaPart *part, size_t row) { size_t item; /* a filtered list's row shows some item of the list */ - return part->pointer >= 0 && pure_app_row_item(app, part->view, row, &item) && - pure_app_point(app, (uint32_t)part->pointer, item) == PURE_OK; + if (part->pointer < 0 || !pure_app_row_item(app, part->view, row, &item) || item > UINT32_MAX) return false; + unsigned char position[4] = {(unsigned char)item, (unsigned char)(item >> 8), (unsigned char)(item >> 16), + (unsigned char)(item >> 24)}; + return pure_app_message(app, (uint32_t)part->pointer, (PureSpan){position, 4}) == PURE_OK; +} + +bool vega_frame(PureApp *app, const VegaScreen *screen) { + static const double dt = 1.0 / 60.0; + if (screen->frame < 0) return false; + bool deferred = app->deferred; + pure_app_defer(app, true); /* a frame's changes are stored by the next event or a save, as before (027's 4d) */ + bool ok = pure_app_message(app, (uint32_t)screen->frame, (PureSpan){(const unsigned char *)&dt, sizeof(dt)}) == PURE_OK; + pure_app_defer(app, deferred); + return ok; } VegaTone vega_tone(PureApp *app, const VegaPart *part, size_t row) { diff --git a/surfaces/vega.h b/surfaces/vega.h index a800835..7cf26ed 100644 --- a/surfaces/vega.h +++ b/surfaces/vega.h @@ -23,7 +23,7 @@ typedef struct { VegaKind kind; uint32_t view; int focus; /* number view with the focused row, or -1 */ - int pointer; /* the index state that view shows, or -1: a surface may move it */ + int pointer; /* the input pointing at this table's rows (focus = at.position), or -1 */ int label, tone, detail, badge; /* columns, or -1 */ uint32_t columns[PURE_MODULE_VIEWS]; /* a table's shown columns, in order */ unsigned column_count; @@ -33,7 +33,7 @@ typedef struct { const PureModule *module; int title; /* text view, or -1 */ int prompt; /* the first text input, or -1 */ - bool ticks; /* it handles frames: a surface runs them, about 60 a second */ + int frame; /* the input frames go to, or -1: a surface sends them, about 60 a second (vega_frame) */ VegaPart parts[VEGA_PARTS]; unsigned count; } VegaScreen; @@ -83,6 +83,9 @@ int vega_key_input(const PureModule *, const char *key); bool vega_press(PureApp *, const char *key); /* Commit text to the screen's text input. */ bool vega_commit(PureApp *, const VegaScreen *, const char *text, size_t length); +/* A frame (1/60 s) to the screen's frame input, stored with the next event or a save; false without one or when its + * event fails. */ +bool vega_frame(PureApp *, const VegaScreen *); VegaTone vega_tone(PureApp *, const VegaPart *, size_t row); /* Values evaluated so far, for checking that surfaces stay lazy. */ unsigned long vega_evaluations(void); diff --git a/surfaces/web.c b/surfaces/web.c index dfa9470..4e81614 100644 --- a/surfaces/web.c +++ b/surfaces/web.c @@ -160,9 +160,9 @@ static void screen_json(Buffer *b, PureApp *app, const VegaScreen *screen, size_ puts_(b, "],\"keys\":["); comma = false; for (uint32_t i = 0; i < m->inputs; ++i) { - if (m->input[i].kind != PURE_KIND_KEY) continue; + if (m->input[i].binding != PURE_BIND_PRESS) continue; bool bound = false; - for (uint32_t h = 0; h < m->handlers && !bound; ++h) bound = m->handler[h].event == 1 + 2 * i; + for (uint32_t h = 0; h < m->handlers && !bound; ++h) bound = m->handler[h].event == i; if (!bound) continue; puts_(b, comma ? ",{\"input\":" : "{\"input\":"); json_name(b, m->input_names[i]); @@ -437,13 +437,13 @@ int vega_web(PureApp *app, const VegaScreen *screen, const char *listen_on, unsi fds[count] = (struct pollfd){c->fd, (short)(POLLIN | (c->out_at < c->out.used ? POLLOUT : 0)), 0}; slot[count++] = i; } - int timeout = ticked ? 0 : screen->ticks ? 33 : reload ? 200 : 1000; + int timeout = ticked ? 0 : screen->frame >= 0 ? 33 : reload ? 200 : 1000; if (due >= 0 && due < timeout) timeout = (int)due; int ready = poll(fds, count, timeout); if (ready < 0 && errno != EINTR) break; bool changed = ticked; app->now = vega_now(); /* what the events of this round see */ - if (ready == 0 && screen->ticks) changed = pure_app_frame(app) == PURE_OK; + if (ready == 0 && screen->frame >= 0) changed = vega_frame(app, screen); if (reload && reload()) { /* a new module: every page draws it */ changed = true; vega_timers_start(&timers, app->module, vega_clock()); |
