xref: /freebsd/contrib/bsddialog/lib/theme.c (revision 3494f7c0)
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
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 */
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 
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 
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
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
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 
285 bool bsddialog_hascolors(void)
286 {
287 	return (hastermcolors);
288 }
289