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