1217309Snwhitehorn/* 2255852Sdteske * $Id: guage.c,v 1.68 2013/09/22 19:10:22 tom Exp $ 3217309Snwhitehorn * 4220749Snwhitehorn * guage.c -- implements the gauge dialog 5217309Snwhitehorn * 6255852Sdteske * Copyright 2000-2012,2013 Thomas E. Dickey 7217309Snwhitehorn * 8217309Snwhitehorn * This program is free software; you can redistribute it and/or modify 9217309Snwhitehorn * it under the terms of the GNU Lesser General Public License, version 2.1 10217309Snwhitehorn * as published by the Free Software Foundation. 11217309Snwhitehorn * 12217309Snwhitehorn * This program is distributed in the hope that it will be useful, but 13217309Snwhitehorn * WITHOUT ANY WARRANTY; without even the implied warranty of 14217309Snwhitehorn * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15217309Snwhitehorn * Lesser General Public License for more details. 16217309Snwhitehorn * 17217309Snwhitehorn * You should have received a copy of the GNU Lesser General Public 18217309Snwhitehorn * License along with this program; if not, write to 19217309Snwhitehorn * Free Software Foundation, Inc. 20217309Snwhitehorn * 51 Franklin St., Fifth Floor 21217309Snwhitehorn * Boston, MA 02110, USA. 22217309Snwhitehorn * 23217309Snwhitehorn * An earlier version of this program lists as authors 24217309Snwhitehorn * Marc Ewing, Red Hat Software 25217309Snwhitehorn */ 26217309Snwhitehorn 27217309Snwhitehorn#include <dialog.h> 28217309Snwhitehorn 29217309Snwhitehorn#include <errno.h> 30217309Snwhitehorn 31217309Snwhitehorn#define MY_LEN (MAX_LEN)/2 32217309Snwhitehorn 33217309Snwhitehorn#define MIN_HIGH (4) 34217309Snwhitehorn#define MIN_WIDE (10 + 2 * (2 + MARGIN)) 35217309Snwhitehorn 36220749Snwhitehorn#define isMarker(buf) !strncmp(buf, "XXX", (size_t) 3) 37217309Snwhitehorn 38224014Snwhitehorntypedef struct _my_obj { 39224014Snwhitehorn DIALOG_CALLBACK obj; /* has to be first in struct */ 40224014Snwhitehorn struct _my_obj *next; 41217309Snwhitehorn WINDOW *text; 42255852Sdteske char *title; 43217309Snwhitehorn char *prompt; 44217309Snwhitehorn char prompt_buf[MY_LEN]; 45217309Snwhitehorn int percent; 46217309Snwhitehorn int height; 47217309Snwhitehorn int width; 48217309Snwhitehorn char line[MAX_LEN + 1]; 49217309Snwhitehorn} MY_OBJ; 50217309Snwhitehorn 51224014Snwhitehornstatic MY_OBJ *all_objects; 52224014Snwhitehorn 53217309Snwhitehornstatic int 54224014Snwhitehornvalid(MY_OBJ * obj) 55224014Snwhitehorn{ 56224014Snwhitehorn MY_OBJ *list = all_objects; 57224014Snwhitehorn int result = 0; 58224014Snwhitehorn 59224014Snwhitehorn while (list != 0) { 60224014Snwhitehorn if (list == obj) { 61224014Snwhitehorn result = 1; 62224014Snwhitehorn break; 63224014Snwhitehorn } 64224014Snwhitehorn list = list->next; 65224014Snwhitehorn } 66224014Snwhitehorn return result; 67224014Snwhitehorn} 68224014Snwhitehorn 69224014Snwhitehornstatic void 70224014Snwhitehorndelink(MY_OBJ * obj) 71224014Snwhitehorn{ 72224014Snwhitehorn MY_OBJ *p = all_objects; 73224014Snwhitehorn MY_OBJ *q = 0; 74224014Snwhitehorn while (p != 0) { 75224014Snwhitehorn if (p == obj) { 76224014Snwhitehorn if (q != 0) { 77224014Snwhitehorn q->next = p->next; 78224014Snwhitehorn } else { 79224014Snwhitehorn all_objects = p->next; 80224014Snwhitehorn } 81224014Snwhitehorn break; 82224014Snwhitehorn } 83224014Snwhitehorn q = p; 84224014Snwhitehorn p = p->next; 85224014Snwhitehorn } 86224014Snwhitehorn} 87224014Snwhitehorn 88224014Snwhitehornstatic int 89217309Snwhitehornread_data(char *buffer, FILE *fp) 90217309Snwhitehorn{ 91217309Snwhitehorn int result; 92217309Snwhitehorn 93217309Snwhitehorn if (feof(fp)) { 94217309Snwhitehorn result = 0; 95217309Snwhitehorn } else if (fgets(buffer, MY_LEN, fp) != 0) { 96224014Snwhitehorn DLG_TRACE(("read_data:%s", buffer)); 97251843Sbapt buffer[MY_LEN] = '\0'; 98217309Snwhitehorn dlg_trim_string(buffer); 99217309Snwhitehorn result = 1; 100217309Snwhitehorn } else { 101217309Snwhitehorn result = -1; 102217309Snwhitehorn } 103217309Snwhitehorn return result; 104217309Snwhitehorn} 105217309Snwhitehorn 106217309Snwhitehornstatic int 107217309Snwhitehorndecode_percent(char *buffer) 108217309Snwhitehorn{ 109217309Snwhitehorn char *tmp = 0; 110217309Snwhitehorn long value = strtol(buffer, &tmp, 10); 111217309Snwhitehorn 112217309Snwhitehorn if (tmp != 0 && (*tmp == 0 || isspace(UCH(*tmp))) && value >= 0) { 113217309Snwhitehorn return TRUE; 114217309Snwhitehorn } 115217309Snwhitehorn return FALSE; 116217309Snwhitehorn} 117217309Snwhitehorn 118217309Snwhitehornstatic void 119217309Snwhitehornrepaint_text(MY_OBJ * obj) 120217309Snwhitehorn{ 121217309Snwhitehorn WINDOW *dialog = obj->obj.win; 122217309Snwhitehorn int i, x; 123217309Snwhitehorn 124220749Snwhitehorn if (dialog != 0 && obj->obj.input != 0) { 125220749Snwhitehorn (void) werase(dialog); 126251843Sbapt dlg_draw_box2(dialog, 0, 0, obj->height, obj->width, dialog_attr, 127251843Sbapt border_attr, border2_attr); 128217309Snwhitehorn 129220749Snwhitehorn dlg_draw_title(dialog, obj->title); 130217309Snwhitehorn 131251843Sbapt (void) wattrset(dialog, dialog_attr); 132224014Snwhitehorn dlg_draw_helpline(dialog, FALSE); 133220749Snwhitehorn dlg_print_autowrap(dialog, obj->prompt, obj->height, obj->width); 134217309Snwhitehorn 135251843Sbapt dlg_draw_box2(dialog, 136251843Sbapt obj->height - 4, 2 + MARGIN, 137251843Sbapt 2 + MARGIN, obj->width - 2 * (2 + MARGIN), 138251843Sbapt dialog_attr, 139251843Sbapt border_attr, 140251843Sbapt border2_attr); 141217309Snwhitehorn 142220749Snwhitehorn /* 143220749Snwhitehorn * Clear the area for the progress bar by filling it with spaces 144251843Sbapt * in the gauge-attribute, and write the percentage with that 145220749Snwhitehorn * attribute. 146220749Snwhitehorn */ 147220749Snwhitehorn (void) wmove(dialog, obj->height - 3, 4); 148251843Sbapt (void) wattrset(dialog, gauge_attr); 149217309Snwhitehorn 150220749Snwhitehorn for (i = 0; i < (obj->width - 2 * (3 + MARGIN)); i++) 151220749Snwhitehorn (void) waddch(dialog, ' '); 152217309Snwhitehorn 153220749Snwhitehorn (void) wmove(dialog, obj->height - 3, (obj->width / 2) - 2); 154220749Snwhitehorn (void) wprintw(dialog, "%3d%%", obj->percent); 155217309Snwhitehorn 156220749Snwhitehorn /* 157220749Snwhitehorn * Now draw a bar in reverse, relative to the background. 158220749Snwhitehorn * The window attribute was useful for painting the background, 159220749Snwhitehorn * but requires some tweaks to reverse it. 160220749Snwhitehorn */ 161220749Snwhitehorn x = (obj->percent * (obj->width - 2 * (3 + MARGIN))) / 100; 162251843Sbapt if ((gauge_attr & A_REVERSE) != 0) { 163220749Snwhitehorn wattroff(dialog, A_REVERSE); 164220749Snwhitehorn } else { 165251843Sbapt (void) wattrset(dialog, A_REVERSE); 166217309Snwhitehorn } 167220749Snwhitehorn (void) wmove(dialog, obj->height - 3, 4); 168220749Snwhitehorn for (i = 0; i < x; i++) { 169220749Snwhitehorn chtype ch2 = winch(dialog); 170251843Sbapt if (gauge_attr & A_REVERSE) { 171220749Snwhitehorn ch2 &= ~A_REVERSE; 172220749Snwhitehorn } 173220749Snwhitehorn (void) waddch(dialog, ch2); 174220749Snwhitehorn } 175220749Snwhitehorn 176220749Snwhitehorn (void) wrefresh(dialog); 177217309Snwhitehorn } 178217309Snwhitehorn} 179217309Snwhitehorn 180220749Snwhitehornstatic bool 181220749Snwhitehornhandle_input(DIALOG_CALLBACK * cb) 182217309Snwhitehorn{ 183220749Snwhitehorn MY_OBJ *obj = (MY_OBJ *) cb; 184220749Snwhitehorn bool result; 185217309Snwhitehorn int status; 186251843Sbapt char buf[MY_LEN + 1]; 187217309Snwhitehorn 188220749Snwhitehorn if (dialog_state.pipe_input == 0) { 189220749Snwhitehorn status = -1; 190220749Snwhitehorn } else if ((status = read_data(buf, dialog_state.pipe_input)) > 0) { 191217309Snwhitehorn 192217309Snwhitehorn if (isMarker(buf)) { 193217309Snwhitehorn /* 194217309Snwhitehorn * Historically, next line should be percentage, but one of the 195217309Snwhitehorn * worse-written clones of 'dialog' assumes the number is missing. 196217309Snwhitehorn * (Gresham's Law applied to software). 197217309Snwhitehorn */ 198217309Snwhitehorn if ((status = read_data(buf, dialog_state.pipe_input)) > 0) { 199217309Snwhitehorn 200217309Snwhitehorn obj->prompt_buf[0] = '\0'; 201217309Snwhitehorn if (decode_percent(buf)) 202217309Snwhitehorn obj->percent = atoi(buf); 203217309Snwhitehorn else 204217309Snwhitehorn strcpy(obj->prompt_buf, buf); 205217309Snwhitehorn 206217309Snwhitehorn /* Rest is message text */ 207217309Snwhitehorn while ((status = read_data(buf, dialog_state.pipe_input)) > 0 208217309Snwhitehorn && !isMarker(buf)) { 209217309Snwhitehorn if (strlen(obj->prompt_buf) + strlen(buf) < 210217309Snwhitehorn sizeof(obj->prompt_buf) - 1) { 211217309Snwhitehorn strcat(obj->prompt_buf, buf); 212217309Snwhitehorn } 213217309Snwhitehorn } 214217309Snwhitehorn 215217309Snwhitehorn if (obj->prompt != obj->prompt_buf) 216217309Snwhitehorn free(obj->prompt); 217217309Snwhitehorn obj->prompt = obj->prompt_buf; 218217309Snwhitehorn } 219217309Snwhitehorn } else if (decode_percent(buf)) { 220217309Snwhitehorn obj->percent = atoi(buf); 221217309Snwhitehorn } 222217309Snwhitehorn } else { 223220749Snwhitehorn if (feof(dialog_state.pipe_input) || 224220749Snwhitehorn (ferror(dialog_state.pipe_input) && errno != EINTR)) { 225224014Snwhitehorn delink(obj); 226220749Snwhitehorn dlg_remove_callback(cb); 227220749Snwhitehorn } 228217309Snwhitehorn } 229217309Snwhitehorn 230220749Snwhitehorn if (status > 0) { 231220749Snwhitehorn result = TRUE; 232220749Snwhitehorn repaint_text(obj); 233220749Snwhitehorn } else { 234220749Snwhitehorn result = FALSE; 235220749Snwhitehorn } 236220749Snwhitehorn 237220749Snwhitehorn return result; 238217309Snwhitehorn} 239217309Snwhitehorn 240217309Snwhitehornstatic bool 241217309Snwhitehornhandle_my_getc(DIALOG_CALLBACK * cb, int ch, int fkey, int *result) 242217309Snwhitehorn{ 243217309Snwhitehorn int status = TRUE; 244217309Snwhitehorn 245217309Snwhitehorn *result = DLG_EXIT_OK; 246220749Snwhitehorn if (cb != 0) { 247217309Snwhitehorn if (!fkey && (ch == ERR)) { 248220749Snwhitehorn (void) handle_input(cb); 249224014Snwhitehorn /* cb might be freed in handle_input */ 250224014Snwhitehorn status = (valid((MY_OBJ *) cb) && (cb->input != 0)); 251217309Snwhitehorn } 252217309Snwhitehorn } else { 253217309Snwhitehorn status = FALSE; 254217309Snwhitehorn } 255217309Snwhitehorn return status; 256217309Snwhitehorn} 257217309Snwhitehorn 258217309Snwhitehornstatic void 259217309Snwhitehornmy_cleanup(DIALOG_CALLBACK * cb) 260217309Snwhitehorn{ 261217309Snwhitehorn MY_OBJ *obj = (MY_OBJ *) cb; 262217309Snwhitehorn 263224014Snwhitehorn if (valid(obj)) { 264224014Snwhitehorn if (obj->prompt != obj->prompt_buf) { 265217309Snwhitehorn free(obj->prompt); 266224014Snwhitehorn obj->prompt = obj->prompt_buf; 267224014Snwhitehorn } 268224014Snwhitehorn delink(obj); 269217309Snwhitehorn } 270217309Snwhitehorn} 271217309Snwhitehorn 272224014Snwhitehornvoid 273224014Snwhitehorndlg_update_gauge(void *objptr, int percent) 274224014Snwhitehorn{ 275224014Snwhitehorn MY_OBJ *obj = (MY_OBJ *) objptr; 276255852Sdteske bool save_finish_string = dialog_state.finish_string; 277224014Snwhitehorn 278255852Sdteske dialog_state.finish_string = TRUE; 279224014Snwhitehorn curs_set(0); 280224014Snwhitehorn obj->percent = percent; 281224014Snwhitehorn repaint_text(obj); 282255852Sdteske dialog_state.finish_string = save_finish_string; 283224014Snwhitehorn} 284224014Snwhitehorn 285217309Snwhitehorn/* 286255852Sdteske * (Re)Allocates an object and fills it as per the arguments 287217309Snwhitehorn */ 288224014Snwhitehornvoid * 289255852Sdteskedlg_reallocate_gauge(void *objptr, 290255852Sdteske const char *title, 291255852Sdteske const char *cprompt, 292255852Sdteske int height, 293255852Sdteske int width, 294255852Sdteske int percent) 295217309Snwhitehorn{ 296217309Snwhitehorn char *prompt = dlg_strclone(cprompt); 297255852Sdteske MY_OBJ *obj = objptr; 298255852Sdteske bool save_finish_string = dialog_state.finish_string; 299217309Snwhitehorn 300255852Sdteske dialog_state.finish_string = TRUE; 301217309Snwhitehorn dlg_tab_correct_str(prompt); 302217309Snwhitehorn 303255852Sdteske if (objptr == 0) { 304255852Sdteske /* create a new object */ 305255852Sdteske obj = dlg_calloc(MY_OBJ, 1); 306255852Sdteske assert_ptr(obj, "dialog_gauge"); 307217309Snwhitehorn 308255852Sdteske dlg_auto_size(title, prompt, &height, &width, MIN_HIGH, MIN_WIDE); 309255852Sdteske dlg_print_size(height, width); 310255852Sdteske dlg_ctl_size(height, width); 311217309Snwhitehorn 312255852Sdteske } else { 313255852Sdteske /* reuse an existing object */ 314255852Sdteske obj = objptr; 315255852Sdteske height = obj->height; 316255852Sdteske width = obj->width; 317255852Sdteske } 318217309Snwhitehorn 319255852Sdteske if (obj->obj.win == 0) { 320255852Sdteske /* center dialog box on screen */ 321255852Sdteske int x = dlg_box_x_ordinate(width); 322255852Sdteske int y = dlg_box_y_ordinate(height); 323255852Sdteske WINDOW *dialog = dlg_new_window(height, width, y, x); 324255852Sdteske obj->obj.win = dialog; 325255852Sdteske } 326217309Snwhitehorn 327224014Snwhitehorn obj->obj.input = dialog_state.pipe_input; 328224014Snwhitehorn obj->obj.keep_win = TRUE; 329224014Snwhitehorn obj->obj.bg_task = TRUE; 330224014Snwhitehorn obj->obj.handle_getc = handle_my_getc; 331224014Snwhitehorn obj->obj.handle_input = handle_input; 332217309Snwhitehorn 333255852Sdteske if (obj->title == 0 || strcmp(obj->title, title)) { 334255852Sdteske dlg_finish_string(obj->title); 335255852Sdteske free(obj->title); 336255852Sdteske obj->title = dlg_strclone(title); 337255852Sdteske } 338255852Sdteske 339255852Sdteske dlg_finish_string(obj->prompt); 340255852Sdteske free(obj->prompt); 341255852Sdteske 342224014Snwhitehorn obj->prompt = prompt; 343224014Snwhitehorn obj->percent = percent; 344224014Snwhitehorn obj->height = height; 345224014Snwhitehorn obj->width = width; 346224014Snwhitehorn 347255852Sdteske /* if this was a new object, link it into the list */ 348255852Sdteske if (objptr == 0) { 349255852Sdteske obj->next = all_objects; 350255852Sdteske all_objects = obj; 351255852Sdteske } 352224014Snwhitehorn 353255852Sdteske dialog_state.finish_string = save_finish_string; 354224014Snwhitehorn return (void *) obj; 355224014Snwhitehorn} 356224014Snwhitehorn 357255852Sdteskevoid * 358255852Sdteskedlg_allocate_gauge(const char *title, 359255852Sdteske const char *cprompt, 360255852Sdteske int height, 361255852Sdteske int width, 362255852Sdteske int percent) 363255852Sdteske{ 364255852Sdteske return dlg_reallocate_gauge(NULL, title, cprompt, height, width, percent); 365255852Sdteske} 366255852Sdteske 367224014Snwhitehornvoid 368224014Snwhitehorndlg_free_gauge(void *objptr) 369224014Snwhitehorn{ 370224014Snwhitehorn MY_OBJ *obj = (MY_OBJ *) objptr; 371224014Snwhitehorn 372224014Snwhitehorn curs_set(1); 373224014Snwhitehorn if (valid(obj)) { 374224014Snwhitehorn delink(obj); 375224014Snwhitehorn obj->obj.keep_win = FALSE; 376224014Snwhitehorn dlg_remove_callback(&(obj->obj)); 377217309Snwhitehorn } 378224014Snwhitehorn} 379217309Snwhitehorn 380224014Snwhitehorn/* 381224014Snwhitehorn * Display a gauge, or progress meter. Starts at percent% and reads stdin. If 382224014Snwhitehorn * stdin is not XXX, then it is interpreted as a percentage, and the display is 383224014Snwhitehorn * updated accordingly. Otherwise the next line is the percentage, and 384224014Snwhitehorn * subsequent lines up to another XXX are used for the new prompt. Note that 385224014Snwhitehorn * the size of the window never changes, so the prompt can not get any larger 386224014Snwhitehorn * than the height and width specified. 387224014Snwhitehorn */ 388224014Snwhitehornint 389224014Snwhitehorndialog_gauge(const char *title, 390224014Snwhitehorn const char *cprompt, 391224014Snwhitehorn int height, 392224014Snwhitehorn int width, 393224014Snwhitehorn int percent) 394224014Snwhitehorn{ 395224014Snwhitehorn int fkey; 396224014Snwhitehorn int ch, result; 397224014Snwhitehorn void *objptr = dlg_allocate_gauge(title, cprompt, height, width, percent); 398224014Snwhitehorn MY_OBJ *obj = (MY_OBJ *) objptr; 399217309Snwhitehorn 400224014Snwhitehorn dlg_add_callback_ref((DIALOG_CALLBACK **) & obj, my_cleanup); 401224014Snwhitehorn dlg_update_gauge(obj, percent); 402224014Snwhitehorn 403251843Sbapt dlg_trace_win(obj->obj.win); 404217309Snwhitehorn do { 405224014Snwhitehorn ch = dlg_getc(obj->obj.win, &fkey); 406217309Snwhitehorn#ifdef KEY_RESIZE 407217309Snwhitehorn if (fkey && ch == KEY_RESIZE) { 408224014Snwhitehorn MY_OBJ *oldobj = obj; 409224014Snwhitehorn 410224014Snwhitehorn dlg_mouse_free_regions(); 411224014Snwhitehorn 412224014Snwhitehorn obj = dlg_allocate_gauge(title, 413224014Snwhitehorn cprompt, 414224014Snwhitehorn height, 415224014Snwhitehorn width, 416224014Snwhitehorn oldobj->percent); 417224014Snwhitehorn 418224014Snwhitehorn /* avoid breaking new window in dlg_remove_callback */ 419224014Snwhitehorn oldobj->obj.caller = 0; 420224014Snwhitehorn oldobj->obj.input = 0; 421224014Snwhitehorn oldobj->obj.keep_win = FALSE; 422224014Snwhitehorn 423224014Snwhitehorn /* remove the old version of the gauge */ 424217309Snwhitehorn dlg_clear(); 425224014Snwhitehorn dlg_remove_callback(&(oldobj->obj)); 426217309Snwhitehorn refresh(); 427224014Snwhitehorn 428224014Snwhitehorn dlg_add_callback_ref((DIALOG_CALLBACK **) & obj, my_cleanup); 429224014Snwhitehorn dlg_update_gauge(obj, obj->percent); 430217309Snwhitehorn } 431217309Snwhitehorn#endif 432217309Snwhitehorn } 433224014Snwhitehorn while (valid(obj) && handle_my_getc(&(obj->obj), ch, fkey, &result)); 434217309Snwhitehorn 435224014Snwhitehorn dlg_free_gauge(obj); 436217309Snwhitehorn 437217309Snwhitehorn return (DLG_EXIT_OK); 438217309Snwhitehorn} 439