1 /* 2 * $Id: pause.c,v 1.39 2018/06/19 22:57:01 tom Exp $ 3 * 4 * pause.c -- implements the pause dialog 5 * 6 * Copyright 2004-2012,2018 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 * This is adapted from source contributed by 24 * Yura Kalinichenko 25 */ 26 27 #include <dialog.h> 28 #include <dlg_keys.h> 29 30 #define MY_TIMEOUT 50 31 32 #define MIN_HIGH (4) 33 #define MIN_WIDE (10 + 2 * (2 + MARGIN)) 34 #define BTN_HIGH (1 + 2 * MARGIN) 35 36 /* 37 * This is like gauge, but can be interrupted. 38 * 39 * A pause box displays a meter along the bottom of the box. The meter 40 * indicates how many seconds remain until the end of the pause. The pause 41 * exits when timeout is reached (status OK) or the user presses: 42 * OK button (status OK) 43 * CANCEL button (status CANCEL) 44 * Esc key (status ESC) 45 * 46 */ 47 int 48 dialog_pause(const char *title, 49 const char *cprompt, 50 int height, 51 int width, 52 int seconds) 53 { 54 /* *INDENT-OFF* */ 55 static DLG_KEYS_BINDING binding[] = { 56 HELPKEY_BINDINGS, 57 ENTERKEY_BINDINGS, 58 TRAVERSE_BINDINGS, 59 END_KEYS_BINDING 60 }; 61 /* *INDENT-ON* */ 62 63 #ifdef KEY_RESIZE 64 int old_height = height; 65 int old_width = width; 66 #endif 67 68 int i, x, y, step; 69 int button = dlg_default_button(); 70 int seconds_orig; 71 WINDOW *dialog; 72 const char **buttons = dlg_ok_labels(); 73 bool have_buttons = (dlg_button_count(buttons) != 0); 74 bool first; 75 int key = 0, fkey; 76 int result = DLG_EXIT_UNKNOWN; 77 int button_high = (have_buttons ? BTN_HIGH : MARGIN); 78 int gauge_y; 79 char *prompt; 80 int save_timeout = dialog_vars.timeout_secs; 81 82 DLG_TRACE(("# pause args:\n")); 83 DLG_TRACE2S("title", title); 84 DLG_TRACE2S("message", cprompt); 85 DLG_TRACE2N("height", height); 86 DLG_TRACE2N("width", width); 87 DLG_TRACE2N("seconds", seconds); 88 89 curs_set(0); 90 91 dialog_vars.timeout_secs = 0; 92 seconds_orig = (seconds > 0) ? seconds : 1; 93 94 #ifdef KEY_RESIZE 95 retry: 96 #endif 97 98 prompt = dlg_strclone(cprompt); 99 dlg_tab_correct_str(prompt); 100 101 if (have_buttons) { 102 dlg_auto_size(title, prompt, &height, &width, 103 MIN_HIGH, 104 MIN_WIDE); 105 dlg_button_layout(buttons, &width); 106 } else { 107 dlg_auto_size(title, prompt, &height, &width, 108 MIN_HIGH + MARGIN - BTN_HIGH, 109 MIN_WIDE); 110 } 111 gauge_y = height - button_high - (1 + 2 * MARGIN); 112 dlg_print_size(height, width); 113 dlg_ctl_size(height, width); 114 115 /* center dialog box on screen */ 116 x = dlg_box_x_ordinate(width); 117 y = dlg_box_y_ordinate(height); 118 119 dialog = dlg_new_window(height, width, y, x); 120 dlg_register_window(dialog, "pause", binding); 121 dlg_register_buttons(dialog, "pause", buttons); 122 123 dlg_mouse_setbase(x, y); 124 nodelay(dialog, TRUE); 125 126 first = TRUE; 127 do { 128 (void) werase(dialog); 129 dlg_draw_box2(dialog, 0, 0, height, width, dialog_attr, border_attr, border2_attr); 130 131 dlg_draw_title(dialog, title); 132 dlg_draw_helpline(dialog, FALSE); 133 134 dlg_attrset(dialog, dialog_attr); 135 dlg_print_autowrap(dialog, prompt, height, width); 136 137 dlg_draw_box2(dialog, 138 gauge_y, 2 + MARGIN, 139 2 + MARGIN, width - 2 * (2 + MARGIN), 140 dialog_attr, 141 border_attr, 142 border2_attr); 143 144 /* 145 * Clear the area for the progress bar by filling it with spaces 146 * in the title-attribute, and write the percentage with that 147 * attribute. 148 */ 149 (void) wmove(dialog, gauge_y + MARGIN, 4); 150 dlg_attrset(dialog, title_attr); 151 152 for (i = 0; i < (width - 2 * (3 + MARGIN)); i++) 153 (void) waddch(dialog, ' '); 154 155 (void) wmove(dialog, gauge_y + MARGIN, (width / 2) - 2); 156 (void) wprintw(dialog, "%3d", seconds); 157 158 /* 159 * Now draw a bar in reverse, relative to the background. 160 * The window attribute was useful for painting the background, 161 * but requires some tweaks to reverse it. 162 */ 163 x = (seconds * (width - 2 * (3 + MARGIN))) / seconds_orig; 164 if ((title_attr & A_REVERSE) != 0) { 165 dlg_attroff(dialog, A_REVERSE); 166 } else { 167 dlg_attrset(dialog, A_REVERSE); 168 } 169 (void) wmove(dialog, gauge_y + MARGIN, 4); 170 for (i = 0; i < x; i++) { 171 chtype ch = winch(dialog); 172 if (title_attr & A_REVERSE) { 173 ch &= ~A_REVERSE; 174 } 175 (void) waddch(dialog, ch); 176 } 177 178 mouse_mkbutton(height - 2, width / 2 - 4, 6, '\n'); 179 if (have_buttons) { 180 dlg_draw_bottom_box2(dialog, border_attr, border2_attr, dialog_attr); 181 dlg_draw_buttons(dialog, height - 2, 0, buttons, button, FALSE, width); 182 } 183 if (first) { 184 (void) wrefresh(dialog); 185 dlg_trace_win(dialog); 186 first = FALSE; 187 } 188 189 for (step = 0; 190 (result == DLG_EXIT_UNKNOWN) && (step < 1000); 191 step += MY_TIMEOUT) { 192 193 napms(MY_TIMEOUT); 194 key = dlg_mouse_wgetch_nowait(dialog, &fkey); 195 if (key == ERR) { 196 ; /* ignore errors in nodelay mode */ 197 } else { 198 if (dlg_result_key(key, fkey, &result)) 199 break; 200 } 201 202 switch (key) { 203 #ifdef KEY_RESIZE 204 case KEY_RESIZE: 205 dlg_will_resize(dialog); 206 dlg_clear(); /* fill the background */ 207 dlg_del_window(dialog); /* delete this window */ 208 height = old_height; 209 width = old_width; 210 free(prompt); 211 refresh(); /* get it all onto the terminal */ 212 goto retry; 213 #endif 214 case DLGK_FIELD_NEXT: 215 button = dlg_next_button(buttons, button); 216 if (button < 0) 217 button = 0; 218 dlg_draw_buttons(dialog, 219 height - 2, 0, 220 buttons, button, 221 FALSE, width); 222 break; 223 case DLGK_FIELD_PREV: 224 button = dlg_prev_button(buttons, button); 225 if (button < 0) 226 button = 0; 227 dlg_draw_buttons(dialog, 228 height - 2, 0, 229 buttons, button, 230 FALSE, width); 231 break; 232 case DLGK_ENTER: 233 result = dlg_enter_buttoncode(button); 234 break; 235 case ERR: 236 break; 237 default: 238 if (is_DLGK_MOUSE(key)) { 239 result = dlg_ok_buttoncode(key - M_EVENT); 240 if (result < 0) 241 result = DLG_EXIT_OK; 242 } 243 break; 244 } 245 } 246 } while ((result == DLG_EXIT_UNKNOWN) && (seconds-- > 0)); 247 248 curs_set(1); 249 dlg_mouse_free_regions(); 250 dlg_del_window(dialog); 251 free(prompt); 252 253 dialog_vars.timeout_secs = save_timeout; 254 255 return ((result == DLG_EXIT_UNKNOWN) ? DLG_EXIT_OK : result); 256 } 257