URI:
       theme.c - ltk - GUI toolkit for X11 (WIP)
  HTML git clone git://lumidify.org/ltk.git (fast, but not encrypted)
  HTML git clone https://lumidify.org/ltk.git (encrypted, but very slow)
  HTML git clone git://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/ltk.git (over tor)
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       theme.c (6292B)
       ---
            1 /*
            2  * Copyright (c) 2022-2024 lumidify <nobody@lumidify.org>
            3  *
            4  * Permission to use, copy, modify, and/or distribute this software for any
            5  * purpose with or without fee is hereby granted, provided that the above
            6  * copyright notice and this permission notice appear in all copies.
            7  *
            8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
            9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
           10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
           11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
           12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
           13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
           14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
           15  */
           16 
           17 #include <stdlib.h>
           18 #include <string.h>
           19 
           20 #include "graphics.h"
           21 #include "util.h"
           22 #include "theme.h"
           23 #include "memory.h"
           24 
           25 /* FIXME: handle '#' or no '#' in color specification */
           26 static int
           27 search_helper(const void *keyv, const void *entryv) {
           28         char *key = (char *)keyv;
           29         ltk_theme_parseinfo *entry = (ltk_theme_parseinfo *)entryv;
           30         return strcmp(key, entry->key);
           31 }
           32 
           33 static int
           34 sort_helper(const void *entry1v, const void *entry2v) {
           35         ltk_theme_parseinfo *entry1 = (ltk_theme_parseinfo *)entry1v;
           36         ltk_theme_parseinfo *entry2 = (ltk_theme_parseinfo *)entry2v;
           37         return strcmp(entry1->key, entry2->key);
           38 }
           39 
           40 /* FIXME: more information for errors */
           41 int
           42 ltk_theme_handle_value(ltk_renderdata *renderdata, char *debug_name, const char *prop, const char *value, ltk_theme_parseinfo *parseinfo, size_t len, int *sorted) {
           43         if (!*sorted) {
           44                 qsort(parseinfo, len, sizeof(ltk_theme_parseinfo), &sort_helper);
           45                 *sorted = 1;
           46         }
           47         ltk_theme_parseinfo *entry = bsearch(prop, parseinfo, len, sizeof(ltk_theme_parseinfo), &search_helper);
           48         if (!entry) {
           49                 ltk_warn("Invalid property '%s:%s'.\n", debug_name, prop);
           50                 return 1;
           51         } else if (entry->initialized) {
           52                 ltk_warn("Duplicate setting for property '%s:%s'.\n", debug_name, prop);
           53                 return 1;
           54         }
           55         const char *errstr = NULL;
           56         switch (entry->type) {
           57         case THEME_INT:
           58                 *(entry->ptr.i) = ltk_strtonum(value, entry->min, entry->max, &errstr);
           59                 if (errstr) {
           60                         ltk_warn("Invalid value '%s' for property '%s:%s'.\n", value, debug_name, prop);
           61                         return 1;
           62                 } else {
           63                         entry->initialized = 1;
           64                 }
           65                 break;
           66         case THEME_SIZE:
           67                 entry->ptr.size->unit = LTK_UNIT_PX;
           68                 char *endptr = NULL;
           69                 /* this already takes care of overflow prevention because entry->min and entry->max are int */
           70                 entry->ptr.size->val = ltk_strtoscalednum(value, entry->min, entry->max, &endptr, &errstr);
           71                 if (errstr) {
           72                         ltk_warn("Invalid value '%s' for property '%s:%s': %s\n", value, debug_name, prop, errstr);
           73                         return 1;
           74                 }
           75                 if (*endptr == '\0') {
           76                         /* NOP */
           77                 } else if (!strcmp(endptr, "px")) {
           78                         entry->ptr.size->unit = LTK_UNIT_PX;
           79                 } else if (!strcmp(endptr, "pt")) {
           80                         entry->ptr.size->unit = LTK_UNIT_PT;
           81                 } else if (!strcmp(endptr, "mm")) {
           82                         entry->ptr.size->unit = LTK_UNIT_MM;
           83                 } else {
           84                         ltk_warn("Invalid value '%s' for property '%s:%s'\n", value, debug_name, prop);
           85                         return 1;
           86                 }
           87                 entry->initialized = 1;
           88                 break;
           89         case THEME_STRING:
           90                 /* FIXME: check if already set? */
           91                 *(entry->ptr.str) = ltk_strdup(value);
           92                 entry->initialized = 1;
           93                 break;
           94         case THEME_COLOR:
           95                 if (!(*(entry->ptr.color) = ltk_color_create(renderdata, value))) {
           96                         ltk_warn("Unable to create color '%s' for property '%s:%s'.\n", value, debug_name, prop);
           97                         return 1;
           98                 } else {
           99                         entry->initialized = 1;
          100                 }
          101                 break;
          102         case THEME_BOOL:
          103                 if (strcmp(value, "true") == 0) {
          104                         *(entry->ptr.b) = 1;
          105                 } else if (strcmp(value, "false") == 0) {
          106                         *(entry->ptr.b) = 0;
          107                 } else {
          108                         ltk_warn("Invalid value '%s' for property '%s:%s'.\n", value, debug_name, prop);
          109                         return 1;
          110                 }
          111                 entry->initialized = 1;
          112                 break;
          113         case THEME_BORDERSIDES:
          114                 *(entry->ptr.border) = LTK_BORDER_NONE;
          115                 for (const char *c = value; *c != '\0'; c++) {
          116                         switch (*c) {
          117                         case 't':
          118                                 *(entry->ptr.border) |= LTK_BORDER_TOP;
          119                                 break;
          120                         case 'b':
          121                                 *(entry->ptr.border) |= LTK_BORDER_BOTTOM;
          122                                 break;
          123                         case 'l':
          124                                 *(entry->ptr.border) |= LTK_BORDER_LEFT;
          125                                 break;
          126                         case 'r':
          127                                 *(entry->ptr.border) |= LTK_BORDER_RIGHT;
          128                                 break;
          129                         default:
          130                                 ltk_warn("Invalid value '%s' for property '%s:%s'.\n", value, debug_name, prop);
          131                                 return 1;
          132                         }
          133                 }
          134                 entry->initialized = 1;
          135                 break;
          136         default:
          137                 ltk_fatal("Invalid theme setting type. This should not happen.\n");
          138                 /* TODO: ltk_assert(0); */
          139         }
          140         return 0;
          141 }
          142 
          143 int
          144 ltk_theme_fill_defaults(ltk_renderdata *renderdata, char *debug_name, ltk_theme_parseinfo *parseinfo, size_t len) {
          145         for (size_t i = 0; i < len; i++) {
          146                 ltk_theme_parseinfo *e = &parseinfo[i];
          147                 if (e->initialized)
          148                         continue;
          149                 switch (e->type) {
          150                 case THEME_INT:
          151                         *(e->ptr.i) = e->defaultval.i;
          152                         e->initialized = 1;
          153                         break;
          154                 case THEME_SIZE:
          155                         *(e->ptr.size) = e->defaultval.size;
          156                         e->initialized = 1;
          157                         break;
          158                 case THEME_STRING:
          159                         *(e->ptr.str) = ltk_strdup(e->defaultval.str);
          160                         e->initialized = 1;
          161                         break;
          162                 case THEME_COLOR:
          163                         if (!(*(e->ptr.color) = ltk_color_create(renderdata, e->defaultval.color))) {
          164                                 ltk_warn("Unable to create default color '%s' for property '%s:%s'.\n", e->defaultval.color, debug_name, e->key);
          165                                 return 1;
          166                         } else {
          167                                 e->initialized = 1;
          168                         }
          169                         break;
          170                 case THEME_BOOL:
          171                         *(e->ptr.b) = e->defaultval.b;
          172                         e->initialized = 1;
          173                         break;
          174                 case THEME_BORDERSIDES:
          175                         *(e->ptr.border) = e->defaultval.border;
          176                         e->initialized = 1;
          177                         break;
          178                 default:
          179                         ltk_fatal("Invalid theme setting type. This should not happen.\n");
          180                         /* TODO: ltk_assert(0); */
          181                 }
          182         }
          183         return 0;
          184 }
          185 
          186 void
          187 ltk_theme_uninitialize(ltk_renderdata *renderdata, ltk_theme_parseinfo *parseinfo, size_t len) {
          188         for (size_t i = 0; i < len; i++) {
          189                 ltk_theme_parseinfo *e = &parseinfo[i];
          190                 if (!e->initialized)
          191                         continue;
          192                 switch (e->type) {
          193                 case THEME_STRING:
          194                         ltk_free(*(e->ptr.str));
          195                         e->initialized = 0;
          196                         break;
          197                 case THEME_COLOR:
          198                         ltk_color_destroy(renderdata, *(e->ptr.color));
          199                         e->initialized = 0;
          200                         break;
          201                 case THEME_SIZE:
          202                 case THEME_INT:
          203                 case THEME_BOOL:
          204                 case THEME_BORDERSIDES:
          205                         e->initialized = 0;
          206                         break;
          207                 default:
          208                         ltk_fatal("Invalid theme setting type. This should not happen.\n");
          209                 }
          210         }
          211 }