X-Git-Url: https://git.ozlabs.org/?p=petitboot;a=blobdiff_plain;f=ui%2Fncurses%2Fnc-widgets.c;h=f82192939dd968d1dfd4ce2f889cbb382b1d6d8b;hp=688722cd69cc7826aba7d8b60dc5f54286bd856f;hb=cd94ab94766ae863467195324fb84b3d020c96cf;hpb=d2668cb8a8b9f5ded7b36217408e688ebc49442a;ds=sidebyside diff --git a/ui/ncurses/nc-widgets.c b/ui/ncurses/nc-widgets.c index 688722c..f821929 100644 --- a/ui/ncurses/nc-widgets.c +++ b/ui/ncurses/nc-widgets.c @@ -15,9 +15,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define _GNU_SOURCE - +#if defined(HAVE_CONFIG_H) #include "config.h" +#endif #include /* This must be included before ncurses.h */ #if defined HAVE_NCURSESW_CURSES_H @@ -52,7 +52,6 @@ #include #include -#include "config.h" #include "nc-cui.h" #include "nc-widgets.h" @@ -78,6 +77,9 @@ struct nc_widgetset { void (*widget_focus)(struct nc_widget *, void *); void *widget_focus_arg; FIELD *cur_field; + + /* custom validators */ + FIELDTYPE *ipv4_multi_type; }; struct nc_widget { @@ -106,6 +108,7 @@ struct nc_widget_checkbox { }; struct nc_widget_textbox { + struct nc_widgetset *set; struct nc_widget widget; }; @@ -132,6 +135,11 @@ struct nc_widget_button { static void widgetset_add_field(struct nc_widgetset *set, FIELD *field); static void widgetset_remove_field(struct nc_widgetset *set, FIELD *field); +static bool key_is_select(int key) +{ + return key == ' ' || key == '\r' || key == '\n' || key == KEY_ENTER; +} + static bool process_key_nop(struct nc_widget *widget __attribute__((unused)), FORM *form __attribute((unused)), int key __attribute__((unused))) @@ -206,7 +214,7 @@ static bool checkbox_process_key(struct nc_widget *widget, { struct nc_widget_checkbox *checkbox = to_checkbox(widget); - if (key != ' ') + if (!key_is_select(key)) return false; checkbox->checked = !checkbox->checked; @@ -324,6 +332,7 @@ struct nc_widget_textbox *widget_new_textbox(struct nc_widgetset *set, FIELD *f; textbox = talloc_zero(set, struct nc_widget_textbox); + textbox->set = set; textbox->widget.height = 1; textbox->widget.width = len; textbox->widget.x = x; @@ -344,6 +353,67 @@ struct nc_widget_textbox *widget_new_textbox(struct nc_widgetset *set, return textbox; } +void widget_textbox_set_fixed_size(struct nc_widget_textbox *textbox) +{ + field_opts_on(textbox->widget.field, O_STATIC); +} + +void widget_textbox_set_validator_integer(struct nc_widget_textbox *textbox, + long min, long max) +{ + set_field_type(textbox->widget.field, TYPE_INTEGER, 1, min, max); +} + +void widget_textbox_set_validator_ipv4(struct nc_widget_textbox *textbox) +{ + set_field_type(textbox->widget.field, TYPE_IPV4); +} + +static bool check_ipv4_multi_char(int c, + const void *arg __attribute__((unused))) +{ + return isdigit(c) || c == '.' || c == ' '; +} + +static bool check_ipv4_multi_field(FIELD *field, + const void *arg __attribute__((unused))) +{ + char *buf = field_buffer(field, 0); + unsigned int ip[4]; + int n, len; + + while (*buf != '\0') { + n = sscanf(buf, "%u.%u.%u.%u%n", + &ip[0], &ip[1], &ip[2], &ip[3], &len); + if (n != 4) + return false; + + if (ip[0] > 255 || ip[1] > 255 || ip[2] > 255 || ip[3] > 255) + return false; + + for (buf += len; *buf != '\0'; buf++) { + if (isspace(*buf)) + continue; + else if (isdigit(*buf)) + break; + else + return false; + } + } + + return true; +} + +void widget_textbox_set_validator_ipv4_multi(struct nc_widget_textbox *textbox) +{ + if (!textbox->set->ipv4_multi_type) { + textbox->set->ipv4_multi_type = new_fieldtype( + check_ipv4_multi_field, + check_ipv4_multi_char); + } + set_field_type(textbox->widget.field, textbox->set->ipv4_multi_type); +} + static void select_option_change(struct select_option *opt, bool selected) { const char *str; @@ -361,13 +431,8 @@ static bool select_process_key(struct nc_widget *w, FORM *form, int key) int i, new_idx; FIELD *field; - switch (key) { - case ' ': - case KEY_ENTER: - break; - default: + if (!key_is_select(key)) return false; - } field = current_field(form); new_opt = NULL; @@ -556,15 +621,11 @@ static bool button_process_key(struct nc_widget *widget, if (!button->click) return false; - switch (key) { - case ' ': - case '\r': - case '\n': - button->click(button->arg); - return true; - } + if (!key_is_select(key)) + return false; - return false; + button->click(button->arg); + return true; } static int button_destructor(void *ptr) @@ -628,19 +689,26 @@ static void widget_focus_change(struct nc_widget *widget, FIELD *field, bool widgetset_process_key(struct nc_widgetset *set, int key) { struct nc_widget *widget; - FIELD *field; + FIELD *field, *tmp; int req = 0; + bool tab; field = current_field(set->form); assert(field); + tab = false; + /* handle field change events */ switch (key) { case KEY_BTAB: + tab = true; + /* fall through */ case KEY_UP: req = REQ_PREV_FIELD; break; case '\t': + tab = true; + /* fall through */ case KEY_DOWN: req = REQ_NEXT_FIELD; break; @@ -656,8 +724,18 @@ bool widgetset_process_key(struct nc_widgetset *set, int key) if (req) { widget_focus_change(widget, field, false); form_driver(set->form, req); - form_driver(set->form, REQ_END_FIELD); + + /* if we're doing a tabbed-field-change, skip until we + * see the next widget */ + tmp = field; field = current_field(set->form); + + for (; tab && tmp != field && field_userptr(field) == widget;) { + form_driver(set->form, req); + field = current_field(set->form); + } + + form_driver(set->form, REQ_END_FIELD); widget = field_userptr(field); widget_focus_change(widget, field, true); if (widget->field_focus) @@ -677,6 +755,8 @@ static int widgetset_destructor(void *ptr) { struct nc_widgetset *set = ptr; free_form(set->form); + if (set->ipv4_multi_type) + free_fieldtype(set->ipv4_multi_type); return 0; } @@ -694,6 +774,13 @@ struct nc_widgetset *widgetset_create(void *ctx, WINDOW *main, WINDOW *sub) return set; } +void widgetset_set_windows(struct nc_widgetset *set, + WINDOW *main, WINDOW *sub) +{ + set->mainwin = main; + set->subwin = sub; +} + void widgetset_set_widget_focus(struct nc_widgetset *set, widget_focus_cb cb, void *arg) { @@ -790,6 +877,10 @@ void widget_move(struct nc_widget *widget, int y, int x) widget->x = x; widget->y = y; + + if (x + widget->width > COLS) + pb_debug("%s: Widget at %d,%d runs over pad! (%d)", __func__, + y, x, x + widget->width); } int widget_height(struct nc_widget *widget)