1 /* 2 * $Id: progressbox.c,v 1.23 2012/12/21 10:00:05 tom Exp $ 3 * 4 * progressbox.c -- implements the progress box 5 * 6 * Copyright 2005 Valery Reznic 7 * Copyright 2006-2012 Thomas E. Dickey 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU Lesser General Public License as 11 * published by the Free Software Foundation; either version 2.1 of the 12 * License, or (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, but 15 * WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this program; if not, write to 21 * Free Software Foundation, Inc. 22 * 51 Franklin St., Fifth Floor 23 * Boston, MA 02110, USA. 24 */ 25 26 #include <dialog.h> 27 #include <dlg_keys.h> 28 29 #define MIN_HIGH (4) 30 #define MIN_WIDE (10 + 2 * (2 + MARGIN)) 31 32 typedef struct { 33 DIALOG_CALLBACK obj; 34 WINDOW *text; 35 char line[MAX_LEN + 1]; 36 int is_eof; 37 } MY_OBJ; 38 39 /* 40 * Return current line of text. 41 */ 42 static char * 43 get_line(MY_OBJ * obj) 44 { 45 FILE *fp = obj->obj.input; 46 int col = 0; 47 int j, tmpint, ch; 48 49 for (;;) { 50 if ((ch = getc(fp)) == EOF) { 51 obj->is_eof = 1; 52 if (col) { 53 break; 54 } else { 55 return NULL; 56 } 57 } 58 if (ch == '\n') 59 break; 60 if (ch == '\r') 61 break; 62 if (col >= MAX_LEN) 63 continue; 64 if ((ch == TAB) && (dialog_vars.tab_correct)) { 65 tmpint = dialog_state.tab_len 66 - (col % dialog_state.tab_len); 67 for (j = 0; j < tmpint; j++) { 68 if (col < MAX_LEN) { 69 obj->line[col] = ' '; 70 ++col; 71 } else { 72 break; 73 } 74 } 75 } else { 76 obj->line[col] = (char) ch; 77 ++col; 78 } 79 } 80 81 obj->line[col] = '\0'; 82 83 return obj->line; 84 } 85 86 /* 87 * Print a new line of text. 88 */ 89 static void 90 print_line(MY_OBJ * obj, WINDOW *win, int row, int width) 91 { 92 int i, y, x; 93 char *line = obj->line; 94 95 (void) wmove(win, row, 0); /* move cursor to correct line */ 96 (void) waddch(win, ' '); 97 #ifdef NCURSES_VERSION 98 (void) waddnstr(win, line, MIN((int) strlen(line), width - 2)); 99 #else 100 line[MIN((int) strlen(line), width - 2)] = '\0'; 101 waddstr(win, line); 102 #endif 103 104 getyx(win, y, x); 105 (void) y; 106 /* Clear 'residue' of previous line */ 107 for (i = 0; i < width - x; i++) 108 (void) waddch(win, ' '); 109 } 110 111 static int 112 pause_for_ok(WINDOW *dialog, int height, int width) 113 { 114 /* *INDENT-OFF* */ 115 static DLG_KEYS_BINDING binding[] = { 116 HELPKEY_BINDINGS, 117 ENTERKEY_BINDINGS, 118 TRAVERSE_BINDINGS, 119 END_KEYS_BINDING 120 }; 121 /* *INDENT-ON* */ 122 123 int button; 124 int key = 0, fkey; 125 int result = DLG_EXIT_UNKNOWN; 126 const char **buttons = dlg_ok_label(); 127 int check; 128 int save_nocancel = dialog_vars.nocancel; 129 bool redraw = TRUE; 130 131 dialog_vars.nocancel = TRUE; 132 button = dlg_default_button(); 133 134 dlg_register_window(dialog, "progressbox", binding); 135 dlg_register_buttons(dialog, "progressbox", buttons); 136 137 dlg_draw_bottom_box2(dialog, border_attr, border2_attr, dialog_attr); 138 mouse_mkbutton(height - 2, width / 2 - 4, 6, '\n'); 139 140 while (result == DLG_EXIT_UNKNOWN) { 141 if (redraw) { 142 redraw = FALSE; 143 if (button < 0) 144 button = 0; 145 dlg_draw_buttons(dialog, 146 height - 2, 0, 147 buttons, button, 148 FALSE, width); 149 } 150 151 key = dlg_mouse_wgetch(dialog, &fkey); 152 if (dlg_result_key(key, fkey, &result)) 153 break; 154 155 if (!fkey && (check = dlg_char_to_button(key, buttons)) >= 0) { 156 result = dlg_ok_buttoncode(check); 157 break; 158 } 159 160 if (fkey) { 161 switch (key) { 162 case DLGK_FIELD_NEXT: 163 button = dlg_next_button(buttons, button); 164 redraw = TRUE; 165 break; 166 case DLGK_FIELD_PREV: 167 button = dlg_prev_button(buttons, button); 168 redraw = TRUE; 169 break; 170 case DLGK_ENTER: 171 result = dlg_ok_buttoncode(button); 172 break; 173 default: 174 if (is_DLGK_MOUSE(key)) { 175 result = dlg_ok_buttoncode(key - M_EVENT); 176 if (result < 0) 177 result = DLG_EXIT_OK; 178 } else { 179 beep(); 180 } 181 break; 182 } 183 184 } else { 185 beep(); 186 } 187 } 188 dlg_unregister_window(dialog); 189 190 dialog_vars.nocancel = save_nocancel; 191 return result; 192 } 193 194 int 195 dlg_progressbox(const char *title, 196 const char *cprompt, 197 int height, 198 int width, 199 int pauseopt, 200 FILE *fp) 201 { 202 int i; 203 int x, y, thigh; 204 WINDOW *dialog, *text; 205 MY_OBJ *obj; 206 char *prompt = dlg_strclone(cprompt); 207 int result; 208 209 dlg_tab_correct_str(prompt); 210 dlg_auto_size(title, prompt, &height, &width, MIN_HIGH, MIN_WIDE); 211 dlg_print_size(height, width); 212 dlg_ctl_size(height, width); 213 214 x = dlg_box_x_ordinate(width); 215 y = dlg_box_y_ordinate(height); 216 thigh = height - (2 * MARGIN); 217 218 dialog = dlg_new_window(height, width, y, x); 219 220 dlg_draw_box2(dialog, 0, 0, height, width, dialog_attr, border_attr, border2_attr); 221 dlg_draw_title(dialog, title); 222 dlg_draw_helpline(dialog, FALSE); 223 224 if (*prompt != '\0') { 225 int y2, x2; 226 227 (void) wattrset(dialog, dialog_attr); 228 dlg_print_autowrap(dialog, prompt, height, width); 229 getyx(dialog, y2, x2); 230 (void) x2; 231 ++y2; 232 wmove(dialog, y2, MARGIN); 233 for (i = 0; i < getmaxx(dialog) - 2 * MARGIN; i++) 234 (void) waddch(dialog, dlg_boxchar(ACS_HLINE)); 235 y += y2; 236 thigh -= y2; 237 } 238 239 /* Create window for text region, used for scrolling text */ 240 text = dlg_sub_window(dialog, 241 thigh, 242 width - (2 * MARGIN), 243 y + MARGIN, 244 x + MARGIN); 245 246 (void) wrefresh(dialog); 247 248 (void) wmove(dialog, thigh, (MARGIN + 1)); 249 (void) wnoutrefresh(dialog); 250 251 obj = dlg_calloc(MY_OBJ, 1); 252 assert_ptr(obj, "dlg_progressbox"); 253 254 obj->obj.input = fp; 255 obj->obj.win = dialog; 256 obj->text = text; 257 258 dlg_attr_clear(text, thigh, getmaxx(text), dialog_attr); 259 for (i = 0; get_line(obj); i++) { 260 if (i < thigh) { 261 print_line(obj, text, i, width - (2 * MARGIN)); 262 } else { 263 scrollok(text, TRUE); 264 scroll(text); 265 scrollok(text, FALSE); 266 print_line(obj, text, thigh - 1, width - (2 * MARGIN)); 267 } 268 (void) wrefresh(text); 269 dlg_trace_win(dialog); 270 if (obj->is_eof) 271 break; 272 } 273 274 if (pauseopt) { 275 scrollok(text, TRUE); 276 wscrl(text, 1 + MARGIN); 277 (void) wrefresh(text); 278 result = pause_for_ok(dialog, height, width); 279 } else { 280 wrefresh(dialog); 281 result = DLG_EXIT_OK; 282 } 283 284 dlg_del_window(dialog); 285 free(prompt); 286 free(obj); 287 288 return result; 289 } 290 291 /* 292 * Display text from a stdin in a scrolling window. 293 */ 294 int 295 dialog_progressbox(const char *title, const char *cprompt, int height, int width) 296 { 297 int result; 298 result = dlg_progressbox(title, 299 cprompt, 300 height, 301 width, 302 FALSE, 303 dialog_state.pipe_input); 304 dialog_state.pipe_input = 0; 305 return result; 306 } 307