4abca38a4a1db33c63428cdad6df905004eb66fb
[petitboot] / ui / ncurses / nc-add-url.c
1 /*
2  *  Copyright (C) 2013 IBM Corporation
3  *
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.
7  *
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.
12  *
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
16  */
17
18 #if defined(HAVE_CONFIG_H)
19 #include "config.h"
20 #endif
21
22 #include <errno.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include <talloc/talloc.h>
27 #include <types/types.h>
28 #include <i18n/i18n.h>
29 #include <log/log.h>
30
31 #include "nc-cui.h"
32 #include "nc-add-url.h"
33 #include "nc-widgets.h"
34
35 #define N_FIELDS        5
36
37 extern const struct help_text add_url_help_text;
38
39 struct add_url_screen {
40         struct nc_scr           scr;
41         struct cui              *cui;
42         struct nc_widgetset     *widgetset;
43         WINDOW                  *pad;
44
45         bool                    exit;
46         bool                    show_help;
47         bool                    need_redraw;
48         void                    (*on_exit)(struct cui *);
49
50         int                     scroll_y;
51
52         int                     label_x;
53         int                     field_x;
54
55         struct {
56                 struct nc_widget_textbox        *url_f;
57                 struct nc_widget_label          *url_l;
58
59                 struct nc_widget_button         *ok_b;
60                 struct nc_widget_button         *help_b;
61                 struct nc_widget_button         *cancel_b;
62         } widgets;
63 };
64
65 static struct add_url_screen *add_url_screen_from_scr(struct nc_scr *scr)
66 {
67         struct add_url_screen *add_url_screen;
68
69         assert(scr->sig == pb_add_url_screen_sig);
70         add_url_screen = (struct add_url_screen *)
71                 ((char *)scr - (size_t)&((struct add_url_screen *)0)->scr);
72         assert(add_url_screen->scr.sig == pb_add_url_screen_sig);
73         return add_url_screen;
74 }
75
76 static void pad_refresh(struct add_url_screen *screen)
77 {
78         int y, x, rows, cols;
79
80         getmaxyx(screen->scr.sub_ncw, rows, cols);
81         getbegyx(screen->scr.sub_ncw, y, x);
82
83         prefresh(screen->pad, screen->scroll_y, 0, y, x, rows, cols);
84 }
85
86 static void add_url_screen_process_key(struct nc_scr *scr, int key)
87 {
88         struct add_url_screen *screen = add_url_screen_from_scr(scr);
89         bool handled;
90
91         handled = widgetset_process_key(screen->widgetset, key);
92
93         if (!handled) {
94                 switch (key) {
95                 case 'x':
96                 case 27: /* esc */
97                         screen->exit = true;
98                         break;
99                 case 'h':
100                         screen->show_help = true;
101                         break;
102                 }
103         }
104
105         if (screen->exit) {
106                 screen->on_exit(screen->cui);
107
108         } else if (screen->show_help) {
109                 screen->show_help = false;
110                 screen->need_redraw = true;
111                 cui_show_help(screen->cui, _("Retrieve Config"),
112                         &add_url_help_text);
113
114         } else if (handled) {
115                 pad_refresh(screen);
116         }
117 }
118
119 static int add_url_screen_post(struct nc_scr *scr)
120 {
121         struct add_url_screen *screen = add_url_screen_from_scr(scr);
122         widgetset_post(screen->widgetset);
123         nc_scr_frame_draw(scr);
124         if (screen->need_redraw) {
125                 redrawwin(scr->main_ncw);
126                 screen->need_redraw = false;
127         }
128         wrefresh(screen->scr.main_ncw);
129         pad_refresh(screen);
130         return 0;
131 }
132
133 static int add_url_screen_unpost(struct nc_scr *scr)
134 {
135         struct add_url_screen *screen = add_url_screen_from_scr(scr);
136         widgetset_unpost(screen->widgetset);
137         return 0;
138 }
139
140 struct nc_scr *add_url_screen_scr(struct add_url_screen *screen)
141 {
142         return &screen->scr;
143 }
144
145 static int screen_process_form(struct add_url_screen *screen)
146 {
147         char *url;
148         int rc;
149
150         url = widget_textbox_get_value(screen->widgets.url_f);
151         if (!url || !strlen(url))
152                 return 0;
153
154         /* Once we have all the info we need, tell the server */
155         rc = cui_send_url(screen->cui, url);
156
157         if (rc)
158                 pb_log("cui_send_retreive failed!\n");
159         else
160                 pb_debug("add_url url sent!\n");
161         return 0;
162 }
163
164 static void ok_click(void *arg)
165 {
166         struct add_url_screen *screen = arg;
167         if (screen_process_form(screen))
168                 /* errors are written to the status line, so we'll need
169                  * to refresh */
170                 wrefresh(screen->scr.main_ncw);
171         else
172                 screen->exit = true;
173 }
174
175 static void help_click(void *arg)
176 {
177         struct add_url_screen *screen = arg;
178         screen->show_help = true;
179 }
180
181 static void cancel_click(void *arg)
182 {
183         struct add_url_screen *screen = arg;
184         screen->exit = true;
185 }
186
187 static int layout_pair(struct add_url_screen *screen, int y,
188         struct nc_widget_label *label,
189         struct nc_widget *field)
190 {
191         struct nc_widget *label_w = widget_label_base(label);
192         widget_move(label_w, y, screen->label_x);
193         widget_move(field, y, screen->field_x);
194         return max(widget_height(label_w), widget_height(field));
195 }
196
197 static void add_url_screen_layout_widgets(struct add_url_screen *screen)
198 {
199         int y = 2;
200
201         /* url field */
202         y += layout_pair(screen, y, screen->widgets.url_l,
203                          widget_textbox_base(screen->widgets.url_f));
204
205         /* ok, help, cancel */
206         y += 1;
207
208         widget_move(widget_button_base(screen->widgets.ok_b),
209                 y, screen->field_x);
210         widget_move(widget_button_base(screen->widgets.help_b),
211                 y, screen->field_x + 14);
212         widget_move(widget_button_base(screen->widgets.cancel_b),
213                 y, screen->field_x + 28);
214 }
215
216 static void add_url_screen_widget_focus(struct nc_widget *widget, void *arg)
217 {
218         struct add_url_screen *screen = arg;
219         int w_y, w_height, w_focus, s_max, adjust;
220
221         w_height = widget_height(widget);
222         w_focus = widget_focus_y(widget);
223         w_y = widget_y(widget) + w_focus;
224         s_max = getmaxy(screen->scr.sub_ncw) - 1;
225
226         if (w_y < screen->scroll_y)
227                 screen->scroll_y = w_y;
228
229         else if (w_y + screen->scroll_y + 1 > s_max) {
230                 /* Fit as much of the widget into the screen as possible */
231                 adjust = min(s_max - 1, w_height - w_focus);
232                 if (w_y + adjust >= screen->scroll_y + s_max)
233                         screen->scroll_y = max(0, 1 + w_y + adjust - s_max);
234         } else
235                 return;
236
237         pad_refresh(screen);
238 }
239
240 static void add_url_screen_setup_widgets(struct add_url_screen *screen)
241 {
242         struct nc_widgetset *set = screen->widgetset;
243
244         build_assert(sizeof(screen->widgets) / sizeof(struct widget *)
245                         == N_FIELDS);
246
247         screen->widgets.url_l = widget_new_label(set, 0, 0,
248                         _("Configuration URL:"));
249         screen->widgets.url_f = widget_new_textbox(set, 0, 0, 50, NULL);
250
251         screen->widgets.ok_b = widget_new_button(set, 0, 0, 10, _("OK"),
252                         ok_click, screen);
253         screen->widgets.help_b = widget_new_button(set, 0, 0, 10, _("Help"),
254                         help_click, screen);
255         screen->widgets.cancel_b = widget_new_button(set, 0, 0, 10, _("Cancel"),
256                         cancel_click, screen);
257 }
258
259 static int add_url_screen_destroy(void *arg)
260 {
261         struct add_url_screen *screen = arg;
262         if (screen->pad)
263                 delwin(screen->pad);
264         return 0;
265 }
266
267 struct add_url_screen *add_url_screen_init(struct cui *cui,
268                 void (*on_exit)(struct cui *))
269 {
270         struct add_url_screen *screen;
271
272         screen = talloc_zero(cui, struct add_url_screen);
273         talloc_set_destructor(screen, add_url_screen_destroy);
274
275         screen->cui = cui;
276         screen->on_exit = on_exit;
277         screen->label_x = 2;
278         screen->field_x = 25;
279         screen->need_redraw = false;
280
281         nc_scr_init(&screen->scr, pb_add_url_screen_sig, 0,
282                 cui, add_url_screen_process_key,
283                 add_url_screen_post, add_url_screen_unpost,
284                 NULL);
285
286         screen->scr.frame.ltitle = talloc_strdup(screen,
287                         _("Petitboot Config Retrieval"));
288         screen->scr.frame.rtitle = NULL;
289         screen->scr.frame.help = talloc_strdup(screen,
290                         _("tab=next, shift+tab=previous, x=exit, h=help"));
291         nc_scr_frame_draw(&screen->scr);
292
293         screen->pad = newpad(LINES, COLS);
294         screen->widgetset = widgetset_create(screen, screen->scr.main_ncw,
295                         screen->pad);
296         widgetset_set_widget_focus(screen->widgetset,
297                         add_url_screen_widget_focus, screen);
298
299         add_url_screen_setup_widgets(screen);
300         add_url_screen_layout_widgets(screen);
301
302         return screen;
303 }
304