diff --git a/example/hello.c b/example/hello.c index 6e39c11..2864034 100644 --- a/example/hello.c +++ b/example/hello.c @@ -1,7 +1,7 @@ #include "tim.h" i32 main(void) { - while (tim_run(0)) { // event loop + while (tim_run(0)) { // init state and start event loop tim_scope(A, A, 24, 8) { // centered 24x8 scope u64 c = 0x0a060f; // three colors tim_frame(0, 0, ~0, ~0, c); // draw frame for scope @@ -11,5 +11,5 @@ i32 main(void) { if (tim_is_key_press('q')) // ctrl-c is masked return 0; // exit on 'q' press } - } //TODO: remove atexit cleanup + } // atexit() cleanup } diff --git a/example/snek.c b/example/snek.c index 82cb4f9..63a86e7 100644 --- a/example/snek.c +++ b/example/snek.c @@ -33,8 +33,8 @@ static struct { static void start(void) { memset(snek.body, -1, sizeof(snek.body)); snek.len = 2; - snek.body[0] = (point){{1, tim.h / 2}}; - snek.food = (point){{tim.w / 8, tim.h / 2}}; + snek.body[0] = (point){{1, tim->h / 2}}; + snek.food = (point){{tim->w / 8, tim->h / 2}}; snek.look = (point){{1, 0}}; } @@ -53,19 +53,19 @@ static void game(void) { crash |= snek.body[0].xy == snek.body[i].xy; } // border crash - crash |= snek.body[0].x < 0 || snek.body[0].x >= tim.w / 2 || - snek.body[0].y < 0 || snek.body[0].y >= tim.h; + crash |= snek.body[0].x < 0 || snek.body[0].x >= tim->w / 2 || + snek.body[0].y < 0 || snek.body[0].y >= tim->h; snek.state = crash ? OVER : snek.state; // food if (snek.food.xy == snek.body[0].xy) { snek.len = MIN(snek.len + 2, (i32)ARRAY_SIZE(snek.body)); - snek.food.x = rand() % (tim.w / 2 - 2) + 1; - snek.food.y = rand() % (tim.h - 2) + 1; + snek.food.x = rand() % (tim->w / 2 - 2) + 1; + snek.food.y = rand() % (tim->h - 2) + 1; } } // draw - if (tim.event.type == TimEvent_Draw) { + if (tim->event.type == TimEvent_Draw) { // food tim_draw_chr(tim_cell(" ", 0, 0xc5), snek.food.x * 2 + 0, snek.food.y); tim_draw_chr(tim_cell(" ", 0, 0xc5), snek.food.x * 2 + 1, snek.food.y); @@ -81,8 +81,8 @@ static void game(void) { } // user input - if (tim.event.type == KEY_EVENT) { - i32 key = tim.event.key; + if (tim->event.type == KEY_EVENT) { + i32 key = tim->event.key; if ((key == TimKey_Right || key == 'd') && snek.look.x != -1) { snek.look = (point){{1, 0}}; } else if ((key == TimKey_Left || key == 'a') && snek.look.x != 1) { @@ -119,7 +119,7 @@ i32 main(void) { // draw every 10 ms while (tim_run(60)) { TimCell bg = tim_cell(" ", 0, BG); - tim_draw_lot(bg, 0, 0, tim.w, tim.h); + tim_draw_lot(bg, 0, 0, tim->w, tim->h); if (snek.state == RUN) { game(); diff --git a/include/tim.h b/include/tim.h index cb30f77..dcc7ea5 100644 --- a/include/tim.h +++ b/include/tim.h @@ -181,8 +181,8 @@ typedef struct TimState { #pragma region general -// TODO: remove global variables -extern TimState tim; +// global statem initialized by tim_run() +extern TimState* tim; bool tim_run(f32 fps); @@ -343,8 +343,6 @@ void tim_init_terminal(void); void tim_read_event(i32 timeout_ms); -void tim_render(void); - #pragma endregion diff --git a/readme.md b/readme.md index 83c8bb7..359729b 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,6 @@ ## about -tim.h is a portable library to create simple terminal applications +tim->h is a portable library to create simple terminal applications Demo video: https://asciinema.org/a/zn3p0dsVCOQOzwY1S9gDfyaxQ ## quick start @@ -66,7 +66,7 @@ immediately followed by a draw event in order to make changes visible. Some elements need to consume events, for example edit consumes the key event when focused in order to prevent other key handlers on acting on them. -The current event is stored in tim.event. +The current event is stored in tim->event. event | cause -------------|----------------------- diff --git a/src/drawing.c b/src/drawing.c index cdd3e9f..a6f03b2 100755 --- a/src/drawing.c +++ b/src/drawing.c @@ -10,52 +10,52 @@ TimCell tim_cell(cstr s, u8 fg, u8 bg) { } void tim_clear_cells(void) { - size_t size = sizeof(tim.cells[0]) * tim.w * tim.h; - memset(tim.cells, 0, size); + size_t size = sizeof(tim->cells[0]) * tim->w * tim->h; + memset(tim->cells, 0, size); } void tim_draw_chr(TimCell cell, i32 x, i32 y) { - if (x >= 0 && x < tim.w && y >= 0 && y < tim.h) { - tim.cells[x + y * tim.w] = cell; + if (x >= 0 && x < tim->w && y >= 0 && y < tim->h) { + tim->cells[x + y * tim->w] = cell; } } void tim_draw_row(TimCell cell, i32 x, i32 y, i32 w) { - if (y >= 0 && y < tim.h && w > 0) { - for (i32 i = MAX(x, 0); i < MIN(x + w, tim.w); i++) { - tim.cells[i + y * tim.w] = cell; + if (y >= 0 && y < tim->h && w > 0) { + for (i32 i = MAX(x, 0); i < MIN(x + w, tim->w); i++) { + tim->cells[i + y * tim->w] = cell; } } } void tim_draw_col(TimCell cell, i32 x, i32 y, i32 h) { - if (x >= 0 && x < tim.w && h > 0) { - for (i32 i = MAX(y, 0); i < MIN(y + h, tim.h); i++) { - tim.cells[x + i * tim.w] = cell; + if (x >= 0 && x < tim->w && h > 0) { + for (i32 i = MAX(y, 0); i < MIN(y + h, tim->h); i++) { + tim->cells[x + i * tim->w] = cell; } } } void tim_draw_lot(TimCell cell, i32 x, i32 y, i32 w, i32 h) { if (w > 0 && h > 0) { - for (i32 iy = MAX(y, 0); iy < MIN(y + h, tim.h); iy++) { - for (i32 ix = MAX(x, 0); ix < MIN(x + w, tim.w); ix++) { - tim.cells[ix + iy * tim.w] = cell; + for (i32 iy = MAX(y, 0); iy < MIN(y + h, tim->h); iy++) { + for (i32 ix = MAX(x, 0); ix < MIN(x + w, tim->w); ix++) { + tim->cells[ix + iy * tim->w] = cell; } } } } void tim_draw_str(cstr s, i32 x, i32 y, i32 w, u8 fg, u8 bg) { - if (s && y >= 0 && x < tim.w && y < tim.h ) { - i32 end = MIN(x + w, tim.w); + if (s && y >= 0 && x < tim->w && y < tim->h ) { + i32 end = MIN(x + w, tim->w); bool wide = false; for (i32 i = 0; s[i] && x < end; x++) { TimCell c = tim_cell(&s[i], fg, bg); wide = wide || tim_utf8_is_wide_perhaps(c.buf, c.n); if (x >= 0) { c.wide = wide; - tim.cells[x + y * tim.w] = c; + tim->cells[x + y * tim->w] = c; } i += c.n; } @@ -75,11 +75,11 @@ void tim_draw_box(i32 x, i32 y, i32 w, i32 h, u8 fg, u8 bg) { } void tim_draw_invert(i32 x, i32 y, i32 w) { - if (y >= 0 && y < tim.h && w > 0) { - for (i32 i = MAX(x, 0); i < MIN(x + w, tim.w); i++) { - TimCell c = tim.cells[i + y * tim.w]; - tim.cells[i + y * tim.w].fg = c.bg; - tim.cells[i + y * tim.w].bg = c.fg; + if (y >= 0 && y < tim->h && w > 0) { + for (i32 i = MAX(x, 0); i < MIN(x + w, tim->w); i++) { + TimCell c = tim->cells[i + y * tim->w]; + tim->cells[i + y * tim->w].fg = c.bg; + tim->cells[i + y * tim->w].bg = c.fg; } } } diff --git a/src/edit.c b/src/edit.c index a4bd62e..00a3407 100755 --- a/src/edit.c +++ b/src/edit.c @@ -39,20 +39,20 @@ void edit_delete(TimEditState* e) { static i32 edit_event(TimEditState* e, TimRect r) { if (tim_is_mouse_click_over(r)) { // take focus - tim.focus = e; + tim->focus = e; return 0; } - if (tim.focus != e || tim.event.type != TimEvent_Key) { + if (tim->focus != e || tim->event.type != TimEvent_Key) { // not focused or no key press return 0; } - tim.event.type = TimEvent_Void; // consume event + tim->event.type = TimEvent_Void; // consume event - switch (tim.event.key) { + switch (tim->event.key) { case TimKey_Escape: case TimKey_Enter: - tim.focus = 0; // release focus + tim->focus = 0; // release focus break; case TimKey_Delete: edit_delete(e); @@ -76,21 +76,21 @@ static i32 edit_event(TimEditState* e, TimRect r) { e->cursor = e->length; break; default: - if (tim.event.key >= ' ') { - edit_insert(e, tim.event.s); + if (tim->event.key >= ' ') { + edit_insert(e, tim->event.s); } break; } - return tim.event.key; + return tim->event.key; } i32 edit(TimEditState* e, i32 x, i32 y, i32 w, u64 color) { TimRect r = tim_scope_rect_to_absolute(x, y, w, 3); - if (tim.event.type == TimEvent_Draw) { + if (tim->event.type == TimEvent_Draw) { tim_draw_box(r.x, r.y, r.w, r.h, color >> 16, color >> 8); - if (tim.focus == e) { + if (tim->focus == e) { char* s = e->s + tim_utf8_pos(e->s, e->cursor - r.w + 4); i32 cur = MIN(r.w - 4, e->cursor); tim_draw_str(s, r.x + 2, r.y + 1, r.w - 3, color, color >> 8); diff --git a/src/event.c b/src/event.c index dae1506..7804edf 100755 --- a/src/event.c +++ b/src/event.c @@ -1,7 +1,7 @@ #include "tim.h" bool tim_is_event_key(TimEventType type, TimKey key) { - return tim.event.type == type && tim.event.key == key; + return tim->event.type == type && tim->event.key == key; } bool tim_is_key_press(TimKey key) { @@ -9,8 +9,8 @@ bool tim_is_key_press(TimKey key) { } bool tim_is_mouse_over(TimRect r) { - i32 x = tim.event.x; - i32 y = tim.event.y; + i32 x = tim->event.x; + i32 y = tim->event.y; return x >= r.x && x < r.x + r.w && y >= r.y && y < r.y + r.h; } diff --git a/src/loop.c b/src/loop.c index 3ea04e3..5b5ee2a 100755 --- a/src/loop.c +++ b/src/loop.c @@ -1,19 +1,37 @@ #include "tim.h" -// TODO: remove global variables -static TimCell _tim_cells[TIM_MAX_CELLS << TIM_ENABLE_DBUF]; -static char _tim_buf[TIM_MAX_BUF]; -TimState tim = { - .cells = _tim_cells, - .cells_double_buf = _tim_cells, - .buf = _tim_buf, -}; +static void tim_render(void); + +TimState* tim = NULL; + +static void tim_init(void){ + tim = (TimState*)malloc(sizeof(TimState)); + memset(tim, 0, sizeof(TimState)); + size_t cdb_size = (TIM_MAX_CELLS << TIM_ENABLE_DBUF); + tim->cells_double_buf = (TimCell*)malloc(cdb_size * sizeof(TimCell)); + tim->cells = tim->cells_double_buf; + tim->buf = (char*)malloc(TIM_MAX_BUF); +} + +static void tim_deinit(void){ + if(!tim) + return; + free(tim->cells_double_buf); + free(tim->buf); + free(tim); + tim = NULL; +} bool tim_run(f32 fps) { + if(tim == NULL){ + tim_init(); + atexit(tim_deinit); + } + i32 timeout = (fps > 0) ? (i32)(1000 / fps) : 0; while (true) { - switch (tim.loop_stage) { + switch (tim->loop_stage) { case 0: // runs only once tim_init_terminal(); @@ -21,31 +39,144 @@ bool tim_run(f32 fps) { // fallthru case 1: // process input event - tim.start_us = tim_time_usec(); - if (tim.event.type != TimEvent_Draw) { + tim->start_us = tim_time_usec(); + if (tim->event.type != TimEvent_Draw) { // reset focus on mouse click if (tim_is_event_key(TimEvent_Mouse, TimKey_MouseButtonLeft)) { - tim.focus = 0; + tim->focus = 0; } - tim.loop_stage = 2; + tim->loop_stage = 2; return true; } // fallthru case 2: // process draw event tim_clear_cells(); - tim.event.type = TimEvent_Draw; - tim.loop_stage = 3; + tim->event.type = TimEvent_Draw; + tim->loop_stage = 3; return true; case 3: // render screen and wait for next event tim_render(); - tim.render_us = tim_time_usec() - tim.start_us; + tim->render_us = tim_time_usec() - tim->start_us; tim_read_event(timeout); // blocks // fallthru default: - tim.loop_stage = 1; + tim->loop_stage = 1; break; } } // while } + +// write character to output buffer +static void tim_put_chr(char c) { + if (tim->buf_size + 1 < TIM_MAX_BUF) { + tim->buf[tim->buf_size] = c; + tim->buf_size += 1; + } +} + +// write string to output buffer +static void tim_put_str(cstr s, i32 size) { + if (size > 0 && tim->buf_size + size < TIM_MAX_BUF) { + memmove(&tim->buf[tim->buf_size], s, size); + tim->buf_size += size; + } +} + +// write integer as decimal string to output buffer +static void tim_put_int(i32 i) { + // optimized for small positive values, reduces load by a third + char* buf = &tim->buf[tim->buf_size]; + if (tim->buf_size + 11 >= TIM_MAX_BUF) { + // not enough space for 32 bit integer + } else if ((u32)i < 10) { + buf[0] = '0' + i; + tim->buf_size += 1; + } else if ((u32)i < 100) { + buf[0] = '0' + i / 10; + buf[1] = '0' + i % 10; + tim->buf_size += 2; + } else if ((u32)i < 1000) { + buf[0] = '0' + i / 100; + buf[1] = '0' + (i / 10) % 10; + buf[2] = '0' + i % 10; + tim->buf_size += 3; + } else { + tim->buf_size += sprintf(buf, "%d", i); + } +} + +static void tim_render(void) { + i32 fg = -1; + i32 bg = -1; + bool wide = false; + bool skip = false; + + // screen buffers + TimCell* new_cells = tim->cells_double_buf; + TimCell* old_cells = tim->cells_double_buf; +#if TIM_ENABLE_DBUF + new_cells += (tim->frame & 1) ? TIM_MAX_CELLS : 0; + old_cells += (tim->frame & 1) ? 0 : TIM_MAX_CELLS; +#endif + tim->buf_size = 0; + + for (i32 i = 0; i < tim->w * tim->h; i++) { + TimCell c = new_cells[i]; +#if TIM_ENABLE_DBUF + // do nothing if cells in look-ahead are identical + const i32 la = 8; // look-ahead + if (!tim->resized && !(i % la) && (i + la < TIM_MAX_CELLS) && + !memcmp(new_cells + i, old_cells + i, la * sizeof(c))) { + skip = true; + i = i + la - 1; + continue; + } +#endif + // Set cursor position after a new line, after a string containing wide + // characters or after skipping identical cells. + bool new_line = i % tim->w == 0; + bool wide_spill = wide && (c.n == 0 || c.buf[0] == ' '); + bool wide_flank = wide && !wide_spill && !c.wide; + if (new_line || wide_flank || skip) { + tim_put_str(S("\33[")); + tim_put_int((i / tim->w) + 1); + tim_put_chr(';'); + tim_put_int((i % tim->w) + 1); + tim_put_chr('H'); + } + wide = c.wide || wide_spill; + skip = false; + + // change foreground color + if (c.fg != fg) { + fg = c.fg; + tim_put_str(S("\33[38;5;")); + tim_put_int(fg); + tim_put_chr('m'); + } + + // change background color + if (c.bg != bg) { + bg = c.bg; + tim_put_str(S("\33[48;5;")); + tim_put_int(bg); + tim_put_chr('m'); + } + + // write character + if (c.n) { + tim_put_str((char*)c.buf, c.n); + } else { + tim_put_chr(' '); + } + } + + // duration depends on connection and terminal rendering speed + tim_write_str(tim->buf, tim->buf_size); + + tim->resized = false; + tim->frame += 1; // frame counter + tim->cells = old_cells; // swap buffer +} diff --git a/src/render.c b/src/render.c deleted file mode 100755 index 0f34fd9..0000000 --- a/src/render.c +++ /dev/null @@ -1,114 +0,0 @@ -#include "tim.h" - -// write character to output buffer -static void tim_put_chr(char c) { - if (tim.buf_size + 1 < TIM_MAX_BUF) { - tim.buf[tim.buf_size] = c; - tim.buf_size += 1; - } -} - -// write string to output buffer -static void tim_put_str(cstr s, i32 size) { - if (size > 0 && tim.buf_size + size < TIM_MAX_BUF) { - memmove(&tim.buf[tim.buf_size], s, size); - tim.buf_size += size; - } -} - -// write integer as decimal string to output buffer -static void tim_put_int(i32 i) { - // optimized for small positive values, reduces load by a third - char* buf = &tim.buf[tim.buf_size]; - if (tim.buf_size + 11 >= TIM_MAX_BUF) { - // not enough space for 32 bit integer - } else if ((u32)i < 10) { - buf[0] = '0' + i; - tim.buf_size += 1; - } else if ((u32)i < 100) { - buf[0] = '0' + i / 10; - buf[1] = '0' + i % 10; - tim.buf_size += 2; - } else if ((u32)i < 1000) { - buf[0] = '0' + i / 100; - buf[1] = '0' + (i / 10) % 10; - buf[2] = '0' + i % 10; - tim.buf_size += 3; - } else { - tim.buf_size += sprintf(buf, "%d", i); - } -} - -void tim_render(void) { - i32 fg = -1; - i32 bg = -1; - bool wide = false; - bool skip = false; - - // screen buffers - TimCell* new_cells = tim.cells_double_buf; - TimCell* old_cells = tim.cells_double_buf; -#if TIM_ENABLE_DBUF - new_cells += (tim.frame & 1) ? TIM_MAX_CELLS : 0; - old_cells += (tim.frame & 1) ? 0 : TIM_MAX_CELLS; -#endif - tim.buf_size = 0; - - for (i32 i = 0; i < tim.w * tim.h; i++) { - TimCell c = new_cells[i]; -#if TIM_ENABLE_DBUF - // do nothing if cells in look-ahead are identical - const i32 la = 8; // look-ahead - if (!tim.resized && !(i % la) && (i + la < TIM_MAX_CELLS) && - !memcmp(new_cells + i, old_cells + i, la * sizeof(c))) { - skip = true; - i = i + la - 1; - continue; - } -#endif - // Set cursor position after a new line, after a string containing wide - // characters or after skipping identical cells. - bool new_line = i % tim.w == 0; - bool wide_spill = wide && (c.n == 0 || c.buf[0] == ' '); - bool wide_flank = wide && !wide_spill && !c.wide; - if (new_line || wide_flank || skip) { - tim_put_str(S("\33[")); - tim_put_int((i / tim.w) + 1); - tim_put_chr(';'); - tim_put_int((i % tim.w) + 1); - tim_put_chr('H'); - } - wide = c.wide || wide_spill; - skip = false; - - // change foreground color - if (c.fg != fg) { - fg = c.fg; - tim_put_str(S("\33[38;5;")); - tim_put_int(fg); - tim_put_chr('m'); - } - - // change background color - if (c.bg != bg) { - bg = c.bg; - tim_put_str(S("\33[48;5;")); - tim_put_int(bg); - tim_put_chr('m'); - } - - // write character - if (c.n) { - tim_put_str((char*)c.buf, c.n); - } else { - tim_put_chr(' '); - } - } - - // duration depends on connection and terminal rendering speed - tim_write_str(tim.buf, tim.buf_size); - - tim.resized = false; - tim.frame += 1; // frame counter - tim.cells = old_cells; // swap buffer -} diff --git a/src/scope.c b/src/scope.c index c954991..05da233 100755 --- a/src/scope.c +++ b/src/scope.c @@ -1,7 +1,7 @@ #include "tim.h" TimRect tim_scope_rect_to_absolute(i32 x, i32 y, i32 w, i32 h) { - TimRect p = tim.scopes[tim.scope]; // parent scope + TimRect p = tim->scopes[tim->scope]; // parent scope x = (x == A && w == A) ? 0 : x; // special cases y = (y == A && h == A) ? 0 : y; // @@ -35,16 +35,16 @@ TimRect tim_scope_rect_to_absolute(i32 x, i32 y, i32 w, i32 h) { } i32 tim_enter_scope(i32 x, i32 y, i32 w, i32 h) { - if (tim.scope + 1 >= TIM_MAX_SCOPE) { + if (tim->scope + 1 >= TIM_MAX_SCOPE) { return 0; } TimRect r = tim_scope_rect_to_absolute(x, y, w, h); - tim.scope += 1; - tim.scopes[tim.scope] = r; + tim->scope += 1; + tim->scopes[tim->scope] = r; return 1; } i32 tim_exit_scope(void) { - tim.scope -= (tim.scope > 0); + tim->scope -= (tim->scope > 0); return 0; } diff --git a/src/unix.c b/src/unix.c index 1e0ccc3..acfcd3c 100755 --- a/src/unix.c +++ b/src/unix.c @@ -15,7 +15,7 @@ void tim_write_str(cstr s, i32 size) { void signal_handler(i32 signal) { // signals are written into a fifo pipe and read by event loop - ssize_t _ = write(tim.signal_pipe[1], &signal, sizeof(signal)); + ssize_t _ = write(tim->signal_pipe[1], &signal, sizeof(signal)); (void)_; // remove unused-result warning } @@ -27,16 +27,16 @@ void tim_update_screen_size(void) { } i32 w = ws.ws_col; i32 h = ws.ws_row; - tim.resized = (u32)(w * h) <= TIM_MAX_CELLS && (w != tim.w || h != tim.h); - if (tim.resized) { - tim.w = tim.scopes[0].w = w; - tim.h = tim.scopes[0].h = h; + tim->resized = (u32)(w * h) <= TIM_MAX_CELLS && (w != tim->w || h != tim->h); + if (tim->resized) { + tim->w = tim->scopes[0].w = w; + tim->h = tim->scopes[0].h = h; } } void tim_init_terminal(void) { - tcgetattr(STDOUT_FILENO, &tim.attr); // store attributes - struct termios attr = tim.attr; // + tcgetattr(STDOUT_FILENO, &tim->attr); // store attributes + struct termios attr = tim->attr; // cfmakeraw(&attr); // configure raw mode tcsetattr(STDOUT_FILENO, TCSADRAIN, &attr); // set new attributes tim_write_str(S("\33[?2004l")); // reset bracketed paste mode @@ -46,14 +46,14 @@ void tim_init_terminal(void) { tim_write_str(S("\33[?1002h")); // enable button events tim_write_str(S("\33[?1006h")); // use mouse sgr protocol tim_update_screen_size(); // get terminal size - i32 err = pipe(tim.signal_pipe); // create signal pipe + i32 err = pipe(tim->signal_pipe); // create signal pipe if (!err) { // signal(SIGWINCH, signal_handler); // terminal size changed } } void tim_reset_terminal(void) { - tcsetattr(STDOUT_FILENO, TCSADRAIN, &tim.attr); // restore attributes + tcsetattr(STDOUT_FILENO, TCSADRAIN, &tim->attr); // restore attributes tim_write_str(S("\33[?1000l")); // disable mouse tim_write_str(S("\33[?1002l")); // disable mouse tim_write_str(S("\33[m")); // reset colors @@ -120,10 +120,10 @@ bool parse_input(event* restrict e, i32 n) { } void tim_read_event(i32 timeout_ms) { - event* e = &tim.event; + event* e = &tim->event; struct pollfd pfd[2] = { - {.fd = tim.signal_pipe[0], .events = POLLIN}, + {.fd = tim->signal_pipe[0], .events = POLLIN}, {.fd = STDIN_FILENO, .events = POLLIN}, }; @@ -143,7 +143,7 @@ void tim_read_event(i32 timeout_ms) { if (pfd[0].revents & POLLIN) { // received signal i32 sig = 0; - i32 n = read(tim.signal_pipe[0], &sig, sizeof(sig)); + i32 n = read(tim->signal_pipe[0], &sig, sizeof(sig)); if (n > 0 && sig == SIGWINCH) { // screen size changed e->type = TimEvent_Draw; diff --git a/src/widgets.c b/src/widgets.c index d114b86..69f6b01 100755 --- a/src/widgets.c +++ b/src/widgets.c @@ -1,14 +1,14 @@ #include "tim.h" void tim_frame(i32 x, i32 y, i32 w, i32 h, u64 color) { - if (tim.event.type == TimEvent_Draw) { + if (tim->event.type == TimEvent_Draw) { TimRect r = tim_scope_rect_to_absolute(x, y, w, h); tim_draw_box(r.x, r.y, r.w, r.h, color, color >> 8); } } void label(cstr s, i32 x, i32 y, i32 w, i32 h, u64 color) { - if (tim.event.type == TimEvent_Draw) { + if (tim->event.type == TimEvent_Draw) { TimText t = tim_scan_str(s); w = (w == A) ? t.width : w; h = (h == A) ? t.lines : h; @@ -28,7 +28,7 @@ bool button(cstr txt, i32 x, i32 y, i32 w, i32 h, u64 color) { h = (h == A) ? 3 : h; TimRect r = tim_scope_rect_to_absolute(x, y, w, h); - if (tim.event.type == TimEvent_Draw) { + if (tim->event.type == TimEvent_Draw) { tim_draw_box(r.x, r.y, r.w, r.h, color >> 16, color >> 8); tim_draw_str(txt, r.x + (w - tw) / 2, r.y + h / 2, w, color, color >> 8); } @@ -39,7 +39,7 @@ bool check(cstr txt, i32* state, i32 x, i32 y, i32 w, u64 color) { w = (w == A) ? tim_utf8_len(txt) + 4 : w; TimRect r = tim_scope_rect_to_absolute(x, y, w, 1); - if (tim.event.type == TimEvent_Draw) { + if (tim->event.type == TimEvent_Draw) { cstr st = *state == -1 ? "-" : *state ? "x" : " "; tim_draw_str("[ ] ", r.x, r.y, 4, color, color >> 8); tim_draw_str(st, r.x + 1, r.y, 1, color >> 16, color >> 8); @@ -56,7 +56,7 @@ bool radio(cstr txt, i32* state, i32 v, i32 x, i32 y, i32 w, u64 color) { w = (w == A) ? tim_utf8_len(txt) + 4 : w; TimRect r = tim_scope_rect_to_absolute(x, y, w, 1); - if (tim.event.type == TimEvent_Draw) { + if (tim->event.type == TimEvent_Draw) { cstr st = *state == v ? "o" : " "; tim_draw_str("( ) ", r.x, r.y, 4, color, color >> 8); tim_draw_str(st, r.x + 1, r.y, 1, color >> 16, color >> 8); diff --git a/src/windows.c b/src/windows.c index 2d4ad91..b7d98b0 100755 --- a/src/windows.c +++ b/src/windows.c @@ -25,19 +25,19 @@ void tim_update_screen_size(void) { } i32 w = csbi.srWindow.Right - csbi.srWindow.Left + 1; i32 h = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; - tim.resized = (u32)(w * h) <= TIM_MAX_CELLS && (w != tim.w || h != tim.h); - if (tim.resized) { - tim.w = tim.scopes[0].w = w; - tim.h = tim.scopes[0].h = h; - tim.window = csbi.srWindow; + tim->resized = (u32)(w * h) <= TIM_MAX_CELLS && (w != tim->w || h != tim->h); + if (tim->resized) { + tim->w = tim->scopes[0].w = w; + tim->h = tim->scopes[0].h = h; + tim->window = csbi.srWindow; } } void tim_init_terminal(void) { DWORD mode = 0; HANDLE hin = GetStdHandle(STD_INPUT_HANDLE); - GetConsoleMode(hin, &tim.mode_in); // get current input mode - mode = tim.mode_in; // + GetConsoleMode(hin, &tim->mode_in); // get current input mode + mode = tim->mode_in; // mode &= ~ENABLE_ECHO_INPUT; // disable echo mode &= ~ENABLE_LINE_INPUT; // disable line buffer // TODO: enable ctrl-c again @@ -49,14 +49,14 @@ void tim_init_terminal(void) { SetConsoleMode(hin, mode); // set input mode // HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE); // - GetConsoleMode(hout, &tim.mode_out); // get current output mode - mode = tim.mode_out; // + GetConsoleMode(hout, &tim->mode_out); // get current output mode + mode = tim->mode_out; // mode |= ENABLE_PROCESSED_OUTPUT; // enable ascii sequences mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; // enable vt sequences SetConsoleMode(hout, mode); // set output mode // - tim.cp_in = GetConsoleCP(); // get current code page - tim.cp_out = GetConsoleOutputCP(); // + tim->cp_in = GetConsoleCP(); // get current code page + tim->cp_out = GetConsoleOutputCP(); // SetConsoleCP(CP_UTF8); // set utf8 in/out code page SetConsoleOutputCP(CP_UTF8); // tim_write_str(S("\33[?1049h")); // use alternate buffer @@ -69,14 +69,14 @@ void tim_reset_terminal(void) { tim_write_str(S("\33[?1049l")); // exit alternate buffer HANDLE hin = GetStdHandle(STD_INPUT_HANDLE); // HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE); // - SetConsoleMode(hin, tim.mode_in); // set original mode - SetConsoleMode(hout, tim.mode_out); // - SetConsoleCP(tim.cp_in); // set original code page - SetConsoleOutputCP(tim.cp_out); // + SetConsoleMode(hin, tim->mode_in); // set original mode + SetConsoleMode(hout, tim->mode_out); // + SetConsoleCP(tim->cp_in); // set original code page + SetConsoleOutputCP(tim->cp_out); // } void tim_read_event(i32 timeout_ms) { - TimEvent* e = &tim.event; + TimEvent* e = &tim->event; HANDLE h = GetStdHandle(STD_INPUT_HANDLE); const i8 key_table[256] = { @@ -150,8 +150,8 @@ void tim_read_event(i32 timeout_ms) { tim_update_screen_size(); // workaround, see WINDOW_BUFFER_SIZE_EVENT e->type = TimEvent_Mouse; e->key = TimKey_MouseButtonLeft; - e->x = rec.Event.MouseEvent.dwMousePosition.X - tim.window.Left; - e->y = rec.Event.MouseEvent.dwMousePosition.Y - tim.window.Top; + e->x = rec.Event.MouseEvent.dwMousePosition.X - tim->window.Left; + e->y = rec.Event.MouseEvent.dwMousePosition.Y - tim->window.Top; return; } diff --git a/test/test.c b/test/test.c index d6bc636..f03350f 100644 --- a/test/test.c +++ b/test/test.c @@ -21,9 +21,9 @@ static inline void test_screen(TimEvent* e) { label("|", A, ~0, A, A, 0xf); // some information - sprintf(buf, "screen: %dx%d", tim.w, tim.h); + sprintf(buf, "screen: %dx%d", tim->w, tim->h); label(buf, 2, 0, A, A, 0xf); - sprintf(buf, "frame : [%c] %d", ": "[tim.frame & 1], tim.frame); + sprintf(buf, "frame : [%c] %d", ": "[tim->frame & 1], tim->frame); label(buf, 2, 1, A, A, 0xf); sprintf(buf, "key : [%d] %s", ke.key, ke.s + (ke.key < 32)); label(buf, 2, 2, A, A, 0xf); @@ -34,12 +34,12 @@ static inline void test_screen(TimEvent* e) { label(buf, 2, 4, A, A, 0xf); // lower right - render_us += tim.render_us; - sprintf(buf, "%d µs (Ø %d µs)", tim.render_us, render_us / MAX(tim.frame, 1)); + render_us += tim->render_us; + sprintf(buf, "%d µs (Ø %d µs)", tim->render_us, render_us / MAX(tim->frame, 1)); label(buf, ~2, ~2, A, A, 0xf); - sprintf(buf, "%d cells (%.0f %%)", tim.w * tim.h, 100.0 * tim.w * tim.h / TIM_MAX_CELLS); + sprintf(buf, "%d cells (%.0f %%)", tim->w * tim->h, 100.0 * tim->w * tim->h / TIM_MAX_CELLS); label(buf, ~2, ~1, A, A, 0xf); - sprintf(buf, "%d bytes (%.0f %%)", tim.buf_size, 100.0 * tim.buf_size / TIM_MAX_BUF); + sprintf(buf, "%d bytes (%.0f %%)", tim->buf_size, 100.0 * tim->buf_size / TIM_MAX_BUF); label(buf, ~2, ~0, A, A, 0xf); // multi line label @@ -112,7 +112,7 @@ static inline void test_screen(TimEvent* e) { i32 main(void) { while (tim_run(1.5)) { - test_screen(&tim.event); + test_screen(&tim->event); if (tim_is_key_press('q') || tim_is_key_press(TimKey_Escape)) { break; }