aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/draw.c12
-rw-r--r--src/main.c6
-rw-r--r--src/screen.c17
-rw-r--r--src/vega.h10
-rw-r--r--src/web.c10
5 files changed, 38 insertions, 17 deletions
diff --git a/src/draw.c b/src/draw.c
index 738c2db..31188c7 100644
--- a/src/draw.c
+++ b/src/draw.c
@@ -138,6 +138,7 @@ static void say_focus(FILE *out, PureApp *app, const VegaPart *part) {
size_t length, rows = vega_rows(app, part);
if (!rows) { fprintf(out, "%s is empty.\n", m->view_names[part->view]); return; }
size_t focus = vega_focus(app, part);
+ if (focus >= rows) { fprintf(out, "%s: none of %zu focused.\n", m->view_names[part->view], rows); return; }
fprintf(out, "Item %zu of %zu: ", focus + 1, rows);
VegaTone tone = vega_tone(app, part, focus);
if (tone >= VEGA_ACCENT) fprintf(out, "%s, ", tone_names[tone]);
@@ -164,8 +165,15 @@ void vega_say(FILE *out, PureApp *app, const VegaScreen *screen, bool all) {
char text[VEGA_TEXT];
size_t length;
if (!all) {
- for (unsigned i = 0; i < screen->count; ++i)
- if (screen->parts[i].kind != VEGA_FIELD) { say_focus(out, app, &screen->parts[i]); return; }
+ /* The focused item where a list shows it, else the first list. */
+ const VegaPart *first = NULL;
+ for (unsigned i = 0; i < screen->count; ++i) {
+ const VegaPart *part = &screen->parts[i];
+ if (part->kind == VEGA_FIELD) continue;
+ if (!first) first = part;
+ if (vega_focus(app, part) < vega_rows(app, part)) { say_focus(out, app, part); return; }
+ }
+ if (first) say_focus(out, app, first);
return;
}
if (screen->title >= 0 && vega_text(app, (uint32_t)screen->title, 0, text, &length)) {
diff --git a/src/main.c b/src/main.c
index 46b672f..b9ea91e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -95,8 +95,10 @@ static bool mouse(unsigned button, unsigned line) {
const VegaPart *part = &screen.parts[index];
if (button == 64 || button == 65) {
size_t focus = vega_focus(&app, part), rows = vega_rows(&app, part);
- if (button == 64 ? !focus : focus + 1 >= rows) return false;
- item = button == 64 ? focus - 1 : focus + 1;
+ if (focus < rows) { /* else the wheel focuses the row under it */
+ if (button == 64 ? !focus : focus + 1 >= rows) return false;
+ item = button == 64 ? focus - 1 : focus + 1;
+ }
} else if (button) return false;
return vega_point(&app, part, item);
}
diff --git a/src/screen.c b/src/screen.c
index bb50de1..26b9fb0 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -146,20 +146,23 @@ bool vega_number(PureApp *app, uint32_t view, size_t row, double *out) {
return app->module->view_table[view] ? pure_app_cell(app, view, row, out) : pure_app_view(app, view, out);
}
-size_t vega_rows(const PureApp *app, const VegaPart *part) {
+size_t vega_rows(PureApp *app, const VegaPart *part) {
return part->kind == VEGA_FIELD ? 0 : pure_app_rows(app, part->view);
}
size_t vega_focus(PureApp *app, const VegaPart *part) {
- size_t rows = vega_rows(app, part);
+ size_t rows = vega_rows(app, part), row;
double focus;
if (part->focus < 0 || !rows || !vega_number(app, (uint32_t)part->focus, 0, &focus) || !(focus >= 0)) return 0;
- return focus >= (double)(rows - 1) ? rows - 1 : (size_t)focus;
+ bool filtered = app->module->view_code[part->view].length > 0;
+ size_t item = focus < (double)SIZE_MAX ? (size_t)focus : SIZE_MAX;
+ if (pure_app_item_row(app, part->view, item, &row)) return row;
+ return filtered ? VEGA_NO_ROW : rows - 1;
}
size_t vega_scroll(size_t first, size_t focus, size_t visible, size_t rows) {
- if (focus < first) first = focus;
- if (visible && focus >= first + visible) first = focus - visible + 1;
+ if (focus < rows && focus < first) first = focus;
+ if (focus < rows && visible && focus >= first + visible) first = focus - visible + 1;
if (first + visible > rows) first = rows > visible ? rows - visible : 0;
return first;
}
@@ -184,7 +187,9 @@ bool vega_commit(PureApp *app, const VegaScreen *screen, const char *text, size_
}
bool vega_point(PureApp *app, const VegaPart *part, size_t row) {
- return part->pointer >= 0 && pure_app_point(app, (uint32_t)part->pointer, row) == PURE_OK;
+ 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;
}
VegaTone vega_tone(PureApp *app, const VegaPart *part, size_t row) {
diff --git a/src/vega.h b/src/vega.h
index 98ed410..59a663e 100644
--- a/src/vega.h
+++ b/src/vega.h
@@ -45,14 +45,18 @@ unsigned vega_check(const PureModule *, void (*report)(void *, const char *name,
* shortest form. false when it has no value (for example a missing item). */
bool vega_text(PureApp *, uint32_t view, size_t row, char out[VEGA_TEXT], size_t *length);
bool vega_number(PureApp *, uint32_t view, size_t row, double *out);
-size_t vega_rows(const PureApp *, const VegaPart *);
-/* The focused row, clamped to the rows; 0 without a focus view. */
+size_t vega_rows(PureApp *, const VegaPart *);
+/* The row of the focused item: the focus view names an item (an index's
+ * position), shown on the row that holds it; VEGA_NO_ROW when a filtered
+ * list leaves that item out. Clamped to the rows without a filter; 0
+ * without a focus view. */
+#define VEGA_NO_ROW SIZE_MAX
size_t vega_focus(PureApp *, const VegaPart *);
/* Focus a row, as a user pointing at it (a click); false when the part's
* focus is not a plain index position or the row is not there. */
bool vega_point(PureApp *, const VegaPart *, size_t row);
/* The first row to show of `rows` when `visible` fit: the least scrolling
- * from first that keeps the focused row in view. */
+ * from first that keeps the focused row in view (any, without one). */
size_t vega_scroll(size_t first, size_t focus, size_t visible, size_t rows);
/* The key input answering a key name (Pure's names, as KeyboardEvent.code
* spells them), or -1; press sends its press and release. */
diff --git a/src/web.c b/src/web.c
index 78da0ab..149e888 100644
--- a/src/web.c
+++ b/src/web.c
@@ -123,8 +123,10 @@ static void screen_json(Buffer *b, PureApp *app, const VegaScreen *screen, size_
puts_(b, comma ? ",{\"part\":" : "{\"part\":");
putf(b, "%u,\"name\":", i);
json_name(b, m->view_names[part->view]);
- putf(b, ",\"kind\":\"%s\",\"rows\":%zu,\"focus\":%zu,\"first\":%zu,\"pointable\":%s,\"columns\":[",
- part->kind == VEGA_LIST ? "list" : "table", rows, rows ? focus : 0, first, part->pointer >= 0 ? "true" : "false");
+ putf(b, ",\"kind\":\"%s\",\"rows\":%zu,\"focus\":", part->kind == VEGA_LIST ? "list" : "table", rows);
+ if (focus < rows) putf(b, "%zu", focus);
+ else puts_(b, "null");
+ putf(b, ",\"first\":%zu,\"pointable\":%s,\"columns\":[", first, part->pointer >= 0 ? "true" : "false");
if (part->kind == VEGA_TABLE)
for (unsigned c = 0; c < part->column_count; ++c) {
if (c) puts_(b, ",");
@@ -224,12 +226,12 @@ static const char *const page_parts[] = {
"el('span',{className:'label',textContent:it.label?\?''}),it.detail?el('span',{className:'detail',textContent:it.detail}):null,"
"it.badge?el('span',{className:'badge',textContent:it.badge}):null);item.setAttribute('role','option');"
"item.setAttribute('aria-selected',it.row===p.focus);list.append(item)}"
-"list.onwheel=e=>{e.preventDefault();pick(Math.max(0,Math.min(p.rows-1,p.focus+Math.sign(e.deltaY))))};"
+"list.onwheel=e=>{e.preventDefault();pick(Math.max(0,Math.min(p.rows-1,(p.focus?\?-1)+Math.sign(e.deltaY))))};"
"return el('section',{},head,list)}"
"const table=el('table',{},el('thead',{},el('tr',{},...p.columns.map(c=>el('th',{textContent:c})))));"
"const body=el('tbody');for(const it of p.items){const tr=el('tr',{className:it.tone,onclick:()=>pick(it.row)},"
"...it.cells.map(c=>el('td',{textContent:c?\?'-'})));tr.setAttribute('aria-selected',it.row===p.focus);body.append(tr)}"
-"table.append(body);table.onwheel=e=>{e.preventDefault();pick(Math.max(0,Math.min(p.rows-1,p.focus+Math.sign(e.deltaY))))};"
+"table.append(body);table.onwheel=e=>{e.preventDefault();pick(Math.max(0,Math.min(p.rows-1,(p.focus?\?-1)+Math.sign(e.deltaY))))};"
"return el('section',{},head,table)}));"
"$('prompt').hidden=!s.prompt;if(s.prompt)$('entry').placeholder=s.prompt;"
"const symbols={ArrowUp:'\u2191',ArrowDown:'\u2193',ArrowLeft:'\u2190',ArrowRight:'\u2192',Backspace:'Bksp',"