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>
55 #include <fold/fold.h>
59 #include "nc-widgets.h"
63 #define to_checkbox(w) container_of(w, struct nc_widget_checkbox, widget)
64 #define to_textbox(w) container_of(w, struct nc_widget_textbox, widget)
65 #define to_button(w) container_of(w, struct nc_widget_button, widget)
66 #define to_select(w) container_of(w, struct nc_widget_select, widget)
67 #define to_subset(w) container_of(w, struct nc_widget_subset, widget)
69 static const char *checkbox_checked_str = "[*]";
70 static const char *checkbox_unchecked_str = "[ ]";
72 static const char *select_selected_str = "(*)";
73 static const char *select_unselected_str = "( )";
80 int n_fields, n_alloc_fields;
81 void (*widget_focus)(struct nc_widget *, void *);
82 void *widget_focus_arg;
85 /* custom validators */
86 FIELDTYPE *ipv4_multi_type;
92 bool (*process_key)(struct nc_widget *, FORM *, int);
93 void (*set_visible)(struct nc_widget *, bool);
94 void (*move)(struct nc_widget *, int, int);
95 void (*field_focus)(struct nc_widget *, FIELD *);
105 struct nc_widget_label {
106 struct nc_widget widget;
110 struct nc_widget_checkbox {
111 struct nc_widget widget;
115 struct nc_widget_textbox {
116 struct nc_widgetset *set;
117 struct nc_widget widget;
120 struct nc_widget_subset {
121 struct nc_widget widget;
124 struct subset_option {
131 struct nc_widgetset *set;
132 void (*on_change)(void *, int);
134 void (*screen_cb)(void *,
135 struct nc_widget_subset *, int);
138 struct nc_widget_select {
139 struct nc_widget widget;
140 struct select_option {
147 int n_options, selected_option;
148 struct nc_widgetset *set;
149 void (*on_change)(void *, int);
153 struct nc_widget_button {
154 struct nc_widget widget;
155 void (*click)(void *arg);
159 static void widgetset_add_field(struct nc_widgetset *set, FIELD *field);
160 static void widgetset_remove_field(struct nc_widgetset *set, FIELD *field);
162 static bool key_is_select(int key)
164 return key == ' ' || key == '\r' || key == '\n' || key == KEY_ENTER;
167 static bool process_key_nop(struct nc_widget *widget __attribute__((unused)),
168 FORM *form __attribute((unused)),
169 int key __attribute__((unused)))
174 static void field_set_visible(FIELD *field, bool visible)
176 int opts = field_opts(field) & ~O_VISIBLE;
179 set_field_opts(field, opts);
182 static bool field_visible(FIELD *field)
184 return (field_opts(field) & O_VISIBLE) == O_VISIBLE;
187 static void field_move(FIELD *field, int y, int x)
189 move_field(field, y, x);
192 static int label_destructor(void *ptr)
194 struct nc_widget_label *label = ptr;
195 free_field(label->widget.field);
200 struct nc_widget_label *widget_new_label(struct nc_widgetset *set,
201 int y, int x, char *str)
203 struct nc_widget_label *label;
209 label = talloc_zero(set, struct nc_widget_label);
210 label->widget.height = 1;
211 label->widget.width = len;
214 label->widget.process_key = process_key_nop;
215 label->widget.field = f = new_field(1, len, y, x, 0, 0);
216 label->widget.focussed_attr = A_NORMAL;
217 label->widget.unfocussed_attr = A_NORMAL;
219 field_opts_off(f, O_ACTIVE);
220 set_field_buffer(f, 0, str);
221 set_field_userptr(f, &label->widget);
223 widgetset_add_field(set, label->widget.field);
224 talloc_set_destructor(label, label_destructor);
229 bool widget_checkbox_get_value(struct nc_widget_checkbox *checkbox)
231 return checkbox->checked;
234 static void checkbox_set_buffer(struct nc_widget_checkbox *checkbox)
237 str = checkbox->checked ? checkbox_checked_str : checkbox_unchecked_str;
238 set_field_buffer(checkbox->widget.field, 0, str);
241 static bool checkbox_process_key(struct nc_widget *widget,
242 FORM *form __attribute__((unused)), int key)
244 struct nc_widget_checkbox *checkbox = to_checkbox(widget);
246 if (!key_is_select(key))
249 checkbox->checked = !checkbox->checked;
250 checkbox_set_buffer(checkbox);
255 static int checkbox_destructor(void *ptr)
257 struct nc_widget_checkbox *checkbox = ptr;
258 free_field(checkbox->widget.field);
262 struct nc_widget_checkbox *widget_new_checkbox(struct nc_widgetset *set,
263 int y, int x, bool checked)
265 struct nc_widget_checkbox *checkbox;
268 checkbox = talloc_zero(set, struct nc_widget_checkbox);
269 checkbox->checked = checked;
270 checkbox->widget.height = 1;
271 checkbox->widget.width = strlen(checkbox_checked_str);
272 checkbox->widget.x = x;
273 checkbox->widget.y = y;
274 checkbox->widget.process_key = checkbox_process_key;
275 checkbox->widget.focussed_attr = A_REVERSE;
276 checkbox->widget.unfocussed_attr = A_NORMAL;
277 checkbox->widget.field = f = new_field(1, strlen(checkbox_checked_str),
280 field_opts_off(f, O_EDIT);
281 set_field_userptr(f, &checkbox->widget);
282 checkbox_set_buffer(checkbox);
284 widgetset_add_field(set, checkbox->widget.field);
285 talloc_set_destructor(checkbox, checkbox_destructor);
290 static char *strip_string(char *str)
296 /* clear trailing space */
297 for (i = len - 1; i >= 0; i--) {
298 if (!isspace(str[i]))
303 /* increment str past leading space */
304 for (i = 0; i < len; i++) {
305 if (str[i] == '\0' || !isspace(str[i]))
312 char *widget_textbox_get_value(struct nc_widget_textbox *textbox)
314 char *str = field_buffer(textbox->widget.field, 0);
315 return str ? strip_string(str) : NULL;
318 static bool textbox_process_key(
319 struct nc_widget *widget __attribute__((unused)),
324 form_driver(form, REQ_BEG_FIELD);
327 form_driver(form, REQ_END_FIELD);
330 form_driver(form, REQ_LEFT_CHAR);
333 form_driver(form, REQ_RIGHT_CHAR);
336 if (form_driver(form, REQ_LEFT_CHAR) != E_OK)
340 form_driver(form, REQ_DEL_CHAR);
348 /* Don't catch navigational keys */
351 form_driver(form, key);
358 static int textbox_destructor(void *ptr)
360 struct nc_widget_textbox *textbox = ptr;
361 free_field(textbox->widget.field);
365 struct nc_widget_textbox *widget_new_textbox(struct nc_widgetset *set,
366 int y, int x, int len, char *str)
368 struct nc_widget_textbox *textbox;
371 textbox = talloc_zero(set, struct nc_widget_textbox);
373 textbox->widget.height = 1;
374 textbox->widget.width = len;
375 textbox->widget.x = x;
376 textbox->widget.y = y;
377 textbox->widget.process_key = textbox_process_key;
378 textbox->widget.field = f = new_field(1, len, y, x, 0, 0);
379 textbox->widget.focussed_attr = A_REVERSE;
380 textbox->widget.unfocussed_attr = A_UNDERLINE;
382 field_opts_off(f, O_STATIC | O_WRAP | O_BLANK);
383 set_field_buffer(f, 0, str);
384 set_field_back(f, textbox->widget.unfocussed_attr);
385 set_field_userptr(f, &textbox->widget);
387 widgetset_add_field(set, textbox->widget.field);
388 talloc_set_destructor(textbox, textbox_destructor);
393 void widget_textbox_set_fixed_size(struct nc_widget_textbox *textbox)
395 field_opts_on(textbox->widget.field, O_STATIC);
398 void widget_textbox_set_validator_integer(struct nc_widget_textbox *textbox,
401 set_field_type(textbox->widget.field, TYPE_INTEGER, 1, min, max);
404 static bool check_url_field(FIELD *field,
405 const void *arg __attribute__((unused)))
407 return is_url(field_buffer(field, 0));
410 void widget_textbox_set_validator_url(struct nc_widget_textbox *textbox)
412 if (!textbox->set->url_type)
413 textbox->set->url_type = new_fieldtype(check_url_field, NULL);
415 set_field_type(textbox->widget.field, textbox->set->url_type);
418 void widget_textbox_set_validator_ipv4(struct nc_widget_textbox *textbox)
420 set_field_type(textbox->widget.field, TYPE_IPV4);
423 static bool check_ipv4_multi_char(int c,
424 const void *arg __attribute__((unused)))
426 return isdigit(c) || c == '.' || c == ' ';
429 static bool check_ipv4_multi_field(FIELD *field,
430 const void *arg __attribute__((unused)))
432 char *buf = field_buffer(field, 0);
436 while (*buf != '\0') {
437 n = sscanf(buf, "%u.%u.%u.%u%n",
438 &ip[0], &ip[1], &ip[2], &ip[3], &len);
442 if (ip[0] > 255 || ip[1] > 255 || ip[2] > 255 || ip[3] > 255)
445 for (buf += len; *buf != '\0'; buf++) {
448 else if (isdigit(*buf))
458 void widget_textbox_set_validator_ipv4_multi(struct nc_widget_textbox *textbox)
460 if (!textbox->set->ipv4_multi_type) {
461 textbox->set->ipv4_multi_type = new_fieldtype(
462 check_ipv4_multi_field,
463 check_ipv4_multi_char);
465 set_field_type(textbox->widget.field, textbox->set->ipv4_multi_type);
468 static void subset_update_order(struct nc_widget_subset *subset)
473 for (i = 0; i < subset->n_active; i++) {
474 val = subset->active[i];
475 str = talloc_asprintf(subset, "(%d) %s",
476 i, subset->options[val].str);
477 set_field_buffer(subset->options[val].field, 0,
483 static void widget_focus_change(struct nc_widget *widget, FIELD *field,
486 static void subset_delete_active(struct nc_widget_subset *subset, int idx)
488 bool last = idx == (subset->n_active - 1);
489 struct nc_widgetset *set = subset->set;
490 struct nc_widget *widget;
495 /* Shift field focus to nearest active option or next visible field */
496 if (subset->n_active > 1) {
498 val = subset->active[idx - 1];
500 val = subset->active[idx + 1];
501 set->cur_field = subset->options[val].field;
503 for (i = 0; i < set->n_fields; i++)
504 if (field_visible(set->fields[i])) {
505 opts = field_opts(set->fields[i]);
506 if ((opts & O_ACTIVE) == O_ACTIVE) {
507 set->cur_field = set->fields[i];
513 set_current_field(set->form, set->cur_field);
514 widget = field_userptr(set->cur_field);
515 widget_focus_change(widget, set->cur_field, true);
516 if (set->widget_focus)
517 set->widget_focus(widget, set->widget_focus_arg);
519 /* Update active array */
520 rem = sizeof(int) * (subset->n_active - idx - 1);
521 val = subset->active[idx];
522 field_set_visible(subset->options[val].field, false);
524 memmove(&subset->active[idx], &subset->active[idx + 1], rem);
526 subset->active = talloc_realloc(subset, subset->active,
527 int, subset->n_active);
529 subset->widget.height = subset->n_active;
532 static bool subset_process_key(struct nc_widget *w, FORM *form, int key)
534 struct nc_widget_subset *subset = to_subset(w);
535 int i, val, opt_idx = -1;
538 if (key != '-' && key != '+' && key != KEY_DC && key != KEY_BACKSPACE)
541 field = current_field(form);
543 for (i = 0; i < subset->n_active; i++) {
544 val = subset->active[i];
545 if (subset->options[val].field == field) {
554 if (key == KEY_DC || key == KEY_BACKSPACE)
555 subset_delete_active(subset, opt_idx);
561 val = subset->active[opt_idx];
562 subset->active[opt_idx] = subset->active[opt_idx - 1];
563 subset->active[opt_idx - 1] = val;
567 if (opt_idx >= subset->n_active - 1)
570 val = subset->active[opt_idx];
571 subset->active[opt_idx] = subset->active[opt_idx + 1];
572 subset->active[opt_idx + 1] = val;
575 subset_update_order(subset);
577 if (subset->on_change)
578 subset->on_change(subset->on_change_arg, 0);
583 static void subset_set_visible(struct nc_widget *widget, bool visible)
585 struct nc_widget_subset *subset = to_subset(widget);
588 for (i = 0; i < subset->n_active; i++) {
589 val = subset->active[i];
590 field_set_visible(subset->options[val].field, visible);
594 static void subset_move(struct nc_widget *widget, int y, int x)
596 struct nc_widget_subset *subset = to_subset(widget);
599 for (i = 0; i < subset->n_active; i++) {
600 val = subset->active[i];
601 field_move(subset->options[val].field, y + i , x);
605 static void subset_field_focus(struct nc_widget *widget, FIELD *field)
607 struct nc_widget_subset *subset = to_subset(widget);
610 for (i = 0; i < subset->n_active; i++) {
611 val = subset->active[i];
612 if (field == subset->options[val].field) {
619 static int subset_destructor(void *ptr)
621 struct nc_widget_subset *subset = ptr;
624 for (i = 0; i < subset->n_options; i++)
625 free_field(subset->options[i].field);
630 struct nc_widget_subset *widget_new_subset(struct nc_widgetset *set,
631 int y, int x, int len, void *screen_cb)
633 struct nc_widget_subset *subset;
635 subset = talloc_zero(set, struct nc_widget_subset);
636 subset->widget.width = len;
637 subset->widget.height = 0;
638 subset->widget.x = x;
639 subset->widget.y = y;
640 subset->widget.process_key = subset_process_key;
641 subset->widget.set_visible = subset_set_visible;
642 subset->widget.move = subset_move;
643 subset->widget.field_focus = subset_field_focus;
644 subset->widget.focussed_attr = A_REVERSE;
645 subset->widget.unfocussed_attr = A_NORMAL;
650 subset->n_active = subset->n_options = 0;
651 subset->active = NULL;
652 subset->options = NULL;
653 subset->screen_cb = screen_cb;
655 talloc_set_destructor(subset, subset_destructor);
660 void widget_subset_add_option(struct nc_widget_subset *subset, const char *text)
665 i = subset->n_options++;
666 subset->options = talloc_realloc(subset, subset->options,
667 struct subset_option, i + 1);
669 subset->options[i].str = talloc_strdup(subset->options, text);
671 subset->options[i].field = f = new_field(1, subset->size, subset->top + i,
674 field_opts_off(f, O_WRAP | O_EDIT);
675 set_field_userptr(f, &subset->widget);
676 set_field_buffer(f, 0, subset->options[i].str);
677 field_set_visible(f, false);
678 widgetset_add_field(subset->set, f);
681 void widget_subset_make_active(struct nc_widget_subset *subset, int idx)
685 for (i = 0; i < subset->n_active; i++)
686 if (subset->active[i] == idx) {
687 pb_debug("%s: Index %d already active\n", __func__, idx);
691 i = subset->n_active++;
692 subset->widget.height = subset->n_active;
693 subset->active = talloc_realloc(subset, subset->active,
695 subset->active[i] = idx;
697 subset_update_order(subset);
700 int widget_subset_get_order(void *ctx, unsigned int **order,
701 struct nc_widget_subset *subset)
703 unsigned int *buf = talloc_array(ctx, unsigned int, subset->n_active);
706 for (i = 0; i < subset->n_active; i++)
707 buf[i] = subset->active[i];
713 void widget_subset_show_inactive(struct nc_widget_subset *subset,
714 struct nc_widget_select *select)
716 bool active = false, first = true;
719 for (i = 0; i < subset->n_options; i++) {
721 for (j = 0; j < subset->n_active; j++)
722 if (subset->active[j] == i)
728 widget_select_add_option(select, i,
729 subset->options[i].str, first);
735 int widget_subset_n_inactive(struct nc_widget_subset *subset)
737 return subset->n_options - subset->n_active;
740 int widget_subset_height(struct nc_widget_subset *subset)
742 return subset->n_active;
745 void widget_subset_on_change(struct nc_widget_subset *subset,
746 void (*on_change)(void *, int), void *arg)
748 subset->on_change = on_change;
749 subset->on_change_arg = arg;
752 void widget_subset_drop_options(struct nc_widget_subset *subset)
754 struct nc_widgetset *set = subset->set;
757 for (i = 0; i < subset->n_options; i++) {
758 FIELD *field = subset->options[i].field;
759 widgetset_remove_field(set, field);
760 if (field == set->cur_field)
761 set->cur_field = NULL;
762 free_field(subset->options[i].field);
765 talloc_free(subset->options);
766 talloc_free(subset->active);
767 subset->options = NULL;
768 subset->active = NULL;
769 subset->n_options = 0;
770 subset->n_active = 0;
771 subset->widget.height = 0;
772 subset->widget.focus_y = 0;
775 void widget_subset_clear_active(struct nc_widget_subset *subset)
779 for (i = 0; i < subset->n_options; i++)
780 field_set_visible(subset->options[i].field, false);
782 talloc_free(subset->active);
783 subset->active = NULL;
784 subset->n_active = 0;
785 subset->widget.height = 0;
786 subset->widget.focus_y = 0;
789 void widget_subset_callback(void *arg,
790 struct nc_widget_subset *subset, int idx)
792 subset->screen_cb(arg, subset, idx);
795 static void select_option_change(struct select_option *opt, bool selected)
799 str = selected ? select_selected_str : select_unselected_str;
801 memcpy(opt->str, str, strlen(str));
802 set_field_buffer(opt->field, 0, opt->str);
805 static bool select_process_key(struct nc_widget *w, FORM *form, int key)
807 struct nc_widget_select *select = to_select(w);
808 struct select_option *new_opt, *old_opt;
812 if (!key_is_select(key))
815 field = current_field(form);
818 for (i = 0; i < select->n_options; i++) {
819 if (select->options[i].field == field) {
820 new_opt = &select->options[i];
829 if (new_idx == select->selected_option)
832 old_opt = &select->options[select->selected_option];
834 select_option_change(old_opt, false);
835 select_option_change(new_opt, true);
837 select->selected_option = new_idx;
839 if (select->on_change)
840 select->on_change(select->on_change_arg, new_opt->val);
845 static void select_set_visible(struct nc_widget *widget, bool visible)
847 struct nc_widget_select *select = to_select(widget);
850 for (i = 0; i < select->n_options; i++)
851 field_set_visible(select->options[i].field, visible);
854 static void select_move(struct nc_widget *widget, int y, int x)
856 struct nc_widget_select *select = to_select(widget);
859 for (i = 0; i < select->n_options; i++) {
860 field_move(select->options[i].field, y + cur, x);
861 cur += select->options[i].lines;
865 static void select_field_focus(struct nc_widget *widget, FIELD *field)
867 struct nc_widget_select *select = to_select(widget);
870 for (i = 0; i < select->n_options; i++) {
871 if (field != select->options[i].field) {
872 cur += select->options[i].lines;
875 widget->focus_y = cur;
880 static int select_destructor(void *ptr)
882 struct nc_widget_select *select = ptr;
885 for (i = 0; i < select->n_options; i++)
886 free_field(select->options[i].field);
891 struct nc_widget_select *widget_new_select(struct nc_widgetset *set,
892 int y, int x, int len)
894 struct nc_widget_select *select;
896 select = talloc_zero(set, struct nc_widget_select);
897 select->widget.width = len;
898 select->widget.height = 0;
899 select->widget.x = x;
900 select->widget.y = y;
901 select->widget.process_key = select_process_key;
902 select->widget.set_visible = select_set_visible;
903 select->widget.move = select_move;
904 select->widget.field_focus = select_field_focus;
905 select->widget.focussed_attr = A_REVERSE;
906 select->widget.unfocussed_attr = A_NORMAL;
912 talloc_set_destructor(select, select_destructor);
917 static int widget_select_fold_cb(void *arg, const char *buf, int len)
919 struct nc_widget_select *select = arg;
920 char *line, *newstr, *padbuf = NULL;
926 line = talloc_strndup(select->options, buf, len);
928 i = select->n_options - 1;
929 pad = max(0, select->widget.width - strncols(line));
932 padbuf = talloc_array(select->options, char, pad + 1);
933 memset(padbuf, ' ', pad);
937 if (select->options[i].str)
938 newstr = talloc_asprintf_append(select->options[i].str,
942 newstr = talloc_asprintf(select->options, "%s%s", line,
945 select->options[i].str = newstr;
946 select->options[i].lines++;
953 void widget_select_add_option(struct nc_widget_select *select, int value,
954 const char *text, bool selected)
961 /* if we never see an option with selected set, we want the first
962 * one to be selected */
963 if (select->n_options == 0)
966 select_option_change(&select->options[select->selected_option],
970 select->selected_option = select->n_options;
971 str = select_selected_str;
973 str = select_unselected_str;
975 i = select->n_options++;
976 select->options = talloc_realloc(select, select->options,
977 struct select_option, i + 2);
978 select->options[i].val = value;
979 select->options[i].lines = 0;
980 select->options[i].str = NULL;
982 full_text = talloc_asprintf(select->options, "%s %s", str, text);
983 fold_text(full_text, select->widget.width,
984 widget_select_fold_cb, select);
986 select->options[i].field = f = new_field(select->options[i].lines,
988 select->top + select->widget.height,
991 select->widget.height += select->options[i].lines;
993 field_opts_off(f, O_EDIT);
994 set_field_userptr(f, &select->widget);
995 set_field_buffer(f, 0, select->options[i].str);
997 widgetset_add_field(select->set, f);
998 talloc_free(full_text);
1001 int widget_select_get_value(struct nc_widget_select *select)
1003 if (!select->n_options)
1005 return select->options[select->selected_option].val;
1008 int widget_select_height(struct nc_widget_select *select)
1010 return select->widget.height;
1013 void widget_select_on_change(struct nc_widget_select *select,
1014 void (*on_change)(void *, int), void *arg)
1016 select->on_change = on_change;
1017 select->on_change_arg = arg;
1020 void widget_select_drop_options(struct nc_widget_select *select)
1022 struct nc_widgetset *set = select->set;
1025 for (i = 0; i < select->n_options; i++) {
1026 FIELD *field = select->options[i].field;
1027 widgetset_remove_field(set, field);
1028 if (field == set->cur_field)
1029 set->cur_field = NULL;
1030 free_field(select->options[i].field);
1033 talloc_free(select->options);
1034 select->options = NULL;
1035 select->n_options = 0;
1036 select->widget.height = 0;
1037 select->widget.focus_y = 0;
1041 static bool button_process_key(struct nc_widget *widget,
1042 FORM *form __attribute__((unused)), int key)
1044 struct nc_widget_button *button = to_button(widget);
1049 if (!key_is_select(key))
1052 button->click(button->arg);
1056 static int button_destructor(void *ptr)
1058 struct nc_widget_button *button = ptr;
1059 free_field(button->widget.field);
1063 struct nc_widget_button *widget_new_button(struct nc_widgetset *set,
1064 int y, int x, int size, const char *str,
1065 void (*click)(void *), void *arg)
1067 struct nc_widget_button *button;
1068 int idx, len, pad1, pad2, bufsz;
1072 int field_size = size + 2;
1074 button = talloc_zero(set, struct nc_widget_button);
1075 button->widget.height = 1;
1076 button->widget.width = field_size;
1077 button->widget.x = x;
1078 button->widget.y = y;
1079 button->widget.field = f = new_field(1, field_size, y, x, 0, 0);
1080 button->widget.process_key = button_process_key;
1081 button->widget.focussed_attr = A_REVERSE;
1082 button->widget.unfocussed_attr = A_NORMAL;
1083 button->click = click;
1086 field_opts_off(f, O_EDIT);
1087 set_field_userptr(f, &button->widget);
1089 /* Center str in the field. This depends on the number of columns used
1090 * by the string, not the number of chars in str */
1091 len = strncols(str);
1093 idx = (field_size - len) / 2;
1096 pb_log("Warning: '%s' %d columns wide "
1097 "but button is %d columns wide\n",
1101 pad1 = max(idx - 1, 0);
1102 pad2 = max(size - len - pad1, 0);
1103 bufsz = 1 + pad1 + strlen(str) + pad2 + 2;
1105 text = talloc_array(button, char, bufsz);
1106 memset(text, ' ', bufsz);
1107 memcpy(text + idx, str, strlen(str));
1109 text[bufsz - 2] = ']';
1110 text[bufsz - 1] = '\0';
1112 set_field_buffer(f, 0, text);
1114 widgetset_add_field(set, button->widget.field);
1115 talloc_set_destructor(button, button_destructor);
1120 void widget_focus_change(struct nc_widget *widget, FIELD *field,
1123 int attr = focussed ? widget->focussed_attr : widget->unfocussed_attr;
1124 set_field_back(field, attr);
1127 bool widgetset_process_key(struct nc_widgetset *set, int key)
1129 struct nc_widget *widget;
1134 field = current_field(set->form);
1137 widget = field_userptr(field);
1139 if (widget->process_key)
1140 if (widget->process_key(widget, set->form, key))
1145 /* handle field change events */
1151 req = REQ_SPREV_FIELD;
1157 req = REQ_SNEXT_FIELD;
1160 req = REQ_SFIRST_FIELD;
1163 req = REQ_SLAST_FIELD;
1166 req = REQ_LEFT_FIELD;
1169 req = REQ_RIGHT_FIELD;
1174 widget_focus_change(widget, field, false);
1175 form_driver(set->form, req);
1177 /* if we're doing a tabbed-field-change, skip until we
1178 * see the next widget */
1180 field = current_field(set->form);
1182 for (; tab && tmp != field && field_userptr(field) == widget;) {
1183 form_driver(set->form, req);
1184 field = current_field(set->form);
1187 form_driver(set->form, REQ_END_FIELD);
1188 widget = field_userptr(field);
1189 widget_focus_change(widget, field, true);
1190 if (widget->field_focus)
1191 widget->field_focus(widget, field);
1192 if (set->widget_focus)
1193 set->widget_focus(widget, set->widget_focus_arg);
1200 static int widgetset_destructor(void *ptr)
1202 struct nc_widgetset *set = ptr;
1203 free_form(set->form);
1204 if (set->ipv4_multi_type)
1205 free_fieldtype(set->ipv4_multi_type);
1209 struct nc_widgetset *widgetset_create(void *ctx, WINDOW *main, WINDOW *sub)
1211 struct nc_widgetset *set;
1213 set = talloc_zero(ctx, struct nc_widgetset);
1214 set->n_alloc_fields = 8;
1215 set->mainwin = main;
1217 set->fields = talloc_array(set, FIELD *, set->n_alloc_fields);
1218 talloc_set_destructor(set, widgetset_destructor);
1223 void widgetset_set_windows(struct nc_widgetset *set,
1224 WINDOW *main, WINDOW *sub)
1226 set->mainwin = main;
1230 void widgetset_set_widget_focus(struct nc_widgetset *set,
1231 widget_focus_cb cb, void *arg)
1233 set->widget_focus = cb;
1234 set->widget_focus_arg = arg;
1237 void widgetset_post(struct nc_widgetset *set)
1239 struct nc_widget *widget;
1242 set->form = new_form(set->fields);
1243 set_form_win(set->form, set->mainwin);
1244 set_form_sub(set->form, set->subwin);
1245 post_form(set->form);
1246 form_driver(set->form, REQ_END_FIELD);
1249 set_current_field(set->form, set->cur_field);
1251 field = current_field(set->form);
1252 widget = field_userptr(field);
1253 widget_focus_change(widget, field, true);
1254 if (set->widget_focus)
1255 set->widget_focus(widget, set->widget_focus_arg);
1258 void widgetset_unpost(struct nc_widgetset *set)
1260 set->cur_field = current_field(set->form);
1261 unpost_form(set->form);
1262 free_form(set->form);
1266 static void widgetset_add_field(struct nc_widgetset *set, FIELD *field)
1268 if (set->n_fields == set->n_alloc_fields - 1) {
1269 set->n_alloc_fields *= 2;
1270 set->fields = talloc_realloc(set, set->fields,
1271 FIELD *, set->n_alloc_fields);
1275 set->fields[set->n_fields - 1] = field;
1276 set->fields[set->n_fields] = NULL;
1279 static void widgetset_remove_field(struct nc_widgetset *set, FIELD *field)
1283 for (i = 0; i < set->n_fields; i++) {
1284 if (set->fields[i] == field)
1288 if (i == set->n_fields)
1291 memmove(&set->fields[i], &set->fields[i+i],
1292 (set->n_fields - i) * sizeof(set->fields[i]));
1296 #define DECLARE_BASEFN(type) \
1297 struct nc_widget *widget_ ## type ## _base \
1298 (struct nc_widget_ ## type *w) \
1299 { return &w->widget; }
1301 DECLARE_BASEFN(textbox);
1302 DECLARE_BASEFN(checkbox);
1303 DECLARE_BASEFN(subset);
1304 DECLARE_BASEFN(select);
1305 DECLARE_BASEFN(label);
1306 DECLARE_BASEFN(button);
1308 void widget_set_visible(struct nc_widget *widget, bool visible)
1310 if (widget->set_visible)
1311 widget->set_visible(widget, visible);
1313 field_set_visible(widget->field, visible);
1316 void widget_move(struct nc_widget *widget, int y, int x)
1319 widget->move(widget, y, x);
1321 field_move(widget->field, y, x);
1326 if (x + widget->width > COLS)
1327 pb_debug("%s: Widget at %d,%d runs over pad! (%d)", __func__,
1328 y, x, x + widget->width);
1331 int widget_height(struct nc_widget *widget)
1333 return widget->height;
1336 int widget_width(struct nc_widget *widget)
1338 return widget->width;
1341 int widget_x(struct nc_widget *widget)
1346 int widget_y(struct nc_widget *widget)
1351 int widget_focus_y(struct nc_widget *widget)
1353 return widget->focus_y;