From e1ab9a0fc4ce3d442f12bdcc1c7a2cf5e1f52ae4 Mon Sep 17 00:00:00 2001 From: jp9000 Date: Wed, 4 Jul 2018 21:01:22 -0700 Subject: [PATCH] UI: Add ability to parse OBSStyle from qss Adds the ability to set the current palette for the program via adding "OBSTheme" objects to the qss files. The values for the OBSTheme object are the values used by QPalette::ColorRole. Modifying the global palette allows the ability to easily/quickly look up application theme colors (especially if you would like to use them for QML), as well as the ability to fix the hyperlink color issue. (On dark themes, links would still be dark blue, causing them to be difficult to see) --- UI/data/themes/Acri.qss | 34 +++++++ UI/data/themes/Dark.qss | 38 ++++++++ UI/data/themes/Rachni.qss | 38 ++++++++ UI/obs-app.cpp | 194 +++++++++++++++++++++++++++++++++++++- UI/obs-app.hpp | 6 ++ 5 files changed, 309 insertions(+), 1 deletion(-) diff --git a/UI/data/themes/Acri.qss b/UI/data/themes/Acri.qss index 26eae664e..bce32d1fb 100644 --- a/UI/data/themes/Acri.qss +++ b/UI/data/themes/Acri.qss @@ -1,3 +1,37 @@ +/* OBSTheme, main QApplication palette and QML values */ +OBSTheme { + window: #181819; + windowText: rgb(225,224,225); + base: rgb(18,18,21); + alternateBase: rgb(0,0,0); + text: rgb(225,224,225); + button: #162458; + buttonText: rgb(225,224,225); + brightText: #484848; + + light: #162458; + mid: #181819; + dark: rgb(18,18,21); + shadow: rgb(0,0,0); + + highlight: #252458; + highlightText: #FFFFFF; + + link: #605ee6; + linkVisited: #605ee6; +} + +OBSTheme::disabled { + text: #484848; + buttonText: #484848; + brightText: #484848; +} + +OBSTheme::inactive { + highlight: rgb(48,47,48); + highlightText: rgb(255, 255, 255); +} + /* General style, we override only what is needed. */ QWidget { background-color: #181819; diff --git a/UI/data/themes/Dark.qss b/UI/data/themes/Dark.qss index 6140a3234..976cc7e26 100644 --- a/UI/data/themes/Dark.qss +++ b/UI/data/themes/Dark.qss @@ -28,6 +28,44 @@ /* rgb(42,130,218); /* blue */ +/* Custom theme information. This will set the application's QPalette, as + * well as pass to QML via the OBSTheme object. + * Can also use OBSTheme::disabled, OBSTheme::active, and OBSTheme::inactive. + * Using it without will set all three (making 'active' a bit redundant) */ +OBSTheme { + window: rgb(58,57,58); /* dark */ + windowText: rgb(225,224,225); /* veryLight */ + base: rgb(31,30,31); /* veryDark */ + alternateBase: rgb(11,10,11); /* veryVeryDark */ + text: rgb(225,224,225); /* veryLight */ + button: rgb(88,87,88); /* kindaDark */ + buttonText: rgb(225,224,225); /* veryLight */ + brightText: rgb(200,199,200); /* lighter */ + + light: rgb(88,87,88); /* kindaDark */ + mid: rgb(58,57,58); /* dark */ + dark: rgb(31,30,31); /* veryDark */ + shadow: rgb(11,10,11); /* veryVeryDark */ + + highlight: rgb(42,130,218); /* blue */ + highlightText: rgb(0,0,0); + + link: rgb(42,130,218); /* blue */ + linkVisited: rgb(42,130,218); /* blue */ +} + +OBSTheme::disabled { + text: rgb(200,199,200); /* lighter */ + buttonText: rgb(200,199,200); /* lighter */ + brightText: rgb(200,199,200); /* lighter */ +} + +OBSTheme::inactive { + highlight: rgb(48,47,48); + highlightText: rgb(255, 255, 255); +} + + /* General style, we override only what is needed. */ QWidget { background-color: rgb(58,57,58); /* dark */ diff --git a/UI/data/themes/Rachni.qss b/UI/data/themes/Rachni.qss index be067c067..f3f53e5d3 100644 --- a/UI/data/themes/Rachni.qss +++ b/UI/data/themes/Rachni.qss @@ -40,6 +40,44 @@ /***************************************************************************/ +/************************/ +/* ---- Main Theme ---- */ +/************************/ + +OBSTheme { + window: rgb(49, 54, 59); /* Blue-gray */ + windowText: rgb(239, 240, 241); /* White */ + base: rgb(0, 139, 163); /* Dark Cyan (Primary Dark) */ + alternateBase: rgb(186, 45, 101); /* Dark Pink (Secondary Dark) */ + text: rgb(239, 240, 241); /* White */ + button: rgb(0, 188, 212); /* Cyan (Primary) */ + buttonText: rgb(239, 240, 241); /* White */ + brightText: rgb(255, 148, 194); /* Light Pink (Secondary Light) */ + + light: rgb(162, 161, 162); /* Lighter Gray */ + mid: rgb(118, 121, 124); /* Light Grey */ + dark: rgb(84, 87, 91); /* Gray */ + shadow: rgb(35, 38, 41); /* Dark Gray */ + + highlight: rgb(98, 238, 255); /* Light Cyan (Primary Light) */ + highlightText: rgb(0,0,0); + + link: rgb(98, 238, 255); /* Light Cyan (Primary Light) */ + linkVisited: rgb(98, 238, 255); /* Light Cyan (Primary Light) */ +} + +OBSTheme::disabled { + text: rgb(255, 148, 194); /* Light Pink (Secondary Light) */ + buttonText: rgb(255, 148, 194); /* Light Pink (Secondary Light) */ + brightText: rgb(255, 148, 194); /* Light Pink (Secondary Light) */ +} + +OBSTheme::inactive { + highlight: rgb(0, 188, 212); /* Cyan (Primary) */ + highlightText: rgb(239, 240, 241); /* White */ +} + + /*************************/ /* --- General style --- */ /*************************/ diff --git a/UI/obs-app.cpp b/UI/obs-app.cpp index 2db37b583..77e59ea4c 100644 --- a/UI/obs-app.cpp +++ b/UI/obs-app.cpp @@ -24,9 +24,10 @@ #include #include #include -#include +#include #include #include +#include #include #include @@ -782,6 +783,192 @@ bool OBSApp::InitLocale() return true; } +void OBSApp::AddExtraThemeColor(QPalette &pal, int group, + const char *name, uint32_t color) +{ + std::function func; + +#define DEF_PALETTE_ASSIGN(name) \ + do { \ + func = [&] (QPalette::ColorGroup group) \ + { \ + pal.setColor(group, QPalette::name, \ + QColor::fromRgb(color)); \ + }; \ + } while (false) + + if (astrcmpi(name, "alternateBase") == 0) { + DEF_PALETTE_ASSIGN(AlternateBase); + } else if (astrcmpi(name, "base") == 0) { + DEF_PALETTE_ASSIGN(Base); + } else if (astrcmpi(name, "brightText") == 0) { + DEF_PALETTE_ASSIGN(BrightText); + } else if (astrcmpi(name, "button") == 0) { + DEF_PALETTE_ASSIGN(Button); + } else if (astrcmpi(name, "buttonText") == 0) { + DEF_PALETTE_ASSIGN(ButtonText); + } else if (astrcmpi(name, "brightText") == 0) { + DEF_PALETTE_ASSIGN(BrightText); + } else if (astrcmpi(name, "dark") == 0) { + DEF_PALETTE_ASSIGN(Dark); + } else if (astrcmpi(name, "highlight") == 0) { + DEF_PALETTE_ASSIGN(Highlight); + } else if (astrcmpi(name, "highlightedText") == 0) { + DEF_PALETTE_ASSIGN(HighlightedText); + } else if (astrcmpi(name, "light") == 0) { + DEF_PALETTE_ASSIGN(Light); + } else if (astrcmpi(name, "link") == 0) { + DEF_PALETTE_ASSIGN(Link); + } else if (astrcmpi(name, "linkVisited") == 0) { + DEF_PALETTE_ASSIGN(LinkVisited); + } else if (astrcmpi(name, "mid") == 0) { + DEF_PALETTE_ASSIGN(Mid); + } else if (astrcmpi(name, "midlight") == 0) { + DEF_PALETTE_ASSIGN(Midlight); + } else if (astrcmpi(name, "shadow") == 0) { + DEF_PALETTE_ASSIGN(Shadow); + } else if (astrcmpi(name, "text") == 0 || + astrcmpi(name, "foreground") == 0) { + DEF_PALETTE_ASSIGN(Text); + } else if (astrcmpi(name, "toolTipBase") == 0) { + DEF_PALETTE_ASSIGN(ToolTipBase); + } else if (astrcmpi(name, "toolTipText") == 0) { + DEF_PALETTE_ASSIGN(ToolTipText); + } else if (astrcmpi(name, "windowText") == 0) { + DEF_PALETTE_ASSIGN(WindowText); + } else if (astrcmpi(name, "window") == 0 || + astrcmpi(name, "background") == 0) { + DEF_PALETTE_ASSIGN(Window); + } else { + return; + } + +#undef DEF_PALETTE_ASSIGN + + switch (group) { + case QPalette::Disabled: + case QPalette::Active: + case QPalette::Inactive: + func((QPalette::ColorGroup)group); + break; + default: + func((QPalette::ColorGroup)QPalette::Disabled); + func((QPalette::ColorGroup)QPalette::Active); + func((QPalette::ColorGroup)QPalette::Inactive); + } +} + +struct CFParser { + cf_parser cfp = {}; + inline ~CFParser() {cf_parser_free(&cfp);} + inline operator cf_parser*() {return &cfp;} + inline cf_parser *operator->() {return &cfp;} +}; + +void OBSApp::ParseExtraThemeData(const char *path) +{ + BPtr data = os_quick_read_utf8_file(path); + QPalette pal = palette(); + CFParser cfp; + int ret; + + cf_parser_parse(cfp, data, path); + + while (cf_go_to_token(cfp, "OBSTheme", nullptr)) { + if (!cf_next_token(cfp)) return; + + int group = -1; + + if (cf_token_is(cfp, ":")) { + ret = cf_next_token_should_be(cfp, ":", nullptr, + nullptr); + if (ret != PARSE_SUCCESS) continue; + + if (!cf_next_token(cfp)) return; + + if (cf_token_is(cfp, "disabled")) { + group = QPalette::Disabled; + } else if (cf_token_is(cfp, "active")) { + group = QPalette::Active; + } else if (cf_token_is(cfp, "inactive")) { + group = QPalette::Inactive; + } else { + continue; + } + + if (!cf_next_token(cfp)) return; + } + + if (!cf_token_is(cfp, "{")) continue; + + for (;;) { + if (!cf_next_token(cfp)) return; + + ret = cf_token_is_type(cfp, CFTOKEN_NAME, "name", + nullptr); + if (ret != PARSE_SUCCESS) + break; + + DStr name; + dstr_copy_strref(name, &cfp->cur_token->str); + + ret = cf_next_token_should_be(cfp, ":", ";", + nullptr); + if (ret != PARSE_SUCCESS) continue; + + if (!cf_next_token(cfp)) return; + + const char *array; + uint32_t color = 0; + + if (cf_token_is(cfp, "#")) { + array = cfp->cur_token->str.array; + color = strtol(array + 1, nullptr, 16); + + } else if (cf_token_is(cfp, "rgb")) { + ret = cf_next_token_should_be(cfp, "(", ";", + nullptr); + if (ret != PARSE_SUCCESS) continue; + if (!cf_next_token(cfp)) return; + + array = cfp->cur_token->str.array; + color |= strtol(array, nullptr, 10) << 16; + + ret = cf_next_token_should_be(cfp, ",", ";", + nullptr); + if (ret != PARSE_SUCCESS) continue; + if (!cf_next_token(cfp)) return; + + array = cfp->cur_token->str.array; + color |= strtol(array, nullptr, 10) << 8; + + ret = cf_next_token_should_be(cfp, ",", ";", + nullptr); + if (ret != PARSE_SUCCESS) continue; + if (!cf_next_token(cfp)) return; + + array = cfp->cur_token->str.array; + color |= strtol(array, nullptr, 10); + + } else if (cf_token_is(cfp, "white")) { + color = 0xFFFFFF; + + } else if (cf_token_is(cfp, "black")) { + color = 0; + } + + if (!cf_go_to_token(cfp, ";", nullptr)) return; + + AddExtraThemeColor(pal, group, name->array, color); + } + + ret = cf_token_should_be(cfp, "}", "}", nullptr); + if (ret != PARSE_SUCCESS) continue; + } + + setPalette(pal); +} + bool OBSApp::SetTheme(std::string name, std::string path) { theme = name; @@ -803,12 +990,17 @@ bool OBSApp::SetTheme(std::string name, std::string path) } QString mpath = QString("file:///") + path.c_str(); + setPalette(defaultPalette); setStyleSheet(mpath); + ParseExtraThemeData(path.c_str()); + return true; } bool OBSApp::InitTheme() { + defaultPalette = palette(); + const char *themeName = config_get_string(globalConfig, "General", "CurrentTheme"); if (!themeName) { diff --git a/UI/obs-app.hpp b/UI/obs-app.hpp index 4a17e4971..f0b2224cb 100644 --- a/UI/obs-app.hpp +++ b/UI/obs-app.hpp @@ -87,6 +87,12 @@ private: inline void ResetHotkeyState(bool inFocus); + QPalette defaultPalette; + + void ParseExtraThemeData(const char *path); + void AddExtraThemeColor(QPalette &pal, int group, + const char *name, uint32_t color); + public: OBSApp(int &argc, char **argv, profiler_name_store_t *store); ~OBSApp();