X-Git-Url: https://git.ozlabs.org/?p=petitboot;a=blobdiff_plain;f=ui%2Fncurses%2Fnc-widgets.c;h=5592db9c7769a3c68fc03497776f469d208d0abc;hp=d17034dd685e14e42fb42294fa734aa4eb250ad6;hb=5d955dcc4f9a699bc84fe25ff337d51103f845ac;hpb=43e9c8147f74fba794fd280fa0fdb57af8b968f4 diff --git a/ui/ncurses/nc-widgets.c b/ui/ncurses/nc-widgets.c index d17034d..5592db9 100644 --- a/ui/ncurses/nc-widgets.c +++ b/ui/ncurses/nc-widgets.c @@ -15,7 +15,34 @@ * 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 +# include +#elif defined HAVE_NCURSESW_H +# include +#elif defined HAVE_NCURSES_CURSES_H +# include +#elif defined HAVE_NCURSES_H +# include +#elif defined HAVE_CURSES_H +# include +#else +# error "Curses header file not found." +#endif + +#if defined HAVE_NCURSESW_FORM_H +# include +#elif defined HAVE_NCURSES_FORM_H +# include +#elif defined HAVE_FORM_H +# include +#else +# error "Curses form.h not found." +#endif #include #include @@ -25,7 +52,6 @@ #include #include -#include "config.h" #include "nc-cui.h" #include "nc-widgets.h" @@ -51,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 { @@ -58,10 +87,12 @@ struct nc_widget { bool (*process_key)(struct nc_widget *, FORM *, int); void (*set_visible)(struct nc_widget *, bool); void (*move)(struct nc_widget *, int, int); + void (*field_focus)(struct nc_widget *, FIELD *); int focussed_attr; int unfocussed_attr; int height; int width; + int focus_y; int x; int y; }; @@ -77,6 +108,7 @@ struct nc_widget_checkbox { }; struct nc_widget_textbox { + struct nc_widgetset *set; struct nc_widget widget; }; @@ -101,6 +133,12 @@ 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)), @@ -176,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; @@ -294,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; @@ -314,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; @@ -331,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; @@ -387,6 +482,19 @@ static void select_move(struct nc_widget *widget, int y, int x) field_move(select->options[i].field, y + i, x); } +static void select_field_focus(struct nc_widget *widget, FIELD *field) +{ + struct nc_widget_select *select = to_select(widget); + int i; + + for (i = 0; i < select->n_options; i++) { + if (field != select->options[i].field) + continue; + widget->focus_y = i; + return; + } +} + static int select_destructor(void *ptr) { struct nc_widget_select *select = ptr; @@ -411,6 +519,7 @@ struct nc_widget_select *widget_new_select(struct nc_widgetset *set, select->widget.process_key = select_process_key; select->widget.set_visible = select_set_visible; select->widget.move = select_move; + select->widget.field_focus = select_field_focus; select->widget.focussed_attr = A_REVERSE; select->widget.unfocussed_attr = A_NORMAL; select->top = y; @@ -466,6 +575,8 @@ void widget_select_add_option(struct nc_widget_select *select, int value, int widget_select_get_value(struct nc_widget_select *select) { + if (!select->n_options) + return -1; return select->options[select->selected_option].val; } @@ -481,6 +592,27 @@ void widget_select_on_change(struct nc_widget_select *select, select->on_change_arg = arg; } +void widget_select_drop_options(struct nc_widget_select *select) +{ + struct nc_widgetset *set = select->set; + int i; + + for (i = 0; i < select->n_options; i++) { + FIELD *field = select->options[i].field; + widgetset_remove_field(set, field); + if (field == set->cur_field) + set->cur_field = NULL; + free_field(select->options[i].field); + } + + talloc_free(select->options); + select->options = NULL; + select->n_options = 0; + select->widget.height = 0; + select->widget.focus_y = 0; + +} + static bool button_process_key(struct nc_widget *widget, FORM *form __attribute__((unused)), int key) { @@ -489,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) @@ -561,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; @@ -589,10 +724,22 @@ 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) + widget->field_focus(widget, field); if (set->widget_focus) set->widget_focus(widget, set->widget_focus_arg); return true; @@ -608,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; } @@ -625,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) { @@ -676,6 +832,23 @@ static void widgetset_add_field(struct nc_widgetset *set, FIELD *field) set->fields[set->n_fields] = NULL; } +static void widgetset_remove_field(struct nc_widgetset *set, FIELD *field) +{ + int i; + + for (i = 0; i < set->n_fields; i++) { + if (set->fields[i] == field) + break; + } + + if (i == set->n_fields) + return; + + memmove(&set->fields[i], &set->fields[i+i], + (set->n_fields - i) * sizeof(set->fields[i])); + set->n_fields--; +} + #define DECLARE_BASEFN(type) \ struct nc_widget *widget_ ## type ## _base \ (struct nc_widget_ ## type *w) \ @@ -726,3 +899,8 @@ int widget_y(struct nc_widget *widget) return widget->y; } +int widget_focus_y(struct nc_widget *widget) +{ + return widget->focus_y; +} +