aboutsummaryrefslogtreecommitdiff
path: root/src/Theme.cpp
blob: 36c8ff76f46f092209c103ad59c473e1db3aefd5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include "../include/Theme.hpp"
#include "../include/Config.hpp"
#include "../include/Storage.hpp"
#include <json/value.h>
#include <assert.h>

namespace QuickMedia {
    static bool theme_initialized = false;
    static Theme *theme = nullptr;

    static bool get_theme_by_name(const std::string &theme_name, Json::Value &json_root) {
        Path config_path = get_storage_dir().join("themes").join(theme_name).append(".json");
        if(read_file_as_json(config_path, json_root) && json_root.isObject())
            return true;

        config_path = Path("/usr/share/quickmedia/themes/").join(theme_name).append(".json");
        if(read_file_as_json(config_path, json_root) && json_root.isObject())
            return true;

        return false;
    }

    // Returns -1 if its not a hex value
    static int get_hex_value(char c) {
        if(c >= '0' && c <= '9')
            return c - '0';
        else if(c >= 'a' && c <= 'f')
            return 10 + (c - 'a');
        else if(c >= 'A' && c <= 'F')
            return 10 + (c - 'A');
        else
            return -1;
    }

    static void parse_hex_set_color(const Json::Value &json_obj, const char *field_name, mgl::Color &color) {
        const Json::Value &json_val = json_obj[field_name];
        if(!json_val.isString()) {
            fprintf(stderr, "Warning: theme variable \"%s\" does not exists or is not a string\n", field_name);
            return;
        }

        // #RRGGBB(AA), case insensitive hex
        const char *color_str = json_val.asCString();
        if(color_str[0] != '#') {
            fprintf(stderr, "Warning: theme variable \"%s\" is an invalid color value. Expected #RRGGBB or #RRGGBBAA, was: %s\n", field_name, color_str);
            return;
        }

        const int color_str_len = strlen(color_str);
        if(color_str_len - 1 != 6 && color_str_len - 1 != 8) {
            fprintf(stderr, "Warning: theme variable \"%s\" is an invalid color value. Expected #RRGGBB or #RRGGBBAA, was: %s\n", field_name, color_str);
            return;
        }

        mgl::Color new_color;
        for(int i = 1; i < color_str_len; i += 2) {
            const int c1 = get_hex_value(color_str[i + 0]);
            const int c2 = get_hex_value(color_str[i + 1]);
            if(c1 == -1 || c2 == -1) {
                fprintf(stderr, "Warning: theme variable \"%s\" is an invalid color value. Expected #RRGGBB or #RRGGBBAA, was: %s\n", field_name, color_str);
                return;
            }

            // TODO: Test on big endian systems
            (&new_color.r)[(i - 1)/2] = (c1 << 4) | c2;
        }
        color = new_color;
    }

    static void get_bool_value(const Json::Value &json_obj, const char *field_name, bool &val) {
        const Json::Value &json_val = json_obj[field_name];
        if(!json_val.isBool()) {
            fprintf(stderr, "Warning: theme variable \"%s\" does not exists or is not a boolean\n", field_name);
            return;
        }
        val = json_val.asBool();
    }

    static void init_theme() {
        if(theme_initialized)
            return;

        setlocale(LC_ALL, "C"); // Sigh... stupid C
        theme_initialized = true;
        // Wtf? can't use static non-pointer config because it causes a segfault.
        // It looks like a libc bug??? crashes for both gcc and clang.
        theme = new Theme();

        Json::Value json_root;
        if(!get_theme_by_name(get_config().theme, json_root)) {
            fprintf(stderr, "Warning: failed to load theme: \"%s\", using \"default\" theme\n", get_config().theme.c_str());
            return;
        }

        parse_hex_set_color(json_root, "background_color", theme->background_color);
        parse_hex_set_color(json_root, "text_color", theme->text_color);
        parse_hex_set_color(json_root, "faded_text_color", theme->faded_text_color);
        parse_hex_set_color(json_root, "shade_color", theme->shade_color);
        parse_hex_set_color(json_root, "selected_color", theme->selected_color);
        parse_hex_set_color(json_root, "card_item_background_color", theme->card_item_background_color);
        parse_hex_set_color(json_root, "replies_text_color", theme->replies_text_color);
        parse_hex_set_color(json_root, "placeholder_text_color", theme->placeholder_text_color);
        parse_hex_set_color(json_root, "image_loading_background_color", theme->image_loading_background_color);
        parse_hex_set_color(json_root, "attention_alert_text_color", theme->attention_alert_text_color);
        parse_hex_set_color(json_root, "cancel_button_background_color", theme->cancel_button_background_color);
        parse_hex_set_color(json_root, "confirm_button_background_color", theme->confirm_button_background_color);
        parse_hex_set_color(json_root, "loading_bar_color", theme->loading_bar_color);
        parse_hex_set_color(json_root, "embedded_item_border_color", theme->embedded_item_border_color);
        parse_hex_set_color(json_root, "provisional_message_color", theme->provisional_message_color);
        parse_hex_set_color(json_root, "failed_text_color", theme->failed_text_color);
        parse_hex_set_color(json_root, "timestamp_text_color", theme->timestamp_text_color);
        parse_hex_set_color(json_root, "new_items_alert_color", theme->new_items_alert_color);
        parse_hex_set_color(json_root, "arrow_color", theme->arrow_color);
        parse_hex_set_color(json_root, "url_text_color", theme->url_text_color);
        parse_hex_set_color(json_root, "loading_page_color", theme->loading_page_color);
        parse_hex_set_color(json_root, "more_items_color", theme->more_items_color);
        get_bool_value(json_root, "drop_shadow", theme->drop_shadow);
    }

    const Theme& get_theme() {
        init_theme();
        return *theme;
    }
}