Procházet zdrojové kódy

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.
Matt Gajownik před 3 roky
rodič
revize
cb8bc3413a

+ 5 - 0
UI/data/themes/Acri.qss

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

+ 4 - 0
UI/data/themes/Dark.qss

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

+ 5 - 0
UI/data/themes/Rachni.qss

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

+ 3 - 0
UI/data/themes/System.qss

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

+ 5 - 0
UI/data/themes/Yami.qss

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

+ 109 - 6
UI/obs-app.cpp

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

+ 10 - 0
UI/obs-app.hpp

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