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
drawsquare(struct bsddialog_conf * conf,WINDOW * win,unsigned int value,bool focus)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
timebox_redraw(struct dialog * d,struct clock * c)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
bsddialog_timebox(struct bsddialog_conf * conf,const char * text,int rows,int cols,unsigned int * hh,unsigned int * mm,unsigned int * ss)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