1217309Snwhitehorn/* 2224014Snwhitehorn * $Id: guage.c,v 1.60 2011/06/27 00:52:28 tom Exp $ 3217309Snwhitehorn * 4220749Snwhitehorn * guage.c -- implements the gauge dialog 5217309Snwhitehorn * 6220749Snwhitehorn * Copyright 2000-2010,2011 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; 42217309Snwhitehorn const 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)); 97217309Snwhitehorn dlg_trim_string(buffer); 98217309Snwhitehorn result = 1; 99217309Snwhitehorn } else { 100217309Snwhitehorn result = -1; 101217309Snwhitehorn } 102217309Snwhitehorn return result; 103217309Snwhitehorn} 104217309Snwhitehorn 105217309Snwhitehornstatic int 106217309Snwhitehorndecode_percent(char *buffer) 107217309Snwhitehorn{ 108217309Snwhitehorn char *tmp = 0; 109217309Snwhitehorn long value = strtol(buffer, &tmp, 10); 110217309Snwhitehorn 111217309Snwhitehorn if (tmp != 0 && (*tmp == 0 || isspace(UCH(*tmp))) && value >= 0) { 112217309Snwhitehorn return TRUE; 113217309Snwhitehorn } 114217309Snwhitehorn return FALSE; 115217309Snwhitehorn} 116217309Snwhitehorn 117217309Snwhitehornstatic void 118217309Snwhitehornrepaint_text(MY_OBJ * obj) 119217309Snwhitehorn{ 120217309Snwhitehorn WINDOW *dialog = obj->obj.win; 121217309Snwhitehorn int i, x; 122217309Snwhitehorn 123220749Snwhitehorn if (dialog != 0 && obj->obj.input != 0) { 124220749Snwhitehorn (void) werase(dialog); 125220749Snwhitehorn dlg_draw_box(dialog, 0, 0, obj->height, obj->width, dialog_attr, border_attr); 126217309Snwhitehorn 127220749Snwhitehorn dlg_draw_title(dialog, obj->title); 128217309Snwhitehorn 129220749Snwhitehorn wattrset(dialog, dialog_attr); 130224014Snwhitehorn dlg_draw_helpline(dialog, FALSE); 131220749Snwhitehorn dlg_print_autowrap(dialog, obj->prompt, obj->height, obj->width); 132217309Snwhitehorn 133220749Snwhitehorn dlg_draw_box(dialog, 134220749Snwhitehorn obj->height - 4, 2 + MARGIN, 135220749Snwhitehorn 2 + MARGIN, obj->width - 2 * (2 + MARGIN), 136220749Snwhitehorn dialog_attr, 137220749Snwhitehorn border_attr); 138217309Snwhitehorn 139220749Snwhitehorn /* 140220749Snwhitehorn * Clear the area for the progress bar by filling it with spaces 141220749Snwhitehorn * in the title-attribute, and write the percentage with that 142220749Snwhitehorn * attribute. 143220749Snwhitehorn */ 144220749Snwhitehorn (void) wmove(dialog, obj->height - 3, 4); 145220749Snwhitehorn wattrset(dialog, gauge_attr); 146217309Snwhitehorn 147220749Snwhitehorn for (i = 0; i < (obj->width - 2 * (3 + MARGIN)); i++) 148220749Snwhitehorn (void) waddch(dialog, ' '); 149217309Snwhitehorn 150220749Snwhitehorn (void) wmove(dialog, obj->height - 3, (obj->width / 2) - 2); 151220749Snwhitehorn (void) wprintw(dialog, "%3d%%", obj->percent); 152217309Snwhitehorn 153220749Snwhitehorn /* 154220749Snwhitehorn * Now draw a bar in reverse, relative to the background. 155220749Snwhitehorn * The window attribute was useful for painting the background, 156220749Snwhitehorn * but requires some tweaks to reverse it. 157220749Snwhitehorn */ 158220749Snwhitehorn x = (obj->percent * (obj->width - 2 * (3 + MARGIN))) / 100; 159220749Snwhitehorn if ((title_attr & A_REVERSE) != 0) { 160220749Snwhitehorn wattroff(dialog, A_REVERSE); 161220749Snwhitehorn } else { 162220749Snwhitehorn wattrset(dialog, A_REVERSE); 163217309Snwhitehorn } 164220749Snwhitehorn (void) wmove(dialog, obj->height - 3, 4); 165220749Snwhitehorn for (i = 0; i < x; i++) { 166220749Snwhitehorn chtype ch2 = winch(dialog); 167220749Snwhitehorn if (title_attr & A_REVERSE) { 168220749Snwhitehorn ch2 &= ~A_REVERSE; 169220749Snwhitehorn } 170220749Snwhitehorn (void) waddch(dialog, ch2); 171220749Snwhitehorn } 172220749Snwhitehorn 173220749Snwhitehorn (void) wrefresh(dialog); 174217309Snwhitehorn } 175217309Snwhitehorn} 176217309Snwhitehorn 177220749Snwhitehornstatic bool 178220749Snwhitehornhandle_input(DIALOG_CALLBACK * cb) 179217309Snwhitehorn{ 180220749Snwhitehorn MY_OBJ *obj = (MY_OBJ *) cb; 181220749Snwhitehorn bool result; 182217309Snwhitehorn int status; 183217309Snwhitehorn char buf[MY_LEN]; 184217309Snwhitehorn 185220749Snwhitehorn if (dialog_state.pipe_input == 0) { 186220749Snwhitehorn status = -1; 187220749Snwhitehorn } else if ((status = read_data(buf, dialog_state.pipe_input)) > 0) { 188217309Snwhitehorn 189217309Snwhitehorn if (isMarker(buf)) { 190217309Snwhitehorn /* 191217309Snwhitehorn * Historically, next line should be percentage, but one of the 192217309Snwhitehorn * worse-written clones of 'dialog' assumes the number is missing. 193217309Snwhitehorn * (Gresham's Law applied to software). 194217309Snwhitehorn */ 195217309Snwhitehorn if ((status = read_data(buf, dialog_state.pipe_input)) > 0) { 196217309Snwhitehorn 197217309Snwhitehorn obj->prompt_buf[0] = '\0'; 198217309Snwhitehorn if (decode_percent(buf)) 199217309Snwhitehorn obj->percent = atoi(buf); 200217309Snwhitehorn else 201217309Snwhitehorn strcpy(obj->prompt_buf, buf); 202217309Snwhitehorn 203217309Snwhitehorn /* Rest is message text */ 204217309Snwhitehorn while ((status = read_data(buf, dialog_state.pipe_input)) > 0 205217309Snwhitehorn && !isMarker(buf)) { 206217309Snwhitehorn if (strlen(obj->prompt_buf) + strlen(buf) < 207217309Snwhitehorn sizeof(obj->prompt_buf) - 1) { 208217309Snwhitehorn strcat(obj->prompt_buf, buf); 209217309Snwhitehorn } 210217309Snwhitehorn } 211217309Snwhitehorn 212217309Snwhitehorn if (obj->prompt != obj->prompt_buf) 213217309Snwhitehorn free(obj->prompt); 214217309Snwhitehorn obj->prompt = obj->prompt_buf; 215217309Snwhitehorn } 216217309Snwhitehorn } else if (decode_percent(buf)) { 217217309Snwhitehorn obj->percent = atoi(buf); 218217309Snwhitehorn } 219217309Snwhitehorn } else { 220220749Snwhitehorn if (feof(dialog_state.pipe_input) || 221220749Snwhitehorn (ferror(dialog_state.pipe_input) && errno != EINTR)) { 222224014Snwhitehorn delink(obj); 223220749Snwhitehorn dlg_remove_callback(cb); 224220749Snwhitehorn } 225217309Snwhitehorn } 226217309Snwhitehorn 227220749Snwhitehorn if (status > 0) { 228220749Snwhitehorn result = TRUE; 229220749Snwhitehorn repaint_text(obj); 230220749Snwhitehorn } else { 231220749Snwhitehorn result = FALSE; 232220749Snwhitehorn } 233220749Snwhitehorn 234220749Snwhitehorn return result; 235217309Snwhitehorn} 236217309Snwhitehorn 237217309Snwhitehornstatic bool 238217309Snwhitehornhandle_my_getc(DIALOG_CALLBACK * cb, int ch, int fkey, int *result) 239217309Snwhitehorn{ 240217309Snwhitehorn int status = TRUE; 241217309Snwhitehorn 242217309Snwhitehorn *result = DLG_EXIT_OK; 243220749Snwhitehorn if (cb != 0) { 244217309Snwhitehorn if (!fkey && (ch == ERR)) { 245220749Snwhitehorn (void) handle_input(cb); 246224014Snwhitehorn /* cb might be freed in handle_input */ 247224014Snwhitehorn status = (valid((MY_OBJ *) cb) && (cb->input != 0)); 248217309Snwhitehorn } 249217309Snwhitehorn } else { 250217309Snwhitehorn status = FALSE; 251217309Snwhitehorn } 252217309Snwhitehorn return status; 253217309Snwhitehorn} 254217309Snwhitehorn 255217309Snwhitehornstatic void 256217309Snwhitehornmy_cleanup(DIALOG_CALLBACK * cb) 257217309Snwhitehorn{ 258217309Snwhitehorn MY_OBJ *obj = (MY_OBJ *) cb; 259217309Snwhitehorn 260224014Snwhitehorn if (valid(obj)) { 261224014Snwhitehorn if (obj->prompt != obj->prompt_buf) { 262217309Snwhitehorn free(obj->prompt); 263224014Snwhitehorn obj->prompt = obj->prompt_buf; 264224014Snwhitehorn } 265224014Snwhitehorn delink(obj); 266217309Snwhitehorn } 267217309Snwhitehorn} 268217309Snwhitehorn 269224014Snwhitehornvoid 270224014Snwhitehorndlg_update_gauge(void *objptr, int percent) 271224014Snwhitehorn{ 272224014Snwhitehorn MY_OBJ *obj = (MY_OBJ *) objptr; 273224014Snwhitehorn 274224014Snwhitehorn curs_set(0); 275224014Snwhitehorn obj->percent = percent; 276224014Snwhitehorn repaint_text(obj); 277224014Snwhitehorn} 278224014Snwhitehorn 279217309Snwhitehorn/* 280224014Snwhitehorn * Allocates a new object and fills it as per the arguments 281217309Snwhitehorn */ 282224014Snwhitehornvoid * 283224014Snwhitehorndlg_allocate_gauge(const char *title, 284224014Snwhitehorn const char *cprompt, 285224014Snwhitehorn int height, 286224014Snwhitehorn int width, 287224014Snwhitehorn int percent) 288217309Snwhitehorn{ 289217309Snwhitehorn int x, y; 290217309Snwhitehorn char *prompt = dlg_strclone(cprompt); 291217309Snwhitehorn WINDOW *dialog; 292217309Snwhitehorn MY_OBJ *obj = 0; 293217309Snwhitehorn 294217309Snwhitehorn dlg_tab_correct_str(prompt); 295217309Snwhitehorn 296217309Snwhitehorn dlg_auto_size(title, prompt, &height, &width, MIN_HIGH, MIN_WIDE); 297217309Snwhitehorn dlg_print_size(height, width); 298217309Snwhitehorn dlg_ctl_size(height, width); 299217309Snwhitehorn 300217309Snwhitehorn /* center dialog box on screen */ 301217309Snwhitehorn x = dlg_box_x_ordinate(width); 302217309Snwhitehorn y = dlg_box_y_ordinate(height); 303217309Snwhitehorn 304217309Snwhitehorn dialog = dlg_new_window(height, width, y, x); 305217309Snwhitehorn 306224014Snwhitehorn obj = dlg_calloc(MY_OBJ, 1); 307224014Snwhitehorn assert_ptr(obj, "dialog_gauge"); 308217309Snwhitehorn 309224014Snwhitehorn obj->obj.input = dialog_state.pipe_input; 310224014Snwhitehorn obj->obj.win = dialog; 311224014Snwhitehorn obj->obj.keep_win = TRUE; 312224014Snwhitehorn obj->obj.bg_task = TRUE; 313224014Snwhitehorn obj->obj.handle_getc = handle_my_getc; 314224014Snwhitehorn obj->obj.handle_input = handle_input; 315217309Snwhitehorn 316224014Snwhitehorn obj->title = title; 317224014Snwhitehorn obj->prompt = prompt; 318224014Snwhitehorn obj->percent = percent; 319224014Snwhitehorn obj->height = height; 320224014Snwhitehorn obj->width = width; 321224014Snwhitehorn 322224014Snwhitehorn obj->next = all_objects; 323224014Snwhitehorn all_objects = obj; 324224014Snwhitehorn 325224014Snwhitehorn return (void *) obj; 326224014Snwhitehorn} 327224014Snwhitehorn 328224014Snwhitehornvoid 329224014Snwhitehorndlg_free_gauge(void *objptr) 330224014Snwhitehorn{ 331224014Snwhitehorn MY_OBJ *obj = (MY_OBJ *) objptr; 332224014Snwhitehorn 333224014Snwhitehorn curs_set(1); 334224014Snwhitehorn if (valid(obj)) { 335224014Snwhitehorn delink(obj); 336224014Snwhitehorn obj->obj.keep_win = FALSE; 337224014Snwhitehorn dlg_remove_callback(&(obj->obj)); 338224014Snwhitehorn free(obj); 339217309Snwhitehorn } 340224014Snwhitehorn} 341217309Snwhitehorn 342224014Snwhitehorn/* 343224014Snwhitehorn * Display a gauge, or progress meter. Starts at percent% and reads stdin. If 344224014Snwhitehorn * stdin is not XXX, then it is interpreted as a percentage, and the display is 345224014Snwhitehorn * updated accordingly. Otherwise the next line is the percentage, and 346224014Snwhitehorn * subsequent lines up to another XXX are used for the new prompt. Note that 347224014Snwhitehorn * the size of the window never changes, so the prompt can not get any larger 348224014Snwhitehorn * than the height and width specified. 349224014Snwhitehorn */ 350224014Snwhitehornint 351224014Snwhitehorndialog_gauge(const char *title, 352224014Snwhitehorn const char *cprompt, 353224014Snwhitehorn int height, 354224014Snwhitehorn int width, 355224014Snwhitehorn int percent) 356224014Snwhitehorn{ 357224014Snwhitehorn int fkey; 358224014Snwhitehorn int ch, result; 359224014Snwhitehorn void *objptr = dlg_allocate_gauge(title, cprompt, height, width, percent); 360224014Snwhitehorn MY_OBJ *obj = (MY_OBJ *) objptr; 361217309Snwhitehorn 362224014Snwhitehorn dlg_add_callback_ref((DIALOG_CALLBACK **) & obj, my_cleanup); 363224014Snwhitehorn dlg_update_gauge(obj, percent); 364224014Snwhitehorn 365217309Snwhitehorn do { 366224014Snwhitehorn ch = dlg_getc(obj->obj.win, &fkey); 367217309Snwhitehorn#ifdef KEY_RESIZE 368217309Snwhitehorn if (fkey && ch == KEY_RESIZE) { 369224014Snwhitehorn MY_OBJ *oldobj = obj; 370224014Snwhitehorn 371224014Snwhitehorn dlg_mouse_free_regions(); 372224014Snwhitehorn 373224014Snwhitehorn obj = dlg_allocate_gauge(title, 374224014Snwhitehorn cprompt, 375224014Snwhitehorn height, 376224014Snwhitehorn width, 377224014Snwhitehorn oldobj->percent); 378224014Snwhitehorn 379224014Snwhitehorn /* avoid breaking new window in dlg_remove_callback */ 380224014Snwhitehorn oldobj->obj.caller = 0; 381224014Snwhitehorn oldobj->obj.input = 0; 382224014Snwhitehorn oldobj->obj.keep_win = FALSE; 383224014Snwhitehorn 384224014Snwhitehorn /* remove the old version of the gauge */ 385217309Snwhitehorn dlg_clear(); 386224014Snwhitehorn dlg_remove_callback(&(oldobj->obj)); 387217309Snwhitehorn refresh(); 388224014Snwhitehorn 389224014Snwhitehorn dlg_add_callback_ref((DIALOG_CALLBACK **) & obj, my_cleanup); 390224014Snwhitehorn dlg_update_gauge(obj, obj->percent); 391217309Snwhitehorn } 392217309Snwhitehorn#endif 393217309Snwhitehorn } 394224014Snwhitehorn while (valid(obj) && handle_my_getc(&(obj->obj), ch, fkey, &result)); 395217309Snwhitehorn 396224014Snwhitehorn dlg_free_gauge(obj); 397217309Snwhitehorn 398217309Snwhitehorn return (DLG_EXIT_OK); 399217309Snwhitehorn} 400