ui/ncurses: Split boot editor layout
[petitboot] / ui / ncurses / nc-boot-editor.c
1 /*
2  *  Copyright (C) 2009 Sony Computer Entertainment Inc.
3  *  Copyright 2009 Sony Corp.
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; version 2 of the License.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19 #include "config.h"
20
21 #define _GNU_SOURCE
22
23 #include <assert.h>
24 #include <string.h>
25
26 #include "log/log.h"
27 #include "talloc/talloc.h"
28 #include "nc-boot-editor.h"
29 #include "nc-widgets.h"
30
31 struct boot_editor {
32         struct nc_scr           scr;
33         struct cui              *cui;
34         void                    *data;
35         struct pmenu_item       *item;
36         void                    (*on_exit)(struct cui *cui,
37                                         struct pmenu_item *item,
38                                         struct pb_boot_data *bd);
39
40         int                     label_x;
41         int                     field_x;
42
43         struct nc_widgetset     *widgetset;
44         struct {
45                 struct nc_widget_label          *image_l;
46                 struct nc_widget_textbox        *image_f;
47                 struct nc_widget_label          *initrd_l;
48                 struct nc_widget_textbox        *initrd_f;
49                 struct nc_widget_label          *dtb_l;
50                 struct nc_widget_textbox        *dtb_f;
51                 struct nc_widget_label          *args_l;
52                 struct nc_widget_textbox        *args_f;
53                 struct nc_widget_button         *ok_b;
54                 struct nc_widget_button         *cancel_b;
55         } widgets;
56 };
57
58 static struct boot_editor *boot_editor_from_scr(struct nc_scr *scr)
59 {
60         struct boot_editor *boot_editor;
61
62         assert(scr->sig == pb_boot_editor_sig);
63         boot_editor = (struct boot_editor *)
64                 ((char *)scr - (size_t)&((struct boot_editor *)0)->scr);
65         assert(boot_editor->scr.sig == pb_boot_editor_sig);
66         return boot_editor;
67 }
68
69 static struct boot_editor *boot_editor_from_arg(void *arg)
70 {
71         struct boot_editor *boot_editor = arg;
72
73         assert(boot_editor->scr.sig == pb_boot_editor_sig);
74         return boot_editor;
75 }
76
77 static int boot_editor_post(struct nc_scr *scr)
78 {
79         struct boot_editor *boot_editor = boot_editor_from_scr(scr);
80
81         widgetset_post(boot_editor->widgetset);
82         nc_scr_frame_draw(scr);
83         redrawwin(boot_editor->scr.main_ncw);
84         wrefresh(boot_editor->scr.main_ncw);
85
86         return 0;
87 }
88
89 static int boot_editor_unpost(struct nc_scr *scr)
90 {
91         widgetset_unpost(boot_editor_from_scr(scr)->widgetset);
92         return 0;
93 }
94
95 struct nc_scr *boot_editor_scr(struct boot_editor *boot_editor)
96 {
97         return &boot_editor->scr;
98 }
99
100 static void boot_editor_resize(struct nc_scr *scr)
101 {
102         /* FIXME: forms can't be resized, need to recreate here */
103         boot_editor_unpost(scr);
104         boot_editor_post(scr);
105 }
106
107 static struct pb_boot_data *boot_editor_prepare_data(
108                 struct boot_editor *boot_editor)
109 {
110         struct pb_boot_data *bd;
111         char *s;
112
113         bd = talloc(boot_editor, struct pb_boot_data);
114
115         if (!bd)
116                 return NULL;
117
118         s = widget_textbox_get_value(boot_editor->widgets.image_f);
119         bd->image = *s ? talloc_strdup(bd, s) : NULL;
120
121         s = widget_textbox_get_value(boot_editor->widgets.initrd_f);
122         bd->initrd = *s ? talloc_strdup(bd, s) : NULL;
123
124         s = widget_textbox_get_value(boot_editor->widgets.dtb_f);
125         bd->dtb = *s ? talloc_strdup(bd, s) : NULL;
126
127         s = widget_textbox_get_value(boot_editor->widgets.args_f);
128         bd->args = *s ? talloc_strdup(bd, s) : NULL;
129
130         return bd;
131 }
132
133 /**
134  * boot_editor_process_key - Process a user keystroke.
135  *
136  * Called from the cui via the scr:process_key method.
137  */
138
139 static void boot_editor_process_key(struct nc_scr *scr, int key)
140 {
141         struct boot_editor *boot_editor = boot_editor_from_scr(scr);
142         bool handled;
143
144         handled = widgetset_process_key(boot_editor->widgetset, key);
145         if (handled) {
146                 wrefresh(boot_editor->scr.main_ncw);
147                 return;
148         }
149
150         switch (key) {
151         case 'x':
152         case 27: /* ESC */
153                 boot_editor->on_exit(boot_editor->cui, NULL, NULL);
154                 nc_flush_keys();
155         }
156 }
157
158 /**
159  * boot_editor_destructor - The talloc destructor for a boot_editor.
160  */
161
162 static int boot_editor_destructor(void *arg)
163 {
164         struct boot_editor *boot_editor = boot_editor_from_arg(arg);
165         boot_editor->scr.sig = pb_removed_sig;
166         return 0;
167 }
168
169 static void ok_click(void *arg)
170 {
171         struct boot_editor *boot_editor = arg;
172         struct pb_boot_data *bd;
173
174         bd = boot_editor_prepare_data(boot_editor);
175         boot_editor->on_exit(boot_editor->cui, boot_editor->item, bd);
176 }
177
178 static void cancel_click(void *arg)
179 {
180         struct boot_editor *boot_editor = arg;
181         boot_editor->on_exit(boot_editor->cui, NULL, NULL);
182 }
183
184 static int layout_pair(struct boot_editor *boot_editor, int y,
185                 struct nc_widget_label *label,
186                 struct nc_widget_textbox *field)
187 {
188         struct nc_widget *label_w = widget_label_base(label);
189         struct nc_widget *field_w = widget_textbox_base(field);
190         widget_move(label_w, y, boot_editor->label_x);
191         widget_move(field_w, y, boot_editor->field_x);
192         return max(widget_height(label_w), widget_height(field_w));
193 }
194
195 static void boot_editor_layout_widgets(struct boot_editor *boot_editor)
196 {
197         int y = 1;
198
199         y += layout_pair(boot_editor, y, boot_editor->widgets.image_l,
200                                          boot_editor->widgets.image_f);
201
202         y += layout_pair(boot_editor, y, boot_editor->widgets.initrd_l,
203                                          boot_editor->widgets.initrd_f);
204
205         y += layout_pair(boot_editor, y, boot_editor->widgets.dtb_l,
206                                          boot_editor->widgets.dtb_f);
207
208         y += layout_pair(boot_editor, y, boot_editor->widgets.args_l,
209                                          boot_editor->widgets.args_f);
210
211
212         y++;
213         widget_move(widget_button_base(boot_editor->widgets.ok_b), y, 9);
214         widget_move(widget_button_base(boot_editor->widgets.cancel_b), y, 19);
215 }
216
217 struct boot_editor *boot_editor_init(struct cui *cui,
218                 struct pmenu_item *item,
219                 const struct system_info *sysinfo,
220                 void (*on_exit)(struct cui *cui,
221                                 struct pmenu_item *item,
222                                 struct pb_boot_data *bd))
223 {
224         char *image, *initrd, *dtb, *args;
225         struct boot_editor *boot_editor;
226         struct nc_widgetset *set;
227         int field_size;
228
229         (void)sysinfo;
230
231         boot_editor = talloc_zero(cui, struct boot_editor);
232
233         if (!boot_editor)
234                 return NULL;
235
236         talloc_set_destructor(boot_editor, boot_editor_destructor);
237         boot_editor->cui = cui;
238         boot_editor->item = item;
239         boot_editor->on_exit = on_exit;
240
241         boot_editor->label_x = 1;
242         boot_editor->field_x = 9;
243
244         nc_scr_init(&boot_editor->scr, pb_boot_editor_sig, 0,
245                         cui, boot_editor_process_key,
246                 boot_editor_post, boot_editor_unpost, boot_editor_resize);
247
248         boot_editor->scr.frame.ltitle = talloc_strdup(boot_editor,
249                         "Petitboot Option Editor");
250         boot_editor->scr.frame.rtitle = NULL;
251         boot_editor->scr.frame.help = talloc_strdup(boot_editor,
252                         "Enter=accept");
253
254         if (item) {
255                 struct pb_boot_data *bd = cod_from_item(item)->bd;
256                 image = bd->image;
257                 initrd = bd->initrd;
258                 dtb = bd->dtb;
259                 args = bd->args;
260         } else {
261                 image = initrd = dtb = args = "";
262         }
263
264         field_size = COLS - 1 - boot_editor->field_x;
265
266         boot_editor->widgetset = set = widgetset_create(boot_editor,
267                         boot_editor->scr.main_ncw,
268                         boot_editor->scr.sub_ncw);
269
270         boot_editor->widgets.image_l = widget_new_label(set, 0, 0, "image:");
271         boot_editor->widgets.image_f = widget_new_textbox(set, 0, 0,
272                                                 field_size, image);
273
274         boot_editor->widgets.initrd_l = widget_new_label(set, 0, 0, "initrd:");
275         boot_editor->widgets.initrd_f = widget_new_textbox(set, 0, 0,
276                                                 field_size, initrd);
277
278         boot_editor->widgets.dtb_l = widget_new_label(set, 0, 0, "dtb:");
279         boot_editor->widgets.dtb_f = widget_new_textbox(set, 0, 0,
280                                                 field_size, dtb);
281
282         boot_editor->widgets.args_l = widget_new_label(set, 0, 0, "args:");
283         boot_editor->widgets.args_f = widget_new_textbox(set, 0, 0,
284                                         field_size, args);
285
286         boot_editor->widgets.ok_b = widget_new_button(set, 0, 0, 6,
287                                         "OK", ok_click, boot_editor);
288         boot_editor->widgets.cancel_b = widget_new_button(set, 0, 0, 6,
289                                         "Cancel", cancel_click, boot_editor);
290
291         boot_editor_layout_widgets(boot_editor);
292
293         return boot_editor;
294 }