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
23 #include <talloc/talloc.h>
24 #include <types/types.h>
26 #include <util/util.h>
30 #include "nc-widgets.h"
34 #define to_checkbox(w) container_of(w, struct nc_widget_checkbox, widget)
35 #define to_textbox(w) container_of(w, struct nc_widget_textbox, widget)
36 #define to_button(w) container_of(w, struct nc_widget_button, widget)
37 #define to_select(w) container_of(w, struct nc_widget_select, widget)
39 static const char *checkbox_checked_str = "[*]";
40 static const char *checkbox_unchecked_str = "[ ]";
42 static const char *select_selected_str = "(*)";
43 static const char *select_unselected_str = "( )";
50 int n_fields, n_alloc_fields;
51 void (*widget_focus)(struct nc_widget *, void *);
52 void *widget_focus_arg;
58 bool (*process_key)(struct nc_widget *, FORM *, int);
59 void (*set_visible)(struct nc_widget *, bool);
60 void (*move)(struct nc_widget *, int, int);
69 struct nc_widget_label {
70 struct nc_widget widget;
74 struct nc_widget_checkbox {
75 struct nc_widget widget;
79 struct nc_widget_textbox {
80 struct nc_widget widget;
83 struct nc_widget_select {
84 struct nc_widget widget;
85 struct select_option {
91 int n_options, selected_option;
92 struct nc_widgetset *set;
93 void (*on_change)(void *, int);
97 struct nc_widget_button {
98 struct nc_widget widget;
99 void (*click)(void *arg);
103 static void widgetset_add_field(struct nc_widgetset *set, FIELD *field);
105 static bool process_key_nop(struct nc_widget *widget __attribute__((unused)),
106 FORM *form __attribute((unused)),
107 int key __attribute__((unused)))
112 static void field_set_visible(FIELD *field, bool visible)
114 int opts = field_opts(field) & ~O_VISIBLE;
117 set_field_opts(field, opts);
120 static void field_move(FIELD *field, int y, int x)
122 move_field(field, y, x);
125 static int label_destructor(void *ptr)
127 struct nc_widget_label *label = ptr;
128 free_field(label->widget.field);
133 struct nc_widget_label *widget_new_label(struct nc_widgetset *set,
134 int y, int x, char *str)
136 struct nc_widget_label *label;
142 label = talloc_zero(set, struct nc_widget_label);
143 label->widget.height = 1;
144 label->widget.width = len;
147 label->widget.process_key = process_key_nop;
148 label->widget.field = f = new_field(1, len, y, x, 0, 0);
149 label->widget.focussed_attr = A_NORMAL;
150 label->widget.unfocussed_attr = A_NORMAL;
152 field_opts_off(f, O_ACTIVE);
153 set_field_buffer(f, 0, str);
154 set_field_userptr(f, &label->widget);
156 widgetset_add_field(set, label->widget.field);
157 talloc_set_destructor(label, label_destructor);
162 bool widget_checkbox_get_value(struct nc_widget_checkbox *checkbox)
164 return checkbox->checked;
167 static void checkbox_set_buffer(struct nc_widget_checkbox *checkbox)
170 str = checkbox->checked ? checkbox_checked_str : checkbox_unchecked_str;
171 set_field_buffer(checkbox->widget.field, 0, str);
174 static bool checkbox_process_key(struct nc_widget *widget,
175 FORM *form __attribute__((unused)), int key)
177 struct nc_widget_checkbox *checkbox = to_checkbox(widget);
182 checkbox->checked = !checkbox->checked;
183 checkbox_set_buffer(checkbox);
188 static int checkbox_destructor(void *ptr)
190 struct nc_widget_checkbox *checkbox = ptr;
191 free_field(checkbox->widget.field);
195 struct nc_widget_checkbox *widget_new_checkbox(struct nc_widgetset *set,
196 int y, int x, bool checked)
198 struct nc_widget_checkbox *checkbox;
201 checkbox = talloc_zero(set, struct nc_widget_checkbox);
202 checkbox->checked = checked;
203 checkbox->widget.height = 1;
204 checkbox->widget.width = strlen(checkbox_checked_str);
205 checkbox->widget.x = x;
206 checkbox->widget.y = y;
207 checkbox->widget.process_key = checkbox_process_key;
208 checkbox->widget.focussed_attr = A_REVERSE;
209 checkbox->widget.unfocussed_attr = A_NORMAL;
210 checkbox->widget.field = f = new_field(1, strlen(checkbox_checked_str),
213 field_opts_off(f, O_EDIT);
214 set_field_userptr(f, &checkbox->widget);
215 checkbox_set_buffer(checkbox);
217 widgetset_add_field(set, checkbox->widget.field);
218 talloc_set_destructor(checkbox, checkbox_destructor);
223 static char *strip_string(char *str)
229 /* clear trailing space */
230 for (i = len - 1; i >= 0; i--) {
231 if (!isspace(str[i]))
236 /* increment str past leading space */
237 for (i = 0; i < len; i++) {
238 if (str[i] == '\0' || !isspace(str[i]))
245 char *widget_textbox_get_value(struct nc_widget_textbox *textbox)
247 char *str = field_buffer(textbox->widget.field, 0);
248 return str ? strip_string(str) : NULL;
251 static bool textbox_process_key(
252 struct nc_widget *widget __attribute__((unused)),
257 form_driver(form, REQ_BEG_FIELD);
260 form_driver(form, REQ_END_FIELD);
263 form_driver(form, REQ_LEFT_CHAR);
266 form_driver(form, REQ_RIGHT_CHAR);
269 if (form_driver(form, REQ_LEFT_CHAR) != E_OK)
273 form_driver(form, REQ_DEL_CHAR);
276 form_driver(form, key);
283 static int textbox_destructor(void *ptr)
285 struct nc_widget_textbox *textbox = ptr;
286 free_field(textbox->widget.field);
290 struct nc_widget_textbox *widget_new_textbox(struct nc_widgetset *set,
291 int y, int x, int len, char *str)
293 struct nc_widget_textbox *textbox;
296 textbox = talloc_zero(set, struct nc_widget_textbox);
297 textbox->widget.height = 1;
298 textbox->widget.width = len;
299 textbox->widget.x = x;
300 textbox->widget.y = y;
301 textbox->widget.process_key = textbox_process_key;
302 textbox->widget.field = f = new_field(1, len, y, x, 0, 0);
303 textbox->widget.focussed_attr = A_REVERSE;
304 textbox->widget.unfocussed_attr = A_UNDERLINE;
306 field_opts_off(f, O_STATIC | O_WRAP | O_BLANK);
307 set_field_buffer(f, 0, str);
308 set_field_back(f, textbox->widget.unfocussed_attr);
309 set_field_userptr(f, &textbox->widget);
311 widgetset_add_field(set, textbox->widget.field);
312 talloc_set_destructor(textbox, textbox_destructor);
317 static void select_option_change(struct select_option *opt, bool selected)
321 str = selected ? select_selected_str : select_unselected_str;
323 memcpy(opt->str, str, strlen(str));
324 set_field_buffer(opt->field, 0, opt->str);
327 static bool select_process_key(struct nc_widget *w, FORM *form, int key)
329 struct nc_widget_select *select = to_select(w);
330 struct select_option *new_opt, *old_opt;
342 field = current_field(form);
345 for (i = 0; i < select->n_options; i++) {
346 if (select->options[i].field == field) {
347 new_opt = &select->options[i];
356 if (new_idx == select->selected_option)
359 old_opt = &select->options[select->selected_option];
361 select_option_change(old_opt, false);
362 select_option_change(new_opt, true);
364 select->selected_option = new_idx;
366 if (select->on_change)
367 select->on_change(select->on_change_arg, new_opt->val);
372 static void select_set_visible(struct nc_widget *widget, bool visible)
374 struct nc_widget_select *select = to_select(widget);
377 for (i = 0; i < select->n_options; i++)
378 field_set_visible(select->options[i].field, visible);
381 static void select_move(struct nc_widget *widget, int y, int x)
383 struct nc_widget_select *select = to_select(widget);
386 for (i = 0; i < select->n_options; i++)
387 field_move(select->options[i].field, y + i, x);
390 static int select_destructor(void *ptr)
392 struct nc_widget_select *select = ptr;
395 for (i = 0; i < select->n_options; i++)
396 free_field(select->options[i].field);
401 struct nc_widget_select *widget_new_select(struct nc_widgetset *set,
402 int y, int x, int len)
404 struct nc_widget_select *select;
406 select = talloc_zero(set, struct nc_widget_select);
407 select->widget.width = len;
408 select->widget.height = 0;
409 select->widget.x = x;
410 select->widget.y = y;
411 select->widget.process_key = select_process_key;
412 select->widget.set_visible = select_set_visible;
413 select->widget.move = select_move;
414 select->widget.focussed_attr = A_REVERSE;
415 select->widget.unfocussed_attr = A_NORMAL;
421 talloc_set_destructor(select, select_destructor);
426 void widget_select_add_option(struct nc_widget_select *select, int value,
427 const char *text, bool selected)
433 /* if we never see an option with selected set, we want the first
434 * one to be selected */
435 if (select->n_options == 0)
438 select_option_change(&select->options[select->selected_option],
442 select->selected_option = select->n_options;
443 str = select_selected_str;
445 str = select_unselected_str;
447 i = select->n_options++;
448 select->widget.height = select->n_options;
450 select->options = talloc_realloc(select, select->options,
451 struct select_option, i + 2);
452 select->options[i].val = value;
453 select->options[i].str = talloc_asprintf(select->options,
456 select->options[i].field = f = new_field(1, select->size,
460 field_opts_off(f, O_WRAP | O_EDIT);
461 set_field_userptr(f, &select->widget);
462 set_field_buffer(f, 0, select->options[i].str);
464 widgetset_add_field(select->set, f);
467 int widget_select_get_value(struct nc_widget_select *select)
469 return select->options[select->selected_option].val;
472 int widget_select_height(struct nc_widget_select *select)
474 return select->n_options;
477 void widget_select_on_change(struct nc_widget_select *select,
478 void (*on_change)(void *, int), void *arg)
480 select->on_change = on_change;
481 select->on_change_arg = arg;
484 static bool button_process_key(struct nc_widget *widget,
485 FORM *form __attribute__((unused)), int key)
487 struct nc_widget_button *button = to_button(widget);
496 button->click(button->arg);
503 static int button_destructor(void *ptr)
505 struct nc_widget_button *button = ptr;
506 free_field(button->widget.field);
510 struct nc_widget_button *widget_new_button(struct nc_widgetset *set,
511 int y, int x, int size, const char *str,
512 void (*click)(void *), void *arg)
514 struct nc_widget_button *button;
519 button = talloc_zero(set, struct nc_widget_button);
520 button->widget.height = 1;
521 button->widget.width = size;
522 button->widget.x = x;
523 button->widget.y = y;
524 button->widget.field = f = new_field(1, size + 2, y, x, 0, 0);
525 button->widget.process_key = button_process_key;
526 button->widget.focussed_attr = A_REVERSE;
527 button->widget.unfocussed_attr = A_NORMAL;
528 button->click = click;
531 field_opts_off(f, O_EDIT);
532 set_field_userptr(f, &button->widget);
534 /* center str in a size-char buffer, but don't overrun */
536 len = min(len, size);
537 idx = (size - len) / 2;
539 text = talloc_array(button, char, size + 3);
540 memset(text, ' ', size + 2);
541 memcpy(text + idx + 1, str, len);
543 text[size + 1] = ']';
544 text[size + 2] = '\0';
546 set_field_buffer(f, 0, text);
548 widgetset_add_field(set, button->widget.field);
549 talloc_set_destructor(button, button_destructor);
554 static void widget_focus_change(struct nc_widget *widget, FIELD *field,
557 int attr = focussed ? widget->focussed_attr : widget->unfocussed_attr;
558 set_field_back(field, attr);
561 bool widgetset_process_key(struct nc_widgetset *set, int key)
563 struct nc_widget *widget;
567 field = current_field(set->form);
570 /* handle field change events */
574 req = REQ_PREV_FIELD;
578 req = REQ_NEXT_FIELD;
581 req = REQ_FIRST_FIELD;
584 req = REQ_LAST_FIELD;
588 widget = field_userptr(field);
590 widget_focus_change(widget, field, false);
591 form_driver(set->form, req);
592 form_driver(set->form, REQ_END_FIELD);
593 field = current_field(set->form);
594 widget = field_userptr(field);
595 widget_focus_change(widget, field, true);
596 if (set->widget_focus)
597 set->widget_focus(widget, set->widget_focus_arg);
601 if (!widget->process_key)
604 return widget->process_key(widget, set->form, key);
607 static int widgetset_destructor(void *ptr)
609 struct nc_widgetset *set = ptr;
610 free_form(set->form);
614 struct nc_widgetset *widgetset_create(void *ctx, WINDOW *main, WINDOW *sub)
616 struct nc_widgetset *set;
618 set = talloc_zero(ctx, struct nc_widgetset);
619 set->n_alloc_fields = 8;
622 set->fields = talloc_array(set, FIELD *, set->n_alloc_fields);
623 talloc_set_destructor(set, widgetset_destructor);
628 void widgetset_set_widget_focus(struct nc_widgetset *set,
629 widget_focus_cb cb, void *arg)
631 set->widget_focus = cb;
632 set->widget_focus_arg = arg;
635 void widgetset_post(struct nc_widgetset *set)
637 struct nc_widget *widget;
640 set->form = new_form(set->fields);
641 set_form_win(set->form, set->mainwin);
642 set_form_sub(set->form, set->subwin);
643 post_form(set->form);
644 form_driver(set->form, REQ_END_FIELD);
646 if (set->cur_field) {
647 set_current_field(set->form, set->cur_field);
648 field = set->cur_field;
651 field = current_field(set->form);
652 widget = field_userptr(field);
653 widget_focus_change(widget, field, true);
654 if (set->widget_focus)
655 set->widget_focus(widget, set->widget_focus_arg);
658 void widgetset_unpost(struct nc_widgetset *set)
660 set->cur_field = current_field(set->form);
661 unpost_form(set->form);
662 free_form(set->form);
666 static void widgetset_add_field(struct nc_widgetset *set, FIELD *field)
668 if (set->n_fields == set->n_alloc_fields - 1) {
669 set->n_alloc_fields *= 2;
670 set->fields = talloc_realloc(set, set->fields,
671 FIELD *, set->n_alloc_fields);
675 set->fields[set->n_fields - 1] = field;
676 set->fields[set->n_fields] = NULL;
679 #define DECLARE_BASEFN(type) \
680 struct nc_widget *widget_ ## type ## _base \
681 (struct nc_widget_ ## type *w) \
682 { return &w->widget; }
684 DECLARE_BASEFN(textbox);
685 DECLARE_BASEFN(checkbox);
686 DECLARE_BASEFN(select);
687 DECLARE_BASEFN(label);
688 DECLARE_BASEFN(button);
690 void widget_set_visible(struct nc_widget *widget, bool visible)
692 if (widget->set_visible)
693 widget->set_visible(widget, visible);
695 field_set_visible(widget->field, visible);
698 void widget_move(struct nc_widget *widget, int y, int x)
701 widget->move(widget, y, x);
703 field_move(widget->field, y, x);
709 int widget_height(struct nc_widget *widget)
711 return widget->height;
714 int widget_width(struct nc_widget *widget)
716 return widget->width;
719 int widget_x(struct nc_widget *widget)
724 int widget_y(struct nc_widget *widget)