357 lines
11 KiB
C
357 lines
11 KiB
C
|
/*-
|
||
|
* 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);
|
||
|
}
|