pane

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

commit 7fe76c958f890df51545862337b8c669677d4a53
parent 724f53a36a61bc30c84d90a9d69babcd775bea4b
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date:   Fri,  2 Sep 2022 01:59:26 +0200

Extract menu interface, hide border from widgets

Diffstat:
Ainclude/menu.h | 45+++++++++++++++++++++++++++++++++++++++++++++
Minclude/pane.h | 46++++++----------------------------------------
Msrc/main.c | 3++-
Asrc/menu.c | 121+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/pane.c | 154++++++++++++++++++-------------------------------------------------------------
5 files changed, 209 insertions(+), 160 deletions(-)

diff --git a/include/menu.h b/include/menu.h @@ -0,0 +1,45 @@ +#ifndef MENU_H +#define MENU_H + +#include "pane.h" + +typedef struct menu_T *menu_T; +typedef struct menuItem_T *menuItem_T; +typedef struct menuStyle_T *menuStyle_T; +typedef struct menuInfo_T *menuInfo_T; + +struct menuItem_T { + void (*callback)(char *, int); + char *name; +}; + +struct menuStyle_T { + char *separator; + int padding; + int spacing; +}; + +struct menuInfo_T { + int start; + int end; + + int y; + int x; + int x_sep; + + int max_item_len; + int sep_len; + int items_num; +}; + +struct menu_T { + int current; + + int items_size; + struct menuItem_T items[]; +}; + +void pane_menu(widget_T widget); +int menu_hadleInput(data_T data, struct tb_event ev); + +#endif diff --git a/include/pane.h b/include/pane.h @@ -13,9 +13,15 @@ int pane_resize(T self); T pane_child(T self, int index); +int pane_x(T self); +int pane_y(T self); +int pane_width(T self); +int pane_height(T self); + T *pane_split(T self, size_t count, ...); T *pane_vsplit(T self, size_t count, ...); void pane_unsplit(T self); +void pane_clear(T self, int clear_border); void setActive(int direction); void pane_setTitle(T self, char *title); @@ -48,45 +54,5 @@ struct widget_T { int widget_activate(widget_T self, Pane_T pane); widget_T pane_widget(T self); -/* MENU */ - -typedef struct menu_T *menu_T; -typedef struct menuItem_T *menuItem_T; -typedef struct menuStyle_T *menuStyle_T; -typedef struct menuInfo_T *menuInfo_T; - -struct menuItem_T { - void (*callback)(char *, int); - char *name; -}; - -struct menuStyle_T { - char *separator; - int padding; - int spacing; -}; - -struct menuInfo_T { - int start; - int end; - - int y; - int x; - int x_sep; - - int max_item_len; - int sep_len; - int items_num; -}; - -struct menu_T { - int current; - - int items_size; - struct menuItem_T items[]; -}; - -void pane_menu(widget_T widget); -int menu_hadleInput(data_T data, struct tb_event ev); #undef T #endif diff --git a/src/main.c b/src/main.c @@ -5,6 +5,7 @@ #include "pane.h" #include "utils.h" +#include "menu.h" extern Pane_T MAIN, ACTIVE; @@ -80,7 +81,7 @@ void input_loop(void) tb_poll_event(&ev); switch (ev.type) { case TB_EVENT_RESIZE: - pane_handle_resize(); + pane_handle_resize(); continue; case TB_EVENT_KEY: { widget_T widget; diff --git a/src/menu.c b/src/menu.c @@ -0,0 +1,121 @@ +#include "menu.h" +#include "pane.h" +#include "utils.h" + +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; +} + +int menu_hadleInput(data_T data, struct tb_event ev) +{ + menu_T menu = (menu_T)data->payload; + + if (ev.type == TB_EVENT_KEY) { + if (ev.ch == 'k' || ev.ch == 'w') { + menu->current--; + CLAMP(menu->current, 0, menu->items_size - 1); + return 1; + } + if (ev.ch == 'j' || ev.ch == 's') { + menu->current++; + CLAMP(menu->current, 0, menu->items_size - 1); + return 1; + } + if (ev.key == TB_KEY_ENTER) { + struct menuItem_T *item = menu->items + menu->current; + item->callback(item->name, menu->current); + return 1; + } + } + + return 0; +} + +void pane_menu(widget_T widget) +{ + size_t i; + Pane_T pane = widget->pane; + menuInfo_T info = (menuInfo_T)(widget->info); + menuStyle_T style = (menuStyle_T)(widget->style); + menu_T menu = (menu_T)(widget->data->payload); + + if (!widget->inited) { + widget->inited = 1; + widget->resized = 1; + + int len, maxi = 0; + + for (i = 0; i < menu->items_size; i++) + if ((len = strlen(menu->items[i].name)) > maxi) + maxi = len; + + info->max_item_len = maxi; + info->sep_len = strlen(style->separator); + info->start = 0; + info->end = info->items_num - 1; + } + + if (widget->resized) { + widget->resized = 0; + + int padding = (style->padding * 2 + 1 > pane_height(pane)) ? + 0 : + style->padding; + // optimal number of elements to display on the screen + int max_items = + (pane_height(pane) - padding * 2 + style->spacing - 2) / + (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); + + info->x_sep = centerHorisontal(pane, info->sep_len); + info->x = centerHorisontal(pane, info->max_item_len); + info->y = centerVertical( + pane, info->items_num * (style->spacing + 1) - + style->spacing); + } + + /* while (1) { */ + pane_clear(pane, 0); + + int relative = menu->current - info->start; + if (relative < 0) { + info->start--; + info->end--; + } else if (relative > 0 && relative > info->end - info->start - 1) { + info->start++; + info->end++; + } + + CLAMP(info->start, 0, menu->items_size - info->items_num); + CLAMP(info->end, info->items_num, menu->items_size); + + if (!menu->items_size) { + char *message = "NOTHING TO DISPLAY HERE!"; + int x = centerHorisontal(pane, strlen(message)); + tb_print(x, info->y, TB_BLUE, 0, message); + return; + } + + if (info->items_num != menu->items_size && info->start == 0) + tb_print(info->x_sep, info->y - 1, TB_BLUE, 0, + style->separator); + + int y = info->y; + for (i = info->start; i < info->end; 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) + tb_print(info->x_sep, y - style->spacing, TB_BLUE, 0, + style->separator); +} diff --git a/src/pane.c b/src/pane.c @@ -30,6 +30,41 @@ struct T { T parent; }; +int pane_hasBorder(T self) +{ + return !self->children; +} + +int pane_x(T self) +{ + if (pane_hasBorder(self)) + return self->x + 1; + else + return self->x; +} + +int pane_y(T self) +{ + if (pane_hasBorder(self)) + return self->y + 1; + else + return self->y; +} +int pane_width(T self) +{ + if (pane_hasBorder(self)) + return self->width - 2; + else + return self->width; +} +int pane_height(T self) +{ + if (pane_hasBorder(self)) + return self->height - 2; + else + return self->height; +} + #define UP(pane) pane->direction[0] #define RIGHT(pane) pane->direction[1] #define DOWN(pane) pane->direction[2] @@ -357,16 +392,6 @@ void setActive(int dir) tb_present(); } -int centerVertical(T self, int len) -{ - return self->y + (self->height - len) / 2; -} - -int centerHorisontal(T self, int len) -{ - return self->x + (self->width - len - 2) / 2 + 1; -} - /* WIDGET */ int widget_activate(widget_T self, Pane_T pane) @@ -384,112 +409,3 @@ int widget_activate(widget_T self, Pane_T pane) return 1; } - -/* MENU DISPLAY */ - -int menu_hadleInput(data_T data, struct tb_event ev) -{ - menu_T menu = (menu_T)data->payload; - - if (ev.type == TB_EVENT_KEY) { - if (ev.ch == 'k' || ev.ch == 'w') { - menu->current--; - CLAMP(menu->current, 0, menu->items_size - 1); - return 1; - } - if (ev.ch == 'j' || ev.ch == 's') { - menu->current++; - CLAMP(menu->current, 0, menu->items_size - 1); - return 1; - } - if (ev.key == TB_KEY_ENTER) { - struct menuItem_T *item = menu->items + menu->current; - item->callback(item->name, menu->current); - return 1; - } - } - - return 0; -} - -void pane_menu(widget_T widget) -{ - size_t i; - Pane_T pane = widget->pane; - menuInfo_T info = (menuInfo_T)(widget->info); - menuStyle_T style = (menuStyle_T)(widget->style); - menu_T menu = (menu_T)(widget->data->payload); - - if (!widget->inited) { - widget->inited = 1; - widget->resized = 1; - - int len, maxi = 0; - - for (i = 0; i < menu->items_size; i++) - if ((len = strlen(menu->items[i].name)) > maxi) - maxi = len; - - info->max_item_len = maxi; - info->sep_len = strlen(style->separator); - info->start = 0; - info->end = info->items_num - 1; - } - - if (widget->resized) { - widget->resized = 0; - - int padding = (style->padding * 2 + 1 > pane->height) ? - 0 : - style->padding; - // optimal number of elements to display on the screen - int max_items = (pane->height - 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); - - info->x_sep = centerHorisontal(pane, info->sep_len); - info->x = centerHorisontal(pane, info->max_item_len); - info->y = centerVertical( - pane, info->items_num * (style->spacing + 1) - - style->spacing); - } - - /* while (1) { */ - pane_clear(pane, 0); - - int relative = menu->current - info->start; - if (relative < 0) { - info->start--; - info->end--; - } else if (relative > 0 && relative > info->end - info->start - 1) { - info->start++; - info->end++; - } - - CLAMP(info->start, 0, menu->items_size - info->items_num); - CLAMP(info->end, info->items_num, menu->items_size); - - if (!menu->items_size) { - char *message = "NOTHING TO DISPLAY HERE!"; - int x = centerHorisontal(pane, strlen(message)); - tb_print(x, info->y, TB_BLUE, 0, message); - return; - } - - if (info->items_num != menu->items_size && info->start == 0) - tb_print(info->x_sep, info->y - 1, TB_BLUE, 0, - style->separator); - - int y = info->y; - for (i = info->start; i < info->end; 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) - tb_print(info->x_sep, y - style->spacing, TB_BLUE, 0, - style->separator); -}