diff --git a/obs/data/locale/en-US.ini b/obs/data/locale/en-US.ini index bb38077e1..d51ab072b 100644 --- a/obs/data/locale/en-US.ini +++ b/obs/data/locale/en-US.ini @@ -217,6 +217,7 @@ Basic.Settings.Confirm="You have unsaved changes. Save changes?" # basic mode 'general' settings Basic.Settings.General="General" +Basic.Settings.General.Theme="Theme" Basic.Settings.General.Language="Language" # basic mode 'stream' settings diff --git a/obs/forms/OBSBasicSettings.ui b/obs/forms/OBSBasicSettings.ui index a3df70654..65813850a 100644 --- a/obs/forms/OBSBasicSettings.ui +++ b/obs/forms/OBSBasicSettings.ui @@ -6,7 +6,7 @@ 0 0 - 770 + 895 602 @@ -143,6 +143,16 @@ + + + + Basic.Settings.General.Theme + + + + + + @@ -2326,8 +2336,8 @@ 0 0 - 609 - 553 + 724 + 536 @@ -2362,7 +2372,7 @@ - 170 + 0 0 @@ -2409,7 +2419,7 @@ - 170 + 0 0 diff --git a/obs/forms/obs.qrc b/obs/forms/obs.qrc index c50846d0b..be69e0bee 100644 --- a/obs/forms/obs.qrc +++ b/obs/forms/obs.qrc @@ -1,5 +1,5 @@ - + images/configuration21_16.png images/list_remove.png images/add.png @@ -10,7 +10,7 @@ images/up.png images/obs.png - + images/settings/advanced.png images/settings/network.png images/settings/video-display-3.png diff --git a/obs/obs-app.cpp b/obs/obs-app.cpp index 4d352d282..1f9bb3437 100644 --- a/obs/obs-app.cpp +++ b/obs/obs-app.cpp @@ -29,6 +29,7 @@ #include "qt-wrappers.hpp" #include "obs-app.hpp" #include "window-basic-main.hpp" +#include "window-basic-settings.hpp" #include "window-license-agreement.hpp" #include "crash-report.hpp" #include "platform.hpp" @@ -233,6 +234,44 @@ bool OBSApp::InitLocale() return true; } +bool OBSApp::SetTheme(std::string name, std::string path) +{ + theme = name; + + /* Check user dir first, then preinstalled themes. */ + if (path == "") { + char userDir[512]; + name = "themes/" + name + ".qss"; + string temp = "obs-studio/" + name; + int ret = os_get_config_path(userDir, sizeof(userDir), + temp.c_str()); + + if (ret > 0 && QFile::exists(userDir)) { + path = string(userDir); + } else if (!GetDataFilePath(name.c_str(), path)) { + OBSErrorBox(NULL, "Failed to find %s.", name.c_str()); + return false; + } + } + + QString mpath = QString("file:///") + path.c_str(); + setStyleSheet(mpath); + return true; +} + +bool OBSApp::InitTheme() +{ + const char *themeName = config_get_string(globalConfig, "General", + "Theme"); + + if (!themeName) + themeName = "Default"; + + stringstream t; + t << themeName; + return SetTheme(t.str()); +} + OBSApp::OBSApp(int &argc, char **argv) : QApplication(argc, argv) {} @@ -247,6 +286,8 @@ void OBSApp::AppInit() throw "Failed to initialize global config"; if (!InitLocale()) throw "Failed to load locale"; + if (!InitTheme()) + throw "Failed to load theme"; } const char *OBSApp::GetRenderModule() const diff --git a/obs/obs-app.hpp b/obs/obs-app.hpp index b13f8eb8e..79853f594 100644 --- a/obs/obs-app.hpp +++ b/obs/obs-app.hpp @@ -55,6 +55,7 @@ class OBSApp : public QApplication { private: std::string locale; + std::string theme; ConfigFile globalConfig; TextLookup textLookup; QPointer mainWindow; @@ -62,6 +63,7 @@ private: bool InitGlobalConfig(); bool InitGlobalConfigDefaults(); bool InitLocale(); + bool InitTheme(); public: OBSApp(int &argc, char **argv); @@ -78,6 +80,9 @@ public: return locale.c_str(); } + inline const char *GetTheme() const {return theme.c_str();} + bool SetTheme(std::string name, std::string path = ""); + inline lookup_t *GetTextLookup() const {return textLookup;} inline const char *GetString(const char *lookupVal) const diff --git a/obs/window-basic-main.cpp b/obs/window-basic-main.cpp index 0a03dbbf3..69870e3c3 100644 --- a/obs/window-basic-main.cpp +++ b/obs/window-basic-main.cpp @@ -82,6 +82,7 @@ OBSBasic::OBSBasic(QWidget *parent) ui (new Ui::OBSBasic) { ui->setupUi(this); + copyActionsDynamicProperties(); int width = config_get_int(App()->GlobalConfig(), "MainWindow", "cx"); @@ -197,6 +198,26 @@ static obs_data_t *GenerateSaveData() return saveData; } +void OBSBasic::copyActionsDynamicProperties() +{ + // Themes need the QAction dynamic properties + for (QAction *x : ui->scenesToolbar->actions()) { + QWidget* temp = ui->scenesToolbar->widgetForAction(x); + + for (QByteArray &y : x->dynamicPropertyNames()) { + temp->setProperty(y, x->property(y)); + } + } + + for (QAction *x : ui->sourcesToolbar->actions()) { + QWidget* temp = ui->sourcesToolbar->widgetForAction(x); + + for (QByteArray &y : x->dynamicPropertyNames()) { + temp->setProperty(y, x->property(y)); + } + } +} + void OBSBasic::ClearVolumeControls() { VolControl *control; diff --git a/obs/window-basic-main.hpp b/obs/window-basic-main.hpp index 2bdaaaa67..08f6523c2 100644 --- a/obs/window-basic-main.hpp +++ b/obs/window-basic-main.hpp @@ -180,6 +180,7 @@ private: void AddSource(const char *id); QMenu *CreateAddSourcePopupMenu(); void AddSourcePopupMenu(const QPoint &pos); + void copyActionsDynamicProperties(); public: OBSScene GetCurrentScene(); diff --git a/obs/window-basic-settings.cpp b/obs/window-basic-settings.cpp index 4267e9346..043866cca 100644 --- a/obs/window-basic-settings.cpp +++ b/obs/window-basic-settings.cpp @@ -1,5 +1,6 @@ /****************************************************************************** Copyright (C) 2013-2014 by Hugh Bailey + Philippe Groarke This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,6 +24,7 @@ #include #include #include +#include #include "obs-app.hpp" #include "platform.hpp" @@ -134,6 +136,7 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent) ui->setupUi(this); HookWidget(ui->language, COMBO_CHANGED, GENERAL_CHANGED); + HookWidget(ui->theme, COMBO_CHANGED, GENERAL_CHANGED); HookWidget(ui->outputMode, COMBO_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->streamType, COMBO_CHANGED, STREAM1_CHANGED); HookWidget(ui->simpleOutputPath, EDIT_CHANGED, OUTPUTS_CHANGED); @@ -336,11 +339,52 @@ void OBSBasicSettings::LoadLanguageList() ui->language->model()->sort(0); } +void OBSBasicSettings::LoadThemeList() +{ + /* Save theme if user presses Cancel */ + savedTheme = string(App()->GetTheme()); + + ui->theme->clear(); + QSet uniqueSet; + string themeDir; + char userThemeDir[512]; + int ret = os_get_config_path(userThemeDir, sizeof(userThemeDir), + "obs-studio/themes/"); + GetDataFilePath("themes/", themeDir); + + /* Check user dir first. */ + if (ret > 0) { + QDirIterator it(QString(userThemeDir), QStringList() << "*.qss", + QDir::Files); + while (it.hasNext()) { + it.next(); + QString name = it.fileName().section(".",0,0); + ui->theme->addItem(name); + uniqueSet.insert(name); + } + } + + /* Check shipped themes. */ + QDirIterator uIt(QString(themeDir.c_str()), QStringList() << "*.qss", + QDir::Files); + while (uIt.hasNext()) { + uIt.next(); + QString name = uIt.fileName().section(".",0,0); + if (!uniqueSet.contains(name)) + ui->theme->addItem(name); + } + + int idx = ui->theme->findText(App()->GetTheme()); + if (idx != -1) + ui->theme->setCurrentIndex(idx); +} + void OBSBasicSettings::LoadGeneralSettings() { loading = true; LoadLanguageList(); + LoadThemeList(); loading = false; } @@ -984,6 +1028,16 @@ void OBSBasicSettings::SaveGeneralSettings() if (WidgetChanged(ui->language)) config_set_string(GetGlobalConfig(), "General", "Language", language.c_str()); + + int themeIndex = ui->theme->currentIndex(); + QString themeData = ui->theme->itemText(themeIndex); + string theme = themeData.toStdString(); + + if (WidgetChanged(ui->theme)) { + config_set_string(GetGlobalConfig(), "General", "Theme", + theme.c_str()); + App()->SetTheme(theme); + } } void OBSBasicSettings::SaveStream1Settings() @@ -1241,6 +1295,12 @@ void OBSBasicSettings::closeEvent(QCloseEvent *event) event->ignore(); } +void OBSBasicSettings::on_theme_activated(int idx) +{ + string currT = ui->theme->itemText(idx).toStdString(); + App()->SetTheme(currT); +} + void OBSBasicSettings::on_simpleOutUseBufsize_toggled(bool checked) { if (!checked) @@ -1276,6 +1336,8 @@ void OBSBasicSettings::on_buttonBox_clicked(QAbstractButton *button) if (val == QDialogButtonBox::AcceptRole || val == QDialogButtonBox::RejectRole) { + if (val == QDialogButtonBox::RejectRole) + App()->SetTheme(savedTheme); ClearChanged(); close(); } diff --git a/obs/window-basic-settings.hpp b/obs/window-basic-settings.hpp index f0fe34016..b36e8e75b 100644 --- a/obs/window-basic-settings.hpp +++ b/obs/window-basic-settings.hpp @@ -1,5 +1,6 @@ /****************************************************************************** Copyright (C) 2013 by Hugh Bailey + Philippe Groarke This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,6 +21,7 @@ #include #include #include +#include #include @@ -45,6 +47,7 @@ private: bool advancedChanged = false; int pageIndex = 0; bool loading = true; + std::string savedTheme; OBSPropertiesView *streamProperties = nullptr; OBSPropertiesView *streamEncoderProps = nullptr; @@ -104,6 +107,7 @@ private: /* general */ void LoadLanguageList(); + void LoadThemeList(); /* output */ void LoadSimpleOutputSettings(); @@ -136,6 +140,8 @@ private: void SaveSettings(); private slots: + void on_theme_activated(int idx); + void on_simpleOutUseBufsize_toggled(bool checked); void on_simpleOutputVBitrate_valueChanged(int val);