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