]> git.ipfire.org Git - thirdparty/newt.git/blob - dialogboxes.c
sync with 0.52.0
[thirdparty/newt.git] / dialogboxes.c
1 /* simple dialog boxes, used by both whiptail and tcl dialog bindings */
2
3 #include "config.h"
4 #include <fcntl.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include <stdlib.h>
8 #include <unistd.h>
9 #include <wchar.h>
10 #include <slang.h>
11
12 #include "nls.h"
13 #include "dialogboxes.h"
14 #include "newt.h"
15 #include "newt_pr.h"
16 #include "popt.h"
17
18 #define MAXBUF 200
19 #define MAXFORMAT 20
20
21 /* globals -- ick */
22 static int buttonHeight = 1;
23
24 int max (int a, int b)
25 {
26 return (a > b) ? a : b;
27 }
28
29 int min (int a, int b)
30 {
31 return ( a < b) ? a : b ;
32 }
33
34 static newtComponent (*makeButton)(int left, int right, const char * text) =
35 newtCompactButton;
36
37 static void addButtons(int height, int width, newtComponent form,
38 newtComponent * okay, newtComponent * cancel,
39 int flags) {
40 // FIXME: DO SOMETHING ABOUT THE HARD-CODED CONSTANTS
41 if (flags & FLAG_NOCANCEL) {
42 *okay = makeButton((width - 8) / 2, height - buttonHeight - 1,
43 dgettext(PACKAGE, "Ok"));
44 *cancel = NULL;
45 newtFormAddComponent(form, *okay);
46 } else {
47 *okay = makeButton((width - 18) / 3, height - buttonHeight - 1,
48 dgettext(PACKAGE,"Ok"));
49 *cancel = makeButton(((width - 18) / 3) * 2 + 9,
50 height - buttonHeight - 1,
51 dgettext(PACKAGE,"Cancel"));
52 newtFormAddComponents(form, *okay, *cancel, NULL);
53 }
54 }
55
56 static newtComponent textbox(int maxHeight, int width, const char * text,
57 int flags, int * height) {
58 newtComponent tb;
59 int sFlag = (flags & FLAG_SCROLL_TEXT) ? NEWT_FLAG_SCROLL : 0;
60 int i;
61 char * buf, * dst;
62 const char * src;
63
64 dst = buf = alloca(strlen(text) + 1);
65 src = text;
66 while (*src) {
67 if (*src == '\\' && *(src + 1) == 'n') {
68 src += 2;
69 *dst++ = '\n';
70 } else
71 *dst++ = *src++;
72 }
73 *dst++ = '\0';
74
75 tb = newtTextbox(1, 0, width, maxHeight, NEWT_FLAG_WRAP | sFlag);
76 newtTextboxSetText(tb, buf);
77
78 i = newtTextboxGetNumLines(tb);
79 if (i < maxHeight) {
80 newtTextboxSetHeight(tb, i);
81 maxHeight = i;
82 }
83
84 *height = maxHeight;
85
86 return tb;
87 }
88
89 int gauge(const char * text, int height, int width, poptContext optCon, int fd,
90 int flags) {
91 newtComponent form, scale, tb;
92 int top;
93 const char * arg;
94 char * end;
95 int val;
96 FILE * f = fdopen(fd, "r");
97 char buf[3000];
98 char buf3[50];
99 int i;
100
101 setlinebuf(f);
102
103 if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
104 val = strtoul(arg, &end, 10);
105 if (*end) return DLG_ERROR;
106
107 tb = textbox(height - 3, width - 2, text, flags, &top);
108
109 form = newtForm(NULL, NULL, 0);
110
111 scale = newtScale(2, height - 2, width - 4, 100);
112 newtScaleSet(scale, val);
113
114 newtFormAddComponents(form, tb, scale, NULL);
115
116 newtDrawForm(form);
117 newtRefresh();
118
119 while (fgets(buf, sizeof(buf) - 1, f)) {
120 buf[strlen(buf) - 1] = '\0';
121
122 if (!strcmp(buf, "XXX")) {
123 fgets(buf3, sizeof(buf3) - 1, f);
124 buf3[strlen(buf3) - 1] = '\0';
125 arg = buf3;
126
127 i = 0;
128 while (fgets(buf + i, sizeof(buf) - 1 - i, f)) {
129 buf[strlen(buf) - 1] = '\0';
130 if (!strcmp(buf + i, "XXX")) {
131 *(buf + i) = '\0';
132 break;
133 }
134 i = strlen(buf);
135 }
136
137 newtTextboxSetText(tb, buf);
138 } else {
139 arg = buf;
140 }
141
142 val = strtoul(buf, &end, 10);
143 if (!*end) {
144 newtScaleSet(scale, val);
145 newtDrawForm(form);
146 newtRefresh();
147 }
148 }
149
150 return DLG_OKAY;
151 }
152
153 int inputBox(const char * text, int height, int width, poptContext optCon,
154 int flags, const char ** result) {
155 newtComponent form, entry, okay, cancel, answer, tb;
156 const char * val;
157 int pFlag = (flags & FLAG_PASSWORD) ? NEWT_FLAG_PASSWORD : 0;
158 int rc = DLG_OKAY;
159 int top;
160
161 val = poptGetArg(optCon);
162 tb = textbox(height - 3 - buttonHeight, width - 2,
163 text, flags, &top);
164
165 form = newtForm(NULL, NULL, 0);
166 entry = newtEntry(1, top + 1, val, width - 2, &val,
167 NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT | pFlag);
168
169 newtFormAddComponents(form, tb, entry, NULL);
170
171 addButtons(height, width, form, &okay, &cancel, flags);
172
173 answer = newtRunForm(form);
174 if (answer == cancel)
175 rc = DLG_CANCEL;
176 else if (answer == NULL)
177 rc = DLG_ESCAPE;
178
179 *result = val;
180
181 return rc;
182 }
183
184 static int mystrncpyw(char *dest, const char *src, int n, int *maxwidth)
185 {
186 int i = 0;
187 int w = 0, cw;
188 wchar_t c;
189 mbstate_t ps;
190 const char *p = src;
191 char *d = dest;
192
193 memset(&ps, 0, sizeof(ps));
194
195 for (;;) {
196 int ret = mbrtowc(&c, p, MB_CUR_MAX, &ps);
197 if (ret <= 0) break;
198 if (ret + i >= n) break;
199 cw = wcwidth(c);
200 if (cw < 0) break;
201 if (cw + w > *maxwidth) break;
202 w += cw;
203 memcpy(d, p, ret);
204 d += ret;
205 p += ret;
206 i += ret;
207 }
208 dest[i] = '\0';
209 *maxwidth = w;
210 return i;
211 }
212
213 int listBox(const char * text, int height, int width, poptContext optCon,
214 int flags, const char *default_item, const char ** result) {
215 newtComponent form, okay, tb, answer, listBox;
216 newtComponent cancel = NULL;
217 const char * arg;
218 char * end;
219 int listHeight;
220 int numItems = 0;
221 int allocedItems = 5;
222 int i, top;
223 int rc = DLG_OKAY;
224 char buf[MAXBUF];
225 int maxTagWidth = 0;
226 int maxTextWidth = 0;
227 int defItem = -1;
228 int scrollFlag;
229 int lineWidth, textWidth, tagWidth;
230 struct {
231 const char * text;
232 const char * tag;
233 } * itemInfo = malloc(allocedItems * sizeof(*itemInfo));
234
235 if (itemInfo == NULL) return DLG_ERROR;
236 if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
237 listHeight = strtoul(arg, &end, 10);
238 if (*end) return DLG_ERROR;
239
240 while ((arg = poptGetArg(optCon))) {
241 if (allocedItems == numItems) {
242 allocedItems += 5;
243 itemInfo = realloc(itemInfo, sizeof(*itemInfo) * allocedItems);
244 if (itemInfo == NULL) return DLG_ERROR;
245 }
246
247 itemInfo[numItems].tag = arg;
248 if (default_item && (strcmp(default_item, arg) == 0)) {
249 defItem = numItems;
250 }
251 if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
252
253 if (!(flags & FLAG_NOITEM)) {
254 itemInfo[numItems].text = arg;
255 } else
256 itemInfo[numItems].text = "";
257
258 if (wstrlen(itemInfo[numItems].text,-1) > (unsigned int)maxTextWidth)
259 maxTextWidth = wstrlen(itemInfo[numItems].text,-1);
260 if (wstrlen(itemInfo[numItems].tag,-1) > (unsigned int)maxTagWidth)
261 maxTagWidth = wstrlen(itemInfo[numItems].tag,-1);
262
263 numItems++;
264 }
265 if (numItems == 0)
266 return DLG_ERROR;
267
268 if (flags & FLAG_NOTAGS) {
269 maxTagWidth = 0;
270 }
271
272 form = newtForm(NULL, NULL, 0);
273
274 tb = textbox(height - 4 - buttonHeight - listHeight, width - 2,
275 text, flags, &top);
276
277 if (listHeight >= numItems) {
278 scrollFlag = 0;
279 i = 0;
280 } else {
281 scrollFlag = NEWT_FLAG_SCROLL;
282 i = 2;
283 }
284
285 lineWidth = min(maxTagWidth + maxTextWidth + i, SLtt_Screen_Cols - 10);
286 listBox = newtListbox( (width - lineWidth) / 2 , top + 1, listHeight,
287 NEWT_FLAG_RETURNEXIT | scrollFlag);
288
289 textWidth = maxTextWidth;
290 tagWidth = maxTagWidth;
291 if (maxTextWidth == 0) {
292 tagWidth = lineWidth;
293 } else {
294 if (maxTextWidth + maxTagWidth + i > lineWidth)
295 tagWidth = textWidth = (lineWidth / 2) - 2;
296 else {
297 tagWidth++;
298 textWidth++;
299 }
300 }
301
302 if (!(flags & FLAG_NOTAGS)) {
303 for (i = 0; i < numItems; i++) {
304 int w = tagWidth;
305 int len, j;
306 len = mystrncpyw(buf, itemInfo[i].tag, MAXBUF, &w);
307 for (j = 0; j < tagWidth - w; j++) {
308 if (len >= MAXBUF) break;
309 buf[len++] = ' ';
310 }
311 buf[len] = '\0';
312 w = textWidth;
313 mystrncpyw(buf + len, itemInfo[i].text, MAXBUF-len, &w);
314 newtListboxAddEntry(listBox, buf, (void *) i);
315 }
316 } else {
317 for (i = 0; i < numItems; i++) {
318 snprintf(buf, MAXBUF, "%s", itemInfo[i].text);
319 newtListboxAddEntry(listBox, buf, (void *) i);
320 }
321 }
322
323 if (defItem != -1)
324 newtListboxSetCurrent (listBox, defItem);
325
326 newtFormAddComponents(form, tb, listBox, NULL);
327
328 addButtons(height, width, form, &okay, &cancel, flags);
329
330 answer = newtRunForm(form);
331 if (answer == cancel)
332 rc = DLG_CANCEL;
333 if (answer == NULL)
334 rc = DLG_ESCAPE;
335
336 i = (int) newtListboxGetCurrent(listBox);
337 *result = itemInfo[i].tag;
338
339 return rc;
340 }
341
342 int checkList(const char * text, int height, int width, poptContext optCon,
343 int useRadio, int flags, const char *** selections) {
344 newtComponent form, okay, tb, subform, answer;
345 newtComponent sb = NULL, cancel = NULL;
346 const char * arg;
347 char * end;
348 int listHeight;
349 int numBoxes = 0;
350 int allocedBoxes = 5;
351 int i;
352 int numSelected;
353 int rc = DLG_OKAY;
354 char buf[MAXBUF], format[MAXFORMAT];
355 int maxWidth = 0;
356 int top;
357 struct {
358 const char * text;
359 const char * tag;
360 newtComponent comp;
361 } * cbInfo = malloc(allocedBoxes * sizeof(*cbInfo));
362 char * cbStates = malloc(allocedBoxes * sizeof(cbStates));
363
364 if ( (cbInfo == NULL) || (cbStates == NULL)) return DLG_ERROR;
365 if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
366 listHeight = strtoul(arg, &end, 10);
367 if (*end) return DLG_ERROR;
368
369 while ((arg = poptGetArg(optCon))) {
370 if (allocedBoxes == numBoxes) {
371 allocedBoxes += 5;
372 cbInfo = realloc(cbInfo, sizeof(*cbInfo) * allocedBoxes);
373 cbStates = realloc(cbStates, sizeof(*cbStates) * allocedBoxes);
374 if ((cbInfo == NULL) || (cbStates == NULL)) return DLG_ERROR;
375 }
376
377 cbInfo[numBoxes].tag = arg;
378 if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
379
380 if (!(flags & FLAG_NOITEM)) {
381 cbInfo[numBoxes].text = arg;
382 if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
383 } else
384 cbInfo[numBoxes].text = "";
385
386 if (!strcmp(arg, "1") || !strcasecmp(arg, "on") ||
387 !strcasecmp(arg, "yes"))
388 cbStates[numBoxes] = '*';
389 else
390 cbStates[numBoxes] = ' ';
391
392 if (wstrlen(cbInfo[numBoxes].tag,-1) > (unsigned int)maxWidth)
393 maxWidth = wstrlen(cbInfo[numBoxes].tag,-1);
394
395 numBoxes++;
396 }
397
398 form = newtForm(NULL, NULL, 0);
399
400 tb = textbox(height - 3 - buttonHeight - listHeight, width - 2,
401 text, flags, &top);
402
403 if (listHeight < numBoxes) {
404 sb = newtVerticalScrollbar(width - 4,
405 top + 1,
406 listHeight, NEWT_COLORSET_CHECKBOX,
407 NEWT_COLORSET_ACTCHECKBOX);
408 newtFormAddComponent(form, sb);
409 }
410 subform = newtForm(sb, NULL, 0);
411 newtFormSetBackground(subform, NEWT_COLORSET_CHECKBOX);
412
413 snprintf(format, MAXFORMAT, "%%-%ds %%s", maxWidth);
414 for (i = 0; i < numBoxes; i++) {
415 snprintf(buf, MAXBUF, format, cbInfo[i].tag, cbInfo[i].text);
416
417 if (useRadio)
418 cbInfo[i].comp = newtRadiobutton(4, top + 1 + i, buf,
419 cbStates[i] != ' ',
420 i ? cbInfo[i - 1].comp : NULL);
421 else
422 cbInfo[i].comp = newtCheckbox(4, top + 1 + i, buf,
423 cbStates[i], NULL, cbStates + i);
424
425 newtCheckboxSetFlags(cbInfo[i].comp, NEWT_FLAG_RETURNEXIT, NEWT_FLAGS_SET);
426 newtFormAddComponent(subform, cbInfo[i].comp);
427 }
428
429 newtFormSetHeight(subform, listHeight);
430 newtFormSetWidth(subform, width - 10);
431
432 newtFormAddComponents(form, tb, subform, NULL);
433
434 addButtons(height, width, form, &okay, &cancel, flags);
435
436 answer = newtRunForm(form);
437 if (answer == cancel)
438 rc = DLG_CANCEL;
439 if (answer == NULL)
440 rc = DLG_ESCAPE;
441
442 if (useRadio) {
443 answer = newtRadioGetCurrent(cbInfo[0].comp);
444 for (i = 0; i < numBoxes; i++)
445 if (cbInfo[i].comp == answer) {
446 *selections = malloc(sizeof(char *) * 2);
447 if (*selections == NULL) return DLG_ERROR;
448 (*selections)[0] = cbInfo[i].tag;
449 (*selections)[1] = NULL;
450 break;
451 }
452 } else {
453 numSelected = 0;
454 for (i = 0; i < numBoxes; i++) {
455 if (cbStates[i] != ' ') numSelected++;
456 }
457
458 *selections = malloc(sizeof(char *) * (numSelected + 1));
459 if (*selections == NULL) return DLG_ERROR;
460
461 numSelected = 0;
462 for (i = 0; i < numBoxes; i++) {
463 if (cbStates[i] != ' ')
464 (*selections)[numSelected++] = cbInfo[i].tag;
465 }
466
467 (*selections)[numSelected] = NULL;
468 }
469
470 return rc;
471 }
472
473 int messageBox(const char * text, int height, int width, int type, int flags) {
474 newtComponent form, yes, tb, answer;
475 newtComponent no = NULL;
476 int rc = DLG_OKAY;
477 int tFlag = (flags & FLAG_SCROLL_TEXT) ? NEWT_FLAG_SCROLL : 0;
478
479 form = newtForm(NULL, NULL, 0);
480
481 tb = newtTextbox(1, 1, width - 2, height - 3 - buttonHeight,
482 NEWT_FLAG_WRAP | tFlag);
483 newtTextboxSetText(tb, text);
484
485 newtFormAddComponent(form, tb);
486
487 switch ( type ) {
488 case MSGBOX_INFO:
489 break;
490 case MSGBOX_MSG:
491 // FIXME Do something about the hard-coded constants
492 yes = makeButton((width - 8) / 2, height - 1 - buttonHeight,
493 dgettext(PACKAGE,"Ok"));
494 newtFormAddComponent(form, yes);
495 break;
496 default:
497 yes = makeButton((width - 16) / 3, height - 1 - buttonHeight,
498 dgettext(PACKAGE,"Yes"));
499 no = makeButton(((width - 16) / 3) * 2 + 9, height - 1 - buttonHeight,
500 dgettext(PACKAGE,"No"));
501 newtFormAddComponents(form, yes, no, NULL);
502
503 if (flags & FLAG_DEFAULT_NO)
504 newtFormSetCurrent(form, no);
505 }
506
507 if ( type != MSGBOX_INFO ) {
508 if (newtRunForm(form) == NULL)
509 rc = DLG_ESCAPE;
510
511 answer = newtFormGetCurrent(form);
512
513 if (answer == no)
514 return DLG_CANCEL;
515 }
516 else {
517 newtDrawForm(form);
518 newtRefresh();
519 }
520
521
522
523 return rc;
524 }
525
526 void useFullButtons(int state) {
527 if (state) {
528 buttonHeight = 3;
529 makeButton = newtButton;
530 } else {
531 buttonHeight = 1;
532 makeButton = newtCompactButton;
533 }
534 }