UI: Add support for theme meta, parent theme palette

Theme Meta allows individual themes to provide additional information to
OBS.

The primarily goal is for a theme to define a "parent", allowing to
extend existing themes with additional attributes.
master
Matt Gajownik 2022-07-05 23:47:12 +10:00 committed by Matt Gajownik
parent bf65c5b041
commit cb8bc3413a
7 changed files with 141 additions and 6 deletions

View File

@ -1,3 +1,8 @@
OBSThemeMeta {
dark: 'true';
author: 'Warchamp7';
}
/* OBSTheme, main QApplication palette and QML values */
OBSTheme {
window: rgb(24,24,25);

View File

@ -28,6 +28,10 @@
/* rgb(11,10,11); /* veryVeryDark */
/* rgb(42,130,218); /* blue */
OBSThemeMeta {
dark: 'true';
author: 'Warchamp7';
}
/* Custom theme information. This will set the application's QPalette, as
* well as pass to QML via the OBSTheme object.

View File

@ -44,6 +44,11 @@
/* ---- Main Theme ---- */
/************************/
OBSThemeMeta {
dark: 'true';
author: 'Fenrir';
}
OBSTheme {
window: rgb(49, 54, 59); /* Blue-gray */
windowText: rgb(239, 240, 241); /* White */

View File

@ -8,6 +8,9 @@
/* Dark Theme is a good place to start if you need */
/* a template. */
OBSThemeMeta {
dark: 'false';
}
/* We need to set back the icons, or the preview wont stick. */

View File

@ -19,6 +19,11 @@
/* Colors */
OBSThemeMeta {
dark: 'true';
author: 'Warchamp7';
}
/* 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.

View File

@ -1095,10 +1095,72 @@ void OBSApp::ParseExtraThemeData(const char *path)
setPalette(pal);
}
bool OBSApp::SetTheme(std::string name, std::string path)
OBSThemeMeta *OBSApp::ParseThemeMeta(const char *path)
{
theme = name;
BPtr<char> data = os_quick_read_utf8_file(path);
CFParser cfp;
int ret;
if (!cf_parser_parse(cfp, data, path))
return nullptr;
if (cf_token_is(cfp, "OBSThemeMeta") ||
cf_go_to_token(cfp, "OBSThemeMeta", nullptr)) {
OBSThemeMeta *meta = new OBSThemeMeta();
if (!cf_next_token(cfp))
return nullptr;
if (!cf_token_is(cfp, "{"))
return nullptr;
for (;;) {
if (!cf_next_token(cfp))
return nullptr;
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 nullptr;
ret = cf_token_is_type(cfp, CFTOKEN_STRING, "value",
";");
if (ret != PARSE_SUCCESS)
continue;
char *str;
str = cf_literal_to_str(cfp->cur_token->str.array,
cfp->cur_token->str.len);
if (strcmp(name->array, "dark") == 0 && str) {
meta->dark = strcmp(str, "true") == 0;
} else if (strcmp(name->array, "parent") == 0 && str) {
meta->parent = std::string(str);
} else if (strcmp(name->array, "author") == 0 && str) {
meta->author = std::string(str);
}
bfree(str);
if (!cf_go_to_token(cfp, ";", nullptr))
return nullptr;
}
return meta;
}
return nullptr;
}
std::string OBSApp::GetTheme(std::string name, std::string path)
{
/* Check user dir first, then preinstalled themes. */
if (path == "") {
char userDir[512];
@ -1110,18 +1172,59 @@ bool OBSApp::SetTheme(std::string name, std::string path)
path = string(userDir);
} else if (!GetDataFilePath(name.c_str(), path)) {
OBSErrorBox(NULL, "Failed to find %s.", name.c_str());
return false;
return "";
}
}
return path;
}
std::string OBSApp::SetParentTheme(std::string name)
{
string path = GetTheme(name.c_str(), "");
if (path.empty())
return path;
setStyleSheet(defaultStyleSheet);
QString mpath = QString("file:///") + path.c_str();
setPalette(defaultPalette);
QString mpath = QString("file:///") + path.c_str();
ParseExtraThemeData(path.c_str());
return path;
}
bool OBSApp::SetTheme(std::string name, std::string path)
{
theme = name;
path = GetTheme(name, path);
if (path.empty())
return false;
themeMeta = ParseThemeMeta(path.c_str());
string parentPath;
if (themeMeta && !themeMeta->parent.empty()) {
parentPath = SetParentTheme(themeMeta->parent);
}
string lpath = path;
if (parentPath.empty()) {
setStyleSheet(defaultStyleSheet);
setPalette(defaultPalette);
} else {
lpath = parentPath;
}
QString mpath = QString("file:///") + lpath.c_str();
ParseExtraThemeData(path.c_str());
setStyle(new OBSIgnoreWheelProxyStyle);
setStyleSheet(mpath);
QColor color = palette().text().color();
themeDarkMode = !(color.redF() < 0.5);
if (themeMeta) {
themeDarkMode = themeMeta->dark;
} else {
QColor color = palette().text().color();
themeDarkMode = !(color.redF() < 0.5);
}
emit StyleChanged();
return true;

View File

@ -68,6 +68,12 @@ public:
typedef std::function<void()> VoidFunc;
struct OBSThemeMeta {
bool dark;
std::string parent;
std::string author;
};
class OBSApp : public QApplication {
Q_OBJECT
@ -75,6 +81,7 @@ private:
std::string locale;
std::string theme;
QString defaultStyleSheet;
OBSThemeMeta *themeMeta = nullptr;
bool themeDarkMode = true;
ConfigFile globalConfig;
TextLookup textLookup;
@ -103,6 +110,7 @@ private:
QPalette defaultPalette;
void ParseExtraThemeData(const char *path);
static OBSThemeMeta *ParseThemeMeta(const char *path);
void AddExtraThemeColor(QPalette &pal, int group, const char *name,
uint32_t color);
@ -130,6 +138,8 @@ public:
inline const char *GetLocale() const { return locale.c_str(); }
inline const char *GetTheme() const { return theme.c_str(); }
std::string GetTheme(std::string name, std::string path);
std::string SetParentTheme(std::string name);
bool SetTheme(std::string name, std::string path = "");
inline bool IsThemeDark() const { return themeDarkMode; };