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)
master
jp9000 2018-07-04 21:01:22 -07:00
parent 8b6d437a97
commit e1ab9a0fc4
5 changed files with 309 additions and 1 deletions

View File

@ -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;

View File

@ -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 */

View File

@ -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 --- */
/*************************/

View File

@ -24,9 +24,10 @@
#include <sstream>
#include <mutex>
#include <util/bmem.h>
#include <util/dstr.h>
#include <util/dstr.hpp>
#include <util/platform.h>
#include <util/profiler.hpp>
#include <util/cf-parser.h>
#include <obs-config.h>
#include <obs.hpp>
@ -782,6 +783,192 @@ bool OBSApp::InitLocale()
return true;
}
void OBSApp::AddExtraThemeColor(QPalette &pal, int group,
const char *name, uint32_t color)
{
std::function<void(QPalette::ColorGroup)> 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<char> 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) {

View File

@ -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();