|
@@ -24,9 +24,10 @@
|
|
#include <sstream>
|
|
#include <sstream>
|
|
#include <mutex>
|
|
#include <mutex>
|
|
#include <util/bmem.h>
|
|
#include <util/bmem.h>
|
|
-#include <util/dstr.h>
|
|
|
|
|
|
+#include <util/dstr.hpp>
|
|
#include <util/platform.h>
|
|
#include <util/platform.h>
|
|
#include <util/profiler.hpp>
|
|
#include <util/profiler.hpp>
|
|
|
|
+#include <util/cf-parser.h>
|
|
#include <obs-config.h>
|
|
#include <obs-config.h>
|
|
#include <obs.hpp>
|
|
#include <obs.hpp>
|
|
|
|
|
|
@@ -782,6 +783,192 @@ bool OBSApp::InitLocale()
|
|
return true;
|
|
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)
|
|
bool OBSApp::SetTheme(std::string name, std::string path)
|
|
{
|
|
{
|
|
theme = name;
|
|
theme = name;
|
|
@@ -803,12 +990,17 @@ bool OBSApp::SetTheme(std::string name, std::string path)
|
|
}
|
|
}
|
|
|
|
|
|
QString mpath = QString("file:///") + path.c_str();
|
|
QString mpath = QString("file:///") + path.c_str();
|
|
|
|
+ setPalette(defaultPalette);
|
|
setStyleSheet(mpath);
|
|
setStyleSheet(mpath);
|
|
|
|
+ ParseExtraThemeData(path.c_str());
|
|
|
|
+
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
bool OBSApp::InitTheme()
|
|
bool OBSApp::InitTheme()
|
|
{
|
|
{
|
|
|
|
+ defaultPalette = palette();
|
|
|
|
+
|
|
const char *themeName = config_get_string(globalConfig, "General",
|
|
const char *themeName = config_get_string(globalConfig, "General",
|
|
"CurrentTheme");
|
|
"CurrentTheme");
|
|
if (!themeName) {
|
|
if (!themeName) {
|