1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2021-2023 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 GET_COLOR(bg, fg) (COLOR_PAIR(bg * 8 + fg +1))
35 #define WHITE GET_COLOR(COLOR_WHITE, COLOR_BLACK)
36 #define BLACK GET_COLOR(COLOR_WHITE, COLOR_BLACK) | A_REVERSE
37 #define NFLAGS 6
38
39 struct bsddialog_theme t;
40 bool hastermcolors;
41
42 struct flag_converter {
43 unsigned int public;
44 unsigned int private;
45 };
46
47 static struct flag_converter flagconv[NFLAGS] = {
48 {BSDDIALOG_BLINK, A_BLINK},
49 {BSDDIALOG_BOLD, A_BOLD},
50 {BSDDIALOG_HALFBRIGHT, A_DIM},
51 {BSDDIALOG_HIGHLIGHT, A_STANDOUT},
52 {BSDDIALOG_REVERSE, A_REVERSE},
53 {BSDDIALOG_UNDERLINE, A_UNDERLINE}
54 };
55
56 static struct bsddialog_theme blackwhite = {
57 .screen.color = WHITE,
58
59 .shadow.color = GET_COLOR(COLOR_BLACK, COLOR_BLACK),
60 .shadow.y = 1,
61 .shadow.x = 2,
62
63 .dialog.delimtitle = true,
64 .dialog.titlecolor = WHITE,
65 .dialog.lineraisecolor = WHITE,
66 .dialog.linelowercolor = WHITE,
67 .dialog.color = WHITE,
68 .dialog.bottomtitlecolor = WHITE,
69 .dialog.arrowcolor = WHITE,
70
71 .menu.f_prefixcolor = WHITE,
72 .menu.prefixcolor = WHITE,
73 .menu.f_selectorcolor = BLACK,
74 .menu.selectorcolor = WHITE,
75 .menu.f_desccolor = BLACK,
76 .menu.desccolor = WHITE,
77 .menu.f_namecolor = BLACK,
78 .menu.namecolor = WHITE,
79 .menu.f_shortcutcolor = BLACK | A_UNDERLINE,
80 .menu.shortcutcolor = WHITE | A_UNDERLINE,
81 .menu.bottomdesccolor = WHITE,
82 .menu.sepnamecolor = WHITE,
83 .menu.sepdesccolor = WHITE,
84
85 .form.f_fieldcolor = BLACK,
86 .form.fieldcolor = WHITE,
87 .form.readonlycolor = WHITE,
88 .form.bottomdesccolor = WHITE,
89
90 .bar.f_color = BLACK,
91 .bar.color = WHITE,
92
93 .button.minmargin = 1,
94 .button.maxmargin = 5,
95 .button.leftdelim = '[',
96 .button.rightdelim = ']',
97 .button.f_delimcolor = WHITE,
98 .button.delimcolor = WHITE,
99 .button.f_color = BLACK,
100 .button.color = WHITE,
101 .button.f_shortcutcolor = BLACK | A_UNDERLINE | A_BOLD,
102 .button.shortcutcolor = WHITE | A_UNDERLINE | A_BOLD
103 };
104
105 static struct bsddialog_theme flat = {
106 .screen.color = GET_COLOR(COLOR_CYAN, COLOR_BLUE) | A_BOLD,
107
108 .shadow.color = GET_COLOR(COLOR_BLACK, COLOR_BLACK),
109 .shadow.y = 1,
110 .shadow.x = 2,
111
112 .dialog.delimtitle = true,
113 .dialog.titlecolor = GET_COLOR(COLOR_BLUE, COLOR_WHITE) | A_BOLD,
114 .dialog.lineraisecolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
115 .dialog.linelowercolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
116 .dialog.color = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
117 .dialog.bottomtitlecolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE) | A_BOLD,
118 .dialog.arrowcolor = GET_COLOR(COLOR_BLUE, COLOR_WHITE),
119
120 .menu.f_prefixcolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
121 .menu.prefixcolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
122 .menu.f_selectorcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
123 .menu.selectorcolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
124 .menu.f_desccolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
125 .menu.desccolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
126 .menu.f_namecolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
127 .menu.namecolor = GET_COLOR(COLOR_BLUE, COLOR_WHITE),
128 .menu.f_shortcutcolor = GET_COLOR(COLOR_RED, COLOR_BLUE),
129 .menu.shortcutcolor = GET_COLOR(COLOR_RED, COLOR_WHITE),
130 .menu.bottomdesccolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
131 .menu.sepnamecolor = GET_COLOR(COLOR_RED, COLOR_WHITE),
132 .menu.sepdesccolor = GET_COLOR(COLOR_RED, COLOR_WHITE),
133
134 .form.f_fieldcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE) | A_BOLD,
135 .form.fieldcolor = GET_COLOR(COLOR_WHITE, COLOR_CYAN) | A_BOLD,
136 .form.readonlycolor = GET_COLOR(COLOR_CYAN, COLOR_WHITE)| A_BOLD,
137 .form.bottomdesccolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
138
139 .bar.f_color = GET_COLOR(COLOR_WHITE, COLOR_BLUE) | A_BOLD,
140 .bar.color = GET_COLOR(COLOR_BLUE, COLOR_WHITE) | A_BOLD,
141
142 .button.minmargin = 1,
143 .button.maxmargin = 5,
144 .button.leftdelim = '[',
145 .button.rightdelim = ']',
146 .button.f_delimcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE) | A_BOLD,
147 .button.delimcolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
148 .button.f_color = GET_COLOR(COLOR_YELLOW, COLOR_BLUE) | A_BOLD,
149 .button.color = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
150 .button.f_shortcutcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE) | A_BOLD,
151 .button.shortcutcolor = GET_COLOR(COLOR_RED, COLOR_WHITE) | A_BOLD
152 };
153
154 static void
set_theme(struct bsddialog_theme * dst,struct bsddialog_theme * src)155 set_theme(struct bsddialog_theme *dst, struct bsddialog_theme *src)
156 {
157 dst->screen.color = src->screen.color;
158
159 dst->shadow.color = src->shadow.color;
160 dst->shadow.y = src->shadow.y;
161 dst->shadow.x = src->shadow.x;
162
163 dst->dialog.delimtitle = src->dialog.delimtitle;
164 dst->dialog.titlecolor = src->dialog.titlecolor;
165 dst->dialog.lineraisecolor = src->dialog.lineraisecolor;
166 dst->dialog.linelowercolor = src->dialog.linelowercolor;
167 dst->dialog.color = src->dialog.color;
168 dst->dialog.bottomtitlecolor = src->dialog.bottomtitlecolor;
169 dst->dialog.arrowcolor = src->dialog.arrowcolor;
170
171 dst->menu.f_prefixcolor = src->menu.f_prefixcolor;
172 dst->menu.prefixcolor = src->menu.prefixcolor;
173 dst->menu.f_selectorcolor = src->menu.f_selectorcolor;
174 dst->menu.selectorcolor = src->menu.selectorcolor;
175 dst->menu.f_desccolor = src->menu.f_desccolor;
176 dst->menu.desccolor = src->menu.desccolor;
177 dst->menu.f_namecolor = src->menu.f_namecolor;
178 dst->menu.namecolor = src->menu.namecolor;
179 dst->menu.f_shortcutcolor = src->menu.f_shortcutcolor;
180 dst->menu.shortcutcolor = src->menu.shortcutcolor;
181 dst->menu.bottomdesccolor = src->menu.bottomdesccolor;
182 dst->menu.sepnamecolor = src->menu.sepnamecolor;
183 dst->menu.sepdesccolor = src->menu.sepdesccolor;
184
185 dst->form.f_fieldcolor = src->form.f_fieldcolor;
186 dst->form.fieldcolor = src->form.fieldcolor;
187 dst->form.readonlycolor = src->form.readonlycolor;
188 dst->form.bottomdesccolor = src->form.bottomdesccolor;
189
190 dst->bar.f_color = src->bar.f_color;
191 dst->bar.color = src->bar.color;
192
193 dst->button.minmargin = src->button.minmargin;
194 dst->button.maxmargin = src->button.maxmargin;
195 dst->button.leftdelim = src->button.leftdelim;
196 dst->button.rightdelim = src->button.rightdelim;
197 dst->button.f_delimcolor = src->button.f_delimcolor;
198 dst->button.delimcolor = src->button.delimcolor;
199 dst->button.f_color = src->button.f_color;
200 dst->button.color = src->button.color;
201 dst->button.f_shortcutcolor = src->button.f_shortcutcolor;
202 dst->button.shortcutcolor = src->button.shortcutcolor;
203
204 bkgd(dst->screen.color);
205 }
206
207 /* API */
bsddialog_get_theme(struct bsddialog_theme * theme)208 int bsddialog_get_theme(struct bsddialog_theme *theme)
209 {
210 CHECK_PTR(theme);
211 set_theme(theme, &t);
212
213 return (BSDDIALOG_OK);
214 }
215
bsddialog_set_theme(struct bsddialog_theme * theme)216 int bsddialog_set_theme(struct bsddialog_theme *theme)
217 {
218 CHECK_PTR(theme);
219 set_theme(&t, theme);
220 refresh();
221
222 return (BSDDIALOG_OK);
223 }
224
bsddialog_set_default_theme(enum bsddialog_default_theme newtheme)225 int bsddialog_set_default_theme(enum bsddialog_default_theme newtheme)
226 {
227 if (newtheme == BSDDIALOG_THEME_3D) {
228 set_theme(&t, &flat);
229 t.dialog.lineraisecolor =
230 GET_COLOR(COLOR_WHITE, COLOR_WHITE) | A_BOLD;
231 t.dialog.delimtitle = false;
232 t.dialog.bottomtitlecolor = t.dialog.bottomtitlecolor | A_BOLD;
233 } else if (newtheme == BSDDIALOG_THEME_BLACKWHITE) {
234 set_theme(&t, &blackwhite);
235 } else if (newtheme == BSDDIALOG_THEME_FLAT) {
236 set_theme(&t, &flat);
237 } else {
238 RETURN_FMTERROR("Unknown default theme (%d), "
239 "to use enum bsddialog_default_theme",
240 newtheme);
241 }
242 refresh();
243
244 return (BSDDIALOG_OK);
245 }
246
247 int
bsddialog_color(enum bsddialog_color foreground,enum bsddialog_color background,unsigned int flags)248 bsddialog_color(enum bsddialog_color foreground,
249 enum bsddialog_color background, unsigned int flags)
250 {
251 unsigned int i, f;
252
253 f = 0;
254 for (i=0; i < NFLAGS; i++)
255 if (flags & flagconv[i].public)
256 f |= flagconv[i].private;
257
258 return (GET_COLOR(foreground, background) | f);
259 }
260
261 int
bsddialog_color_attrs(int color,enum bsddialog_color * foreground,enum bsddialog_color * background,unsigned int * flags)262 bsddialog_color_attrs(int color, enum bsddialog_color *foreground,
263 enum bsddialog_color *background, unsigned int *flags)
264 {
265 short fg, bg;
266 unsigned int i, f;
267
268 if (flags != NULL) {
269 f = 0;
270 for (i=0; i < NFLAGS; i++)
271 if (color & flagconv[i].private)
272 f |= flagconv[i].public;
273 *flags = f;
274 }
275 if (pair_content(PAIR_NUMBER(color), &fg, &bg) != OK)
276 RETURN_ERROR("Cannot get color attributes");
277 if (foreground != NULL)
278 *foreground = fg;
279 if (background != NULL)
280 *background = bg;
281
282 return (BSDDIALOG_OK);
283 }
284
bsddialog_hascolors(void)285 bool bsddialog_hascolors(void)
286 {
287 return (hastermcolors);
288 }
289