ui/ncurses: Add help facility to text screens
[petitboot] / ui / ncurses / nc-textscreen.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 <string.h>
23
24 #include <talloc/talloc.h>
25 #include <types/types.h>
26 #include <log/log.h>
27 #include <fold/fold.h>
28 #include <util/util.h>
29
30 #include "nc-cui.h"
31 #include "nc-textscreen.h"
32
33 struct text_screen *text_screen_from_scr(struct nc_scr *scr)
34 {
35         struct text_screen *text_screen;
36         assert(scr->sig == pb_text_screen_sig);
37         text_screen = container_of(scr, struct text_screen, scr);
38         return text_screen;
39 }
40
41 void text_screen_draw(struct text_screen *screen)
42 {
43         int max_y, i;
44
45         max_y = getmaxy(screen->scr.sub_ncw);
46
47         max_y = min(max_y, screen->scroll_y + screen->n_lines);
48
49         for (i = screen->scroll_y; i < max_y; i++)
50                 mvwaddstr(screen->scr.sub_ncw, i, 1, screen->lines[i]);
51
52         wrefresh(screen->scr.sub_ncw);
53 }
54
55 static void text_screen_scroll(struct text_screen *screen, int key)
56 {
57         int win_lines = getmaxy(screen->scr.sub_ncw);
58         int delta;
59
60         if (key == KEY_UP)
61                 delta = -1;
62         else if (key == KEY_DOWN)
63                 delta = 1;
64         else
65                 return;
66
67         if (screen->scroll_y + delta < 0)
68                 return;
69         if (screen->scroll_y + delta + win_lines > screen->n_lines)
70                 return;
71
72         screen->scroll_y += delta;
73         wscrl(screen->scr.sub_ncw, delta);
74
75         if (delta > 0) {
76                 mvwaddstr(screen->scr.sub_ncw, win_lines - 1, 1,
77                                 screen->lines[screen->scroll_y+win_lines-1]);
78         } else if (delta < 0) {
79                 mvwaddstr(screen->scr.sub_ncw, 0, 1,
80                                 screen->lines[screen->scroll_y]);
81         }
82
83         wrefresh(screen->scr.sub_ncw);
84 }
85
86 void text_screen_clear(struct text_screen *screen)
87 {
88         talloc_free(screen->lines);
89         screen->n_lines = 0;
90         screen->n_alloc_lines = 16;
91         screen->lines = talloc_array(screen, const char *,
92                         screen->n_alloc_lines);
93 }
94
95 static void __text_screen_append_line(struct text_screen *screen,
96                 const char *line)
97 {
98         if (screen->n_lines == screen->n_alloc_lines) {
99                 screen->n_alloc_lines *= 2;
100                 screen->lines = talloc_realloc(screen, screen->lines,
101                                                 const char *,
102                                                 screen->n_alloc_lines);
103         }
104
105         screen->lines[screen->n_lines] = line;
106         screen->n_lines++;
107 }
108
109 void text_screen_append_line(struct text_screen *screen, const char *fmt, ...)
110 {
111         char *line;
112         va_list ap;
113
114         if (fmt) {
115                 va_start(ap, fmt);
116                 line = talloc_vasprintf(screen->lines, fmt, ap);
117                 va_end(ap);
118         } else {
119                 line = "";
120         }
121
122         __text_screen_append_line(screen, line);
123 }
124
125 static int text_screen_fold_cb(void *arg, const char *buf, int len)
126 {
127         struct text_screen *screen = arg;
128
129         buf = len ? talloc_strndup(screen->lines, buf, len) : "";
130         __text_screen_append_line(screen, buf);
131
132         return 0;
133 }
134
135 void text_screen_set_text(struct text_screen *screen, const char *text)
136 {
137         fold_text(text, getmaxx(screen->scr.sub_ncw), text_screen_fold_cb,
138                         screen);
139 }
140
141 void text_screen_process_key(struct nc_scr *scr, int key)
142 {
143         struct text_screen *screen = text_screen_from_scr(scr);
144
145         switch (key) {
146         case 'x':
147                 screen->on_exit(screen->cui);
148                 break;
149         case KEY_DOWN:
150         case KEY_UP:
151                 text_screen_scroll(screen, key);
152                 break;
153         case 'h':
154                 if (screen->help_text)
155                         cui_show_help(screen->cui, screen->help_title,
156                                         screen->help_text);
157                 break;
158         default:
159                 break;
160         }
161 }
162
163 static void text_screen_resize(struct nc_scr *scr)
164 {
165         struct text_screen *screen = text_screen_from_scr(scr);
166         text_screen_draw(screen);
167 }
168
169 struct nc_scr *text_screen_scr(struct text_screen *screen)
170 {
171         return &screen->scr;
172 }
173
174 void text_screen_set_help(struct text_screen *screen, const char *title,
175                 const char *text)
176 {
177         screen->help_title = title;
178         screen->help_text = text;
179         screen->scr.frame.help = "x=exit h=help";
180 }
181
182 static int text_screen_post(struct nc_scr *scr)
183 {
184         nc_scr_frame_draw(scr);
185         redrawwin(scr->main_ncw);
186         wrefresh(scr->main_ncw);
187         return 0;
188 }
189
190 void text_screen_init(struct text_screen *screen, struct cui *cui,
191                 const char *title, void (*on_exit)(struct cui *))
192 {
193         nc_scr_init(&screen->scr, pb_text_screen_sig, 0,
194                         cui, text_screen_process_key,
195                         text_screen_post, NULL, text_screen_resize);
196
197         /* this will establish our array of lines */
198         screen->lines = NULL;
199         text_screen_clear(screen);
200
201         screen->cui = cui;
202         screen->on_exit = on_exit;
203
204         screen->scr.frame.ltitle = talloc_strdup(screen, title);
205         screen->scr.frame.rtitle = NULL;
206         screen->scr.frame.help = "x=exit";
207         scrollok(screen->scr.sub_ncw, true);
208 }