2 * Copyright (C) 2013 IBM Corporation
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 #if defined(HAVE_CONFIG_H)
22 #include <linux/input.h> /* This must be included before ncurses.h */
23 #if defined HAVE_NCURSESW_CURSES_H
24 # include <ncursesw/curses.h>
25 #elif defined HAVE_NCURSESW_H
26 # include <ncursesw.h>
27 #elif defined HAVE_NCURSES_CURSES_H
28 # include <ncurses/curses.h>
29 #elif defined HAVE_NCURSES_H
31 #elif defined HAVE_CURSES_H
34 # error "Curses header file not found."
37 #if defined HAVE_NCURSESW_FORM_H
38 # include <ncursesw/form.h>
39 #elif defined HAVE_NCURSES_FORM_H
40 # include <ncurses/form.h>
41 #elif defined HAVE_FORM_H
44 # error "Curses form.h not found."
50 #include <talloc/talloc.h>
51 #include <types/types.h>
53 #include <util/util.h>
54 #include <i18n/i18n.h>
57 #include "nc-widgets.h"
61 #define to_checkbox(w) container_of(w, struct nc_widget_checkbox, widget)
62 #define to_textbox(w) container_of(w, struct nc_widget_textbox, widget)
63 #define to_button(w) container_of(w, struct nc_widget_button, widget)
64 #define to_select(w) container_of(w, struct nc_widget_select, widget)
65 #define to_subset(w) container_of(w, struct nc_widget_subset, widget)
67 static const char *checkbox_checked_str = "[*]";
68 static const char *checkbox_unchecked_str = "[ ]";
70 static const char *select_selected_str = "(*)";
71 static const char *select_unselected_str = "( )";
78 int n_fields, n_alloc_fields;
79 void (*widget_focus)(struct nc_widget *, void *);
80 void *widget_focus_arg;
83 /* custom validators */
84 FIELDTYPE *ipv4_multi_type;
89 bool (*process_key)(struct nc_widget *, FORM *, int);
90 void (*set_visible)(struct nc_widget *, bool);
91 void (*move)(struct nc_widget *, int, int);
92 void (*field_focus)(struct nc_widget *, FIELD *);
102 struct nc_widget_label {
103 struct nc_widget widget;
107 struct nc_widget_checkbox {
108 struct nc_widget widget;
112 struct nc_widget_textbox {
113 struct nc_widgetset *set;
114 struct nc_widget widget;
117 struct nc_widget_subset {
118 struct nc_widget widget;
121 struct subset_option {
128 struct nc_widgetset *set;
129 void (*on_change)(void *, int);
131 void (*screen_cb)(void *,
132 struct nc_widget_subset *, int);
135 struct nc_widget_select {
136 struct nc_widget widget;
137 struct select_option {
143 int n_options, selected_option;
144 struct nc_widgetset *set;
145 void (*on_change)(void *, int);
149 struct nc_widget_button {
150 struct nc_widget widget;
151 void (*click)(void *arg);
155 static void widgetset_add_field(struct nc_widgetset *set, FIELD *field);
156 static void widgetset_remove_field(struct nc_widgetset *set, FIELD *field);
158 static bool key_is_select(int key)
160 return key == ' ' || key == '\r' || key == '\n' || key == KEY_ENTER;
163 static bool key_is_minus(int key)
168 static bool key_is_left(int key)
170 return key == KEY_LEFT;
173 static bool key_is_right(int key)
175 return key == KEY_RIGHT;
178 static bool process_key_nop(struct nc_widget *widget __attribute__((unused)),
179 FORM *form __attribute((unused)),
180 int key __attribute__((unused)))
185 static void field_set_visible(FIELD *field, bool visible)
187 int opts = field_opts(field) & ~O_VISIBLE;
190 set_field_opts(field, opts);
193 static bool field_visible(FIELD *field)
195 return (field_opts(field) & O_VISIBLE) == O_VISIBLE;
198 static void field_move(FIELD *field, int y, int x)
200 move_field(field, y, x);
203 static int label_destructor(void *ptr)
205 struct nc_widget_label *label = ptr;
206 free_field(label->widget.field);
211 struct nc_widget_label *widget_new_label(struct nc_widgetset *set,
212 int y, int x, char *str)
214 struct nc_widget_label *label;
220 label = talloc_zero(set, struct nc_widget_label);
221 label->widget.height = 1;
222 label->widget.width = len;
225 label->widget.process_key = process_key_nop;
226 label->widget.field = f = new_field(1, len, y, x, 0, 0);
227 label->widget.focussed_attr = A_NORMAL;
228 label->widget.unfocussed_attr = A_NORMAL;
230 field_opts_off(f, O_ACTIVE);
231 set_field_buffer(f, 0, str);
232 set_field_userptr(f, &label->widget);
234 widgetset_add_field(set, label->widget.field);
235 talloc_set_destructor(label, label_destructor);
240 bool widget_checkbox_get_value(struct nc_widget_checkbox *checkbox)
242 return checkbox->checked;
245 static void checkbox_set_buffer(struct nc_widget_checkbox *checkbox)
248 str = checkbox->checked ? checkbox_checked_str : checkbox_unchecked_str;
249 set_field_buffer(checkbox->widget.field, 0, str);
252 static bool checkbox_process_key(struct nc_widget *widget,
253 FORM *form __attribute__((unused)), int key)
255 struct nc_widget_checkbox *checkbox = to_checkbox(widget);
257 if (!key_is_select(key))
260 checkbox->checked = !checkbox->checked;
261 checkbox_set_buffer(checkbox);
266 static int checkbox_destructor(void *ptr)
268 struct nc_widget_checkbox *checkbox = ptr;
269 free_field(checkbox->widget.field);
273 struct nc_widget_checkbox *widget_new_checkbox(struct nc_widgetset *set,
274 int y, int x, bool checked)
276 struct nc_widget_checkbox *checkbox;
279 checkbox = talloc_zero(set, struct nc_widget_checkbox);
280 checkbox->checked = checked;
281 checkbox->widget.height = 1;
282 checkbox->widget.width = strlen(checkbox_checked_str);
283 checkbox->widget.x = x;
284 checkbox->widget.y = y;
285 checkbox->widget.process_key = checkbox_process_key;
286 checkbox->widget.focussed_attr = A_REVERSE;
287 checkbox->widget.unfocussed_attr = A_NORMAL;
288 checkbox->widget.field = f = new_field(1, strlen(checkbox_checked_str),
291 field_opts_off(f, O_EDIT);
292 set_field_userptr(f, &checkbox->widget);
293 checkbox_set_buffer(checkbox);
295 widgetset_add_field(set, checkbox->widget.field);
296 talloc_set_destructor(checkbox, checkbox_destructor);
301 static char *strip_string(char *str)
307 /* clear trailing space */
308 for (i = len - 1; i >= 0; i--) {
309 if (!isspace(str[i]))
314 /* increment str past leading space */
315 for (i = 0; i < len; i++) {
316 if (str[i] == '\0' || !isspace(str[i]))
323 char *widget_textbox_get_value(struct nc_widget_textbox *textbox)
325 char *str = field_buffer(textbox->widget.field, 0);
326 return str ? strip_string(str) : NULL;
329 static bool textbox_process_key(
330 struct nc_widget *widget __attribute__((unused)),
335 form_driver(form, REQ_BEG_FIELD);
338 form_driver(form, REQ_END_FIELD);
341 form_driver(form, REQ_LEFT_CHAR);
344 form_driver(form, REQ_RIGHT_CHAR);
347 if (form_driver(form, REQ_LEFT_CHAR) != E_OK)
351 form_driver(form, REQ_DEL_CHAR);
354 form_driver(form, key);
361 static int textbox_destructor(void *ptr)
363 struct nc_widget_textbox *textbox = ptr;
364 free_field(textbox->widget.field);
368 struct nc_widget_textbox *widget_new_textbox(struct nc_widgetset *set,
369 int y, int x, int len, char *str)
371 struct nc_widget_textbox *textbox;
374 textbox = talloc_zero(set, struct nc_widget_textbox);
376 textbox->widget.height = 1;
377 textbox->widget.width = len;
378 textbox->widget.x = x;
379 textbox->widget.y = y;
380 textbox->widget.process_key = textbox_process_key;
381 textbox->widget.field = f = new_field(1, len, y, x, 0, 0);
382 textbox->widget.focussed_attr = A_REVERSE;
383 textbox->widget.unfocussed_attr = A_UNDERLINE;
385 field_opts_off(f, O_STATIC | O_WRAP | O_BLANK);
386 set_field_buffer(f, 0, str);
387 set_field_back(f, textbox->widget.unfocussed_attr);
388 set_field_userptr(f, &textbox->widget);
390 widgetset_add_field(set, textbox->widget.field);
391 talloc_set_destructor(textbox, textbox_destructor);
396 void widget_textbox_set_fixed_size(struct nc_widget_textbox *textbox)
398 field_opts_on(textbox->widget.field, O_STATIC);
401 void widget_textbox_set_validator_integer(struct nc_widget_textbox *textbox,
404 set_field_type(textbox->widget.field, TYPE_INTEGER, 1, min, max);
407 void widget_textbox_set_validator_ipv4(struct nc_widget_textbox *textbox)
409 set_field_type(textbox->widget.field, TYPE_IPV4);
412 static bool check_ipv4_multi_char(int c,
413 const void *arg __attribute__((unused)))
415 return isdigit(c) || c == '.' || c == ' ';
418 static bool check_ipv4_multi_field(FIELD *field,
419 const void *arg __attribute__((unused)))
421 char *buf = field_buffer(field, 0);
425 while (*buf != '\0') {
426 n = sscanf(buf, "%u.%u.%u.%u%n",
427 &ip[0], &ip[1], &ip[2], &ip[3], &len);
431 if (ip[0] > 255 || ip[1] > 255 || ip[2] > 255 || ip[3] > 255)
434 for (buf += len; *buf != '\0'; buf++) {
437 else if (isdigit(*buf))
447 void widget_textbox_set_validator_ipv4_multi(struct nc_widget_textbox *textbox)
449 if (!textbox->set->ipv4_multi_type) {
450 textbox->set->ipv4_multi_type = new_fieldtype(
451 check_ipv4_multi_field,
452 check_ipv4_multi_char);
454 set_field_type(textbox->widget.field, textbox->set->ipv4_multi_type);
457 static void subset_update_order(struct nc_widget_subset *subset)
462 for (i = 0; i < subset->n_active; i++) {
463 val = subset->active[i];
464 str = talloc_asprintf(subset, "(%d) %s",
465 i, subset->options[val].str);
466 set_field_buffer(subset->options[val].field, 0,
472 static void widget_focus_change(struct nc_widget *widget, FIELD *field,
475 static void subset_delete_active(struct nc_widget_subset *subset, int idx)
477 bool last = idx == (subset->n_active - 1);
478 struct nc_widgetset *set = subset->set;
479 struct nc_widget *widget;
483 /* Shift field focus to nearest active option or next visible field */
484 if (subset->n_active > 1) {
486 val = subset->active[idx - 1];
488 val = subset->active[idx + 1];
489 set->cur_field = subset->options[val].field;
491 for (i = 0; i < set->n_fields; i++)
492 if (field_visible(set->fields[i])) {
493 set->cur_field = set->fields[i];
498 set_current_field(set->form, set->cur_field);
499 widget = field_userptr(set->cur_field);
500 widget_focus_change(widget, set->cur_field, true);
501 if (set->widget_focus)
502 set->widget_focus(widget, set->widget_focus_arg);
504 /* Update active array */
505 rem = sizeof(int) * (subset->n_active - idx - 1);
506 val = subset->active[idx];
507 field_set_visible(subset->options[val].field, false);
509 memmove(&subset->active[idx], &subset->active[idx + 1], rem);
511 subset->active = talloc_realloc(subset, subset->active,
512 int, subset->n_active);
514 subset->widget.height = subset->n_active;
517 static bool subset_process_key(struct nc_widget *w, FORM *form, int key)
519 struct nc_widget_subset *subset = to_subset(w);
520 int i, val, opt_idx = -1;
523 if (!key_is_minus(key) && !key_is_left(key) && !key_is_right(key))
526 field = current_field(form);
528 for (i = 0; i < subset->n_active; i++) {
529 val = subset->active[i];
530 if (subset->options[val].field == field) {
539 if (key_is_minus(key))
540 subset_delete_active(subset, opt_idx);
542 if (key_is_left(key)){
546 val = subset->active[opt_idx];
547 subset->active[opt_idx] = subset->active[opt_idx - 1];
548 subset->active[opt_idx - 1] = val;
551 if (key_is_right(key)){
552 if (opt_idx >= subset->n_active - 1)
555 val = subset->active[opt_idx];
556 subset->active[opt_idx] = subset->active[opt_idx + 1];
557 subset->active[opt_idx + 1] = val;
560 subset_update_order(subset);
562 if (subset->on_change)
563 subset->on_change(subset->on_change_arg, 0);
568 static void subset_set_visible(struct nc_widget *widget, bool visible)
570 struct nc_widget_subset *subset = to_subset(widget);
573 for (i = 0; i < subset->n_active; i++) {
574 val = subset->active[i];
575 field_set_visible(subset->options[val].field, visible);
579 static void subset_move(struct nc_widget *widget, int y, int x)
581 struct nc_widget_subset *subset = to_subset(widget);
584 for (i = 0; i < subset->n_active; i++) {
585 val = subset->active[i];
586 field_move(subset->options[val].field, y + i , x);
590 static void subset_field_focus(struct nc_widget *widget, FIELD *field)
592 struct nc_widget_subset *subset = to_subset(widget);
595 for (i = 0; i < subset->n_active; i++) {
596 val = subset->active[i];
597 if (field == subset->options[val].field) {
604 static int subset_destructor(void *ptr)
606 struct nc_widget_subset *subset = ptr;
609 for (i = 0; i < subset->n_options; i++)
610 free_field(subset->options[i].field);
615 struct nc_widget_subset *widget_new_subset(struct nc_widgetset *set,
616 int y, int x, int len, void *screen_cb)
618 struct nc_widget_subset *subset;
620 subset = talloc_zero(set, struct nc_widget_subset);
621 subset->widget.width = len;
622 subset->widget.height = 0;
623 subset->widget.x = x;
624 subset->widget.y = y;
625 subset->widget.process_key = subset_process_key;
626 subset->widget.set_visible = subset_set_visible;
627 subset->widget.move = subset_move;
628 subset->widget.field_focus = subset_field_focus;
629 subset->widget.focussed_attr = A_REVERSE;
630 subset->widget.unfocussed_attr = A_NORMAL;
635 subset->n_active = subset->n_options = 0;
636 subset->active = NULL;
637 subset->options = NULL;
638 subset->screen_cb = screen_cb;
640 talloc_set_destructor(subset, subset_destructor);
645 void widget_subset_add_option(struct nc_widget_subset *subset, const char *text)
650 i = subset->n_options++;
651 subset->options = talloc_realloc(subset, subset->options,
652 struct subset_option, i + 1);
654 subset->options[i].str = talloc_strdup(subset->options, text);
656 subset->options[i].field = f = new_field(1, subset->size, subset->top + i,
659 field_opts_off(f, O_WRAP | O_EDIT);
660 set_field_userptr(f, &subset->widget);
661 set_field_buffer(f, 0, subset->options[i].str);
662 field_set_visible(f, false);
663 widgetset_add_field(subset->set, f);
666 void widget_subset_make_active(struct nc_widget_subset *subset, int idx)
670 for (i = 0; i < subset->n_active; i++)
671 if (subset->active[i] == idx) {
672 pb_debug("%s: Index %d already active\n", __func__, idx);
676 i = subset->n_active++;
677 subset->widget.height = subset->n_active;
678 subset->active = talloc_realloc(subset, subset->active,
680 subset->active[i] = idx;
682 subset_update_order(subset);
685 int widget_subset_get_order(void *ctx, unsigned int **order,
686 struct nc_widget_subset *subset)
688 unsigned int *buf = talloc_array(ctx, unsigned int, subset->n_active);
691 for (i = 0; i < subset->n_active; i++)
692 buf[i] = subset->active[i];
698 void widget_subset_show_inactive(struct nc_widget_subset *subset,
699 struct nc_widget_select *select)
701 bool active = false, first = true;
704 for (i = 0; i < subset->n_options; i++) {
706 for (j = 0; j < subset->n_active; j++)
707 if (subset->active[j] == i)
713 widget_select_add_option(select, i,
714 subset->options[i].str, first);
720 int widget_subset_n_inactive(struct nc_widget_subset *subset)
722 return subset->n_options - subset->n_active;
725 int widget_subset_height(struct nc_widget_subset *subset)
727 return subset->n_active;
730 void widget_subset_on_change(struct nc_widget_subset *subset,
731 void (*on_change)(void *, int), void *arg)
733 subset->on_change = on_change;
734 subset->on_change_arg = arg;
737 void widget_subset_drop_options(struct nc_widget_subset *subset)
739 struct nc_widgetset *set = subset->set;
742 for (i = 0; i < subset->n_options; i++) {
743 FIELD *field = subset->options[i].field;
744 widgetset_remove_field(set, field);
745 if (field == set->cur_field)
746 set->cur_field = NULL;
747 free_field(subset->options[i].field);
750 talloc_free(subset->options);
751 talloc_free(subset->active);
752 subset->options = NULL;
753 subset->active = NULL;
754 subset->n_options = 0;
755 subset->n_active = 0;
756 subset->widget.height = 0;
757 subset->widget.focus_y = 0;
760 void widget_subset_clear_active(struct nc_widget_subset *subset)
764 for (i = 0; i < subset->n_options; i++)
765 field_set_visible(subset->options[i].field, false);
767 talloc_free(subset->active);
768 subset->active = NULL;
769 subset->n_active = 0;
770 subset->widget.height = 0;
771 subset->widget.focus_y = 0;
774 void widget_subset_callback(void *arg,
775 struct nc_widget_subset *subset, int idx)
777 subset->screen_cb(arg, subset, idx);
780 static void select_option_change(struct select_option *opt, bool selected)
784 str = selected ? select_selected_str : select_unselected_str;
786 memcpy(opt->str, str, strlen(str));
787 set_field_buffer(opt->field, 0, opt->str);
790 static bool select_process_key(struct nc_widget *w, FORM *form, int key)
792 struct nc_widget_select *select = to_select(w);
793 struct select_option *new_opt, *old_opt;
797 if (!key_is_select(key))
800 field = current_field(form);
803 for (i = 0; i < select->n_options; i++) {
804 if (select->options[i].field == field) {
805 new_opt = &select->options[i];
814 if (new_idx == select->selected_option)
817 old_opt = &select->options[select->selected_option];
819 select_option_change(old_opt, false);
820 select_option_change(new_opt, true);
822 select->selected_option = new_idx;
824 if (select->on_change)
825 select->on_change(select->on_change_arg, new_opt->val);
830 static void select_set_visible(struct nc_widget *widget, bool visible)
832 struct nc_widget_select *select = to_select(widget);
835 for (i = 0; i < select->n_options; i++)
836 field_set_visible(select->options[i].field, visible);
839 static void select_move(struct nc_widget *widget, int y, int x)
841 struct nc_widget_select *select = to_select(widget);
844 for (i = 0; i < select->n_options; i++)
845 field_move(select->options[i].field, y + i, x);
848 static void select_field_focus(struct nc_widget *widget, FIELD *field)
850 struct nc_widget_select *select = to_select(widget);
853 for (i = 0; i < select->n_options; i++) {
854 if (field != select->options[i].field)
861 static int select_destructor(void *ptr)
863 struct nc_widget_select *select = ptr;
866 for (i = 0; i < select->n_options; i++)
867 free_field(select->options[i].field);
872 struct nc_widget_select *widget_new_select(struct nc_widgetset *set,
873 int y, int x, int len)
875 struct nc_widget_select *select;
877 select = talloc_zero(set, struct nc_widget_select);
878 select->widget.width = len;
879 select->widget.height = 0;
880 select->widget.x = x;
881 select->widget.y = y;
882 select->widget.process_key = select_process_key;
883 select->widget.set_visible = select_set_visible;
884 select->widget.move = select_move;
885 select->widget.field_focus = select_field_focus;
886 select->widget.focussed_attr = A_REVERSE;
887 select->widget.unfocussed_attr = A_NORMAL;
893 talloc_set_destructor(select, select_destructor);
898 void widget_select_add_option(struct nc_widget_select *select, int value,
899 const char *text, bool selected)
905 /* if we never see an option with selected set, we want the first
906 * one to be selected */
907 if (select->n_options == 0)
910 select_option_change(&select->options[select->selected_option],
914 select->selected_option = select->n_options;
915 str = select_selected_str;
917 str = select_unselected_str;
919 i = select->n_options++;
920 select->widget.height = select->n_options;
922 select->options = talloc_realloc(select, select->options,
923 struct select_option, i + 2);
924 select->options[i].val = value;
925 select->options[i].str = talloc_asprintf(select->options,
928 select->options[i].field = f = new_field(1, select->size,
932 field_opts_off(f, O_WRAP | O_EDIT);
933 set_field_userptr(f, &select->widget);
934 set_field_buffer(f, 0, select->options[i].str);
936 widgetset_add_field(select->set, f);
939 int widget_select_get_value(struct nc_widget_select *select)
941 if (!select->n_options)
943 return select->options[select->selected_option].val;
946 int widget_select_height(struct nc_widget_select *select)
948 return select->n_options;
951 void widget_select_on_change(struct nc_widget_select *select,
952 void (*on_change)(void *, int), void *arg)
954 select->on_change = on_change;
955 select->on_change_arg = arg;
958 void widget_select_drop_options(struct nc_widget_select *select)
960 struct nc_widgetset *set = select->set;
963 for (i = 0; i < select->n_options; i++) {
964 FIELD *field = select->options[i].field;
965 widgetset_remove_field(set, field);
966 if (field == set->cur_field)
967 set->cur_field = NULL;
968 free_field(select->options[i].field);
971 talloc_free(select->options);
972 select->options = NULL;
973 select->n_options = 0;
974 select->widget.height = 0;
975 select->widget.focus_y = 0;
979 static bool button_process_key(struct nc_widget *widget,
980 FORM *form __attribute__((unused)), int key)
982 struct nc_widget_button *button = to_button(widget);
987 if (!key_is_select(key))
990 button->click(button->arg);
994 static int button_destructor(void *ptr)
996 struct nc_widget_button *button = ptr;
997 free_field(button->widget.field);
1001 struct nc_widget_button *widget_new_button(struct nc_widgetset *set,
1002 int y, int x, int size, const char *str,
1003 void (*click)(void *), void *arg)
1005 struct nc_widget_button *button;
1006 int idx, len, pad1, pad2, bufsz;
1010 int field_size = size + 2;
1012 button = talloc_zero(set, struct nc_widget_button);
1013 button->widget.height = 1;
1014 button->widget.width = field_size;
1015 button->widget.x = x;
1016 button->widget.y = y;
1017 button->widget.field = f = new_field(1, field_size, y, x, 0, 0);
1018 button->widget.process_key = button_process_key;
1019 button->widget.focussed_attr = A_REVERSE;
1020 button->widget.unfocussed_attr = A_NORMAL;
1021 button->click = click;
1024 field_opts_off(f, O_EDIT);
1025 set_field_userptr(f, &button->widget);
1027 /* Center str in the field. This depends on the number of columns used
1028 * by the string, not the number of chars in str */
1029 len = strncols(str);
1031 idx = (field_size - len) / 2;
1034 pb_log("Warning: '%s' %d columns wide "
1035 "but button is %d columns wide\n",
1039 pad1 = max(idx - 1, 0);
1040 pad2 = max(size - len - pad1, 0);
1041 bufsz = 1 + pad1 + strlen(str) + pad2 + 2;
1043 text = talloc_array(button, char, bufsz);
1044 memset(text, ' ', bufsz);
1045 memcpy(text + idx, str, strlen(str));
1047 text[bufsz - 2] = ']';
1048 text[bufsz - 1] = '\0';
1050 set_field_buffer(f, 0, text);
1052 widgetset_add_field(set, button->widget.field);
1053 talloc_set_destructor(button, button_destructor);
1058 void widget_focus_change(struct nc_widget *widget, FIELD *field,
1061 int attr = focussed ? widget->focussed_attr : widget->unfocussed_attr;
1062 set_field_back(field, attr);
1065 bool widgetset_process_key(struct nc_widgetset *set, int key)
1067 struct nc_widget *widget;
1072 field = current_field(set->form);
1077 /* handle field change events */
1083 req = REQ_SPREV_FIELD;
1089 req = REQ_SNEXT_FIELD;
1092 req = REQ_SFIRST_FIELD;
1095 req = REQ_SLAST_FIELD;
1099 widget = field_userptr(field);
1101 widget_focus_change(widget, field, false);
1102 form_driver(set->form, req);
1104 /* if we're doing a tabbed-field-change, skip until we
1105 * see the next widget */
1107 field = current_field(set->form);
1109 for (; tab && tmp != field && field_userptr(field) == widget;) {
1110 form_driver(set->form, req);
1111 field = current_field(set->form);
1114 form_driver(set->form, REQ_END_FIELD);
1115 widget = field_userptr(field);
1116 widget_focus_change(widget, field, true);
1117 if (widget->field_focus)
1118 widget->field_focus(widget, field);
1119 if (set->widget_focus)
1120 set->widget_focus(widget, set->widget_focus_arg);
1124 if (!widget->process_key)
1127 return widget->process_key(widget, set->form, key);
1130 static int widgetset_destructor(void *ptr)
1132 struct nc_widgetset *set = ptr;
1133 free_form(set->form);
1134 if (set->ipv4_multi_type)
1135 free_fieldtype(set->ipv4_multi_type);
1139 struct nc_widgetset *widgetset_create(void *ctx, WINDOW *main, WINDOW *sub)
1141 struct nc_widgetset *set;
1143 set = talloc_zero(ctx, struct nc_widgetset);
1144 set->n_alloc_fields = 8;
1145 set->mainwin = main;
1147 set->fields = talloc_array(set, FIELD *, set->n_alloc_fields);
1148 talloc_set_destructor(set, widgetset_destructor);
1153 void widgetset_set_windows(struct nc_widgetset *set,
1154 WINDOW *main, WINDOW *sub)
1156 set->mainwin = main;
1160 void widgetset_set_widget_focus(struct nc_widgetset *set,
1161 widget_focus_cb cb, void *arg)
1163 set->widget_focus = cb;
1164 set->widget_focus_arg = arg;
1167 void widgetset_post(struct nc_widgetset *set)
1169 struct nc_widget *widget;
1172 set->form = new_form(set->fields);
1173 set_form_win(set->form, set->mainwin);
1174 set_form_sub(set->form, set->subwin);
1175 post_form(set->form);
1176 form_driver(set->form, REQ_END_FIELD);
1178 if (set->cur_field) {
1179 set_current_field(set->form, set->cur_field);
1180 field = set->cur_field;
1183 field = current_field(set->form);
1184 widget = field_userptr(field);
1185 widget_focus_change(widget, field, true);
1186 if (set->widget_focus)
1187 set->widget_focus(widget, set->widget_focus_arg);
1190 void widgetset_unpost(struct nc_widgetset *set)
1192 set->cur_field = current_field(set->form);
1193 unpost_form(set->form);
1194 free_form(set->form);
1198 static void widgetset_add_field(struct nc_widgetset *set, FIELD *field)
1200 if (set->n_fields == set->n_alloc_fields - 1) {
1201 set->n_alloc_fields *= 2;
1202 set->fields = talloc_realloc(set, set->fields,
1203 FIELD *, set->n_alloc_fields);
1207 set->fields[set->n_fields - 1] = field;
1208 set->fields[set->n_fields] = NULL;
1211 static void widgetset_remove_field(struct nc_widgetset *set, FIELD *field)
1215 for (i = 0; i < set->n_fields; i++) {
1216 if (set->fields[i] == field)
1220 if (i == set->n_fields)
1223 memmove(&set->fields[i], &set->fields[i+i],
1224 (set->n_fields - i) * sizeof(set->fields[i]));
1228 #define DECLARE_BASEFN(type) \
1229 struct nc_widget *widget_ ## type ## _base \
1230 (struct nc_widget_ ## type *w) \
1231 { return &w->widget; }
1233 DECLARE_BASEFN(textbox);
1234 DECLARE_BASEFN(checkbox);
1235 DECLARE_BASEFN(subset);
1236 DECLARE_BASEFN(select);
1237 DECLARE_BASEFN(label);
1238 DECLARE_BASEFN(button);
1240 void widget_set_visible(struct nc_widget *widget, bool visible)
1242 if (widget->set_visible)
1243 widget->set_visible(widget, visible);
1245 field_set_visible(widget->field, visible);
1248 void widget_move(struct nc_widget *widget, int y, int x)
1251 widget->move(widget, y, x);
1253 field_move(widget->field, y, x);
1258 if (x + widget->width > COLS)
1259 pb_debug("%s: Widget at %d,%d runs over pad! (%d)", __func__,
1260 y, x, x + widget->width);
1263 int widget_height(struct nc_widget *widget)
1265 return widget->height;
1268 int widget_width(struct nc_widget *widget)
1270 return widget->width;
1273 int widget_x(struct nc_widget *widget)
1278 int widget_y(struct nc_widget *widget)
1283 int widget_focus_y(struct nc_widget *widget)
1285 return widget->focus_y;