diff --git a/OpenRGB.pro b/OpenRGB.pro index 10d209ce..5c71b06f 100644 --- a/OpenRGB.pro +++ b/OpenRGB.pro @@ -112,6 +112,8 @@ HEADERS += NetworkClient.h \ NetworkProtocol.h \ NetworkServer.h \ + OpenRGBPluginInterface.h \ + PluginManager.h \ ProfileManager.h \ ResourceManager.h \ SettingsManager.h \ @@ -284,7 +286,6 @@ HEADERS += RGBController/RGBController_Dummy.h \ RGBController/RGBController_Network.h \ - SOURCES += \ dependencies/dmiinfo.cpp \ dependencies/ColorWheel/ColorWheel.cpp \ @@ -293,6 +294,7 @@ SOURCES += cli.cpp \ NetworkClient.cpp \ NetworkServer.cpp \ + PluginManager.cpp \ ProfileManager.cpp \ ResourceManager.cpp \ SettingsManager.cpp \ diff --git a/OpenRGBPluginInterface.h b/OpenRGBPluginInterface.h new file mode 100644 index 00000000..9ee829fe --- /dev/null +++ b/OpenRGBPluginInterface.h @@ -0,0 +1,43 @@ +/*-----------------------------------------*\ +| OpenRGBPluginInterface.h | +| | +| OpenRGB Plugin Interface Class | +| | +| herosilas12 (CoffeeIsLife) 12/11/2020 | +| Adam Honse (CalcProgrammer1) 1/5/2021 | +\*-----------------------------------------*/ + +#pragma once + +#include "ResourceManager.h" + +#include +#include + +#define OpenRGBPluginInterface_IID "com.OpenRGBPluginInterface" + +struct OpenRGBPluginInfo +{ + std::string PluginName; + std::string PluginDescription; + std::string PluginLocation; + + bool HasCustom; + QLabel *PluginLabel; + + std::string SettingName; +}; + +class OpenRGBPluginInterface +{ +public: + virtual ~OpenRGBPluginInterface() {} + + virtual OpenRGBPluginInfo Initialize(bool dark_theme, ResourceManager* resource_manager_ptr) = 0; + + virtual QWidget *CreateGUI(QWidget* parent) = 0; + + OpenRGBPluginInfo info; +}; + +Q_DECLARE_INTERFACE(OpenRGBPluginInterface, OpenRGBPluginInterface_IID) diff --git a/PluginManager.cpp b/PluginManager.cpp new file mode 100644 index 00000000..046002d7 --- /dev/null +++ b/PluginManager.cpp @@ -0,0 +1,45 @@ +#include "PluginManager.h" + +void PluginManager::ScanAndLoadPlugins() +{ + std::string OpenRGBConfigDir = ResourceManager::get()->GetConfigurationDirectory(); + + std::string PluginPath = OpenRGBConfigDir + "/Plugins"; + + /*--------------------------------------------------------------------------------------*\ + | I used https://github.com/krf/cmake-qtqml-plugin-example to figure out how to do this | + | So BIG credit to krf | + \*--------------------------------------------------------------------------------------*/ + OpenRGBPluginInterface *OpenRGBPlugin = nullptr; + + const QDir pluginsDir = QString().fromStdString(ResourceManager::get()->GetConfigurationDirectory()) + "plugins/"; + + std::vector FileList; + + for(int i = 0; i < QDir(pluginsDir).entryList(QDir::Files).size(); i++) + { + /*--------------------------------------*\ + | Add all of the Plugin Files to a list | + \*--------------------------------------*/ + FileList.push_back(QDir(pluginsDir).entryList(QDir::Files)[i].toStdString()); + } + + for(const std::string &fileName : FileList) + { + const std::string filePath = pluginsDir.absoluteFilePath(QString().fromStdString(fileName)).toStdString(); + + QPluginLoader loader(pluginsDir.absoluteFilePath(QString().fromStdString(fileName))); + + if (QObject *instance = loader.instance()) + { + if ((OpenRGBPlugin = qobject_cast(instance))) + { + PluginManager::ActivePlugins.push_back(OpenRGBPlugin); + } + } + else + { + std::cout << loader.errorString().toStdString() << std::endl; + } + } +} diff --git a/PluginManager.h b/PluginManager.h new file mode 100644 index 00000000..acd7c5fc --- /dev/null +++ b/PluginManager.h @@ -0,0 +1,20 @@ +#pragma once + +#include "OpenRGBPluginInterface.h" +#include "ResourceManager.h" + +#include +#include +#include +#include + +#include +#include + +class PluginManager +{ +public: + std::vector ActivePlugins; + + void ScanAndLoadPlugins(); +}; diff --git a/ProfileManager.h b/ProfileManager.h index c4202c27..3769698c 100644 --- a/ProfileManager.h +++ b/ProfileManager.h @@ -2,7 +2,33 @@ #pragma once -class ProfileManager +class ProfileManagerInterface +{ +public: + virtual bool SaveProfile(std::string profile_name) = 0; + virtual bool LoadProfile(std::string profile_name) = 0; + virtual bool LoadSizeFromProfile(std::string profile_name) = 0; + virtual void DeleteProfile(std::string profile_name) = 0; + + std::vector profile_list; + + virtual bool LoadDeviceFromListWithOptions + ( + std::vector& temp_controllers, + std::vector& temp_controller_used, + RGBController* load_controller, + bool load_size, + bool load_settings + ) = 0; + + virtual std::vector LoadProfileToList (std::string profile_name) = 0; + + virtual void SetConfigurationDirectory(std::string directory) = 0; +protected: + virtual ~ProfileManagerInterface() {}; +}; + +class ProfileManager: public ProfileManagerInterface { public: ProfileManager(std::string config_dir); diff --git a/ResourceManager.cpp b/ResourceManager.cpp index b2eaae24..8efa2c23 100644 --- a/ResourceManager.cpp +++ b/ResourceManager.cpp @@ -18,7 +18,7 @@ #include #include -std::unique_ptr ResourceManager::instance; +ResourceManager* ResourceManager::instance; using namespace std::chrono_literals; @@ -26,10 +26,10 @@ ResourceManager *ResourceManager::get() { if(!instance) { - instance = std::make_unique(); + instance = new ResourceManager(); } - - return instance.get(); + + return instance; } ResourceManager::ResourceManager() diff --git a/ResourceManager.h b/ResourceManager.h index cfd6e96a..0683551b 100644 --- a/ResourceManager.h +++ b/ResourceManager.h @@ -50,7 +50,34 @@ typedef void (*DeviceListChangeCallback)(void *); typedef void (*DetectionProgressCallback)(void *); typedef void (*I2CBusListChangeCallback)(void *); -class ResourceManager +class ResourceManagerInterface +{ +public: + virtual std::vector & GetI2CBusses() = 0; + + virtual void RegisterRGBController(RGBController *rgb_controller) = 0; + + virtual void RegisterDeviceListChangeCallback(DeviceListChangeCallback new_callback, void * new_callback_arg) = 0; + virtual void RegisterDetectionProgressCallback(DetectionProgressCallback new_callback, void * new_callback_arg) = 0; + virtual void RegisterI2CBusListChangeCallback(I2CBusListChangeCallback new_callback, void * new_callback_arg) = 0; + + virtual std::vector & GetRGBControllers() = 0; + + virtual std::string GetConfigurationDirectory() = 0; + + virtual std::vector& GetClients() = 0; + virtual NetworkServer* GetServer() = 0; + + virtual ProfileManager* GetProfileManager() = 0; + virtual SettingsManager* GetSettingsManager() = 0; + + virtual void DeviceListChanged() = 0; + +protected: + virtual ~ResourceManagerInterface() {}; +}; + +class ResourceManager: public ResourceManagerInterface { public: static ResourceManager *get(); @@ -110,7 +137,10 @@ public: private: void DetectDevicesThreadFunction(); - static std::unique_ptr instance; + /*-------------------------------------------------------------------------------------*\ + | Static pointer to shared instance of ResourceManager | + \*-------------------------------------------------------------------------------------*/ + static ResourceManager* instance; /*-------------------------------------------------------------------------------------*\ | Detection enabled flag | diff --git a/SettingsManager.h b/SettingsManager.h index 48a3dbd0..350e72c0 100644 --- a/SettingsManager.h +++ b/SettingsManager.h @@ -15,19 +15,31 @@ using json = nlohmann::json; -class SettingsManager +class SettingsManagerInterface +{ +public: + virtual json GetSettings(std::string settings_key) = 0; + virtual void SetSettings(std::string settings_key, json new_settings) = 0; + + virtual void LoadSettings(std::string filename) = 0; + virtual void SaveSettings() = 0; + +protected: + virtual ~SettingsManagerInterface() {}; +}; + +class SettingsManager: public SettingsManagerInterface { public: SettingsManager(); ~SettingsManager(); - json GetSettings(std::string settings_key); - void SetSettings(std::string settings_key, json new_settings); + json GetSettings(std::string settings_key) override; + void SetSettings(std::string settings_key, json new_settings) override; - void LoadSettings(std::string filename); - void SaveSettings(); + void LoadSettings(std::string filename) override; + void SaveSettings() override; - private: json settings_data; json settings_prototype; diff --git a/qt/OpenRGBDialog2.cpp b/qt/OpenRGBDialog2.cpp index c609eb70..7ddac977 100644 --- a/qt/OpenRGBDialog2.cpp +++ b/qt/OpenRGBDialog2.cpp @@ -1,4 +1,5 @@ #include "OpenRGBDialog2.h" +#include "PluginManager.h" #include "OpenRGBDevicePage.h" #include "OpenRGBDeviceInfoPage.h" #include "OpenRGBServerInfoPage.h" @@ -88,7 +89,7 @@ static void UpdateDetectionProgressCallback(void * this_ptr) bool OpenRGBDialog2::IsDarkTheme() { - #ifdef _WIN32 +#ifdef _WIN32 /*-------------------------------------------------*\ | Windows dark theme settings | \*-------------------------------------------------*/ @@ -131,12 +132,12 @@ bool OpenRGBDialog2::IsDarkTheme() } return false; - #else +#else if(QPalette().window().color().value() < 127) { return true; } - #endif +#endif return false; } @@ -287,6 +288,24 @@ OpenRGBDialog2::OpenRGBDialog2(QWidget *parent) : QMainWindow(parent), ui(new Op { AddI2CToolsPage(); } + + /*-----------------------------------------------------*\ + | Add the various plugins tabs | + \*-----------------------------------------------------*/ + PluginManager* plugin_manager = new PluginManager; + + plugin_manager->ScanAndLoadPlugins(); + + if(plugin_manager->ActivePlugins.size() > 0) + { + for(int i = 0; i < int(plugin_manager->ActivePlugins.size()); i++) + { + /*---------------------------------------------------------------------------*\ + | Start by getting location and then placing the widget where it needs to go | + \*---------------------------------------------------------------------------*/ + OpenRGBDialog2::AddPluginTab(plugin_manager, i); + } + } } OpenRGBDialog2::~OpenRGBDialog2() @@ -358,6 +377,98 @@ void OpenRGBDialog2::AddSupportedDevicesPage() ui->SettingsTabBar->tabBar()->setTabButton(ui->SettingsTabBar->tabBar()->count() - 1, QTabBar::LeftSide, SupportedTabLabel); } +void OpenRGBDialog2::AddPluginTab(PluginManager* plugin_manager, int plugin_index) +{ + /*-----------------------------------------------------*\ + | Initialize the plugin | + \*-----------------------------------------------------*/ + plugin_manager->ActivePlugins[plugin_index]->info = plugin_manager->ActivePlugins[plugin_index]->Initialize(OpenRGBDialog2::IsDarkTheme(), ResourceManager::get()); + + /*-----------------------------------------------------*\ + | Create Label for the Tab | + \*-----------------------------------------------------*/ + QLabel* PluginTabLabel = new QLabel; + + /*-----------------------------------------------------*\ + | If the plugin has custom information, use it, | + | otherwise generate it | + \*-----------------------------------------------------*/ + if(plugin_manager->ActivePlugins[plugin_index]->info.HasCustom) + { + PluginTabLabel = plugin_manager->ActivePlugins[plugin_index]->info.PluginLabel; + } + else + { + QLabel *TabLabelText = plugin_manager->ActivePlugins[plugin_index]->info.PluginLabel; + + QString NewTabLabelText = TabLabelText->text(); + QString PluginLabelString = "
" + NewTabLabelText + "
"; + PluginTabLabel->setText(PluginLabelString); + + PluginTabLabel->setIndent(20); + if(IsDarkTheme()) + { + PluginTabLabel->setGeometry(0, 25, 200, 50); + } + else + { + PluginTabLabel->setGeometry(0, 0, 200, 25); + } + } + + /*-----------------------------------------------------*\ + | Determine plugin location | + \*-----------------------------------------------------*/ + std::string Location = plugin_manager->ActivePlugins[plugin_index]->info.PluginLocation; + + /*-----------------------------------------------------*\ + | InformationTab - Place plugin in the Information tab | + \*-----------------------------------------------------*/ + if(Location == "InformationTab") + { + QWidget* NewPluginTab = new QWidget; + + NewPluginTab = plugin_manager->ActivePlugins[plugin_index]->CreateGUI(NewPluginTab); + ui->InformationTabBar->addTab(NewPluginTab," "); + + ui->InformationTabBar->tabBar()->setTabButton((ui->InformationTabBar->count() - 1),QTabBar::LeftSide , PluginTabLabel); + } + /*-----------------------------------------------------*\ + | DevicesTab - Place plugin in the Devices tab | + \*-----------------------------------------------------*/ + else if(Location == "DevicesTab") + { + QWidget* NewPluginTab = new QWidget; + + NewPluginTab = plugin_manager->ActivePlugins[plugin_index]->CreateGUI(NewPluginTab); + ui->DevicesTabBar->addTab(NewPluginTab," "); + + ui->DevicesTabBar->tabBar()->setTabButton((ui->DevicesTabBar->count() - 1),QTabBar::LeftSide , PluginTabLabel); + } + /*-----------------------------------------------------*\ + | TopTabBar - Place plugin as its own top level tab | + \*-----------------------------------------------------*/ + else if(Location == "TopTabBar") + { + QWidget* NewPluginTab = new QWidget; + + NewPluginTab = plugin_manager->ActivePlugins[plugin_index]->CreateGUI(NewPluginTab); + + ui->MainTabBar->addTab(NewPluginTab,QString().fromStdString(plugin_manager->ActivePlugins[plugin_index]->info.PluginName)); + } + /*-----------------------------------------------------*\ + | Display an error message if the plugin does not | + | specify a valid location | + \*-----------------------------------------------------*/ + else + { + std::cout << (plugin_manager->ActivePlugins[plugin_index]->info.PluginName + " Is broken\nNo valid location specified"); + } +} + void OpenRGBDialog2::AddI2CToolsPage() { ShowI2CTools = true; @@ -934,6 +1045,7 @@ void Ui::OpenRGBDialog2::SetDetectionViewState(bool detection_showing) ui->ProfileBox->setVisible(true); } } + void Ui::OpenRGBDialog2::on_ButtonRescan_clicked() { SetDetectionViewState(true); diff --git a/qt/OpenRGBDialog2.h b/qt/OpenRGBDialog2.h index 5f528caf..bece13c0 100644 --- a/qt/OpenRGBDialog2.h +++ b/qt/OpenRGBDialog2.h @@ -7,6 +7,7 @@ #include "OpenRGBSoftwareInfoPage.h" #include "OpenRGBSystemInfoPage.h" #include "OpenRGBSupportedDevicesPage.h" +#include "PluginManager.h" #include #include "i2c_smbus.h" @@ -66,6 +67,7 @@ private: void AddSoftwareInfoPage(); void AddSupportedDevicesPage(); + void AddPluginTab(PluginManager* plugin_manager,int plugin_index); void ClearDevicesList(); void UpdateDevicesList(); diff --git a/qt/plugin.png b/qt/plugin.png new file mode 100644 index 00000000..76bccd20 Binary files /dev/null and b/qt/plugin.png differ diff --git a/qt/plugin_dark.png b/qt/plugin_dark.png new file mode 100644 index 00000000..434b8f08 Binary files /dev/null and b/qt/plugin_dark.png differ diff --git a/qt/resources.qrc b/qt/resources.qrc index 66d708b0..d9702cbf 100644 --- a/qt/resources.qrc +++ b/qt/resources.qrc @@ -32,5 +32,7 @@ windows_dark.qss arrow-down.png arrow-up.png + plugin.png + plugin_dark.png diff --git a/qt/windows_dark.qss b/qt/windows_dark.qss index 4f2e0c64..86c26462 100644 --- a/qt/windows_dark.qss +++ b/qt/windows_dark.qss @@ -58,10 +58,18 @@ QTabWidget QWidget QTabBar::tab padding-top: 4px; padding-bottom: 5px; height: 50px; + border: 10px; + border: 1px solid #5c5c5c; border-right: 1px solid #2e2e2e; margin-right: 0px; - margin-bottom: 0px; - border: 1px solid #2e2e2e; +} + +QTabWidget QWidget QTabBar::tab:!selected +{ + background-color: #5c5c5c; + border-right: 1px solid #2e2e2e; + border-left: 1px solid #2e2e2e; + border-top: 1px solid #2e2e2e; } QTabWidget QWidget QTabBar::tab:selected @@ -71,6 +79,12 @@ QTabWidget QWidget QTabBar::tab:selected border-right: 1px solid #454545; } +QTabWidget QWidget QTabBar::tab:last:!selected +{ + background-color: #5c5c5c; + border: 1px solid #2e2e2e; +} + QTabWidget QWidget QTabBar::tab:hover { background-color: #757575; @@ -78,6 +92,13 @@ QTabWidget QWidget QTabBar::tab:hover border-right: 1px solid #2e2e2e; } +QTabWidget QWidget QTabBar::tab:last:hover +{ + background-color: #757575; + border: 1px solid #5c5c5c; + border-right: 1px solid #2e2e2e; +} + QTabWidget QWidget QTabWidget::pane /* The contents of the tab (colors, modes, leds, etc.) */ { background-color: #454545; @@ -259,10 +280,15 @@ QDialog background-color: #5c5c5c } -/* -the default color is fine -QSlider::handle +/* QTableWidgets */ + +QTableWidget { - background: ; + background-color: #454545; + color: white; +} + +QTableWidget QTableCornerButton::section +{ + background-color: #444444; } -*/