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