1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2021-2024 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 <curses.h> 29 30 #include "bsddialog.h" 31 #include "bsddialog_theme.h" 32 #include "lib_util.h" 33 34 #define MINWTIME 14 /* 3 windows and their borders */ 35 #define HBOX 3 36 #define WBOX 4 37 38 struct clock { 39 unsigned int max; 40 unsigned int value; 41 WINDOW *win; 42 }; 43 44 static void 45 drawsquare(struct bsddialog_conf *conf, WINDOW *win, unsigned int value, 46 bool focus) 47 { 48 draw_borders(conf, win, LOWERED); 49 if (focus) { 50 wattron(win, t.dialog.arrowcolor); 51 mvwhline(win, 0, 1, UARROW(conf), 2); 52 mvwhline(win, 2, 1, DARROW(conf), 2); 53 wattroff(win, t.dialog.arrowcolor); 54 } 55 56 if (focus) 57 wattron(win, t.menu.f_namecolor); 58 mvwprintw(win, 1, 1, "%02u", value); 59 if (focus) 60 wattroff(win, t.menu.f_namecolor); 61 62 wnoutrefresh(win); 63 } 64 65 static int timebox_redraw(struct dialog *d, struct clock *c) 66 { 67 int y, x; 68 69 if (d->built) { 70 hide_dialog(d); 71 refresh(); /* Important for decreasing screen */ 72 } 73 if (dialog_size_position(d, HBOX, MINWTIME, NULL) != 0) 74 return (BSDDIALOG_ERROR); 75 if (draw_dialog(d) != 0) 76 return (BSDDIALOG_ERROR); 77 if (d->built) 78 refresh(); /* Important to fix grey lines expanding screen */ 79 TEXTPAD(d, HBOX + HBUTTONS); 80 81 y = d->y + d->h - BORDER - HBUTTONS - HBOX; 82 x = d->x + d->w/2 - 7; 83 update_box(d->conf, c[0].win, y, x, HBOX, WBOX, LOWERED); 84 mvwaddch(d->widget, d->h - 5, d->w/2 - 3, ':'); 85 update_box(d->conf, c[1].win, y, x += 5, HBOX, WBOX, LOWERED); 86 mvwaddch(d->widget, d->h - 5, d->w/2 + 2, ':'); 87 update_box(d->conf, c[2].win, y, x + 5, HBOX, WBOX, LOWERED); 88 wnoutrefresh(d->widget); /* for mvwaddch(':') */ 89 90 return (0); 91 } 92 93 /* API */ 94 int 95 bsddialog_timebox(struct bsddialog_conf *conf, const char* text, int rows, 96 int cols, unsigned int *hh, unsigned int *mm, unsigned int *ss) 97 { 98 bool loop, focusbuttons; 99 int i, retval, sel; 100 wint_t input; 101 struct dialog d; 102 struct clock c[3] = { 103 {23, *hh, NULL}, 104 {59, *mm, NULL}, 105 {59, *ss, NULL} 106 }; 107 108 CHECK_PTR(hh); 109 CHECK_PTR(mm); 110 CHECK_PTR(ss); 111 if (prepare_dialog(conf, text, rows, cols, &d) != 0) 112 return (BSDDIALOG_ERROR); 113 set_buttons(&d, true, OK_LABEL, CANCEL_LABEL); 114 for (i=0; i<3; i++) { 115 if ((c[i].win = newwin(1, 1, 1, 1)) == NULL) 116 RETURN_FMTERROR("Cannot build WINDOW for time[%d]", i); 117 wbkgd(c[i].win, t.dialog.color); 118 c[i].value = MIN(c[i].value, c[i].max); 119 } 120 if (timebox_redraw(&d, c) != 0) 121 return (BSDDIALOG_ERROR); 122 123 sel = -1; 124 loop = focusbuttons = true; 125 while (loop) { 126 for (i = 0; i < 3; i++) 127 drawsquare(conf, c[i].win, c[i].value, sel == i); 128 doupdate(); 129 if (get_wch(&input) == ERR) 130 continue; 131 switch(input) { 132 case KEY_ENTER: 133 case 10: /* Enter */ 134 if (focusbuttons || conf->button.always_active) { 135 retval = BUTTONVALUE(d.bs); 136 loop = false; 137 } 138 break; 139 case 27: /* Esc */ 140 if (conf->key.enable_esc) { 141 retval = BSDDIALOG_ESC; 142 loop = false; 143 } 144 break; 145 case '\t': /* TAB */ 146 case KEY_CTRL('n'): 147 case KEY_RIGHT: 148 if (focusbuttons) { 149 d.bs.curr++; 150 focusbuttons = d.bs.curr < (int)d.bs.nbuttons ? 151 true : false; 152 if (focusbuttons == false) { 153 sel = 0; 154 d.bs.curr = 155 conf->button.always_active ? 0 : -1; 156 } 157 } else { 158 sel++; 159 focusbuttons = sel > 2 ? true : false; 160 if (focusbuttons) { 161 d.bs.curr = 0; 162 } 163 } 164 DRAW_BUTTONS(d); 165 break; 166 case KEY_CTRL('p'): 167 case KEY_LEFT: 168 if (focusbuttons) { 169 d.bs.curr--; 170 focusbuttons = d.bs.curr < 0 ? false : true; 171 if (focusbuttons == false) { 172 sel = 2; 173 d.bs.curr = 174 conf->button.always_active ? 0 : -1; 175 } 176 } else { 177 sel--; 178 focusbuttons = sel < 0 ? true : false; 179 if (focusbuttons) 180 d.bs.curr = (int)d.bs.nbuttons - 1; 181 } 182 DRAW_BUTTONS(d); 183 break; 184 case '-': 185 if (focusbuttons == false) 186 c[sel].value = c[sel].value > 0 ? 187 c[sel].value - 1 : c[sel].max; 188 break; 189 case KEY_UP: 190 if (focusbuttons) { 191 sel = 0; 192 focusbuttons = false; 193 d.bs.curr = conf->button.always_active ? 0 : -1; 194 DRAW_BUTTONS(d); 195 } else { 196 c[sel].value = c[sel].value > 0 ? 197 c[sel].value - 1 : c[sel].max; 198 } 199 break; 200 case '+': 201 case KEY_DOWN: 202 if (focusbuttons) 203 break; 204 c[sel].value = c[sel].value < c[sel].max ? 205 c[sel].value + 1 : 0; 206 break; 207 case KEY_F(1): 208 if (conf->key.f1_file == NULL && 209 conf->key.f1_message == NULL) 210 break; 211 if (f1help_dialog(conf) != 0) 212 return (BSDDIALOG_ERROR); 213 if (timebox_redraw(&d, c) != 0) 214 return (BSDDIALOG_ERROR); 215 break; 216 case KEY_CTRL('l'): 217 case KEY_RESIZE: 218 if (timebox_redraw(&d, c) != 0) 219 return (BSDDIALOG_ERROR); 220 break; 221 default: 222 if (shortcut_buttons(input, &d.bs)) { 223 DRAW_BUTTONS(d); 224 doupdate(); 225 retval = BUTTONVALUE(d.bs); 226 loop = false; 227 } 228 } 229 } 230 231 *hh = c[0].value; 232 *mm = c[1].value; 233 *ss = c[2].value; 234 235 for (i = 0; i < 3; i++) 236 delwin(c[i].win); 237 end_dialog(&d); 238 239 return (retval); 240 } 241