1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2021 Alfonso Sabato Siciliano 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <stdlib.h> 29 #include <string.h> 30 31 #ifdef PORTNCURSES 32 #include <ncurses/curses.h> 33 #else 34 #include <curses.h> 35 #endif 36 37 #include "bsddialog.h" 38 #include "lib_util.h" 39 #include "bsddialog_theme.h" 40 41 /* "Bar": gauge - mixedgauge - rangebox - pause */ 42 43 extern struct bsddialog_theme t; 44 45 static void 46 draw_perc_bar(WINDOW *win, int y, int x, int size, int perc, bool withlabel, int label) 47 { 48 char labelstr[128]; 49 int i, blue_x, color; 50 51 blue_x = (int)((perc*(size))/100); 52 53 wmove(win, y, x); 54 for (i = 0; i < size; i++) { 55 color = (i <= blue_x) ? t.currbarcolor : t.barcolor; 56 wattron(win, color); 57 waddch(win, ' '); 58 wattroff(win, color); 59 } 60 61 if (withlabel) 62 sprintf(labelstr, "%d", label); 63 else 64 sprintf(labelstr, "%3d%%", perc); 65 wmove(win, y, x + size/2 - 2); 66 for (i=0; i < (int) strlen(labelstr); i++) { 67 color = ( (blue_x + 1) <= (size/2 - (int) strlen(labelstr)/2 + i) ) ? 68 t.barcolor : t.currbarcolor; 69 wattron(win, color); 70 waddch(win, labelstr[i]); 71 wattroff(win, color); 72 } 73 } 74 75 int bsddialog_gauge(struct bsddialog_conf conf, char* text, int rows, int cols, int perc) 76 { 77 WINDOW *widget, *bar, *shadow; 78 char input[2048]; 79 int i, y, x; 80 bool mainloop = true; 81 82 if (new_widget(conf, &widget, &y, &x, text, &rows, &cols, &shadow, 83 false) <0) 84 return -1; 85 86 bar = new_boxed_window(conf, y+rows -4, x+3, 3, cols-6, RAISED); 87 88 wrefresh(widget); 89 wrefresh(bar); 90 91 while (mainloop) { 92 draw_perc_bar(bar, 1, 1, cols-8, perc, false, -1 /*unused*/); 93 94 wrefresh(widget); 95 wrefresh(bar); 96 97 while (true) { 98 scanf("%s", input); 99 if (strcmp(input,"EOF") == 0) { 100 mainloop = false; 101 break; 102 } 103 if (strcmp(input,"XXX") == 0) 104 break; 105 } 106 scanf("%d", &perc); 107 perc = perc < 0 ? 0 : perc; 108 perc = perc > 100 ? 100 : perc; 109 i = 2; 110 wmove(widget, 1, 1); 111 wclrtoeol(widget); 112 while (true) { 113 scanf("%s", input); 114 if (strcmp(input,"EOF") == 0) { 115 mainloop = false; 116 break; 117 } 118 if (strcmp(input,"XXX") == 0) 119 break; 120 //print_text(conf, widget, 1, 1, cols-2, input); 121 mvwaddstr(widget, 1, i, input); 122 i = i + strlen(input) + 1; 123 wrefresh(widget); 124 } 125 } 126 127 delwin(bar); 128 end_widget(conf, widget, rows, cols, shadow); 129 130 return BSDDIALOG_YESOK; 131 } 132 133 int bsddialog_mixedgauge(struct bsddialog_conf conf, char* text, int rows, int cols, 134 unsigned int perc, int argc, char **argv) 135 { 136 WINDOW *widget, *bar, *shadow; 137 int i, miniperc, y, x; 138 char states[11][16] = { 139 "[ Succeeded ]", 140 "[ Failed ]", 141 "[ Passed ]", 142 "[ Completed ]", 143 "[ Checked ]", 144 "[ Done ]", 145 "[ Skipped ]", 146 "[ In Progress ]", 147 "!!! BLANK !!!", 148 "[ N/A ]", 149 "[ UNKNOWN ]",}; 150 151 if (new_widget(conf, &widget, &y, &x, NULL, &rows, &cols, &shadow, 152 false) <0) 153 return -1; 154 155 bar = new_boxed_window(conf, y+rows -4, x+3, 3, cols-6, RAISED); 156 157 /* mini bars */ 158 for (i=0; i < (argc/2); i++) { 159 miniperc = atol(argv[i*2 + 1]); 160 if (miniperc == 8) 161 continue; 162 mvwaddstr(widget, i+1, 2, argv[i*2]); 163 if (miniperc > 9) 164 mvwaddstr(widget, i+1, cols-2-15, states[10]); 165 else if (miniperc >= 0 && miniperc <= 9) 166 mvwaddstr(widget, i+1, cols-2-15, states[miniperc]); 167 else { //miniperc < 0 168 miniperc = abs(miniperc); 169 mvwaddstr(widget, i+1, cols-2-15, "[ ]"); 170 draw_perc_bar(widget, i+1, 1+cols-2-15, 13, miniperc, 171 false, -1 /*unused*/); 172 } 173 } 174 175 print_text(conf, widget, rows-6, 2, cols-2, text); 176 177 /* main bar */ 178 draw_perc_bar(bar, 1, 1, cols-8, perc, false, -1 /*unused*/); 179 180 wattron(bar, t.barcolor); 181 mvwaddstr(bar, 0, 2, "Overall Progress"); 182 wattroff(bar, t.barcolor); 183 184 wrefresh(widget); 185 wrefresh(bar); 186 187 getch(); 188 189 delwin(bar); 190 end_widget(conf, widget, rows, cols, shadow); 191 192 return BSDDIALOG_YESOK; 193 } 194 195 int 196 bsddialog_rangebox(struct bsddialog_conf conf, char* text, int rows, int cols, int min, 197 int max, int *value) 198 { 199 WINDOW *widget, *bar, *shadow; 200 int y, x; 201 bool loop, buttupdate, barupdate; 202 int input, currvalue, output, sizebar; 203 float perc; 204 int positions = max - min + 1; 205 struct buttons bs; 206 207 if (new_widget(conf, &widget, &y, &x, text, &rows, &cols, &shadow, 208 true) <0) 209 return -1; 210 211 bar = new_boxed_window(conf, y + rows - 6, x +7, 3, cols-14, RAISED); 212 213 get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label), 214 BUTTONLABEL(cancel_label), BUTTONLABEL(help_label)); 215 216 if (value == NULL) 217 RETURN_ERROR("*value == NULL"); 218 219 currvalue = *value; 220 sizebar = cols - 16; 221 loop = buttupdate = barupdate = true; 222 while(loop) { 223 if (barupdate) { 224 perc = ((float)(currvalue - min)*100) / ((float)positions-1); 225 draw_perc_bar(bar, 1, 1, sizebar, perc, true, currvalue); 226 barupdate = false; 227 wrefresh(bar); 228 } 229 230 if (buttupdate) { 231 draw_buttons(widget, rows-2, cols, bs, true); 232 wrefresh(widget); 233 buttupdate = false; 234 } 235 236 input = getch(); 237 switch(input) { 238 case 10: // Enter 239 output = bs.value[bs.curr]; // values -> outputs 240 *value = currvalue; 241 loop = false; 242 break; 243 case 27: /* Esc */ 244 output = BSDDIALOG_ESC; 245 loop = false; 246 break; 247 case '\t': // TAB 248 bs.curr = (bs.curr + 1) % bs.nbuttons; 249 buttupdate = true; 250 break; 251 case KEY_LEFT: 252 if (bs.curr > 0) { 253 bs.curr--; 254 buttupdate = true; 255 } 256 break; 257 case KEY_RIGHT: 258 if (bs.curr < (int) bs.nbuttons - 1) { 259 bs.curr++; 260 buttupdate = true; 261 } 262 break; 263 case KEY_UP: 264 if (currvalue < max) { 265 currvalue++; 266 barupdate = true; 267 } 268 break; 269 case KEY_DOWN: 270 if (currvalue > min) { 271 currvalue--; 272 barupdate = true; 273 } 274 break; 275 } 276 } 277 278 delwin(bar); 279 end_widget(conf, widget, rows, cols, shadow); 280 281 return output; 282 } 283 284 int bsddialog_pause(struct bsddialog_conf conf, char* text, int rows, int cols, int sec) 285 { 286 WINDOW *widget, *bar, *shadow; 287 int output, y, x; 288 bool loop, buttupdate, barupdate; 289 int input, currvalue, sizebar; 290 float perc; 291 struct buttons bs; 292 293 if (new_widget(conf, &widget, &y, &x, text, &rows, &cols, &shadow, 294 true) <0) 295 return -1; 296 297 bar = new_boxed_window(conf, y + rows - 6, x +7, 3, cols-14, RAISED); 298 299 get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label), 300 BUTTONLABEL(cancel_label), BUTTONLABEL(help_label)); 301 302 currvalue = sec; 303 sizebar = cols-16; 304 nodelay(stdscr, TRUE); 305 timeout(1000); 306 //wtimeout(buttwin, 2); 307 loop = buttupdate = barupdate = true; 308 while(loop) { 309 if (barupdate) { 310 perc = ((float)(currvalue*100)) / ((float)sec); 311 draw_perc_bar(bar, 1, 1, sizebar, perc, true, currvalue); 312 barupdate = false; 313 wrefresh(bar); 314 } 315 316 if (buttupdate) { 317 draw_buttons(widget, rows-2, cols, bs, true); 318 wrefresh(widget); 319 buttupdate = false; 320 } 321 322 input = getch(); 323 if(input < 0) { 324 currvalue--; 325 if (currvalue < 0) { 326 output = BSDDIALOG_ERROR; 327 break; 328 } 329 else { 330 barupdate = true; 331 continue; 332 } 333 } 334 switch(input) { 335 case 10: // Enter 336 output = bs.value[bs.curr]; // values -> outputs 337 loop = false; 338 break; 339 case 27: /* Esc */ 340 output = BSDDIALOG_ESC; 341 loop = false; 342 break; 343 case '\t': // TAB 344 bs.curr = (bs.curr + 1) % bs.nbuttons; 345 buttupdate = true; 346 break; 347 case KEY_LEFT: 348 if (bs.curr > 0) { 349 bs.curr--; 350 buttupdate = true; 351 } 352 break; 353 case KEY_RIGHT: 354 if (bs.curr < (int) bs.nbuttons - 1) { 355 bs.curr++; 356 buttupdate = true; 357 } 358 break; 359 } 360 } 361 362 nodelay(stdscr, FALSE); 363 364 delwin(bar); 365 end_widget(conf, widget, rows, cols, shadow); 366 367 return output; 368 } 369 370