aboutsummaryrefslogtreecommitdiff
path: root/src/Theme.cpp
blob: 4c4ff67a1adbaf29cad8f1232faee95316ef7661 (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
125
126
127
128
129
130
#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.isNull())
            return;

        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;
            }
            (&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.isNull())
            return;

        if(!json_val.isBool()) {
            fprintf(stderr, "Warning: theme variable \"%s\" 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, "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);
        get_bool_value(json_root, "circle_mask_enabled", theme->circle_mask_enabled);
        get_bool_value(json_root, "rounded_rectangles", theme->rounded_rectangles);
    }

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