]> git.ipfire.org Git - thirdparty/newt.git/blame - dialogboxes.c
don't call automake in autogen.sh
[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) {
eadebb02 49 case 0: return dgettext(PACKAGE, "Ok");
50 case 1: return dgettext(PACKAGE, "Cancel");
51 case 2: return dgettext(PACKAGE, "Yes");
52 case 3: return dgettext(PACKAGE, "No");
60d3c50b 53 default:
54 return NULL;
55 }
60d3c50b 56}
57
649a0152 58static void addButtons(int height, int width, newtComponent form,
6f481af2 59 newtComponent * okay, newtComponent * cancel,
60 int flags) {
feef2cb5 61 // FIXME: DO SOMETHING ABOUT THE HARD-CODED CONSTANTS
649a0152 62 if (flags & FLAG_NOCANCEL) {
feef2cb5 63 *okay = makeButton((width - 8) / 2, height - buttonHeight - 1,
60d3c50b 64 getButtonText(BUTTON_OK));
feef2cb5 65 *cancel = NULL;
6f481af2 66 newtFormAddComponent(form, *okay);
649a0152 67 } else {
feef2cb5 68 *okay = makeButton((width - 18) / 3, height - buttonHeight - 1,
60d3c50b 69 getButtonText(BUTTON_OK));
6f481af2 70 *cancel = makeButton(((width - 18) / 3) * 2 + 9,
feef2cb5 71 height - buttonHeight - 1,
60d3c50b 72 getButtonText(BUTTON_CANCEL));
6f481af2 73 newtFormAddComponents(form, *okay, *cancel, NULL);
649a0152 74 }
75}
76
ae446151
ML
77static void cleanNewlines(char *text)
78{
79 char *p, *q;
80
81 for (p = q = text; *p; p++, q++)
82 if (*p == '\\' && p[1] == 'n') {
83 p++;
84 *q = '\n';
85 } else
86 *q = *p;
87 *q = '\0';
88}
89
eb0a0545 90static newtComponent textbox(int maxHeight, int width, const char * text,
6f481af2 91 int flags, int * height) {
649a0152 92 newtComponent tb;
93 int sFlag = (flags & FLAG_SCROLL_TEXT) ? NEWT_FLAG_SCROLL : 0;
94 int i;
ae446151
ML
95 char *buf;
96
97 buf = alloca(strlen(text) + 1);
98 strcpy(buf, text);
99 cleanNewlines(buf);
649a0152 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
cf6356e4
ML
145 do {
146 if (!fgets(buf, sizeof(buf) - 1, f))
147 continue;
6f481af2 148 buf[strlen(buf) - 1] = '\0';
149
150 if (!strcmp(buf, "XXX")) {
cf6356e4
ML
151 while (!fgets(buf3, sizeof(buf3) - 1, f) && !feof(f))
152 ;
153 if (feof(f))
c00a8d1b 154 break;
6f481af2 155 buf3[strlen(buf3) - 1] = '\0';
6f481af2 156
157 i = 0;
cf6356e4
ML
158 do {
159 if (!fgets(buf + i, sizeof(buf) - 1 - i, f))
160 continue;
ae446151 161 if (!strcmp(buf + i, "XXX\n")) {
6f481af2 162 *(buf + i) = '\0';
163 break;
164 }
165 i = strlen(buf);
cf6356e4 166 } while (!feof(f));
6f481af2 167
ae446151
ML
168 if (i > 0)
169 buf[strlen(buf) - 1] = '\0';
170 else
171 buf[0] = '\0';
172
173 cleanNewlines(buf);
6f481af2 174 newtTextboxSetText(tb, buf);
44e7bee7
ML
175
176 arg = buf3;
177 } else {
178 arg = buf;
6f481af2 179 }
180
44e7bee7 181 val = strtoul(arg, &end, 10);
ae446151 182 if (!*end) {
6f481af2 183 newtScaleSet(scale, val);
184 newtDrawForm(form);
185 newtRefresh();
186 }
cf6356e4 187 } while (!feof(f));
649a0152 188
3341bdc5
ML
189 newtFormDestroy(form);
190
649a0152 191 return DLG_OKAY;
192}
193
eb0a0545 194int inputBox(const char * text, int height, int width, poptContext optCon,
f40f18ae 195 int flags, char ** result) {
649a0152 196 newtComponent form, entry, okay, cancel, answer, tb;
d78245ab 197 const char * val;
feef2cb5 198 int pFlag = (flags & FLAG_PASSWORD) ? NEWT_FLAG_PASSWORD : 0;
649a0152 199 int rc = DLG_OKAY;
200 int top;
201
202 val = poptGetArg(optCon);
203 tb = textbox(height - 3 - buttonHeight, width - 2,
6f481af2 204 text, flags, &top);
649a0152 205
206 form = newtForm(NULL, NULL, 0);
207 entry = newtEntry(1, top + 1, val, width - 2, &val,
feef2cb5 208 NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT | pFlag);
649a0152 209
210 newtFormAddComponents(form, tb, entry, NULL);
211
212 addButtons(height, width, form, &okay, &cancel, flags);
213
214 answer = newtRunForm(form);
f40f18ae 215 *result = NULL;
649a0152 216 if (answer == cancel)
6f481af2 217 rc = DLG_CANCEL;
feef2cb5 218 else if (answer == NULL)
219 rc = DLG_ESCAPE;
f40f18ae
ML
220 else
221 *result = strdup(val);
649a0152 222
3341bdc5
ML
223 newtFormDestroy(form);
224
649a0152 225 return rc;
226}
227
feef2cb5 228static int mystrncpyw(char *dest, const char *src, int n, int *maxwidth)
229{
230 int i = 0;
231 int w = 0, cw;
232 wchar_t c;
233 mbstate_t ps;
234 const char *p = src;
235 char *d = dest;
236
237 memset(&ps, 0, sizeof(ps));
238
239 for (;;) {
240 int ret = mbrtowc(&c, p, MB_CUR_MAX, &ps);
241 if (ret <= 0) break;
242 if (ret + i >= n) break;
243 cw = wcwidth(c);
244 if (cw < 0) break;
245 if (cw + w > *maxwidth) break;
246 w += cw;
247 memcpy(d, p, ret);
248 d += ret;
249 p += ret;
250 i += ret;
251 }
252 dest[i] = '\0';
253 *maxwidth = w;
254 return i;
255}
256
eb0a0545 257int listBox(const char * text, int height, int width, poptContext optCon,
f40f18ae 258 int flags, const char *default_item, char ** result) {
649a0152 259 newtComponent form, okay, tb, answer, listBox;
260 newtComponent cancel = NULL;
eb0a0545 261 const char * arg;
262 char * end;
649a0152 263 int listHeight;
264 int numItems = 0;
265 int allocedItems = 5;
266 int i, top;
267 int rc = DLG_OKAY;
feef2cb5 268 char buf[MAXBUF];
649a0152 269 int maxTagWidth = 0;
270 int maxTextWidth = 0;
feef2cb5 271 int defItem = -1;
394c9a80 272 int scrollFlag;
feef2cb5 273 int lineWidth, textWidth, tagWidth;
649a0152 274 struct {
6f481af2 275 const char * text;
276 const char * tag;
649a0152 277 } * itemInfo = malloc(allocedItems * sizeof(*itemInfo));
278
b3ddfdd7 279 if (itemInfo == NULL) return DLG_ERROR;
649a0152 280 if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
281 listHeight = strtoul(arg, &end, 10);
282 if (*end) return DLG_ERROR;
283
284 while ((arg = poptGetArg(optCon))) {
6f481af2 285 if (allocedItems == numItems) {
286 allocedItems += 5;
287 itemInfo = realloc(itemInfo, sizeof(*itemInfo) * allocedItems);
288 if (itemInfo == NULL) return DLG_ERROR;
289 }
290
291 itemInfo[numItems].tag = arg;
feef2cb5 292 if (default_item && (strcmp(default_item, arg) == 0)) {
293 defItem = numItems;
294 }
6f481af2 295 if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
296
297 if (!(flags & FLAG_NOITEM)) {
298 itemInfo[numItems].text = arg;
299 } else
300 itemInfo[numItems].text = "";
301
302 if (wstrlen(itemInfo[numItems].text,-1) > (unsigned int)maxTextWidth)
303 maxTextWidth = wstrlen(itemInfo[numItems].text,-1);
304 if (wstrlen(itemInfo[numItems].tag,-1) > (unsigned int)maxTagWidth)
305 maxTagWidth = wstrlen(itemInfo[numItems].tag,-1);
306
307 numItems++;
649a0152 308 }
b3ddfdd7 309 if (numItems == 0)
6f481af2 310 return DLG_ERROR;
649a0152 311
57cb49e7 312 if (flags & FLAG_NOTAGS) {
6f481af2 313 maxTagWidth = 0;
57cb49e7 314 }
315
649a0152 316 form = newtForm(NULL, NULL, 0);
317
318 tb = textbox(height - 4 - buttonHeight - listHeight, width - 2,
6f481af2 319 text, flags, &top);
649a0152 320
321 if (listHeight >= numItems) {
6f481af2 322 scrollFlag = 0;
323 i = 0;
649a0152 324 } else {
6f481af2 325 scrollFlag = NEWT_FLAG_SCROLL;
326 i = 2;
649a0152 327 }
328
10bbfd28 329 lineWidth = min(maxTagWidth + maxTextWidth + i + 1, SLtt_Screen_Cols - 6);
feef2cb5 330 listBox = newtListbox( (width - lineWidth) / 2 , top + 1, listHeight,
331 NEWT_FLAG_RETURNEXIT | scrollFlag);
649a0152 332
feef2cb5 333 textWidth = maxTextWidth;
334 tagWidth = maxTagWidth;
335 if (maxTextWidth == 0) {
336 tagWidth = lineWidth;
337 } else {
10bbfd28
ML
338 tagWidth++;
339 textWidth++;
340 while (textWidth + tagWidth + i > lineWidth) {
341 if (textWidth >= tagWidth && textWidth > 0)
342 textWidth--;
343 else if (tagWidth > 0)
344 tagWidth--;
345 else
346 break;
347 }
649a0152 348 }
349
feef2cb5 350 if (!(flags & FLAG_NOTAGS)) {
351 for (i = 0; i < numItems; i++) {
352 int w = tagWidth;
353 int len, j;
354 len = mystrncpyw(buf, itemInfo[i].tag, MAXBUF, &w);
355 for (j = 0; j < tagWidth - w; j++) {
3341bdc5
ML
356 if (len + 1 >= MAXBUF)
357 break;
feef2cb5 358 buf[len++] = ' ';
359 }
360 buf[len] = '\0';
361 w = textWidth;
362 mystrncpyw(buf + len, itemInfo[i].text, MAXBUF-len, &w);
8bec7d99 363 newtListboxAddEntry(listBox, buf, (void *)(long) i);
feef2cb5 364 }
365 } else {
366 for (i = 0; i < numItems; i++) {
367 snprintf(buf, MAXBUF, "%s", itemInfo[i].text);
8bec7d99 368 newtListboxAddEntry(listBox, buf, (void *)(long) i);
feef2cb5 369 }
370 }
371
372 if (defItem != -1)
373 newtListboxSetCurrent (listBox, defItem);
374
649a0152 375 newtFormAddComponents(form, tb, listBox, NULL);
376
377 addButtons(height, width, form, &okay, &cancel, flags);
378
379 answer = newtRunForm(form);
f40f18ae 380 *result = NULL;
649a0152 381 if (answer == cancel)
6f481af2 382 rc = DLG_CANCEL;
5a34899c 383 else if (answer == NULL)
feef2cb5 384 rc = DLG_ESCAPE;
f40f18ae
ML
385 else {
386 i = (long) newtListboxGetCurrent(listBox);
387 *result = strdup(itemInfo[i].tag);
388 }
649a0152 389
3341bdc5
ML
390 newtFormDestroy(form);
391 free(itemInfo);
392
649a0152 393 return rc;
394}
395
eb0a0545 396int checkList(const char * text, int height, int width, poptContext optCon,
f40f18ae 397 int useRadio, int flags, char *** selections) {
649a0152 398 newtComponent form, okay, tb, subform, answer;
399 newtComponent sb = NULL, cancel = NULL;
eb0a0545 400 const char * arg;
401 char * end;
649a0152 402 int listHeight;
403 int numBoxes = 0;
404 int allocedBoxes = 5;
405 int i;
406 int numSelected;
407 int rc = DLG_OKAY;
feef2cb5 408 char buf[MAXBUF], format[MAXFORMAT];
649a0152 409 int maxWidth = 0;
410 int top;
411 struct {
6f481af2 412 const char * text;
413 const char * tag;
414 newtComponent comp;
649a0152 415 } * cbInfo = malloc(allocedBoxes * sizeof(*cbInfo));
3341bdc5 416 char * cbStates = malloc(allocedBoxes * sizeof(*cbStates));
649a0152 417
b3ddfdd7 418 if ( (cbInfo == NULL) || (cbStates == NULL)) return DLG_ERROR;
649a0152 419 if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
420 listHeight = strtoul(arg, &end, 10);
421 if (*end) return DLG_ERROR;
422
423 while ((arg = poptGetArg(optCon))) {
6f481af2 424 if (allocedBoxes == numBoxes) {
425 allocedBoxes += 5;
426 cbInfo = realloc(cbInfo, sizeof(*cbInfo) * allocedBoxes);
427 cbStates = realloc(cbStates, sizeof(*cbStates) * allocedBoxes);
428 if ((cbInfo == NULL) || (cbStates == NULL)) return DLG_ERROR;
429 }
430
431 cbInfo[numBoxes].tag = arg;
432 if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
433
434 if (!(flags & FLAG_NOITEM)) {
435 cbInfo[numBoxes].text = arg;
436 if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
437 } else
438 cbInfo[numBoxes].text = "";
439
440 if (!strcmp(arg, "1") || !strcasecmp(arg, "on") ||
441 !strcasecmp(arg, "yes"))
442 cbStates[numBoxes] = '*';
443 else
444 cbStates[numBoxes] = ' ';
445
446 if (wstrlen(cbInfo[numBoxes].tag,-1) > (unsigned int)maxWidth)
447 maxWidth = wstrlen(cbInfo[numBoxes].tag,-1);
448
449 numBoxes++;
649a0152 450 }
451
452 form = newtForm(NULL, NULL, 0);
453
454 tb = textbox(height - 3 - buttonHeight - listHeight, width - 2,
6f481af2 455 text, flags, &top);
649a0152 456
457 if (listHeight < numBoxes) {
6f481af2 458 sb = newtVerticalScrollbar(width - 4,
459 top + 1,
460 listHeight, NEWT_COLORSET_CHECKBOX,
461 NEWT_COLORSET_ACTCHECKBOX);
462 newtFormAddComponent(form, sb);
649a0152 463 }
464 subform = newtForm(sb, NULL, 0);
465 newtFormSetBackground(subform, NEWT_COLORSET_CHECKBOX);
466
52b75483
ML
467 if (flags & FLAG_NOTAGS)
468 snprintf(format, MAXFORMAT, "%%.0s%%s");
469 else
470 snprintf(format, MAXFORMAT, "%%-%ds %%s", maxWidth);
471
649a0152 472 for (i = 0; i < numBoxes; i++) {
6f481af2 473 snprintf(buf, MAXBUF, format, cbInfo[i].tag, cbInfo[i].text);
649a0152 474
6f481af2 475 if (useRadio)
476 cbInfo[i].comp = newtRadiobutton(4, top + 1 + i, buf,
477 cbStates[i] != ' ',
478 i ? cbInfo[i - 1].comp : NULL);
479 else
480 cbInfo[i].comp = newtCheckbox(4, top + 1 + i, buf,
481 cbStates[i], NULL, cbStates + i);
649a0152 482
feef2cb5 483 newtCheckboxSetFlags(cbInfo[i].comp, NEWT_FLAG_RETURNEXIT, NEWT_FLAGS_SET);
6f481af2 484 newtFormAddComponent(subform, cbInfo[i].comp);
649a0152 485 }
486
487 newtFormSetHeight(subform, listHeight);
488 newtFormSetWidth(subform, width - 10);
489
490 newtFormAddComponents(form, tb, subform, NULL);
491
492 addButtons(height, width, form, &okay, &cancel, flags);
493
494 answer = newtRunForm(form);
f40f18ae 495 *selections = NULL;
649a0152 496 if (answer == cancel)
6f481af2 497 rc = DLG_CANCEL;
5a34899c 498 else if (answer == NULL)
feef2cb5 499 rc = DLG_ESCAPE;
f40f18ae
ML
500 else {
501 if (useRadio) {
502 answer = newtRadioGetCurrent(cbInfo[0].comp);
503 *selections = malloc(sizeof(char *) * 2);
504 if (*selections == NULL)
505 return DLG_ERROR;
506 (*selections)[0] = (*selections)[1] = NULL;
507 for (i = 0; i < numBoxes; i++)
508 if (cbInfo[i].comp == answer) {
509 (*selections)[0] = strdup(cbInfo[i].tag);
510 break;
511 }
512 } else {
513 numSelected = 0;
514 for (i = 0; i < numBoxes; i++) {
515 if (cbStates[i] != ' ') numSelected++;
6f481af2 516 }
649a0152 517
f40f18ae
ML
518 *selections = malloc(sizeof(char *) * (numSelected + 1));
519 if (*selections == NULL)
520 return DLG_ERROR;
649a0152 521
f40f18ae
ML
522 numSelected = 0;
523 for (i = 0; i < numBoxes; i++) {
524 if (cbStates[i] != ' ')
525 (*selections)[numSelected++] = strdup(cbInfo[i].tag);
526 }
649a0152 527
f40f18ae
ML
528 (*selections)[numSelected] = NULL;
529 }
649a0152 530 }
531
73f1f27f
ML
532 free(cbInfo);
533 free(cbStates);
3341bdc5
ML
534 newtFormDestroy(form);
535
649a0152 536 return rc;
537}
538
eb0a0545 539int messageBox(const char * text, int height, int width, int type, int flags) {
649a0152 540 newtComponent form, yes, tb, answer;
541 newtComponent no = NULL;
feef2cb5 542 int rc = DLG_OKAY;
649a0152 543 int tFlag = (flags & FLAG_SCROLL_TEXT) ? NEWT_FLAG_SCROLL : 0;
544
545 form = newtForm(NULL, NULL, 0);
546
547 tb = newtTextbox(1, 1, width - 2, height - 3 - buttonHeight,
6f481af2 548 NEWT_FLAG_WRAP | tFlag);
649a0152 549 newtTextboxSetText(tb, text);
550
551 newtFormAddComponent(form, tb);
552
139f06bc 553 switch ( type ) {
554 case MSGBOX_INFO:
6f481af2 555 break;
139f06bc 556 case MSGBOX_MSG:
feef2cb5 557 // FIXME Do something about the hard-coded constants
558 yes = makeButton((width - 8) / 2, height - 1 - buttonHeight,
60d3c50b 559 getButtonText(BUTTON_OK));
6f481af2 560 newtFormAddComponent(form, yes);
561 break;
139f06bc 562 default:
feef2cb5 563 yes = makeButton((width - 16) / 3, height - 1 - buttonHeight,
60d3c50b 564 getButtonText(BUTTON_YES));
6f481af2 565 no = makeButton(((width - 16) / 3) * 2 + 9, height - 1 - buttonHeight,
60d3c50b 566 getButtonText(BUTTON_NO));
6f481af2 567 newtFormAddComponents(form, yes, no, NULL);
649a0152 568
6f481af2 569 if (flags & FLAG_DEFAULT_NO)
570 newtFormSetCurrent(form, no);
649a0152 571 }
572
139f06bc 573 if ( type != MSGBOX_INFO ) {
feef2cb5 574 if (newtRunForm(form) == NULL)
575 rc = DLG_ESCAPE;
139f06bc 576
6f481af2 577 answer = newtFormGetCurrent(form);
139f06bc 578
6f481af2 579 if (answer == no)
5a34899c 580 rc = DLG_CANCEL;
139f06bc 581 }
582 else {
6f481af2 583 newtDrawForm(form);
584 newtRefresh();
139f06bc 585 }
649a0152 586
3341bdc5 587 newtFormDestroy(form);
649a0152 588
feef2cb5 589 return rc;
649a0152 590}
591
592void useFullButtons(int state) {
593 if (state) {
6f481af2 594 buttonHeight = 3;
595 makeButton = newtButton;
649a0152 596 } else {
6f481af2 597 buttonHeight = 1;
598 makeButton = newtCompactButton;
649a0152 599 }
600}
60d3c50b 601
602void setButtonText(const char * text, int button) {
603 if (button < 0 || button >= BUTTONS)
604 return;
605 buttonText[button] = text;
606}