Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 30 additions & 11 deletions views/detail_canvas.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,17 @@ static void fit_with_ellipsis(Canvas* c, char* s, int max_w) {
}
}

static size_t detail_scroll_positions(size_t row_count) {
if(row_count < DETAIL_VISIBLE) return 1;

/* One trailing blank row lets the last data row scroll above the OK hint. */
return row_count - DETAIL_VISIBLE + 2;
}

static size_t detail_scroll_max(size_t row_count) {
return detail_scroll_positions(row_count) - 1;
}

static void draw_rows(Canvas* c, const DetailModel* m) {
canvas_set_color(c, ColorBlack);

Expand All @@ -122,7 +133,8 @@ static void draw_rows(Canvas* c, const DetailModel* m) {
size_t end = m->scroll + DETAIL_VISIBLE;
if(end > m->row_count) end = m->row_count;

bool has_scrollbar = m->row_count > DETAIL_VISIBLE;
size_t scroll_positions = detail_scroll_positions(m->row_count);
bool has_scrollbar = scroll_positions > 1;
int right_edge = has_scrollbar ? 122 : 126;

for(size_t i = m->scroll; i < end; i++) {
Expand Down Expand Up @@ -165,7 +177,7 @@ static void draw_rows(Canvas* c, const DetailModel* m) {
if(has_scrollbar) {
elements_scrollbar_pos(
c, 127, DETAIL_LIST_TOP, 64 - DETAIL_LIST_TOP,
m->scroll, m->row_count - DETAIL_VISIBLE + 1);
m->scroll, scroll_positions);
}
}

Expand All @@ -182,7 +194,8 @@ static void draw_raw(Canvas* c, const DetailModel* m) {
"(no payload)");
return;
}
bool has_scrollbar = total_rows > DETAIL_VISIBLE;
size_t scroll_positions = detail_scroll_positions(total_rows);
bool has_scrollbar = scroll_positions > 1;
size_t end = m->raw_scroll + DETAIL_VISIBLE;
if(end > total_rows) end = total_rows;

Expand All @@ -201,7 +214,7 @@ static void draw_raw(Canvas* c, const DetailModel* m) {
if(has_scrollbar) {
elements_scrollbar_pos(
c, 127, DETAIL_LIST_TOP, 64 - DETAIL_LIST_TOP,
m->raw_scroll, total_rows - DETAIL_VISIBLE + 1);
m->raw_scroll, scroll_positions);
}
}

Expand Down Expand Up @@ -248,18 +261,24 @@ static bool detail_view_input(InputEvent* ev, void* ctx) {
}
} else if(m->raw_view) {
size_t total = (m->apdu_len + DETAIL_RAW_BYTES_PER_ROW - 1) / DETAIL_RAW_BYTES_PER_ROW;
if(total > DETAIL_VISIBLE) {
size_t max_scroll = detail_scroll_max(total);
if(max_scroll > 0) {
if(ev->key == InputKeyUp && m->raw_scroll > 0) {
m->raw_scroll--; need = true;
} else if(ev->key == InputKeyDown &&
m->raw_scroll + DETAIL_VISIBLE < total) {
m->raw_scroll < max_scroll) {
m->raw_scroll++; need = true;
}
}
} else if(m->row_count > DETAIL_VISIBLE) {
if(ev->key == InputKeyUp && m->scroll > 0) { m->scroll--; need = true; }
else if(ev->key == InputKeyDown &&
m->scroll + DETAIL_VISIBLE < m->row_count) { m->scroll++; need = true; }
} else {
size_t max_scroll = detail_scroll_max(m->row_count);
if(max_scroll > 0) {
if(ev->key == InputKeyUp && m->scroll > 0) {
m->scroll--; need = true;
} else if(ev->key == InputKeyDown && m->scroll < max_scroll) {
m->scroll++; need = true;
}
}
}
},
need);
Expand Down Expand Up @@ -316,7 +335,7 @@ void detail_canvas_set_rows(DetailCanvas* dc, const DetailRow* rows, size_t n) {
{
for(size_t i = 0; i < n; i++) m->rows[i] = rows[i];
m->row_count = n;
if(m->scroll > n) m->scroll = 0;
if(m->scroll > detail_scroll_max(n)) m->scroll = 0;
/* Always reset to decoded view when fields change so the user
* sees the new content first; OK still toggles on demand. */
m->raw_view = false;
Expand Down
66 changes: 52 additions & 14 deletions views/scan_canvas.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,44 @@ static void draw_footer(Canvas* c, const ScanModel* m) {
canvas_draw_str(c, 128 - tail_w - 2, 64 - 2, m->stats_tail);
}

static void draw_row(Canvas* c, int y_top, const ScanRow* r, bool selected) {
static void fit_scan_text(Canvas* c, char* s, int max_w) {
while(canvas_string_width(c, s) > max_w && s[0]) {
s[strlen(s) - 1] = 0;
}
}

static void fit_scan_head(Canvas* c, char* head, size_t cap, int max_w) {
if(canvas_string_width(c, head) <= max_w) return;

char mfr[5] = {0};
char medium[8] = {0};
char tail[8] = {0};
const char* first_space = strchr(head, ' ');
const char* last_space = strrchr(head, ' ');

if(first_space && last_space && first_space < last_space) {
size_t mfr_len = (size_t)(first_space - head);
size_t medium_len = (size_t)(last_space - first_space - 1);
if(mfr_len >= sizeof(mfr)) mfr_len = sizeof(mfr) - 1;
if(medium_len >= sizeof(medium)) medium_len = sizeof(medium) - 1;

memcpy(mfr, head, mfr_len);
memcpy(medium, first_space + 1, medium_len);
strncpy(tail, last_space + 1, sizeof(tail) - 1);

if(medium[0]) {
snprintf(head, cap, "%s %c %s", mfr, medium[0], tail);
if(canvas_string_width(c, head) <= max_w) return;
}

snprintf(head, cap, "%s %s", mfr, tail);
if(canvas_string_width(c, head) <= max_w) return;
}

fit_scan_text(c, head, max_w);
}

static void draw_row(Canvas* c, int y_top, const ScanRow* r, bool selected, bool has_scrollbar) {
/* Selected rows paint inverted; the pen colour must remain set across
* every draw call in the row. */
if(selected) {
Expand Down Expand Up @@ -136,27 +173,26 @@ static void draw_row(Canvas* c, int y_top, const ScanRow* r, bool selected) {
* edge until both fit. Without this clamp a verbose value (e.g. a
* raw hex dump from a proprietary frame) used to wipe the head off
* the row entirely, leaving the user staring at nothing but hex. */
const int kHeadMinW = 60; /* enough for "MFR 12345678" + medium */
const int kHeadMinW = 42; /* enough for compact "MFR 1234" */
const int right_edge = has_scrollbar ? 122 : 126;
char val[24];
val[0] = 0;
if(r->value[0]) {
strncpy(val, r->value, sizeof(val) - 1);
val[sizeof(val) - 1] = 0;
}
int vw = val[0] ? canvas_string_width(c, val) : 0;
int max_val_w = 128 - text_x - kHeadMinW - 4;
while(vw > max_val_w && val[0]) {
val[strlen(val) - 1] = 0;
vw = canvas_string_width(c, val);
}
int max_val_w = right_edge - text_x - kHeadMinW - 4;
if(max_val_w < 0) max_val_w = 0;
fit_scan_text(c, val, max_val_w);
vw = val[0] ? canvas_string_width(c, val) : 0;

int max_head_w = 128 - text_x - vw - 4;
while(canvas_string_width(c, head) > max_head_w && head[0]) {
head[strlen(head) - 1] = 0;
}
int max_head_w = right_edge - text_x - vw - 4;
if(max_head_w < 0) max_head_w = 0;
fit_scan_head(c, head, sizeof(head), max_head_w);

canvas_draw_str(c, text_x, text_y, head);
if(val[0]) canvas_draw_str(c, 128 - vw - 2, text_y, val);
if(val[0]) canvas_draw_str(c, right_edge - vw, text_y, val);

canvas_set_color(c, ColorBlack);
}
Expand All @@ -176,16 +212,18 @@ static void scan_view_draw(Canvas* c, void* m_) {
return;
}

bool has_scrollbar = m->row_count > SCAN_VISIBLE_ROWS;

/* Visible window: rows[scroll .. scroll+SCAN_VISIBLE_ROWS-1]. */
for(size_t i = 0; i < SCAN_VISIBLE_ROWS; i++) {
size_t idx = m->scroll + i;
if(idx >= m->row_count) break;
int y = SCAN_LIST_TOP + (int)i * SCAN_ROW_HEIGHT;
draw_row(c, y, &m->rows[idx], idx == m->cursor);
draw_row(c, y, &m->rows[idx], idx == m->cursor, has_scrollbar);
}

/* Scrollbar — thin column on the right edge of the list area. */
if(m->row_count > SCAN_VISIBLE_ROWS) {
if(has_scrollbar) {
elements_scrollbar_pos(c, 127, SCAN_LIST_TOP, SCAN_LIST_BOTTOM - SCAN_LIST_TOP,
m->cursor, m->row_count);
}
Expand Down
Loading