diff options
Diffstat (limited to 'contrib/dialog/util.c')
-rw-r--r-- | contrib/dialog/util.c | 429 |
1 files changed, 333 insertions, 96 deletions
diff --git a/contrib/dialog/util.c b/contrib/dialog/util.c index 8496330..82ef4fa 100644 --- a/contrib/dialog/util.c +++ b/contrib/dialog/util.c @@ -1,5 +1,5 @@ /* - * $Id: util.c,v 1.211 2011/01/19 00:31:43 tom Exp $ + * $Id: util.c,v 1.227 2011/07/07 23:42:30 tom Exp $ * * util.c -- miscellaneous utilities for dialog * @@ -37,6 +37,20 @@ #endif #endif +#if defined(HAVE_WCHGAT) +# if defined(NCURSES_VERSION_PATCH) +# if NCURSES_VERSION_PATCH >= 20060715 +# define USE_WCHGAT 1 +# else +# define USE_WCHGAT 0 +# endif +# else +# define USE_WCHGAT 1 +# endif +#else +# define USE_WCHGAT 0 +#endif + /* globals */ DIALOG_STATE dialog_state; DIALOG_VARS dialog_vars; @@ -61,6 +75,8 @@ DIALOG_VARS dialog_vars; #define DATA(atr,upr,lwr,cmt) { atr COLOR_DATA(upr) RC_DATA(lwr,cmt) } +#define UseShadow(dw) ((dw) != 0 && (dw)->normal != 0 && (dw)->shadow != 0) + /* * Table of color and attribute values, default is for mono display. */ @@ -411,7 +427,7 @@ dlg_get_attrs(WINDOW *win) { chtype result; #ifdef HAVE_GETATTRS - result = getattrs(win); + result = (chtype) getattrs(win); #else attr_t my_result; short my_pair; @@ -487,6 +503,7 @@ end_dialog(void) } } +#define ESCAPE_LEN 3 #define isOurEscape(p) (((p)[0] == '\\') && ((p)[1] == 'Z') && ((p)[2] != 0)) static int @@ -500,7 +517,7 @@ centered(int width, const char *string) if (dialog_vars.colors) { for (n = 0; n < len; ++n) { if (isOurEscape(string + n)) { - hide += 3; + hide += ESCAPE_LEN; } } } @@ -661,6 +678,7 @@ dlg_print_line(WINDOW *win, { const char *wrap_ptr = prompt; const char *test_ptr = prompt; + const char *hide_ptr = 0; const int *cols = dlg_index_columns(prompt); const int *indx = dlg_index_wchars(prompt); int wrap_inx = 0; @@ -687,8 +705,9 @@ dlg_print_line(WINDOW *win, wrap_inx = n; *x = cur_x; } else if (isOurEscape(test_ptr)) { - hidden += 3; - n += 2; + hide_ptr = test_ptr; + hidden += ESCAPE_LEN; + n += (ESCAPE_LEN - 1); } cur_x = lm + tabbed + cols[n + 1]; if (cur_x > (rm + hidden)) @@ -725,6 +744,23 @@ dlg_print_line(WINDOW *win, #endif /* + * If we found hidden text past the last point that we will display, + * discount that from the displayed length. + */ + if ((hide_ptr != 0) && (hide_ptr >= wrap_ptr)) { + hidden -= ESCAPE_LEN; + test_ptr = wrap_ptr; + while (test_ptr < wrap_ptr) { + if (isOurEscape(test_ptr)) { + hidden -= ESCAPE_LEN; + test_ptr += ESCAPE_LEN; + } else { + ++test_ptr; + } + } + } + + /* * Print the line if we have a window pointer. Otherwise this routine * is just being called for sizing the window. */ @@ -736,6 +772,8 @@ dlg_print_line(WINDOW *win, if (*x == 1) *x = rm; + *x -= hidden; + /* Find the start of the next line and return a pointer to it */ test_ptr = wrap_ptr; while (*test_ptr == ' ') @@ -863,43 +901,49 @@ dlg_print_scrolled(WINDOW *win, high = len; #endif dummy = newwin(high, width, 0, 0); - wbkgdset(dummy, dialog_attr | ' '); - wattrset(dummy, dialog_attr); - werase(dummy); - dlg_print_autowrap(dummy, prompt, high, width); - getyx(dummy, y, x); - - copywin(dummy, /* srcwin */ - win, /* dstwin */ - offset + MARGIN, /* sminrow */ - MARGIN, /* smincol */ - MARGIN, /* dminrow */ - MARGIN, /* dmincol */ - height, /* dmaxrow */ - wide, /* dmaxcol */ - FALSE); - - delwin(dummy); - - /* if the text is incomplete, or we have scrolled, show the percentage */ - if (y > 0 && wide > 4) { - percent = (int) ((height + offset) * 100.0 / y); - if (percent < 0) - percent = 0; - if (percent > 100) - percent = 100; - if (offset != 0 || percent != 100) { - (void) wattrset(win, position_indicator_attr); - (void) wmove(win, MARGIN + height, wide - 4); - (void) sprintf(buffer, "%d%%", percent); - (void) waddstr(win, buffer); - if ((len = (int) strlen(buffer)) < 4) { - wattrset(win, border_attr); - whline(win, dlg_boxchar(ACS_HLINE), 4 - len); + if (dummy == 0) { + wattrset(win, dialog_attr); + dlg_print_autowrap(win, prompt, height + 1 + (3 * MARGIN), width); + last = 0; + } else { + wbkgdset(dummy, dialog_attr | ' '); + wattrset(dummy, dialog_attr); + werase(dummy); + dlg_print_autowrap(dummy, prompt, high, width); + getyx(dummy, y, x); + + copywin(dummy, /* srcwin */ + win, /* dstwin */ + offset + MARGIN, /* sminrow */ + MARGIN, /* smincol */ + MARGIN, /* dminrow */ + MARGIN, /* dmincol */ + height, /* dmaxrow */ + wide, /* dmaxcol */ + FALSE); + + delwin(dummy); + + /* if the text is incomplete, or we have scrolled, show the percentage */ + if (y > 0 && wide > 4) { + percent = (int) ((height + offset) * 100.0 / y); + if (percent < 0) + percent = 0; + if (percent > 100) + percent = 100; + if (offset != 0 || percent != 100) { + (void) wattrset(win, position_indicator_attr); + (void) wmove(win, MARGIN + height, wide - 4); + (void) sprintf(buffer, "%d%%", percent); + (void) waddstr(win, buffer); + if ((len = (int) strlen(buffer)) < 4) { + wattrset(win, border_attr); + whline(win, dlg_boxchar(ACS_HLINE), 4 - len); + } } } + last = (y - height); } - last = (y - height); } else #endif { @@ -1037,6 +1081,25 @@ longest_word(const char *string) return result; } +static int +count_real_columns(const char *text) +{ + int result = dlg_count_columns(text); + if (result && dialog_vars.colors) { + int hidden = 0; + while (*text) { + if (isOurEscape(text)) { + hidden += ESCAPE_LEN; + text += ESCAPE_LEN; + } else { + ++text; + } + } + result -= hidden; + } + return result; +} + /* * if (height or width == -1) Maximize() * if (height or width == 0), justify and return actual limits. @@ -1074,7 +1137,7 @@ real_auto_size(const char *title, } else if (prompt != 0) { wide = MAX(title_length, mincols); if (strchr(prompt, '\n') == 0) { - double val = dialog_state.aspect_ratio * dlg_count_columns(prompt); + double val = dialog_state.aspect_ratio * count_real_columns(prompt); double xxx = sqrt(val); int tmp = (int) xxx; wide = MAX(wide, tmp); @@ -1190,6 +1253,27 @@ dlg_auto_sizefile(const char *title, (void) fclose(fd); } +static chtype +dlg_get_cell_attrs(WINDOW *win) +{ + chtype result; +#ifdef USE_WIDE_CURSES + cchar_t wch; + wchar_t cc; + attr_t attrs; + short pair; + if (win_wch(win, &wch) == OK + && getcchar(&wch, &cc, &attrs, &pair, NULL) == OK) { + result = attrs; + } else { + result = 0; + } +#else + result = winch(win) & (A_ATTRIBUTES & ~A_COLOR); +#endif + return result; +} + /* * Draw a rectangular box with line drawing characters. * @@ -1239,54 +1323,221 @@ dlg_draw_box(WINDOW *win, int y, int x, int height, int width, wattrset(win, save); } +static DIALOG_WINDOWS * +find_window(WINDOW *win) +{ + DIALOG_WINDOWS *result = 0; + DIALOG_WINDOWS *p; + + for (p = dialog_state.all_windows; p != 0; p = p->next) { + if (p->normal == win) { + result = p; + break; + } + } + return result; +} + #ifdef HAVE_COLOR /* - * Draw a shadow on the parent window corresponding to the right- and - * bottom-edge of the child window, to give a 3-dimensional look. + * If we have wchgat(), use that for updating shadow attributes, to work with + * wide-character data. */ -static void -draw_childs_shadow(WINDOW *parent, WINDOW *child) + +/* + * Check if the given point is "in" the given window. If so, return the window + * pointer, otherwise null. + */ +static WINDOW * +in_window(WINDOW *win, int y, int x) { - if (has_colors()) { /* Whether terminal supports color? */ - chtype save = dlg_get_attrs(parent); + WINDOW *result = 0; + int y_base = getbegy(win); + int x_base = getbegx(win); + int y_last = getmaxy(win) + y_base; + int x_last = getmaxx(win) + x_base; + + if (y >= y_base && y <= y_last && x >= x_base && x <= x_last) + result = win; + return result; +} + +static WINDOW * +window_at_cell(DIALOG_WINDOWS * dw, int y, int x) +{ + WINDOW *result = 0; + DIALOG_WINDOWS *p; + int y_want = y + getbegy(dw->shadow); + int x_want = x + getbegx(dw->shadow); + + for (p = dialog_state.all_windows; p != 0; p = p->next) { + if (dw->normal != p->normal + && dw->shadow != p->normal + && (result = in_window(p->normal, y_want, x_want)) != 0) { + break; + } + } + if (result == 0) { + result = stdscr; + } + return result; +} - dlg_draw_shadow(parent, - getbegy(child) - getbegy(parent), - getbegx(child) - getbegx(parent), - getmaxy(child), - getmaxx(child)); - wattrset(parent, save); +static bool +in_shadow(WINDOW *normal, WINDOW *shadow, int y, int x) +{ + bool result = FALSE; + int ybase = getbegy(normal); + int ylast = getmaxy(normal) + ybase; + int xbase = getbegx(normal); + int xlast = getmaxx(normal) + xbase; + + y += getbegy(shadow); + x += getbegx(shadow); + + if (y >= ybase + SHADOW_ROWS + && y < ylast + SHADOW_ROWS + && x >= xlast + && x < xlast + SHADOW_COLS) { + /* in the right-side */ + result = TRUE; + } else if (y >= ylast + && y < ylast + SHADOW_ROWS + && x >= ybase + SHADOW_COLS + && x < ylast + SHADOW_COLS) { + /* check the bottom */ + result = TRUE; } + + return result; } /* - * Draw shadows along the right and bottom edge to give a more 3D look - * to the boxes + * When erasing a shadow, check each cell to make sure that it is not part of + * another box's shadow. This is a little complicated since most shadows are + * merged onto stdscr. */ -void -dlg_draw_shadow(WINDOW *win, int y, int x, int height, int width) +static bool +last_shadow(DIALOG_WINDOWS * dw, int y, int x) +{ + DIALOG_WINDOWS *p; + bool result = TRUE; + + for (p = dialog_state.all_windows; p != 0; p = p->next) { + if (p->normal != dw->normal + && in_shadow(p->normal, dw->shadow, y, x)) { + result = FALSE; + break; + } + } + return result; +} + +static void +repaint_cell(DIALOG_WINDOWS * dw, bool draw, int y, int x) +{ + WINDOW *win = dw->shadow; + WINDOW *cellwin; + int y2, x2; + + if ((cellwin = window_at_cell(dw, y, x)) != 0 + && (draw || last_shadow(dw, y, x)) + && (y2 = (y + getbegy(win) - getbegy(cellwin))) >= 0 + && (x2 = (x + getbegx(win) - getbegx(cellwin))) >= 0 + && wmove(cellwin, y2, x2) != ERR) { + chtype the_cell = dlg_get_attrs(cellwin); + chtype the_attr = (draw ? shadow_attr : the_cell); + + if (dlg_get_cell_attrs(cellwin) & A_ALTCHARSET) { + the_attr |= A_ALTCHARSET; + } +#if USE_WCHGAT + wchgat(cellwin, 1, + the_attr & (chtype) (~A_COLOR), + PAIR_NUMBER(the_attr), + NULL); +#else + { + chtype the_char = ((winch(cellwin) & A_CHARTEXT) | the_attr); + (void) waddch(cellwin, the_char); + } +#endif + wnoutrefresh(cellwin); + } +} + +#define RepaintCell(dw, draw, y, x) repaint_cell(dw, draw, y, x) + +static void +repaint_shadow(DIALOG_WINDOWS * dw, bool draw, int y, int x, int height, int width) { int i, j; - if (has_colors()) { /* Whether terminal supports color? */ - wattrset(win, shadow_attr); + if (UseShadow(dw)) { +#if !USE_WCHGAT + chtype save = dlg_get_attrs(dw->shadow); + wattrset(dw->shadow, draw ? shadow_attr : screen_attr); +#endif for (i = 0; i < SHADOW_ROWS; ++i) { for (j = 0; j < width; ++j) { - if (wmove(win, i + y + height, j + x + SHADOW_COLS) != ERR) { - (void) waddch(win, winch(win) & (chtype) (~A_COLOR)); - } + RepaintCell(dw, draw, i + y + height, j + x + SHADOW_COLS); } } for (i = 0; i < height; i++) { for (j = 0; j < SHADOW_COLS; ++j) { - if (wmove(win, i + y + SHADOW_ROWS, j + x + width) != ERR) { - (void) waddch(win, winch(win) & (chtype) (~A_COLOR)); - } + RepaintCell(dw, draw, i + y + SHADOW_ROWS, j + x + width); } } - (void) wnoutrefresh(win); + (void) wnoutrefresh(dw->shadow); +#if !USE_WCHGAT + wattrset(dw->shadow, save); +#endif + } +} + +/* + * Draw a shadow on the parent window corresponding to the right- and + * bottom-edge of the child window, to give a 3-dimensional look. + */ +static void +draw_childs_shadow(DIALOG_WINDOWS * dw) +{ + if (UseShadow(dw)) { + repaint_shadow(dw, + TRUE, + getbegy(dw->normal) - getbegy(dw->shadow), + getbegx(dw->normal) - getbegx(dw->shadow), + getmaxy(dw->normal), + getmaxx(dw->normal)); } } + +/* + * Erase a shadow on the parent window corresponding to the right- and + * bottom-edge of the child window. + */ +static void +erase_childs_shadow(DIALOG_WINDOWS * dw) +{ + if (UseShadow(dw)) { + repaint_shadow(dw, + FALSE, + getbegy(dw->normal) - getbegy(dw->shadow), + getbegx(dw->normal) - getbegx(dw->shadow), + getmaxy(dw->normal), + getmaxx(dw->normal)); + } +} + +/* + * Draw shadows along the right and bottom edge to give a more 3D look + * to the boxes. + */ +void +dlg_draw_shadow(WINDOW *win, int y, int x, int height, int width) +{ + repaint_shadow(find_window(win), TRUE, y, x, height, width); +} #endif /* HAVE_COLOR */ /* @@ -1340,6 +1591,10 @@ dlg_exit(int code) code = DLG_EXIT_HELP; goto retry; } +#ifdef HAVE_DLG_TRACE + dlg_trace((const char *) 0); /* close it */ +#endif + #ifdef NO_LEAKS _dlg_inputstr_leaks(); #if defined(NCURSES_VERSION) && defined(HAVE__NC_FREE_AND_EXIT) @@ -1650,6 +1905,8 @@ dlg_del_window(WINDOW *win) } if (q) { + if (dialog_state.all_windows != 0) + erase_childs_shadow(q); delwin(q->normal); dlg_unregister_window(q->normal); free(q); @@ -1663,26 +1920,13 @@ dlg_del_window(WINDOW *win) WINDOW * dlg_new_window(int height, int width, int y, int x) { - WINDOW *win; - DIALOG_WINDOWS *p = dlg_calloc(DIALOG_WINDOWS, 1); - - if ((win = newwin(height, width, y, x)) == 0) { - dlg_exiterr("Can't make new window at (%d,%d), size (%d,%d).\n", - y, x, height, width); - } - p->next = dialog_state.all_windows; - p->normal = win; - dialog_state.all_windows = p; -#ifdef HAVE_COLOR - if (dialog_state.use_shadow) { - draw_childs_shadow(p->shadow = stdscr, win); - } -#endif - - (void) keypad(win, TRUE); - return win; + return dlg_new_modal_window(stdscr, height, width, y, x); } +/* + * "Modal" windows differ from normal ones by having a shadow in a window + * separate from the standard screen. + */ WINDOW * dlg_new_modal_window(WINDOW *parent, int height, int width, int y, int x) { @@ -1699,7 +1943,8 @@ dlg_new_modal_window(WINDOW *parent, int height, int width, int y, int x) dialog_state.all_windows = p; #ifdef HAVE_COLOR if (dialog_state.use_shadow) { - draw_childs_shadow(p->shadow = parent, win); + p->shadow = parent; + draw_childs_shadow(p); } #endif @@ -1714,19 +1959,12 @@ dlg_new_modal_window(WINDOW *parent, int height, int width, int y, int x) void dlg_move_window(WINDOW *win, int height, int width, int y, int x) { - DIALOG_WINDOWS *p, *q; + DIALOG_WINDOWS *p; if (win != 0) { dlg_ctl_size(height, width); - for (p = dialog_state.all_windows; p != 0; p = q) { - q = p->next; - if (p->normal == win) { - break; - } - } - - if (p != 0) { + if ((p = find_window(win)) != 0) { (void) wresize(win, height, width); (void) mvwin(win, y, x); #ifdef HAVE_COLOR @@ -1741,8 +1979,7 @@ dlg_move_window(WINDOW *win, int height, int width, int y, int x) (void) refresh(); #ifdef HAVE_COLOR - if (p->shadow) - draw_childs_shadow(p->shadow, win); + draw_childs_shadow(p); #endif } } @@ -1883,7 +2120,7 @@ dlg_trim_string(char *s) char *base = s; char *p1; char *p = s; - int has_newlines = (strstr(s, "\\n") != 0); + int has_newlines = !dialog_vars.no_nl_expand && (strstr(s, "\\n") != 0); while (*p != '\0') { if (*p == TAB && !dialog_vars.nocollapse) |