/* simple dialog boxes, used by both whiptail and tcl dialog bindings */ #include "config.h" #include #include #include #include #include #include #include #include "nls.h" #include "dialogboxes.h" #include "newt.h" #include "newt_pr.h" #include "popt.h" #define MAXBUF 200 #define MAXFORMAT 20 #define BUTTONS 4 /* globals -- ick */ static int buttonHeight = 1; static const char * buttonText[BUTTONS]; int max (int a, int b) { return (a > b) ? a : b; } int min (int a, int b) { return ( a < b) ? a : b ; } static newtComponent (*makeButton)(int left, int right, const char * text) = newtCompactButton; static const char * getButtonText(int button) { const char * text; if (button < 0 || button >= BUTTONS) return NULL; text = buttonText[button]; if (text) return text; switch (button) { case 0: return dgettext(PACKAGE, "Ok"); case 1: return dgettext(PACKAGE, "Cancel"); case 2: return dgettext(PACKAGE, "Yes"); case 3: return dgettext(PACKAGE, "No"); default: return NULL; } } static void addButtons(int height, int width, newtComponent form, newtComponent * okay, newtComponent * cancel, int flags) { // FIXME: DO SOMETHING ABOUT THE HARD-CODED CONSTANTS if (flags & FLAG_NOCANCEL) { *okay = makeButton((width - 8) / 2, height - buttonHeight - 1, getButtonText(BUTTON_OK)); *cancel = NULL; newtFormAddComponent(form, *okay); } else { *okay = makeButton((width - 18) / 3, height - buttonHeight - 1, getButtonText(BUTTON_OK)); *cancel = makeButton(((width - 18) / 3) * 2 + 9, height - buttonHeight - 1, getButtonText(BUTTON_CANCEL)); newtFormAddComponents(form, *okay, *cancel, NULL); } } static void cleanNewlines(char *text) { char *p, *q; for (p = q = text; *p; p++, q++) if (*p == '\\' && p[1] == 'n') { p++; *q = '\n'; } else *q = *p; *q = '\0'; } static newtComponent textbox(int maxHeight, int width, const char * text, int flags, int * height) { newtComponent tb; int sFlag = (flags & FLAG_SCROLL_TEXT) ? NEWT_FLAG_SCROLL : 0; int i; char *buf; buf = alloca(strlen(text) + 1); strcpy(buf, text); cleanNewlines(buf); tb = newtTextbox(1, 0, width, maxHeight, NEWT_FLAG_WRAP | sFlag); newtTextboxSetText(tb, buf); i = newtTextboxGetNumLines(tb); if (i < maxHeight) { newtTextboxSetHeight(tb, i); maxHeight = i; } *height = maxHeight; return tb; } int gauge(const char * text, int height, int width, poptContext optCon, int fd, int flags) { newtComponent form, scale, tb; int top; const char * arg; char * end; int val; FILE * f = fdopen(fd, "r"); char buf[3000]; char buf3[50]; int i; setlinebuf(f); if (!(arg = poptGetArg(optCon))) return DLG_ERROR; val = strtoul(arg, &end, 10); if (*end) return DLG_ERROR; tb = textbox(height - 3, width - 2, text, flags, &top); form = newtForm(NULL, NULL, 0); scale = newtScale(2, height - 2, width - 4, 100); newtScaleSet(scale, val); newtFormAddComponents(form, tb, scale, NULL); newtDrawForm(form); newtRefresh(); do { if (!fgets(buf, sizeof(buf) - 1, f)) continue; buf[strlen(buf) - 1] = '\0'; if (!strcmp(buf, "XXX")) { while (!fgets(buf3, sizeof(buf3) - 1, f) && !feof(f)) ; if (feof(f)) break; buf3[strlen(buf3) - 1] = '\0'; i = 0; do { if (!fgets(buf + i, sizeof(buf) - 1 - i, f)) continue; if (!strcmp(buf + i, "XXX\n")) { *(buf + i) = '\0'; break; } i = strlen(buf); } while (!feof(f)); if (i > 0) buf[strlen(buf) - 1] = '\0'; else buf[0] = '\0'; cleanNewlines(buf); newtTextboxSetText(tb, buf); arg = buf3; } else { arg = buf; } val = strtoul(arg, &end, 10); if (!*end) { newtScaleSet(scale, val); newtDrawForm(form); newtRefresh(); } } while (!feof(f)); newtFormDestroy(form); return DLG_OKAY; } int inputBox(const char * text, int height, int width, poptContext optCon, int flags, char ** result) { newtComponent form, entry, okay, cancel, answer, tb; const char * val; int pFlag = (flags & FLAG_PASSWORD) ? NEWT_FLAG_PASSWORD : 0; int rc = DLG_OKAY; int top; val = poptGetArg(optCon); tb = textbox(height - 3 - buttonHeight, width - 2, text, flags, &top); form = newtForm(NULL, NULL, 0); entry = newtEntry(1, top + 1, val, width - 2, &val, NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT | pFlag); newtFormAddComponents(form, tb, entry, NULL); addButtons(height, width, form, &okay, &cancel, flags); answer = newtRunForm(form); *result = NULL; if (answer == cancel) rc = DLG_CANCEL; else if (answer == NULL) rc = DLG_ESCAPE; else *result = strdup(val); newtFormDestroy(form); return rc; } static int mystrncpyw(char *dest, const char *src, int n, int *maxwidth) { int i = 0; int w = 0, cw; wchar_t c; mbstate_t ps; const char *p = src; char *d = dest; memset(&ps, 0, sizeof(ps)); for (;;) { int ret = mbrtowc(&c, p, MB_CUR_MAX, &ps); if (ret <= 0) break; if (ret + i >= n) break; cw = wcwidth(c); if (cw < 0) break; if (cw + w > *maxwidth) break; w += cw; memcpy(d, p, ret); d += ret; p += ret; i += ret; } dest[i] = '\0'; *maxwidth = w; return i; } int listBox(const char * text, int height, int width, poptContext optCon, int flags, const char *default_item, char ** result) { newtComponent form, okay, tb, answer, listBox; newtComponent cancel = NULL; const char * arg; char * end; int listHeight; int numItems = 0; int allocedItems = 5; int i, top; int rc = DLG_OKAY; char buf[MAXBUF]; int maxTagWidth = 0; int maxTextWidth = 0; int defItem = -1; int scrollFlag; int lineWidth, textWidth, tagWidth; struct { const char * text; const char * tag; } * itemInfo = malloc(allocedItems * sizeof(*itemInfo)); if (itemInfo == NULL) return DLG_ERROR; if (!(arg = poptGetArg(optCon))) return DLG_ERROR; listHeight = strtoul(arg, &end, 10); if (*end) return DLG_ERROR; while ((arg = poptGetArg(optCon))) { if (allocedItems == numItems) { allocedItems += 5; itemInfo = realloc(itemInfo, sizeof(*itemInfo) * allocedItems); if (itemInfo == NULL) return DLG_ERROR; } itemInfo[numItems].tag = arg; if (default_item && (strcmp(default_item, arg) == 0)) { defItem = numItems; } if (!(arg = poptGetArg(optCon))) return DLG_ERROR; if (!(flags & FLAG_NOITEM)) { itemInfo[numItems].text = arg; } else itemInfo[numItems].text = ""; if (wstrlen(itemInfo[numItems].text,-1) > (unsigned int)maxTextWidth) maxTextWidth = wstrlen(itemInfo[numItems].text,-1); if (wstrlen(itemInfo[numItems].tag,-1) > (unsigned int)maxTagWidth) maxTagWidth = wstrlen(itemInfo[numItems].tag,-1); numItems++; } if (numItems == 0) return DLG_ERROR; if (flags & FLAG_NOTAGS) { maxTagWidth = 0; } form = newtForm(NULL, NULL, 0); tb = textbox(height - 4 - buttonHeight - listHeight, width - 2, text, flags, &top); if (listHeight >= numItems) { scrollFlag = 0; i = 0; } else { scrollFlag = NEWT_FLAG_SCROLL; i = 2; } lineWidth = min(maxTagWidth + maxTextWidth + i + 1, SLtt_Screen_Cols - 6); listBox = newtListbox( (width - lineWidth) / 2 , top + 1, listHeight, NEWT_FLAG_RETURNEXIT | scrollFlag); textWidth = maxTextWidth; tagWidth = maxTagWidth; if (maxTextWidth == 0) { tagWidth = lineWidth; } else { tagWidth++; textWidth++; while (textWidth + tagWidth + i > lineWidth) { if (textWidth >= tagWidth && textWidth > 0) textWidth--; else if (tagWidth > 0) tagWidth--; else break; } } if (!(flags & FLAG_NOTAGS)) { for (i = 0; i < numItems; i++) { int w = tagWidth; int len, j; len = mystrncpyw(buf, itemInfo[i].tag, MAXBUF, &w); for (j = 0; j < tagWidth - w; j++) { if (len + 1 >= MAXBUF) break; buf[len++] = ' '; } buf[len] = '\0'; w = textWidth; mystrncpyw(buf + len, itemInfo[i].text, MAXBUF-len, &w); newtListboxAddEntry(listBox, buf, (void *)(long) i); } } else { for (i = 0; i < numItems; i++) { snprintf(buf, MAXBUF, "%s", itemInfo[i].text); newtListboxAddEntry(listBox, buf, (void *)(long) i); } } if (defItem != -1) newtListboxSetCurrent (listBox, defItem); newtFormAddComponents(form, tb, listBox, NULL); addButtons(height, width, form, &okay, &cancel, flags); answer = newtRunForm(form); *result = NULL; if (answer == cancel) rc = DLG_CANCEL; else if (answer == NULL) rc = DLG_ESCAPE; else { i = (long) newtListboxGetCurrent(listBox); *result = strdup(itemInfo[i].tag); } newtFormDestroy(form); free(itemInfo); return rc; } int checkList(const char * text, int height, int width, poptContext optCon, int useRadio, int flags, char *** selections) { newtComponent form, okay, tb, subform, answer; newtComponent sb = NULL, cancel = NULL; const char * arg; char * end; int listHeight; int numBoxes = 0; int allocedBoxes = 5; int i; int numSelected; int rc = DLG_OKAY; char buf[MAXBUF], format[MAXFORMAT]; int maxWidth = 0; int top; struct { const char * text; const char * tag; newtComponent comp; } * cbInfo = malloc(allocedBoxes * sizeof(*cbInfo)); char * cbStates = malloc(allocedBoxes * sizeof(*cbStates)); if ( (cbInfo == NULL) || (cbStates == NULL)) return DLG_ERROR; if (!(arg = poptGetArg(optCon))) return DLG_ERROR; listHeight = strtoul(arg, &end, 10); if (*end) return DLG_ERROR; while ((arg = poptGetArg(optCon))) { if (allocedBoxes == numBoxes) { allocedBoxes += 5; cbInfo = realloc(cbInfo, sizeof(*cbInfo) * allocedBoxes); cbStates = realloc(cbStates, sizeof(*cbStates) * allocedBoxes); if ((cbInfo == NULL) || (cbStates == NULL)) return DLG_ERROR; } cbInfo[numBoxes].tag = arg; if (!(arg = poptGetArg(optCon))) return DLG_ERROR; if (!(flags & FLAG_NOITEM)) { cbInfo[numBoxes].text = arg; if (!(arg = poptGetArg(optCon))) return DLG_ERROR; } else cbInfo[numBoxes].text = ""; if (!strcmp(arg, "1") || !strcasecmp(arg, "on") || !strcasecmp(arg, "yes")) cbStates[numBoxes] = '*'; else cbStates[numBoxes] = ' '; if (wstrlen(cbInfo[numBoxes].tag,-1) > (unsigned int)maxWidth) maxWidth = wstrlen(cbInfo[numBoxes].tag,-1); numBoxes++; } form = newtForm(NULL, NULL, 0); tb = textbox(height - 3 - buttonHeight - listHeight, width - 2, text, flags, &top); if (listHeight < numBoxes) { sb = newtVerticalScrollbar(width - 4, top + 1, listHeight, NEWT_COLORSET_CHECKBOX, NEWT_COLORSET_ACTCHECKBOX); newtFormAddComponent(form, sb); } subform = newtForm(sb, NULL, 0); newtFormSetBackground(subform, NEWT_COLORSET_CHECKBOX); if (flags & FLAG_NOTAGS) snprintf(format, MAXFORMAT, "%%.0s%%s"); else snprintf(format, MAXFORMAT, "%%-%ds %%s", maxWidth); for (i = 0; i < numBoxes; i++) { snprintf(buf, MAXBUF, format, cbInfo[i].tag, cbInfo[i].text); if (useRadio) cbInfo[i].comp = newtRadiobutton(4, top + 1 + i, buf, cbStates[i] != ' ', i ? cbInfo[i - 1].comp : NULL); else cbInfo[i].comp = newtCheckbox(4, top + 1 + i, buf, cbStates[i], NULL, cbStates + i); newtCheckboxSetFlags(cbInfo[i].comp, NEWT_FLAG_RETURNEXIT, NEWT_FLAGS_SET); newtFormAddComponent(subform, cbInfo[i].comp); } newtFormSetHeight(subform, listHeight); newtFormSetWidth(subform, width - 10); newtFormAddComponents(form, tb, subform, NULL); addButtons(height, width, form, &okay, &cancel, flags); answer = newtRunForm(form); *selections = NULL; if (answer == cancel) rc = DLG_CANCEL; else if (answer == NULL) rc = DLG_ESCAPE; else { if (useRadio) { answer = newtRadioGetCurrent(cbInfo[0].comp); *selections = malloc(sizeof(char *) * 2); if (*selections == NULL) return DLG_ERROR; (*selections)[0] = (*selections)[1] = NULL; for (i = 0; i < numBoxes; i++) if (cbInfo[i].comp == answer) { (*selections)[0] = strdup(cbInfo[i].tag); break; } } else { numSelected = 0; for (i = 0; i < numBoxes; i++) { if (cbStates[i] != ' ') numSelected++; } *selections = malloc(sizeof(char *) * (numSelected + 1)); if (*selections == NULL) return DLG_ERROR; numSelected = 0; for (i = 0; i < numBoxes; i++) { if (cbStates[i] != ' ') (*selections)[numSelected++] = strdup(cbInfo[i].tag); } (*selections)[numSelected] = NULL; } } free(cbInfo); free(cbStates); newtFormDestroy(form); return rc; } int messageBox(const char * text, int height, int width, int type, int flags) { newtComponent form, yes, tb, answer; newtComponent no = NULL; int rc = DLG_OKAY; int tFlag = (flags & FLAG_SCROLL_TEXT) ? NEWT_FLAG_SCROLL : 0; form = newtForm(NULL, NULL, 0); tb = newtTextbox(1, 1, width - 2, height - 3 - buttonHeight, NEWT_FLAG_WRAP | tFlag); newtTextboxSetText(tb, text); newtFormAddComponent(form, tb); switch ( type ) { case MSGBOX_INFO: break; case MSGBOX_MSG: // FIXME Do something about the hard-coded constants yes = makeButton((width - 8) / 2, height - 1 - buttonHeight, getButtonText(BUTTON_OK)); newtFormAddComponent(form, yes); break; default: yes = makeButton((width - 16) / 3, height - 1 - buttonHeight, getButtonText(BUTTON_YES)); no = makeButton(((width - 16) / 3) * 2 + 9, height - 1 - buttonHeight, getButtonText(BUTTON_NO)); newtFormAddComponents(form, yes, no, NULL); if (flags & FLAG_DEFAULT_NO) newtFormSetCurrent(form, no); } if ( type != MSGBOX_INFO ) { if (newtRunForm(form) == NULL) rc = DLG_ESCAPE; answer = newtFormGetCurrent(form); if (answer == no) rc = DLG_CANCEL; } else { newtDrawForm(form); newtRefresh(); } newtFormDestroy(form); return rc; } void useFullButtons(int state) { if (state) { buttonHeight = 3; makeButton = newtButton; } else { buttonHeight = 1; makeButton = newtCompactButton; } } void setButtonText(const char * text, int button) { if (button < 0 || button >= BUTTONS) return; buttonText[button] = text; }