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