diff options
| -rw-r--r-- | src/ui/base.c | 90 | ||||
| -rw-r--r-- | src/ui/dock.c | 12 | ||||
| -rw-r--r-- | src/ui/root.c | 81 | ||||
| -rw-r--r-- | src/ui/ui.internal.h | 21 |
4 files changed, 179 insertions, 25 deletions
diff --git a/src/ui/base.c b/src/ui/base.c index dd454ec..0db31b3 100644 --- a/src/ui/base.c +++ b/src/ui/base.c @@ -47,6 +47,7 @@ void ui__init_window_base(struct ui_window_base *base) base->draw_proc = &ui__default_draw_proc; base->layout_proc = NULL; + base->control_proc = NULL; } void ui__init_window_leaf(struct ui_window_leaf *leaf) @@ -65,6 +66,7 @@ void ui__init_window_dock(struct ui_window_dock *dock) dock->super.type = UI__WINDOW_TYPE_DOCK; dock->super.draw_proc = &ui__dock_default_draw_proc; dock->super.layout_proc = &ui__dock_default_layout_proc; + dock->super.control_proc = &ui__dock_default_control_proc; for (unsigned i = 0; i < UI__WINDOW_DOCK_MAX; ++i) { @@ -81,14 +83,19 @@ void ui__init_window_root(struct ui_window_root *root, WINDOW *cwindow) root->super.type = UI__WINDOW_TYPE_ROOT; root->super.draw_proc = &ui__root_draw_proc; root->super.layout_proc = &ui__root_layout_proc; + root->super.control_proc = &ui__root_control_proc; root->cwindow = cwindow; getmaxyx(cwindow, root->super.dims.maxy, root->super.dims.maxx); getbegyx(cwindow, root->super.dims.begy, root->super.dims.begx); + root->menu_cwindow = newwin(1, root->super.dims.maxx, 0, 0); + root->menu_selected = NULL; + root->undersize_scr = false; root->content = NULL; root->floating = NULL; + root->modal = NULL; root->menu_root = malloc(sizeof(struct uimenu_item_menu)); uimenu_item_menu_init(root->menu_root, NULL); @@ -207,6 +214,55 @@ childfound: } } +WINDOW *ui__find_focused_leaf(struct ui_window_base *start) +{ + switch (start->type) { + case UI__WINDOW_TYPE_LEAF: + return ui__cast(leaf, start)->cwindow; + case UI__WINDOW_TYPE_DOCK: { + struct ui_window_dock *dock = ui__cast(dock, start); + + for (unsigned i = 0; i < UI__WINDOW_DOCK_MAX; ++i) { + if (dock->children[i]) { + WINDOW *focus = ui__find_focused_leaf(dock->children[i]); + if (focus) return focus; + } + } + + return NULL; + } + case UI__WINDOW_TYPE_ROOT: { + struct ui_window_root *root = ui__cast(root, start); + WINDOW *focus; + + if (root->undersize_scr) + return root->cwindow; /* gobble up focus if the screen is undersize */ + + if (root->modal) { + focus = ui__find_focused_leaf(root->modal); + if (focus) return focus; + } + + if (root->floating) { + focus = ui__find_focused_leaf(root->modal); + if (focus) return focus; + } + + if (root->menu_selected) { + return root->menu_cwindow; + } + + if (root->content) { + return ui__find_focused_leaf(root->content); + } + + return NULL; + } + default: + umps_trap; + } +} + void ui__call_draw_proc(struct ui_window_base *base) { if (base->draw_proc) @@ -223,6 +279,16 @@ void ui__call_layout_proc(struct ui_window_base *base) } } +struct ui_window_base *ui__call_control_proc(struct ui_window_base *base, ui_control inp) +{ + if (base->control_proc) + { + return (*base->control_proc)(base, inp); + } + + return NULL; +} + void ui_init(void) { ui_root = malloc(sizeof(struct ui_window_root)); /* TODO: check */ @@ -267,17 +333,18 @@ void ui_handle(void) { while (true) { - struct ui_window_base *window = ui__find_focused(); + WINDOW *cwindow = ui__find_focused_leaf(ui__cast(base, ui_root)); + + ui_control inp; #ifdef NCURSES_WIDE - wint_t inp; - /* FIXME: find a better way of circumnavigating this annoying implied-wrefresh business */ - wget_wch(ui__cast(leaf, window)->cwindow, &inp); + keypad(cwindow, TRUE); + wget_wch(cwindow, &inp); #else - int inp = wgetch(window->cwindow); + inp = wgetch(window->cwindow); #endif - if (inp == NS('q')) + if (inp == NS('q')) /* TODO: make quitting flag in ui_root */ { break; } @@ -287,12 +354,11 @@ void ui_handle(void) getbegyx(ui_root->cwindow, ui_root->super.dims.begy, ui_root->super.dims.begx); ui__call_layout_proc(ui__cast(base, ui_root)); ui__call_draw_proc(ui__cast(base, ui_root)); - } else if (inp == NS('h')) { - ui__status_text = "Hello..."; - ui__call_draw_proc(ui__cast(base, ui_root)); - } else if (inp == NS('w')) { - ui__status_text = "World\u0416!"; - ui__call_draw_proc(ui__cast(base, ui_root)); + } + + struct ui_window_base *target = ui__cast(base, ui_root); + while (target) { + target = ui__call_control_proc(target, inp); } } diff --git a/src/ui/dock.c b/src/ui/dock.c index 82f6728..c0931ba 100644 --- a/src/ui/dock.c +++ b/src/ui/dock.c @@ -153,3 +153,15 @@ void ui__dock_default_layout_proc(struct ui_window_base *base) ui__call_layout_proc(child); } } + +struct ui_window_base *ui__dock_default_control_proc(struct ui_window_base *base, ui_control inp) +{ + struct ui_window_dock *dock = ui__cast(dock, base); + umps_unused(inp); + + if (dock->focus != UI__WINDOW_FOCUS_NONE && dock->children[dock->focus]) { + return dock->children[dock->focus]; + } + + return NULL; /* no focus */ +} diff --git a/src/ui/root.c b/src/ui/root.c index 00eda14..6846d45 100644 --- a/src/ui/root.c +++ b/src/ui/root.c @@ -1,6 +1,7 @@ #include "ui.internal.h" #include "macros.h" #include "ui/uimenu.internal.h" +#include <curses.h> #include <string.h> #define UI__ROOT_MIN_Y (24) @@ -51,6 +52,7 @@ void ui__root_draw_proc(struct ui_window_base *base) ui__root_draw_status(root); wnoutrefresh(root->cwindow); + wnoutrefresh(root->menu_cwindow); if (root->content) { ui__call_draw_proc(root->content); @@ -65,17 +67,18 @@ void ui__root_draw_proc(struct ui_window_base *base) void ui__root_draw_menu(struct ui_window_root *root) { - WINDOW *mywin = root->cwindow; - attron(A_REVERSE); - mvwhline(mywin, 0, 0, ' ', getmaxx(mywin)); - mvwaddstr(mywin, 0, 0, " UMPS v0.1.0-dev"); + wattron(root->menu_cwindow, A_REVERSE); + mvwhline(root->menu_cwindow, 0, 0, ' ', getmaxx(root->menu_cwindow)); + mvwaddstr(root->menu_cwindow, 0, 0, " UMPS v0.1.0-dev"); char *text; - for (struct uimenu_item_header *item = root->menu_root->head; item; item = item->next) { - waddstr(mywin, " "); + int idx = 0; + for (struct uimenu_item_header *item = root->menu_root->head; item; item = item->next, ++idx) { + waddstr(root->menu_cwindow, " "); + switch (item->type) { case UMPS__MENU_TYPE_SPACER: - waddstr(mywin, "--"); + waddstr(root->menu_cwindow, "--"); continue; case UMPS__MENU_TYPE_BUTTON: text = ((struct uimenu_item_button *)item)->text; @@ -87,11 +90,23 @@ void ui__root_draw_menu(struct ui_window_root *root) umps_trap; } - if (text) waddstr(mywin, text); - else waddstr(mywin, "???"); + if (item == root->menu_selected) + wattroff(root->menu_cwindow, A_REVERSE); + + if (text) waddstr(root->menu_cwindow, text); + else waddstr(root->menu_cwindow, "???"); + + wattron(root->menu_cwindow, A_REVERSE); } - attroff(A_REVERSE); + wattroff(root->menu_cwindow, A_REVERSE); +} + +void ui__root_redraw_menu(struct ui_window_root *root) +{ + ui__root_draw_menu(root); + wnoutrefresh(root->menu_cwindow); + doupdate(); } void ui__root_draw_status(struct ui_window_root *root) @@ -117,6 +132,9 @@ void ui__root_layout_proc(struct ui_window_base *base) root->cwindow = newwin(root->super.dims.maxy, root->super.dims.maxx, root->super.dims.begy, root->super.dims.begx); } + delwin(root->menu_cwindow); + root->menu_cwindow = newwin(1, root->super.dims.maxx, 0, 0); + if (root->super.dims.maxy < UI__ROOT_MIN_Y || root->super.dims.maxx < UI__ROOT_MIN_X) { root->undersize_scr = true; return; @@ -130,6 +148,49 @@ void ui__root_layout_proc(struct ui_window_base *base) } } +struct ui_window_base *ui__root_control_proc(struct ui_window_base *base, ui_control inp) +{ + struct ui_window_root *root = ui__cast(root, base); + + if (root->undersize_scr) return NULL; + + switch (inp) { + case NS('h'): + ui__status_text = "Hello..."; + ui__call_draw_proc(ui__cast(base, ui_root)); + break; + case NS('w'): + ui__status_text = "World!"; + ui__call_draw_proc(ui__cast(base, ui_root)); + break; + case NS('m'): + if (root->menu_selected) { + root->menu_selected = NULL; + } else { + root->menu_selected = root->menu_root->head; + } + ui__root_redraw_menu(root); + return NULL; + case KEY_LEFT: + case KEY_RIGHT: + if (root->menu_selected) { + struct uimenu_item_header *nxt = inp == KEY_RIGHT ? root->menu_selected->next : root->menu_selected->prev; + if (nxt) { + root->menu_selected = nxt; + ui__root_redraw_menu(root); + } + return NULL; + } + break; + } + + if (root->menu_selected) { + return NULL; + } else { + return root->content; + } +} + void ui__root_set_content(struct ui_window_root *root, struct ui_window_base *window) { umps_assert(!window->parent); diff --git a/src/ui/ui.internal.h b/src/ui/ui.internal.h index 201e61e..763f9a7 100644 --- a/src/ui/ui.internal.h +++ b/src/ui/ui.internal.h @@ -53,6 +53,14 @@ typedef void (ui__draw_proc)(struct ui_window_base *); /* called to recalculate the layout of the window (for resize) */ typedef void (ui__layout_proc)(struct ui_window_base *); +#ifdef NCURSES_WIDE +typedef wint_t ui_control; +#else +typedef int ui_control; +#endif + +typedef struct ui_window_base *(ui__control_proc)(struct ui_window_base *, ui_control); + struct ui_window_base { unsigned type; struct ui_window_base *parent; /* the parent of a window manages its memory */ @@ -63,6 +71,7 @@ struct ui_window_base { ui__draw_proc *draw_proc; ui__layout_proc *layout_proc; + ui__control_proc *control_proc; }; struct ui_window_leaf { @@ -82,12 +91,15 @@ struct ui_window_dock { struct ui_window_root { struct ui_window_base super; - WINDOW *cwindow; + WINDOW *cwindow, *menu_cwindow; + + struct uimenu_item_header *menu_selected; bool undersize_scr; - struct ui_window_base *content; - struct ui_window_base *floating; + struct ui_window_base *content; /* content of the editor */ + struct ui_window_base *floating; /* floating menu layer */ + struct ui_window_base *modal; /* modal (dialog) layer */ struct uimenu_item_menu *menu_root; }; @@ -115,13 +127,16 @@ void ui__destroy_window(struct ui_window_base *); void ui__dock_add_child(struct ui_window_dock *, struct ui_window_base *, unsigned position, float size); void ui__dock_default_draw_proc(struct ui_window_base *base); void ui__dock_default_layout_proc(struct ui_window_base *base); +struct ui_window_base *ui__dock_default_control_proc(struct ui_window_base *base, ui_control inp); /* root window hooks */ void ui__root_draw_proc(struct ui_window_base *); void ui__root_layout_proc(struct ui_window_base *); +struct ui_window_base *ui__root_control_proc(struct ui_window_base *base, ui_control inp); /* root_window_utilities */ +void ui__root_redraw_menu(struct ui_window_root *); void ui__root_set_content(struct ui_window_root *, struct ui_window_base *); extern const char *ui__status_text; |
