diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2017-05-13 12:42:17 -0700 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2017-05-13 12:42:17 -0700 |
commit | 0c0d1ea5cdb96a98e7eb62edbd1acb534ae12940 (patch) | |
tree | 7b64a6e98fb16d2bf02c5003acc2c14d7d1d6043 /termbox | |
parent | 8195ed4ee94f490d377b91caa0d79f21dd3e86ed (diff) | |
download | mu-0c0d1ea5cdb96a98e7eb62edbd1acb534ae12940.tar.gz |
3854
Revert commits 3824, 3850 and 3852. We'll redo them more carefully.
Diffstat (limited to 'termbox')
-rw-r--r-- | termbox/termbox.c | 156 | ||||
-rw-r--r-- | termbox/termbox.h | 36 |
2 files changed, 180 insertions, 12 deletions
diff --git a/termbox/termbox.c b/termbox/termbox.c index 6a22f109..36c9496a 100644 --- a/termbox/termbox.c +++ b/termbox/termbox.c @@ -23,10 +23,20 @@ extern int wcwidth (wchar_t); #include "output.inl" #include "input.inl" +struct cellbuf { + int width; + int height; + struct tb_cell *cells; +}; + +#define CELL(buf, x, y) (buf)->cells[(y) * (buf)->width + (x)] +#define IS_CURSOR_HIDDEN(cx, cy) (cx == -1 || cy == -1) #define LAST_COORD_INIT -1 static struct termios orig_tios; +static struct cellbuf back_buffer; +static struct cellbuf front_buffer; static struct bytebuffer output_buffer; static struct bytebuffer input_buffer; @@ -47,6 +57,11 @@ static uint16_t foreground = TB_WHITE; static void write_cursor(int x, int y); static void write_sgr(uint16_t fg, uint16_t bg); +static void cellbuf_init(struct cellbuf *buf, int width, int height); +static void cellbuf_resize(struct cellbuf *buf, int width, int height); +static void cellbuf_clear(struct cellbuf *buf); +static void cellbuf_free(struct cellbuf *buf); + static void update_size(void); static void update_term_size(void); static void send_attr(uint16_t fg, uint16_t bg); @@ -104,9 +119,14 @@ int tb_init(void) bytebuffer_puts(&output_buffer, funcs[T_ENTER_KEYPAD]); bytebuffer_puts(&output_buffer, funcs[T_ENTER_MOUSE]); bytebuffer_puts(&output_buffer, funcs[T_ENTER_BRACKETED_PASTE]); - bytebuffer_flush(&output_buffer, inout); + send_clear(); update_term_size(); + cellbuf_init(&back_buffer, termw, termh); + cellbuf_init(&front_buffer, termw, termh); + cellbuf_clear(&back_buffer); + cellbuf_clear(&front_buffer); + return 0; } @@ -126,6 +146,8 @@ void tb_shutdown(void) close(winch_fds[0]); close(winch_fds[1]); + cellbuf_free(&back_buffer); + cellbuf_free(&front_buffer); bytebuffer_free(&output_buffer); bytebuffer_free(&input_buffer); termw = termh = -1; @@ -136,21 +158,88 @@ int tb_is_active(void) return termw != -1; } +static void tb_repaint(bool force) { + int x,y,w,i; + struct tb_cell *back, *front; + + assert(termw != -1); + + /* invalidate cursor position */ + lastx = LAST_COORD_INIT; + lasty = LAST_COORD_INIT; + + if (buffer_size_change_request) { + update_size(); + buffer_size_change_request = 0; + } + + for (y = 0; y < front_buffer.height; ++y) { + for (x = 0; x < front_buffer.width; ) { + back = &CELL(&back_buffer, x, y); + front = &CELL(&front_buffer, x, y); + w = wcwidth(back->ch); + if (w < 1) w = 1; + if (!force && memcmp(back, front, sizeof(struct tb_cell)) == 0) { + x += w; + continue; + } + memcpy(front, back, sizeof(struct tb_cell)); + send_attr(back->fg, back->bg); + if (w > 1 && x >= front_buffer.width - (w - 1)) { + // Not enough room for wide ch, so send spaces + for (i = x; i < front_buffer.width; ++i) { + send_char(i, y, ' '); + } + } else { + send_char(x, y, back->ch); + for (i = 1; i < w; ++i) { + front = &CELL(&front_buffer, x + i, y); + front->ch = 0; + front->fg = back->fg; + front->bg = back->bg; + } + } + x += w; + } + } + if (!IS_CURSOR_HIDDEN(cursor_x, cursor_y)) + write_cursor(cursor_x, cursor_y); + bytebuffer_flush(&output_buffer, inout); +} + +void tb_present(void) +{ + tb_repaint(false); +} + +void tb_sync(void) +{ + tb_repaint(true); +} + void tb_set_cursor(int cx, int cy) { assert(termw != -1); cursor_x = cx; cursor_y = cy; - write_cursor(cursor_x, cursor_y); - bytebuffer_flush(&output_buffer, inout); + if (!IS_CURSOR_HIDDEN(cursor_x, cursor_y)) + write_cursor(cursor_x, cursor_y); } void tb_change_cell(int x, int y, uint32_t ch, uint16_t fg, uint16_t bg) { assert(termw != -1); - send_attr(fg, bg); - send_char(x, y, ch); - bytebuffer_flush(&output_buffer, inout); + if ((unsigned)x >= (unsigned)back_buffer.width) + return; + if ((unsigned)y >= (unsigned)back_buffer.height) + return; + struct tb_cell c = {ch, fg, bg}; + CELL(&back_buffer, x, y) = c; +} + +struct tb_cell *tb_cell_buffer() +{ + return back_buffer.cells; } int tb_poll_event(struct tb_event *event) @@ -187,7 +276,7 @@ void tb_clear(void) update_size(); buffer_size_change_request = 0; } - send_clear(); + cellbuf_clear(&back_buffer); } void tb_set_clear_attributes(uint16_t fg, uint16_t bg) @@ -236,6 +325,56 @@ static void write_sgr(uint16_t fg, uint16_t bg) { WRITE_LITERAL("m"); } +static void cellbuf_init(struct cellbuf *buf, int width, int height) +{ + buf->cells = (struct tb_cell*)malloc(sizeof(struct tb_cell) * width * height); + assert(buf->cells); + buf->width = width; + buf->height = height; +} + +static void cellbuf_resize(struct cellbuf *buf, int width, int height) +{ + if (buf->width == width && buf->height == height) + return; + + int oldw = buf->width; + int oldh = buf->height; + struct tb_cell *oldcells = buf->cells; + + cellbuf_init(buf, width, height); + cellbuf_clear(buf); + + int minw = (width < oldw) ? width : oldw; + int minh = (height < oldh) ? height : oldh; + int i; + + for (i = 0; i < minh; ++i) { + struct tb_cell *csrc = oldcells + (i * oldw); + struct tb_cell *cdst = buf->cells + (i * width); + memcpy(cdst, csrc, sizeof(struct tb_cell) * minw); + } + + free(oldcells); +} + +static void cellbuf_clear(struct cellbuf *buf) +{ + int i; + int ncells = buf->width * buf->height; + + for (i = 0; i < ncells; ++i) { + buf->cells[i].ch = ' '; + buf->cells[i].fg = foreground; + buf->cells[i].bg = background; + } +} + +static void cellbuf_free(struct cellbuf *buf) +{ + free(buf->cells); +} + static void get_term_size(int *w, int *h) { struct winsize sz; @@ -329,6 +468,9 @@ static void sigwinch_handler(int xxx) static void update_size(void) { update_term_size(); + cellbuf_resize(&back_buffer, termw, termh); + cellbuf_resize(&front_buffer, termw, termh); + cellbuf_clear(&front_buffer); send_clear(); } diff --git a/termbox/termbox.h b/termbox/termbox.h index 97e3f524..c6cda6e1 100644 --- a/termbox/termbox.h +++ b/termbox/termbox.h @@ -9,12 +9,18 @@ extern "C" { /*** 1. Controlling the screen. */ /* The screen is a 2D array of cells. */ +struct tb_cell { + uint32_t ch; /* unicode character */ + uint16_t fg; /* foreground color (0-255) and attributes */ + uint16_t bg; /* background color (0-255) and attributes */ +}; -/* Names for some colors. */ +/* Names for some colors in tb_cell.fg and tb_cell.bg. */ #define TB_BLACK 232 #define TB_WHITE 255 -/* Some attributes of screen cells that can be combined with colors using bitwise-OR. */ +/* Colors in tb_cell can be combined using bitwise-OR with multiple + * of the following attributes. */ #define TB_BOLD 0x0100 #define TB_UNDERLINE 0x0200 #define TB_REVERSE 0x0400 @@ -38,14 +44,34 @@ int tb_is_active(void); int tb_width(void); int tb_height(void); -/* Clear the screen. */ +/* Update the screen with internal state. Most methods below modify just the + * internal state of the screen. Changes won't be visible until you call + * tb_present(). */ +void tb_present(void); + +/* Variant of tb_present() that always refreshes the entire screen. */ +void tb_sync(void); + +/* Returns a pointer to the internal screen state: a 1D array of cells in + * raster order. You'll need to call tb_width() and tb_height() for the + * array's dimensions. The array stays valid until tb_clear() or tb_present() + * are called. */ +struct tb_cell *tb_cell_buffer(); + +/* Clear the internal screen state using either TB_DEFAULT or the + * color/attributes set by tb_set_clear_attributes(). */ void tb_clear(void); void tb_set_clear_attributes(uint16_t fg, uint16_t bg); -/* Move the cursor. Upper-left character is (0, 0). */ +/* Move the cursor. Upper-left character is (0, 0). + */ void tb_set_cursor(int cx, int cy); +/* To hide the cursor, call tb_set_cursor(TB_HIDE_CURSOR, TB_HIDE_CURSOR). + * Cursor starts out hidden. */ +#define TB_HIDE_CURSOR -1 -/* Modify a specific cell of the screen. */ +/* Modify a specific cell of the screen. Don't forget to call tb_present() to + * commit your changes. */ void tb_change_cell(int x, int y, uint32_t ch, uint16_t fg, uint16_t bg); /*** 2. Controlling keyboard events. */ |