#include "../include/Theme.hpp" #include "../include/Config.hpp" #include "../include/Storage.hpp" #include #include 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, "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); 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; } }