1 /* 2 * $Id: arrows.c,v 1.53 2019/07/24 23:04:14 tom Exp $ 3 * 4 * arrows.c -- draw arrows to indicate end-of-range for lists 5 * 6 * Copyright 2000-2018,2019 Thomas E. Dickey 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU Lesser General Public License, version 2.1 10 * as published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this program; if not, write to 19 * Free Software Foundation, Inc. 20 * 51 Franklin St., Fifth Floor 21 * Boston, MA 02110, USA. 22 */ 23 24 #include <dialog.h> 25 26 #ifdef USE_WIDE_CURSES 27 #if defined(CURSES_WACS_ARRAY) && !defined(CURSES_WACS_SYMBOLS) 28 /* workaround for NetBSD 5.1 curses */ 29 #undef WACS_DARROW 30 #undef WACS_UARROW 31 #define WACS_DARROW &(CURSES_WACS_ARRAY['.']) 32 #define WACS_UARROW &(CURSES_WACS_ARRAY['-']) 33 #endif 34 #define add_acs(win, code) wadd_wch(win, W ## code) 35 #else 36 #define add_acs(win, code) waddch(win, dlg_boxchar(code)) 37 #endif 38 39 /* size of decorations */ 40 #define ON_LEFT 4 41 #define ON_RIGHT 3 42 43 #ifdef HAVE_COLOR 44 static chtype 45 merge_colors(chtype foreground, chtype background) 46 { 47 chtype result = foreground; 48 if ((foreground & A_COLOR) != (background & A_COLOR)) { 49 short fg_f, bg_f; 50 short fg_b, bg_b; 51 short fg_pair = (short) PAIR_NUMBER(foreground); 52 short bg_pair = (short) PAIR_NUMBER(background); 53 54 if (pair_content(fg_pair, &fg_f, &bg_f) != ERR 55 && pair_content(bg_pair, &fg_b, &bg_b) != ERR) { 56 result &= ~A_COLOR; 57 result |= dlg_color_pair(fg_f, bg_b); 58 } 59 } 60 return result; 61 } 62 #else 63 #define merge_colors(f,b) (f) 64 #endif 65 66 /* 67 * If we have help-line text, e.g., from "--hline", draw it between the other 68 * decorations at the bottom of the dialog window. 69 */ 70 void 71 dlg_draw_helpline(WINDOW *win, bool decorations) 72 { 73 int bottom; 74 75 if (dialog_vars.help_line != 0 76 && dialog_vars.help_line[0] != 0 77 && (bottom = getmaxy(win) - 1) > 0) { 78 chtype attr = A_NORMAL; 79 int cols = dlg_count_columns(dialog_vars.help_line); 80 int other = decorations ? (ON_LEFT + ON_RIGHT) : 0; 81 int avail = (getmaxx(win) - other - 2); 82 int limit = dlg_count_real_columns(dialog_vars.help_line) + 2; 83 84 if (limit < avail) { 85 int cur_x, cur_y; 86 87 getyx(win, cur_y, cur_x); 88 other = decorations ? ON_LEFT : 0; 89 (void) wmove(win, bottom, other + (avail - limit) / 2); 90 waddch(win, '['); 91 dlg_print_text(win, dialog_vars.help_line, cols, &attr); 92 waddch(win, ']'); 93 wmove(win, cur_y, cur_x); 94 } 95 } 96 } 97 98 void 99 dlg_draw_arrows2(WINDOW *win, 100 int top_arrow, 101 int bottom_arrow, 102 int x, 103 int top, 104 int bottom, 105 chtype attr, 106 chtype borderattr) 107 { 108 chtype save = dlg_get_attrs(win); 109 int cur_x, cur_y; 110 int limit_x = getmaxx(win); 111 bool draw_top = TRUE; 112 bool is_toplevel = (wgetparent(win) == stdscr); 113 114 getyx(win, cur_y, cur_x); 115 116 /* 117 * If we're drawing a centered title, do not overwrite with the arrows. 118 */ 119 if (dialog_vars.title && is_toplevel && (top - getbegy(win)) < MARGIN) { 120 int have = (limit_x - dlg_count_columns(dialog_vars.title)) / 2; 121 int need = x + 5; 122 if (need > have) 123 draw_top = FALSE; 124 } 125 126 if (draw_top) { 127 (void) wmove(win, top, x); 128 if (top_arrow) { 129 dlg_attrset(win, merge_colors(uarrow_attr, attr)); 130 (void) add_acs(win, ACS_UARROW); 131 (void) waddstr(win, "(-)"); 132 } else { 133 dlg_attrset(win, attr); 134 (void) whline(win, dlg_boxchar(ACS_HLINE), ON_LEFT); 135 } 136 } 137 mouse_mkbutton(top, x - 1, 6, KEY_PPAGE); 138 139 (void) wmove(win, bottom, x); 140 if (bottom_arrow) { 141 dlg_attrset(win, merge_colors(darrow_attr, borderattr)); 142 (void) add_acs(win, ACS_DARROW); 143 (void) waddstr(win, "(+)"); 144 } else { 145 dlg_attrset(win, borderattr); 146 (void) whline(win, dlg_boxchar(ACS_HLINE), ON_LEFT); 147 } 148 mouse_mkbutton(bottom, x - 1, 6, KEY_NPAGE); 149 150 (void) wmove(win, cur_y, cur_x); 151 wrefresh(win); 152 153 dlg_attrset(win, save); 154 } 155 156 void 157 dlg_draw_scrollbar(WINDOW *win, 158 long first_data, 159 long this_data, 160 long next_data, 161 long total_data, 162 int left, 163 int right, 164 int top, 165 int bottom, 166 chtype attr, 167 chtype borderattr) 168 { 169 int oldy, oldx; 170 171 chtype save = dlg_get_attrs(win); 172 int top_arrow = (first_data != 0); 173 int bottom_arrow = (next_data < total_data); 174 175 getyx(win, oldy, oldx); 176 177 dlg_draw_helpline(win, TRUE); 178 if (bottom_arrow || top_arrow || dialog_state.use_scrollbar) { 179 char buffer[80]; 180 int percent; 181 int len; 182 183 percent = (!total_data 184 ? 100 185 : (int) ((next_data * 100) 186 / total_data)); 187 188 if (percent < 0) 189 percent = 0; 190 else if (percent > 100) 191 percent = 100; 192 193 dlg_attrset(win, position_indicator_attr); 194 (void) sprintf(buffer, "%d%%", percent); 195 (void) wmove(win, bottom, right - 7); 196 (void) waddstr(win, buffer); 197 if ((len = dlg_count_columns(buffer)) < 4) { 198 dlg_attrset(win, border_attr); 199 whline(win, dlg_boxchar(ACS_HLINE), 4 - len); 200 } 201 } 202 #define BARSIZE(num) (int) (0.5 + (double) ((all_high * (int) (num)) / (double) total_data)) 203 #define ORDSIZE(num) (int) ((double) ((all_high * (int) (num)) / (double) all_diff)) 204 205 if (dialog_state.use_scrollbar) { 206 int all_high = (bottom - top - 1); 207 208 this_data = MAX(0, this_data); 209 210 if (total_data > 0 && all_high > 0) { 211 int all_diff = (int) (total_data + 1); 212 int bar_diff = (int) (next_data + 1 - this_data); 213 int bar_high; 214 215 bar_high = ORDSIZE(bar_diff); 216 if (bar_high <= 0) 217 bar_high = 1; 218 219 if (bar_high < all_high) { 220 int bar_last = BARSIZE(next_data); 221 int bar_y; 222 223 wmove(win, top + 1, right); 224 225 dlg_attrset(win, save); 226 wvline(win, ACS_VLINE | A_REVERSE, all_high); 227 228 bar_y = ORDSIZE(this_data); 229 if (bar_y >= bar_last && bar_y > 0) 230 bar_y = bar_last - 1; 231 if (bar_last - bar_y > bar_high && bar_high > 1) 232 ++bar_y; 233 bar_last = MIN(bar_last, all_high); 234 235 wmove(win, top + 1 + bar_y, right); 236 237 dlg_attrset(win, position_indicator_attr); 238 dlg_attron(win, A_REVERSE); 239 #if defined(WACS_BLOCK) && defined(NCURSES_VERSION) && defined(USE_WIDE_CURSES) 240 wvline_set(win, WACS_BLOCK, bar_last - bar_y); 241 #else 242 wvline(win, ACS_BLOCK, bar_last - bar_y); 243 #endif 244 } 245 } 246 } 247 dlg_draw_arrows2(win, 248 top_arrow, 249 bottom_arrow, 250 left + ARROWS_COL, 251 top, 252 bottom, 253 attr, 254 borderattr); 255 256 dlg_attrset(win, save); 257 wmove(win, oldy, oldx); 258 } 259 260 void 261 dlg_draw_arrows(WINDOW *win, 262 int top_arrow, 263 int bottom_arrow, 264 int x, 265 int top, 266 int bottom) 267 { 268 dlg_draw_helpline(win, TRUE); 269 dlg_draw_arrows2(win, 270 top_arrow, 271 bottom_arrow, 272 x, 273 top, 274 bottom, 275 menubox_border2_attr, 276 menubox_border_attr); 277 } 278