From fb7ecf3d1c3493377c317e207d237b829102ba56 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Sun, 16 May 2021 18:49:54 -0700 Subject: [PATCH] Added mode setting (TUI mode vs normal mode) --- C/test.c | 2 +- Lua/lbtui.c | 25 +++++++++++++++++++++++-- Python/btui.py | 25 ++++++++++++++++++++----- README.md | 3 ++- btui.h | 51 ++++++++++++++++++++++++++++++++++++++------------ 5 files changed, 85 insertions(+), 21 deletions(-) diff --git a/C/test.c b/C/test.c index 0e79e51..d4d14da 100644 --- a/C/test.c +++ b/C/test.c @@ -7,7 +7,7 @@ int main(void) { - btui_t *bt = btui_enable(); + btui_t *bt = btui_create(BTUI_MODE_TUI); if (!bt) return 1; int done = 0; int x = 1, y = 1; diff --git a/Lua/lbtui.c b/Lua/lbtui.c index 46dcd67..53588e0 100644 --- a/Lua/lbtui.c +++ b/Lua/lbtui.c @@ -23,7 +23,13 @@ static int Lbtui_enable(lua_State *L) { btui_t **bt = (btui_t**)lua_touserdata(L, 1); if (bt == NULL) luaL_error(L, "Not a BTUI object"); - *bt = btui_enable(); + const char *modestring = luaL_optlstring(L, 2, "TUI", NULL); + btui_mode_t mode = BTUI_MODE_TUI; + if (strcmp(modestring, "normal") == 0) + mode = BTUI_MODE_NORMAL; + else if (strcmp(modestring, "TUI") != 0) + luaL_error(L, "Invalid BTUI mode"); + *bt = btui_create(mode); btui_move_cursor(*bt, 0, 0); btui_flush(*bt); return 0; @@ -183,6 +189,20 @@ static int Lbtui_setcursor(lua_State *L) return 0; } +static int Lbtui_setmode(lua_State *L) +{ + btui_t **bt = (btui_t**)lua_touserdata(L, 1); + if (bt == NULL) luaL_error(L, "Not a BTUI object"); + const char *modestring = luaL_checkstring(L, 2); + btui_mode_t mode = BTUI_MODE_TUI; + if (strcmp(modestring, "normal") == 0) + mode = BTUI_MODE_NORMAL; + else if (strcmp(modestring, "TUI") != 0) + luaL_error(L, "Invalid BTUI mode"); + btui_set_mode(*bt, mode); + return 0; +} + static int Lbtui_withfg(lua_State *L) { btui_t **bt = (btui_t**)lua_touserdata(L, 1); @@ -372,7 +392,7 @@ static int Lbtui_wrap(lua_State *L) lua_pushlightuserdata(L, (void*)&BTUI_METATABLE); lua_gettable(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); - *bt = btui_enable(); + *bt = btui_create(BTUI_MODE_TUI); btui_move_cursor(*bt, 0, 0); btui_flush(*bt); int status = lua_pcall(L, 1, 0, 0); @@ -495,6 +515,7 @@ static const luaL_Reg Rclass_metamethods[] = {"scroll", Lbtui_scroll}, {"setattributes", Lbtui_setattributes}, {"setcursor", Lbtui_setcursor}, + {"setmode", Lbtui_setmode}, {"shadow", Lbtui_shadow}, {"showcursor", Lbtui_showcursor}, {"suspend", Lbtui_suspend}, diff --git a/Python/btui.py b/Python/btui.py index a96c7b9..b518522 100644 --- a/Python/btui.py +++ b/Python/btui.py @@ -20,7 +20,9 @@ class BTUI_struct(ctypes.Structure): ('size_changed', ctypes.c_int), ] -libbtui.btui_enable.restype = ctypes.POINTER(BTUI_struct) +libbtui.btui_create.restype = ctypes.POINTER(BTUI_struct) + +BTUI_MODE_UNINITIALIZED, BTUI_MODE_NORMAL, BTUI_MODE_TUI = 0, 1, 2 attr = lambda name: ctypes.c_longlong.in_dll(libbtui, name) attr_t = ctypes.c_longlong @@ -141,8 +143,21 @@ class BTUI: libbtui.btui_draw_shadow(self._btui, int(x), int(y), int(w), int(h)) libbtui.btui_flush(self._btui) - def enable(self): - self._btui = libbtui.btui_enable() + def enable(self, mode='TUI'): + if mode == 'TUI': + mode = BTUI_MODE_TUI + elif mode == 'normal': + mode = BTUI_MODE_NORMAL + else: raise ArgumentError("Invalid mode: "+str(mode)) + self._btui = libbtui.btui_create(mode) + + def set_mode(self, mode): + if mode == 'TUI': + mode = BTUI_MODE_TUI + elif mode == 'normal': + mode = BTUI_MODE_NORMAL + else: raise ArgumentError("Invalid mode: "+str(mode)) + self._btui = libbtui.set_mode(self._btui, mode) @contextmanager def fg(self, r, g, b): @@ -274,7 +289,7 @@ for fn_name in ('clear', 'draw_shadow', 'fill_box', 'move', 'set_cursor', 'hide_ _btui = None @contextmanager -def open_btui(*, debug=False, delay=0.05): +def open_btui(*, debug=False, delay=0.05, mode='TUI'): global _btui if not _btui: if debug: @@ -282,7 +297,7 @@ def open_btui(*, debug=False, delay=0.05): _btui.delay = delay else: _btui = BTUI() - _btui.enable() + _btui.enable(mode=mode) _btui.move(0, 0) try: yield _btui finally: _btui.disable() diff --git a/README.md b/README.md index b239d2a..f78fb3a 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,8 @@ int btui_clear(btui_t *bt, int mode); void btui_disable(btui_t *bt); void btui_draw_linebox(btui_t *bt, int x, int y, int w, int h); void btui_draw_shadow(btui_t *bt, int x, int y, int w, int h); -btui_t* btui_enable(void); +btui_t* btui_create(btui_mode_t mode); +#define btui_enable() btui_create(BTUI_MODE_TUI) void btui_fill_box(btui_t *bt, int x, int y, int w, int h); int btui_flush(btui_t *bt); int btui_getkey(btui_t *bt, int timeout, int *mouse_x, int *mouse_y); diff --git a/btui.h b/btui.h index 324660e..d9d16b5 100644 --- a/btui.h +++ b/btui.h @@ -29,8 +29,6 @@ #define T_ALT_SCREEN "1049" #define T_ON(opt) "\033[?" opt "h" #define T_OFF(opt) "\033[?" opt "l" -#define BTUI_ENTER T_OFF(T_SHOW_CURSOR ";" T_WRAP) T_ON(T_ALT_SCREEN ";" T_MOUSE_XY ";" T_MOUSE_CELL ";" T_MOUSE_SGR) -#define BTUI_LEAVE T_ON(T_SHOW_CURSOR ";" T_WRAP) T_OFF(T_ALT_SCREEN ";" T_MOUSE_XY ";" T_MOUSE_CELL ";" T_MOUSE_SGR) "\033[0m" // Maximum time in milliseconds between double clicks #ifndef BTUI_DOUBLECLICK_THRESHOLD @@ -44,6 +42,12 @@ #define MOD_ALT (1 << (MOD_BITSHIFT + 2)) #define MOD_SHIFT (1 << (MOD_BITSHIFT + 3)) +typedef enum { + BTUI_MODE_UNINITIALIZED = 0, + BTUI_MODE_NORMAL, + BTUI_MODE_TUI, +} btui_mode_t; + typedef enum { // ASCII chars: KEY_CTRL_AT = 0x00, KEY_CTRL_A, KEY_CTRL_B, KEY_CTRL_C, KEY_CTRL_D, @@ -167,6 +171,7 @@ typedef struct { FILE *in, *out; int width, height; int size_changed; + btui_mode_t mode; } btui_t; // Key Names: @@ -181,7 +186,8 @@ int btui_clear(btui_t *bt, int mode); void btui_disable(btui_t *bt); void btui_draw_linebox(btui_t *bt, int x, int y, int w, int h); void btui_draw_shadow(btui_t *bt, int x, int y, int w, int h); -btui_t* btui_enable(void); +btui_t* btui_create(btui_mode_t mode); +#define btui_enable() btui_create(BTUI_MODE_TUI) void btui_fill_box(btui_t *bt, int x, int y, int w, int h); int btui_flush(btui_t *bt); void btui_force_close(btui_t *bt); @@ -199,12 +205,13 @@ int btui_set_bg_hex(btui_t *bt, int hex); int btui_set_cursor(btui_t *bt, cursor_t cur); int btui_set_fg(btui_t *bt, unsigned char r, unsigned char g, unsigned char b); int btui_set_fg_hex(btui_t *bt, int hex); +void btui_set_mode(btui_t *bt, btui_mode_t mode); int btui_show_cursor(btui_t *bt); int btui_suspend(btui_t *bt); // File-local variables: -static btui_t current_bt = {.in = NULL, .out = NULL}; +static btui_t current_bt = {.in = NULL, .out = NULL, .mode = BTUI_MODE_UNINITIALIZED}; // The names of keys that don't render well: static keyname_t key_names[] = { @@ -282,7 +289,7 @@ static void btui_cleanup(void) if (!current_bt.out) return; tcsetattr(fileno(current_bt.out), TCSANOW, &normal_termios); btui_set_cursor(¤t_bt, CURSOR_DEFAULT); - fputs(BTUI_LEAVE, current_bt.out); + btui_set_mode(¤t_bt, BTUI_MODE_UNINITIALIZED); fflush(current_bt.out); fclose(current_bt.in); fclose(current_bt.out); @@ -296,10 +303,11 @@ static void btui_cleanup(void) */ static void btui_cleanup_and_raise(int sig) { + btui_mode_t mode = current_bt.mode; btui_cleanup(); raise(sig); // This code will only ever be run if sig is SIGTSTP/SIGSTOP, otherwise, raise() won't return: - btui_enable(); + btui_create(mode); struct sigaction sa = {.sa_handler = &btui_cleanup_and_raise, .sa_flags = (int)(SA_NODEFER | SA_RESETHAND)}; sigaction(sig, &sa, NULL); } @@ -397,11 +405,11 @@ void btui_draw_shadow(btui_t *bt, int x, int y, int w, int h) * Enable TUI mode for this terminal and return a pointer to the BTUI struct * that should be passed to future API calls. */ -btui_t *btui_enable(void) +btui_t *btui_create(btui_mode_t mode) { - FILE *in = fopen(ttyname(STDIN_FILENO), "r"); + FILE *in = fopen("/dev/tty", "r"); if (!in) return NULL; - FILE *out = fopen(ttyname(STDOUT_FILENO), "w"); + FILE *out = fopen("/dev/tty", "w"); if (!out) { fclose(in); return NULL; @@ -418,6 +426,7 @@ btui_t *btui_enable(void) current_bt.in = in; current_bt.out = out; + current_bt.mode = BTUI_MODE_NORMAL; atexit(btui_cleanup); struct sigaction sa_winch = {.sa_handler = &update_term_size}; @@ -429,12 +438,30 @@ btui_t *btui_enable(void) update_term_size(SIGWINCH); current_bt.size_changed = 0; - - fputs(BTUI_ENTER, out); - fflush(out); + btui_set_mode(¤t_bt, mode); return ¤t_bt; } +/* + * Set the display mode of BTUI + */ +void btui_set_mode(btui_t *bt, btui_mode_t mode) +{ + if (mode == bt->mode) return; + switch (mode) { + case BTUI_MODE_NORMAL: case BTUI_MODE_UNINITIALIZED: + if (bt->mode == BTUI_MODE_TUI) + fputs(T_OFF(T_ALT_SCREEN), bt->out); + fputs(T_ON(T_SHOW_CURSOR ";" T_WRAP) T_OFF(T_MOUSE_XY ";" T_MOUSE_CELL ";" T_MOUSE_SGR) "\033[0m", bt->out); + break; + case BTUI_MODE_TUI: + fputs(T_OFF(T_SHOW_CURSOR ";" T_WRAP) T_ON(T_ALT_SCREEN ";" T_MOUSE_XY ";" T_MOUSE_CELL ";" T_MOUSE_SGR), bt->out); + break; + } + fflush(bt->out); + bt->mode = mode; +} + /* * Fill the given rectangular area (x,y coordinates and width,height) with * spaces.