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>
58 #include "nc-widgets.h"
62 #define to_checkbox(w) container_of(w, struct nc_widget_checkbox, widget)
63 #define to_textbox(w) container_of(w, struct nc_widget_textbox, widget)
64 #define to_button(w) container_of(w, struct nc_widget_button, widget)
65 #define to_select(w) container_of(w, struct nc_widget_select, widget)
66 #define to_subset(w) container_of(w, struct nc_widget_subset, widget)
68 static const char *checkbox_checked_str = "[*]";
69 static const char *checkbox_unchecked_str = "[ ]";
71 static const char *select_selected_str = "(*)";
72 static const char *select_unselected_str = "( )";
79 int n_fields, n_alloc_fields;
80 void (*widget_focus)(struct nc_widget *, void *);
81 void *widget_focus_arg;
84 /* custom validators */
85 FIELDTYPE *ipv4_multi_type;
90 bool (*process_key)(struct nc_widget *, FORM *, int);
91 void (*set_visible)(struct nc_widget *, bool);
92 void (*move)(struct nc_widget *, int, int);
93 void (*field_focus)(struct nc_widget *, FIELD *);
103 struct nc_widget_label {
104 struct nc_widget widget;
108 struct nc_widget_checkbox {
109 struct nc_widget widget;
113 struct nc_widget_textbox {
114 struct nc_widgetset *set;
115 struct nc_widget widget;
118 struct nc_widget_subset {
119 struct nc_widget widget;
122 struct subset_option {
129 struct nc_widgetset *set;
130 void (*on_change)(void *, int);
132 void (*screen_cb)(void *,
133 struct nc_widget_subset *, int);
136 struct nc_widget_select {
137 struct nc_widget widget;
138 struct select_option {
145 int n_options, selected_option;
146 struct nc_widgetset *set;
147 void (*on_change)(void *, int);
151 struct nc_widget_button {
152 struct nc_widget widget;
153 void (*click)(void *arg);
157 static void widgetset_add_field(struct nc_widgetset *set, FIELD *field);
158 static void widgetset_remove_field(struct nc_widgetset *set, FIELD *field);
160 static bool key_is_select(int key)
162 return key == ' ' || key == '\r' || key == '\n' || key == KEY_ENTER;
165 static bool key_is_minus(int key)
170 static bool key_is_left(int key)
172 return key == KEY_LEFT;
175 static bool key_is_right(int key)
177 return key == KEY_RIGHT;
180 static bool process_key_nop(struct nc_widget *widget __attribute__((unused)),
181 FORM *form __attribute((unused)),
182 int key __attribute__((unused)))
187 static void field_set_visible(FIELD *field, bool visible)
189 int opts = field_opts(field) & ~O_VISIBLE;
192 set_field_opts(field, opts);
195 static bool field_visible(FIELD *field)
197 return (field_opts(field) & O_VISIBLE) == O_VISIBLE;
200 static void field_move(FIELD *field, int y, int x)
202 move_field(field, y, x);
205 static int label_destructor(void *ptr)
207 struct nc_widget_label *label = ptr;
208 free_field(label->widget.field);
213 struct nc_widget_label *widget_new_label(struct nc_widgetset *set,
214 int y, int x, char *str)
216 struct nc_widget_label *label;
222 label = talloc_zero(set, struct nc_widget_label);
223 label->widget.height = 1;
224 label->widget.width = len;
227 label->widget.process_key = process_key_nop;
228 label->widget.field = f = new_field(1, len, y, x, 0, 0);
229 label->widget.focussed_attr = A_NORMAL;
230 label->widget.unfocussed_attr = A_NORMAL;
232 field_opts_off(f, O_ACTIVE);
233 set_field_buffer(f, 0, str);
234 set_field_userptr(f, &label->widget);
236 widgetset_add_field(set, label->widget.field);
237 talloc_set_destructor(label, label_destructor);
242 bool widget_checkbox_get_value(struct nc_widget_checkbox *checkbox)
244 return checkbox->checked;
247 static void checkbox_set_buffer(struct nc_widget_checkbox *checkbox)
250 str = checkbox->checked ? checkbox_checked_str : checkbox_unchecked_str;
251 set_field_buffer(checkbox->widget.field, 0, str);
254 static bool checkbox_process_key(struct nc_widget *widget,
255 FORM *form __attribute__((unused)), int key)
257 struct nc_widget_checkbox *checkbox = to_checkbox(widget);
259 if (!key_is_select(key))
262 checkbox->checked = !checkbox->checked;
263 checkbox_set_buffer(checkbox);
268 static int checkbox_destructor(void *ptr)
270 struct nc_widget_checkbox *checkbox = ptr;
271 free_field(checkbox->widget.field);
275 struct nc_widget_checkbox *widget_new_checkbox(struct nc_widgetset *set,
276 int y, int x, bool checked)
278 struct nc_widget_checkbox *checkbox;
281 checkbox = talloc_zero(set, struct nc_widget_checkbox);
282 checkbox->checked = checked;
283 checkbox->widget.height = 1;
284 checkbox->widget.width = strlen(checkbox_checked_str);
285 checkbox->widget.x = x;
286 checkbox->widget.y = y;
287 checkbox->widget.process_key = checkbox_process_key;
288 checkbox->widget.focussed_attr = A_REVERSE;
289 checkbox->widget.unfocussed_attr = A_NORMAL;
290 checkbox->widget.field = f = new_field(1, strlen(checkbox_checked_str),
293 field_opts_off(f, O_EDIT);
294 set_field_userptr(f, &checkbox->widget);
295 checkbox_set_buffer(checkbox);
297 widgetset_add_field(set, checkbox->widget.field);
298 talloc_set_destructor(checkbox, checkbox_destructor);
303 static char *strip_string(char *str)
309 /* clear trailing space */
310 for (i = len - 1; i >= 0; i--) {
311 if (!isspace(str[i]))
316 /* increment str past leading space */
317 for (i = 0; i < len; i++) {
318 if (str[i] == '\0' || !isspace(str[i]))
325 char *widget_textbox_get_value(struct nc_widget_textbox *textbox)
327 char *str = field_buffer(textbox->widget.field, 0);
328 return str ? strip_string(str) : NULL;
331 static bool textbox_process_key(
332 struct nc_widget *widget __attribute__((unused)),
337 form_driver(form, REQ_BEG_FIELD);
340 form_driver(form, REQ_END_FIELD);
343 form_driver(form, REQ_LEFT_CHAR);
346 form_driver(form, REQ_RIGHT_CHAR);
349 if (form_driver(form, REQ_LEFT_CHAR) != E_OK)
353 form_driver(form, REQ_DEL_CHAR);
356 form_driver(form, key);
363 static int textbox_destructor(void *ptr)
365 struct nc_widget_textbox *textbox = ptr;
366 free_field(textbox->widget.field);
370 struct nc_widget_textbox *widget_new_textbox(struct nc_widgetset *set,
371 int y, int x, int len, char *str)
373 struct nc_widget_textbox *textbox;
376 textbox = talloc_zero(set, struct nc_widget_textbox);
378 textbox->widget.height = 1;
379 textbox->widget.width = len;
380 textbox->widget.x = x;
381 textbox->widget.y = y;
382 textbox->widget.process_key = textbox_process_key;
383 textbox->widget.field = f = new_field(1, len, y, x, 0, 0);
384 textbox->widget.focussed_attr = A_REVERSE;
385 textbox->widget.unfocussed_attr = A_UNDERLINE;
387 field_opts_off(f, O_STATIC | O_WRAP | O_BLANK);
388 set_field_buffer(f, 0, str);
389 set_field_back(f, textbox->widget.unfocussed_attr);
390 set_field_userptr(f, &textbox->widget);
392 widgetset_add_field(set, textbox->widget.field);
393 talloc_set_destructor(textbox, textbox_destructor);
398 void widget_textbox_set_fixed_size(struct nc_widget_textbox *textbox)
400 field_opts_on(textbox->widget.field, O_STATIC);
403 void widget_textbox_set_validator_integer(struct nc_widget_textbox *textbox,
406 set_field_type(textbox->widget.field, TYPE_INTEGER, 1, min, max);
409 void widget_textbox_set_validator_ipv4(struct nc_widget_textbox *textbox)
411 set_field_type(textbox->widget.field, TYPE_IPV4);
414 static bool check_ipv4_multi_char(int c,
415 const void *arg __attribute__((unused)))
417 return isdigit(c) || c == '.' || c == ' ';
420 static bool check_ipv4_multi_field(FIELD *field,
421 const void *arg __attribute__((unused)))
423 char *buf = field_buffer(field, 0);
427 while (*buf != '\0') {
428 n = sscanf(buf, "%u.%u.%u.%u%n",
429 &ip[0], &ip[1], &ip[2], &ip[3], &len);
433 if (ip[0] > 255 || ip[1] > 255 || ip[2] > 255 || ip[3] > 255)
436 for (buf += len; *buf != '\0'; buf++) {
439 else if (isdigit(*buf))
449 void widget_textbox_set_validator_ipv4_multi(struct nc_widget_textbox *textbox)
451 if (!textbox->set->ipv4_multi_type) {
452 textbox->set->ipv4_multi_type = new_fieldtype(
453 check_ipv4_multi_field,
454 check_ipv4_multi_char);
456 set_field_type(textbox->widget.field, textbox->set->ipv4_multi_type);
459 static void subset_update_order(struct nc_widget_subset *subset)
464 for (i = 0; i < subset->n_active; i++) {
465 val = subset->active[i];
466 str = talloc_asprintf(subset, "(%d) %s",
467 i, subset->options[val].str);
468 set_field_buffer(subset->options[val].field, 0,
474 static void widget_focus_change(struct nc_widget *widget, FIELD *field,
477 static void subset_delete_active(struct nc_widget_subset *subset, int idx)
479 bool last = idx == (subset->n_active - 1);
480 struct nc_widgetset *set = subset->set;
481 struct nc_widget *widget;
485 /* Shift field focus to nearest active option or next visible field */
486 if (subset->n_active > 1) {
488 val = subset->active[idx - 1];
490 val = subset->active[idx + 1];
491 set->cur_field = subset->options[val].field;
493 for (i = 0; i < set->n_fields; i++)
494 if (field_visible(set->fields[i])) {
495 set->cur_field = set->fields[i];
500 set_current_field(set->form, set->cur_field);
501 widget = field_userptr(set->cur_field);
502 widget_focus_change(widget, set->cur_field, true);
503 if (set->widget_focus)
504 set->widget_focus(widget, set->widget_focus_arg);
506 /* Update active array */
507 rem = sizeof(int) * (subset->n_active - idx - 1);
508 val = subset->active[idx];
509 field_set_visible(subset->options[val].field, false);
511 memmove(&subset->active[idx], &subset->active[idx + 1], rem);
513 subset->active = talloc_realloc(subset, subset->active,
514 int, subset->n_active);
516 subset->widget.height = subset->n_active;
519 static bool subset_process_key(struct nc_widget *w, FORM *form, int key)
521 struct nc_widget_subset *subset = to_subset(w);
522 int i, val, opt_idx = -1;
525 if (!key_is_minus(key) && !key_is_left(key) && !key_is_right(key))
528 field = current_field(form);
530 for (i = 0; i < subset->n_active; i++) {
531 val = subset->active[i];
532 if (subset->options[val].field == field) {
541 if (key_is_minus(key))
542 subset_delete_active(subset, opt_idx);
544 if (key_is_left(key)){
548 val = subset->active[opt_idx];
549 subset->active[opt_idx] = subset->active[opt_idx - 1];
550 subset->active[opt_idx - 1] = val;
553 if (key_is_right(key)){
554 if (opt_idx >= subset->n_active - 1)
557 val = subset->active[opt_idx];
558 subset->active[opt_idx] = subset->active[opt_idx + 1];
559 subset->active[opt_idx + 1] = val;
562 subset_update_order(subset);
564 if (subset->on_change)
565 subset->on_change(subset->on_change_arg, 0);
570 static void subset_set_visible(struct nc_widget *widget, bool visible)
572 struct nc_widget_subset *subset = to_subset(widget);
575 for (i = 0; i < subset->n_active; i++) {
576 val = subset->active[i];
577 field_set_visible(subset->options[val].field, visible);
581 static void subset_move(struct nc_widget *widget, int y, int x)
583 struct nc_widget_subset *subset = to_subset(widget);
586 for (i = 0; i < subset->n_active; i++) {
587 val = subset->active[i];
588 field_move(subset->options[val].field, y + i , x);
592 static void subset_field_focus(struct nc_widget *widget, FIELD *field)
594 struct nc_widget_subset *subset = to_subset(widget);
597 for (i = 0; i < subset->n_active; i++) {
598 val = subset->active[i];
599 if (field == subset->options[val].field) {
606 static int subset_destructor(void *ptr)
608 struct nc_widget_subset *subset = ptr;
611 for (i = 0; i < subset->n_options; i++)
612 free_field(subset->options[i].field);
617 struct nc_widget_subset *widget_new_subset(struct nc_widgetset *set,
618 int y, int x, int len, void *screen_cb)
620 struct nc_widget_subset *subset;
622 subset = talloc_zero(set, struct nc_widget_subset);
623 subset->widget.width = len;
624 subset->widget.height = 0;
625 subset->widget.x = x;
626 subset->widget.y = y;
627 subset->widget.process_key = subset_process_key;
628 subset->widget.set_visible = subset_set_visible;
629 subset->widget.move = subset_move;
630 subset->widget.field_focus = subset_field_focus;
631 subset->widget.focussed_attr = A_REVERSE;
632 subset->widget.unfocussed_attr = A_NORMAL;
637 subset->n_active = subset->n_options = 0;
638 subset->active = NULL;
639 subset->options = NULL;
640 subset->screen_cb = screen_cb;
642 talloc_set_destructor(subset, subset_destructor);
647 void widget_subset_add_option(struct nc_widget_subset *subset, const char *text)
652 i = subset->n_options++;
653 subset->options = talloc_realloc(subset, subset->options,
654 struct subset_option, i + 1);
656 subset->options[i].str = talloc_strdup(subset->options, text);
658 subset->options[i].field = f = new_field(1, subset->size, subset->top + i,
661 field_opts_off(f, O_WRAP | O_EDIT);
662 set_field_userptr(f, &subset->widget);
663 set_field_buffer(f, 0, subset->options[i].str);
664 field_set_visible(f, false);
665 widgetset_add_field(subset->set, f);
668 void widget_subset_make_active(struct nc_widget_subset *subset, int idx)
672 for (i = 0; i < subset->n_active; i++)
673 if (subset->active[i] == idx) {
674 pb_debug("%s: Index %d already active\n", __func__, idx);
678 i = subset->n_active++;
679 subset->widget.height = subset->n_active;
680 subset->active = talloc_realloc(subset, subset->active,
682 subset->active[i] = idx;
684 subset_update_order(subset);
687 int widget_subset_get_order(void *ctx, unsigned int **order,
688 struct nc_widget_subset *subset)
690 unsigned int *buf = talloc_array(ctx, unsigned int, subset->n_active);
693 for (i = 0; i < subset->n_active; i++)
694 buf[i] = subset->active[i];
700 void widget_subset_show_inactive(struct nc_widget_subset *subset,
701 struct nc_widget_select *select)
703 bool active = false, first = true;
706 for (i = 0; i < subset->n_options; i++) {
708 for (j = 0; j < subset->n_active; j++)
709 if (subset->active[j] == i)
715 widget_select_add_option(select, i,
716 subset->options[i].str, first);
722 int widget_subset_n_inactive(struct nc_widget_subset *subset)
724 return subset->n_options - subset->n_active;
727 int widget_subset_height(struct nc_widget_subset *subset)
729 return subset->n_active;
732 void widget_subset_on_change(struct nc_widget_subset *subset,
733 void (*on_change)(void *, int), void *arg)
735 subset->on_change = on_change;
736 subset->on_change_arg = arg;
739 void widget_subset_drop_options(struct nc_widget_subset *subset)
741 struct nc_widgetset *set = subset->set;
744 for (i = 0; i < subset->n_options; i++) {
745 FIELD *field = subset->options[i].field;
746 widgetset_remove_field(set, field);
747 if (field == set->cur_field)
748 set->cur_field = NULL;
749 free_field(subset->options[i].field);
752 talloc_free(subset->options);
753 talloc_free(subset->active);
754 subset->options = NULL;
755 subset->active = NULL;
756 subset->n_options = 0;
757 subset->n_active = 0;
758 subset->widget.height = 0;
759 subset->widget.focus_y = 0;
762 void widget_subset_clear_active(struct nc_widget_subset *subset)
766 for (i = 0; i < subset->n_options; i++)
767 field_set_visible(subset->options[i].field, false);
769 talloc_free(subset->active);
770 subset->active = NULL;
771 subset->n_active = 0;
772 subset->widget.height = 0;
773 subset->widget.focus_y = 0;
776 void widget_subset_callback(void *arg,
777 struct nc_widget_subset *subset, int idx)
779 subset->screen_cb(arg, subset, idx);
782 static void select_option_change(struct select_option *opt, bool selected)
786 str = selected ? select_selected_str : select_unselected_str;
788 memcpy(opt->str, str, strlen(str));
789 set_field_buffer(opt->field, 0, opt->str);
792 static bool select_process_key(struct nc_widget *w, FORM *form, int key)
794 struct nc_widget_select *select = to_select(w);
795 struct select_option *new_opt, *old_opt;
799 if (!key_is_select(key))
802 field = current_field(form);
805 for (i = 0; i < select->n_options; i++) {
806 if (select->options[i].field == field) {
807 new_opt = &select->options[i];
816 if (new_idx == select->selected_option)
819 old_opt = &select->options[select->selected_option];
821 select_option_change(old_opt, false);
822 select_option_change(new_opt, true);
824 select->selected_option = new_idx;
826 if (select->on_change)
827 select->on_change(select->on_change_arg, new_opt->val);
832 static void select_set_visible(struct nc_widget *widget, bool visible)
834 struct nc_widget_select *select = to_select(widget);
837 for (i = 0; i < select->n_options; i++)
838 field_set_visible(select->options[i].field, visible);
841 static void select_move(struct nc_widget *widget, int y, int x)
843 struct nc_widget_select *select = to_select(widget);
846 for (i = 0; i < select->n_options; i++) {
847 field_move(select->options[i].field, y + cur, x);
848 cur += select->options[i].lines;
852 static void select_field_focus(struct nc_widget *widget, FIELD *field)
854 struct nc_widget_select *select = to_select(widget);
857 for (i = 0; i < select->n_options; i++) {
858 if (field != select->options[i].field) {
859 cur += select->options[i].lines;
862 widget->focus_y = cur;
867 static int select_destructor(void *ptr)
869 struct nc_widget_select *select = ptr;
872 for (i = 0; i < select->n_options; i++)
873 free_field(select->options[i].field);
878 struct nc_widget_select *widget_new_select(struct nc_widgetset *set,
879 int y, int x, int len)
881 struct nc_widget_select *select;
883 select = talloc_zero(set, struct nc_widget_select);
884 select->widget.width = len;
885 select->widget.height = 0;
886 select->widget.x = x;
887 select->widget.y = y;
888 select->widget.process_key = select_process_key;
889 select->widget.set_visible = select_set_visible;
890 select->widget.move = select_move;
891 select->widget.field_focus = select_field_focus;
892 select->widget.focussed_attr = A_REVERSE;
893 select->widget.unfocussed_attr = A_NORMAL;
899 talloc_set_destructor(select, select_destructor);
904 static int widget_select_fold_cb(void *arg, const char *buf, int len)
906 struct nc_widget_select *select = arg;
907 char *line, *newstr, *padbuf = NULL;
913 line = talloc_strndup(select->options, buf, len);
915 i = select->n_options - 1;
916 pad = max(0, select->widget.width - strncols(line));
919 padbuf = talloc_array(select->options, char, pad + 1);
920 memset(padbuf, ' ', pad);
924 if (select->options[i].str)
925 newstr = talloc_asprintf_append(select->options[i].str,
929 newstr = talloc_asprintf(select->options, "%s%s", line,
932 select->options[i].str = newstr;
933 select->options[i].lines++;
940 void widget_select_add_option(struct nc_widget_select *select, int value,
941 const char *text, bool selected)
948 /* if we never see an option with selected set, we want the first
949 * one to be selected */
950 if (select->n_options == 0)
953 select_option_change(&select->options[select->selected_option],
957 select->selected_option = select->n_options;
958 str = select_selected_str;
960 str = select_unselected_str;
962 i = select->n_options++;
963 select->options = talloc_realloc(select, select->options,
964 struct select_option, i + 2);
965 select->options[i].val = value;
966 select->options[i].lines = 0;
967 select->options[i].str = NULL;
969 full_text = talloc_asprintf(select->options, "%s %s", str, text);
970 fold_text(full_text, select->widget.width,
971 widget_select_fold_cb, select);
973 select->options[i].field = f = new_field(select->options[i].lines,
975 select->top + select->widget.height,
978 select->widget.height += select->options[i].lines;
980 field_opts_off(f, O_EDIT);
981 set_field_userptr(f, &select->widget);
982 set_field_buffer(f, 0, select->options[i].str);
984 widgetset_add_field(select->set, f);
985 talloc_free(full_text);
988 int widget_select_get_value(struct nc_widget_select *select)
990 if (!select->n_options)
992 return select->options[select->selected_option].val;
995 int widget_select_height(struct nc_widget_select *select)
997 return select->widget.height;
1000 void widget_select_on_change(struct nc_widget_select *select,
1001 void (*on_change)(void *, int), void *arg)
1003 select->on_change = on_change;
1004 select->on_change_arg = arg;
1007 void widget_select_drop_options(struct nc_widget_select *select)
1009 struct nc_widgetset *set = select->set;
1012 for (i = 0; i < select->n_options; i++) {
1013 FIELD *field = select->options[i].field;
1014 widgetset_remove_field(set, field);
1015 if (field == set->cur_field)
1016 set->cur_field = NULL;
1017 free_field(select->options[i].field);
1020 talloc_free(select->options);
1021 select->options = NULL;
1022 select->n_options = 0;
1023 select->widget.height = 0;
1024 select->widget.focus_y = 0;
1028 static bool button_process_key(struct nc_widget *widget,
1029 FORM *form __attribute__((unused)), int key)
1031 struct nc_widget_button *button = to_button(widget);
1036 if (!key_is_select(key))
1039 button->click(button->arg);
1043 static int button_destructor(void *ptr)
1045 struct nc_widget_button *button = ptr;
1046 free_field(button->widget.field);
1050 struct nc_widget_button *widget_new_button(struct nc_widgetset *set,
1051 int y, int x, int size, const char *str,
1052 void (*click)(void *), void *arg)
1054 struct nc_widget_button *button;
1055 int idx, len, pad1, pad2, bufsz;
1059 int field_size = size + 2;
1061 button = talloc_zero(set, struct nc_widget_button);
1062 button->widget.height = 1;
1063 button->widget.width = field_size;
1064 button->widget.x = x;
1065 button->widget.y = y;
1066 button->widget.field = f = new_field(1, field_size, y, x, 0, 0);
1067 button->widget.process_key = button_process_key;
1068 button->widget.focussed_attr = A_REVERSE;
1069 button->widget.unfocussed_attr = A_NORMAL;
1070 button->click = click;
1073 field_opts_off(f, O_EDIT);
1074 set_field_userptr(f, &button->widget);
1076 /* Center str in the field. This depends on the number of columns used
1077 * by the string, not the number of chars in str */
1078 len = strncols(str);
1080 idx = (field_size - len) / 2;
1083 pb_log("Warning: '%s' %d columns wide "
1084 "but button is %d columns wide\n",
1088 pad1 = max(idx - 1, 0);
1089 pad2 = max(size - len - pad1, 0);
1090 bufsz = 1 + pad1 + strlen(str) + pad2 + 2;
1092 text = talloc_array(button, char, bufsz);
1093 memset(text, ' ', bufsz);
1094 memcpy(text + idx, str, strlen(str));
1096 text[bufsz - 2] = ']';
1097 text[bufsz - 1] = '\0';
1099 set_field_buffer(f, 0, text);
1101 widgetset_add_field(set, button->widget.field);
1102 talloc_set_destructor(button, button_destructor);
1107 void widget_focus_change(struct nc_widget *widget, FIELD *field,
1110 int attr = focussed ? widget->focussed_attr : widget->unfocussed_attr;
1111 set_field_back(field, attr);
1114 bool widgetset_process_key(struct nc_widgetset *set, int key)
1116 struct nc_widget *widget;
1121 field = current_field(set->form);
1126 /* handle field change events */
1132 req = REQ_SPREV_FIELD;
1138 req = REQ_SNEXT_FIELD;
1141 req = REQ_SFIRST_FIELD;
1144 req = REQ_SLAST_FIELD;
1148 widget = field_userptr(field);
1150 widget_focus_change(widget, field, false);
1151 form_driver(set->form, req);
1153 /* if we're doing a tabbed-field-change, skip until we
1154 * see the next widget */
1156 field = current_field(set->form);
1158 for (; tab && tmp != field && field_userptr(field) == widget;) {
1159 form_driver(set->form, req);
1160 field = current_field(set->form);
1163 form_driver(set->form, REQ_END_FIELD);
1164 widget = field_userptr(field);
1165 widget_focus_change(widget, field, true);
1166 if (widget->field_focus)
1167 widget->field_focus(widget, field);
1168 if (set->widget_focus)
1169 set->widget_focus(widget, set->widget_focus_arg);
1173 if (!widget->process_key)
1176 return widget->process_key(widget, set->form, key);
1179 static int widgetset_destructor(void *ptr)
1181 struct nc_widgetset *set = ptr;
1182 free_form(set->form);
1183 if (set->ipv4_multi_type)
1184 free_fieldtype(set->ipv4_multi_type);
1188 struct nc_widgetset *widgetset_create(void *ctx, WINDOW *main, WINDOW *sub)
1190 struct nc_widgetset *set;
1192 set = talloc_zero(ctx, struct nc_widgetset);
1193 set->n_alloc_fields = 8;
1194 set->mainwin = main;
1196 set->fields = talloc_array(set, FIELD *, set->n_alloc_fields);
1197 talloc_set_destructor(set, widgetset_destructor);
1202 void widgetset_set_windows(struct nc_widgetset *set,
1203 WINDOW *main, WINDOW *sub)
1205 set->mainwin = main;
1209 void widgetset_set_widget_focus(struct nc_widgetset *set,
1210 widget_focus_cb cb, void *arg)
1212 set->widget_focus = cb;
1213 set->widget_focus_arg = arg;
1216 void widgetset_post(struct nc_widgetset *set)
1218 struct nc_widget *widget;
1221 set->form = new_form(set->fields);
1222 set_form_win(set->form, set->mainwin);
1223 set_form_sub(set->form, set->subwin);
1224 post_form(set->form);
1225 form_driver(set->form, REQ_END_FIELD);
1228 set_current_field(set->form, set->cur_field);
1230 field = current_field(set->form);
1231 widget = field_userptr(field);
1232 widget_focus_change(widget, field, true);
1233 if (set->widget_focus)
1234 set->widget_focus(widget, set->widget_focus_arg);
1237 void widgetset_unpost(struct nc_widgetset *set)
1239 set->cur_field = current_field(set->form);
1240 unpost_form(set->form);
1241 free_form(set->form);
1245 static void widgetset_add_field(struct nc_widgetset *set, FIELD *field)
1247 if (set->n_fields == set->n_alloc_fields - 1) {
1248 set->n_alloc_fields *= 2;
1249 set->fields = talloc_realloc(set, set->fields,
1250 FIELD *, set->n_alloc_fields);
1254 set->fields[set->n_fields - 1] = field;
1255 set->fields[set->n_fields] = NULL;
1258 static void widgetset_remove_field(struct nc_widgetset *set, FIELD *field)
1262 for (i = 0; i < set->n_fields; i++) {
1263 if (set->fields[i] == field)
1267 if (i == set->n_fields)
1270 memmove(&set->fields[i], &set->fields[i+i],
1271 (set->n_fields - i) * sizeof(set->fields[i]));
1275 #define DECLARE_BASEFN(type) \
1276 struct nc_widget *widget_ ## type ## _base \
1277 (struct nc_widget_ ## type *w) \
1278 { return &w->widget; }
1280 DECLARE_BASEFN(textbox);
1281 DECLARE_BASEFN(checkbox);
1282 DECLARE_BASEFN(subset);
1283 DECLARE_BASEFN(select);
1284 DECLARE_BASEFN(label);
1285 DECLARE_BASEFN(button);
1287 void widget_set_visible(struct nc_widget *widget, bool visible)
1289 if (widget->set_visible)
1290 widget->set_visible(widget, visible);
1292 field_set_visible(widget->field, visible);
1295 void widget_move(struct nc_widget *widget, int y, int x)
1298 widget->move(widget, y, x);
1300 field_move(widget->field, y, x);
1305 if (x + widget->width > COLS)
1306 pb_debug("%s: Widget at %d,%d runs over pad! (%d)", __func__,
1307 y, x, x + widget->width);
1310 int widget_height(struct nc_widget *widget)
1312 return widget->height;
1315 int widget_width(struct nc_widget *widget)
1317 return widget->width;
1320 int widget_x(struct nc_widget *widget)
1325 int widget_y(struct nc_widget *widget)
1330 int widget_focus_y(struct nc_widget *widget)
1332 return widget->focus_y;