1 /* 2 * $Id: pause.c,v 1.48 2020/11/23 00:38:19 tom Exp $ 3 * 4 * pause.c -- implements the pause dialog 5 * 6 * Copyright 2004-2019,2020 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, 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 seconds_orig = (seconds > 0) ? seconds : 1; 92 dialog_vars.pause_secs = seconds_orig; 93 dialog_vars.timeout_secs = 0; 94 95 #ifdef KEY_RESIZE 96 retry: 97 #endif 98 99 prompt = dlg_strclone(cprompt); 100 dlg_tab_correct_str(prompt); 101 102 if (have_buttons) { 103 dlg_auto_size(title, prompt, &height, &width, 104 MIN_HIGH, 105 MIN_WIDE); 106 dlg_button_layout(buttons, &width); 107 } else { 108 dlg_auto_size(title, prompt, &height, &width, 109 MIN_HIGH + MARGIN - BTN_HIGH, 110 MIN_WIDE); 111 } 112 gauge_y = height - button_high - (1 + 2 * MARGIN); 113 dlg_print_size(height, width); 114 dlg_ctl_size(height, width); 115 116 /* center dialog box on screen */ 117 x = dlg_box_x_ordinate(width); 118 y = dlg_box_y_ordinate(height); 119 120 dialog = dlg_new_window(height, width, y, x); 121 dlg_register_window(dialog, "pause", binding); 122 dlg_register_buttons(dialog, "pause", buttons); 123 124 dlg_mouse_setbase(x, y); 125 nodelay(dialog, TRUE); 126 127 first = TRUE; 128 do { 129 (void) werase(dialog); 130 dlg_draw_box2(dialog, 0, 0, height, width, dialog_attr, border_attr, border2_attr); 131 132 dlg_draw_title(dialog, title); 133 dlg_draw_helpline(dialog, FALSE); 134 135 dlg_attrset(dialog, dialog_attr); 136 dlg_print_autowrap(dialog, prompt, height, width); 137 138 dlg_draw_box2(dialog, 139 gauge_y, 2 + MARGIN, 140 2 + MARGIN, width - 2 * (2 + MARGIN), 141 dialog_attr, 142 border_attr, 143 border2_attr); 144 145 /* 146 * Clear the area for the progress bar by filling it with spaces 147 * in the title-attribute, and write the percentage with that 148 * attribute. 149 */ 150 (void) wmove(dialog, gauge_y + MARGIN, 4); 151 dlg_attrset(dialog, title_attr); 152 153 for (i = 0; i < (width - 2 * (3 + MARGIN)); i++) 154 (void) waddch(dialog, ' '); 155 156 (void) wmove(dialog, gauge_y + MARGIN, (width / 2) - 2); 157 (void) wprintw(dialog, "%3d", seconds); 158 159 /* 160 * Now draw a bar in reverse, relative to the background. 161 * The window attribute was useful for painting the background, 162 * but requires some tweaks to reverse it. 163 */ 164 x = (seconds * (width - 2 * (3 + MARGIN))) / seconds_orig; 165 if ((title_attr & A_REVERSE) != 0) { 166 dlg_attroff(dialog, A_REVERSE); 167 } else { 168 dlg_attrset(dialog, A_REVERSE); 169 } 170 (void) wmove(dialog, gauge_y + MARGIN, 4); 171 for (i = 0; i < x; i++) { 172 chtype ch = winch(dialog); 173 if (title_attr & A_REVERSE) { 174 ch &= ~A_REVERSE; 175 } 176 (void) waddch(dialog, ch); 177 } 178 179 mouse_mkbutton(height - 2, width / 2 - 4, 6, '\n'); 180 if (have_buttons) { 181 dlg_draw_bottom_box2(dialog, border_attr, border2_attr, dialog_attr); 182 dlg_draw_buttons(dialog, height - 2, 0, buttons, button, FALSE, width); 183 } 184 if (first) { 185 (void) wrefresh(dialog); 186 dlg_trace_win(dialog); 187 first = FALSE; 188 } 189 190 for (step = 0; 191 (result == DLG_EXIT_UNKNOWN) && (step < 1000); 192 step += MY_TIMEOUT) { 193 194 napms(MY_TIMEOUT); 195 key = dlg_mouse_wgetch_nowait(dialog, &fkey); 196 if (key == ERR) { 197 ; /* ignore errors in nodelay mode */ 198 } else if (dlg_result_key(key, fkey, &result)) { 199 if (!dlg_button_key(result, &button, &key, &fkey)) 200 break; 201 } 202 203 switch (key) { 204 #ifdef KEY_RESIZE 205 case KEY_RESIZE: 206 dlg_will_resize(dialog); 207 height = old_height; 208 width = old_width; 209 free(prompt); 210 _dlg_resize_cleanup(dialog); 211 goto retry; 212 #endif 213 case DLGK_FIELD_NEXT: 214 button = dlg_next_button(buttons, button); 215 if (button < 0) 216 button = 0; 217 dlg_draw_buttons(dialog, 218 height - 2, 0, 219 buttons, button, 220 FALSE, width); 221 break; 222 case DLGK_FIELD_PREV: 223 button = dlg_prev_button(buttons, button); 224 if (button < 0) 225 button = 0; 226 dlg_draw_buttons(dialog, 227 height - 2, 0, 228 buttons, button, 229 FALSE, width); 230 break; 231 case DLGK_ENTER: 232 result = dlg_enter_buttoncode(button); 233 break; 234 case DLGK_LEAVE: 235 result = dlg_ok_buttoncode(button); 236 break; 237 case ERR: 238 break; 239 default: 240 if (is_DLGK_MOUSE(key)) { 241 result = dlg_ok_buttoncode(key - M_EVENT); 242 if (result < 0) 243 result = DLG_EXIT_OK; 244 } 245 break; 246 } 247 } 248 } while ((result == DLG_EXIT_UNKNOWN) && (seconds-- > 0)); 249 dlg_add_last_key(-1); 250 251 curs_set(1); 252 dlg_mouse_free_regions(); 253 dlg_del_window(dialog); 254 free(prompt); 255 256 dialog_vars.timeout_secs = save_timeout; 257 258 return ((result == DLG_EXIT_UNKNOWN) ? DLG_EXIT_OK : result); 259 } 260