From e340e6ccd74fbef991671fad152bcf32c1edf45f Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 8 Aug 2023 07:41:04 +0000 Subject: [PATCH] Extend the menu drawing function to support custom characters and styles, from Alexis Hildebrandt. --- usr.bin/tmux/menu.c | 5 +- usr.bin/tmux/screen-write.c | 150 ++++++++++++++++++++--------------- usr.bin/tmux/tmux.h | 6 +- usr.bin/tmux/window-client.c | 4 +- 4 files changed, 93 insertions(+), 72 deletions(-) diff --git a/usr.bin/tmux/menu.c b/usr.bin/tmux/menu.c index e1efa60e72d..4c72a49edde 100644 --- a/usr.bin/tmux/menu.c +++ b/usr.bin/tmux/menu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: menu.c,v 1.49 2023/02/05 21:26:48 nicm Exp $ */ +/* $OpenBSD: menu.c,v 1.50 2023/08/08 07:41:04 nicm Exp $ */ /* * Copyright (c) 2019 Nicholas Marriott @@ -203,7 +203,8 @@ menu_draw_cb(struct client *c, void *data, screen_write_start(&ctx, s); screen_write_clearscreen(&ctx, 8); - screen_write_menu(&ctx, menu, md->choice, &gc); + screen_write_menu(&ctx, menu, md->choice, BOX_LINES_DEFAULT, + &grid_default_cell, &grid_default_cell, &gc); screen_write_stop(&ctx); for (i = 0; i < screen_size_y(&md->s); i++) { diff --git a/usr.bin/tmux/screen-write.c b/usr.bin/tmux/screen-write.c index 43c923e681e..9f57565a88c 100644 --- a/usr.bin/tmux/screen-write.c +++ b/usr.bin/tmux/screen-write.c @@ -1,4 +1,4 @@ -/* $OpenBSD: screen-write.c,v 1.215 2023/07/14 19:32:59 nicm Exp $ */ +/* $OpenBSD: screen-write.c,v 1.216 2023/08/08 07:41:04 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -30,7 +30,6 @@ static void screen_write_collect_clear(struct screen_write_ctx *, u_int, static void screen_write_collect_scroll(struct screen_write_ctx *, u_int); static void screen_write_collect_flush(struct screen_write_ctx *, int, const char *); - static int screen_write_overwrite(struct screen_write_ctx *, struct grid_cell *, u_int); static const struct grid_cell *screen_write_combine(struct screen_write_ctx *, @@ -592,9 +591,46 @@ screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src, } } +/* Select character set for drawing border lines. */ +static void +screen_write_box_border_set(enum box_lines lines, int cell_type, + struct grid_cell *gc) +{ + switch (lines) { + case BOX_LINES_NONE: + break; + case BOX_LINES_DOUBLE: + gc->attr &= ~GRID_ATTR_CHARSET; + utf8_copy(&gc->data, tty_acs_double_borders(cell_type)); + break; + case BOX_LINES_HEAVY: + gc->attr &= ~GRID_ATTR_CHARSET; + utf8_copy(&gc->data, tty_acs_heavy_borders(cell_type)); + break; + case BOX_LINES_ROUNDED: + gc->attr &= ~GRID_ATTR_CHARSET; + utf8_copy(&gc->data, tty_acs_rounded_borders(cell_type)); + break; + case BOX_LINES_SIMPLE: + gc->attr &= ~GRID_ATTR_CHARSET; + utf8_set(&gc->data, SIMPLE_BORDERS[cell_type]); + break; + case BOX_LINES_PADDED: + gc->attr &= ~GRID_ATTR_CHARSET; + utf8_set(&gc->data, PADDED_BORDERS[cell_type]); + break; + case BOX_LINES_SINGLE: + case BOX_LINES_DEFAULT: + gc->attr |= GRID_ATTR_CHARSET; + utf8_set(&gc->data, CELL_BORDERS[cell_type]); + break; + } +} + /* Draw a horizontal line on screen. */ void -screen_write_hline(struct screen_write_ctx *ctx, u_int nx, int left, int right) +screen_write_hline(struct screen_write_ctx *ctx, u_int nx, int left, int right, + enum box_lines lines, const struct grid_cell *border_gc) { struct screen *s = ctx->s; struct grid_cell gc; @@ -603,13 +639,27 @@ screen_write_hline(struct screen_write_ctx *ctx, u_int nx, int left, int right) cx = s->cx; cy = s->cy; - memcpy(&gc, &grid_default_cell, sizeof gc); + if (border_gc != NULL) + memcpy(&gc, border_gc, sizeof gc); + else + memcpy(&gc, &grid_default_cell, sizeof gc); gc.attr |= GRID_ATTR_CHARSET; - screen_write_putc(ctx, &gc, left ? 't' : 'q'); + if (left) + screen_write_box_border_set(lines, CELL_LEFTJOIN, &gc); + else + screen_write_box_border_set(lines, CELL_LEFTRIGHT, &gc); + screen_write_cell(ctx, &gc); + + screen_write_box_border_set(lines, CELL_LEFTRIGHT, &gc); for (i = 1; i < nx - 1; i++) - screen_write_putc(ctx, &gc, 'q'); - screen_write_putc(ctx, &gc, right ? 'u' : 'q'); + screen_write_cell(ctx, &gc); + + if (right) + screen_write_box_border_set(lines, CELL_RIGHTJOIN, &gc); + else + screen_write_box_border_set(lines, CELL_LEFTRIGHT, &gc); + screen_write_cell(ctx, &gc); screen_write_set_cursor(ctx, cx, cy); } @@ -641,84 +691,52 @@ screen_write_vline(struct screen_write_ctx *ctx, u_int ny, int top, int bottom) /* Draw a menu on screen. */ void -screen_write_menu(struct screen_write_ctx *ctx, struct menu *menu, - int choice, const struct grid_cell *choice_gc) +screen_write_menu(struct screen_write_ctx *ctx, struct menu *menu, int choice, + enum box_lines lines, const struct grid_cell *menu_gc, + const struct grid_cell *border_gc, const struct grid_cell *choice_gc) { struct screen *s = ctx->s; struct grid_cell default_gc; const struct grid_cell *gc = &default_gc; - u_int cx, cy, i, j; + u_int cx, cy, i, j, width = menu->width; const char *name; cx = s->cx; cy = s->cy; - memcpy(&default_gc, &grid_default_cell, sizeof default_gc); + memcpy(&default_gc, menu_gc, sizeof default_gc); - screen_write_box(ctx, menu->width + 4, menu->count + 2, - BOX_LINES_DEFAULT, &default_gc, menu->title); + screen_write_box(ctx, menu->width + 4, menu->count + 2, lines, + border_gc, menu->title); for (i = 0; i < menu->count; i++) { name = menu->items[i].name; if (name == NULL) { screen_write_cursormove(ctx, cx, cy + 1 + i, 0); - screen_write_hline(ctx, menu->width + 4, 1, 1); - } else { - if (choice >= 0 && i == (u_int)choice && *name != '-') - gc = choice_gc; - screen_write_cursormove(ctx, cx + 2, cy + 1 + i, 0); - for (j = 0; j < menu->width; j++) - screen_write_putc(ctx, gc, ' '); - screen_write_cursormove(ctx, cx + 2, cy + 1 + i, 0); - if (*name == '-') { - name++; - default_gc.attr |= GRID_ATTR_DIM; - format_draw(ctx, gc, menu->width, name, NULL, - 0); - default_gc.attr &= ~GRID_ATTR_DIM; - } else - format_draw(ctx, gc, menu->width, name, NULL, - gc == choice_gc); - gc = &default_gc; + screen_write_hline(ctx, width + 4, 1, 1, lines, gc); + continue; } - } - screen_write_set_cursor(ctx, cx, cy); -} + if (choice >= 0 && i == (u_int)choice && *name != '-') + gc = choice_gc; -static void -screen_write_box_border_set(enum box_lines box_lines, int cell_type, - struct grid_cell *gc) -{ - switch (box_lines) { - case BOX_LINES_NONE: - break; - case BOX_LINES_DOUBLE: - gc->attr &= ~GRID_ATTR_CHARSET; - utf8_copy(&gc->data, tty_acs_double_borders(cell_type)); - break; - case BOX_LINES_HEAVY: - gc->attr &= ~GRID_ATTR_CHARSET; - utf8_copy(&gc->data, tty_acs_heavy_borders(cell_type)); - break; - case BOX_LINES_ROUNDED: - gc->attr &= ~GRID_ATTR_CHARSET; - utf8_copy(&gc->data, tty_acs_rounded_borders(cell_type)); - break; - case BOX_LINES_SIMPLE: - gc->attr &= ~GRID_ATTR_CHARSET; - utf8_set(&gc->data, SIMPLE_BORDERS[cell_type]); - break; - case BOX_LINES_PADDED: - gc->attr &= ~GRID_ATTR_CHARSET; - utf8_set(&gc->data, PADDED_BORDERS[cell_type]); - break; - case BOX_LINES_SINGLE: - case BOX_LINES_DEFAULT: - gc->attr |= GRID_ATTR_CHARSET; - utf8_set(&gc->data, CELL_BORDERS[cell_type]); - break; + screen_write_cursormove(ctx, cx + 2, cy + 1 + i, 0); + for (j = 0; j < width; j++) + screen_write_putc(ctx, gc, ' '); + + screen_write_cursormove(ctx, cx + 2, cy + 1 + i, 0); + if (*name == '-') { + default_gc.attr |= GRID_ATTR_DIM; + format_draw(ctx, gc, width, name + 1, NULL, 0); + default_gc.attr &= ~GRID_ATTR_DIM; + continue; + } + + format_draw(ctx, gc, width, name, NULL, gc == choice_gc); + gc = &default_gc; } + + screen_write_set_cursor(ctx, cx, cy); } /* Draw a box on screen. */ diff --git a/usr.bin/tmux/tmux.h b/usr.bin/tmux/tmux.h index fae976b8cbb..1b994db77e2 100644 --- a/usr.bin/tmux/tmux.h +++ b/usr.bin/tmux/tmux.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tmux.h,v 1.1201 2023/07/10 09:24:53 nicm Exp $ */ +/* $OpenBSD: tmux.h,v 1.1202 2023/08/08 07:41:04 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -2889,9 +2889,11 @@ void screen_write_putc(struct screen_write_ctx *, const struct grid_cell *, u_char); void screen_write_fast_copy(struct screen_write_ctx *, struct screen *, u_int, u_int, u_int, u_int); -void screen_write_hline(struct screen_write_ctx *, u_int, int, int); +void screen_write_hline(struct screen_write_ctx *, u_int, int, int, + enum box_lines, const struct grid_cell *); void screen_write_vline(struct screen_write_ctx *, u_int, int, int); void screen_write_menu(struct screen_write_ctx *, struct menu *, int, + enum box_lines, const struct grid_cell *, const struct grid_cell *, const struct grid_cell *); void screen_write_box(struct screen_write_ctx *, u_int, u_int, enum box_lines, const struct grid_cell *, const char *); diff --git a/usr.bin/tmux/window-client.c b/usr.bin/tmux/window-client.c index c6b79f8597e..26161035a21 100644 --- a/usr.bin/tmux/window-client.c +++ b/usr.bin/tmux/window-client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: window-client.c,v 1.33 2022/05/30 12:55:25 nicm Exp $ */ +/* $OpenBSD: window-client.c,v 1.34 2023/08/08 07:41:04 nicm Exp $ */ /* * Copyright (c) 2017 Nicholas Marriott @@ -242,7 +242,7 @@ window_client_draw(__unused void *modedata, void *itemdata, screen_write_cursormove(ctx, cx, cy + 2, 0); else screen_write_cursormove(ctx, cx, cy + sy - 1 - lines, 0); - screen_write_hline(ctx, sx, 0, 0); + screen_write_hline(ctx, sx, 0, 0, BOX_LINES_DEFAULT, NULL); if (at != 0) screen_write_cursormove(ctx, cx, cy, 0); -- 2.20.1