pane

Termbox2 based terminal UI library
git clone git://git.dimitrijedobrota.com/pane.git
Log | Files | Refs

commit 2d45bf507eaa7814eb4bf765d1970c8c6f8ee5d4
parent 7fe76c958f890df51545862337b8c669677d4a53
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date:   Thu,  8 Sep 2022 12:21:24 +0200

Streamlining interface and general improvements

Diffstat:
MMakefile | 6+++---
Minclude/menu.h | 13++++++++++---
Minclude/pane.h | 15+++++++++++++--
Msrc/main.c | 63++++-----------------------------------------------------------
Msrc/menu.c | 45++++++++++++++++++++++++++++++---------------
Msrc/pane.c | 195+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
6 files changed, 232 insertions(+), 105 deletions(-)

diff --git a/Makefile b/Makefile @@ -20,12 +20,12 @@ OBJS=$(patsubst $(SRC)/%.c, $(OBJ)/%.o, $(SRCS)) CFLAGS = -I$(INCLUDE) ifeq ($(DEBUG),Y) - CFLAGS += -Wall -ggdb + CFLAGS += -Wall -ggdb -lciid SRCS := $(filter-out $(SRC)/mem.c, $(SRCS)) LIBNAME =$(NAME)d LIB = $(OBJ)/lib$(LIBNAME) else - CFLAGS += -DNDEBUG + CFLAGS += -DNDEBUG -lcii SRCS := $(filter-out $(SRC)/memchk.c, $(SRCS)) LIBNAME = $(NAME) LIB = $(OBJ)/lib$(LIBNAME) @@ -44,7 +44,7 @@ $(OBJ)/%.o: $(SRC)/%.c install: install -d /usr/local/include/$(NAME) - install -p -m 644 $(INCLUDE)/* /usr/local/include/$(NAME) + install -p -m 644 $(INCLUDE)/* /usr/local/include/ install -d /usr/local/lib install -p -m 644 $(LIB).a /usr/local/lib diff --git a/include/menu.h b/include/menu.h @@ -3,14 +3,17 @@ #include "pane.h" +extern Pane_T MAIN, ACTIVE; + typedef struct menu_T *menu_T; typedef struct menuItem_T *menuItem_T; typedef struct menuStyle_T *menuStyle_T; typedef struct menuInfo_T *menuInfo_T; +typedef void (*menuItem_select_f)(char *, int); struct menuItem_T { - void (*callback)(char *, int); - char *name; + menuItem_select_f select_f; + const char *name; }; struct menuStyle_T { @@ -21,7 +24,7 @@ struct menuStyle_T { struct menuInfo_T { int start; - int end; + /* int end; */ int y; int x; @@ -32,13 +35,17 @@ struct menuInfo_T { int items_num; }; +typedef void (*menu_back_f)(void); struct menu_T { int current; + menu_back_f back_f; int items_size; struct menuItem_T items[]; }; +menu_T menu_new(int item_num, menu_back_f back_f); + void pane_menu(widget_T widget); int menu_hadleInput(data_T data, struct tb_event ev); diff --git a/include/pane.h b/include/pane.h @@ -6,8 +6,9 @@ #define T Pane_T typedef struct T *T; -int pane_start(void); +int pane_start(int active); int pane_stop(void); +void pane_event_loop(void); int pane_handle_resize(void); int pane_resize(T self); @@ -26,14 +27,20 @@ void setActive(int direction); void pane_setTitle(T self, char *title); +int centerVertical(Pane_T pane, int len); +int centerHorisontal(Pane_T pane, int len); +void draw_border(int x, int y, int x_max, int y_max, uintattr_t color); + /* WIDGET */ typedef struct data_T *data_T; typedef struct widget_T *widget_T; +typedef int (*data_handler)(data_T, struct tb_event); + struct data_T { + data_handler handle_input; void *payload; - int (*handle_input)(data_T, struct tb_event); int widget_num; widget_T *widgets; @@ -51,7 +58,11 @@ struct widget_T { void (*callback)(widget_T); }; +data_T data_new(void *payload, data_handler handler); + int widget_activate(widget_T self, Pane_T pane); +int widget_deactivate(widget_T self); +void widget_setData(widget_T self, data_T data); widget_T pane_widget(T self); #undef T diff --git a/src/main.c b/src/main.c @@ -7,8 +7,6 @@ #include "utils.h" #include "menu.h" -extern Pane_T MAIN, ACTIVE; - void quit(char *pass, int index) { pane_stop(); @@ -33,8 +31,8 @@ struct menu_T mainMenu = { struct menuStyle_T mainMenuStyle = { .separator = "<------------->", - .padding = 5, - .spacing = 2, + .padding = 1, + .spacing = 1, }; struct menuStyle_T mainMenuStyle2 = { @@ -72,62 +70,9 @@ struct widget_T mainMenu_widget2 = { .info = &mainMenuInfo2, }; -void input_loop(void) -{ - struct tb_event ev; - size_t i; - - while (1) { - tb_poll_event(&ev); - switch (ev.type) { - case TB_EVENT_RESIZE: - pane_handle_resize(); - continue; - case TB_EVENT_KEY: { - widget_T widget; - data_T payload; - - switch (ev.key) { - case TB_KEY_ARROW_UP: - setActive(0); - continue; - case TB_KEY_ARROW_RIGHT: - setActive(1); - continue; - case TB_KEY_ARROW_DOWN: - setActive(2); - continue; - case TB_KEY_ARROW_LEFT: - setActive(3); - continue; - } - if (ev.ch == 'q' || ev.key == TB_KEY_ESC) { - return; - } - - if (!(widget = pane_widget(ACTIVE))) - continue; - - if (!(payload = widget->data)) { - continue; - } - - if (payload->handle_input(payload, ev)) { - for (i = 0; i < payload->widget_num; i++) { - widget = payload->widgets[i]; - widget->callback(widget); - tb_present(); - } - } - break; - } - } - } -} - int main(int argc, char **argv) { - pane_start(); + pane_start(0); { Pane_T *sections, *mids, *bots; @@ -139,7 +84,7 @@ int main(int argc, char **argv) widget_activate(&mainMenu_widget, mids[1]); widget_activate(&mainMenu_widget2, bots[1]); - input_loop(); + pane_event_loop(); } pane_stop(); return 0; diff --git a/src/menu.c b/src/menu.c @@ -2,14 +2,16 @@ #include "pane.h" #include "utils.h" -int centerVertical(Pane_T pane, int len) +menu_T menu_new(int item_num, menu_back_f back_f) { - return pane_y(pane) + (pane_height(pane) - len) / 2; -} + menu_T menu = + malloc(sizeof(*menu) + item_num * sizeof(struct menuItem_T)); -int centerHorisontal(Pane_T pane, int len) -{ - return pane_x(pane) + (pane_width(pane) - len - 2) / 2 + 1; + menu->items_size = item_num; + menu->current = 0; + menu->back_f = back_f; + + return menu; } int menu_hadleInput(data_T data, struct tb_event ev) @@ -29,9 +31,15 @@ int menu_hadleInput(data_T data, struct tb_event ev) } if (ev.key == TB_KEY_ENTER) { struct menuItem_T *item = menu->items + menu->current; - item->callback(item->name, menu->current); + item->select_f(item->name, menu->current); return 1; } + if (ev.key == TB_KEY_BACKSPACE || ev.key == TB_KEY_BACKSPACE2) { + if (menu->back_f) { + menu->back_f(); + return 1; + } + } } return 0; @@ -49,6 +57,8 @@ void pane_menu(widget_T widget) widget->inited = 1; widget->resized = 1; + pane_clear(pane, 0); + int len, maxi = 0; for (i = 0; i < menu->items_size; i++) @@ -58,7 +68,7 @@ void pane_menu(widget_T widget) info->max_item_len = maxi; info->sep_len = strlen(style->separator); info->start = 0; - info->end = info->items_num - 1; + /* info->end = info->items_num - 1; */ } if (widget->resized) { @@ -69,7 +79,7 @@ void pane_menu(widget_T widget) style->padding; // optimal number of elements to display on the screen int max_items = - (pane_height(pane) - padding * 2 + style->spacing - 2) / + (pane_height(pane) - padding * 2 + style->spacing) / (style->spacing + 1); // number of items displayed cant exceed actual number of items in the menu info->items_num = ACLAMP(max_items, 0, menu->items_size); @@ -79,6 +89,11 @@ void pane_menu(widget_T widget) info->y = centerVertical( pane, info->items_num * (style->spacing + 1) - style->spacing); + + /* info->start = menu->current - in */ + /* info->end = info->start + info->items_num - 1; */ + if (menu->current >= info->start + info->items_num) + info->start += menu->current - info->items_num; } /* while (1) { */ @@ -87,14 +102,14 @@ void pane_menu(widget_T widget) int relative = menu->current - info->start; if (relative < 0) { info->start--; - info->end--; - } else if (relative > 0 && relative > info->end - info->start - 1) { + } else if (relative > 0 && relative > info->items_num - 1) { info->start++; - info->end++; } + tb_printf(pane_x(pane), pane_y(pane), TB_GREEN, 0, "%d", info->start); + CLAMP(info->start, 0, menu->items_size - info->items_num); - CLAMP(info->end, info->items_num, menu->items_size); + /* CLAMP(menu->current, info->start, info->start + info->items_num); */ if (!menu->items_size) { char *message = "NOTHING TO DISPLAY HERE!"; @@ -108,14 +123,14 @@ void pane_menu(widget_T widget) style->separator); int y = info->y; - for (i = info->start; i < info->end; i++) { + for (i = info->start; i < info->start + info->items_num; i++) { int color = (i == menu->current) ? TB_RED : TB_BLUE; tb_printf(info->x, y, color, 0, "%s", menu->items[i].name); y += style->spacing + 1; } if (info->items_num != menu->items_size && - info->end == menu->items_size) + info->start + info->items_num == menu->items_size) tb_print(info->x_sep, y - style->spacing, TB_BLUE, 0, style->separator); } diff --git a/src/pane.c b/src/pane.c @@ -88,33 +88,36 @@ void draw_title(T self) tb_printf(self->x + 1, self->y, TB_RED, 0, " %d ", self->index); } -void draw_border(T self) +void draw_border(int x, int y, int x_max, int y_max, uintattr_t color) { size_t i; - int x_max = self->x + self->width - 1; - int y_max = self->y + self->height - 1; - - int color = (self->active) ? TB_BLUE : TB_GREEN; - for (i = self->x + 1; i < x_max; i++) { - tb_print(i, self->y, color, 0, BORDER_HORIZONTAL); + for (i = x + 1; i < x_max; i++) { + tb_print(i, y, color, 0, BORDER_HORIZONTAL); tb_print(i, y_max, color, 0, BORDER_HORIZONTAL); } - for (i = self->y + 1; i < y_max; i++) { - tb_print(self->x, i, color, 0, BORDER_VERTICAL); + for (i = y + 1; i < y_max; i++) { + tb_print(x, i, color, 0, BORDER_VERTICAL); tb_print(x_max, i, color, 0, BORDER_VERTICAL); } - tb_print(self->x, self->y, color, 0, BORDER_CORNER_1); - tb_print(x_max, self->y, color, 0, BORDER_CORNER_2); - tb_print(self->x, y_max, color, 0, BORDER_CORNER_3); + tb_print(x, y, color, 0, BORDER_CORNER_1); + tb_print(x_max, y, color, 0, BORDER_CORNER_2); + tb_print(x, y_max, color, 0, BORDER_CORNER_3); tb_print(x_max, y_max, color, 0, BORDER_CORNER_4); +} +void pane_draw_border(T self) +{ + int x_max = self->x + self->width - 1; + int y_max = self->y + self->height - 1; + uintattr_t color = (self == ACTIVE) ? TB_BLUE : TB_GREEN; + draw_border(self->x, self->y, x_max, y_max, color); draw_title(self); - tb_printf(self->x, self->y, TB_RED, 0, "%dx%d", self->height, - self->width); + /* tb_printf(self->x, self->y, TB_RED, 0, "%dx%d", self->height, */ + /* self->width); */ } void pane_clear(T self, int clear_border) @@ -214,7 +217,7 @@ int pane_resize(T self) } if (self->children_num == 0) { - draw_border(self); + pane_draw_border(self); return 1; } @@ -231,6 +234,10 @@ int pane_handle_resize(void) MAIN->width = tb_width(); MAIN->x = 0; MAIN->y = 0; + MAIN->direction[0] = NULL; + MAIN->direction[1] = NULL; + MAIN->direction[2] = NULL; + MAIN->direction[3] = NULL; tb_clear(); pane_resize(MAIN); @@ -239,17 +246,20 @@ int pane_handle_resize(void) return 1; } -int pane_start(void) +int pane_start(int active) { tb_init(); MAIN = calloc(1, sizeof(*MAIN)); MAIN->height = tb_height(); MAIN->width = tb_width(); - MAIN->active = 1; MAIN->parent = MAIN; pane_handle_resize(); - ACTIVE = MAIN; + if (active) { + ACTIVE = MAIN; + MAIN->active = 1; + } + return 1; } @@ -292,6 +302,9 @@ void split(T self, size_t count, va_list ap) ACTIVE = self->children[0]; } + if (self->widget) + widget_deactivate(self->widget); + pane_resize(self); } @@ -318,7 +331,7 @@ void pane_unsplit(T self) ACTIVE = self; } pane_clear(self, 1); - draw_border(self); + pane_draw_border(self); tb_present(); } @@ -362,6 +375,9 @@ void pane_setTitle(T self, char *title) void setActive(int dir) { T old = ACTIVE, tmp; + if (!ACTIVE->direction[dir]) + return; + ACTIVE = ACTIVE->direction[dir]; while (ACTIVE->children_num) { @@ -387,25 +403,158 @@ void setActive(int dir) tmp->parent->active = tmp->child_no; } - draw_border(old); - draw_border(ACTIVE); + pane_draw_border(old); + pane_draw_border(ACTIVE); tb_present(); } +int centerVertical(Pane_T pane, int len) +{ + return pane_y(pane) + (pane_height(pane) - len) / 2; +} + +int centerHorisontal(Pane_T pane, int len) +{ + return pane_x(pane) + (pane_width(pane) - len - 2) / 2 + 1; +} + +/* DATA */ + +data_T data_new(void *payload, data_handler handler) +{ + data_T data = calloc(1, sizeof(*data)); + data->handle_input = handler; + data->payload = payload; + return data; +} + /* WIDGET */ int widget_activate(widget_T self, Pane_T pane) { + size_t i; + self->pane = pane; pane->widget = self; pane_setTitle(pane, self->title); + self->callback(self); + tb_present(); + data_T data = self->data; + for (i = 0; i < data->widget_num; i++) + if (data->widgets[i] == self) + return 1; + data->widgets = realloc(data->widgets, data->widget_num + 1); data->widgets[data->widget_num++] = self; - self->callback(self); - tb_present(); + return 1; +} + +int widget_deactivate(widget_T self) +{ + size_t i, j; + + pane_setTitle(self->pane, NULL); + self->pane->widget = NULL; + self->pane = NULL; + + data_T data = self->data; + for (i = j = 0; i < data->widget_num; i++) + if (data->widgets[i] != self) + data->widgets[j++] = data->widgets[i]; + data->widget_num = j; return 1; } + +void widget_setData(widget_T self, data_T data) +{ + self->inited = 0; + if (self->data) { + data->widget_num = self->data->widget_num; + data->widgets = self->data->widgets; + } + self->data = data; +} + +int pane_handle_input(Pane_T self, struct tb_event ev) +{ + size_t i; + widget_T widget; + data_T data; + + if ((widget = pane_widget(self)) && (data = widget->data)) { + if (data->handle_input(data, ev)) { + size_t size = data->widget_num; + for (i = 0; i < size; i++) { + widget = data->widgets[i]; + widget->callback(widget); + size = data->widget_num; + } + tb_present(); + return 1; + } + } + return 0; +} + +int pane_recursive_handle(Pane_T self, struct tb_event ev) +{ + size_t i; + + if (!self) + return 0; + + if (!pane_handle_input(self, ev)) { + for (i = 0; i < self->children_num; i++) + if (pane_recursive_handle(self->children[i], ev)) + return 1; + } + + return 0; +} + +void pane_event_loop(void) +{ + struct tb_event ev; + + while (1) { + tb_poll_event(&ev); + switch (ev.type) { + case TB_EVENT_RESIZE: + pane_handle_resize(); + continue; + case TB_EVENT_KEY: { + if (ev.ch == 'q' || ev.key == TB_KEY_ESC) { + return; + } + + if (ACTIVE) { + switch (ev.key) { + case TB_KEY_ARROW_UP: + setActive(0); + continue; + case TB_KEY_ARROW_RIGHT: + setActive(1); + continue; + case TB_KEY_ARROW_DOWN: + setActive(2); + continue; + case TB_KEY_ARROW_LEFT: + setActive(3); + continue; + } + if (!pane_handle_input(ACTIVE, ev)) + continue; + break; + } else { + pane_recursive_handle(MAIN, ev); + } + } + } + } +} + +/* CENTER WIDGET */