diff options
| -rw-r--r-- | meson.build | 16 | ||||
| -rw-r--r-- | src/config.h.in | 2 | ||||
| -rw-r--r-- | src/ui/base.c | 17 | ||||
| -rw-r--r-- | src/ui/debug.c | 22 | ||||
| -rw-r--r-- | src/ui/root.c | 123 | ||||
| -rw-r--r-- | src/ui/ui.internal.h | 17 |
6 files changed, 168 insertions, 29 deletions
diff --git a/meson.build b/meson.build index 134a16f..4951e76 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,18 @@ project('umps', 'c') +git_program = find_program('git', required : false) +if git_program.found() + res = run_command(['git', 'describe', '--dirty=-dirty', '--always'], check : true, capture : true) + + # trim version string down so it won't ever be too large for the UI + prog_version = res.stdout().strip().substring(0, 48) + + message('Found version string', prog_version) +else + prog_version = '???' + message('Git not found. Falling back to version', prog_version) +endif + conf_data = configuration_data() opt_ncurses_narrow = get_option('ncurses_narrow') @@ -25,6 +38,9 @@ else conf_data.set('NCURSES_INCLUDE', '<ncurses.h>') endif +conf_data.set_quoted('UMPS_VERSION', prog_version) +conf_data.set_quoted('UMPS_NAME', 'UMPS') + subdir('src') executable('umps', umps_srcs, dependencies : [curses_dep], include_directories : umps_config_inc, override_options : {'b_ndebug' : 'if-release', 'c_std' : 'c99' }) diff --git a/src/config.h.in b/src/config.h.in index 4e9f870..09e7f55 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -1,5 +1,7 @@ #mesondefine NCURSES_WIDE #mesondefine NCURSES_INCLUDE +#mesondefine UMPS_NAME +#mesondefine UMPS_VERSION #ifdef NCURSES_WIDE #define NCURSES_TEXT(_s) L ## _s diff --git a/src/ui/base.c b/src/ui/base.c index 0db31b3..f1aa217 100644 --- a/src/ui/base.c +++ b/src/ui/base.c @@ -5,6 +5,7 @@ #include "ui.internal.h" #include "ui/uimenu.internal.h" #include "../macros.h" +#include "config.h" struct ui_window_root *ui_root = NULL; @@ -31,8 +32,8 @@ void ui__leaf_draw_proc(struct ui_window_base *base) void ui__leaf_layout_proc(struct ui_window_base *base) { struct ui_window_leaf *leaf = (struct ui_window_leaf *)base; - if (leaf->cwindow) delwin(leaf->cwindow); - leaf->cwindow = newwin(leaf->super.dims.maxy, leaf->super.dims.maxx, leaf->super.dims.begy, leaf->super.dims.begx); + if (leaf->cwindow) NCCI(delwin(leaf->cwindow)); + leaf->cwindow = NCCP(newwin(leaf->super.dims.maxy, leaf->super.dims.maxx, leaf->super.dims.begy, leaf->super.dims.begx)); } void ui__init_window_base(struct ui_window_base *base) @@ -89,8 +90,12 @@ void ui__init_window_root(struct ui_window_root *root, WINDOW *cwindow) getmaxyx(cwindow, root->super.dims.maxy, root->super.dims.maxx); getbegyx(cwindow, root->super.dims.begy, root->super.dims.begx); + root->menu_prefix = ""; + root->menu_prefix_len = 0; + root->menu_cwindow = newwin(1, root->super.dims.maxx, 0, 0); root->menu_selected = NULL; + root->menu_scroll = 0; root->undersize_scr = false; root->content = NULL; @@ -303,14 +308,18 @@ void ui_init(void) curs_set(0); ui__init_window_root(ui_root, stdscr); + ui__call_layout_proc(ui__cast(base, ui_root)); /* set up UI */ + ui_root->menu_prefix = " " UMPS_NAME " " UMPS_VERSION " "; + ui_root->menu_prefix_len = strlen(ui_root->menu_prefix); + struct ui_window_dock *maindock = malloc(sizeof(struct ui_window_dock)); ui__init_window_dock(maindock); ui__root_set_content(ui_root, ui__cast(base, maindock)); - const char *menu_names[] = { "File", "View", "Tools", "Filters", "Help", NULL }; + const char *menu_names[] = { "File", "View", "Tools", "Filters", "Help", "1", "22", "333", "4444", "55555", "666666", "7777777", "88888888", "999999999", "0000000000", NULL }; for (int i = 0; menu_names[i]; ++i) { struct uimenu_item_menu *menu = malloc(sizeof(struct uimenu_item_menu)); uimenu_item_menu_init(menu, menu_names[i]); @@ -325,7 +334,7 @@ void ui_init(void) ui__dock_add_child(maindock, ui__cast(base, win_traces), i, 1./5); } - /* ui__call_layout_proc(ui__cast(base, ui_root)); */ + ui__call_layout_proc(ui__cast(base, ui_root)); /* should call layout proc to check for undersize at least */ ui__call_draw_proc(ui__cast(base, ui_root)); } diff --git a/src/ui/debug.c b/src/ui/debug.c index 6e404a3..5623b97 100644 --- a/src/ui/debug.c +++ b/src/ui/debug.c @@ -51,6 +51,28 @@ struct ui_window_root *ui__check_cast_to_root(void *obj, const char *file, const UMPS__DEBUG_DO_ERROR(obj, file, func, line, UI__WINDOW_TYPE_ROOT); } +int ui__debug_nc_check_int(int in, const char *call, const char *file, const char *func, int line) +{ + if (in == ERR) { + fprintf(stderr, "!!!!!\n!!!!!\n!!!!! UMPS checked ncurses call \"%s\" failed (returned ERR) at %s:%d %s !!!!!\n!!!!!\n!!!!!\n", + call, file, line, func); + umps_trap; + } + + return in; +} + +WINDOW *ui__debug_nc_check_ptr(WINDOW *ptr, const char *call, const char *file, const char *func, int line) +{ + if (ptr == NULL) { + fprintf(stderr, "!!!!!\n!!!!!\n!!!!! UMPS checked ncurses call \"%s\" failed (returned NULL) at %s:%d %s !!!!!\n!!!!!\n!!!!!\n", + call, file, line, func); + umps_trap; + } + + return ptr; +} + #else /* the file must have a declaration */ diff --git a/src/ui/root.c b/src/ui/root.c index 6846d45..fd82ea6 100644 --- a/src/ui/root.c +++ b/src/ui/root.c @@ -1,7 +1,6 @@ #include "ui.internal.h" #include "macros.h" #include "ui/uimenu.internal.h" -#include <curses.h> #include <string.h> #define UI__ROOT_MIN_Y (24) @@ -65,40 +64,108 @@ void ui__root_draw_proc(struct ui_window_base *base) doupdate(); } +const char *ui__root_get_menu_text(struct uimenu_item_header *item) +{ + const char *text = NULL; + switch (item->type) { + case UMPS__MENU_TYPE_SPACER: + return "--"; + case UMPS__MENU_TYPE_BUTTON: + text = ((struct uimenu_item_button *)item)->text; + break; + case UMPS__MENU_TYPE_MENU: + text = ((struct uimenu_item_menu *)item)->text; + break; + default: + umps_trap; + } + + return text ? text : "???"; +} + +void ui__update_scroll(struct ui_window_root *root) +{ + unsigned cursor = 0, prevcursor = 0; + unsigned menu_len = getmaxx(root->menu_cwindow) - root->menu_prefix_len - 2; + + for (struct uimenu_item_header *item = root->menu_root->head; item; item = item->next, prevcursor = cursor) { + if (item == root->menu_selected) { /* we have found the item :) */ + if (root->menu_scroll > cursor) { /* we are scrolled too far to the right */ + root->menu_scroll = cursor; + return; + } + } + + cursor += 2; + + cursor += strlen(ui__root_get_menu_text(item)); + + if (item == root->menu_selected) { + if (cursor > root->menu_scroll + menu_len) { + root->menu_scroll = cursor - menu_len; + } + + return; + } + } +} + +void ui__root_scroll_text(struct ui_window_root *root, unsigned cursor, const char *text, size_t tlen) +{ + if (cursor < root->menu_scroll) { + size_t strend = cursor + tlen; + if (strend > root->menu_scroll) { + size_t desired_length = strend - root->menu_scroll; + waddnstr(root->menu_cwindow, text + (tlen - desired_length), desired_length); + } + return; + } + + waddnstr(root->menu_cwindow, text, tlen); +} + void ui__root_draw_menu(struct ui_window_root *root) { 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"); + mvwaddnstr(root->menu_cwindow, 0, 0, root->menu_prefix, root->menu_prefix_len); + + ui__update_scroll(root); + + if (root->menu_scroll > 2) { + waddch(root->menu_cwindow, ACS_LARROW); + } else { + waddch(root->menu_cwindow, ' '); + } - char *text; + unsigned cursor = 0; + const char *text; 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(root->menu_cwindow, "--"); - continue; - case UMPS__MENU_TYPE_BUTTON: - text = ((struct uimenu_item_button *)item)->text; - break; - case UMPS__MENU_TYPE_MENU: - text = ((struct uimenu_item_menu *)item)->text; - break; - default: - umps_trap; + unsigned menu_len = getmaxx(root->menu_cwindow) - root->menu_prefix_len - 2; + struct uimenu_item_header *item; + for (item = root->menu_root->head; item; item = item->next, ++idx) { + if (cursor > root->menu_scroll) { + waddstr(root->menu_cwindow, " "); } + cursor += 2; + text = ui__root_get_menu_text(item); + size_t tlen = strlen(text); if (item == root->menu_selected) wattroff(root->menu_cwindow, A_REVERSE); - if (text) waddstr(root->menu_cwindow, text); - else waddstr(root->menu_cwindow, "???"); + ui__root_scroll_text(root, cursor, text, tlen); wattron(root->menu_cwindow, A_REVERSE); + cursor += tlen; + + if (cursor >= root->menu_scroll + menu_len) { + break; + } } + mvwaddch(root->menu_cwindow, 0, getmaxx(root->menu_cwindow)-1, (cursor > root->menu_scroll + menu_len || (item && item->next)) ? ACS_RARROW : ' '); + wattroff(root->menu_cwindow, A_REVERSE); } @@ -128,12 +195,12 @@ void ui__root_layout_proc(struct ui_window_base *base) struct ui_window_root *root = ui__cast(root, base); if (root->cwindow != stdscr) { - if (root->cwindow) delwin(root->cwindow); - root->cwindow = newwin(root->super.dims.maxy, root->super.dims.maxx, root->super.dims.begy, root->super.dims.begx); + if (root->cwindow) NCCI(delwin(root->cwindow)); + root->cwindow = NCCP(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); + NCCI(delwin(root->menu_cwindow)); + root->menu_cwindow = NCCP(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; @@ -171,6 +238,14 @@ struct ui_window_base *ui__root_control_proc(struct ui_window_base *base, ui_con } ui__root_redraw_menu(root); return NULL; + case NS('a'): + --root->menu_scroll; + ui__root_redraw_menu(root); + break; + case NS('d'): + ++root->menu_scroll; + ui__root_redraw_menu(root); + break; case KEY_LEFT: case KEY_RIGHT: if (root->menu_selected) { diff --git a/src/ui/ui.internal.h b/src/ui/ui.internal.h index 763f9a7..863d9b2 100644 --- a/src/ui/ui.internal.h +++ b/src/ui/ui.internal.h @@ -6,6 +6,7 @@ #include "config.h" #include NCURSES_INCLUDE +#include <stddef.h> /* for size_t */ #include <stdbool.h> #define UI__WINDOW_DOCK_TOP (0u) @@ -36,6 +37,10 @@ enum { #ifdef NDEBUG #define ui__cast(_t, _v) ((struct ui_window_ ## _t *)(_v)) + +/* ncurses auto-checkers no-op in release */ +#define NCCI(_call) _call +#define NCCP(_call) _call #else #define ui__cast(_t, _v) (ui__check_cast_to_ ## _t(_v, __FILE__, __func__, __LINE__)) @@ -43,6 +48,12 @@ struct ui_window_base *ui__check_cast_to_base(void *, const char *, const char * struct ui_window_leaf *ui__check_cast_to_leaf(void *, const char *, const char *, int); struct ui_window_dock *ui__check_cast_to_dock(void *, const char *, const char *, int); struct ui_window_root *ui__check_cast_to_root(void *, const char *, const char *, int); + +#define NCCI(_call) ui__debug_nc_check_int(_call, #_call, __FILE__, __func__, __LINE__) +#define NCCP(_call) ui__debug_nc_check_ptr(_call, #_call, __FILE__, __func__, __LINE__) + +int ui__debug_nc_check_int(int in, const char *call, const char *file, const char *func, int line); +WINDOW *ui__debug_nc_check_ptr(WINDOW *ptr, const char *call, const char *file, const char *func, int line); #endif /* concrete type definitions */ @@ -93,9 +104,13 @@ struct ui_window_root { struct ui_window_base super; WINDOW *cwindow, *menu_cwindow; + const char *menu_prefix; + size_t menu_prefix_len; + struct uimenu_item_header *menu_selected; + unsigned menu_scroll; - bool undersize_scr; + bool undersize_scr; /* true if the screen was found to be undersize (set in layout proc) */ struct ui_window_base *content; /* content of the editor */ struct ui_window_base *floating; /* floating menu layer */ |
