diff options
Diffstat (limited to 'util_theme.c')
| -rw-r--r-- | util_theme.c | 356 |
1 files changed, 356 insertions, 0 deletions
diff --git a/util_theme.c b/util_theme.c new file mode 100644 index 000000000000..e003e2c3d05f --- /dev/null +++ b/util_theme.c @@ -0,0 +1,356 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2022 Alfonso Sabato Siciliano + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <bsddialog.h> +#include <bsddialog_theme.h> + +#include "util_theme.h" + +static struct bsddialog_theme t; +static char title[1024]; + +enum typeprop { + BOOL, + CHAR, + INT, + UINT, + COLOR +}; + +struct property { + const char* name; + enum typeprop type; + void *value; +}; + +#define NPROPERTY 38 +static struct property p[NPROPERTY] = { + { "theme.screen.color", COLOR, &t.screen.color }, + + { "theme.shadow.color", COLOR, &t.shadow.color }, + { "theme.shadow.y", UINT, &t.shadow.y }, + { "theme.shadow.x", UINT, &t.shadow.x }, + + { "theme.dialog.color", COLOR, &t.dialog.color }, + { "theme.dialog.delimtitle", BOOL, &t.dialog.delimtitle }, + { "theme.dialog.titlecolor", COLOR, &t.dialog.titlecolor }, + { "theme.dialog.lineraisecolor", COLOR, &t.dialog.lineraisecolor }, + { "theme.dialog.linelowercolor", COLOR, &t.dialog.linelowercolor }, + { "theme.dialog.bottomtitlecolor", COLOR, &t.dialog.bottomtitlecolor }, + { "theme.dialog.arrowcolor", COLOR, &t.dialog.arrowcolor }, + + { "theme.menu.f_selectorcolor", COLOR, &t.menu.f_selectorcolor}, + { "theme.menu.selectorcolor", COLOR, &t.menu.selectorcolor}, + { "theme.menu.f_namecolor", COLOR, &t.menu.f_namecolor}, + { "theme.menu.namecolor", COLOR, &t.menu.namecolor}, + { "theme.menu.f_desccolor", COLOR, &t.menu.f_desccolor}, + { "theme.menu.desccolor", COLOR, &t.menu.desccolor}, + { "theme.menu.namesepcolor", COLOR, &t.menu.namesepcolor}, + { "theme.menu.descsepcolor", COLOR, &t.menu.descsepcolor}, + { "theme.menu.f_shortcutcolor", COLOR, &t.menu.f_shortcutcolor}, + { "theme.menu.shortcutcolor", COLOR, &t.menu.shortcutcolor}, + { "theme.menu.bottomdesccolor", COLOR, &t.menu.bottomdesccolor}, + + { "theme.form.f_fieldcolor", COLOR, &t.form.f_fieldcolor}, + { "theme.form.fieldcolor", COLOR, &t.form.fieldcolor}, + { "theme.form.readonlycolor", COLOR, &t.form.readonlycolor}, + { "theme.form.bottomdesccolor", COLOR, &t.form.bottomdesccolor}, + + { "theme.bar.f_color", COLOR, &t.bar.f_color}, + { "theme.bar.color", COLOR, &t.bar.color}, + + { "theme.button.minmargin", UINT, &t.button.minmargin}, + { "theme.button.maxmargin", UINT, &t.button.maxmargin}, + { "theme.button.leftdelim", CHAR, &t.button.leftdelim}, + { "theme.button.rightdelim", CHAR, &t.button.rightdelim}, + { "theme.button.delimcolor", COLOR, &t.button.delimcolor}, + { "theme.button.f_delimcolor", COLOR, &t.button.f_delimcolor}, + { "theme.button.color", COLOR, &t.button.color}, + { "theme.button.f_color", COLOR, &t.button.f_color}, + { "theme.button.shortcutcolor", COLOR, &t.button.shortcutcolor}, + { "theme.button.f_shortcutcolor", COLOR, &t.button.f_shortcutcolor} +}; + +static char *color[8] = { + "black", + "red", + "green", + "yellow", + "blue", + "magenta", + "cyan", + "white" +}; + +int savetheme(const char *file, char *errbuf, const char *version) +{ + int i; + unsigned int flags; + enum bsddialog_color bg, fg; + time_t clock; + FILE *fp; + + if (bsddialog_get_theme(&t) != BSDDIALOG_OK) { + sprintf(errbuf, "Cannot save theme: %s", bsddialog_geterror()); + return (BSDDIALOG_ERROR); + } + + if(time(&clock) < 0) { + sprintf(errbuf, "Cannot save profile (getting current time)"); + return (BSDDIALOG_ERROR); + } + + if ((fp = fopen(file, "w")) == NULL) { + sprintf(errbuf, "Cannot open %s to save profile", file); + return (BSDDIALOG_ERROR); + } + + fprintf(fp, "### bsddialog theme - %s", ctime(&clock)); + fputs("# Refer to bsddialog(3) manual for theme.* properties\n", fp); + fprintf(fp, "version %s\n", version); + + for (i = 0; i < NPROPERTY; i++) { + switch (p[i].type) { + case CHAR: + fprintf(fp, "%s %c\n", p[i].name, *((char*)p[i].value)); + break; + case INT: + fprintf(fp, "%s %d\n", p[i].name, *((int*)p[i].value)); + break; + case UINT: + fprintf(fp, "%s %u\n", p[i].name, + *((unsigned int*)p[i].value)); + break; + case BOOL: + fprintf(fp, "%s %s\n", p[i].name, + *((bool*)p[i].value) ? "true" : "false"); + break; + case COLOR: + bsddialog_color_attrs(*(int*)p[i].value, &fg, &bg, + &flags); + fprintf(fp, "%s %s %s%s%s%s\n", + p[i].name, color[fg], color[bg], + flags & BSDDIALOG_BOLD ? " bold" : "", + flags & BSDDIALOG_REVERSE ? " reverse" : "", + flags & BSDDIALOG_UNDERLINE ? " underline" : ""); + break; + } + } + + fclose(fp); + + return (BSDDIALOG_OK); +} + +int loadtheme(const char *file, char *errbuf) +{ + bool boolvalue; + char charvalue, *value; + char line[BUFSIZ], name[BUFSIZ], c1[BUFSIZ], c2[BUFSIZ]; + int i, j, intvalue, flags; + unsigned int uintvalue; + enum bsddialog_color bg, fg; + FILE *fp; + + if (bsddialog_get_theme(&t) != BSDDIALOG_OK) { + sprintf(errbuf, "Cannot get current theme: %s", + bsddialog_geterror()); + return (BSDDIALOG_ERROR); + } + + if((fp = fopen(file, "r")) == NULL) { + sprintf(errbuf, "Cannot open theme \"%s\"", file); + return (BSDDIALOG_ERROR); + } + +#define RETURN_ERROR(name, error) do { \ + sprintf(errbuf, "%s for \"%s\"", error, name); \ + fclose(fp); \ + return (BSDDIALOG_ERROR); \ +} while (0) + + while(fgets(line, BUFSIZ, fp) != NULL) { + if(line[0] == '#' || line[0] == '\n') + continue; /* superfluous, only for efficiency */ + sscanf(line, "%s", name); + for (i = 0; i < NPROPERTY; i++) { + if (strcmp(name, p[i].name) == 0) { + value = &line[strlen(name)]; + break; + } + } + if (i >= NPROPERTY) { + if (strcmp(name, "version") == 0) + continue; + RETURN_ERROR(name, "Unknown theme property name"); + } + switch (p[i].type) { + case CHAR: + while (value[0] == ' ' || value[0] == '\n' || + value[0] == '\0') + value++; + if (sscanf(value, "%c", &charvalue) != 1) + RETURN_ERROR(p[i].name, "Cannot get a char"); + *((int*)p[i].value) = charvalue; + break; + case INT: + if (sscanf(value, "%d", &intvalue) != 1) + RETURN_ERROR(p[i].name, "Cannot get a int"); + *((int*)p[i].value) = intvalue; + break; + case UINT: + if (sscanf(value, "%u", &uintvalue) != 1) + RETURN_ERROR(p[i].name, "Cannot get a uint"); + *((unsigned int*)p[i].value) = uintvalue; + break; + case BOOL: + boolvalue = (strstr(value, "true") != NULL) ? + true :false; + *((bool*)p[i].value) = boolvalue; + break; + case COLOR: + if (sscanf(value, "%s %s", c1, c2) != 2) + RETURN_ERROR(p[i].name, "Cannot get 2 colors"); + /* Foreground */ + for (j = 0; j < 8 ; j++) + if ((strstr(c1, color[j])) != NULL) + break; + if ((fg = j) > 7) + RETURN_ERROR(p[i].name, "Bad foreground"); + /* Background */ + for (j = 0; j < 8 ; j++) + if ((value = strstr(c2, color[j])) != NULL) + break; + if ((bg = j) > 7) + RETURN_ERROR(p[i].name, "Bad background"); + /* Flags */ + flags = 0; + if (strstr(value, "bold") != NULL) + flags |= BSDDIALOG_BOLD; + if (strstr(value, "reverse") != NULL) + flags |= BSDDIALOG_REVERSE; + if (strstr(value, "underline") != NULL) + flags |= BSDDIALOG_UNDERLINE; + *((int*)p[i].value) = bsddialog_color(fg, bg, flags); + break; + } + } + + fclose(fp); + + bsddialog_set_theme(&t); + + return (BSDDIALOG_OK); +} + +int bikeshed(struct bsddialog_conf *conf, char *errbuf) +{ + int margin, i; + int colors[8] = {0, 0, 0, 0 ,0 ,0 , 0, 0}; + enum bsddialog_color col[6]; + time_t clock; + + time(&clock); + srand(clock); + + /* theme */ + if (bsddialog_get_theme(&t) != BSDDIALOG_OK) + return (BSDDIALOG_ERROR); + + for (i = 0; i < 6; i++) { + do { + col[i] = rand() % 8; + } while (colors[col[i]] == 1); + colors[col[i]] = 1; + } + + t.screen.color = bsddialog_color(col[4], col[3], 0); + + t.shadow.color = bsddialog_color(col[0], col[0], 0); + t.shadow.y = 1, + t.shadow.x = 2, + + t.dialog.delimtitle = (rand() % 2 == 0) ? true : false; + t.dialog.titlecolor = bsddialog_color(col[3], col[5], 0); + t.dialog.lineraisecolor = bsddialog_color(col[0], col[5], 0); + t.dialog.linelowercolor = bsddialog_color(col[0], col[5], 0); + t.dialog.color = bsddialog_color(col[0], col[5], 0); + t.dialog.bottomtitlecolor = bsddialog_color(col[0], col[5], 0); + t.dialog.arrowcolor = bsddialog_color(col[3], col[5], 0); + + t.menu.f_selectorcolor = bsddialog_color(col[5], col[3], 0); + t.menu.selectorcolor = bsddialog_color(col[0], col[5], 0); + t.menu.f_desccolor = bsddialog_color(col[5], col[3], 0); + t.menu.desccolor = bsddialog_color(col[0], col[5], 0); + t.menu.f_namecolor = bsddialog_color(col[5], col[3], 0); + t.menu.namecolor = bsddialog_color(col[3], col[5], 0); + t.menu.namesepcolor = bsddialog_color(col[1], col[5], 0); + t.menu.descsepcolor = bsddialog_color(col[1], col[5], 0); + t.menu.f_shortcutcolor = bsddialog_color(col[1], col[3], 0); + t.menu.shortcutcolor = bsddialog_color(col[1], col[5], 0); + t.menu.bottomdesccolor = bsddialog_color(col[4], col[3], 0); + + t.form.f_fieldcolor = bsddialog_color(col[5], col[3], 0); + t.form.fieldcolor = bsddialog_color(col[5], col[4], 0); + t.form.readonlycolor = bsddialog_color(col[4], col[5], 0); + t.form.bottomdesccolor = bsddialog_color(col[4], col[3], 0); + + t.bar.f_color = bsddialog_color(col[5], col[3], 0); + t.bar.color = bsddialog_color(col[3], col[5], 0); + + t.button.minmargin = 1, + t.button.maxmargin = 5, + t.button.leftdelim = '[', + t.button.rightdelim = ']', + t.button.f_delimcolor = bsddialog_color(col[5], col[3], 0); + t.button.delimcolor = bsddialog_color(col[0], col[5], 0); + t.button.f_color = bsddialog_color(col[2], col[3], 0); + t.button.color = bsddialog_color(col[0], col[5], 0); + t.button.f_shortcutcolor = bsddialog_color(col[5], col[3], 0); + t.button.shortcutcolor = bsddialog_color(col[1], col[5], 0); + + if (bsddialog_set_theme(&t)) + return (BSDDIALOG_ERROR); + + /* conf */ + conf->button.always_active = (rand() % 2 == 0) ? true : false; + if (conf->title != NULL) { + memset(title, 0, 1024); + margin = rand() % 5; + memset(title, ' ', margin); + strcpy(title + margin, conf->title); + memset(title + strlen(title), ' ', margin); + conf->title = title; + } + + return (BSDDIALOG_OK); +} |
