From 072d27d9dddea5c970024590f3598805e3933cc7 Mon Sep 17 00:00:00 2001 From: Adam Honse Date: Wed, 15 Apr 2026 11:51:28 -0500 Subject: [PATCH] Settings Rework * Add JSON string configuration field to RGBController to store device-specific configurations * This JSON string holds both configuration and schema * Add settings schema tracking to SettingsManager * Implement dynamic settings widget that generates a settings UI based on a JSON schema * Implement SettingsManager callback for notifying of settings changes and settings schema updates * Always enable Entire Device zone option and use it to enable Edit Device * Rename SaveSizes to SaveConfiguration in ProfileManager and Sizes.json to Configuration.json * Add zone flag for indicating that a zone's geometry may change, informing profile manager to ignore this check * Remove Theme setting and Theme Manager, as this didn't work on most setups anyways and Qt6 has proper Windows dark theming --- .../DebugController/RGBController_Debug.cpp | 320 +++-- .../DebugController/RGBController_Debug.h | 3 + .../E131Controller/RGBController_E131.cpp | 3 +- .../ElgatoLightStripController.cpp | 6 +- .../GoveeController/GoveeController.cpp | 4 +- .../KasaSmartController.cpp | 9 +- .../NanoleafController/NanoleafController.cpp | 3 +- .../PhilipsWizController.cpp | 6 +- DetectionManager.cpp | 18 +- Documentation/OpenRGBSDK.md | 91 +- JsonUtils.cpp | 71 + JsonUtils.h | 22 + LogManager.cpp | 45 +- NetworkClient.cpp | 64 + NetworkClient.h | 5 + NetworkProtocol.h | 13 +- NetworkServer.cpp | 167 ++- NetworkServer.h | 4 + OpenRGB.pro | 10 +- OpenRGBPluginInterface.h | 1 + PluginManager.cpp | 24 +- PluginManager.h | 1 + ProfileManager.cpp | 113 +- ProfileManager.h | 20 +- RGBController/RGBController.cpp | 313 +++- RGBController/RGBController.h | 66 +- RGBController/RGBController_Network.cpp | 55 + RGBController/RGBController_Network.h | 10 +- ResourceManager.cpp | 77 +- SettingsManager.cpp | 180 ++- SettingsManager.h | 87 +- cli.cpp | 4 +- qt/DeviceView.cpp | 126 +- qt/DeviceView.h | 2 + .../OpenRGBDeviceEditorDialog.cpp | 113 ++ .../OpenRGBDeviceEditorDialog.h | 48 + .../OpenRGBDeviceEditorDialog.ui | 69 + qt/OpenRGBDevicePage/OpenRGBDevicePage.cpp | 170 ++- qt/OpenRGBDevicePage/OpenRGBDevicePage.h | 1 + qt/OpenRGBDialog/OpenRGBDialog.cpp | 436 ++++-- qt/OpenRGBDialog/OpenRGBDialog.h | 11 +- .../OpenRGBDynamicSettingsWidget.cpp | 488 +++++++ .../OpenRGBDynamicSettingsWidget.h | 57 + ...RGBGreyscale.png => OpenRGBMonochrome.png} | Bin .../OpenRGBSettingsPage.cpp | 1272 ++--------------- qt/OpenRGBSettingsPage/OpenRGBSettingsPage.h | 87 +- qt/OpenRGBSettingsPage/OpenRGBSettingsPage.ui | 404 +----- qt/OpenRGBThemeManager.cpp | 126 -- qt/OpenRGBThemeManager.h | 20 - .../OpenRGBZoneEditorDialog.cpp | 100 +- .../OpenRGBZoneEditorDialog.h | 14 +- .../OpenRGBZoneEditorDialog.ui | 127 +- .../OpenRGBZoneInitializationDialog.cpp | 7 +- qt/i18n/OpenRGB_be_BY.ts | 20 +- qt/i18n/OpenRGB_de_DE.ts | 20 +- qt/i18n/OpenRGB_el_GR.ts | 18 +- qt/i18n/OpenRGB_en_AU.ts | 18 +- qt/i18n/OpenRGB_en_GB.ts | 18 +- qt/i18n/OpenRGB_en_US.ts | 662 +++++---- qt/i18n/OpenRGB_es_ES.ts | 20 +- qt/i18n/OpenRGB_fr_FR.ts | 20 +- qt/i18n/OpenRGB_hr_HR.ts | 18 +- qt/i18n/OpenRGB_it_IT.ts | 20 +- qt/i18n/OpenRGB_ja_JP.ts | 20 +- qt/i18n/OpenRGB_ko_KR.ts | 18 +- qt/i18n/OpenRGB_ms_MY.ts | 18 +- qt/i18n/OpenRGB_nb_NO.ts | 20 +- qt/i18n/OpenRGB_pl_PL.ts | 18 +- qt/i18n/OpenRGB_pt_BR.ts | 20 +- qt/i18n/OpenRGB_ru_RU.ts | 20 +- qt/i18n/OpenRGB_tr_TR.ts | 20 +- qt/i18n/OpenRGB_uk_UA.ts | 20 +- qt/i18n/OpenRGB_zh_CN.ts | 16 +- qt/i18n/OpenRGB_zh_TW.ts | 16 +- qt/resources.qrc | 2 +- 75 files changed, 3467 insertions(+), 3068 deletions(-) create mode 100644 JsonUtils.cpp create mode 100644 JsonUtils.h create mode 100644 qt/OpenRGBDeviceEditorDialog/OpenRGBDeviceEditorDialog.cpp create mode 100644 qt/OpenRGBDeviceEditorDialog/OpenRGBDeviceEditorDialog.h create mode 100644 qt/OpenRGBDeviceEditorDialog/OpenRGBDeviceEditorDialog.ui create mode 100644 qt/OpenRGBDynamicSettingsWidget/OpenRGBDynamicSettingsWidget.cpp create mode 100644 qt/OpenRGBDynamicSettingsWidget/OpenRGBDynamicSettingsWidget.h rename qt/{OpenRGBGreyscale.png => OpenRGBMonochrome.png} (100%) delete mode 100644 qt/OpenRGBThemeManager.cpp delete mode 100644 qt/OpenRGBThemeManager.h diff --git a/Controllers/DebugController/RGBController_Debug.cpp b/Controllers/DebugController/RGBController_Debug.cpp index 3574002c7..777efe3ff 100644 --- a/Controllers/DebugController/RGBController_Debug.cpp +++ b/Controllers/DebugController/RGBController_Debug.cpp @@ -13,6 +13,7 @@ #include #include #include "KeyboardLayoutManager.h" +#include "JsonUtils.h" #include "RGBController_Debug.h" /**------------------------------------------------------------------*\ @@ -54,80 +55,69 @@ RGBController_Debug::RGBController_Debug(bool custom, json settings) if(custom_controller) { /*-------------------------------------------------*\ - | Set the name | + | Set the name, description, location, version, and | + | serial | \*-------------------------------------------------*/ - name = debug_settings["DeviceName"]; + name = JsonUtils::JsonGetString(debug_settings, "DeviceName", "Custom Device"); + description = JsonUtils::JsonGetString(debug_settings, "DeviceDescription"); + location = JsonUtils::JsonGetString(debug_settings, "DeviceLocation"); + version = JsonUtils::JsonGetString(debug_settings, "DeviceVersion"); + serial = JsonUtils::JsonGetString(debug_settings, "DeviceSerial"); /*-------------------------------------------------*\ | Find the device type | \*-------------------------------------------------*/ - if (debug_settings["DeviceType"] == "motherboard") type = DEVICE_TYPE_MOTHERBOARD; - else if (debug_settings["DeviceType"] == "dram") type = DEVICE_TYPE_DRAM; - else if (debug_settings["DeviceType"] == "gpu") type = DEVICE_TYPE_GPU; - else if (debug_settings["DeviceType"] == "cooler") type = DEVICE_TYPE_COOLER; - else if (debug_settings["DeviceType"] == "led_strip") type = DEVICE_TYPE_LEDSTRIP; - else if (debug_settings["DeviceType"] == "keyboard") type = DEVICE_TYPE_KEYBOARD; - else if (debug_settings["DeviceType"] == "mouse") type = DEVICE_TYPE_MOUSE; - else if (debug_settings["DeviceType"] == "mousemat") type = DEVICE_TYPE_MOUSEMAT; - else if (debug_settings["DeviceType"] == "headset") type = DEVICE_TYPE_HEADSET; - else if (debug_settings["DeviceType"] == "headset_stand") type = DEVICE_TYPE_HEADSET_STAND; - else if (debug_settings["DeviceType"] == "gamepad") type = DEVICE_TYPE_GAMEPAD; - else if (debug_settings["DeviceType"] == "light") type = DEVICE_TYPE_LIGHT; - else if (debug_settings["DeviceType"] == "speaker") type = DEVICE_TYPE_SPEAKER; - else if (debug_settings["DeviceType"] == "unknown") type = DEVICE_TYPE_UNKNOWN; + std::string device_type = JsonUtils::JsonGetString(debug_settings, "DeviceType", "keyboard"); - /*-------------------------------------------------*\ - | Set description, location, version, and serial | - \*-------------------------------------------------*/ - description = debug_settings["DeviceDescription"]; - location = debug_settings["DeviceLocation"]; - version = debug_settings["DeviceVersion"]; - serial = debug_settings["DeviceSerial"]; + if( device_type == "motherboard") type = DEVICE_TYPE_MOTHERBOARD; + else if(device_type == "dram") type = DEVICE_TYPE_DRAM; + else if(device_type == "gpu") type = DEVICE_TYPE_GPU; + else if(device_type == "cooler") type = DEVICE_TYPE_COOLER; + else if(device_type == "led_strip") type = DEVICE_TYPE_LEDSTRIP; + else if(device_type == "keyboard") type = DEVICE_TYPE_KEYBOARD; + else if(device_type == "mouse") type = DEVICE_TYPE_MOUSE; + else if(device_type == "mousemat") type = DEVICE_TYPE_MOUSEMAT; + else if(device_type == "headset") type = DEVICE_TYPE_HEADSET; + else if(device_type == "headset_stand") type = DEVICE_TYPE_HEADSET_STAND; + else if(device_type == "gamepad") type = DEVICE_TYPE_GAMEPAD; + else if(device_type == "light") type = DEVICE_TYPE_LIGHT; + else if(device_type == "speaker") type = DEVICE_TYPE_SPEAKER; + else if(device_type == "unknown") type = DEVICE_TYPE_UNKNOWN; } else { - std::string name_setting = ""; - std::string type_setting = "keyboard"; - - if(debug_settings.contains("name")) - { - name_setting = debug_settings["name"]; - } - - if(debug_settings.contains("type")) - { - type_setting = debug_settings["type"]; - } + std::string name_setting = JsonUtils::JsonGetString(debug_settings, "name"); + std::string type_setting = JsonUtils::JsonGetString(debug_settings, "type", "keyboard"); if(type_setting == "motherboard") { - name = "Debug Motherboard"; - type = DEVICE_TYPE_MOTHERBOARD; + name = "Debug Motherboard"; + type = DEVICE_TYPE_MOTHERBOARD; } else if(type_setting == "dram") { - name = "Debug DRAM"; - type = DEVICE_TYPE_DRAM; + name = "Debug DRAM"; + type = DEVICE_TYPE_DRAM; } else if(type_setting == "gpu") { - name = "Debug GPU"; - type = DEVICE_TYPE_GPU; + name = "Debug GPU"; + type = DEVICE_TYPE_GPU; } else if(type_setting == "keyboard") { - name = "Debug Keyboard"; - type = DEVICE_TYPE_KEYBOARD; + name = "Debug Keyboard"; + type = DEVICE_TYPE_KEYBOARD; } else if(type_setting == "mouse") { - name = "Debug Mouse"; - type = DEVICE_TYPE_MOUSE; + name = "Debug Mouse"; + type = DEVICE_TYPE_MOUSE; } else if(type_setting == "argb") { - name = "Debug ARGB Controller"; - type = DEVICE_TYPE_LEDSTRIP; + name = "Debug ARGB Controller"; + type = DEVICE_TYPE_LEDSTRIP; } /*---------------------------------------------------------*\ @@ -143,6 +133,41 @@ RGBController_Debug::RGBController_Debug(bool custom, json settings) { name = name_setting; } + + /*---------------------------------------------------------*\ + | Create test configuration | + \*---------------------------------------------------------*/ + nlohmann::json configuration_json; + JsonUtils::JsonParse(configuration, configuration_json); + + configuration_json["schema"]["test_string"]["title"] = "String Setting"; + configuration_json["schema"]["test_string"]["type"] = "string"; + + configuration_json["schema"]["test_bool"]["title"] = "Boolean Setting"; + configuration_json["schema"]["test_bool"]["type"] = "bool"; + + configuration_json["schema"]["test_enum"]["title"] = "String Enum Setting"; + configuration_json["schema"]["test_enum"]["type"] = "string"; + configuration_json["schema"]["test_enum"]["enum"][0] = "Option 1"; + configuration_json["schema"]["test_enum"]["enum"][1] = "Option 2"; + configuration_json["schema"]["test_enum"]["enum"][2] = "Option 3"; + + configuration_json["schema"]["test_enum_int"]["title"] = "Integer Enum Setting"; + configuration_json["schema"]["test_enum_int"]["type"] = "integer"; + configuration_json["schema"]["test_enum_int"]["enum"][0] = 2; + configuration_json["schema"]["test_enum_int"]["enum"][1] = 4; + configuration_json["schema"]["test_enum_int"]["enum"][2] = 8; + + configuration_json["schema"]["test_int"]["title"] = "Integer Setting"; + configuration_json["schema"]["test_int"]["type"] = "integer"; + + configuration_json["configuration"]["test_string"] = "This is a test"; + configuration_json["configuration"]["test_bool"] = true; + configuration_json["configuration"]["test_enum"] = "Option 2"; + configuration_json["configuration"]["test_enum_int"] = 4; + configuration_json["configuration"]["test_int"] = 12345; + + configuration = configuration_json.dump(); } /*-----------------------------------------------------*\ @@ -181,6 +206,7 @@ void RGBController_Debug::SetupZones() /*-------------------------------------------------*\ | Clear any existing color/LED configuration | \*-------------------------------------------------*/ + led_alt_names.clear(); leds.clear(); colors.clear(); @@ -216,9 +242,9 @@ void RGBController_Debug::SetupZones() continue; } - custom_zone.leds_min = ZoneJson["leds_min"]; - custom_zone.leds_max = ZoneJson["leds_max"]; - custom_zone.leds_count = ZoneJson["leds_count"]; + custom_zone.leds_min = JsonUtils::JsonGetInt(ZoneJson, "leds_min"); + custom_zone.leds_max = JsonUtils::JsonGetInt(ZoneJson, "leds_max"); + custom_zone.leds_count = JsonUtils::JsonGetInt(ZoneJson, "leds_count"); /*---------------------------------------------*\ | Fill in the matrix map | @@ -241,8 +267,8 @@ void RGBController_Debug::SetupZones() continue; } - unsigned int H = ZoneJson["matrix_width"]; - unsigned int W = ZoneJson["matrix_height"]; + unsigned int H = JsonUtils::JsonGetInt(ZoneJson, "matrix_width"); + unsigned int W = JsonUtils::JsonGetInt(ZoneJson, "matrix_height"); BadVal = ((unsigned int)ZoneJson["matrix_map"].size() != H); @@ -333,36 +359,11 @@ void RGBController_Debug::SetupZones() } else { - bool zone_single = true; - bool zone_linear = true; - bool zone_resizable = false; - bool zone_keyboard = false; - bool zone_underglow = false; - - if(debug_settings.contains("single")) - { - zone_single = debug_settings["single"]; - } - - if(debug_settings.contains("linear")) - { - zone_linear = debug_settings["linear"]; - } - - if(debug_settings.contains("resizable")) - { - zone_resizable = debug_settings["resizable"]; - } - - if(debug_settings.contains("keyboard")) - { - zone_keyboard = debug_settings["keyboard"]; - } - - if(debug_settings.contains("underglow")) - { - zone_underglow = debug_settings["underglow"]; - } + bool zone_single = JsonUtils::JsonGetBool(debug_settings, "single", true); + bool zone_linear = JsonUtils::JsonGetBool(debug_settings, "linear", true); + bool zone_resizable = JsonUtils::JsonGetBool(debug_settings, "resizable", false); + bool zone_keyboard = JsonUtils::JsonGetBool(debug_settings, "keyboard", false); + bool zone_underglow = JsonUtils::JsonGetBool(debug_settings, "underglow", false); /*-------------------------------------------------*\ | Create a single zone/LED | @@ -371,21 +372,23 @@ void RGBController_Debug::SetupZones() { zone single_zone; - single_zone.name = "Single Zone"; - single_zone.type = ZONE_TYPE_SINGLE; - single_zone.leds_min = 1; - single_zone.leds_max = 1; - single_zone.leds_count = 1; - if(first_run) { zones.push_back(single_zone); } - else + + zones[zone_idx].name = "Single Zone"; + zones[zone_idx].type = ZONE_TYPE_SINGLE; + + if(first_run) { - zones[zone_idx] = single_zone; + zones[zone_idx].flags = ZONE_FLAG_MANUALLY_CONFIGURABLE_DEVICE_SPECIFIC; } + zones[zone_idx].leds_min = 1; + zones[zone_idx].leds_max = 1; + zones[zone_idx].leds_count = 1; + led single_led; single_led.name = "Single LED"; @@ -394,6 +397,27 @@ void RGBController_Debug::SetupZones() led_alt_names.push_back(""); + nlohmann::json configuration_json; + JsonUtils::JsonParse(configuration, configuration_json); + + if(first_run) + { + /*-----------------------------------------*\ + | Create test configuration | + \*-----------------------------------------*/ + configuration_json["zones"][zone_idx]["schema"]["color_order"]["title"] = "Color Order"; + configuration_json["zones"][zone_idx]["schema"]["color_order"]["type"] = "string"; + configuration_json["zones"][zone_idx]["schema"]["color_order"]["enum"][0] = "RGB"; + configuration_json["zones"][zone_idx]["schema"]["color_order"]["enum"][1] = "GRB"; + } + + if((zones[zone_idx].flags & ZONE_FLAG_MANUALLY_CONFIGURED_DEVICE_SPECIFIC) == 0) + { + configuration_json["zones"][zone_idx]["configuration"]["color_order"] = "RGB"; + } + + configuration = configuration_json.dump(); + zone_idx++; } @@ -404,22 +428,18 @@ void RGBController_Debug::SetupZones() { zone linear_zone; - linear_zone.name = "Linear Zone"; - linear_zone.type = ZONE_TYPE_LINEAR; - linear_zone.leds_min = 10; - linear_zone.leds_max = 10; - linear_zone.leds_count = 10; - if(first_run) { zones.push_back(linear_zone); } - else - { - zones[zone_idx] = linear_zone; - } - for(std::size_t led_idx = 0; led_idx < 10; led_idx++) + zones[zone_idx].name = "Linear Zone"; + zones[zone_idx].type = ZONE_TYPE_LINEAR; + zones[zone_idx].leds_min = 10; + zones[zone_idx].leds_max = 10; + zones[zone_idx].leds_count = 10; + + for(std::size_t led_idx = 0; led_idx < zones[zone_idx].leds_count; led_idx++) { led linear_led; @@ -441,6 +461,24 @@ void RGBController_Debug::SetupZones() KEYBOARD_LAYOUT layout = KEYBOARD_LAYOUT::KEYBOARD_LAYOUT_ANSI_QWERTY; KEYBOARD_SIZE size = KEYBOARD_SIZE::KEYBOARD_SIZE_FULL; + nlohmann::json configuration_json; + JsonUtils::JsonParse(configuration, configuration_json); + + zone keyboard_zone; + + if(first_run) + { + zones.push_back(keyboard_zone); + } + + zones[zone_idx].name = "Keyboard Zone"; + zones[zone_idx].type = ZONE_TYPE_MATRIX; + + if(first_run) + { + zones[zone_idx].flags = ZONE_FLAG_MANUALLY_CONFIGURABLE_DEVICE_SPECIFIC | ZONE_FLAG_ZONE_GEOMETRY_MAY_CHANGE; + } + if(debug_settings.contains("layout")) { KEYBOARD_LAYOUT temp_layout = debug_settings["layout"]; @@ -451,6 +489,29 @@ void RGBController_Debug::SetupZones() } } + if(zones[zone_idx].flags & ZONE_FLAG_MANUALLY_CONFIGURED_DEVICE_SPECIFIC) + { + if(configuration_json.contains("zones") && (zone_idx < (int)configuration_json["zones"].size())) + { + if(configuration_json["zones"][zone_idx].contains("configuration")) + { + if(configuration_json["zones"][zone_idx]["configuration"].contains("layout")) + { + std::string layout_string = configuration_json["zones"][zone_idx]["configuration"]["layout"]; + + for(std::size_t layout_idx = 0; layout_idx < NUM_LAYOUTS; layout_idx++) + { + if(layout_names[layout_idx] == layout_string) + { + layout = (KEYBOARD_LAYOUT)layout_idx; + break; + } + } + } + } + } + } + if(debug_settings.contains("size")) { size = debug_settings["size"]; @@ -458,8 +519,6 @@ void RGBController_Debug::SetupZones() KeyboardLayoutManager new_kb(layout, size); - description += ", Layout: " + layout_names[layout] + ", Size: " + new_kb.GetName(); - /*---------------------------------------------*\ | Check for custom key inserts and swaps | \*---------------------------------------------*/ @@ -518,25 +577,12 @@ void RGBController_Debug::SetupZones() new_kb.ChangeKeys(change); } - zone keyboard_zone; + zones[zone_idx].leds_min = new_kb.GetKeyCount(); + zones[zone_idx].leds_max = new_kb.GetKeyCount(); + zones[zone_idx].leds_count = new_kb.GetKeyCount(); + zones[zone_idx].matrix_map = new_kb.GetKeyMap(KEYBOARD_MAP_FILL_TYPE_COUNT); - keyboard_zone.name = "Keyboard Zone"; - keyboard_zone.type = ZONE_TYPE_MATRIX; - keyboard_zone.leds_min = new_kb.GetKeyCount(); - keyboard_zone.leds_max = new_kb.GetKeyCount(); - keyboard_zone.leds_count = new_kb.GetKeyCount(); - keyboard_zone.matrix_map = new_kb.GetKeyMap(KEYBOARD_MAP_FILL_TYPE_COUNT); - - if(first_run) - { - zones.push_back(keyboard_zone); - } - else - { - zones[zone_idx] = keyboard_zone; - } - - for(unsigned int led_idx = 0; led_idx < keyboard_zone.leds_count; led_idx++) + for(unsigned int led_idx = 0; led_idx < zones[zone_idx].leds_count; led_idx++) { led keyboard_led; @@ -547,6 +593,28 @@ void RGBController_Debug::SetupZones() led_alt_names.push_back(new_kb.GetKeyAltNameAt(led_idx)); } + if(first_run) + { + /*-----------------------------------------*\ + | Create test configuration | + \*-----------------------------------------*/ + configuration_json["zones"][zone_idx]["schema"]["layout"]["title"] = "Layout"; + configuration_json["zones"][zone_idx]["schema"]["layout"]["type"] = "string"; + configuration_json["zones"][zone_idx]["schema"]["layout"]["enum"][0] = "Default", + configuration_json["zones"][zone_idx]["schema"]["layout"]["enum"][1] = "ANSI QWERTY"; + configuration_json["zones"][zone_idx]["schema"]["layout"]["enum"][2] = "ISO QWERTY"; + configuration_json["zones"][zone_idx]["schema"]["layout"]["enum"][3] = "ISO QWERTZ"; + configuration_json["zones"][zone_idx]["schema"]["layout"]["enum"][4] = "ISO AZERTY"; + configuration_json["zones"][zone_idx]["schema"]["layout"]["enum"][5] = "JIS"; + } + + if((zones[zone_idx].flags & ZONE_FLAG_MANUALLY_CONFIGURED_DEVICE_SPECIFIC) == 0) + { + configuration_json["zones"][zone_idx]["configuration"]["layout"] = "Default"; + } + + configuration = configuration_json.dump(); + zone_idx++; } @@ -674,3 +742,13 @@ void RGBController_Debug::DeviceUpdateMode() { } + +void RGBController_Debug::DeviceUpdateDeviceSpecificConfiguration() +{ + +} + +void RGBController_Debug::DeviceUpdateDeviceSpecificZoneConfiguration(int zone) +{ + SetupZones(); +} diff --git a/Controllers/DebugController/RGBController_Debug.h b/Controllers/DebugController/RGBController_Debug.h index db5a81726..8ff8868d0 100644 --- a/Controllers/DebugController/RGBController_Debug.h +++ b/Controllers/DebugController/RGBController_Debug.h @@ -33,6 +33,9 @@ public: void DeviceUpdateMode(); + void DeviceUpdateDeviceSpecificConfiguration(); + void DeviceUpdateDeviceSpecificZoneConfiguration(int zone); + private: json debug_settings; bool custom_controller; diff --git a/Controllers/E131Controller/RGBController_E131.cpp b/Controllers/E131Controller/RGBController_E131.cpp index 833b1a4da..f274814f0 100644 --- a/Controllers/E131Controller/RGBController_E131.cpp +++ b/Controllers/E131Controller/RGBController_E131.cpp @@ -235,8 +235,7 @@ void RGBController_E131::SetupZones() led_zone.leds_count = devices[zone_idx].num_leds; led_zone.flags = ZONE_FLAG_MANUALLY_CONFIGURABLE_TYPE | ZONE_FLAG_MANUALLY_CONFIGURABLE_MATRIX_MAP - | ZONE_FLAG_MANUALLY_CONFIGURABLE_SEGMENTS - | ZONE_FLAG_MANUALLY_CONFIGURABLE_COLOR_ORDER; + | ZONE_FLAG_MANUALLY_CONFIGURABLE_SEGMENTS; zones.push_back(led_zone); } diff --git a/Controllers/ElgatoLightStripController/ElgatoLightStripController.cpp b/Controllers/ElgatoLightStripController/ElgatoLightStripController.cpp index 6c46e2583..1631eda93 100644 --- a/Controllers/ElgatoLightStripController/ElgatoLightStripController.cpp +++ b/Controllers/ElgatoLightStripController/ElgatoLightStripController.cpp @@ -13,8 +13,9 @@ #include #include #include -#include "ElgatoLightStripController.h" #include +#include "ElgatoLightStripController.h" +#include "JsonUtils.h" #include "LogManager.h" using json = nlohmann::json; @@ -58,7 +59,8 @@ ElgatoLightStripController::ElgatoLightStripController(std::string ip) } std::string result = recv_list[5]; - json elgato_lightstrip_data = json::parse(result); + json elgato_lightstrip_data; + JsonUtils::JsonParse(result, elgato_lightstrip_data); firmware_version = elgato_lightstrip_data["firmwareVersion"]; serialnumber = elgato_lightstrip_data["serialNumber"]; diff --git a/Controllers/GoveeController/GoveeController.cpp b/Controllers/GoveeController/GoveeController.cpp index 7f346b249..c43c42fd9 100644 --- a/Controllers/GoveeController/GoveeController.cpp +++ b/Controllers/GoveeController/GoveeController.cpp @@ -13,6 +13,7 @@ #include #include "base64.hpp" #include "GoveeController.h" +#include "JsonUtils.h" using json = nlohmann::json; using namespace std::chrono_literals; @@ -106,7 +107,8 @@ void GoveeController::ReceiveBroadcast(char* recv_buf, int size) /*-----------------------------------------------------*\ | Convert null-terminated response to JSON | \*-----------------------------------------------------*/ - json response = json::parse(recv_buf); + json response; + JsonUtils::JsonParse(recv_buf, response); /*-----------------------------------------------------*\ | Check if the response contains the method name | diff --git a/Controllers/KasaSmartController/KasaSmartController.cpp b/Controllers/KasaSmartController/KasaSmartController.cpp index d26630a8c..4cacc6837 100644 --- a/Controllers/KasaSmartController/KasaSmartController.cpp +++ b/Controllers/KasaSmartController/KasaSmartController.cpp @@ -10,8 +10,9 @@ \*---------------------------------------------------------*/ #include -#include "KasaSmartController.h" #include +#include "JsonUtils.h" +#include "KasaSmartController.h" #include "hsv.h" using json = nlohmann::json; @@ -64,11 +65,7 @@ bool KasaSmartController::Initialize() } json system_information; - try - { - system_information = json::parse(system_info_json); - } - catch (json::parse_error&) + if(!JsonUtils::JsonParse(system_info_json, system_information)) { /*-----------------------*\ | Can't parse system info | diff --git a/Controllers/NanoleafController/NanoleafController.cpp b/Controllers/NanoleafController/NanoleafController.cpp index b239bd17f..2ff5fc507 100644 --- a/Controllers/NanoleafController/NanoleafController.cpp +++ b/Controllers/NanoleafController/NanoleafController.cpp @@ -12,6 +12,7 @@ #include "NanoleafController.h" #include "LogManager.h" #include "httplib.h" +#include "JsonUtils.h" long APIRequest(std::string method, std::string location, std::string URI, json* request_data = nullptr, json* response_data = nullptr) { @@ -91,7 +92,7 @@ long APIRequest(std::string method, std::string location, std::string URI, json* { if(response_data) { - *response_data = json::parse(body); + JsonUtils::JsonParse(body, *response_data); } } else diff --git a/Controllers/PhilipsWizController/PhilipsWizController.cpp b/Controllers/PhilipsWizController/PhilipsWizController.cpp index 0a06d60de..99f82a78e 100644 --- a/Controllers/PhilipsWizController/PhilipsWizController.cpp +++ b/Controllers/PhilipsWizController/PhilipsWizController.cpp @@ -9,8 +9,9 @@ | SPDX-License-Identifier: GPL-2.0-or-later | \*---------------------------------------------------------*/ -#include "PhilipsWizController.h" #include +#include "JsonUtils.h" +#include "PhilipsWizController.h" using json = nlohmann::json; using namespace std::chrono_literals; @@ -194,7 +195,8 @@ void PhilipsWizController::ReceiveThreadFunction() /*-----------------------------------------------------------------*\ | Convert null-terminated response to JSON | \*-----------------------------------------------------------------*/ - json response = json::parse(recv_buf); + json response; + JsonUtils::JsonParse(recv_buf, response); /*-----------------------------------------------------------------*\ | Check if the response contains the method name | diff --git a/DetectionManager.cpp b/DetectionManager.cpp index 3a072c03e..989b68699 100644 --- a/DetectionManager.cpp +++ b/DetectionManager.cpp @@ -12,6 +12,7 @@ #include #include "DetectionManager.h" +#include "JsonUtils.h" #include "LogManager.h" #include "pci_ids.h" #include "ProfileManager.h" @@ -30,11 +31,6 @@ using namespace std::chrono_literals; \*---------------------------------------------------------*/ const char* DETECTIONMANAGER = "DetectionManager"; -/*---------------------------------------------------------*\ -| Define a macro for QT lupdate to parse | -\*---------------------------------------------------------*/ -#define QT_TRANSLATE_NOOP(scope, x) x - /*---------------------------------------------------------*\ | Warning Strings | \*---------------------------------------------------------*/ @@ -597,8 +593,6 @@ void DetectionManager::BackgroundDetectDevices() hid_device_info* current_hid_device; json detector_settings; hid_device_info* hid_devices = NULL; - bool hid_safe_mode = false; - unsigned int initial_detection_delay_ms = 0; LOG_INFO("------------------------------------------------------"); LOG_INFO("| Start device detection |"); @@ -621,18 +615,12 @@ void DetectionManager::BackgroundDetectDevices() /*-----------------------------------------------------*\ | Check HID safe mode setting | \*-----------------------------------------------------*/ - if(detector_settings.contains("hid_safe_mode")) - { - hid_safe_mode = detector_settings["hid_safe_mode"]; - } + bool hid_safe_mode = JsonUtils::JsonGetBool(detector_settings, "hid_safe_mode"); /*-----------------------------------------------------*\ | Check initial detection delay setting | \*-----------------------------------------------------*/ - if(detector_settings.contains("initial_detection_delay_ms")) - { - initial_detection_delay_ms = detector_settings["initial_detection_delay_ms"]; - } + unsigned int initial_detection_delay_ms = JsonUtils::JsonGetInt(detector_settings, "initial_detection_delay_ms"); /*-----------------------------------------------------*\ | If configured, delay detection for the configured | diff --git a/Documentation/OpenRGBSDK.md b/Documentation/OpenRGBSDK.md index d2899f53f..1c89d168c 100644 --- a/Documentation/OpenRGBSDK.md +++ b/Documentation/OpenRGBSDK.md @@ -45,45 +45,47 @@ Each packet starts with a header that indicates the packet is an OpenRGB SDK pac The following IDs represent different SDK commands. Each ID packet has a certain format of data associated with it, which will be explained under each ID's section of this document. Gaps have been left in the ID values to allow for future expansion. The same ID values are often used for both request and response packets. -| Value | Name | Description | Protocol Version | -| ----- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | ---------------- | -| 0 | [NET_PACKET_ID_REQUEST_CONTROLLER_COUNT](#net_packet_id_request_controller_count) | Request RGBController device count/device IDs from server | 0 | -| 1 | [NET_PACKET_ID_REQUEST_CONTROLLER_DATA](#net_packet_id_request_controller_data) | Request RGBController data block | 0 | -| 10 | [NET_PACKET_ID_ACK](#net_packet_id_ack) | Acknowledgement | 6 | -| 40 | [NET_PACKET_ID_REQUEST_PROTOCOL_VERSION](#net_packet_id_request_protocol_version) | Request OpenRGB SDK protocol version from server | 1* | -| 50 | [NET_PACKET_ID_SET_CLIENT_NAME](#net_packet_id_set_client_name) | Send client name string to server | 0 | -| 51 | [NET_PACKET_ID_SET_SERVER_NAME](#net_packet_id_set_server_name) | Send server name string to client | 6 | -| 52 | [NET_PACKET_ID_SET_CLIENT_FLAGS](#net_packet_id_set_client_flags) | Send client flags to server | 6 | -| 53 | [NET_PACKET_ID_SET_SERVER_FLAGS](#net_packet_id_set_server_flags) | Send server flags to client | 6 | -| 100 | [NET_PACKET_ID_DEVICE_LIST_UPDATED](#net_packet_id_device_list_updated) | Indicate to clients that device list has updated | 1 | -| 101 | [NET_PACKET_ID_DETECTION_STARTED](#net_packet_id_detection_started) | Indicate to clients that detection started | 6 | -| 102 | [NET_PACKET_ID_DETECTION_PROGRESS_CHANGED](#net_packet_id_detection_progress_changed) | Indicate to clients that detection progress changed | 6 | -| 103 | [NET_PACKET_ID_DETECTION_COMPLETE](#net_packet_id_detection_complete) | Indicate to clients that detection completed | 6 | -| 140 | [NET_PACKET_ID_REQUEST_RESCAN_DEVICES](#net_packet_id_request_rescan_devices) | Request server to rescan devices | 5 | -| 150 | [NET_PACKET_ID_PROFILEMANAGER_GET_PROFILE_LIST](#net_packet_id_profilemanager_get_profile_list) | Get profile list | 2 | -| 151 | [NET_PACKET_ID_PROFILEMANAGER_SAVE_PROFILE](#net_packet_id_profilemanager_save_profile) | Save current configuration in a new profile | 2 | -| 152 | [NET_PACKET_ID_PROFILEMANAGER_LOAD_PROFILE](#net_packet_id_profilemanager_load_profile) | Load a given profile | 2 | -| 153 | [NET_PACKET_ID_PROFILEMANAGER_DELETE_PROFILE](#net_packet_id_profilemanager_delete_profile) | Delete a given profile | 2 | -| 154 | [NET_PACKET_ID_PROFILEMANAGER_UPLOAD_PROFILE](#net_packet_id_profilemanager_upload_profile) | Upload a profile to the server in JSON format | 6 | -| 155 | [NET_PACKET_ID_PROFILEMANAGER_DOWNLOAD_PROFILE](#net_packet_id_profilemanager_download_profile) | Download a profile from the server in JSON format | 6 | -| 156 | [NET_PACKET_ID_PROFILEMANAGER_GET_ACTIVE_PROFILE](#net_packet_id_profilemanager_get_active_profile) | Get the active profile name | 6 | -| 200 | [NET_PACKET_ID_PLUGINMANAGER_GET_PLUGIN_LIST](#net_packet_id_pluginmanager_get_plugin_list) | Get list of plugins | 4 | -| 201 | [NET_PACKET_ID_PLUGINMANAGER_PLUGIN_SPECIFIC](#net_packet_id_pluginmanager_plugin_specific) | Interact with a plugin | 4 | -| 250 | [NET_PACKET_ID_SETTINGSMANAGER_GET_SETTINGS](#net_packet_id_settingsmanager_get_settings) | Get settings for a given key in JSON format | 6 | -| 251 | [NET_PACKET_ID_SETTINGSMANAGER_SET_SETTINGS](#net_packet_id_settingsmanager_set_settings) | Set settings for a given key in JSON format | 6 | -| 252 | [NET_PACKET_ID_SETTINGSMANAGER_SAVE_SETTINGS](#net_packet_id_settingsmanager_save_settings) | Save settings | 6 | -| 1000 | [NET_PACKET_ID_RGBCONTROLLER_RESIZEZONE](#net_packet_id_rgbcontroller_resizezone) | RGBController::ResizeZone() | 0 | -| 1001 | [NET_PACKET_ID_RGBCONTROLLER_CLEARSEGMENTS](#net_packet_id_rgbcontroller_clearsegments) | RGBController::ClearSegments() | 5 | -| 1002 | [NET_PACKET_ID_RGBCONTROLLER_ADDSEGMENT](#net_packet_id_rgbcontroller_addsegment) | RGBController::AddSegment() | 5 | -| 1003 | [NET_PACKET_ID_RGBCONTROLLER_CONFIGUREZONE](#net_packet_id_rgbcontroller_configurezone) | RGBController::ConfigureZone() | 6 | -| 1050 | [NET_PACKET_ID_RGBCONTROLLER_UPDATELEDS](#net_packet_id_rgbcontroller_updateleds) | RGBController::UpdateLEDs() | 0 | -| 1051 | [NET_PACKET_ID_RGBCONTROLLER_UPDATEZONELEDS](#net_packet_id_rgbcontroller_updatezoneleds) | RGBController::UpdateZoneLEDs() | 0 | -| 1052 | [NET_PACKET_ID_RGBCONTROLLER_UPDATESINGLELED](#net_packet_id_rgbcontroller_updatesingleled) | RGBController::UpdateSingleLED() | 0 | -| 1100 | [NET_PACKET_ID_RGBCONTROLLER_SETCUSTOMMODE](#net_packet_id_rgbcontroller_setcustommode) | RGBController::SetCustomMode() | 0 | -| 1101 | [NET_PACKET_ID_RGBCONTROLLER_UPDATEMODE](#net_packet_id_rgbcontroller_updatemode) | RGBController::UpdateMode() | 0 | -| 1102 | [NET_PACKET_ID_RGBCONTROLLER_SAVEMODE](#net_packet_id_rgbcontroller_savemode) | RGBController::SaveMode() | 3 | -| 1103 | [NET_PACKET_ID_RGBCONTROLLER_UPDATEZONEMODE](#net_packet_id_rgbcontroller_updatezonemode) | RGBController::UpdateZoneMode() | 6 | -| 1150 | [NET_PACKET_ID_RGBCONTROLLER_SIGNALUPDATE](#net_packet_id_rgbcontroller_signalupdate) | RGBController::SignalUpdate() | 6 | +| Value | Name | Description | Protocol Version | +| ----- | --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | ---------------- | +| 0 | [NET_PACKET_ID_REQUEST_CONTROLLER_COUNT](#net_packet_id_request_controller_count) | Request RGBController device count/device IDs from server | 0 | +| 1 | [NET_PACKET_ID_REQUEST_CONTROLLER_DATA](#net_packet_id_request_controller_data) | Request RGBController data block | 0 | +| 10 | [NET_PACKET_ID_ACK](#net_packet_id_ack) | Acknowledgement | 6 | +| 40 | [NET_PACKET_ID_REQUEST_PROTOCOL_VERSION](#net_packet_id_request_protocol_version) | Request OpenRGB SDK protocol version from server | 1* | +| 50 | [NET_PACKET_ID_SET_CLIENT_NAME](#net_packet_id_set_client_name) | Send client name string to server | 0 | +| 51 | [NET_PACKET_ID_SET_SERVER_NAME](#net_packet_id_set_server_name) | Send server name string to client | 6 | +| 52 | [NET_PACKET_ID_SET_CLIENT_FLAGS](#net_packet_id_set_client_flags) | Send client flags to server | 6 | +| 53 | [NET_PACKET_ID_SET_SERVER_FLAGS](#net_packet_id_set_server_flags) | Send server flags to client | 6 | +| 100 | [NET_PACKET_ID_DEVICE_LIST_UPDATED](#net_packet_id_device_list_updated) | Indicate to clients that device list has updated | 1 | +| 101 | [NET_PACKET_ID_DETECTION_STARTED](#net_packet_id_detection_started) | Indicate to clients that detection started | 6 | +| 102 | [NET_PACKET_ID_DETECTION_PROGRESS_CHANGED](#net_packet_id_detection_progress_changed) | Indicate to clients that detection progress changed | 6 | +| 103 | [NET_PACKET_ID_DETECTION_COMPLETE](#net_packet_id_detection_complete) | Indicate to clients that detection completed | 6 | +| 140 | [NET_PACKET_ID_REQUEST_RESCAN_DEVICES](#net_packet_id_request_rescan_devices) | Request server to rescan devices | 5 | +| 150 | [NET_PACKET_ID_PROFILEMANAGER_GET_PROFILE_LIST](#net_packet_id_profilemanager_get_profile_list) | Get profile list | 2 | +| 151 | [NET_PACKET_ID_PROFILEMANAGER_SAVE_PROFILE](#net_packet_id_profilemanager_save_profile) | Save current configuration in a new profile | 2 | +| 152 | [NET_PACKET_ID_PROFILEMANAGER_LOAD_PROFILE](#net_packet_id_profilemanager_load_profile) | Load a given profile | 2 | +| 153 | [NET_PACKET_ID_PROFILEMANAGER_DELETE_PROFILE](#net_packet_id_profilemanager_delete_profile) | Delete a given profile | 2 | +| 154 | [NET_PACKET_ID_PROFILEMANAGER_UPLOAD_PROFILE](#net_packet_id_profilemanager_upload_profile) | Upload a profile to the server in JSON format | 6 | +| 155 | [NET_PACKET_ID_PROFILEMANAGER_DOWNLOAD_PROFILE](#net_packet_id_profilemanager_download_profile) | Download a profile from the server in JSON format | 6 | +| 156 | [NET_PACKET_ID_PROFILEMANAGER_GET_ACTIVE_PROFILE](#net_packet_id_profilemanager_get_active_profile) | Get the active profile name | 6 | +| 200 | [NET_PACKET_ID_PLUGINMANAGER_GET_PLUGIN_LIST](#net_packet_id_pluginmanager_get_plugin_list) | Get list of plugins | 4 | +| 201 | [NET_PACKET_ID_PLUGINMANAGER_PLUGIN_SPECIFIC](#net_packet_id_pluginmanager_plugin_specific) | Interact with a plugin | 4 | +| 250 | [NET_PACKET_ID_SETTINGSMANAGER_GET_SETTINGS](#net_packet_id_settingsmanager_get_settings) | Get settings for a given key in JSON format | 6 | +| 251 | [NET_PACKET_ID_SETTINGSMANAGER_SET_SETTINGS](#net_packet_id_settingsmanager_set_settings) | Set settings for a given key in JSON format | 6 | +| 252 | [NET_PACKET_ID_SETTINGSMANAGER_SAVE_SETTINGS](#net_packet_id_settingsmanager_save_settings) | Save settings | 6 | +| 1000 | [NET_PACKET_ID_RGBCONTROLLER_RESIZEZONE](#net_packet_id_rgbcontroller_resizezone) | RGBController::ResizeZone() | 0 | +| 1001 | [NET_PACKET_ID_RGBCONTROLLER_CLEARSEGMENTS](#net_packet_id_rgbcontroller_clearsegments) | RGBController::ClearSegments() | 5 | +| 1002 | [NET_PACKET_ID_RGBCONTROLLER_ADDSEGMENT](#net_packet_id_rgbcontroller_addsegment) | RGBController::AddSegment() | 5 | +| 1003 | [NET_PACKET_ID_RGBCONTROLLER_CONFIGUREZONE](#net_packet_id_rgbcontroller_configurezone) | RGBController::ConfigureZone() | 6 | +| 1050 | [NET_PACKET_ID_RGBCONTROLLER_UPDATELEDS](#net_packet_id_rgbcontroller_updateleds) | RGBController::UpdateLEDs() | 0 | +| 1051 | [NET_PACKET_ID_RGBCONTROLLER_UPDATEZONELEDS](#net_packet_id_rgbcontroller_updatezoneleds) | RGBController::UpdateZoneLEDs() | 0 | +| 1052 | [NET_PACKET_ID_RGBCONTROLLER_UPDATESINGLELED](#net_packet_id_rgbcontroller_updatesingleled) | RGBController::UpdateSingleLED() | 0 | +| 1100 | [NET_PACKET_ID_RGBCONTROLLER_SETCUSTOMMODE](#net_packet_id_rgbcontroller_setcustommode) | RGBController::SetCustomMode() | 0 | +| 1101 | [NET_PACKET_ID_RGBCONTROLLER_UPDATEMODE](#net_packet_id_rgbcontroller_updatemode) | RGBController::UpdateMode() | 0 | +| 1102 | [NET_PACKET_ID_RGBCONTROLLER_SAVEMODE](#net_packet_id_rgbcontroller_savemode) | RGBController::SaveMode() | 3 | +| 1103 | [NET_PACKET_ID_RGBCONTROLLER_UPDATEZONEMODE](#net_packet_id_rgbcontroller_updatezonemode) | RGBController::UpdateZoneMode() | 6 | +| 1130 | [NET_PACKET_ID_RGBCONTROLLER_SETDEVICESPECIFICCONFIGURATION](#net_packet_id_rgbcontroller_setdevicespecificconfiguration) | RGBController::SetDeviceSpecificConfiguration | 6 | +| 1131 | [NET_PACKET_ID_RGBCONTROLLER_SETDEVICESPECIFICZONECONFIGURATION](#net_packet_id_rgbcontroller_setdevicespecificzoneconfiguration) | RGBController::SetDeviceSpecificZoneConfiguration | 6 | +| 1150 | [NET_PACKET_ID_RGBCONTROLLER_SIGNALUPDATE](#net_packet_id_rgbcontroller_signalupdate) | RGBController::SignalUpdate() | 6 | \* The [NET_PACKET_ID_REQUEST_PROTOCOL_VERSION](#net_packet_id_request_protocol_version) packet was not present in protocol version 0, but clients supporting protocol versions 1+ should always send this packet. If no response is received, it should be assumed that the server is using protocol 0. @@ -162,6 +164,8 @@ The Device Data block represents an entire `RGBController`. This data block is | 2 | unsigned short | num_led_alt_names | 5 | Number of LED alternate name strings | | Variable | LED Alternate Name[num_led_alt_names] | led_alt_names | 5 | See [LED Alternate Name Data](#led-alternate-names-data) block format table. Repeat num_led_alt_names times | | 4 | unsigned int | flags | 5 | RGBController flags field value | +| 4 | unsigned int | configuration_len | 6 | Length of RGBController configuration field string, including null termination | +| configuration_len | char[configuration_len] | configuration | | RGBController configuration field string value, including null termination | ## Mode Data @@ -206,7 +210,6 @@ The Zone Data block represents one entry in the `RGBController::zones` vector. | 2 | unsigned short | zone_num_modes | 6 | Number of modes in zone | | 4 | int | zone_active_mode | 6 | Zone active_mode field value | | Variable | Mode Data[zone_num_modes] | zone_modes | 6 | See [Mode Data](#mode-data) block format table. Repeat zone_num_modes times | -| 4 | unsigned int | zone_color_order | 6 | Zone color_order field value | ## Segment Data @@ -575,6 +578,14 @@ The client uses this ID to call the SaveMode() function of an RGBController devi The client uses this ID to call the UpdateZoneMode() function of an RGBController device. The packet contains a data block. The format of the data block is shown below. The `pkt_dev_id` of this request's header indicates which controller you are calling UpdateZoneMode() on. See the [Device IDs](#device-ids) section for more information. +## NET_PACKET_ID_RGBCONTROLLER_SETDEVICESPECIFICCONFIGURATION + +The client uses this ID to call the SetDeviceSpecificConfiguration function of an RGBController device. The `pkt_dev_id` of this request's header indicates which controller you are calling SetDeviceSpecificConfiguration on. See the [Device IDs](#device-ids) section for more information. + +## NET_PACKET_ID_RGBCONTROLLER_SETDEVICESPECIFICZONECONFIGURATION + +The client uses this ID to call the SetDeviceSpecificZoneConfiguration function of an RGBController device. The `pkt_dev_id` of this request's header indicates which controller you are calling SetDeviceSpecificZoneConfiguration on. See the [Device IDs](#device-ids) section for more information. + ## NET_PACKET_ID_RGBCONTROLLER_SIGNALUPDATE The server uses this ID to signal the client that SignalUpdate() was called on an RGBController device. The packet contains a data block. The format of the data block is shown below. The `pkt_dev_id` of this request's header indicates which controller signalled SignalUpdate(). See the [Device IDs](#device-ids) section for more information. diff --git a/JsonUtils.cpp b/JsonUtils.cpp new file mode 100644 index 000000000..7a9a8a5dc --- /dev/null +++ b/JsonUtils.cpp @@ -0,0 +1,71 @@ +/*---------------------------------------------------------*\ +| JsonUtils.cpp | +| | +| JSON utility functions | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#include "JsonUtils.h" + +bool JsonUtils::JsonGetBool(nlohmann::json& val, std::string key, bool dft) +{ + if((val.contains(key)) && (val[key].type() == nlohmann::json::value_t::boolean)) + { + return((bool)val[key]); + } + else + { + return(dft); + } +} + +int JsonUtils::JsonGetInt(nlohmann::json& val, std::string key, int dft) +{ + if((val.contains(key)) && + ((val[key].type() == nlohmann::json::value_t::number_integer) || + (val[key].type() == nlohmann::json::value_t::number_unsigned) || + (val[key].type() == nlohmann::json::value_t::number_float))) + { + return((int)val[key]); + } + else + { + return(dft); + } +} + +std::string JsonUtils::JsonGetString(nlohmann::json& val, std::string key, std::string dft, bool allow_empty) +{ + if((val.contains(key)) && (val[key].type() == nlohmann::json::value_t::string)) + { + std::string ret_val = (std::string)val[key]; + + if((!allow_empty) && (ret_val == "")) + { + return(dft); + } + else + { + return(ret_val); + } + } + else + { + return(dft); + } +} + +bool JsonUtils::JsonParse(std::string json_string, nlohmann::json& json_ref) +{ + try + { + json_ref = nlohmann::json::parse(json_string); + return(true); + } + catch(...) + { + return(false); + } +} diff --git a/JsonUtils.h b/JsonUtils.h new file mode 100644 index 000000000..871253436 --- /dev/null +++ b/JsonUtils.h @@ -0,0 +1,22 @@ +/*---------------------------------------------------------*\ +| JsonUtils.h | +| | +| JSON utility functions | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#pragma once + +#include +#include "nlohmann/json.hpp" + +class JsonUtils +{ +public: + static bool JsonGetBool(nlohmann::json& val, std::string key, bool dft = false); + static int JsonGetInt(nlohmann::json& val, std::string key, int dft = 0); + static std::string JsonGetString(nlohmann::json& val, std::string key, std::string dft = "", bool allow_empty = true); + static bool JsonParse(std::string json_string, nlohmann::json& json_ref); +}; diff --git a/LogManager.cpp b/LogManager.cpp index fbef70015..4b1434257 100644 --- a/LogManager.cpp +++ b/LogManager.cpp @@ -7,15 +7,14 @@ | SPDX-License-Identifier: GPL-2.0-or-later | \*---------------------------------------------------------*/ -#include "LogManager.h" - +#include +#include +#include #include #include -#include -#include -#include - #include "filesystem.h" +#include "JsonUtils.h" +#include "LogManager.h" const char* LogManager::log_codes[] = {"FATAL:", "ERROR:", "Warning:", "Info:", "Verbose:", "Debug:", "Trace:", "Dialog:"}; @@ -80,41 +79,17 @@ void LogManager::configure(json config, const filesystem::path& defaultDir) | i.e. with the lexicographically smallest filename | | 0 or less equals no limit (default) | \*-------------------------------------------------*/ - int loglimit = 0; - if(config.contains("file_count_limit") && config["file_count_limit"].is_number_integer()) - { - loglimit = config["file_count_limit"]; - } - - if(config.contains("log_file")) - { - log_file_enabled = config["log_file"]; - } + int loglimit = JsonUtils::JsonGetInt(config, "file_count_limit"); + log_file_enabled = JsonUtils::JsonGetBool(config, "log_file"); /*-------------------------------------------------*\ | Default template for the logfile name | | The # symbol is replaced with a timestamp | \*-------------------------------------------------*/ - std::string logtempl = "OpenRGB_#.log"; + std::string logtemp = JsonUtils::JsonGetString(config, "logfile", "OpenRGB_#.log", false); if(log_file_enabled) { - /*---------------------------------------------*\ - | If the logfile is defined in the | - | configuration, use the configured name | - \*---------------------------------------------*/ - if(config.contains("logfile")) - { - const json& logfile_obj = config["logfile"]; - if(logfile_obj.is_string()) - { - std::string tmpname = config["logfile"]; - if(!tmpname.empty()) - { - logtempl = tmpname; - } - } - } /*---------------------------------------------*\ | If the # symbol is found in the log file | | name, replace it with a timestamp | @@ -124,7 +99,7 @@ void LogManager::configure(json config, const filesystem::path& defaultDir) char time_string[64]; snprintf(time_string, 64, TimestampPattern, 1900 + tmp->tm_year, tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); - std::string logname = logtempl; + std::string logname = logtemp; size_t oct = logname.find("#"); if(oct != logname.npos) { @@ -145,7 +120,7 @@ void LogManager::configure(json config, const filesystem::path& defaultDir) | "Log rotation": remove old log files | | exceeding the current configured limit | \*---------------------------------------------*/ - rotate_logs(p.parent_path(), filesystem::u8path(logtempl).filename(), loglimit); + rotate_logs(p.parent_path(), filesystem::u8path(logtemp).filename(), loglimit); /*---------------------------------------------*\ | Open the logfile | diff --git a/NetworkClient.cpp b/NetworkClient.cpp index 9953e5085..1c0eb0fa4 100644 --- a/NetworkClient.cpp +++ b/NetworkClient.cpp @@ -494,6 +494,44 @@ std::string NetworkClient::SettingsManager_GetSettings(std::string settings_key) return(response_string); } +std::string NetworkClient::SettingsManager_GetSettingsSchema(std::string settings_key) +{ + NetPacketHeader request_hdr; + std::string response_string; + + InitNetPacketHeader(&request_hdr, 0, NET_PACKET_ID_SETTINGSMANAGER_GET_SETTINGS_SCHEMA, (unsigned int)strlen(settings_key.c_str()) + 1); + + send_in_progress.lock(); + send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send(client_sock, (char *)settings_key.c_str(), request_hdr.pkt_size, MSG_NOSIGNAL); + send_in_progress.unlock(); + + std::unique_lock wait_lock(waiting_on_response_mutex); + waiting_on_response_cv.wait(wait_lock); + + if(response_header.pkt_id == NET_PACKET_ID_SETTINGSMANAGER_GET_SETTINGS_SCHEMA && response_data_ptr != NULL) + { + response_string.assign(response_data_ptr, response_header.pkt_size); + response_string = StringUtils::remove_null_terminating_chars(response_string); + delete[] response_data_ptr; + response_data_ptr = NULL; + } + + return(response_string); +} + +void NetworkClient::SettingsManager_ModifySettings(std::string settings_json_str) +{ + NetPacketHeader request_hdr; + + InitNetPacketHeader(&request_hdr, 0, NET_PACKET_ID_SETTINGSMANAGER_MODIFY_SETTINGS, (unsigned int)strlen(settings_json_str.c_str()) + 1); + + send_in_progress.lock(); + send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send(client_sock, (char *)settings_json_str.c_str(), request_hdr.pkt_size, MSG_NOSIGNAL); + send_in_progress.unlock(); +} + void NetworkClient::SettingsManager_SaveSettings() { NetPacketHeader request_hdr; @@ -718,6 +756,30 @@ void NetworkClient::SendRequest_RGBController_SaveMode(unsigned int dev_idx, uns send_in_progress.unlock(); } +void NetworkClient::SendRequest_RGBController_SetDeviceSpecificConfiguration(unsigned int dev_idx, unsigned char * data, unsigned int size) +{ + NetPacketHeader request_hdr; + + InitNetPacketHeader(&request_hdr, dev_idx, NET_PACKET_ID_RGBCONTROLLER_SETDEVICESPECIFICCONFIGURATION, size); + + send_in_progress.lock(); + send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send(client_sock, (char *)data, size, MSG_NOSIGNAL); + send_in_progress.unlock(); +} + +void NetworkClient::SendRequest_RGBController_SetDeviceSpecificZoneConfiguration(unsigned int dev_idx, unsigned char * data, unsigned int size) +{ + NetPacketHeader request_hdr; + + InitNetPacketHeader(&request_hdr, dev_idx, NET_PACKET_ID_RGBCONTROLLER_SETDEVICESPECIFICZONECONFIGURATION, size); + + send_in_progress.lock(); + send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send(client_sock, (char *)data, size, MSG_NOSIGNAL); + send_in_progress.unlock(); +} + void NetworkClient::WaitOnControllerData() { for(int i = 0; i < 1000; i++) @@ -1492,6 +1554,8 @@ void NetworkClient::ProcessRequest_RGBController_SignalUpdate(unsigned int data_ case RGBCONTROLLER_UPDATE_REASON_ADDSEGMENT: case RGBCONTROLLER_UPDATE_REASON_HIDDEN: case RGBCONTROLLER_UPDATE_REASON_UNHIDDEN: + case RGBCONTROLLER_UPDATE_REASON_SETDEVICESPECIFICCONFIGURATION: + case RGBCONTROLLER_UPDATE_REASON_SETDEVICESPECIFICZONECONFIGURATION: default: RGBController::SetDeviceDescription((unsigned char *)data_ptr, data_size, controller, GetProtocolVersion()); break; diff --git a/NetworkClient.h b/NetworkClient.h index 9552e57d3..02f4a7c9a 100644 --- a/NetworkClient.h +++ b/NetworkClient.h @@ -109,6 +109,8 @@ public: | SettingsManager functions | \*-----------------------------------------------------*/ std::string SettingsManager_GetSettings(std::string settings_key); + std::string SettingsManager_GetSettingsSchema(std::string settings_key); + void SettingsManager_ModifySettings(std::string settings_json_str); void SettingsManager_SaveSettings(); void SettingsManager_SetSettings(std::string settings_json_str); @@ -132,6 +134,9 @@ public: void SendRequest_RGBController_UpdateZoneMode(unsigned int dev_idx, unsigned char * data, unsigned int size); void SendRequest_RGBController_SaveMode(unsigned int dev_idx, unsigned char * data, unsigned int size); + void SendRequest_RGBController_SetDeviceSpecificConfiguration(unsigned int dev_idx, unsigned char * data, unsigned int size); + void SendRequest_RGBController_SetDeviceSpecificZoneConfiguration(unsigned int dev_idx, unsigned char * data, unsigned int size); + void WaitOnControllerData(); private: diff --git a/NetworkProtocol.h b/NetworkProtocol.h index d0add765c..4308267c1 100644 --- a/NetworkProtocol.h +++ b/NetworkProtocol.h @@ -147,8 +147,11 @@ enum | SettingsManager functions | \*----------------------------------------------------------------------------------------------------------*/ NET_PACKET_ID_SETTINGSMANAGER_GET_SETTINGS = 250, /* Get settings for a given key in JSON format */ - NET_PACKET_ID_SETTINGSMANAGER_SET_SETTINGS = 251, /* Set settings for a given key in JSON format */ - NET_PACKET_ID_SETTINGSMANAGER_SAVE_SETTINGS = 252, /* Save settings */ + NET_PACKET_ID_SETTINGSMANAGER_GET_SETTINGS_SCHEMA + = 251, /* Get settings schema for given key in JSON format */ + NET_PACKET_ID_SETTINGSMANAGER_MODIFY_SETTINGS = 252, /* Modify settings for a given key in JSON format */ + NET_PACKET_ID_SETTINGSMANAGER_SET_SETTINGS = 253, /* Set settings for a given key in JSON format */ + NET_PACKET_ID_SETTINGSMANAGER_SAVE_SETTINGS = 254, /* Save settings */ /*----------------------------------------------------------------------------------------------------------*\ | RGBController functions | @@ -167,6 +170,12 @@ enum NET_PACKET_ID_RGBCONTROLLER_SAVEMODE = 1102, /* RGBController::SaveMode() */ NET_PACKET_ID_RGBCONTROLLER_UPDATEZONEMODE = 1103, /* RGBController::UpdateZoneMode() */ + NET_PACKET_ID_RGBCONTROLLER_SETDEVICESPECIFICCONFIGURATION + = 1130, /* RGBController::SetDeviceSpecificConfiguration() */ + NET_PACKET_ID_RGBCONTROLLER_SETDEVICESPECIFICZONECONFIGURATION + = 1131, /* RGBController:: */ + /* SetDeviceSpecificZoneConfiguration() */ + NET_PACKET_ID_RGBCONTROLLER_SIGNALUPDATE = 1150, /* RGBController::SignalUpdate() */ }; diff --git a/NetworkServer.cpp b/NetworkServer.cpp index cde3a0474..afa5c3e89 100644 --- a/NetworkServer.cpp +++ b/NetworkServer.cpp @@ -11,6 +11,7 @@ #include #include +#include "JsonUtils.h" #include "LogManager.h" #include "NetworkServer.h" #include "StringUtils.h" @@ -1244,6 +1245,14 @@ void NetworkServer::ListenThreadFunction(NetworkClientInfo * client_info) status = ProcessRequest_SettingsManager_GetSettings(client_info, header.pkt_size, data); break; + case NET_PACKET_ID_SETTINGSMANAGER_GET_SETTINGS_SCHEMA: + status = ProcessRequest_SettingsManager_GetSettingsSchema(client_info, header.pkt_size, data); + break; + + case NET_PACKET_ID_SETTINGSMANAGER_MODIFY_SETTINGS: + status = ProcessRequest_SettingsManager_ModifySettings(client_info, header.pkt_size, data); + break; + case NET_PACKET_ID_SETTINGSMANAGER_SET_SETTINGS: status = ProcessRequest_SettingsManager_SetSettings(client_info, header.pkt_size, data); break; @@ -1424,6 +1433,14 @@ void NetworkServer::ListenThreadFunction(NetworkClientInfo * client_info) } break; + case NET_PACKET_ID_RGBCONTROLLER_SETDEVICESPECIFICCONFIGURATION: + ProcessRequest_RGBController_SetDeviceSpecificConfiguration(header.pkt_dev_id, (unsigned char *)data, header.pkt_size, client_info->client_protocol_version); + break; + + case NET_PACKET_ID_RGBCONTROLLER_SETDEVICESPECIFICZONECONFIGURATION: + ProcessRequest_RGBController_SetDeviceSpecificZoneConfiguration(header.pkt_dev_id, (unsigned char *)data, header.pkt_size, client_info->client_protocol_version); + break; + default: status = NET_PACKET_STATUS_ERROR_UNSUPPORTED; break; @@ -1748,7 +1765,8 @@ NetPacketStatus NetworkServer::ProcessRequest_ProfileManager_UploadProfile(Netwo profile_json_string.assign(data, data_size); profile_json_string = StringUtils::remove_null_terminating_chars(profile_json_string); - nlohmann::json profile_json = nlohmann::json::parse(profile_json_string); + nlohmann::json profile_json; + JsonUtils::JsonParse(profile_json_string, profile_json); if(profile_manager->SaveProfileFromJSON(profile_json)) { @@ -1794,6 +1812,63 @@ NetPacketStatus NetworkServer::ProcessRequest_SettingsManager_GetSettings(Networ return(NET_PACKET_STATUS_ERROR_UNSUPPORTED); } +NetPacketStatus NetworkServer::ProcessRequest_SettingsManager_GetSettingsSchema(NetworkClientInfo* client_info, unsigned int data_size, char* data) +{ + if(data == NULL) + { + return(NET_PACKET_STATUS_ERROR_INVALID_DATA); + } + + if(settings_manager != NULL) + { + std::string settings_key; + settings_key.assign(data, data_size); + settings_key = StringUtils::remove_null_terminating_chars(settings_key); + + nlohmann::json settings_json = settings_manager->GetSettingsSchema(settings_key); + std::string settings_json_str = settings_json.dump(); + + NetPacketHeader reply_hdr; + + InitNetPacketHeader(&reply_hdr, 0, NET_PACKET_ID_SETTINGSMANAGER_GET_SETTINGS_SCHEMA, (unsigned int)strlen(settings_json_str.c_str()) + 1); + + send_in_progress.lock(); + send(client_info->client_sock, (char *)&reply_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send(client_info->client_sock, (char *)settings_json_str.c_str(), reply_hdr.pkt_size, MSG_NOSIGNAL); + send_in_progress.unlock(); + + return(NET_PACKET_STATUS_OK); + } + + return(NET_PACKET_STATUS_ERROR_UNSUPPORTED); +} + +NetPacketStatus NetworkServer::ProcessRequest_SettingsManager_ModifySettings(NetworkClientInfo* client_info, unsigned int data_size, char* data) +{ + if(data == NULL) + { + return(NET_PACKET_STATUS_ERROR_INVALID_DATA); + } + + if(!client_info->client_is_local_client) + { + return(NET_PACKET_STATUS_ERROR_NOT_ALLOWED); + } + + if(settings_manager != NULL) + { + std::string settings_json_str; + settings_json_str.assign(data, data_size); + settings_json_str = StringUtils::remove_null_terminating_chars(settings_json_str); + + settings_manager->ModifySettingsFromJsonString(settings_json_str); + + return(NET_PACKET_STATUS_OK); + } + + return(NET_PACKET_STATUS_ERROR_UNSUPPORTED); +} + NetPacketStatus NetworkServer::ProcessRequest_SettingsManager_SetSettings(NetworkClientInfo* client_info, unsigned int data_size, char* data) { if(data == NULL) @@ -1880,9 +1955,9 @@ NetPacketStatus NetworkServer::ProcessRequest_RGBController_AddSegment(unsigned controllers[controller_idx]->AddSegment(zone_idx, new_segment); /*-----------------------------------------------------*\ - | Save sizes | + | Save configuration | \*-----------------------------------------------------*/ - profile_manager->SaveSizes(); + profile_manager->SaveConfiguration(); return(NET_PACKET_STATUS_OK); } @@ -1915,9 +1990,9 @@ NetPacketStatus NetworkServer::ProcessRequest_RGBController_ClearSegments(unsign controllers[controller_idx]->ClearSegments(zone_idx); /*-----------------------------------------------------*\ - | Save sizes | + | Save configuration | \*-----------------------------------------------------*/ - profile_manager->SaveSizes(); + profile_manager->SaveConfiguration(); return(NET_PACKET_STATUS_OK); } @@ -1965,9 +2040,9 @@ NetPacketStatus NetworkServer::ProcessRequest_RGBController_ConfigureZone(unsign controllers[controller_idx]->ConfigureZone(zone_idx, new_zone); /*-----------------------------------------------------*\ - | Save sizes | + | Save configuration | \*-----------------------------------------------------*/ - profile_manager->SaveSizes(); + profile_manager->SaveConfiguration(); return(NET_PACKET_STATUS_OK); } @@ -2007,9 +2082,9 @@ NetPacketStatus NetworkServer::ProcessRequest_RGBController_ResizeZone(unsigned controllers[controller_idx]->ResizeZone(zone_idx, new_size); /*-----------------------------------------------------*\ - | Save sizes | + | Save configuration | \*-----------------------------------------------------*/ - profile_manager->SaveSizes(); + profile_manager->SaveConfiguration(); return(NET_PACKET_STATUS_OK); } @@ -2038,6 +2113,78 @@ NetPacketStatus NetworkServer::ProcessRequest_RGBController_SetCustomMode(unsign return(NET_PACKET_STATUS_OK); } +NetPacketStatus NetworkServer::ProcessRequest_RGBController_SetDeviceSpecificConfiguration(unsigned int controller_id, unsigned char* data_ptr, unsigned int data_size, unsigned int protocol_version) +{ + /*-----------------------------------------------------*\ + | Convert ID to index | + \*-----------------------------------------------------*/ + bool idx_valid; + unsigned int controller_idx = index_from_id(controller_id, protocol_version, &idx_valid); + + /*-----------------------------------------------------*\ + | If controller ID is invalid, return | + \*-----------------------------------------------------*/ + if(!idx_valid) + { + return(NET_PACKET_STATUS_ERROR_INVALID_ID); + } + + /*-----------------------------------------------------*\ + | Save configuration JSON string | + \*-----------------------------------------------------*/ + std::string configuration_string; + nlohmann::json configuration; + + configuration_string.assign((char*)data_ptr, data_size); + configuration_string = StringUtils::remove_null_terminating_chars(configuration_string); + + JsonUtils::JsonParse(configuration_string, configuration); + + controllers[controller_idx]->SetDeviceSpecificConfiguration(configuration); + + return(NET_PACKET_STATUS_OK); +} + +NetPacketStatus NetworkServer::ProcessRequest_RGBController_SetDeviceSpecificZoneConfiguration(unsigned int controller_id, unsigned char* data_ptr, unsigned int data_size, unsigned int protocol_version) +{ + /*-----------------------------------------------------*\ + | Convert ID to index | + \*-----------------------------------------------------*/ + bool idx_valid; + unsigned int controller_idx = index_from_id(controller_id, protocol_version, &idx_valid); + + /*-----------------------------------------------------*\ + | If controller ID is invalid, return | + \*-----------------------------------------------------*/ + if(!idx_valid) + { + return(NET_PACKET_STATUS_ERROR_INVALID_ID); + } + + /*-----------------------------------------------------*\ + | Save configuration JSON string | + \*-----------------------------------------------------*/ + int zone_idx; + unsigned int configuration_string_size; + std::string configuration_string; + nlohmann::json configuration; + + memcpy(&zone_idx, data_ptr, sizeof(zone_idx)); + data_ptr += sizeof(zone_idx); + + memcpy(&configuration_string_size, data_ptr, sizeof(configuration_string_size)); + data_ptr += sizeof(configuration_string_size); + + configuration_string.assign((char*)data_ptr, configuration_string_size); + configuration_string = StringUtils::remove_null_terminating_chars(configuration_string); + + JsonUtils::JsonParse(configuration_string, configuration); + + controllers[controller_idx]->SetDeviceSpecificZoneConfiguration(zone_idx, configuration); + + return(NET_PACKET_STATUS_OK); +} + NetPacketStatus NetworkServer::ProcessRequest_RGBController_UpdateLEDs(unsigned int controller_id, unsigned char * data_ptr, unsigned int data_size, unsigned int protocol_version) { /*-----------------------------------------------------*\ @@ -3066,6 +3213,8 @@ void NetworkServer::SendRequest_RGBController_SignalUpdate(RGBController * contr case RGBCONTROLLER_UPDATE_REASON_ADDSEGMENT: case RGBCONTROLLER_UPDATE_REASON_HIDDEN: case RGBCONTROLLER_UPDATE_REASON_UNHIDDEN: + case RGBCONTROLLER_UPDATE_REASON_SETDEVICESPECIFICCONFIGURATION: + case RGBCONTROLLER_UPDATE_REASON_SETDEVICESPECIFICZONECONFIGURATION: default: data_ptr = RGBController::GetDeviceDescriptionData(data_ptr, controller_ptr, protocol_version); break; diff --git a/NetworkServer.h b/NetworkServer.h index 0b02c7928..8d4872ef7 100644 --- a/NetworkServer.h +++ b/NetworkServer.h @@ -238,6 +238,8 @@ private: NetPacketStatus ProcessRequest_ProfileManager_UploadProfile(NetworkClientInfo* client_info, unsigned int data_size, char* data); NetPacketStatus ProcessRequest_SettingsManager_GetSettings(NetworkClientInfo* client_info, unsigned int data_size, char* data); + NetPacketStatus ProcessRequest_SettingsManager_GetSettingsSchema(NetworkClientInfo* client_info, unsigned int data_size, char* data); + NetPacketStatus ProcessRequest_SettingsManager_ModifySettings(NetworkClientInfo* client_info, unsigned int data_size, char* data); NetPacketStatus ProcessRequest_SettingsManager_SetSettings(NetworkClientInfo* client_info, unsigned int data_size, char* data); NetPacketStatus ProcessRequest_SettingsManager_SaveSettings(NetworkClientInfo* client_info); @@ -246,6 +248,8 @@ private: NetPacketStatus ProcessRequest_RGBController_ConfigureZone(unsigned int controller_id, unsigned char* data_ptr, unsigned int data_size, unsigned int protocol_version); NetPacketStatus ProcessRequest_RGBController_ResizeZone(unsigned int controller_id, unsigned char* data_ptr, unsigned int data_size, unsigned int protocol_version); NetPacketStatus ProcessRequest_RGBController_SetCustomMode(unsigned int controller_id, unsigned int protocol_version); + NetPacketStatus ProcessRequest_RGBController_SetDeviceSpecificConfiguration(unsigned int controller_id, unsigned char* data_ptr, unsigned int data_size, unsigned int protocol_version); + NetPacketStatus ProcessRequest_RGBController_SetDeviceSpecificZoneConfiguration(unsigned int controller_id, unsigned char* data_ptr, unsigned int data_size, unsigned int protocol_version); NetPacketStatus ProcessRequest_RGBController_UpdateLEDs(unsigned int controller_id, unsigned char* data_ptr, unsigned int data_size, unsigned int protocol_version); NetPacketStatus ProcessRequest_RGBController_UpdateSaveMode(unsigned int controller_id, unsigned char* data_ptr, unsigned int data_size, unsigned int protocol_version, bool save_mode); NetPacketStatus ProcessRequest_RGBController_UpdateSingleLED(unsigned int controller_id, unsigned char* data_ptr, unsigned int data_size, unsigned int protocol_version); diff --git a/OpenRGB.pro b/OpenRGB.pro index d21a137f4..d3154bb9c 100644 --- a/OpenRGB.pro +++ b/OpenRGB.pro @@ -87,14 +87,14 @@ DEFINES += #-----------------------------------------------------------------------------------------------# FORMS += $$files("qt/*.ui", true) -for(iter, FORMS) { +GUI_H = $$files("qt/*.h", true) +GUI_CPP = $$files("qt/*.cpp", true) + +for(iter, $$list($$GUI_H)) { GUI_INCLUDES += $$dirname(iter) } GUI_INCLUDES = $$unique(GUI_INCLUDES) -GUI_H = $$files("qt/*.h", true) -GUI_CPP = $$files("qt/*.cpp", true) - CONTROLLER_H = $$files("Controllers/*.h", true) CONTROLLER_CPP = $$files("Controllers/*.cpp", true) @@ -166,6 +166,7 @@ HEADERS += Colors.h \ dependencies/ColorWheel/ColorWheel.h \ dependencies/json/nlohmann/json.hpp \ + JsonUtils.h \ LogManager.h \ NetworkClient.h \ NetworkProtocol.h \ @@ -238,6 +239,7 @@ SOURCES += cli.cpp \ DetectionManager.cpp \ dmiinfo/dmiinfo.cpp \ + JsonUtils.cpp \ LogManager.cpp \ NetworkClient.cpp \ NetworkProtocol.cpp \ diff --git a/OpenRGBPluginInterface.h b/OpenRGBPluginInterface.h index bd0a4dc26..4a695a86d 100644 --- a/OpenRGBPluginInterface.h +++ b/OpenRGBPluginInterface.h @@ -141,6 +141,7 @@ public: \*-----------------------------------------------------*/ virtual void ProfileManagerUpdated(unsigned int update_reason) = 0; virtual void ResourceManagerUpdated(unsigned int update_reason) = 0; + virtual void SettingsManagerUpdated(unsigned int update_reason) = 0; }; Q_DECLARE_INTERFACE(OpenRGBPluginInterface, OpenRGBPluginInterface_IID) diff --git a/PluginManager.cpp b/PluginManager.cpp index 7ac70e64e..bde51893b 100644 --- a/PluginManager.cpp +++ b/PluginManager.cpp @@ -32,6 +32,13 @@ void PluginManagerResourceManagerCallback(void * this_ptr, unsigned int update_r this_obj->ResourceManagerCallback(update_reason); } +void PluginManagerSettingsManagerCallback(void * this_ptr, unsigned int update_reason) +{ + PluginManager * this_obj = (PluginManager *)this_ptr; + + this_obj->SettingsManagerCallback(update_reason); +} + PluginManager::PluginManager() { /*-----------------------------------------------------*\ @@ -54,6 +61,7 @@ PluginManager::PluginManager() \*-----------------------------------------------------*/ ResourceManager::get()->GetProfileManager()->RegisterProfileManagerCallback(PluginManagerProfileManagerCallback, this); ResourceManager::get()->RegisterResourceManagerCallback(PluginManagerResourceManagerCallback, this); + ResourceManager::get()->GetSettingsManager()->RegisterSettingsManagerCallback(PluginManagerSettingsManagerCallback, this); } PluginManager::~PluginManager() @@ -61,8 +69,9 @@ PluginManager::~PluginManager() /*-----------------------------------------------------*\ | Unegister callbacks | \*-----------------------------------------------------*/ - ResourceManager::get()->GetProfileManager()->RegisterProfileManagerCallback(PluginManagerProfileManagerCallback, this); - ResourceManager::get()->RegisterResourceManagerCallback(PluginManagerResourceManagerCallback, this); + ResourceManager::get()->GetProfileManager()->UnregisterProfileManagerCallback(PluginManagerProfileManagerCallback, this); + ResourceManager::get()->UnregisterResourceManagerCallback(PluginManagerResourceManagerCallback, this); + ResourceManager::get()->GetSettingsManager()->UnregisterSettingsManagerCallback(PluginManagerSettingsManagerCallback, this); } void PluginManager::RegisterAddPluginCallback(AddPluginCallback new_callback, void * new_callback_arg) @@ -682,6 +691,17 @@ void PluginManager::ResourceManagerCallback(unsigned int update_reason) } } +void PluginManager::SettingsManagerCallback(unsigned int update_reason) +{ + for(std::size_t plugin_idx = 0; plugin_idx < ActivePlugins.size(); plugin_idx++) + { + if(ActivePlugins[plugin_idx].enabled && ActivePlugins[plugin_idx].loader->isLoaded()) + { + ActivePlugins[plugin_idx].plugin->SettingsManagerUpdated(update_reason); + } + } +} + /*---------------------------------------------------------*\ | Plugin Information | \*---------------------------------------------------------*/ diff --git a/PluginManager.h b/PluginManager.h index 0ddb2ef28..2df15bc3f 100644 --- a/PluginManager.h +++ b/PluginManager.h @@ -94,6 +94,7 @@ public: \*-----------------------------------------------------*/ void ProfileManagerCallback(unsigned int update_reason); void ResourceManagerCallback(unsigned int update_reason); + void SettingsManagerCallback(unsigned int update_reason); std::vector ActivePlugins; diff --git a/ProfileManager.cpp b/ProfileManager.cpp index 51876ca74..80184b89d 100644 --- a/ProfileManager.cpp +++ b/ProfileManager.cpp @@ -13,6 +13,7 @@ #include #include #include "filesystem.h" +#include "JsonUtils.h" #include "LogManager.h" #include "NetworkClient.h" #include "NetworkProtocol.h" @@ -41,11 +42,34 @@ ProfileManager::ProfileManager(const filesystem::path& config_dir) SetConfigurationDirectory(config_dir); UpdateProfileList(); + /*-----------------------------------------------------*\ + | Create ProfileManager settings schema | + \*-----------------------------------------------------*/ + SettingsManager* settings_manager = ResourceManager::get()->GetSettingsManager(); + json profilemanager_settings_schema; + + profilemanager_settings_schema["exit_profile"]["title"] = QT_TRANSLATE_NOOP("Settings", "Load Profile on Exit"); + profilemanager_settings_schema["exit_profile"]["type"] = "profile"; + profilemanager_settings_schema["exit_profile"]["description"] = QT_TRANSLATE_NOOP("Settings", "Profile to load when OpenRGB exits"); + + profilemanager_settings_schema["open_profile"]["title"] = QT_TRANSLATE_NOOP("Settings", "Load Profile on Open"); + profilemanager_settings_schema["open_profile"]["type"] = "profile"; + profilemanager_settings_schema["open_profile"]["description"] = QT_TRANSLATE_NOOP("Settings", "Profile to load when OpenRGB opens"); + + profilemanager_settings_schema["resume_profile"]["title"] = QT_TRANSLATE_NOOP("Settings", "Load Profile on Resume"); + profilemanager_settings_schema["resume_profile"]["type"] = "profile"; + profilemanager_settings_schema["resume_profile"]["description"] = QT_TRANSLATE_NOOP("Settings", "Profile to load after system resumes from sleep"); + + profilemanager_settings_schema["suspend_profile"]["title"] = QT_TRANSLATE_NOOP("Settings", "Load Profile on Suspend"); + profilemanager_settings_schema["suspend_profile"]["type"] = "profile"; + profilemanager_settings_schema["suspend_profile"]["description"] = QT_TRANSLATE_NOOP("Settings", "Profile to load before system enters sleep mode"); + + settings_manager->RegisterSettingsSchema("ProfileManager", "Profile Manager", profilemanager_settings_schema, 1); + /*-----------------------------------------------------*\ | Read in profile manager settings and initialize any | | missing settings to defaults | \*-----------------------------------------------------*/ - SettingsManager* settings_manager = ResourceManager::get()->GetSettingsManager(); json profilemanager_settings = settings_manager->GetSettings("ProfileManager"); bool new_settings_keys = false; @@ -98,7 +122,7 @@ ProfileManager::ProfileManager(const filesystem::path& config_dir) /*-----------------------------------------------------*\ | Initialize manually configured controllers list | \*-----------------------------------------------------*/ - manually_configured_rgb_controllers = GetControllerListFromSizes(); + manually_configured_rgb_controllers = GetControllerListFromSavedConfiguration(); } ProfileManager::~ProfileManager() @@ -213,8 +237,9 @@ bool ProfileManager::CompareControllers(RGBController* controller_1, RGBControll { for(std::size_t zone_index = 0; zone_index < controller_1->zones.size(); zone_index++) { - bool check_zone_name = true; - bool check_zone_type = true; + bool check_zone_geometry = true; + bool check_zone_name = true; + bool check_zone_type = true; /*---------------------------------------------*\ | Do not check zone name if manually configured | @@ -234,11 +259,17 @@ bool ProfileManager::CompareControllers(RGBController* controller_1, RGBControll check_zone_type = false; } - if((check_zone_name && (controller_1->GetZoneName(zone_index) != controller_2->GetZoneName(zone_index) )) - || (check_zone_type && (controller_1->GetZoneType(zone_index) != controller_2->GetZoneType(zone_index) )) - || (controller_1->GetZoneLEDsMin(zone_index) != controller_2->GetZoneLEDsMin(zone_index) ) - || (controller_1->GetZoneLEDsMax(zone_index) != controller_2->GetZoneLEDsMax(zone_index) ) - || (controller_1->GetZoneModeCount(zone_index) != controller_2->GetZoneModeCount(zone_index))) + if((controller_1->GetZoneFlags(zone_index) & ZONE_FLAG_ZONE_GEOMETRY_MAY_CHANGE) + || (controller_2->GetZoneFlags(zone_index) & ZONE_FLAG_ZONE_GEOMETRY_MAY_CHANGE)) + { + check_zone_geometry = false; + } + + if((check_zone_name && (controller_1->GetZoneName(zone_index) != controller_2->GetZoneName(zone_index) )) + || (check_zone_type && (controller_1->GetZoneType(zone_index) != controller_2->GetZoneType(zone_index) )) + || (check_zone_geometry && ((controller_1->GetZoneLEDsMin(zone_index) != controller_2->GetZoneLEDsMin(zone_index) ) + || (controller_1->GetZoneLEDsMax(zone_index) != controller_2->GetZoneLEDsMax(zone_index) ))) + || (controller_1->GetZoneModeCount(zone_index) != controller_2->GetZoneModeCount(zone_index))) { return(false); } @@ -320,15 +351,15 @@ std::vector ProfileManager::GetControllerListFromProfileName(std return(GetControllerListFromProfileJson(ReadProfileJSON(profile_name))); } -std::vector ProfileManager::GetControllerListFromSizes() +std::vector ProfileManager::GetControllerListFromSavedConfiguration() { /*-----------------------------------------------------*\ - | Read the sizes JSON from the file | + | Read the configuration JSON from the file | \*-----------------------------------------------------*/ - filesystem::path filename = configuration_directory / "Sizes.json"; - nlohmann::json sizes_json = ReadProfileFileJSON(filename); + filesystem::path filename = configuration_directory / "Configuration.json"; + nlohmann::json config_json = ReadProfileFileJSON(filename); - return(GetControllerListFromProfileJson(sizes_json)); + return(GetControllerListFromProfileJson(config_json)); } std::vector ProfileManager::GetProfileList() @@ -455,8 +486,7 @@ void ProfileManager::OnProfileAboutToLoad() void ProfileManager::OnProfileLoaded(std::string profile_json_string) { nlohmann::json profile_json; - - profile_json = nlohmann::json::parse(profile_json_string); + JsonUtils::JsonParse(profile_json_string, profile_json); /*-------------------------------------------------*\ | Get plugin profile data | @@ -517,7 +547,7 @@ nlohmann::json ProfileManager::ReadProfileJSON(std::string profile_name) if(ResourceManager::get()->IsLocalClient() && (ResourceManager::get()->GetLocalClient()->GetSupportsProfileManagerAPI())) { - profile_json = nlohmann::json::parse(ResourceManager::get()->GetLocalClient()->ProfileManager_DownloadProfile(profile_name)); + JsonUtils::JsonParse(ResourceManager::get()->GetLocalClient()->ProfileManager_DownloadProfile(profile_name), profile_json); } else { @@ -809,7 +839,7 @@ bool ProfileManager::SaveProfileFromJSON(nlohmann::json profile_json) } } -bool ProfileManager::SaveSizes() +bool ProfileManager::SaveConfiguration() { /*-----------------------------------------------------*\ | Get the list of controllers from the resource manager | @@ -819,7 +849,7 @@ bool ProfileManager::SaveSizes() /*-----------------------------------------------------*\ | Open an output file in the profile directory | \*-----------------------------------------------------*/ - filesystem::path profile_path = configuration_directory / "Sizes.json"; + filesystem::path profile_path = configuration_directory / "Configuration.json"; std::ofstream controller_file(profile_path, std::ios::out ); /*-----------------------------------------------------*\ @@ -828,7 +858,7 @@ bool ProfileManager::SaveSizes() nlohmann::json profile_json; profile_json["profile_version"] = OPENRGB_PROFILE_VERSION; - profile_json["profile_name"] = "Sizes"; + profile_json["profile_name"] = "Controller Configuration"; /*-----------------------------------------------------*\ | Write controller data for each controller | @@ -839,7 +869,7 @@ bool ProfileManager::SaveSizes() { /*-------------------------------------------------*\ | Ignore remote and virtual controllers when saving | - | sizes | + | configuration | \*-------------------------------------------------*/ if(controllers[controller_index]->GetFlags() & CONTROLLER_FLAG_REMOTE || controllers[controller_index]->GetFlags() & CONTROLLER_FLAG_VIRTUAL) @@ -864,9 +894,9 @@ bool ProfileManager::SaveSizes() } /*-----------------------------------------------------*\ - | Loop through the previously saved sizes and add any | - | controllers that were previously saved but not in the | - | current controllers list | + | Loop through the previously saved configuration and | + | add any controllers that were previously saved but | + | not in the current controllers list | \*-----------------------------------------------------*/ for(std::size_t old_saved_controller_index = 0; old_saved_controller_index < manually_configured_rgb_controllers.size(); old_saved_controller_index++) { @@ -902,7 +932,7 @@ bool ProfileManager::SaveSizes() /*-----------------------------------------------------*\ | Reinitialize manually configured controllers list | \*-----------------------------------------------------*/ - manually_configured_rgb_controllers = GetControllerListFromSizes(); + manually_configured_rgb_controllers = GetControllerListFromSavedConfiguration(); return(true); } @@ -936,7 +966,7 @@ void ProfileManager::SetConfigurationDirectory(const filesystem::path& directory /*-----------------------------------------------------*\ | Reinitialize manually configured controllers list | \*-----------------------------------------------------*/ - manually_configured_rgb_controllers = GetControllerListFromSizes(); + manually_configured_rgb_controllers = GetControllerListFromSavedConfiguration(); } void ProfileManager::SetProfileListFromDescription(unsigned int /*data_size*/, char * data_buf) @@ -1077,8 +1107,8 @@ bool ProfileManager::LoadControllerFromListWithOptions ( std::vector& profile_controllers, RGBController* load_controller, - bool load_size, - bool load_settings + bool load_configuration, + bool load_state ) { for(std::size_t temp_index = 0; temp_index < profile_controllers.size(); temp_index++) @@ -1128,10 +1158,21 @@ bool ProfileManager::LoadControllerFromListWithOptions &&(location_check == true )) { /*---------------------------------------------*\ - | Update zone sizes if requested | + | Update device configuration if requested | \*---------------------------------------------*/ - if(load_size) + if(load_configuration) { + /*-----------------------------------------*\ + | Load device-specific configuration | + \*-----------------------------------------*/ + nlohmann::json configuration_json; + JsonUtils::JsonParse(profile_controller->configuration, configuration_json); + + load_controller->SetDeviceSpecificConfiguration(configuration_json["configuration"]); + + /*-----------------------------------------*\ + | Load zone configuration | + \*-----------------------------------------*/ if(profile_controller->zones.size() == load_controller->zones.size()) { for(std::size_t zone_idx = 0; zone_idx < profile_controller->zones.size(); zone_idx++) @@ -1176,6 +1217,8 @@ bool ProfileManager::LoadControllerFromListWithOptions } } } + + load_controller->SetDeviceSpecificZoneConfiguration(zone_idx, configuration_json["zones"][zone_idx]["configuration"]); } } } @@ -1183,7 +1226,7 @@ bool ProfileManager::LoadControllerFromListWithOptions /*---------------------------------------------*\ | Update settings if requested | \*---------------------------------------------*/ - if(load_settings) + if(load_state) { /*-----------------------------------------*\ | If mode list matches, load all modes | @@ -1289,7 +1332,7 @@ bool ProfileManager::LoadControllerFromListWithOptions | this controller, apply the base color if it is | | enabled | \*-----------------------------------------------------*/ - if(load_settings && active_base_color_enabled) + if(load_state && active_base_color_enabled) { load_controller->SetCustomMode(); @@ -1311,8 +1354,8 @@ bool ProfileManager::LoadControllerFromListWithOptions bool ProfileManager::LoadProfileWithOptions ( std::string profile_name, - bool load_size, - bool load_settings + bool load_configuration, + bool load_state ) { /*-------------------------------------------------*\ @@ -1385,7 +1428,7 @@ bool ProfileManager::LoadProfileWithOptions \*-------------------------------------------------*/ for(std::size_t controller_index = 0; controller_index < controllers.size(); controller_index++) { - LoadControllerFromListWithOptions(active_rgb_controllers, controllers[controller_index], load_size, load_settings); + LoadControllerFromListWithOptions(active_rgb_controllers, controllers[controller_index], load_configuration, load_state); } /*-------------------------------------------------*\ diff --git a/ProfileManager.h b/ProfileManager.h index c6816b43f..b401f3d08 100644 --- a/ProfileManager.h +++ b/ProfileManager.h @@ -39,7 +39,7 @@ public: virtual std::string GetActiveProfile() = 0; virtual std::vector GetControllerListFromProfileJson(nlohmann::json profile_json) = 0; virtual std::vector GetControllerListFromProfileName(std::string profile_name) = 0; - virtual std::vector GetControllerListFromSizes() = 0; + virtual std::vector GetControllerListFromSavedConfiguration() = 0; virtual std::vector GetProfileList() = 0; virtual unsigned char * GetProfileListDescription() = 0; @@ -47,8 +47,8 @@ public: ( std::vector& temp_controllers, RGBController* load_controller, - bool load_size, - bool load_settings + bool load_configuration, + bool load_state ) = 0; virtual bool LoadControllerActiveProfile(RGBController* load_controller) = 0; @@ -60,7 +60,7 @@ public: virtual bool SaveProfile(std::string profile_name) = 0; virtual bool SaveProfileFromJSON(nlohmann::json profile_json) = 0; - virtual bool SaveSizes() = 0; + virtual bool SaveConfiguration() = 0; virtual void SetConfigurationDirectory(const filesystem::path& directory) = 0; @@ -86,7 +86,7 @@ public: std::string GetActiveProfile(); std::vector GetControllerListFromProfileJson(nlohmann::json profile_json); std::vector GetControllerListFromProfileName(std::string profile_name); - std::vector GetControllerListFromSizes(); + std::vector GetControllerListFromSavedConfiguration(); std::vector GetProfileList(); unsigned char * GetProfileListDescription(); @@ -99,8 +99,8 @@ public: ( std::vector& temp_controllers, RGBController* load_controller, - bool load_size, - bool load_settings + bool load_configuration, + bool load_state ); bool LoadControllerActiveProfile(RGBController* load_controller); @@ -123,7 +123,7 @@ public: bool SaveProfile(std::string profile_name); bool SaveProfileCustom(std::string profile_name, std::vector controllers, RGBColor base_color, bool base_color_enabled, std::vector enabled_plugins); bool SaveProfileFromJSON(nlohmann::json profile_json); - bool SaveSizes(); + bool SaveConfiguration(); void SetActiveProfile(std::string profile_name); void SetConfigurationDirectory(const filesystem::path& directory); @@ -178,8 +178,8 @@ private: bool LoadProfileWithOptions ( std::string profile_name, - bool load_size, - bool load_settings + bool load_configuration, + bool load_state ); nlohmann::json ReadProfileFileJSON(filesystem::path profile_filepath); diff --git a/RGBController/RGBController.cpp b/RGBController/RGBController.cpp index f1c1b5a8a..3a677c595 100644 --- a/RGBController/RGBController.cpp +++ b/RGBController/RGBController.cpp @@ -332,24 +332,6 @@ RGBColor RGBController::GetZoneColor(unsigned int zone, unsigned int color_index return(color); } -zone_color_order RGBController::GetZoneColorOrder(unsigned int zone) -{ - zone_color_order color_order; - - AccessMutex.lock_shared(); - if(zone < zones.size()) - { - color_order = zones[zone].color_order; - } - else - { - color_order = ZONE_COLOR_ORDER_DEFAULT; - } - AccessMutex.unlock_shared(); - - return(color_order); -} - RGBColor* RGBController::GetZoneColorsPointer(unsigned int zone) { /*-----------------------------------------------------*\ @@ -1727,6 +1709,204 @@ void RGBController::SetAllZoneColors(int zone, RGBColor color) AccessMutex.unlock(); } +/*-----------------------------------------------------*\ +| Device-Specific Configuration Functions | +\*-----------------------------------------------------*/ +nlohmann::json RGBController::GetDeviceSpecificConfigurationSchema() +{ + nlohmann::json configuration_schema_json; + nlohmann::json configuration_string_json; + + AccessMutex.lock_shared(); + try + { + configuration_string_json = json::parse(configuration); + } + catch(...) + { + } + AccessMutex.unlock_shared(); + + if(configuration_string_json.contains("schema")) + { + configuration_schema_json = configuration_string_json["schema"]; + } + + return(configuration_schema_json); +} + +nlohmann::json RGBController::GetDeviceSpecificConfiguration() +{ + nlohmann::json configuration_json; + nlohmann::json configuration_string_json; + + AccessMutex.lock_shared(); + try + { + configuration_string_json = json::parse(configuration); + } + catch(...) + { + } + AccessMutex.unlock_shared(); + + if(configuration_string_json.contains("configuration")) + { + configuration_json = configuration_string_json["configuration"]; + } + + return(configuration_json); +} + +void RGBController::SetDeviceSpecificConfiguration(nlohmann::json configuration_json) +{ + nlohmann::json configuration_string_json; + nlohmann::json configuration_schema_json; + + AccessMutex.lock(); + + try + { + configuration_string_json = json::parse(configuration); + } + catch(...) + { + } + + if(configuration_string_json.contains("schema")) + { + configuration_schema_json = configuration_string_json["schema"]; + } + + if(configuration_string_json.contains("configuration")) + { + /*-------------------------------------------------*\ + | Iterate through all keys in updated configuration | + | to validate them against the schema | + \*-------------------------------------------------*/ + for(nlohmann::json::iterator json_iterator = configuration_json.begin(); json_iterator != configuration_json.end(); json_iterator++) + { + std::string key = json_iterator.key(); + std::string type = ""; + + if(configuration_schema_json.contains(key) && configuration_schema_json[key].contains("title") && configuration_schema_json[key].contains("type")) + { + configuration_string_json["configuration"][key] = configuration_json[key]; + } + } + } + + configuration = configuration_string_json.dump(); + + DeviceUpdateDeviceSpecificConfiguration(); + + AccessMutex.unlock(); + + SignalUpdate(RGBCONTROLLER_UPDATE_REASON_SETDEVICESPECIFICCONFIGURATION); +} + +nlohmann::json RGBController::GetDeviceSpecificZoneConfigurationSchema(int zone) +{ + nlohmann::json configuration_schema_json; + nlohmann::json configuration_string_json; + + AccessMutex.lock_shared(); + try + { + configuration_string_json = json::parse(configuration); + } + catch(...) + { + } + AccessMutex.unlock_shared(); + + if(configuration_string_json.contains("zones") && (zone < (int)configuration_string_json["zones"].size())) + { + if(configuration_string_json["zones"][zone].contains("schema")) + { + configuration_schema_json = configuration_string_json["zones"][zone]["schema"]; + } + } + + return(configuration_schema_json); +} + +nlohmann::json RGBController::GetDeviceSpecificZoneConfiguration(int zone) +{ + nlohmann::json configuration_json; + nlohmann::json configuration_string_json; + + AccessMutex.lock_shared(); + try + { + configuration_string_json = json::parse(configuration); + } + catch(...) + { + } + AccessMutex.unlock_shared(); + + if(configuration_string_json.contains("zones") && (zone < (int)configuration_string_json["zones"].size())) + { + if(configuration_string_json["zones"][zone].contains("configuration")) + { + configuration_json = configuration_string_json["zones"][zone]["configuration"]; + } + } + + return(configuration_json); +} + +void RGBController::SetDeviceSpecificZoneConfiguration(int zone, nlohmann::json configuration_json) +{ + nlohmann::json configuration_string_json; + nlohmann::json configuration_schema_json; + + AccessMutex.lock(); + + try + { + configuration_string_json = json::parse(configuration); + } + catch(...) + { + } + + if(configuration_string_json.contains("zones") && (zone < (int)configuration_string_json["zones"].size())) + { + if(configuration_string_json["zones"][zone].contains("schema")) + { + configuration_schema_json = configuration_string_json["zones"][zone]["schema"]; + } + + if(configuration_string_json["zones"][zone].contains("configuration")) + { + /*-------------------------------------------------*\ + | Iterate through all keys in updated configuration | + | to validate them against the schema | + \*-------------------------------------------------*/ + for(nlohmann::json::iterator json_iterator = configuration_json.begin(); json_iterator != configuration_json.end(); json_iterator++) + { + std::string key = json_iterator.key(); + std::string type = ""; + + if(configuration_schema_json.contains(key) && configuration_schema_json[key].contains("title") && configuration_schema_json[key].contains("type")) + { + configuration_string_json["zones"][zone]["configuration"][key] = configuration_json[key]; + } + } + } + } + + configuration = configuration_string_json.dump(); + + DeviceUpdateDeviceSpecificZoneConfiguration(zone); + + AccessMutex.unlock(); + + SignalUpdate(RGBCONTROLLER_UPDATE_REASON_SETDEVICESPECIFICZONECONFIGURATION); +} + /*---------------------------------------------------------*\ | Update Callback Functions | \*---------------------------------------------------------*/ @@ -1972,16 +2152,6 @@ void RGBController::ConfigureZone(int zone_idx, zone new_zone) zones[zone_idx].flags &= ~ZONE_FLAG_MANUALLY_CONFIGURED_MATRIX_MAP; } - if(new_zone.flags & ZONE_FLAG_MANUALLY_CONFIGURED_COLOR_ORDER) - { - zones[zone_idx].flags |= ZONE_FLAG_MANUALLY_CONFIGURED_COLOR_ORDER; - zones[zone_idx].color_order = new_zone.color_order; - } - else - { - zones[zone_idx].flags &= ~ZONE_FLAG_MANUALLY_CONFIGURED_COLOR_ORDER; - } - if(new_zone.flags & ZONE_FLAG_MANUALLY_CONFIGURED_SEGMENTS) { zones[zone_idx].flags |= ZONE_FLAG_MANUALLY_CONFIGURED_SEGMENTS; @@ -1993,6 +2163,15 @@ void RGBController::ConfigureZone(int zone_idx, zone new_zone) zones[zone_idx].segments.clear(); } + if(new_zone.flags & ZONE_FLAG_MANUALLY_CONFIGURED_DEVICE_SPECIFIC) + { + zones[zone_idx].flags |= ZONE_FLAG_MANUALLY_CONFIGURED_DEVICE_SPECIFIC; + } + else + { + zones[zone_idx].flags &= ~ZONE_FLAG_MANUALLY_CONFIGURED_DEVICE_SPECIFIC; + } + DeviceConfigureZone(zone_idx); AccessMutex.unlock(); @@ -2146,6 +2325,19 @@ void RGBController::DeviceSaveMode() \*-----------------------------------------------------*/ } +void RGBController::DeviceUpdateDeviceSpecificConfiguration() +{ + /*-----------------------------------------------------*\ + | If not implemented by controller, does nothing | + \*-----------------------------------------------------*/ +} + +void RGBController::DeviceUpdateDeviceSpecificZoneConfiguration(int /*zone*/) +{ + /*-----------------------------------------------------*\ + | If not implemented by controller, does nothing | + \*-----------------------------------------------------*/ +} /*---------------------------------------------------------*\ | Static Serialized Description Functions | @@ -2207,6 +2399,7 @@ unsigned char * RGBController::GetDeviceDescriptionData(unsigned char* data_ptr, unsigned short num_zones = (unsigned short)controller->zones.size(); unsigned short num_leds = (unsigned short)controller->leds.size(); unsigned short num_led_alt_names = (unsigned short)controller->led_alt_names.size(); + unsigned int configuration_len = (unsigned int )strlen(controller->configuration.c_str()) + 1; /*-----------------------------------------------------*\ | Copy in type | @@ -2359,6 +2552,18 @@ unsigned char * RGBController::GetDeviceDescriptionData(unsigned char* data_ptr, data_ptr += sizeof(flags); } + /*-----------------------------------------------------*\ + | Copy in controller device-specific configuration | + \*-----------------------------------------------------*/ + if(protocol_version >= 6) + { + memcpy(data_ptr, &configuration_len, sizeof(configuration_len)); + data_ptr += sizeof(configuration_len); + + strcpy((char *)data_ptr, controller->configuration.c_str()); + data_ptr += configuration_len; + } + return(data_ptr); } @@ -2382,6 +2587,7 @@ unsigned int RGBController::GetDeviceDescriptionSize(RGBController* controller, unsigned short num_zones = (unsigned short)controller->zones.size(); unsigned short num_leds = (unsigned short)controller->leds.size(); unsigned short num_led_alt_names = (unsigned short)controller->led_alt_names.size(); + unsigned int configuration_len = (unsigned int )strlen(controller->configuration.c_str()) + 1; data_size += sizeof(device_type); data_size += sizeof(name_len); @@ -2442,6 +2648,12 @@ unsigned int RGBController::GetDeviceDescriptionSize(RGBController* controller, data_size += sizeof(flags); } + if(protocol_version >= 6) + { + data_size += sizeof(configuration_len); + data_size += configuration_len; + } + return(data_size); } @@ -2914,12 +3126,6 @@ unsigned char * RGBController::GetZoneDescriptionData(unsigned char* data_ptr, z { data_ptr = GetModeDescriptionData(data_ptr, zone.modes[mode_index], protocol_version); } - - /*-------------------------------------------------*\ - | Copy in color order | - \*-------------------------------------------------*/ - memcpy(data_ptr, &zone.color_order, sizeof(zone.color_order)); - data_ptr += sizeof(zone.color_order); } return(data_ptr); @@ -2971,7 +3177,7 @@ unsigned int RGBController::GetZoneDescriptionSize(zone zone, unsigned int proto } /*-----------------------------------------------------*\ - | Zone modes and color order | + | Zone modes | \*-----------------------------------------------------*/ if(protocol_version >= 6) { @@ -2984,8 +3190,6 @@ unsigned int RGBController::GetZoneDescriptionSize(zone zone, unsigned int proto { data_size += GetModeDescriptionSize(zone.modes[mode_index], protocol_version); } - - data_size += sizeof(zone.color_order); } return(data_size); @@ -3172,6 +3376,16 @@ unsigned char* RGBController::SetDeviceDescription(unsigned char* data_ptr, unsi COPY_DATA_FIELD_UNLOCK(data_ptr, data_start, controller->flags, controller); } + /*-----------------------------------------------------*\ + | Copy in device-specific configuration | + \*-----------------------------------------------------*/ + if(protocol_version >= 6) + { + unsigned int configuration_len; + COPY_DATA_FIELD_UNLOCK(data_ptr, data_start, configuration_len, controller); + COPY_STRING_FIELD_UNLOCK(data_ptr, data_start, configuration_len, controller->configuration, controller); + } + /*-----------------------------------------------------*\ | Unlock access mutex | \*-----------------------------------------------------*/ @@ -3589,11 +3803,6 @@ unsigned char* RGBController::SetZoneDescription(unsigned char* data_ptr, unsign return(NULL); } } - - /*-------------------------------------------------*\ - | Copy in color order | - \*-------------------------------------------------*/ - COPY_DATA_FIELD(data_ptr, data_start, zone->color_order); } return(data_ptr); @@ -3621,6 +3830,14 @@ nlohmann::json RGBController::GetDeviceDescriptionJSON(RGBController* controller controller_json["vendor"] = controller->vendor; controller_json["version"] = controller->version; + try + { + controller_json["configuration"] = json::parse(controller->configuration); + } + catch(...) + { + } + /*-----------------------------------------------------*\ | Controller variables | \*-----------------------------------------------------*/ @@ -3785,8 +4002,6 @@ nlohmann::json RGBController::GetZoneDescriptionJSON(zone zone) zone_json["active_mode"] = zone.active_mode; } - zone_json["color_order"] = zone.color_order; - return(zone_json); } @@ -3830,6 +4045,11 @@ void RGBController::SetDeviceDescriptionJSON(nlohmann::json controller_json, RGB controller->version = controller_json["version"]; } + if(controller_json.contains("configuration")) + { + controller->configuration = controller_json["configuration"].dump(); + } + /*-----------------------------------------------------*\ | Controller variables | \*-----------------------------------------------------*/ @@ -4161,11 +4381,6 @@ zone RGBController::SetZoneDescriptionJSON(nlohmann::json zone_json) new_zone.active_mode = zone_json["active_mode"]; } - if(zone_json.contains("color_order")) - { - new_zone.color_order = zone_json["color_order"]; - } - return(new_zone); } diff --git a/RGBController/RGBController.h b/RGBController/RGBController.h index 59a3f42e5..430002a13 100644 --- a/RGBController/RGBController.h +++ b/RGBController/RGBController.h @@ -136,14 +136,14 @@ typedef unsigned int zone_flags; ZONE_FLAG_MANUALLY_CONFIGURABLE_TYPE | \ ZONE_FLAG_MANUALLY_CONFIGURABLE_MATRIX_MAP | \ ZONE_FLAG_MANUALLY_CONFIGURABLE_SEGMENTS | \ - ZONE_FLAG_MANUALLY_CONFIGURABLE_COLOR_ORDER) + ZONE_FLAG_MANUALLY_CONFIGURABLE_DEVICE_SPECIFIC) #define ZONE_FLAGS_MANUALLY_CONFIGURED (ZONE_FLAG_MANUALLY_CONFIGURED_SIZE | \ ZONE_FLAG_MANUALLY_CONFIGURED_NAME | \ ZONE_FLAG_MANUALLY_CONFIGURED_TYPE | \ ZONE_FLAG_MANUALLY_CONFIGURED_MATRIX_MAP | \ ZONE_FLAG_MANUALLY_CONFIGURED_SEGMENTS | \ - ZONE_FLAG_MANUALLY_CONFIGURED_COLOR_ORDER) + ZONE_FLAG_MANUALLY_CONFIGURED_DEVICE_SPECIFIC) enum { ZONE_FLAG_MANUALLY_CONFIGURABLE_SIZE_EFFECTS_ONLY = (1 << 0), /* Zone size is manually configurable, but only */ @@ -154,20 +154,14 @@ enum ZONE_FLAG_MANUALLY_CONFIGURABLE_TYPE = (1 << 3), /* Zone type is manually configurable */ ZONE_FLAG_MANUALLY_CONFIGURABLE_MATRIX_MAP = (1 << 4), /* Zone matrix map is manually configurable */ ZONE_FLAG_MANUALLY_CONFIGURABLE_SEGMENTS = (1 << 5), /* Zone segments are manually configurable */ - ZONE_FLAG_MANUALLY_CONFIGURABLE_COLOR_ORDER = (1 << 6), /* Zone color order is manually configurable */ + ZONE_FLAG_MANUALLY_CONFIGURABLE_DEVICE_SPECIFIC = (1 << 6), /* Zone dev-specific cfg manually configurable */ ZONE_FLAG_MANUALLY_CONFIGURED_SIZE = (1 << 12),/* Zone size has been manually configured */ ZONE_FLAG_MANUALLY_CONFIGURED_NAME = (1 << 13),/* Zone name has been manually configured */ ZONE_FLAG_MANUALLY_CONFIGURED_TYPE = (1 << 14),/* Zone type has been manually configured */ ZONE_FLAG_MANUALLY_CONFIGURED_MATRIX_MAP = (1 << 15),/* Zone matrix map has been manually configured */ ZONE_FLAG_MANUALLY_CONFIGURED_SEGMENTS = (1 << 16),/* Zone segments have been manually configured */ - ZONE_FLAG_MANUALLY_CONFIGURED_COLOR_ORDER = (1 << 17),/* Zone color order has been manually configured*/ - ZONE_FLAG_SUPPORTS_COLOR_ORDER_DEFAULT = (1 << 24),/* Zone supports default color order */ - ZONE_FLAG_SUPPORTS_COLOR_ORDER_RGB = (1 << 25),/* Zone supports RGB color order */ - ZONE_FLAG_SUPPORTS_COLOR_ORDER_RBG = (1 << 26),/* Zone supports RBG color order */ - ZONE_FLAG_SUPPORTS_COLOR_ORDER_GRB = (1 << 27),/* Zone supports GRB color order */ - ZONE_FLAG_SUPPORTS_COLOR_ORDER_GBR = (1 << 28),/* Zone supports GBR color order */ - ZONE_FLAG_SUPPORTS_COLOR_ORDER_BRG = (1 << 29),/* Zone supports BRG color order */ - ZONE_FLAG_SUPPORTS_COLOR_ORDER_BGR = (1 << 30),/* Zone supports BGR color order */ + ZONE_FLAG_MANUALLY_CONFIGURED_DEVICE_SPECIFIC = (1 << 17),/* Zone device-specific cfg manually configured */ + ZONE_FLAG_ZONE_GEOMETRY_MAY_CHANGE = (1 << 24),/* Zone geometry may change */ }; /*---------------------------------------------------------*\ @@ -186,22 +180,6 @@ enum ZONE_TYPE_SEGMENTED }; -/*---------------------------------------------------------*\ -| Zone Color Order | -\*---------------------------------------------------------*/ -typedef unsigned int zone_color_order; - -enum -{ - ZONE_COLOR_ORDER_DEFAULT, /* Device default color order */ - ZONE_COLOR_ORDER_RGB, /* RGB color order */ - ZONE_COLOR_ORDER_RBG, /* RBG color order */ - ZONE_COLOR_ORDER_GRB, /* GRB color order */ - ZONE_COLOR_ORDER_GBR, /* GBR color order */ - ZONE_COLOR_ORDER_BRG, /* BRG color order */ - ZONE_COLOR_ORDER_BGR /* BGR color order */ -}; - /*---------------------------------------------------------*\ | Matrix Map Struct | \*---------------------------------------------------------*/ @@ -268,7 +246,6 @@ public: zone_flags flags; /* Zone flags bitfield */ std::vector modes; /* Zone-specific modes */ int active_mode; /* Active zone-specific mode*/ - zone_color_order color_order; /* Zone color order */ /*-----------------------------------------------------*\ | Zone Constructor / Destructor | @@ -344,6 +321,10 @@ enum RGBCONTROLLER_UPDATE_REASON_ADDSEGMENT, /* AddSegment() called */ RGBCONTROLLER_UPDATE_REASON_HIDDEN, /* Hidden flag set */ RGBCONTROLLER_UPDATE_REASON_UNHIDDEN, /* Hidden flag cleared */ + RGBCONTROLLER_UPDATE_REASON_SETDEVICESPECIFICCONFIGURATION, + /* SetDeviceSpecificConfiguration() called */ + RGBCONTROLLER_UPDATE_REASON_SETDEVICESPECIFICZONECONFIGURATION, + /* SetDeviceSpecificZoneConfiguration() called */ }; std::string device_type_to_str(device_type type); @@ -376,7 +357,6 @@ public: virtual zone GetZone(unsigned int zone_idx) = 0; virtual int GetZoneActiveMode(unsigned int zone) = 0; virtual RGBColor GetZoneColor(unsigned int zone, unsigned int color_index) = 0; - virtual zone_color_order GetZoneColorOrder(unsigned int zone) = 0; virtual RGBColor* GetZoneColorsPointer(unsigned int zone) = 0; virtual std::size_t GetZoneCount() = 0; virtual unsigned int GetZoneFlags(unsigned int zone) = 0; @@ -480,6 +460,17 @@ public: virtual void SetAllColors(RGBColor color) = 0; virtual void SetAllZoneColors(int zone, RGBColor color) = 0; + /*-----------------------------------------------------*\ + | Device-Specific Configuration Functions | + \*-----------------------------------------------------*/ + virtual nlohmann::json GetDeviceSpecificConfigurationSchema() = 0; + virtual nlohmann::json GetDeviceSpecificConfiguration() = 0; + virtual void SetDeviceSpecificConfiguration(nlohmann::json configuration_json) = 0; + + virtual nlohmann::json GetDeviceSpecificZoneConfigurationSchema(int zone) = 0; + virtual nlohmann::json GetDeviceSpecificZoneConfiguration(int zone) = 0; + virtual void SetDeviceSpecificZoneConfiguration(int zone, nlohmann::json configuration_json) = 0; + /*-----------------------------------------------------*\ | Update Callback Functions | \*-----------------------------------------------------*/ @@ -540,7 +531,6 @@ public: zone GetZone(unsigned int zone_idx); int GetZoneActiveMode(unsigned int zone); RGBColor GetZoneColor(unsigned int zone, unsigned int color_index); - zone_color_order GetZoneColorOrder(unsigned int zone); RGBColor* GetZoneColorsPointer(unsigned int zone); std::size_t GetZoneCount(); unsigned int GetZoneFlags(unsigned int zone); @@ -643,6 +633,17 @@ public: void SetAllColors(RGBColor color); void SetAllZoneColors(int zone, RGBColor color); + /*-----------------------------------------------------*\ + | Device-Specific Configuration Functions | + \*-----------------------------------------------------*/ + nlohmann::json GetDeviceSpecificConfigurationSchema(); + nlohmann::json GetDeviceSpecificConfiguration(); + void SetDeviceSpecificConfiguration(nlohmann::json configuration_json); + + nlohmann::json GetDeviceSpecificZoneConfigurationSchema(int zone); + nlohmann::json GetDeviceSpecificZoneConfiguration(int zone); + void SetDeviceSpecificZoneConfiguration(int zone, nlohmann::json configuration_json); + /*-----------------------------------------------------*\ | Update Callback Functions | \*-----------------------------------------------------*/ @@ -685,6 +686,9 @@ public: virtual void DeviceUpdateZoneMode(int zone); virtual void DeviceSaveMode(); + virtual void DeviceUpdateDeviceSpecificConfiguration(); + virtual void DeviceUpdateDeviceSpecificZoneConfiguration(int zone); + /*-----------------------------------------------------*\ | Static Serialized Description Functions | \*-----------------------------------------------------*/ @@ -738,6 +742,8 @@ protected: std::string serial; /* controller serial number */ std::string vendor; /* controller vendor */ std::string version; /* controller version */ + std::string configuration; /* controller device- */ + /* specific config JSON */ /*-----------------------------------------------------*\ | Controller variables | diff --git a/RGBController/RGBController_Network.cpp b/RGBController/RGBController_Network.cpp index 31fd8e05a..a882da15f 100644 --- a/RGBController/RGBController_Network.cpp +++ b/RGBController/RGBController_Network.cpp @@ -264,6 +264,61 @@ void RGBController_Network::DeviceSaveMode() delete[] data; } +void RGBController_Network::SetDeviceSpecificConfiguration(nlohmann::json configuration_json) +{ + std::string json_string = configuration_json.dump(); + + client->SendRequest_RGBController_SetDeviceSpecificConfiguration(dev_id, (unsigned char *)json_string.c_str(), strlen(json_string.c_str()) + 1); + + client->SendRequest_ControllerData(dev_id); + client->WaitOnControllerData(); +} + +void RGBController_Network::SetDeviceSpecificZoneConfiguration(int zone, nlohmann::json configuration_json) +{ + /*-----------------------------------------------------*\ + | Initialize variables | + \*-----------------------------------------------------*/ + unsigned int data_size = 0; + std::string json_string = configuration_json.dump(); + unsigned int json_string_size = strlen(json_string.c_str()) +1; + + /*-----------------------------------------------------*\ + | Calculate data size | + \*-----------------------------------------------------*/ + data_size += sizeof(int); + data_size += sizeof(json_string_size); + data_size += json_string_size; + + /*-----------------------------------------------------*\ + | Create data buffer | + \*-----------------------------------------------------*/ + unsigned char * data_buf = new unsigned char[data_size]; + unsigned char * data_ptr = data_buf; + + /*-----------------------------------------------------*\ + | Copy in zone | + \*-----------------------------------------------------*/ + memcpy(data_ptr, &zone, sizeof(zone)); + data_ptr += sizeof(zone); + + /*-----------------------------------------------------*\ + | Copy in string size | + \*-----------------------------------------------------*/ + memcpy(data_ptr, &json_string_size, sizeof(json_string_size)); + data_ptr += sizeof(json_string_size); + + memcpy(data_ptr, json_string.c_str(), json_string_size); + data_ptr += json_string_size; + + client->SendRequest_RGBController_SetDeviceSpecificZoneConfiguration(dev_id, data_buf, data_size); + + delete[] data_buf; + + client->SendRequest_ControllerData(dev_id); + client->WaitOnControllerData(); +} + /*-----------------------------------------------------*\ | This function overrides RGBController::UpdateLEDs()! | | Normally, UpdateLEDs() sets a flag for the updater | diff --git a/RGBController/RGBController_Network.h b/RGBController/RGBController_Network.h index 7d8acff9e..a529e597c 100644 --- a/RGBController/RGBController_Network.h +++ b/RGBController/RGBController_Network.h @@ -34,13 +34,17 @@ public: void DeviceUpdateSingleLED(int led); void SetCustomMode(); - void DeviceUpdateMode(); - void DeviceUpdateZoneMode(int zone); - void DeviceSaveMode(); + + void SetDeviceSpecificConfiguration(nlohmann::json configuration_json); + void SetDeviceSpecificZoneConfiguration(int zone, nlohmann::json configuration_json); void UpdateLEDs(); void UpdateMode(); + void DeviceUpdateMode(); + void DeviceUpdateZoneMode(int zone); + void DeviceSaveMode(); + private: NetworkClient * client; unsigned int dev_id; diff --git a/ResourceManager.cpp b/ResourceManager.cpp index 0b5d9bc23..76345984c 100644 --- a/ResourceManager.cpp +++ b/ResourceManager.cpp @@ -144,10 +144,85 @@ ResourceManager::ResourceManager() /*-----------------------------------------------------*\ | Load settings from file | \*-----------------------------------------------------*/ - settings_manager = new SettingsManager(); + settings_manager = new SettingsManager(); settings_manager->LoadSettings(GetConfigurationDirectory() / "OpenRGB.json"); + /*-----------------------------------------------------*\ + | Create Detection settings schema | + \*-----------------------------------------------------*/ + json detection_settings_schema; + + detection_settings_schema["hid_safe_mode"]["title"] = QT_TRANSLATE_NOOP("Settings", "HID Safe Mode"); + detection_settings_schema["hid_safe_mode"]["type"] = "bool"; + detection_settings_schema["hid_safe_mode"]["description"] = QT_TRANSLATE_NOOP("Settings", "Use an alternate method for detecting HID devices"); + + detection_settings_schema["initial_detection_delay_ms"]["title"] = QT_TRANSLATE_NOOP("Settings", "Initial Detection Delay (ms)"); + detection_settings_schema["initial_detection_delay_ms"]["type"] = "integer"; + detection_settings_schema["initial_detection_delay_ms"]["description"] = QT_TRANSLATE_NOOP("Settings", "Amount of time, in milliseconds, to wait before detecting devices when started"); + + settings_manager->RegisterSettingsSchema("Detectors", "Detection", detection_settings_schema); + + /*-----------------------------------------------------*\ + | Create LogManager settings schema | + \*-----------------------------------------------------*/ + json logmanager_settings_schema; + + logmanager_settings_schema["log_console"]["title"] = QT_TRANSLATE_NOOP("Settings", "Enable Log Console"); + logmanager_settings_schema["log_console"]["type"] = "bool"; + + logmanager_settings_schema["log_file"]["title"] = QT_TRANSLATE_NOOP("Settings", "Enable Log File"); + logmanager_settings_schema["log_file"]["type"] = "bool"; + logmanager_settings_schema["log_file"]["default"] = true; + + logmanager_settings_schema["loglevel"]["title"] = QT_TRANSLATE_NOOP("Settings", "Log Level"); + logmanager_settings_schema["loglevel"]["type"] = "integer"; + logmanager_settings_schema["loglevel"]["enum"][0] = 0; + logmanager_settings_schema["loglevel"]["enumNames"][0] = "Fatal"; + logmanager_settings_schema["loglevel"]["enum"][1] = 1; + logmanager_settings_schema["loglevel"]["enumNames"][1] = "Error"; + logmanager_settings_schema["loglevel"]["enum"][2] = 2; + logmanager_settings_schema["loglevel"]["enumNames"][2] = "Warning"; + logmanager_settings_schema["loglevel"]["enum"][3] = 3; + logmanager_settings_schema["loglevel"]["enumNames"][3] = "Info"; + logmanager_settings_schema["loglevel"]["enum"][4] = 4; + logmanager_settings_schema["loglevel"]["enumNames"][4] = "Verbose"; + logmanager_settings_schema["loglevel"]["enum"][5] = 5; + logmanager_settings_schema["loglevel"]["enumNames"][5] = "Debug"; + logmanager_settings_schema["loglevel"]["enum"][6] = 6; + logmanager_settings_schema["loglevel"]["enumNames"][6] = "Trace"; + + logmanager_settings_schema["file_count_limit"]["title"] = QT_TRANSLATE_NOOP("Settings", "Log File Count Limit"); + logmanager_settings_schema["file_count_limit"]["type"] = "integer"; + logmanager_settings_schema["file_count_limit"]["minimum"] = 0; + + settings_manager->RegisterSettingsSchema("LogManager", "Log Manager", logmanager_settings_schema); + + /*-----------------------------------------------------*\ + | Create Server settings schema | + \*-----------------------------------------------------*/ + json server_settings_schema; + + server_settings_schema["all_controllers"]["title"] = QT_TRANSLATE_NOOP("Settings", "Serve All Controllers"); + server_settings_schema["all_controllers"]["type"] = "bool"; + server_settings_schema["all_controllers"]["description"] = QT_TRANSLATE_NOOP("Settings", "Include controllers provided by client connections and plugins"); + + server_settings_schema["default_host"]["title"] = QT_TRANSLATE_NOOP("Settings", "Default Host"); + server_settings_schema["default_host"]["type"] = "string"; + server_settings_schema["default_host"]["default"] = OPENRGB_SDK_HOST; + + server_settings_schema["default_port"]["title"] = QT_TRANSLATE_NOOP("Settings", "Default Port"); + server_settings_schema["default_port"]["type"] = "integer"; + server_settings_schema["default_port"]["default"] = OPENRGB_SDK_PORT; + server_settings_schema["default_port"]["minimum"] = 0; + server_settings_schema["default_port"]["maximum"] = 65535; + + server_settings_schema["legacy_workaround"]["title"] = QT_TRANSLATE_NOOP("Settings", "Legacy Workaround"); + server_settings_schema["legacy_workaround"]["type"] = "bool"; + server_settings_schema["legacy_workaround"]["description"] = QT_TRANSLATE_NOOP("Settings", "Workaround for some older SDK implementations that sent incorrect packet size for certain packets"); + + settings_manager->RegisterSettingsSchema("Server", "Server", server_settings_schema); + /*-----------------------------------------------------*\ | Configure the log manager | \*-----------------------------------------------------*/ diff --git a/SettingsManager.cpp b/SettingsManager.cpp index e87d04e11..4729d87c4 100644 --- a/SettingsManager.cpp +++ b/SettingsManager.cpp @@ -13,17 +13,22 @@ #include #include +#include "JsonUtils.h" #include "LogManager.h" #include "NetworkClient.h" #include "ResourceManager.h" #include "SettingsManager.h" #include "StringUtils.h" +/*---------------------------------------------------------*\ +| SettingsManager name for log entries | +\*---------------------------------------------------------*/ +const char* SETTINGSMANAGER = "SettingsManager"; + static const std::string ui_settings_keys[7] = { "UserInterface", "AutoStart", - "Theme", "Plugins", "Client", "LogManager", @@ -59,14 +64,7 @@ json SettingsManager::GetSettings(std::string settings_key) | If this is a local client, request the settings | | from the server | \*-------------------------------------------------*/ - try - { - result = nlohmann::json::parse(ResourceManager::get()->GetLocalClient()->SettingsManager_GetSettings(settings_key)); - } - catch(...) - { - - } + JsonUtils::JsonParse(ResourceManager::get()->GetLocalClient()->SettingsManager_GetSettings(settings_key), result); } else { @@ -88,6 +86,97 @@ json SettingsManager::GetSettings(std::string settings_key) return result; } +json SettingsManager::GetSettingsSchema(std::string settings_key) +{ + if(settings_key == "") + { + return(settings_schema); + } + else if(settings_schema.contains(settings_key) && settings_schema[settings_key].contains("properties")) + { + return(settings_schema[settings_key]["properties"]); + } + else + { + nlohmann::json empty; + return(empty); + } +} + +void SettingsManager::RegisterSettingsSchema(std::string settings_key, std::string settings_title, json& new_schema) +{ + RegisterSettingsSchema(settings_key, settings_title, new_schema, -1); +} + +void SettingsManager::RegisterSettingsSchema(std::string settings_key, std::string settings_title, json& new_schema, int order) +{ + settings_schema[settings_key]["title"] = settings_title; + settings_schema[settings_key]["type"] = "object"; + settings_schema[settings_key]["properties"].update(new_schema, true); + + if(order >= 0) + { + settings_schema[settings_key]["order"] = order; + } + + SignalSettingsManagerUpdate(SETTINGSMANAGER_UPDATE_REASON_SETTINGS_SCHEMA_UPDATED); +} + +void SettingsManager::ModifySettings(std::string settings_key, json new_settings) +{ + bool ui_settings_key = false; + + for(std::size_t settings_key_idx = 0; settings_key_idx < 7; settings_key_idx++) + { + if(settings_key == ui_settings_keys[settings_key_idx]) + { + ui_settings_key = true; + break; + } + } + + if(!ui_settings_key && ResourceManager::get()->IsLocalClient() && (ResourceManager::get()->GetLocalClient()->GetSupportsSettingsManagerAPI())) + { + /*-------------------------------------------------*\ + | If this is a local client, request the settings | + | from the server | + \*-------------------------------------------------*/ + nlohmann::json settings_json; + + settings_json[settings_key] = new_settings; + + ResourceManager::get()->GetLocalClient()->SettingsManager_ModifySettings(settings_json.dump()); + } + else + { + mutex.lock(); + settings_data[settings_key].update(new_settings, true); + mutex.unlock(); + } + + SignalSettingsManagerUpdate(SETTINGSMANAGER_UPDATE_REASON_SETTINGS_UPDATED); +} + +void SettingsManager::ModifySettingsFromJsonString(std::string settings_json_str) +{ + /*-----------------------------------------------------*\ + | Parse the JSON string | + \*-----------------------------------------------------*/ + nlohmann::json settings_json; + JsonUtils::JsonParse(settings_json_str, settings_json); + + /*-----------------------------------------------------*\ + | Get key/value pairs from JSON, call SetSettings for | + | each key. This use of `auto` is acceptable due to | + | how the JSON library implements iterators, the type | + | would change based on the library version. | + \*-----------------------------------------------------*/ + for(auto& element : settings_json.items()) + { + ModifySettings(element.key(), element.value()); + } +} + void SettingsManager::SetSettings(std::string settings_key, json new_settings) { bool ui_settings_key = false; @@ -119,6 +208,8 @@ void SettingsManager::SetSettings(std::string settings_key, json new_settings) settings_data[settings_key] = new_settings; mutex.unlock(); } + + SignalSettingsManagerUpdate(SETTINGSMANAGER_UPDATE_REASON_SETTINGS_UPDATED); } void SettingsManager::SetSettingsFromJsonString(std::string settings_json_str) @@ -126,7 +217,8 @@ void SettingsManager::SetSettingsFromJsonString(std::string settings_json_str) /*-----------------------------------------------------*\ | Parse the JSON string | \*-----------------------------------------------------*/ - nlohmann::json settings_json = nlohmann::json::parse(settings_json_str); + nlohmann::json settings_json; + JsonUtils::JsonParse(settings_json_str, settings_json); /*-----------------------------------------------------*\ | Get key/value pairs from JSON, call SetSettings for | @@ -214,10 +306,76 @@ void SettingsManager::SaveSettings() } catch(const std::exception& e) { - LOG_ERROR("[SettingsManager] Cannot write to file: %s", e.what()); + LOG_ERROR("[%s] Cannot write to file: %s", SETTINGSMANAGER, e.what()); } settings_file.close(); } mutex.unlock(); } + +/*---------------------------------------------------------*\ +| Callback Registration Functions | +\*---------------------------------------------------------*/ +void SettingsManager::RegisterSettingsManagerCallback(SettingsManagerCallback new_callback, void * new_callback_arg) +{ + SettingsManagerCallbackMutex.lock(); + + for(size_t idx = 0; idx < SettingsManagerCallbacks.size(); idx++) + { + if(SettingsManagerCallbackArgs[idx] == new_callback && SettingsManagerCallbackArgs[idx] == new_callback_arg) + { + SettingsManagerCallbackMutex.unlock(); + + LOG_TRACE("[%s] Tried to register an already registered SettingsManager callback, skipping. Total callbacks registered: %d", SETTINGSMANAGER, SettingsManagerCallbacks.size()); + + return; + } + } + + SettingsManagerCallbacks.push_back(new_callback); + SettingsManagerCallbackArgs.push_back(new_callback_arg); + + SettingsManagerCallbackMutex.unlock(); + + LOG_TRACE("[%s] Registered SettingsManager callback. Total callbacks registered: %d", SETTINGSMANAGER, SettingsManagerCallbacks.size()); +} + +void SettingsManager::UnregisterSettingsManagerCallback(SettingsManagerCallback callback, void * callback_arg) +{ + SettingsManagerCallbackMutex.lock(); + + for(size_t idx = 0; idx < SettingsManagerCallbacks.size(); idx++) + { + if(SettingsManagerCallbacks[idx] == callback && SettingsManagerCallbackArgs[idx] == callback_arg) + { + SettingsManagerCallbacks.erase(SettingsManagerCallbacks.begin() + idx); + SettingsManagerCallbackArgs.erase(SettingsManagerCallbackArgs.begin() + idx); + } + } + + SettingsManagerCallbackMutex.unlock(); + + LOG_TRACE("[%s] Unregistered SettingsManager callback. Total callbacks registered: %d", SETTINGSMANAGER, SettingsManagerCallbackArgs.size()); +} + +void SettingsManager::SignalSettingsManagerUpdate(unsigned int update_reason) +{ +// NetworkServer* server = ResourceManager::get()->GetServer(); +// +// if(server) +// { +// server->SignalProfileManagerUpdate(update_reason); +// } + + SettingsManagerCallbackMutex.lock(); + + for(std::size_t callback_idx = 0; callback_idx < SettingsManagerCallbacks.size(); callback_idx++) + { + SettingsManagerCallbacks[callback_idx](SettingsManagerCallbackArgs[callback_idx], update_reason); + } + + SettingsManagerCallbackMutex.unlock(); + + LOG_TRACE("[%s] SettingsManager update signalled: %d", SETTINGSMANAGER, update_reason); +} diff --git a/SettingsManager.h b/SettingsManager.h index db48af344..afcd4bd5c 100644 --- a/SettingsManager.h +++ b/SettingsManager.h @@ -17,17 +17,37 @@ #include #include "filesystem.h" -using json = nlohmann::json; +/*---------------------------------------------------------*\ +| Define a macro for QT lupdate to parse | +\*---------------------------------------------------------*/ +#define QT_TRANSLATE_NOOP(scope, x) x + +/*---------------------------------------------------------*\ +| Callback Types | +\*---------------------------------------------------------*/ +typedef void (*SettingsManagerCallback)(void *, unsigned int); + +/*---------------------------------------------------------*\ +| SettingsManager Update Reason Codes | +\*---------------------------------------------------------*/ +enum +{ + SETTINGSMANAGER_UPDATE_REASON_SETTINGS_UPDATED, /* Settings updated */ + SETTINGSMANAGER_UPDATE_REASON_SETTINGS_SCHEMA_UPDATED, /* Settings schema updated */ +}; class SettingsManagerInterface { public: - virtual json GetSettings(std::string settings_key) = 0; - virtual void SetSettings(std::string settings_key, json new_settings) = 0; - virtual void SetSettingsFromJsonString(std::string settings_json_str) = 0; + virtual nlohmann::json GetSettings(std::string settings_key) = 0; + virtual nlohmann::json GetSettingsSchema(std::string settings_key) = 0; + virtual void ModifySettings(std::string settings_key, nlohmann::json new_settings) = 0; + virtual void ModifySettingsFromJsonString(std::string settings_json_str) = 0; + virtual void SetSettings(std::string settings_key, nlohmann::json new_settings) = 0; + virtual void SetSettingsFromJsonString(std::string settings_json_str) = 0; - virtual void LoadSettings(const filesystem::path& filename) = 0; - virtual void SaveSettings() = 0; + virtual void LoadSettings(const filesystem::path& filename) = 0; + virtual void SaveSettings() = 0; protected: virtual ~SettingsManagerInterface() {}; @@ -39,17 +59,52 @@ public: SettingsManager(); ~SettingsManager(); - json GetSettings(std::string settings_key) override; - void SetSettings(std::string settings_key, json new_settings) override; - void SetSettingsFromJsonString(std::string settings_json_str) override; + nlohmann::json GetSettings(std::string settings_key); + nlohmann::json GetSettingsSchema(std::string settings_key); + void RegisterSettingsSchema(std::string settings_key, std::string settings_title, nlohmann::json& new_schema); + void RegisterSettingsSchema(std::string settings_key, std::string settings_title, nlohmann::json& new_schema, int order); + void ModifySettings(std::string settings_key, nlohmann::json new_settings); + void ModifySettingsFromJsonString(std::string settings_json_str); + void SetSettings(std::string settings_key, nlohmann::json new_settings); + void SetSettingsFromJsonString(std::string settings_json_str); - void LoadSettings(const filesystem::path& filename) override; - void SaveSettings() override; + void LoadSettings(const filesystem::path& filename); + void SaveSettings(); + + /*-----------------------------------------------------*\ + | Callback Registration Functions | + \*-----------------------------------------------------*/ + void RegisterSettingsManagerCallback(SettingsManagerCallback new_callback, void * new_callback_arg); + void UnregisterSettingsManagerCallback(SettingsManagerCallback callback, void * callback_arg); + + void SignalSettingsManagerUpdate(unsigned int update_reason); private: - json settings_data; - json settings_prototype; - filesystem::path settings_filename; - std::mutex mutex; - bool config_found; + /*-----------------------------------------------------*\ + | JSON objects for settings data and schema | + \*-----------------------------------------------------*/ + nlohmann::json settings_data; + nlohmann::json settings_schema; + + /*-----------------------------------------------------*\ + | Settings filename | + \*-----------------------------------------------------*/ + filesystem::path settings_filename; + + /*-----------------------------------------------------*\ + | Settings mutex | + \*-----------------------------------------------------*/ + std::mutex mutex; + + /*-----------------------------------------------------*\ + | Configuration found flag | + \*-----------------------------------------------------*/ + bool config_found; + + /*-----------------------------------------------------*\ + | SettingsManager Callbacks | + \*-----------------------------------------------------*/ + std::vector SettingsManagerCallbacks; + std::vector SettingsManagerCallbackArgs; + std::mutex SettingsManagerCallbackMutex; }; diff --git a/cli.cpp b/cli.cpp index 0ba1139ac..98b567d5d 100644 --- a/cli.cpp +++ b/cli.cpp @@ -863,9 +863,9 @@ bool OptionSize(std::vector* current_devices, std::string argumen rgb_controllers[current_device]->ResizeZone(current_zone, new_size); /*---------------------------------------------------------*\ - | Save the profile | + | Save configuration | \*---------------------------------------------------------*/ - ResourceManager::get()->GetProfileManager()->SaveSizes(); + ResourceManager::get()->GetProfileManager()->SaveConfiguration(); } return true; diff --git a/qt/DeviceView.cpp b/qt/DeviceView.cpp index 9de7b6b36..e9a39499f 100644 --- a/qt/DeviceView.cpp +++ b/qt/DeviceView.cpp @@ -19,7 +19,6 @@ #include "ResourceManager.h" #include "RGBControllerKeyNames.h" #include "RGBController.h" -#include "SettingsManager.h" #define MAX_COLS 20 #define PAD_LED 0.1f @@ -256,6 +255,14 @@ QSize DeviceView::sizeHint() const \*---------------------------------------------------------*/ bool DeviceView::SelectLED(std::size_t led_idx) { + /*-----------------------------------------------------*\ + | Verify controller exists | + \*-----------------------------------------------------*/ + if(controller == NULL) + { + return(false); + } + /*-----------------------------------------------------*\ | Check validity | \*-----------------------------------------------------*/ @@ -289,6 +296,14 @@ bool DeviceView::SelectLED(std::size_t led_idx) bool DeviceView::SelectLEDs(std::vector leds) { + /*-----------------------------------------------------*\ + | Verify controller exists | + \*-----------------------------------------------------*/ + if(controller == NULL) + { + return(false); + } + /*-----------------------------------------------------*\ | Check validity | \*-----------------------------------------------------*/ @@ -339,6 +354,14 @@ bool DeviceView::SelectLEDs(std::vector leds) bool DeviceView::SelectSegment(std::size_t zone_idx, std::size_t segment_idx, bool add) { + /*-----------------------------------------------------*\ + | Verify controller exists | + \*-----------------------------------------------------*/ + if(controller == NULL) + { + return(false); + } + /*-----------------------------------------------------*\ | Check validity | \*-----------------------------------------------------*/ @@ -400,6 +423,14 @@ bool DeviceView::SelectSegment(std::size_t zone_idx, std::size_t segment_idx, bo bool DeviceView::SelectZone(std::size_t zone_idx, bool add) { + /*-----------------------------------------------------*\ + | Verify controller exists | + \*-----------------------------------------------------*/ + if(controller == NULL) + { + return(false); + } + /*-----------------------------------------------------*\ | Check validity | \*-----------------------------------------------------*/ @@ -458,6 +489,14 @@ bool DeviceView::SelectZone(std::size_t zone_idx, bool add) \*---------------------------------------------------------*/ void DeviceView::ClearSelection() { + /*-----------------------------------------------------*\ + | Verify controller exists | + \*-----------------------------------------------------*/ + if(controller == NULL) + { + return; + } + /*-----------------------------------------------------*\ | Same as selecting the entire device | \*-----------------------------------------------------*/ @@ -482,12 +521,24 @@ void DeviceView::SetController(RGBController * controller_ptr) controller = controller_ptr; } +void DeviceView::SetDisableKeyExpansion(bool disable_key_expansion) +{ + /*-----------------------------------------------------*\ + | Store the disable key expansion flag | + \*-----------------------------------------------------*/ + disable_expansion = disable_key_expansion; + + InitDeviceView(); +} + void DeviceView::SetNumericalLabels(bool enable) { /*-----------------------------------------------------*\ | Store the numerical labels flag | \*-----------------------------------------------------*/ numerical_labels = enable; + + InitDeviceView(); } void DeviceView::SetPerLED(bool per_led_mode) @@ -505,6 +556,14 @@ void DeviceView::SetPerLED(bool per_led_mode) void DeviceView::SetSelectionColor(RGBColor color) { + /*-----------------------------------------------------*\ + | Verify controller exists | + \*-----------------------------------------------------*/ + if(controller == NULL) + { + return; + } + /*-----------------------------------------------------*\ | If no LEDs are selected, set entire device using the | | SetAllColors function | @@ -541,6 +600,14 @@ void DeviceView::SetSelectionColor(RGBColor color) \*---------------------------------------------------------*/ void DeviceView::mousePressEvent(QMouseEvent *event) { + /*-----------------------------------------------------*\ + | Verify controller exists | + \*-----------------------------------------------------*/ + if(controller == NULL) + { + return; + } + /*-----------------------------------------------------*\ | Only handle events when in per-LED mode | \*-----------------------------------------------------*/ @@ -592,6 +659,14 @@ void DeviceView::mousePressEvent(QMouseEvent *event) void DeviceView::mouseMoveEvent(QMouseEvent *event) { + /*-----------------------------------------------------*\ + | Verify controller exists | + \*-----------------------------------------------------*/ + if(controller == NULL) + { + return; + } + /*-----------------------------------------------------*\ | Only handle events when in per-LED mode | \*-----------------------------------------------------*/ @@ -656,6 +731,14 @@ void DeviceView::mouseMoveEvent(QMouseEvent *event) void DeviceView::mouseReleaseEvent(QMouseEvent* event) { + /*-----------------------------------------------------*\ + | Verify controller exists | + \*-----------------------------------------------------*/ + if(controller == NULL) + { + return; + } + /*-----------------------------------------------------*\ | Only handle events when in per-LED mode | \*-----------------------------------------------------*/ @@ -780,6 +863,14 @@ void DeviceView::resizeEvent(QResizeEvent* /*event*/) void DeviceView::paintEvent(QPaintEvent* /* event */) { + /*-----------------------------------------------------*\ + | Verify controller exists | + \*-----------------------------------------------------*/ + if(controller == NULL) + { + return; + } + /*-----------------------------------------------------*\ | If Device View is hidden, don't paint | \*-----------------------------------------------------*/ @@ -1014,6 +1105,14 @@ void DeviceView::paintEvent(QPaintEvent* /* event */) \*---------------------------------------------------------*/ void DeviceView::InitDeviceView() { + /*-----------------------------------------------------*\ + | Verify controller exists | + \*-----------------------------------------------------*/ + if(controller == NULL) + { + return; + } + /*-----------------------------------------------------*\ | Set the size of the selection flags vector | \*-----------------------------------------------------*/ @@ -1033,19 +1132,6 @@ void DeviceView::InitDeviceView() unsigned int segment_count = 0; float total_height = 0.0f; - /*-----------------------------------------------------*\ - | Get device view settings | - \*-----------------------------------------------------*/ - SettingsManager* settings_manager = ResourceManager::get()->GetSettingsManager(); - std::string ui_string = "UserInterface"; - json ui_settings = settings_manager->GetSettings(ui_string); - bool disable_expansion = false; - - if(ui_settings.contains("disable_key_expansion")) - { - disable_expansion = ui_settings["disable_key_expansion"]; - } - /*-----------------------------------------------------*\ | Determine the total height (in LEDs) of all zones | \*-----------------------------------------------------*/ @@ -1325,6 +1411,10 @@ void DeviceView::InitDeviceView() { led_labels[led_idx] = QString::number(led_idx); } + else + { + led_labels[led_idx] = ""; + } } /*-----------------------------------------------------*\ @@ -1377,6 +1467,14 @@ void DeviceView::InitDeviceView() void DeviceView::UpdateSelection() { + /*-----------------------------------------------------*\ + | Verify controller exists | + \*-----------------------------------------------------*/ + if(controller == NULL) + { + return; + } + /*-----------------------------------------------------*\ | Clear existing selection | \*-----------------------------------------------------*/ diff --git a/qt/DeviceView.h b/qt/DeviceView.h index deeb7de03..66cdf1553 100644 --- a/qt/DeviceView.h +++ b/qt/DeviceView.h @@ -49,6 +49,7 @@ public: void ClearSelection(); void SetChanged(); void SetController(RGBController * controller_ptr); + void SetDisableKeyExpansion(bool disable_key_expansion); void SetNumericalLabels(bool enable); void SetPerLED(bool per_led_mode); void SetSelectionColor(RGBColor); @@ -69,6 +70,7 @@ private: \*-----------------------------------------------------*/ bool changed; bool ctrl_down; + bool disable_expansion; QPoint last_mouse_point; bool mouse_down; bool mouse_moved; diff --git a/qt/OpenRGBDeviceEditorDialog/OpenRGBDeviceEditorDialog.cpp b/qt/OpenRGBDeviceEditorDialog/OpenRGBDeviceEditorDialog.cpp new file mode 100644 index 000000000..e0bd9e770 --- /dev/null +++ b/qt/OpenRGBDeviceEditorDialog/OpenRGBDeviceEditorDialog.cpp @@ -0,0 +1,113 @@ +/*---------------------------------------------------------*\ +| OpenRGBDeviceEditorDialog.cpp | +| | +| User interface for OpenRGB device editor dialog | +| | +| Adam Honse 15 Apr 2026 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#include "OpenRGBDynamicSettingsWidget.h" +#include "OpenRGBDeviceEditorDialog.h" +#include "ProfileManager.h" +#include "ResourceManager.h" +#include "ui_OpenRGBDeviceEditorDialog.h" + +static void Callback(void* this_ptr, std::string key, nlohmann::json settings) +{ + ((OpenRGBDeviceEditorDialog*)this_ptr)->OnSettingChanged(key, settings); +} + +OpenRGBDeviceEditorDialog::OpenRGBDeviceEditorDialog(RGBController *dev, QWidget *parent) : + QDialog(parent), + ui(new Ui::OpenRGBDeviceEditorDialog) +{ + ui->setupUi(this); + + /*-----------------------------------------------------*\ + | Store device pointer | + \*-----------------------------------------------------*/ + edit_dev = dev; + + /*-----------------------------------------------------*\ + | Append zone name to window title | + \*-----------------------------------------------------*/ + QString currentTitle = windowTitle(); + + QString newTitle = currentTitle + " - " + QString::fromStdString(edit_dev->GetName()); + + setWindowTitle(newTitle); + + /*-----------------------------------------------------*\ + | Initialize configuration schema and data | + \*-----------------------------------------------------*/ + nlohmann::json configuration_schema = edit_dev->GetDeviceSpecificConfigurationSchema(); + nlohmann::json configuration_value = edit_dev->GetDeviceSpecificConfiguration(); + + /*-----------------------------------------------------*\ + | Loop through the schema and create an entry for each | + | setting | + \*-----------------------------------------------------*/ + for(nlohmann::json::iterator json_iterator = configuration_schema.begin(); json_iterator != configuration_schema.end(); json_iterator++) + { + nlohmann::json schema_entry = json_iterator.value(); + OpenRGBDynamicSettingsWidget* item_widget = new OpenRGBDynamicSettingsWidget(json_iterator.key(), schema_entry, configuration_value); + + item_widget->SetCallback(Callback, this); + ui->ScrollAreaDeviceConfigurationLayout->addWidget(item_widget); + } + + /*-----------------------------------------------------*\ + | Add a spacer at the end to prevent expanding | + \*-----------------------------------------------------*/ + QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); + ui->ScrollAreaDeviceConfigurationLayout->addItem(spacer); +} + +OpenRGBDeviceEditorDialog::~OpenRGBDeviceEditorDialog() +{ + +} + +int OpenRGBDeviceEditorDialog::show() +{ + /*-----------------------------------------------------*\ + | Execute this dialog | + \*-----------------------------------------------------*/ + int ret_val = 0; + int result = this->exec(); + + /*-----------------------------------------------------*\ + | Return -1 if cancelled or edit device is invalid | + \*-----------------------------------------------------*/ + if(result == QDialog::Rejected || edit_dev == NULL) + { + ret_val = -1; + } + else + { + /*-------------------------------------------------*\ + | Apply the configuration | + \*-------------------------------------------------*/ + edit_dev->SetDeviceSpecificConfiguration(device_configuration); + + /*-------------------------------------------------*\ + | Save the configuration | + \*-------------------------------------------------*/ + ProfileManager* profile_manager = ResourceManager::get()->GetProfileManager(); + + if(profile_manager != NULL) + { + profile_manager->SaveConfiguration(); + } + } + + return(ret_val); +} + +void OpenRGBDeviceEditorDialog::OnSettingChanged(std::string /*key*/, nlohmann::json settings) +{ + device_configuration.update(settings, true); +} diff --git a/qt/OpenRGBDeviceEditorDialog/OpenRGBDeviceEditorDialog.h b/qt/OpenRGBDeviceEditorDialog/OpenRGBDeviceEditorDialog.h new file mode 100644 index 000000000..2a4e6a4a5 --- /dev/null +++ b/qt/OpenRGBDeviceEditorDialog/OpenRGBDeviceEditorDialog.h @@ -0,0 +1,48 @@ +/*---------------------------------------------------------*\ +| OpenRGBDeviceEditorDialog.h | +| | +| User interface for OpenRGB device editor dialog | +| | +| Adam Honse 15 Apr 2026 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#pragma once + +#include +#include "RGBController.h" + +namespace Ui +{ + class OpenRGBDeviceEditorDialog; +} + +class OpenRGBDeviceEditorDialog : public QDialog +{ + Q_OBJECT + +public: + explicit OpenRGBDeviceEditorDialog(RGBController *dev, QWidget *parent = nullptr); + ~OpenRGBDeviceEditorDialog(); + + int show(); + void OnSettingChanged(std::string key, nlohmann::json settings); + +private: + /*-----------------------------------------------------*\ + | UI Pointer | + \*-----------------------------------------------------*/ + Ui::OpenRGBDeviceEditorDialog* ui; + + /*-----------------------------------------------------*\ + | Device pointer | + \*-----------------------------------------------------*/ + RGBController* edit_dev; + + /*-----------------------------------------------------*\ + | Device configuration | + \*-----------------------------------------------------*/ + nlohmann::json device_configuration; +}; diff --git a/qt/OpenRGBDeviceEditorDialog/OpenRGBDeviceEditorDialog.ui b/qt/OpenRGBDeviceEditorDialog/OpenRGBDeviceEditorDialog.ui new file mode 100644 index 000000000..40a83af75 --- /dev/null +++ b/qt/OpenRGBDeviceEditorDialog/OpenRGBDeviceEditorDialog.ui @@ -0,0 +1,69 @@ + + + OpenRGBDeviceEditorDialog + + + + 0 + 0 + 400 + 300 + + + + Device Editor + + + + + + Device-Specific Configuration + + + + + + true + + + + + 0 + 0 + 368 + 232 + + + + + + + + + + QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok + + + + + + + + + + + + + ButtonBox + accepted() + OpenRGBDeviceEditorDialog + accept() + + + ButtonBox + rejected() + OpenRGBDeviceEditorDialog + reject() + + + diff --git a/qt/OpenRGBDevicePage/OpenRGBDevicePage.cpp b/qt/OpenRGBDevicePage/OpenRGBDevicePage.cpp index b4e6b82b3..ad08dfb00 100644 --- a/qt/OpenRGBDevicePage/OpenRGBDevicePage.cpp +++ b/qt/OpenRGBDevicePage/OpenRGBDevicePage.cpp @@ -8,12 +8,25 @@ \*---------------------------------------------------------*/ #include "OpenRGBDevicePage.h" +#include "OpenRGBDeviceEditorDialog.h" #include "OpenRGBZoneEditorDialog.h" #include "ProfileManager.h" #include "ResourceManager.h" #include "SettingsManager.h" #include "ui_OpenRGBDevicePage.h" +static void OpenRGBDevicePageSettingsManagerCallback(void * this_ptr, unsigned int update_reason) +{ + OpenRGBDevicePage * this_obj = (OpenRGBDevicePage *)this_ptr; + + switch(update_reason) + { + case SETTINGSMANAGER_UPDATE_REASON_SETTINGS_UPDATED: + QMetaObject::invokeMethod(this_obj, "on_SettingsUpdated", Qt::QueuedConnection); + break; + } +} + static void UpdateCallback(void * this_ptr, unsigned int update_reason, void * /*controller_ptr*/) { OpenRGBDevicePage * this_obj = (OpenRGBDevicePage *)this_ptr; @@ -37,39 +50,20 @@ OpenRGBDevicePage::OpenRGBDevicePage(RGBController *dev, QWidget *parent) : \*-----------------------------------------------------*/ device->RegisterUpdateCallback(UpdateCallback, this); + /*-----------------------------------------------------*\ + | Register settings manager callbacks | + \*-----------------------------------------------------*/ + ResourceManager::get()->GetSettingsManager()->RegisterSettingsManagerCallback(OpenRGBDevicePageSettingsManagerCallback, this); + /*-----------------------------------------------------*\ | Set up the device view | \*-----------------------------------------------------*/ connect(ui->DeviceViewBox, &DeviceView::selectionChanged, this, &OpenRGBDevicePage::on_DeviceViewBox_selectionChanged); /*-----------------------------------------------------*\ - | Get the UserInterface settings and check the | - | numerical labels and hex format settings | + | Initialize Settings | \*-----------------------------------------------------*/ - SettingsManager* settings_manager = ResourceManager::get()->GetSettingsManager(); - std::string ui_string = "UserInterface"; - json ui_settings; - - ui_settings = settings_manager->GetSettings(ui_string); - - if(ui_settings.contains("numerical_labels")) - { - bool numerical_labels = ui_settings["numerical_labels"]; - - ui->DeviceViewBox->SetNumericalLabels(numerical_labels); - } - - if(ui_settings.contains("hex_format")) - { - if(ui_settings["hex_format"] == "RGB") - { - HexFormatRGB = true; - } - else if(ui_settings["hex_format"] == "BGR") - { - HexFormatRGB = false; - } - } + on_SettingsUpdated(); /*-----------------------------------------------------*\ | Initialize Device View | @@ -118,6 +112,11 @@ OpenRGBDevicePage::~OpenRGBDevicePage() } } + /*-----------------------------------------------------*\ + | Unregister settings manager callbacks | + \*-----------------------------------------------------*/ + ResourceManager::get()->GetSettingsManager()->UnregisterSettingsManagerCallback(OpenRGBDevicePageSettingsManagerCallback, this); + delete ui; } @@ -524,7 +523,8 @@ void OpenRGBDevicePage::UpdateLEDList() | Editing is not allowed when all zones are | | selected at once | \*-----------------------------------------*/ - ui->EditZoneButton->setEnabled(false); + ui->EditZoneButton->setEnabled(true); + ui->EditZoneButton->setText("Edit Device"); if(!ui->ZoneBox->signalsBlocked()) { @@ -581,7 +581,8 @@ void OpenRGBDevicePage::UpdateLEDList() zone_is_editable = true; } - ui->EditZoneButton->setEnabled(zone_is_editable); + ui->EditZoneButton->setEnabled(true); + ui->EditZoneButton->setText("Edit Zone"); if(!ui->ZoneBox->signalsBlocked()) { @@ -1671,18 +1672,8 @@ void OpenRGBDevicePage::UpdateModeUi() if(device->GetZoneCount() > 1) { - ui->ZoneBox->setEnabled(1); ui->ZoneBox->addItem(tr("All Zones")); } - else if(device->GetZoneCount() == 1 && device->GetZoneSegmentCount(0) > 1) - { - ui->ZoneBox->setEnabled(1); - } - else - { - ui->ZoneBox->setDisabled(1); - ui->EditZoneButton->setEnabled(false); - } for(std::size_t zone_idx = 0; zone_idx < device->GetZoneCount(); zone_idx++) { @@ -1764,19 +1755,12 @@ void OpenRGBDevicePage::UpdateZoneList() ui->ZoneBox->blockSignals(true); ui->ZoneBox->clear(); - if(device->GetZoneCount() > 1) - { - ui->ZoneBox->setEnabled(1); - ui->ZoneBox->addItem(tr("Entire Device")); - } - else if(device->GetZoneCount() == 1 && device->GetZoneSegmentCount(0) > 1) - { - ui->ZoneBox->setEnabled(1); - } - else + ui->ZoneBox->setEnabled(1); + ui->ZoneBox->addItem(tr("Entire Device")); + + if(device->GetZoneCount() == 0) { ui->ZoneBox->setDisabled(1); - ui->EditZoneButton->setEnabled(false); } for(std::size_t zone_idx = 0; zone_idx < device->GetZoneCount(); zone_idx++) @@ -1898,18 +1882,14 @@ void OpenRGBDevicePage::GetSelectedZone(bool * selected_all_zones, int * selecte | which adds an "All Zones" entry to the Zone menu in | | the first index | \*-----------------------------------------------------*/ - if(device->GetZoneCount() > 1) + if(index == current_index) { - if(index == current_index) - { - *selected_all_zones = true; - } - - current_index++; + *selected_all_zones = true; } - - if(!(*selected_all_zones)) + else { + current_index++; + for(std::size_t zone_idx = 0; zone_idx < device->GetZoneCount(); zone_idx++) { if(index == (int)current_index) @@ -1950,10 +1930,7 @@ void OpenRGBDevicePage::SetSelectedZone(bool selected_all_zones, int selected_zo return; } - if(device->GetZoneCount() > 1) - { - current_index++; - } + current_index++; for(std::size_t zone_idx = 0; zone_idx < device->GetZoneCount(); zone_idx++) { @@ -2055,6 +2032,8 @@ void OpenRGBDevicePage::UpdateInterface(unsigned int update_reason) case RGBCONTROLLER_UPDATE_REASON_ADDSEGMENT: case RGBCONTROLLER_UPDATE_REASON_CLEARSEGMENTS: case RGBCONTROLLER_UPDATE_REASON_CONFIGUREZONE: + case RGBCONTROLLER_UPDATE_REASON_SETDEVICESPECIFICCONFIGURATION: + case RGBCONTROLLER_UPDATE_REASON_SETDEVICESPECIFICZONECONFIGURATION: UpdateModeUi(); ui->DeviceViewBox->SetChanged(); ui->DeviceViewBox->repaint(); @@ -2234,22 +2213,24 @@ void OpenRGBDevicePage::on_EditZoneButton_clicked() | the edit button should not be clickable. | | If somehow this did get clicked, ignore. | \*-----------------------------------------*/ - if(selected_all_zones || selected_segment != -1) + if(selected_all_zones) { - return; + OpenRGBDeviceEditorDialog dlg(device); + dlg.show(); } + else + { + OpenRGBZoneEditorDialog dlg(device, selected_zone); + dlg.show(); - OpenRGBZoneEditorDialog dlg(device, selected_zone); - - dlg.show(); - - /*-----------------------------------------*\ - | Update Zone list and then reset the | - | current index | - \*-----------------------------------------*/ - selected_zone = ui->ZoneBox->currentIndex(); - UpdateZoneList(); - ui->ZoneBox->setCurrentIndex(selected_zone); + /*-----------------------------------------*\ + | Update Zone list and then reset the | + | current index | + \*-----------------------------------------*/ + selected_zone = ui->ZoneBox->currentIndex(); + UpdateZoneList(); + ui->ZoneBox->setCurrentIndex(selected_zone); + } } break; } @@ -2531,6 +2512,45 @@ void OpenRGBDevicePage::on_SetAllButton_clicked() emit SetAllDevices(current_color.red(), current_color.green(), current_color.blue()); } +void OpenRGBDevicePage::on_SettingsUpdated() +{ + /*-----------------------------------------------------*\ + | Get the UserInterface settings and check the | + | numerical labels and hex format settings | + \*-----------------------------------------------------*/ + SettingsManager* settings_manager = ResourceManager::get()->GetSettingsManager(); + std::string ui_string = "UserInterface"; + json ui_settings; + + ui_settings = settings_manager->GetSettings(ui_string); + + if(ui_settings.contains("numerical_labels")) + { + bool numerical_labels = ui_settings["numerical_labels"]; + + ui->DeviceViewBox->SetNumericalLabels(numerical_labels); + } + + if(ui_settings.contains("disable_key_expansion")) + { + bool disable_expansion = ui_settings["disable_key_expansion"]; + + ui->DeviceViewBox->SetDisableKeyExpansion(disable_expansion); + } + + if(ui_settings.contains("hex_format")) + { + if(ui_settings["hex_format"] == "RGB") + { + HexFormatRGB = true; + } + else if(ui_settings["hex_format"] == "BGR") + { + HexFormatRGB = false; + } + } +} + void OpenRGBDevicePage::on_SpeedSlider_valueChanged(int /*value*/) { ResourceManager::get()->GetProfileManager()->ClearActiveProfile(); diff --git a/qt/OpenRGBDevicePage/OpenRGBDevicePage.h b/qt/OpenRGBDevicePage/OpenRGBDevicePage.h index 70fcffc35..d87cc8b4f 100644 --- a/qt/OpenRGBDevicePage/OpenRGBDevicePage.h +++ b/qt/OpenRGBDevicePage/OpenRGBDevicePage.h @@ -120,6 +120,7 @@ private slots: void on_SatSpinBox_valueChanged(int sat); void on_SelectAllLEDsButton_clicked(); void on_SetAllButton_clicked(); + void on_SettingsUpdated(); void on_SpeedSlider_valueChanged(int value); void on_SpinBoxModeColors_valueChanged(int arg1); void on_SwatchBox_swatchChanged(const QColor color); diff --git a/qt/OpenRGBDialog/OpenRGBDialog.cpp b/qt/OpenRGBDialog/OpenRGBDialog.cpp index f6b3441a0..57ffe014c 100644 --- a/qt/OpenRGBDialog/OpenRGBDialog.cpp +++ b/qt/OpenRGBDialog/OpenRGBDialog.cpp @@ -7,7 +7,9 @@ | SPDX-License-Identifier: GPL-2.0-or-later | \*---------------------------------------------------------*/ +#include "AutoStart.h" #include "OpenRGBDialog.h" +#include "JsonUtils.h" #include "LogManager.h" #include "PluginManager.h" #include "OpenRGBDevicePage.h" @@ -21,11 +23,11 @@ #include "SettingsManager.h" #include "TabLabel.h" #include "OpenRGBZoneInitializationDialog.h" -#include "OpenRGBThemeManager.h" #include "OpenRGBFont.h" #include "ui_OpenRGBDialog.h" +#include #include #include #include @@ -59,6 +61,18 @@ static void OpenRGBDialogProfileManagerCallback(void * this_ptr, unsigned int up } } +static void OpenRGBDialogSettingsManagerCallback(void * this_ptr, unsigned int update_reason) +{ + OpenRGBDialog * this_obj = (OpenRGBDialog *)this_ptr; + + switch(update_reason) + { + case SETTINGSMANAGER_UPDATE_REASON_SETTINGS_UPDATED: + QMetaObject::invokeMethod(this_obj, "onSettingsUpdated", Qt::QueuedConnection); + break; + } +} + static void OpenRGBDialogResourceManagerCallback(void * this_ptr, unsigned int update_reason) { OpenRGBDialog * this_obj = (OpenRGBDialog *)this_ptr; @@ -128,73 +142,127 @@ OpenRGBDialog::OpenRGBDialog(QWidget *parent) : QMainWindow(parent), ui(new Ui:: setWindowIcon(logo); /*-----------------------------------------------------*\ - | Set window geometry from config (if available) | + | Create AutoStart settings schema | \*-----------------------------------------------------*/ - SettingsManager* settings_manager = ResourceManager::get()->GetSettingsManager(); - std::string ui_string = "UserInterface"; - json ui_settings; - bool new_settings_keys = false; + json autostart_settings_schema; - ui_settings = settings_manager->GetSettings(ui_string); + autostart_settings_schema["enabled"]["title"] = QT_TRANSLATE_NOOP("Settings", "Enable Start at Login"); + autostart_settings_schema["enabled"]["type"] = "bool"; + autostart_settings_schema["enabled"]["description"] = QT_TRANSLATE_NOOP("Settings", "Start OpenRGB on login"); + autostart_settings_schema["enabled"]["order"] = 0; - if(ui_settings.contains("show_led_view") && ui_settings["show_led_view"]) - { - ShowLEDView(); - } + autostart_settings_schema["start_minimized"]["title"] = QT_TRANSLATE_NOOP("Settings", "Start Minimized"); + autostart_settings_schema["start_minimized"]["type"] = "bool"; + autostart_settings_schema["start_minimized"]["description"] = QT_TRANSLATE_NOOP("Settings", "Start minimized to the system tray"); + autostart_settings_schema["start_minimized"]["order"] = 1; + + autostart_settings_schema["custom_arguments"]["title"] = QT_TRANSLATE_NOOP("Settings", "Custom Arguments"); + autostart_settings_schema["custom_arguments"]["type"] = "string"; + autostart_settings_schema["custom_arguments"]["description"] = QT_TRANSLATE_NOOP("Settings", "Additional command line arguments to pass to OpenRGB when starting on login"); + autostart_settings_schema["custom_arguments"]["order"] = 2; + + ResourceManager::get()->GetSettingsManager()->RegisterSettingsSchema("AutoStart", "Start at Login", autostart_settings_schema, 2); /*-----------------------------------------------------*\ - | If geometry info doesn't exist, write it to config | + | Create UserInterface settings schema | \*-----------------------------------------------------*/ - if(!ui_settings.contains("geometry")) - { - json geometry_settings; + json ui_settings_schema; - geometry_settings["load_geometry"] = false; - geometry_settings["save_on_exit"] = false; - geometry_settings["x"] = 0; - geometry_settings["y"] = 0; - geometry_settings["width"] = 0; - geometry_settings["height"] = 0; + ui_settings_schema["language"]["title"] = QT_TRANSLATE_NOOP("Settings", "Language"); + ui_settings_schema["language"]["type"] = "language"; + ui_settings_schema["language"]["description"] = QT_TRANSLATE_NOOP("Settings", "Language for the user interface"); + ui_settings_schema["language"]["order"] = 0; - ui_settings["geometry"] = geometry_settings; - new_settings_keys = true; - } + ui_settings_schema["minimize_on_close"]["title"] = QT_TRANSLATE_NOOP("Settings", "Minimize on Close"); + ui_settings_schema["minimize_on_close"]["description"] = QT_TRANSLATE_NOOP("Settings", "Keep OpenRGB active in the system tray when closing the main window"); + ui_settings_schema["minimize_on_close"]["type"] = "bool"; + ui_settings_schema["minimize_on_close"]["order"] = 1; + ui_settings_schema["monochrome_tray_icon"]["title"] = QT_TRANSLATE_NOOP("Settings", "Monochrome Tray Icon"); + ui_settings_schema["monochrome_tray_icon"]["description"] = QT_TRANSLATE_NOOP("Settings", "Use a monochrome icon in the system tray instead of a full color icon"); + ui_settings_schema["monochrome_tray_icon"]["type"] = "bool"; + ui_settings_schema["monochrome_tray_icon"]["order"] = 2; + + ui_settings_schema["hex_format"]["title"] = QT_TRANSLATE_NOOP("Settings", "Hex Format"); + ui_settings_schema["hex_format"]["type"] = "string"; + ui_settings_schema["hex_format"]["description"] = QT_TRANSLATE_NOOP("Settings", "Select #BBGGRR or #RRGGBB format for hex display and input"); + ui_settings_schema["hex_format"]["enum"][0] = "BGR"; + ui_settings_schema["hex_format"]["enum"][1] = "RGB"; + ui_settings_schema["hex_format"]["order"] = 3; + + ui_settings_schema["show_led_view"]["title"] = QT_TRANSLATE_NOOP("Settings", "Show LED View by Default"); + ui_settings_schema["show_led_view"]["type"] = "bool"; + ui_settings_schema["show_led_view"]["order"] = 4; + + ui_settings_schema["numerical_labels"]["title"] = QT_TRANSLATE_NOOP("Settings", "Numerical Labels"); + ui_settings_schema["numerical_labels"]["description"] = QT_TRANSLATE_NOOP("Settings", "Display numerical labels for otherwise non-labeled LEDs in the LED view"); + ui_settings_schema["numerical_labels"]["type"] = "bool"; + ui_settings_schema["numerical_labels"]["order"] = 5; + + ui_settings_schema["disable_key_expansion"]["title"] = QT_TRANSLATE_NOOP("Settings", "Disable Key Expansion"); + ui_settings_schema["disable_key_expansion"]["type"] = "bool"; + ui_settings_schema["disable_key_expansion"]["order"] = 6; + + ui_settings_schema["run_zone_checks"]["title"] = QT_TRANSLATE_NOOP("Settings", "Run Zone Checks on Rescan"); + ui_settings_schema["run_zone_checks"]["type"] = "bool"; + ui_settings_schema["run_zone_checks"]["order"] = 7; + + ui_settings_schema["geometry"]["title"] = QT_TRANSLATE_NOOP("Settings", "Window Geometry"); + ui_settings_schema["geometry"]["type"] = "object"; + ui_settings_schema["geometry"]["order"] = 8; + + ui_settings_schema["geometry"]["properties"]["load_geometry"]["title"] = QT_TRANSLATE_NOOP("Settings", "Load Window Geometry"); + ui_settings_schema["geometry"]["properties"]["load_geometry"]["type"] = "bool"; + ui_settings_schema["geometry"]["properties"]["load_geometry"]["order"] = 0; + + ui_settings_schema["geometry"]["properties"]["save_on_exit"]["title"] = QT_TRANSLATE_NOOP("Settings", "Save on Exit"); + ui_settings_schema["geometry"]["properties"]["save_on_exit"]["type"] = "bool"; + ui_settings_schema["geometry"]["properties"]["save_on_exit"]["description"] = QT_TRANSLATE_NOOP("Settings", "Save window geometry on exit"); + ui_settings_schema["geometry"]["properties"]["save_on_exit"]["order"] = 1; + + ui_settings_schema["geometry"]["properties"]["x"]["title"] = QT_TRANSLATE_NOOP("Settings", "X"); + ui_settings_schema["geometry"]["properties"]["x"]["type"] = "integer"; + ui_settings_schema["geometry"]["properties"]["x"]["order"] = 2; + + ui_settings_schema["geometry"]["properties"]["y"]["title"] = QT_TRANSLATE_NOOP("Settings", "Y"); + ui_settings_schema["geometry"]["properties"]["y"]["type"] = "integer"; + ui_settings_schema["geometry"]["properties"]["y"]["order"] = 3; + + ui_settings_schema["geometry"]["properties"]["width"]["title"] = QT_TRANSLATE_NOOP("Settings", "Width"); + ui_settings_schema["geometry"]["properties"]["width"]["type"] = "integer"; + ui_settings_schema["geometry"]["properties"]["width"]["order"] = 4; + + ui_settings_schema["geometry"]["properties"]["height"]["title"] = QT_TRANSLATE_NOOP("Settings", "Height"); + ui_settings_schema["geometry"]["properties"]["height"]["type"] = "integer"; + ui_settings_schema["geometry"]["properties"]["height"]["order"] = 5; + + ResourceManager::get()->GetSettingsManager()->RegisterSettingsSchema("UserInterface", "User Interface", ui_settings_schema, 0); + +#if defined(_WIN32) || defined(_MACOSX_X86_X64) /*-----------------------------------------------------*\ - | If geometry information exists in settings, apply it | + | Create Drivers settings schema | \*-----------------------------------------------------*/ - bool load_geometry = false; + json drivers_settings_schema; - if(ui_settings["geometry"].contains("load_geometry")) - { - load_geometry = ui_settings["geometry"]["load_geometry"].get(); - } +#if defined(_WIN32) + drivers_settings_schema["shared_smbus_acces"]["title"] = QT_TRANSLATE_NOOP("Settings", "Shared SMBus Access (restart required)"); + drivers_settings_schema["shared_smbus_acces"]["type"] = "bool"; - if(load_geometry) - { - QRect set_window; + drivers_settings_schema["smbus_sleep_mode"]["title"] = QT_TRANSLATE_NOOP("Settings", "SMBus Sleep Mode (restart required)"); + drivers_settings_schema["smbus_sleep_mode"]["type"] = "integer"; + drivers_settings_schema["smbus_sleep_mode"]["enum"][0] = 0; + drivers_settings_schema["smbus_sleep_mode"]["enumNames"][0] = "Always Busy"; + drivers_settings_schema["smbus_sleep_mode"]["enum"][1] = 1; + drivers_settings_schema["smbus_sleep_mode"]["enumNames"][1] = "Short Busy"; + drivers_settings_schema["smbus_sleep_mode"]["enum"][2] = 2; + drivers_settings_schema["smbus_sleep_mode"]["enumNames"][2] = "Always Sleep"; +#else + drivers_settings_schema["amd_smbus_reduce_cpu"]["title"] = QT_TRANSLATE_NOOP("Settings", "AMD SMBus: Reduce CPU Usage (restart required)"); + drivers_settings_schema["amd_smbus_reduce_cpu"]["type"] = "bool"; +#endif - /*-------------------------------------------------*\ - | x and y can be set independent of width and | - | height. QT attempts to clamp these values in | - | case the user enters invalid numbers. | - \*-------------------------------------------------*/ - if( ui_settings["geometry"].contains("x") - && ui_settings["geometry"].contains("y")) - { - set_window.setX(ui_settings["geometry"]["x"].get()); - set_window.setY(ui_settings["geometry"]["y"].get()); - } - - if( ui_settings["geometry"].contains("width") - && ui_settings["geometry"].contains("height")) - { - set_window.setWidth(ui_settings["geometry"]["width"].get()); - set_window.setHeight(ui_settings["geometry"]["height"].get()); - } - - setGeometry(set_window); - } + ResourceManager::get()->GetSettingsManager()->RegisterSettingsSchema("Drivers", "Drivers", drivers_settings_schema); +#endif /*-----------------------------------------------------*\ | Register resource manager callbacks | @@ -206,6 +274,11 @@ OpenRGBDialog::OpenRGBDialog(QWidget *parent) : QMainWindow(parent), ui(new Ui:: \*-----------------------------------------------------*/ ResourceManager::get()->GetProfileManager()->RegisterProfileManagerCallback(OpenRGBDialogProfileManagerCallback, this); + /*-----------------------------------------------------*\ + | Register settings manager callbacks | + \*-----------------------------------------------------*/ + ResourceManager::get()->GetSettingsManager()->RegisterSettingsManagerCallback(OpenRGBDialogSettingsManagerCallback, this); + /*-----------------------------------------------------*\ | Register dialog show callback with log manager | \*-----------------------------------------------------*/ @@ -295,56 +368,12 @@ OpenRGBDialog::OpenRGBDialog(QWidget *parent) : QMainWindow(parent), ui(new Ui:: connect( actionExit, SIGNAL( triggered() ), this, SLOT( on_Exit() )); trayIconMenu->addAction(actionExit); - /*-----------------------------------------------------*\ - | If tray minimize flag isn't in the config, set | - | default value to false | - \*-----------------------------------------------------*/ - if(!ui_settings.contains("minimize_on_close")) - { - ui_settings["minimize_on_close"] = false; - new_settings_keys = true; - } - connect(trayIcon,SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(on_ReShow(QSystemTrayIcon::ActivationReason))); - /*-----------------------------------------------------*\ - | If Greyscale Tray Icon flag is not set in config then | - | set the default value to false | - \*-----------------------------------------------------*/ - if(!ui_settings.contains("greyscale_tray_icon")) - { - ui_settings["greyscale_tray_icon"] = false; - new_settings_keys = true; - } - - /*-----------------------------------------------------*\ - | If greyscale tray icon exists in settings, apply it | - | or else set the icon to the default window logo | - \*-----------------------------------------------------*/ - if(ui_settings.contains("greyscale_tray_icon")) - { - SetTrayIcon(ui_settings["greyscale_tray_icon"].get()); - } - - /*-----------------------------------------------------*\ - | Save the settings if new default values have been | - | inserted | - \*-----------------------------------------------------*/ - if(new_settings_keys) - { - settings_manager->SetSettings(ui_string, ui_settings); - settings_manager->SaveSettings(); - } - trayIcon->setToolTip("OpenRGB"); trayIcon->setContextMenu(trayIconMenu); trayIcon->show(); - /*-----------------------------------------------------*\ - | Initialize the theme manager | - \*-----------------------------------------------------*/ - OpenRGBThemeManager::Init(); - /*-----------------------------------------------------*\ | Update the profile list | \*-----------------------------------------------------*/ @@ -408,23 +437,9 @@ OpenRGBDialog::OpenRGBDialog(QWidget *parent) : QMainWindow(parent), ui(new Ui:: } /*-----------------------------------------------------*\ - | If log console is enabled in settings, enable it | + | Process Settings | \*-----------------------------------------------------*/ - json log_manager_settings = settings_manager->GetSettings("LogManager"); - - bool log_console_enabled = false; - if(log_manager_settings.contains("log_console")) - { - log_console_enabled = log_manager_settings["log_console"]; - } - - /*-----------------------------------------------------*\ - | Add the log console page | - \*-----------------------------------------------------*/ - if(log_console_enabled) - { - AddConsolePage(); - } + onSettingsUpdated(); /*-----------------------------------------------------*\ | Connect aboutToQuit signal to handleAboutToQuit | @@ -572,7 +587,7 @@ bool OpenRGBDialog::isCompactTabMode() } void OpenRGBDialog::resizeEvent(QResizeEvent *event) -{ +{ bool compact_mode = isCompactTabMode(); for(int i = 0; i < ui->DevicesTabBar->count(); i++) @@ -669,12 +684,6 @@ void OpenRGBDialog::AddSettingsPage() TabLabel* SettingsTabLabel = new TabLabel(OpenRGBFont::options, (char *)"General Settings", (char *)context, true); ui->SettingsTabBar->tabBar()->setTabButton(ui->SettingsTabBar->tabBar()->count() - 1, QTabBar::LeftSide, SettingsTabLabel); - - /*-----------------------------------------------------*\ - | Connect signals to slots | - \*-----------------------------------------------------*/ - connect(SettingsPage, SIGNAL(TrayIconChanged(bool)), this, SLOT(SetTrayIcon(bool))); - connect(this, SIGNAL(ProfileListChanged()), SettingsPage, SLOT(UpdateProfiles())); } void OpenRGBDialog::AddManualDevicesSettingsPage() @@ -1222,6 +1231,38 @@ void OpenRGBDialog::SetDialogMessage(PLogMessage msg) dialog_message = QString::fromStdString(msg->buffer); } +void OpenRGBDialog::SetLanguage(std::string locale) +{ + QApplication* app = static_cast(QApplication::instance()); + QDirIterator language_files(":/i18n/", QDirIterator::Subdirectories); + bool loaded = false; + + app->removeTranslator(&translator); + + /*-----------------------------------------------------*\ + | Attempt to load given locale | + \*-----------------------------------------------------*/ + loaded = translator.load(":/i18n/" + QString("OpenRGB_%1.qm").arg(QString::fromStdString(locale))); + + /*-----------------------------------------------------*\ + | If the given locale could not be loaded, try loading | + | the system locale | + \*-----------------------------------------------------*/ + if(!loaded) + { + QLocale locale = QLocale(QLocale::system()); + QLocale::setDefault(locale); + + loaded = translator.load(":/i18n/" + QString("OpenRGB_%1.qm").arg(locale.name())); + } + + if(loaded) + { + app->installTranslator(&translator); + LOG_DEBUG("[OpenRGBDialog] Changed Language to %s\n", locale.c_str()); + } +} + void OpenRGBDialog::UpdateActiveProfile() { ProfileManager* profile_manager = ResourceManager::get()->GetProfileManager(); @@ -1414,6 +1455,119 @@ void OpenRGBDialog::onDetectionEnded() ResourceManager::get()->GetProfileManager()->LoadAutoProfileOpen(); } +void OpenRGBDialog::onSettingsUpdated() +{ + /*-----------------------------------------------------*\ + | Get SettingsManager pointer | + \*-----------------------------------------------------*/ + SettingsManager* settings_manager = ResourceManager::get()->GetSettingsManager(); + + /*-----------------------------------------------------*\ + | Read UserInterface settings | + \*-----------------------------------------------------*/ + json ui_settings = settings_manager->GetSettings("UserInterface"); + + if(JsonUtils::JsonGetBool(ui_settings, "show_led_view")) + { + ShowLEDView(); + } + + /*-----------------------------------------------------*\ + | If geometry information exists in settings, apply it | + \*-----------------------------------------------------*/ + if(ui_settings.contains("geometry")) + { + bool load_geometry = JsonUtils::JsonGetBool(ui_settings["geometry"], "load_geometry"); + + if(load_geometry) + { + QRect set_window; + + /*---------------------------------------------*\ + | x and y can be set independent of width and | + | height. QT attempts to clamp these values in | + | case the user enters invalid numbers. | + \*---------------------------------------------*/ + if( ui_settings["geometry"].contains("x") + && ui_settings["geometry"].contains("y")) + { + set_window.setX(ui_settings["geometry"]["x"].get()); + set_window.setY(ui_settings["geometry"]["y"].get()); + } + + if( ui_settings["geometry"].contains("width") + && ui_settings["geometry"].contains("height")) + { + set_window.setWidth(ui_settings["geometry"]["width"].get()); + set_window.setHeight(ui_settings["geometry"]["height"].get()); + } + + setGeometry(set_window); + } + } + + /*-----------------------------------------------------*\ + | If monochrome tray icon exists in settings, apply it | + | or else set the icon to the default window logo | + \*-----------------------------------------------------*/ + SetTrayIcon(JsonUtils::JsonGetBool(ui_settings, "monochrome_tray_icon")); + + if(ui_settings.contains("language")) + { + std::string language = ui_settings["language"]; + SetLanguage(language); + } + + /*-----------------------------------------------------*\ + | Read LogManager settings | + \*-----------------------------------------------------*/ + json log_manager_settings = settings_manager->GetSettings("LogManager"); + bool log_console_enabled = JsonUtils::JsonGetBool(log_manager_settings, "log_console"); + + /*-----------------------------------------------------*\ + | Add the log console page | + \*-----------------------------------------------------*/ + if(log_console_enabled) + { + AddConsolePage(); + } + else + { + RemoveConsolePage(); + } + + /*-----------------------------------------------------*\ + | Read AutoStart settings | + \*-----------------------------------------------------*/ + json autostart_settings = settings_manager->GetSettings("AutoStart"); + std::string autostart_arguments = JsonUtils::JsonGetString(autostart_settings, "custom_arguments"); + bool autostart_enabled = JsonUtils::JsonGetBool(autostart_settings, "enabled"); + bool autostart_minimized = JsonUtils::JsonGetBool(autostart_settings, "start_minimized"); + AutoStart auto_start("OpenRGB"); + + if(autostart_minimized) + { + autostart_arguments = "--startminimized " + autostart_arguments; + } + + if(autostart_enabled) + { + AutoStartInfo auto_start_info; + + auto_start_info.args = autostart_arguments; + auto_start_info.category = "Utility;"; + auto_start_info.desc = std::string("OpenRGB ") + std::string(VERSION_STRING); + auto_start_info.icon = "OpenRGB"; + auto_start_info.path = auto_start.GetExePath(); + + auto_start.EnableAutoStart(auto_start_info); + } + else + { + auto_start.DisableAutoStart(); + } +} + void OpenRGBDialog::on_SetAllDevices(unsigned char red, unsigned char green, unsigned char blue) { ResourceManager::get()->GetProfileManager()->ClearActiveProfile(); @@ -1738,7 +1892,7 @@ void OpenRGBDialog::SetTrayIcon(bool tray_icon) { if(tray_icon) { - trayIcon->setIcon(QIcon(":OpenRGBGreyscale.png")); + trayIcon->setIcon(QIcon(":OpenRGBMonochrome.png")); } else { @@ -1880,14 +2034,38 @@ void OpenRGBDialog::TogglePluginsVisibility(int tab_idx, QTabWidget* tabBar) void OpenRGBDialog::AddConsolePage() { - OpenRGBConsolePage* page = new OpenRGBConsolePage(); + bool found = false; + int index = (ui->InformationTabBar->tabBar()->count() - 1); + QWidget* tab = ui->InformationTabBar->widget(index); - ui->InformationTabBar->addTab(page, ""); + if(dynamic_cast(tab) != nullptr) + { + found = true; + } - /*-----------------------------------------------------*\ - | Create the tab label | - \*-----------------------------------------------------*/ - TabLabel* ConsoleTabLabel = new TabLabel(OpenRGBFont::terminal, (char *)"Log Console", (char *)context, true); + if(!found) + { + OpenRGBConsolePage* page = new OpenRGBConsolePage(); - ui->InformationTabBar->tabBar()->setTabButton(ui->InformationTabBar->tabBar()->count() - 1, QTabBar::LeftSide, ConsoleTabLabel); + ui->InformationTabBar->addTab(page, ""); + + /*-----------------------------------------------------*\ + | Create the tab label | + \*-----------------------------------------------------*/ + TabLabel* ConsoleTabLabel = new TabLabel(OpenRGBFont::terminal, (char *)"Log Console", (char *)context, true); + + ui->InformationTabBar->tabBar()->setTabButton(ui->InformationTabBar->tabBar()->count() - 1, QTabBar::LeftSide, ConsoleTabLabel); + } +} + +void OpenRGBDialog::RemoveConsolePage() +{ + int index = (ui->InformationTabBar->tabBar()->count() - 1); + QWidget* tab = ui->InformationTabBar->widget(index); + + if(dynamic_cast(tab) != nullptr) + { + ui->InformationTabBar->removeTab(index); + delete tab; + } } diff --git a/qt/OpenRGBDialog/OpenRGBDialog.h b/qt/OpenRGBDialog/OpenRGBDialog.h index 3e208954c..7281e95d0 100644 --- a/qt/OpenRGBDialog/OpenRGBDialog.h +++ b/qt/OpenRGBDialog/OpenRGBDialog.h @@ -15,6 +15,7 @@ #include #include #include +#include #include "OpenRGBClientInfoPage.h" #include "OpenRGBDevicePage.h" @@ -59,6 +60,7 @@ public: static bool IsMinimizeOnClose(); void SetDialogMessage(PLogMessage msg); + void SetLanguage(std::string locale); bool DontShowAgain; @@ -117,13 +119,19 @@ private: /*-----------------------------------------------------*\ | User interface | \*-----------------------------------------------------*/ - Ui::OpenRGBDialog *ui; + Ui::OpenRGBDialog* ui; + + /*-----------------------------------------------------*\ + | Translator | + \*-----------------------------------------------------*/ + QTranslator translator; void AddSoftwareInfoPage(); void AddSupportedDevicesPage(); void AddSettingsPage(); void AddPluginsPage(); void AddConsolePage(); + void RemoveConsolePage(); void AddManualDevicesSettingsPage(); void ClearDevicesList(); @@ -159,6 +167,7 @@ private slots: void onDetectionProgressUpdated(); void onDetectionStarted(); void onDetectionEnded(); + void onSettingsUpdated(); void on_SetAllDevices(unsigned char red, unsigned char green, unsigned char blue); void on_ShowHide(); void onShowDialogMessage(); diff --git a/qt/OpenRGBDynamicSettingsWidget/OpenRGBDynamicSettingsWidget.cpp b/qt/OpenRGBDynamicSettingsWidget/OpenRGBDynamicSettingsWidget.cpp new file mode 100644 index 000000000..a52a1afc1 --- /dev/null +++ b/qt/OpenRGBDynamicSettingsWidget/OpenRGBDynamicSettingsWidget.cpp @@ -0,0 +1,488 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "JsonUtils.h" +#include "OpenRGBDynamicSettingsWidget.h" +#include "ProfileManager.h" +#include "ResourceManager.h" + + + +static void OpenRGBDynamicSettingsWidgetProfileManagerCallback(void * this_ptr, unsigned int update_reason) +{ + OpenRGBDynamicSettingsWidget * this_obj = (OpenRGBDynamicSettingsWidget *)this_ptr; + + switch(update_reason) + { + case PROFILEMANAGER_UPDATE_REASON_PROFILE_LIST_UPDATED: + this_obj->ProfileListUpdated(); + break; + } +} + +void OpenRGBDynamicSettingsWidget::NestedCallback(void* this_ptr, std::string /*key*/, nlohmann::json settings) +{ + nlohmann::json nested_settings; + + nested_settings[((OpenRGBDynamicSettingsWidget*)this_ptr)->key] = settings; + + if(((OpenRGBDynamicSettingsWidget*)this_ptr)->callback) + { + ((OpenRGBDynamicSettingsWidget*)this_ptr)->callback(((OpenRGBDynamicSettingsWidget*)this_ptr)->callback_arg, ((OpenRGBDynamicSettingsWidget*)this_ptr)->key, nested_settings); + } +} + +OpenRGBDynamicSettingsWidget::OpenRGBDynamicSettingsWidget(std::string key, nlohmann::json& schema, nlohmann::json& settings, QWidget* parent) : + QWidget(parent) +{ + /*-----------------------------------------------------*\ + | Type to track ordering | + \*-----------------------------------------------------*/ + typedef struct + { + int order; + std::string key; + std::reference_wrapper value; + } ordered_settings_t; + + this->key = key; + type = ""; + is_enum = false; + callback = nullptr; + left_widget = nullptr; + right_widget = nullptr; + + /*-----------------------------------------------------*\ + | Ensure each schema entry has a title and type | + \*-----------------------------------------------------*/ + if(schema.contains("title") && schema.contains("type")) + { + /*-------------------------------------------------*\ + | Create main layout | + \*-------------------------------------------------*/ + layout = new QHBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); + + /*-------------------------------------------------*\ + | Get schema title and type, check if it is an enum | + \*-------------------------------------------------*/ + description = JsonUtils::JsonGetString(schema, "description"); + title = JsonUtils::JsonGetString(schema, "title"); + type = JsonUtils::JsonGetString(schema, "type"); + + if(schema.contains("enum")) + { + is_enum = true; + } + + /*-------------------------------------------------*\ + | If type is object, create a nested group | + \*-------------------------------------------------*/ + if(type == "object" && schema.contains("properties")) + { + /*---------------------------------------------*\ + | Create the groupbox and layout | + \*---------------------------------------------*/ + QGroupBox* groupbox = new QGroupBox(QString::fromStdString(title)); + QVBoxLayout* groupbox_layout = new QVBoxLayout(); + nlohmann::json& properties_json = schema["properties"]; + std::vector setting_entries; + nlohmann::json& settings_json = settings[key]; + + groupbox->setLayout(groupbox_layout); + + /*---------------------------------------------*\ + | Loop through the schema and build a vector | + | containing the entries in desired order. | + | Entries with negative order (default -1) are | + | put at the end of the list. | + \*---------------------------------------------*/ + for(nlohmann::json::iterator json_iterator = properties_json.begin(); json_iterator != properties_json.end(); json_iterator++) + { + int order = -1; + + if(json_iterator.value().contains("order")) + { + order = json_iterator.value()["order"]; + } + + ordered_settings_t setting = {order, json_iterator.key(), json_iterator.value()}; + + if((order < 0) || (setting_entries.size() == 0)) + { + setting_entries.push_back(setting); + } + else + { + bool added = false; + + for(std::size_t setting_idx = 0; setting_idx < setting_entries.size(); setting_idx++) + { + if((setting_entries[setting_idx].order > order) || (setting_entries[setting_idx].order < 0)) + { + setting_entries.insert(setting_entries.begin() + setting_idx, setting); + added = true; + break; + } + } + + if(!added) + { + setting_entries.push_back(setting); + } + } + } + + /*---------------------------------------------*\ + | Create UI elements for each setting | + \*---------------------------------------------*/ + for(std::size_t setting_idx = 0; setting_idx < setting_entries.size(); setting_idx++) + { + OpenRGBDynamicSettingsWidget* item_widget = new OpenRGBDynamicSettingsWidget(setting_entries[setting_idx].key, setting_entries[setting_idx].value, settings_json); + + item_widget->SetCallback(&OpenRGBDynamicSettingsWidget::NestedCallback, this); + groupbox_layout->addWidget(item_widget); + } + + layout->addWidget(groupbox); + } + /*-------------------------------------------------*\ + | Otherwise, create a single settings entry | + \*-------------------------------------------------*/ + else + { + if(type == "profile") + { + /*-----------------------------------------*\ + | Add a CheckBox and ComboBox for profile | + | settings | + \*-----------------------------------------*/ + bool enabled_value = false; + std::string name_value = ""; + std::vector profile_list = ResourceManager::get()->GetProfileManager()->GetProfileList(); + + ResourceManager::get()->GetProfileManager()->RegisterProfileManagerCallback(OpenRGBDynamicSettingsWidgetProfileManagerCallback, this); + + if(settings.contains(key)) + { + enabled_value = JsonUtils::JsonGetBool(settings[key], "enabled"); + name_value = JsonUtils::JsonGetString(settings[key], "name"); + } + + left_widget = (QWidget*)new QCheckBox(); + right_widget = (QWidget*)new QComboBox(); + + for(std::size_t profile_idx = 0; profile_idx < profile_list.size(); profile_idx++) + { + std::string profile_str = profile_list[profile_idx]; + ((QComboBox*)right_widget)->addItem(QString::fromStdString(profile_str)); + } + + ((QCheckBox*)left_widget)->setChecked(enabled_value); + ((QComboBox*)right_widget)->setEnabled(enabled_value); + ((QComboBox*)right_widget)->setCurrentText(QString::fromStdString(name_value)); + + QObject::connect((QCheckBox*)left_widget, qOverload(&QCheckBox::stateChanged), this, &OpenRGBDynamicSettingsWidget::OnSettingChanged); + QObject::connect((QComboBox*)right_widget, qOverload(&QComboBox::currentIndexChanged), this, &OpenRGBDynamicSettingsWidget::OnSettingChanged); + } + else + { + /*-----------------------------------------*\ + | The left widget for these setting types | + | is a label | + \*-----------------------------------------*/ + left_widget = (QWidget*)new QLabel(); + + /*-----------------------------------------*\ + | Add a LineEdit for non-enum string | + | settings | + \*-----------------------------------------*/ + if(type == "string" && !is_enum) + { + std::string value = JsonUtils::JsonGetString(schema, "default"); + + if(settings.contains(key)) + { + value = JsonUtils::JsonGetString(settings, key); + } + + right_widget = (QWidget*)new QLineEdit(QString::fromStdString(value)); + + QObject::connect((QLineEdit*)right_widget, &QLineEdit::textChanged, this, &OpenRGBDynamicSettingsWidget::OnSettingChanged); + } + /*-----------------------------------------*\ + | Add a ComboBox for enum string settings | + \*-----------------------------------------*/ + else if(type == "string" && is_enum) + { + std::string value = JsonUtils::JsonGetString(schema, "default"); + + if(settings.contains(key)) + { + value = JsonUtils::JsonGetString(settings, key); + } + + right_widget = (QWidget*)new QComboBox(); + + for(std::size_t enum_idx = 0; enum_idx < schema["enum"].size(); enum_idx++) + { + std::string enum_str = schema["enum"][enum_idx]; + ((QComboBox*)right_widget)->addItem(QString::fromStdString(enum_str)); + } + + ((QComboBox*)right_widget)->setCurrentText(QString::fromStdString(value)); + + QObject::connect((QComboBox*)right_widget, qOverload(&QComboBox::currentIndexChanged), this, &OpenRGBDynamicSettingsWidget::OnSettingChanged); + } + /*-----------------------------------------*\ + | Add a LineEdit for non-enum integer | + | settings | + \*-----------------------------------------*/ + if(type == "integer" && !is_enum) + { + int maximum = JsonUtils::JsonGetInt(schema, "maximum", 2147483647); + int minimum = JsonUtils::JsonGetInt(schema, "minimum", -2147483648); + int value = JsonUtils::JsonGetInt(schema, "default"); + + if(settings.contains(key)) + { + value = JsonUtils::JsonGetInt(settings, key); + } + + right_widget = (QWidget*)new QSpinBox(); + ((QSpinBox*)right_widget)->setRange(minimum, maximum); + ((QSpinBox*)right_widget)->setValue(value); + + QObject::connect((QSpinBox*)right_widget, qOverload(&QSpinBox::valueChanged), this, &OpenRGBDynamicSettingsWidget::OnSettingChanged); + } + /*-----------------------------------------*\ + | Add a ComboBox for enum integer settings | + \*-----------------------------------------*/ + else if(type == "integer" && is_enum) + { + int value = JsonUtils::JsonGetInt(schema, "default"); + + if(settings.contains(key)) + { + value = JsonUtils::JsonGetInt(settings, key); + } + + right_widget = (QWidget*)new QComboBox(); + + for(std::size_t enum_idx = 0; enum_idx < schema["enum"].size(); enum_idx++) + { + int enum_int = schema["enum"][enum_idx]; + std::string label = std::to_string(enum_int); + + if(schema.contains("enumNames") && (enum_idx < schema["enumNames"].size())) + { + label = schema["enumNames"][enum_idx]; + } + + ((QComboBox*)right_widget)->addItem(QString::fromStdString(label), enum_int); + } + + int index = ((QComboBox*)right_widget)->findData(value); + if(index != -1) + { + ((QComboBox*)right_widget)->setCurrentIndex(index); + } + + QObject::connect((QComboBox*)right_widget, qOverload(&QComboBox::currentIndexChanged), this, &OpenRGBDynamicSettingsWidget::OnSettingChanged); + } + /*-----------------------------------------*\ + | Add a CheckBox for bool settings | + \*-----------------------------------------*/ + else if(type == "bool") + { + bool value = JsonUtils::JsonGetBool(schema, "default"); + + if(settings.contains(key)) + { + value = JsonUtils::JsonGetBool(settings, key); + } + + right_widget = (QWidget*)new QCheckBox(); + + ((QCheckBox*)right_widget)->setChecked(value); + + QObject::connect((QCheckBox*)right_widget, &QCheckBox::stateChanged, this, &OpenRGBDynamicSettingsWidget::OnSettingChanged); + } + else if(type == "language") + { + std::string value = JsonUtils::JsonGetString(schema, "default"); + + if(settings.contains(key)) + { + value = JsonUtils::JsonGetString(settings, key); + } + + right_widget = (QWidget*)new QComboBox(); + + /*-------------------------------------*\ + | Load available languages | + | Technically the QString is unused but | + | declared here to show up in the | + | translation file. | + \*-------------------------------------*/ + QTranslator translator; + QMap language_map; + QString language = tr("English - US"); + QDirIterator file(":/i18n/", QDirIterator::Subdirectories); + + while(file.hasNext()) + { + if(translator.load(file.next())) + { + QString language_locale = file.fileName().replace("OpenRGB_", "").replace(".qm", ""); + language_map.insert(translator.translate("Settings", "English - US"), language_locale); + } + } + + ((QComboBox*)right_widget)->addItem(tr("System Default"), "default"); + + QMapIterator language_map_iterator(language_map); + + while(language_map_iterator.hasNext()) + { + language_map_iterator.next(); + ((QComboBox*)right_widget)->addItem(language_map_iterator.key(), language_map_iterator.value()); + } + + int index = ((QComboBox*)right_widget)->findData(QVariant::fromValue(QString::fromStdString(value))); + if(index != -1) + { + ((QComboBox*)right_widget)->setCurrentIndex(index); + } + + QObject::connect((QComboBox*)right_widget, qOverload(&QComboBox::currentIndexChanged), this, &OpenRGBDynamicSettingsWidget::OnSettingChanged); + } + } + + layout->addWidget(left_widget, 1); + layout->addWidget(right_widget, 1); + + UpdateLabels(); + + adjustSize(); + } + } +} + +OpenRGBDynamicSettingsWidget::~OpenRGBDynamicSettingsWidget() +{ + ResourceManager::get()->GetProfileManager()->UnregisterProfileManagerCallback(OpenRGBDynamicSettingsWidgetProfileManagerCallback, this); +} + +void OpenRGBDynamicSettingsWidget::changeEvent(QEvent *event) +{ + if(event->type() == QEvent::LanguageChange) + { + UpdateLabels(); + } +} + +void OpenRGBDynamicSettingsWidget::ProfileListUpdated() +{ + if(type == "profile") + { + std::string name_value = ((QComboBox*)right_widget)->currentText().toStdString(); + std::vector profile_list = ResourceManager::get()->GetProfileManager()->GetProfileList(); + + ((QComboBox*)right_widget)->clear(); + + for(std::size_t profile_idx = 0; profile_idx < profile_list.size(); profile_idx++) + { + std::string profile_str = profile_list[profile_idx]; + ((QComboBox*)right_widget)->addItem(QString::fromStdString(profile_str)); + } + + ((QComboBox*)right_widget)->setCurrentText(QString::fromStdString(name_value)); + } +} + +void OpenRGBDynamicSettingsWidget::OnSettingChanged() +{ + nlohmann::json settings_change; + + if(type == "string" && !is_enum) + { + std::string value = ((QLineEdit*)right_widget)->text().toStdString(); + settings_change[key] = value; + } + else if(type == "string" && is_enum) + { + std::string value = ((QComboBox*)right_widget)->currentText().toStdString(); + settings_change[key] = value; + } + else if(type == "integer" && !is_enum) + { + int value = ((QSpinBox*)right_widget)->value(); + settings_change[key] = value; + } + else if(type == "integer" && is_enum) + { + int value = ((QComboBox*)right_widget)->currentData().toInt(); + settings_change[key] = value; + } + else if(type == "bool") + { + bool value = ((QCheckBox*)right_widget)->isChecked(); + settings_change[key] = value; + } + else if(type == "profile") + { + bool enabled_value = ((QCheckBox*)left_widget)->isChecked(); + std::string name_value = ((QComboBox*)right_widget)->currentText().toStdString(); + ((QComboBox*)right_widget)->setEnabled(enabled_value); + settings_change[key]["enabled"] = enabled_value; + settings_change[key]["name"] = name_value; + } + else if(type == "language") + { + std::string value = ((QComboBox*)right_widget)->currentData().toString().toStdString(); + settings_change[key] = value; + } + + if(callback) + { + callback(callback_arg, key, settings_change); + } +} + +void OpenRGBDynamicSettingsWidget::SetCallback(OpenRGBDynamicSettingsCallback callback, void* callback_arg) +{ + this->callback = callback; + this->callback_arg = callback_arg; +} + +void OpenRGBDynamicSettingsWidget::UpdateLabels() +{ + QApplication* app = static_cast(QApplication::instance()); + + if(type == "profile") + { + if(left_widget) + { + ((QCheckBox*)left_widget)->setText(app->translate("Settings", title.c_str()) + ":"); + } + setToolTip(app->translate("Settings", description.c_str())); + } + else if(type != "object") + { + if(left_widget) + { + ((QLabel*)left_widget)->setText(app->translate("Settings", title.c_str()) + ":"); + } + + setToolTip(app->translate("Settings", description.c_str())); + } +} diff --git a/qt/OpenRGBDynamicSettingsWidget/OpenRGBDynamicSettingsWidget.h b/qt/OpenRGBDynamicSettingsWidget/OpenRGBDynamicSettingsWidget.h new file mode 100644 index 000000000..f42d4abd4 --- /dev/null +++ b/qt/OpenRGBDynamicSettingsWidget/OpenRGBDynamicSettingsWidget.h @@ -0,0 +1,57 @@ +/*---------------------------------------------------------*\ +| OpenRGBDynamicSettingsWidget.h | +| | +| Widget for one dynamic settings list entry | +| | +| Adam Honse 16 Apr 2026 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#pragma once +#include +#include +#include +#include +#include "nlohmann/json.hpp" + +/*---------------------------------------------------------*\ +| Callback Type | +\*---------------------------------------------------------*/ +typedef void (*OpenRGBDynamicSettingsCallback)(void*, std::string, nlohmann::json); + +class OpenRGBDynamicSettingsWidget : public QWidget +{ + Q_OBJECT +public: + OpenRGBDynamicSettingsWidget(std::string key, nlohmann::json& schema, nlohmann::json& settings, QWidget* parent = nullptr); + ~OpenRGBDynamicSettingsWidget(); + + void ProfileListUpdated(); + + void SetCallback(OpenRGBDynamicSettingsCallback callback, void* callback_arg); + void OnSettingChanged(); + +private: + std::string description; + std::string key; + std::string title; + std::string type; + bool is_enum; + + QHBoxLayout* layout; + QWidget* left_widget; + QWidget* right_widget; + + OpenRGBDynamicSettingsCallback callback; + void* callback_arg; + + void UpdateLabels(); + +private slots: + void changeEvent(QEvent *event); + +public: + static void NestedCallback(void* this_ptr, std::string key, nlohmann::json settings); +}; diff --git a/qt/OpenRGBGreyscale.png b/qt/OpenRGBMonochrome.png similarity index 100% rename from qt/OpenRGBGreyscale.png rename to qt/OpenRGBMonochrome.png diff --git a/qt/OpenRGBSettingsPage/OpenRGBSettingsPage.cpp b/qt/OpenRGBSettingsPage/OpenRGBSettingsPage.cpp index e0cff04d0..eb28f17c2 100644 --- a/qt/OpenRGBSettingsPage/OpenRGBSettingsPage.cpp +++ b/qt/OpenRGBSettingsPage/OpenRGBSettingsPage.cpp @@ -1,1209 +1,155 @@ /*---------------------------------------------------------*\ | OpenRGBSettingsPage.cpp | | | -| User interface for general settings page | +| User interface for OpenRGB settings page | +| | +| Adam Honse 15 Apr 2026 | | | | This file is part of the OpenRGB project | | SPDX-License-Identifier: GPL-2.0-or-later | \*---------------------------------------------------------*/ -#include -#include -#include "AutoStart.h" +#include +#include +#include +#include +#include "OpenRGBDynamicSettingsWidget.h" #include "OpenRGBSettingsPage.h" -#include "ui_OpenRGBSettingsPage.h" -#include "LogManager.h" #include "ResourceManager.h" #include "SettingsManager.h" -#include "ProfileManager.h" +#include "ui_OpenRGBSettingsPage.h" + +static void OpenRGBSettingsManagerCallback(void * this_ptr, unsigned int update_reason) +{ + OpenRGBSettingsPage * this_obj = (OpenRGBSettingsPage *)this_ptr; + + switch(update_reason) + { + case SETTINGSMANAGER_UPDATE_REASON_SETTINGS_SCHEMA_UPDATED: + this_obj->UpdateInterface(); + break; + } +} + +static void Callback(void* this_ptr, std::string key, nlohmann::json settings) +{ + ((OpenRGBSettingsPage*)this_ptr)->OnSettingChanged(key, settings); +} OpenRGBSettingsPage::OpenRGBSettingsPage(QWidget *parent) : - QWidget(parent), + QDialog(parent), ui(new Ui::OpenRGBSettingsPage) { ui->setupUi(this); - /*---------------------------------------------------------*\ - | App translation | - | To add a new language: | - | Add an entry to TRANSLATIONS in OpenRGB.pro | - | Then run lupdate OpenRGB.pro to generate the new file | - | | - | Edit this file with | - | linguist qt/i18n/OpenRGB_en.ts qt/i18n/OpenRGB_XX.ts | - | or manually with any text editor | - \*---------------------------------------------------------*/ - - /*---------------------------------------------------------*\ - | Load available languages | - | Tehcnically the QString is unused but declared | - | here to show up in the translation file. | - \*---------------------------------------------------------*/ - QTranslator translator; - QMap map; - QString language = tr("English - US"); - - QDirIterator file(":/i18n/", QDirIterator::Subdirectories); - while(file.hasNext()) - { - if(translator.load(file.next())) - { - map.insert(translator.translate("OpenRGBSettingsPage", "English - US"), file.filePath()); - } - } - - ui->ComboBoxLanguage->blockSignals(true); - ui->ComboBoxLanguage->addItem(tr("System Default"), "default"); - QMapIterator i(map); - while(i.hasNext()) - { - i.next(); - ui->ComboBoxLanguage->addItem(i.key(), i.value()); - } - ui->ComboBoxLanguage->blockSignals(false); - - /*---------------------------------------------------------*\ - | Populate hex format combo box | - \*---------------------------------------------------------*/ - ui->ComboBoxHexFormat->addItem("RGB"); - ui->ComboBoxHexFormat->addItem("BGR"); - - hex_format_initialized = true; - - /*---------------------------------------------------------*\ - | Load theme settings | - \*---------------------------------------------------------*/ - ui->ComboBoxTheme->addItems({"Auto", "Light", "Dark"}); - - json theme_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("Theme"); - - if(theme_settings.contains("theme")) - { - std::string theme = theme_settings["theme"]; - ui->ComboBoxTheme->setCurrentText(QString::fromStdString(theme)); - } - else - { - ui->ComboBoxTheme->setCurrentText(QString::fromStdString(("Light"))); - } - - theme_initialized = true; - - /*---------------------------------------------------------*\ - | Load user interface settings | - \*---------------------------------------------------------*/ - json ui_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("UserInterface"); - - ui->ComboBoxLanguage->blockSignals(true); - if(ui_settings.contains("language")) - { - /*-----------------------------------------------------*\ - | Get the language preference from settings | - | and check the language combobox for a match | - \*-----------------------------------------------------*/ - std::string language = ui_settings["language"].get(); - int language_index = ui->ComboBoxLanguage->findText(QString::fromStdString(language)); - - if(language_index > -1) - { - ui->ComboBoxLanguage->setCurrentIndex(language_index); - } - } - else - { - ui_settings["language"] = "default"; - ResourceManager::get()->GetSettingsManager()->SetSettings("UserInterface",ui_settings); - SaveSettings(); - ui->ComboBoxLanguage->setCurrentIndex(0); - } - - /*---------------------------------------------------------*\ - | Explicitly load the current selected language | - \*---------------------------------------------------------*/ - on_ComboBoxLanguage_currentTextChanged(ui->ComboBoxLanguage->currentText()); - ui->ComboBoxLanguage->blockSignals(false); - - if(ui_settings.contains("greyscale_tray_icon")) - { - ui->CheckboxTrayIconGreyscale->setChecked(ui_settings["greyscale_tray_icon"]); - } - - if(ui_settings.contains("minimize_on_close")) - { - ui->CheckboxMinimizeOnClose->setChecked(ui_settings["minimize_on_close"]); - } - - if(ui_settings.contains("geometry")) - { - if(ui_settings["geometry"].contains("load_geometry")) - { - ui->CheckboxLoadGeometry->setChecked(ui_settings["geometry"]["load_geometry"]); - } - - if(ui_settings["geometry"].contains("save_on_exit")) - { - ui->CheckboxSaveGeometry->setChecked(ui_settings["geometry"]["save_on_exit"]); - } - } - - /*-------------------------------------*\ - | Use PascalCase key for compatibility | - | should be removed later on. | - \*-------------------------------------*/ - if(ui_settings.contains("RunZoneChecks")) - { - /*----------------------------------*\ - | Migrate key to snake_case version | - \*----------------------------------*/ - ui_settings["run_zone_checks"] = ui_settings["RunZoneChecks"]; - ui_settings.erase("RunZoneChecks"); - ResourceManager::get()->GetSettingsManager()->SetSettings("UserInterface", ui_settings); - - ui->CheckboxRunZoneChecks->setChecked(ui_settings["run_zone_checks"]); - } - else if (ui_settings.contains("run_zone_checks")) - { - ui->CheckboxRunZoneChecks->setChecked(ui_settings["run_zone_checks"]); - } - else - { - ui->CheckboxRunZoneChecks->setChecked(true); - } - - if(ui_settings.contains("disable_key_expansion")) - { - ui->CheckboxDisableKeyExpansion->setChecked(ui_settings["disable_key_expansion"]); - } - else - { - ui->CheckboxDisableKeyExpansion->setChecked(false); - } - - if(ui_settings.contains("show_led_view")) - { - ui->CheckboxShowLEDView->setChecked(ui_settings["show_led_view"]); - } - else - { - ui->CheckboxShowLEDView->setChecked(false); - } - - if(ui_settings.contains("hex_format")) - { - if(ui_settings["hex_format"] == "RGB") - { - ui->ComboBoxHexFormat->setCurrentIndex(0); - } - else if(ui_settings["hex_format"] == "BGR") - { - ui->ComboBoxHexFormat->setCurrentIndex(1); - } - } - - /*---------------------------------------------------------*\ - | Load LogManager settings | - \*---------------------------------------------------------*/ - json log_manager_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("LogManager"); - - if(log_manager_settings.contains("log_file")) - { - ui->CheckboxLogFile->setChecked(log_manager_settings["log_file"]); - } - else - { - ui->CheckboxLogFile->setChecked(true); - } - - if(log_manager_settings.contains("log_console")) - { - ui->CheckboxLogConsole->setChecked(log_manager_settings["log_console"]); - } - else - { - ui->CheckboxLogConsole->setChecked(false); - } - - /*---------------------------------------------------------*\ - | Load detector settings | - \*---------------------------------------------------------*/ - json detector_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("Detectors"); - - if(detector_settings.contains("hid_safe_mode")) - { - ui->CheckboxHIDSafeMode->setChecked(detector_settings["hid_safe_mode"]); - } - else - { - ui->CheckboxHIDSafeMode->setChecked(false); - } - - if(detector_settings.contains("initial_detection_delay_ms")) - { - ui->TextDetectionDelay->setValue(detector_settings["initial_detection_delay_ms"]); - } - else - { - ui->TextDetectionDelay->setValue(0); - } - -#if defined(_MACOSX_X86_X64) - /*---------------------------------------------------------*\ - | Load drivers settings (MacOS only) | - \*---------------------------------------------------------*/ - json drivers_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("Drivers"); - - ui->CheckboxSharedSMBusAccess->hide(); - ui->LabelSMBusSleepMode->hide(); - ui->ComboBoxSMBusSleepMode->hide(); - - if(drivers_settings.contains("amd_smbus_reduce_cpu")) - { - ui->CheckboxAMDSMBusReduceCPU->setChecked(drivers_settings["amd_smbus_reduce_cpu"]); - } -#elif defined(_WIN32) - /*---------------------------------------------------------*\ - | Load drivers settings (Windows only) | - \*---------------------------------------------------------*/ - json drivers_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("Drivers"); - - ui->CheckboxAMDSMBusReduceCPU->hide(); - - if(drivers_settings.contains("shared_smbus_access")) - { - ui->CheckboxSharedSMBusAccess->setChecked(drivers_settings["shared_smbus_access"]); - } - else - { - ui->CheckboxSharedSMBusAccess->setChecked(true); - } - - ui->ComboBoxSMBusSleepMode->addItem("Always Busy"); - ui->ComboBoxSMBusSleepMode->addItem("Short Busy"); - ui->ComboBoxSMBusSleepMode->addItem("Always Sleep"); - - if(drivers_settings.contains("smbus_sleep_mode") && (drivers_settings["smbus_sleep_mode"] <= 2)) - { - ui->ComboBoxSMBusSleepMode->setCurrentIndex(drivers_settings["smbus_sleep_mode"]); - } - else - { - ui->ComboBoxSMBusSleepMode->setCurrentIndex(2); - } -#else - /*---------------------------------------------------------*\ - | Hide all drivers settings otherwise | - \*---------------------------------------------------------*/ - ui->GroupBoxDriverSettings->hide(); - ui->CheckboxAMDSMBusReduceCPU->hide(); - ui->CheckboxSharedSMBusAccess->hide(); - ui->LabelSMBusSleepMode->hide(); - ui->ComboBoxSMBusSleepMode->hide(); -#endif - /*-----------------------------------------------------*\ - | Load server settings | + | Register settings manager callbacks | \*-----------------------------------------------------*/ - json server_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("Server"); + ResourceManager::get()->GetSettingsManager()->RegisterSettingsManagerCallback(OpenRGBSettingsManagerCallback, this); - if(server_settings.contains("all_devices")) - { - bool all_devices = server_settings["all_devices"]; - ui->CheckboxAllDevices->setChecked(all_devices); - } - - if(server_settings.contains("legacy_workaround")) - { - bool legacy_workaround = server_settings["legacy_workaround"]; - ui->CheckboxLegacyWorkaround->setChecked(legacy_workaround); - } - - if(server_settings.contains("default_host")) - { - std::string host = server_settings["default_host"]; - ui->LineEditServerDefaultHost->setText(QString::fromStdString(host)); - } - - if(server_settings.contains("default_port")) - { - unsigned short port = server_settings["default_port"]; - ui->SpinBoxServerDefaultPort->setValue(port); - } - - UpdateProfiles(); - - /*---------------------------------------------------------*\ - | Make sure autostart settings exist | - \*---------------------------------------------------------*/ - CreateAutoStartSettings(); - - /*---------------------------------------------------------*\ - | Initialise UI to current settings or defaults | - \*---------------------------------------------------------*/ - json autostart_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("AutoStart"); - - RemediateAutoStartProfile(autostart_settings); - - /*---------------------------------------------------------*\ - | Text boxes | - \*---------------------------------------------------------*/ - ui->TextServerHost->setText(QString::fromStdString(autostart_settings["host"])); - ui->TextServerHost->setEnabled(autostart_settings["setserverhost"]); - - ui->TextServerPort->setValue(QString::fromStdString(autostart_settings["port"]).toInt()); - ui->TextServerPort->setEnabled(autostart_settings["setserverport"]); - - ui->TextClientHost->setText(QString::fromStdString(autostart_settings["client"])); - ui->TextClientHost->setEnabled(autostart_settings["setclient"]); - - ui->TextCustomArgs->setText(QString::fromStdString(autostart_settings["custom"])); - ui->TextCustomArgs->setEnabled(autostart_settings["setcustom"]); - - /*---------------------------------------------------------*\ - | Checkboxes | - \*---------------------------------------------------------*/ - ui->CheckboxAutoStart->setChecked(autostart_settings["enabled"]); - SetAutoStartVisibility(autostart_settings["enabled"]); - - ui->CheckboxAutoStartMinimized->setChecked(autostart_settings["setminimized"]); - ui->CheckboxAutoStartClient->setChecked(autostart_settings["setclient"]); - ui->CheckboxAutoStartServer->setChecked(autostart_settings["setserver"]); - ui->CheckboxAutoStartSetServerHost->setChecked(autostart_settings["setserverhost"]); - ui->CheckboxAutoStartSetServerPort->setChecked(autostart_settings["setserverport"]); - ui->CheckboxAutoStartCustom->setChecked(autostart_settings["setcustom"]); - - ui->AutoStartStatusLabel->hide(); - autostart_initialized = true; - - /*---------------------------------------------------------*\ - | Sync the autostart system configuration with settings on | - | startup. This ensures the file is recreated if it was | - | deleted (e.g. by a reinstall) without requiring the user | - | to manually toggle the checkbox. | - \*---------------------------------------------------------*/ - ConfigureAutoStart(); + UpdateInterface(); } OpenRGBSettingsPage::~OpenRGBSettingsPage() -{ - delete ui; -} - -void OpenRGBSettingsPage::changeEvent(QEvent *event) -{ - if(event->type() == QEvent::LanguageChange) - { - ui->retranslateUi(this); - } -} - -void OpenRGBSettingsPage::UpdateProfiles() { /*-----------------------------------------------------*\ - | Load AutoStart settings | + | Unregister settings manager callbacks | \*-----------------------------------------------------*/ - ProfileManager* profile_manager = ResourceManager::get()->GetProfileManager(); - - /*-----------------------------------------------------*\ - | Load profiles into combo box | - \*-----------------------------------------------------*/ - if(profile_manager != NULL) - { - ui->ComboBoxAutoStartProfile->blockSignals(true); - ui->ComboBoxExitProfile->blockSignals(true); - ui->ComboBoxOpenProfile->blockSignals(true); - ui->ComboBoxResumeProfile->blockSignals(true); - ui->ComboBoxSuspendProfile->blockSignals(true); - - ui->ComboBoxAutoStartProfile->clear(); - ui->ComboBoxExitProfile->clear(); - ui->ComboBoxOpenProfile->clear(); - ui->ComboBoxResumeProfile->clear(); - ui->ComboBoxSuspendProfile->clear(); - - for(std::size_t profile_index = 0; profile_index < profile_manager->GetProfileList().size(); profile_index++) - { - QString new_profile = QString(profile_manager->GetProfileList()[profile_index].c_str()); - - ui->ComboBoxAutoStartProfile->addItem(new_profile); - ui->ComboBoxExitProfile->addItem(new_profile); - ui->ComboBoxOpenProfile->addItem(new_profile); - ui->ComboBoxResumeProfile->addItem(new_profile); - ui->ComboBoxSuspendProfile->addItem(new_profile); - } - - ui->ComboBoxAutoStartProfile->blockSignals(false); - ui->ComboBoxExitProfile->blockSignals(false); - ui->ComboBoxOpenProfile->blockSignals(false); - ui->ComboBoxResumeProfile->blockSignals(false); - ui->ComboBoxSuspendProfile->blockSignals(false); - } - - /*-----------------------------------------------------*\ - | Load user interface settings | - \*-----------------------------------------------------*/ - json autostart_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("AutoStart"); - - if(autostart_settings.contains("profile")) - { - /*-------------------------------------------------*\ - | Set the profile name from settings and check the | - | profile combobox for a match | - \*-------------------------------------------------*/ - std::string profile_name = autostart_settings["profile"].get(); - int profile_index = ui->ComboBoxAutoStartProfile->findText(QString::fromStdString(profile_name)); - - if(profile_index > -1) - { - ui->ComboBoxAutoStartProfile->setCurrentIndex(profile_index); - } - } - - /*-----------------------------------------------------*\ - | Load profile manager settings | - \*-----------------------------------------------------*/ - json profilemanager_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("ProfileManager"); - - if(profilemanager_settings.contains("exit_profile")) - { - json profile = profilemanager_settings["exit_profile"]; - - if(profile.contains("enabled")) - { - bool is_enabled = profile["enabled"].get(); - ui->CheckboxSetOnExit->setChecked(is_enabled); - ui->ComboBoxExitProfile->setEnabled(is_enabled); - } - - if(profile.contains("name")) - { - /*---------------------------------------------*\ - | Set the profile name from settings and check | - | the profile combobox for a match | - \*---------------------------------------------*/ - std::string profile_name = profile["name"].get(); - int profile_index = ui->ComboBoxExitProfile->findText(QString::fromStdString(profile_name)); - - if(profile_index > -1) - { - ui->ComboBoxExitProfile->setCurrentIndex(profile_index); - } - } - } - - if(profilemanager_settings.contains("open_profile")) - { - json profile = profilemanager_settings["open_profile"]; - - if(profile.contains("enabled")) - { - bool is_enabled = profile["enabled"].get(); - ui->CheckboxSetOnOpen->setChecked(is_enabled); - ui->ComboBoxOpenProfile->setEnabled(is_enabled); - } - - if(profile.contains("name")) - { - /*---------------------------------------------*\ - | Set the profile name from settings and check | - | the profile combobox for a match | - \*---------------------------------------------*/ - std::string profile_name = profile["name"].get(); - int profile_index = ui->ComboBoxOpenProfile->findText(QString::fromStdString(profile_name)); - - if(profile_index > -1) - { - ui->ComboBoxOpenProfile->setCurrentIndex(profile_index); - } - } - } - - if(profilemanager_settings.contains("resume_profile")) - { - json profile = profilemanager_settings["resume_profile"]; - - if(profile.contains("enabled")) - { - bool is_enabled = profile["enabled"].get(); - ui->CheckboxSetOnResume->setChecked(is_enabled); - ui->ComboBoxResumeProfile->setEnabled(is_enabled); - } - - if(profile.contains("name")) - { - /*---------------------------------------------*\ - | Set the profile name from settings and check | - | the profile combobox for a match | - \*---------------------------------------------*/ - std::string profile_name = profile["name"].get(); - int profile_index = ui->ComboBoxResumeProfile->findText(QString::fromStdString(profile_name)); - - if(profile_index > -1) - { - ui->ComboBoxResumeProfile->setCurrentIndex(profile_index); - } - } - } - - if(profilemanager_settings.contains("suspend_profile")) - { - json profile = profilemanager_settings["suspend_profile"]; - - if(profile.contains("enabled")) - { - bool is_enabled = profile["enabled"].get(); - ui->CheckboxSetOnSuspend->setChecked(is_enabled); - ui->ComboBoxSuspendProfile->setEnabled(is_enabled); - } - - if(profile.contains("name")) - { - /*---------------------------------------------*\ - | Set the profile name from settings and check | - | the profile combobox for a match | - \*---------------------------------------------*/ - std::string profile_name = profile["name"].get(); - int profile_index = ui->ComboBoxSuspendProfile->findText(QString::fromStdString(profile_name)); - - if(profile_index > -1) - { - ui->ComboBoxSuspendProfile->setCurrentIndex(profile_index); - } - } - } + ResourceManager::get()->GetSettingsManager()->UnregisterSettingsManagerCallback(OpenRGBSettingsManagerCallback, this); } -void OpenRGBSettingsPage::on_ComboBoxLanguage_currentTextChanged(const QString language) -{ - - bool loaded = false; - QString file = ui->ComboBoxLanguage->currentData().toString(); - QApplication* app = static_cast(QApplication::instance()); - - app->removeTranslator(&translator); - - if(file == "default") - { - QLocale locale = QLocale(QLocale::system()); - QLocale::setDefault(locale); - - loaded = translator.load(":/i18n/" + QString("OpenRGB_%1.qm").arg(locale.name())); - } - else - { - loaded = translator.load(file); - } - - if(loaded) - { - app->installTranslator(&translator); - LOG_DEBUG("[Settings] Changed Language to %s from the %s file\n", language.toStdString().c_str(), file.toStdString().c_str()); - - json ui_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("UserInterface"); - std::string saved = ui_settings["language"].get(); - - if(saved != language.toStdString()) - { - ui_settings["language"] = language.toStdString(); - ResourceManager::get()->GetSettingsManager()->SetSettings("UserInterface",ui_settings); - SaveSettings(); - } - } -} - -void OpenRGBSettingsPage::on_ComboBoxTheme_currentTextChanged(const QString theme) -{ - if(theme_initialized) - { - json theme_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("Theme"); - theme_settings["theme"] = theme.toStdString(); - ResourceManager::get()->GetSettingsManager()->SetSettings("Theme", theme_settings); - SaveSettings(); - } -} - -void OpenRGBSettingsPage::on_ComboBoxHexFormat_currentTextChanged(const QString hex_format) -{ - if(hex_format_initialized) - { - json ui_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("UserInterface"); - ui_settings["hex_format"] = hex_format.toStdString(); - ResourceManager::get()->GetSettingsManager()->SetSettings("UserInterface",ui_settings); - SaveSettings(); - } -} - -void OpenRGBSettingsPage::on_CheckboxTrayIconGreyscale_clicked() -{ - json ui_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("UserInterface"); - bool tray_icon = ui->CheckboxTrayIconGreyscale->isChecked(); - - ui_settings["greyscale_tray_icon"] = tray_icon; - ResourceManager::get()->GetSettingsManager()->SetSettings("UserInterface", ui_settings); - SaveSettings(); - - emit TrayIconChanged(tray_icon); -} - -void OpenRGBSettingsPage::on_CheckboxMinimizeOnClose_clicked() -{ - json ui_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("UserInterface"); - ui_settings["minimize_on_close"] = ui->CheckboxMinimizeOnClose->isChecked(); - ResourceManager::get()->GetSettingsManager()->SetSettings("UserInterface", ui_settings); - SaveSettings(); -} - -void OpenRGBSettingsPage::on_CheckboxLoadGeometry_clicked() -{ - json ui_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("UserInterface"); - ui_settings["geometry"]["load_geometry"] = ui->CheckboxLoadGeometry->isChecked(); - ResourceManager::get()->GetSettingsManager()->SetSettings("UserInterface", ui_settings); - SaveSettings(); -} - -void OpenRGBSettingsPage::on_CheckboxSaveGeometry_clicked() -{ - json ui_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("UserInterface"); - ui_settings["geometry"]["save_on_exit"] = ui->CheckboxSaveGeometry->isChecked(); - ResourceManager::get()->GetSettingsManager()->SetSettings("UserInterface", ui_settings); - SaveSettings(); -} - -void OpenRGBSettingsPage::on_CheckboxRunZoneChecks_clicked() -{ - json ui_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("UserInterface"); - ui_settings["run_zone_checks"] = ui->CheckboxRunZoneChecks->isChecked(); - ResourceManager::get()->GetSettingsManager()->SetSettings("UserInterface", ui_settings); - SaveSettings(); -} - -void OpenRGBSettingsPage::on_CheckboxSetOnExit_clicked(bool checked) -{ - json profilemanager_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("ProfileManager"); - profilemanager_settings["exit_profile"]["enabled"] = checked; - profilemanager_settings["exit_profile"]["name"] = ui->ComboBoxExitProfile->currentText().toStdString(); - ResourceManager::get()->GetSettingsManager()->SetSettings("ProfileManager", profilemanager_settings); - SaveSettings(); - - ui->ComboBoxExitProfile->setEnabled(checked); -} - -void OpenRGBSettingsPage::on_ComboBoxExitProfile_currentTextChanged(const QString exit_profile_name) -{ - json profilemanager_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("ProfileManager"); - profilemanager_settings["exit_profile"]["name"] = exit_profile_name.toStdString(); - ResourceManager::get()->GetSettingsManager()->SetSettings("ProfileManager", profilemanager_settings); - SaveSettings(); -} - -void OpenRGBSettingsPage::on_CheckboxSetOnOpen_clicked(bool checked) -{ - json profilemanager_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("ProfileManager"); - profilemanager_settings["open_profile"]["enabled"] = checked; - profilemanager_settings["open_profile"]["name"] = ui->ComboBoxOpenProfile->currentText().toStdString(); - ResourceManager::get()->GetSettingsManager()->SetSettings("ProfileManager", profilemanager_settings); - SaveSettings(); - - ui->ComboBoxOpenProfile->setEnabled(checked); -} - -void OpenRGBSettingsPage::on_ComboBoxOpenProfile_currentTextChanged(const QString open_profile_name) -{ - json profilemanager_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("ProfileManager"); - profilemanager_settings["open_profile"]["name"] = open_profile_name.toStdString(); - ResourceManager::get()->GetSettingsManager()->SetSettings("ProfileManager", profilemanager_settings); - SaveSettings(); -} - -void OpenRGBSettingsPage::on_CheckboxSetOnResume_clicked(bool checked) -{ - json profilemanager_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("ProfileManager"); - profilemanager_settings["resume_profile"]["enabled"] = checked; - profilemanager_settings["resume_profile"]["name"] = ui->ComboBoxResumeProfile->currentText().toStdString(); - ResourceManager::get()->GetSettingsManager()->SetSettings("ProfileManager", profilemanager_settings); - SaveSettings(); - - ui->ComboBoxResumeProfile->setEnabled(checked); -} - -void OpenRGBSettingsPage::on_ComboBoxResumeProfile_currentTextChanged(const QString resume_profile_name) -{ - json profilemanager_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("ProfileManager"); - profilemanager_settings["resume_profile"]["name"] = resume_profile_name.toStdString(); - ResourceManager::get()->GetSettingsManager()->SetSettings("ProfileManager", profilemanager_settings); - SaveSettings(); -} - -void OpenRGBSettingsPage::on_CheckboxSetOnSuspend_clicked(bool checked) -{ - json profilemanager_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("ProfileManager"); - profilemanager_settings["suspend_profile"]["enabled"] = checked; - profilemanager_settings["suspend_profile"]["name"] = ui->ComboBoxSuspendProfile->currentText().toStdString(); - ResourceManager::get()->GetSettingsManager()->SetSettings("ProfileManager", profilemanager_settings); - SaveSettings(); - - ui->ComboBoxSuspendProfile->setEnabled(checked); -} - -void OpenRGBSettingsPage::on_ComboBoxSuspendProfile_currentTextChanged(const QString suspend_profile_name) -{ - json profilemanager_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("ProfileManager"); - profilemanager_settings["suspend_profile"]["name"] = suspend_profile_name.toStdString(); - ResourceManager::get()->GetSettingsManager()->SetSettings("ProfileManager", profilemanager_settings); - SaveSettings(); -} - -void OpenRGBSettingsPage::on_CheckboxAllDevices_clicked(bool checked) -{ - json server_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("Server"); - server_settings["all_devices"] = checked; - ResourceManager::get()->GetSettingsManager()->SetSettings("Server", server_settings); - SaveSettings(); -} - -void OpenRGBSettingsPage::on_CheckboxLegacyWorkaround_clicked(bool checked) -{ - json server_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("Server"); - server_settings["legacy_workaround"] = checked; - ResourceManager::get()->GetSettingsManager()->SetSettings("Server", server_settings); - SaveSettings(); -} - -void OpenRGBSettingsPage::on_CheckboxAutoStart_clicked() -{ - if(autostart_initialized) - { - json autostart_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("AutoStart"); - autostart_settings["enabled"] = ui->CheckboxAutoStart->isChecked(); - - if(autostart_settings["enabled"]) - { - RemediateAutoStartProfile(autostart_settings); - } - - ResourceManager::get()->GetSettingsManager()->SetSettings("AutoStart", autostart_settings); - SaveSettings(); - - SetAutoStartVisibility(autostart_settings["enabled"]); - - ConfigureAutoStart(); - } -} - -void OpenRGBSettingsPage::on_CheckboxAutoStartMinimized_clicked() -{ - SaveAutoStartSetting("setminimized", ui->CheckboxAutoStartMinimized->isChecked()); -} - -void OpenRGBSettingsPage::on_CheckboxAutoStartServer_clicked() -{ - SaveAutoStartSetting("setserver", ui->CheckboxAutoStartServer->isChecked()); -} - -void OpenRGBSettingsPage::on_CheckboxAutoStartSetServerHost_clicked() -{ - SaveAutoStartSetting("setserverhost", ui->CheckboxAutoStartSetServerHost->isChecked()); - ui->TextServerHost->setEnabled(ui->CheckboxAutoStartSetServerHost->isChecked()); -} - -void OpenRGBSettingsPage::on_CheckboxAutoStartSetServerPort_clicked() -{ - SaveAutoStartSetting("setserverport", ui->CheckboxAutoStartSetServerPort->isChecked()); - ui->TextServerPort->setEnabled(ui->CheckboxAutoStartSetServerPort->isChecked()); -} - -void OpenRGBSettingsPage::on_CheckboxAutoStartClient_clicked() -{ - SaveAutoStartSetting("setclient", ui->CheckboxAutoStartClient->isChecked()); - ui->TextClientHost->setEnabled(ui->CheckboxAutoStartClient->isChecked()); -} - -void OpenRGBSettingsPage::on_CheckboxAutoStartProfile_clicked() -{ - SaveAutoStartSetting("setprofile", ui->CheckboxAutoStartProfile->isChecked()); - ui->ComboBoxAutoStartProfile->setEnabled(ui->CheckboxAutoStartProfile->isChecked()); -} - -void OpenRGBSettingsPage::on_CheckboxAutoStartCustom_clicked() -{ - SaveAutoStartSetting("setcustom", ui->CheckboxAutoStartCustom->isChecked()); - ui->TextCustomArgs->setEnabled(ui->CheckboxAutoStartCustom->isChecked()); -} - -void OpenRGBSettingsPage::on_TextServerHost_textChanged(QString host) -{ - SaveAutoStartSetting("host", host); -} - -void OpenRGBSettingsPage::on_TextServerPort_valueChanged(int port) -{ - SaveAutoStartSetting("port", QString::number(port)); -} - -void OpenRGBSettingsPage::on_TextClientHost_textChanged(QString client) -{ - SaveAutoStartSetting("client", client); -} - -void OpenRGBSettingsPage::on_TextCustomArgs_textChanged(QString custom) -{ - SaveAutoStartSetting("custom", custom); -} - -void OpenRGBSettingsPage::on_ComboBoxAutoStartProfile_currentTextChanged(const QString profile) -{ - SaveAutoStartSetting("profile", profile); -} - -void OpenRGBSettingsPage::SaveAutoStartSetting(std::string name, QString value) -{ - if(autostart_initialized) - { - json autostart_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("AutoStart"); - autostart_settings[name] = value.toStdString(); - ResourceManager::get()->GetSettingsManager()->SetSettings("AutoStart", autostart_settings); - SaveSettings(); - - ConfigureAutoStart(); - } -} - -void OpenRGBSettingsPage::SaveAutoStartSetting(std::string name, bool value) -{ - if(autostart_initialized) - { - json autostart_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("AutoStart"); - autostart_settings[name] = value; - ResourceManager::get()->GetSettingsManager()->SetSettings("AutoStart", autostart_settings); - SaveSettings(); - - ConfigureAutoStart(); - } -} - -void OpenRGBSettingsPage::SetAutoStartVisibility(bool visible) -{ - if (!visible) - { - ui->ComboBoxAutoStartProfile->hide(); - ui->CheckboxAutoStartClient->hide(); - ui->CheckboxAutoStartCustom->hide(); - ui->CheckboxAutoStartMinimized->hide(); - ui->CheckboxAutoStartProfile->hide(); - ui->CheckboxAutoStartServer->hide(); - ui->CheckboxAutoStartSetServerHost->hide(); - ui->CheckboxAutoStartSetServerPort->hide(); - ui->TextCustomArgs->hide(); - ui->TextClientHost->hide(); - ui->TextServerHost->hide(); - ui->TextServerPort->hide(); - ui->AutoStartStatusLabel->hide(); - } - else - { - ui->ComboBoxAutoStartProfile->show(); - ui->CheckboxAutoStartClient->show(); - ui->CheckboxAutoStartCustom->show(); - ui->CheckboxAutoStartMinimized->show(); - ui->CheckboxAutoStartProfile->show(); - ui->CheckboxAutoStartServer->show(); - ui->CheckboxAutoStartSetServerHost->show(); - ui->CheckboxAutoStartSetServerPort->show(); - ui->TextCustomArgs->show(); - ui->TextClientHost->show(); - ui->TextServerHost->show(); - ui->TextServerPort->show(); - ui->AutoStartStatusLabel->show(); - } -} - -void OpenRGBSettingsPage::ConfigureAutoStart() -{ - std::map> autostart_map = { - {"setminimized", {"--startminimized","",false}}, - {"setserver", {"--server","",false}}, - {"setserverhost", {"--server-host","host",false}}, - {"setserverport", {"--server-port","port",false}}, - {"setclient", {"--client","client",false}}, - {"setprofile", {"--profile","profile",true}}, - {"setcustom", {"","custom",false}}, - }; - - json autostart_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("AutoStart"); - - AutoStart auto_start("OpenRGB"); - - if (!autostart_settings["enabled"]) - { - if (!auto_start.DisableAutoStart()) - { - ui->AutoStartStatusLabel->setText("A problem occurred disabling Start At Login."); - ui->AutoStartStatusLabel->show(); - SetAutoStartVisibility(true); - } - else - { - ui->AutoStartStatusLabel->hide(); - } - } - else - { - std::string desc = "OpenRGB "; - desc += VERSION_STRING; - desc += ", for controlling RGB lighting."; - - std::string arguments = ""; - - for(std::pair>& x: autostart_map) - { - std::string argumentsetting = x.first; - std::string argument = std::get<0>(x.second); - std::string argumentvaluename = std::get<1>(x.second); - bool argumentquoted = std::get<2>(x.second); - - if (autostart_settings[x.first]) - { - if (argument != "") - { - if (arguments != "") - { - arguments += " "; - } - arguments += argument; - } - if (argumentvaluename != "") - { - std::string argumentvalue = autostart_settings[argumentvaluename]; - if (argumentvalue != "") - { - if (arguments != "") - { - arguments += " "; - } - if (argumentquoted) - { - arguments += "\"" + argumentvalue + "\""; - } - else - { - arguments += argumentvalue; - } - } - } - } - } - - AutoStartInfo auto_start_info; - - auto_start_info.args = arguments; - auto_start_info.category = "Utility;"; - auto_start_info.desc = desc; - auto_start_info.icon = "OpenRGB"; - auto_start_info.path = auto_start.GetExePath(); - - if (!auto_start.EnableAutoStart(auto_start_info)) - { - ui->AutoStartStatusLabel->setText(tr("A problem occurred enabling Start at Login.")); - ui->AutoStartStatusLabel->show(); - SetAutoStartVisibility(true); - } - else - { - ui->AutoStartStatusLabel->hide(); - } - } -} - -void OpenRGBSettingsPage::CreateAutoStartSettings() -{ - std::map autostart_default_map_string = { - {"custom", ""}, - {"host", "0.0.0.0"}, - {"port", "6742"}, - {"client","localhost:6742"}, - {"profile",ui->ComboBoxAutoStartProfile->count() > 0 ? ui->ComboBoxAutoStartProfile->itemText(0).toStdString(): ""} - }; - - std::map autostart_default_map_bool = { - {"enabled", false}, - {"setminimized", false}, - {"setclient", false}, - {"setserver", false}, - {"setserverhost", false}, - {"setserverport", false}, - {"setcustom", false}, - {"setprofile", false}, - }; - - json autostart_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("AutoStart"); - - for(std::pair& x: autostart_default_map_bool) - { - if(!autostart_settings.contains(x.first)) - { - autostart_settings[x.first] = x.second; - } - } - - for(std::pair& x: autostart_default_map_string) - { - if(!autostart_settings.contains(x.first)) - { - autostart_settings[x.first] = x.second; - } - } - - ResourceManager::get()->GetSettingsManager()->SetSettings("AutoStart", autostart_settings); -} - -void OpenRGBSettingsPage::RemediateAutoStartProfile(json &autostart_settings) -{ - /*---------------------------------------------------------*\ - | If there are no profiles then we disable the UI for | - | profiles and if AutoStart is enabled then we force | - | disable setprofile | - \*---------------------------------------------------------*/ - if(ui->ComboBoxAutoStartProfile->count() == 0) - { - ui->CheckboxAutoStartProfile->setEnabled(false); - ui->ComboBoxAutoStartProfile->setEnabled(false); - - autostart_settings["profile"] = ""; - - if(autostart_settings["enabled"]) - { - autostart_settings["setprofile"] = false; - - ResourceManager::get()->GetSettingsManager()->SetSettings("AutoStart", autostart_settings); - - ConfigureAutoStart(); - SaveSettings(); - } - } - - /*---------------------------------------------------------*\ - | Else If the profile we want doesn't exist then we force | - | it to a profile which exists and if AutoStart is enabled | - | then we force disable setprofile | - \*---------------------------------------------------------*/ - else if(autostart_settings["profile"] == "" || - (autostart_settings["profile"] != "" && - ui->ComboBoxAutoStartProfile->findText(QString::fromStdString(autostart_settings["profile"])) == -1)) - { - autostart_settings["profile"] = ui->ComboBoxAutoStartProfile->itemText(0).toStdString(); - - if(autostart_settings["enabled"]) - { - autostart_settings["setprofile"] = false; - - ResourceManager::get()->GetSettingsManager()->SetSettings("AutoStart", autostart_settings); - - ConfigureAutoStart(); - SaveSettings(); - } - } - - ui->ComboBoxAutoStartProfile->setCurrentText(QString::fromStdString(autostart_settings["profile"])); - ui->ComboBoxAutoStartProfile->setEnabled(autostart_settings["setprofile"]); - ui->CheckboxAutoStartProfile->setChecked(autostart_settings["setprofile"]); -} - -void OpenRGBSettingsPage::SaveSettings() +void OpenRGBSettingsPage::OnSettingChanged(std::string key, nlohmann::json settings) { + ResourceManager::get()->GetSettingsManager()->ModifySettings(key, settings[key]); ResourceManager::get()->GetSettingsManager()->SaveSettings(); } -void OpenRGBSettingsPage::on_OpenSettingsFolderButton_clicked() +void OpenRGBSettingsPage::UpdateInterface() { - std::string config_dir = ResourceManager::get()->GetConfigurationDirectory().generic_u8string(); - QUrl url = QUrl::fromLocalFile(QString::fromStdString(config_dir)); - QDesktopServices::openUrl(url); -} + /*-----------------------------------------------------*\ + | Type to track ordering | + \*-----------------------------------------------------*/ + typedef struct + { + int order; + std::string key; + std::reference_wrapper value; + } ordered_settings_t; + /*-----------------------------------------------------*\ + | Delete existing items in the layout | + \*-----------------------------------------------------*/ + QLayoutItem* item; -void OpenRGBSettingsPage::on_CheckboxLogConsole_clicked() -{ - json log_manager_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("LogManager"); - log_manager_settings["log_console"] = ui->CheckboxLogConsole->isChecked(); - ResourceManager::get()->GetSettingsManager()->SetSettings("LogManager", log_manager_settings); - SaveSettings(); -} + while((item = ui->ScrollAreaSettingsLayout->layout()->takeAt(0)) != NULL) + { + delete item->widget(); + delete item; + } -void OpenRGBSettingsPage::on_CheckboxLogFile_clicked() -{ - json log_manager_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("LogManager"); - log_manager_settings["log_file"] = ui->CheckboxLogFile->isChecked(); - ResourceManager::get()->GetSettingsManager()->SetSettings("LogManager", log_manager_settings); - SaveSettings(); -} + /*-----------------------------------------------------*\ + | Initialize settings schema | + \*-----------------------------------------------------*/ + std::vector setting_entries; + nlohmann::json settings_schema = ResourceManager::get()->GetSettingsManager()->GetSettingsSchema(""); -void OpenRGBSettingsPage::on_CheckboxHIDSafeMode_clicked() -{ - json detector_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("Detectors"); - detector_settings["hid_safe_mode"] = ui->CheckboxHIDSafeMode->isChecked(); - ResourceManager::get()->GetSettingsManager()->SetSettings("Detectors", detector_settings); - SaveSettings(); -} + /*-----------------------------------------------------*\ + | Loop through the schema and build a vector containing | + | the entries in desired order. Entries with negative | + | order (default -1) are put at the end of the list. | + \*-----------------------------------------------------*/ + for(nlohmann::json::iterator key_iterator = settings_schema.begin(); key_iterator != settings_schema.end(); key_iterator++) + { + int order = -1; -void OpenRGBSettingsPage::on_TextDetectionDelay_valueChanged(int delay) -{ - json detector_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("Detectors"); - detector_settings["initial_detection_delay_ms"] = delay; - ResourceManager::get()->GetSettingsManager()->SetSettings("Detectors", detector_settings); - SaveSettings(); -} + if(key_iterator.value().contains("order")) + { + order = key_iterator.value()["order"]; + } -void OpenRGBSettingsPage::on_CheckboxAMDSMBusReduceCPU_clicked() -{ - json drivers_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("Drivers"); - drivers_settings["amd_smbus_reduce_cpu"] = ui->CheckboxAMDSMBusReduceCPU->isChecked(); - ResourceManager::get()->GetSettingsManager()->SetSettings("Drivers", drivers_settings); - SaveSettings(); -} + ordered_settings_t setting = {order, key_iterator.key(), key_iterator.value()}; -void OpenRGBSettingsPage::on_CheckboxSharedSMBusAccess_clicked() -{ - json drivers_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("Drivers"); - drivers_settings["shared_smbus_access"] = ui->CheckboxSharedSMBusAccess->isChecked(); - ResourceManager::get()->GetSettingsManager()->SetSettings("Drivers", drivers_settings); - SaveSettings(); -} + if((order < 0) || (setting_entries.size() == 0)) + { + setting_entries.push_back(setting); + } + else + { + bool added = false; -void OpenRGBSettingsPage::on_ComboBoxSMBusSleepMode_currentIndexChanged(int index) -{ - json drivers_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("Drivers"); - drivers_settings["smbus_sleep_mode"] = index; - ResourceManager::get()->GetSettingsManager()->SetSettings("Drivers", drivers_settings); - SaveSettings(); -} + for(std::size_t setting_idx = 0; setting_idx < setting_entries.size(); setting_idx++) + { + if((setting_entries[setting_idx].order > order) || (setting_entries[setting_idx].order < 0)) + { + setting_entries.insert(setting_entries.begin() + setting_idx, setting); + added = true; + break; + } + } -void OpenRGBSettingsPage::on_CheckboxDisableKeyExpansion_clicked() -{ - json ui_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("UserInterface"); - ui_settings["disable_key_expansion"] = ui->CheckboxDisableKeyExpansion->isChecked(); - ResourceManager::get()->GetSettingsManager()->SetSettings("UserInterface", ui_settings); - SaveSettings(); -} + if(!added) + { + setting_entries.push_back(setting); + } + } + } -void OpenRGBSettingsPage::on_CheckboxShowLEDView_clicked() -{ - json ui_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("UserInterface"); - ui_settings["show_led_view"] = ui->CheckboxShowLEDView->isChecked(); - ResourceManager::get()->GetSettingsManager()->SetSettings("UserInterface", ui_settings); - SaveSettings(); -} + /*-----------------------------------------------------*\ + | Create UI elements for each setting | + \*-----------------------------------------------------*/ + for(std::size_t setting_idx = 0; setting_idx < setting_entries.size(); setting_idx++) + { + nlohmann::json setting_value; + setting_value[setting_entries[setting_idx].key] = ResourceManager::get()->GetSettingsManager()->GetSettings(setting_entries[setting_idx].key); + OpenRGBDynamicSettingsWidget* item_widget = new OpenRGBDynamicSettingsWidget(setting_entries[setting_idx].key, setting_entries[setting_idx].value, setting_value); -void OpenRGBSettingsPage::on_LineEditServerDefaultHost_textChanged(const QString server_default_host) -{ - json server_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("Server"); - server_settings["default_host"] = server_default_host.toStdString(); - ResourceManager::get()->GetSettingsManager()->SetSettings("Server", server_settings); - SaveSettings(); -} + item_widget->SetCallback(Callback, this); + ui->ScrollAreaSettingsLayout->addWidget(item_widget); + } -void OpenRGBSettingsPage::on_SpinBoxServerDefaultPort_valueChanged(int server_default_port) -{ - json server_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("Server"); - server_settings["default_port"] = (unsigned short)server_default_port; - ResourceManager::get()->GetSettingsManager()->SetSettings("Server", server_settings); - SaveSettings(); + /*-----------------------------------------------------*\ + | Add a spacer at the end to prevent expanding | + \*-----------------------------------------------------*/ + QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); + ui->ScrollAreaSettingsLayout->addItem(spacer); } diff --git a/qt/OpenRGBSettingsPage/OpenRGBSettingsPage.h b/qt/OpenRGBSettingsPage/OpenRGBSettingsPage.h index 6b9e19037..bdc4fdd20 100644 --- a/qt/OpenRGBSettingsPage/OpenRGBSettingsPage.h +++ b/qt/OpenRGBSettingsPage/OpenRGBSettingsPage.h @@ -1,7 +1,9 @@ /*---------------------------------------------------------*\ | OpenRGBSettingsPage.h | | | -| User interface for general settings page | +| User interface for OpenRGB settings page | +| | +| Adam Honse 15 Apr 2026 | | | | This file is part of the OpenRGB project | | SPDX-License-Identifier: GPL-2.0-or-later | @@ -9,20 +11,15 @@ #pragma once -#include -#include -#include -#include -#include - -using json = nlohmann::json; +#include +#include "nlohmann/json.hpp" namespace Ui { class OpenRGBSettingsPage; } -class OpenRGBSettingsPage : public QWidget +class OpenRGBSettingsPage : public QDialog { Q_OBJECT @@ -30,72 +27,12 @@ public: explicit OpenRGBSettingsPage(QWidget *parent = nullptr); ~OpenRGBSettingsPage(); -signals: - void TrayIconChanged(bool tray_icon); - -public slots: - void UpdateProfiles(); + void OnSettingChanged(std::string key, nlohmann::json settings); + void UpdateInterface(); private: - Ui::OpenRGBSettingsPage *ui; - void SaveSettings(); - - void CreateAutoStartSettings(); - void ConfigureAutoStart(); - void RemediateAutoStartProfile(json &autostart_settings); - void SetAutoStartVisibility(bool visible); - void SaveAutoStartSetting(std::string name, QString value); - void SaveAutoStartSetting(std::string name, bool value); - - bool theme_initialized = false; - bool autostart_initialized = false; - bool hex_format_initialized = false; - QTranslator translator; - -private slots: - void changeEvent(QEvent *event); - void on_ComboBoxLanguage_currentTextChanged(const QString); - void on_ComboBoxTheme_currentTextChanged(const QString); - void on_ComboBoxHexFormat_currentTextChanged(const QString); - void on_CheckboxMinimizeOnClose_clicked(); - void on_CheckboxTrayIconGreyscale_clicked(); - void on_CheckboxLoadGeometry_clicked(); - void on_CheckboxSaveGeometry_clicked(); - void on_CheckboxAutoStart_clicked(); - void on_CheckboxAutoStartMinimized_clicked(); - void on_CheckboxAutoStartServer_clicked(); - void on_CheckboxAutoStartClient_clicked(); - void on_CheckboxAutoStartProfile_clicked(); - void on_TextServerHost_textChanged(const QString); - void on_TextServerPort_valueChanged(int); - void on_TextClientHost_textChanged(const QString); - void on_TextCustomArgs_textChanged(const QString); - void on_ComboBoxAutoStartProfile_currentTextChanged(const QString); - void on_CheckboxAutoStartSetServerHost_clicked(); - void on_CheckboxAutoStartSetServerPort_clicked(); - void on_CheckboxAutoStartCustom_clicked(); - void on_CheckboxRunZoneChecks_clicked(); - void on_OpenSettingsFolderButton_clicked(); - void on_CheckboxLogConsole_clicked(); - void on_CheckboxLogFile_clicked(); - void on_CheckboxHIDSafeMode_clicked(); - void on_TextDetectionDelay_valueChanged(int); - void on_CheckboxAMDSMBusReduceCPU_clicked(); - void on_CheckboxSharedSMBusAccess_clicked(); - void on_ComboBoxSMBusSleepMode_currentIndexChanged(int index); - - void on_CheckboxSetOnExit_clicked(bool checked); - void on_ComboBoxExitProfile_currentTextChanged(const QString exit_profile_name); - void on_CheckboxSetOnOpen_clicked(bool checked); - void on_ComboBoxOpenProfile_currentTextChanged(const QString open_profile_name); - void on_CheckboxSetOnResume_clicked(bool checked); - void on_ComboBoxResumeProfile_currentTextChanged(const QString resume_profile_name); - void on_CheckboxSetOnSuspend_clicked(bool checked); - void on_ComboBoxSuspendProfile_currentTextChanged(const QString suspend_profile_name); - void on_CheckboxDisableKeyExpansion_clicked(); - void on_CheckboxShowLEDView_clicked(); - void on_CheckboxAllDevices_clicked(bool checked); - void on_CheckboxLegacyWorkaround_clicked(bool checked); - void on_LineEditServerDefaultHost_textChanged(const QString server_default_host); - void on_SpinBoxServerDefaultPort_valueChanged(int server_default_port); + /*-----------------------------------------------------*\ + | UI Pointer | + \*-----------------------------------------------------*/ + Ui::OpenRGBSettingsPage* ui; }; diff --git a/qt/OpenRGBSettingsPage/OpenRGBSettingsPage.ui b/qt/OpenRGBSettingsPage/OpenRGBSettingsPage.ui index d56ec145c..8df4afe8a 100644 --- a/qt/OpenRGBSettingsPage/OpenRGBSettingsPage.ui +++ b/qt/OpenRGBSettingsPage/OpenRGBSettingsPage.ui @@ -1,419 +1,37 @@ OpenRGBSettingsPage - + 0 0 - 550 - 475 + 400 + 300 - Settings Page + Device Settings - - + + true - + 0 - -450 - 516 - 1294 + 0 + 386 + 286 - - - - - Autostart - - - - - - Start Client - - - - - - - - - - Start Server - - - - - - - Load Profile - - - - - - - Start at Login - - - - - - - - - - - - - Custom Arguments - - - - - - - Set Server Host - - - - - - - - - - 1 - - - 65535 - - - 6742 - - - - - - - Set Server Port - - - - - - - Start Minimized - - - - - - - Start at Login Status - - - - - - - - - - User Interface - - - - - - - - - Disable Key Expansion in Device View - - - - - - - Minimize on Close - - - - - - - Greyscale Tray Icon - - - - - - - - - - Language - - - - - - - Run Zone Checks on Rescan - - - - - - - Show LED View by Default - - - - - - - Load Window Geometry - - - - - - - Save Geometry on Close - - - - - - - Theme (restart required) - - - - - - - Hex Format - - - - - - - - - - - - - Server - - - - - - 127.0.0.1 - - - - - - - Server Default Host - - - - - - - Legacy Workaround - - - - - - - Serve All Devices (Including those from client connections) - - - - - - - Server Default Port - - - - - - - 65535 - - - 6742 - - - - - - - - - - Driver - - - - - - Shared SMBus Access (restart required) - - - - - - - AMD SMBus: Reduce CPU Usage (restart required) - - - - - - - SMBus Sleep Mode (restart required) - - - - - - - - - - - - - Detection - - - - - - 2147483647 - - - - - - - Initial Detection Delay (milliseconds, 0 to disable) - - - - - - - HID Safe Mode - - - - - - - - - - Profile - - - - - - - - - - - - Set Profile on Open - - - - - - - Set Profile on Exit - - - - - - - - - - Set Profile on Suspend - - - - - - - Set Profile on Resume - - - - - - - - - - - - - Log Manager - - - - - - Enable Log File (restart required) - - - - - - - Enable Log Console (restart required) - - - - - - - + - - - - Open Settings Folder - - - diff --git a/qt/OpenRGBThemeManager.cpp b/qt/OpenRGBThemeManager.cpp deleted file mode 100644 index 78725b4ff..000000000 --- a/qt/OpenRGBThemeManager.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/*---------------------------------------------------------*\ -| OpenRGBThemeManager.cpp | -| | -| Functionality for managing dark theme mode | -| | -| This file is part of the OpenRGB project | -| SPDX-License-Identifier: GPL-2.0-or-later | -\*---------------------------------------------------------*/ - -#include -#include -#include -#include -#include - -#ifdef _WIN32 -#include -#endif - -#include "OpenRGBThemeManager.h" -#include "ResourceManager.h" -#include "PluginManager.h" -#include "SettingsManager.h" - -void OpenRGBThemeManager::Init() -{ - -#ifdef __APPLE__ - /*-------------------------------------------------*\ - | Apply Qt Fusion theme on MacOS, as the MacOS | - | default theme does not handle vertical tabs well | - \*-------------------------------------------------*/ - QApplication::setStyle(QStyleFactory::create("Fusion")); -#endif - /*-------------------------------------------------*\ - | Apply dark theme if configured | - \*-------------------------------------------------*/ - if(IsDarkTheme()) - { - SetDarkTheme(); - } -} - -void OpenRGBThemeManager::SetDarkTheme() -{ - QPalette pal; - - pal.setColor(QPalette::WindowText, Qt::white); - pal.setColor(QPalette::Link, QColor(0,127,220)); - pal.setColor(QPalette::LinkVisited, QColor(64,196,220)); - pal.setColor(QPalette::Window, QColor(53,53,53)); - pal.setColor(QPalette::Base, QColor(53,53,53)); - pal.setColor(QPalette::AlternateBase, QColor(66,66,66)); - pal.setColor(QPalette::ToolTipBase, Qt::white); - pal.setColor(QPalette::ToolTipText, Qt::black); - pal.setColor(QPalette::Text, Qt::white); - pal.setColor(QPalette::Dark, QColor(35,35,35)); - pal.setColor(QPalette::Shadow, QColor(20,20,20)); - pal.setColor(QPalette::Button, QColor(53,53,53)); - pal.setColor(QPalette::ButtonText, Qt::white); - pal.setColor(QPalette::BrightText, Qt::red); - pal.setColor(QPalette::Highlight, QColor(42,130,218)); - pal.setColor(QPalette::HighlightedText, Qt::white); - - pal.setColor(QPalette::Disabled, QPalette::Text, QColor(127,127,127)); - pal.setColor(QPalette::Disabled, QPalette::WindowText, QColor(127,127,127)); - pal.setColor(QPalette::Disabled, QPalette::Highlight, QColor(80,80,80) ); - pal.setColor(QPalette::Disabled, QPalette::ButtonText, QColor(127,127,127)); - pal.setColor(QPalette::Disabled, QPalette::HighlightedText, QColor(127,127,127)); - pal.setColor(QPalette::Disabled, QPalette::Text, QColor(127,127,127)); - pal.setColor(QPalette::Disabled, QPalette::ButtonText, QColor(127,127,127)); - -#ifdef _WIN32 - QApplication::setStyle(QStyleFactory::create("Fusion")); -#endif - - QApplication::setPalette(pal); -} - -bool OpenRGBThemeManager::IsDarkTheme() -{ - - /*-------------------------------------------------*\ - | Dark theme settings | - \*-------------------------------------------------*/ - json theme_settings; - - /*-------------------------------------------------*\ - | Get prefered theme from settings manager | - \*-------------------------------------------------*/ - theme_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("Theme"); - - /*-------------------------------------------------*\ - | Read the theme key and adjust accordingly | - \*-------------------------------------------------*/ - std::string current_theme = "Light"; - - if(theme_settings.contains("theme")) - { - current_theme = theme_settings["theme"]; - } - - if(current_theme == "Dark") - { - return true; - } -#ifdef _WIN32 - else if(current_theme == "Auto") - { - QSettings settings("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", QSettings::NativeFormat); - - if(settings.value("AppsUseLightTheme") != 0) - { - return false; - } - else - { - return true; - } - } - - return false; -#endif - - return false; -} diff --git a/qt/OpenRGBThemeManager.h b/qt/OpenRGBThemeManager.h deleted file mode 100644 index e39b8836a..000000000 --- a/qt/OpenRGBThemeManager.h +++ /dev/null @@ -1,20 +0,0 @@ -/*---------------------------------------------------------*\ -| OpenRGBThemeManager.h | -| | -| Functionality for managing dark theme mode | -| | -| This file is part of the OpenRGB project | -| SPDX-License-Identifier: GPL-2.0-or-later | -\*---------------------------------------------------------*/ - -#pragma once - -#include - -class OpenRGBThemeManager -{ -public: - static void Init(); - static void SetDarkTheme(); - static bool IsDarkTheme(); -}; diff --git a/qt/OpenRGBZoneEditorDialog/OpenRGBZoneEditorDialog.cpp b/qt/OpenRGBZoneEditorDialog/OpenRGBZoneEditorDialog.cpp index 8e4808975..6e4d29c24 100644 --- a/qt/OpenRGBZoneEditorDialog/OpenRGBZoneEditorDialog.cpp +++ b/qt/OpenRGBZoneEditorDialog/OpenRGBZoneEditorDialog.cpp @@ -12,6 +12,8 @@ #include #include #include +#include +#include "OpenRGBDynamicSettingsWidget.h" #include "OpenRGBMatrixMapEditorDialog.h" #include "OpenRGBSegmentExportDialog.h" #include "OpenRGBZoneEditorDialog.h" @@ -19,6 +21,11 @@ #include "ResourceManager.h" #include "ui_OpenRGBZoneEditorDialog.h" +static void Callback(void* this_ptr, std::string key, nlohmann::json settings) +{ + ((OpenRGBZoneEditorDialog*)this_ptr)->OnSettingChanged(key, settings); +} + OpenRGBZoneEditorDialog::OpenRGBZoneEditorDialog(RGBController* edit_dev_ptr, unsigned int edit_zone_idx_val, QWidget *parent) : QDialog(parent), ui(new Ui::OpenRGBZoneEditorDialog) @@ -119,29 +126,6 @@ OpenRGBZoneEditorDialog::OpenRGBZoneEditorDialog(RGBController* edit_dev_ptr, un ui->LabelZoneMatrixMap->setText("Zone Matrix Map (*):"); } - /*-----------------------------------------------------*\ - | Initialize zone color order | - \*-----------------------------------------------------*/ - ui->ComboBoxZoneColorOrder->blockSignals(true); - ui->ComboBoxZoneColorOrder->addItem("Default"); - if(edit_zone.flags & ZONE_FLAG_SUPPORTS_COLOR_ORDER_DEFAULT) ui->ComboBoxZoneColorOrder->addItem("Default"); - if(edit_zone.flags & ZONE_FLAG_SUPPORTS_COLOR_ORDER_RGB) ui->ComboBoxZoneColorOrder->addItem("RGB"); - if(edit_zone.flags & ZONE_FLAG_SUPPORTS_COLOR_ORDER_RBG) ui->ComboBoxZoneColorOrder->addItem("RBG"); - if(edit_zone.flags & ZONE_FLAG_SUPPORTS_COLOR_ORDER_GRB) ui->ComboBoxZoneColorOrder->addItem("GRB"); - if(edit_zone.flags & ZONE_FLAG_SUPPORTS_COLOR_ORDER_GBR) ui->ComboBoxZoneColorOrder->addItem("GBR"); - if(edit_zone.flags & ZONE_FLAG_SUPPORTS_COLOR_ORDER_BRG) ui->ComboBoxZoneColorOrder->addItem("BRG"); - if(edit_zone.flags & ZONE_FLAG_SUPPORTS_COLOR_ORDER_BGR) ui->ComboBoxZoneColorOrder->addItem("BGR"); - ui->ComboBoxZoneColorOrder->blockSignals(false); - - if((edit_zone.flags & ZONE_FLAG_MANUALLY_CONFIGURABLE_COLOR_ORDER) == 0) - { - ui->ComboBoxZoneColorOrder->setEnabled(false); - } - else if(edit_zone.flags & ZONE_FLAG_MANUALLY_CONFIGURED_COLOR_ORDER) - { - ui->LabelZoneColorOrder->setText("Zone Color Order (*):"); - } - /*-----------------------------------------------------*\ | Initialize segment list | \*-----------------------------------------------------*/ @@ -179,6 +163,38 @@ OpenRGBZoneEditorDialog::OpenRGBZoneEditorDialog(RGBController* edit_dev_ptr, un edit_zone.flags |= ZONE_FLAG_MANUALLY_CONFIGURED_SEGMENTS; ui->GroupBoxSegments->setTitle("Segments Configuration (*)"); } + + /*-----------------------------------------------------*\ + | Initialize configuration list | + \*-----------------------------------------------------*/ + nlohmann::json configuration_schema = edit_dev->GetDeviceSpecificZoneConfigurationSchema(edit_zone_idx); + nlohmann::json configuration_value = edit_dev->GetDeviceSpecificZoneConfiguration(edit_zone_idx); + + if(configuration_schema.empty()) + { + ui->GroupBoxDeviceSpecificZoneConfiguration->setHidden(true); + } + else + { + /*-------------------------------------------------*\ + | Loop through the schema and create an entry for | + | each configuration | + \*-------------------------------------------------*/ + for(nlohmann::json::iterator json_iterator = configuration_schema.begin(); json_iterator != configuration_schema.end(); json_iterator++) + { + nlohmann::json schema_entry = json_iterator.value(); + OpenRGBDynamicSettingsWidget* item_widget = new OpenRGBDynamicSettingsWidget(json_iterator.key(), schema_entry, configuration_value); + + item_widget->SetCallback(Callback, this); + ui->ScrollAreaDeviceSpecificZoneConfigurationLayout->addWidget(item_widget); + } + + /*-------------------------------------------------*\ + | Add a spacer at the end to prevent expanding | + \*-------------------------------------------------*/ + QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); + ui->ScrollAreaDeviceSpecificZoneConfigurationLayout->addItem(spacer); + } } OpenRGBZoneEditorDialog::~OpenRGBZoneEditorDialog() @@ -347,27 +363,12 @@ int OpenRGBZoneEditorDialog::show() } else { - /*-------------------------------------------------*\ - | Read the selected color order | - \*-------------------------------------------------*/ - zone_color_order new_color_order = 0; - int new_color_order_index = ui->ComboBoxZoneColorOrder->currentIndex(); - - if(((int)new_color_order < new_color_order_index) && (edit_zone.flags & ZONE_FLAG_SUPPORTS_COLOR_ORDER_DEFAULT)) new_color_order++; - if(((int)new_color_order < new_color_order_index) && (edit_zone.flags & ZONE_FLAG_SUPPORTS_COLOR_ORDER_RGB)) new_color_order++; - if(((int)new_color_order < new_color_order_index) && (edit_zone.flags & ZONE_FLAG_SUPPORTS_COLOR_ORDER_RBG)) new_color_order++; - if(((int)new_color_order < new_color_order_index) && (edit_zone.flags & ZONE_FLAG_SUPPORTS_COLOR_ORDER_GRB)) new_color_order++; - if(((int)new_color_order < new_color_order_index) && (edit_zone.flags & ZONE_FLAG_SUPPORTS_COLOR_ORDER_GBR)) new_color_order++; - if(((int)new_color_order < new_color_order_index) && (edit_zone.flags & ZONE_FLAG_SUPPORTS_COLOR_ORDER_BRG)) new_color_order++; - if(((int)new_color_order < new_color_order_index) && (edit_zone.flags & ZONE_FLAG_SUPPORTS_COLOR_ORDER_BGR)) new_color_order++; - /*-------------------------------------------------*\ | Update zone with new settings | \*-------------------------------------------------*/ edit_zone.name = ui->LineEditZoneName->text().toStdString(); edit_zone.leds_count = ui->SliderZoneSize->value(); edit_zone.type = ui->ComboBoxZoneType->currentIndex(); - edit_zone.color_order = ui->ComboBoxZoneColorOrder->currentIndex(); if(edit_zone.flags & ZONE_FLAG_MANUALLY_CONFIGURED_SEGMENTS) { @@ -420,13 +421,18 @@ int OpenRGBZoneEditorDialog::show() edit_dev->ConfigureZone(edit_zone_idx, edit_zone); /*-------------------------------------------------*\ - | Save the size profile | + | Apply zone configuration | + \*-------------------------------------------------*/ + edit_dev->SetDeviceSpecificZoneConfiguration(edit_zone_idx, zone_configuration); + + /*-------------------------------------------------*\ + | Save the configuration | \*-------------------------------------------------*/ ProfileManager* profile_manager = ResourceManager::get()->GetProfileManager(); if(profile_manager != NULL) { - profile_manager->SaveSizes(); + profile_manager->SaveConfiguration(); } /*-------------------------------------------------*\ @@ -885,13 +891,13 @@ void OpenRGBZoneEditorDialog::on_ButtonResetZoneConfiguration_clicked() edit_dev->ConfigureZone(edit_zone_idx, edit_zone); /*-------------------------------------------------*\ - | Save the size profile | + | Save the configuration | \*-------------------------------------------------*/ ProfileManager* profile_manager = ResourceManager::get()->GetProfileManager(); if(profile_manager != NULL) { - profile_manager->SaveSizes(); + profile_manager->SaveConfiguration(); } done(0); @@ -915,12 +921,8 @@ void OpenRGBZoneEditorDialog::on_ComboBoxZoneType_currentIndexChanged(int /*inde } } -void OpenRGBZoneEditorDialog::on_ComboBoxZoneColorOrder_currentIndexChanged(int /*index*/) +void OpenRGBZoneEditorDialog::OnSettingChanged(std::string /*key*/, nlohmann::json settings) { - if((edit_zone.flags & ZONE_FLAG_MANUALLY_CONFIGURED_COLOR_ORDER) == 0) - { - edit_zone.flags |= ZONE_FLAG_MANUALLY_CONFIGURED_COLOR_ORDER; - ui->LabelZoneColorOrder->setText("Zone Color Order (*):"); - } + edit_zone.flags |= ZONE_FLAG_MANUALLY_CONFIGURED_DEVICE_SPECIFIC; + zone_configuration.update(settings, true); } - diff --git a/qt/OpenRGBZoneEditorDialog/OpenRGBZoneEditorDialog.h b/qt/OpenRGBZoneEditorDialog/OpenRGBZoneEditorDialog.h index f91bb9009..fc40a7e2a 100644 --- a/qt/OpenRGBZoneEditorDialog/OpenRGBZoneEditorDialog.h +++ b/qt/OpenRGBZoneEditorDialog/OpenRGBZoneEditorDialog.h @@ -43,6 +43,7 @@ public: ~OpenRGBZoneEditorDialog(); int show(); + void OnSettingChanged(std::string key, nlohmann::json settings); private slots: void changeEvent(QEvent *event); @@ -59,14 +60,25 @@ private slots: void on_ButtonResetZoneConfiguration_clicked(); void on_LineEditZoneName_textChanged(const QString& arg1); void on_ComboBoxZoneType_currentIndexChanged(int index); - void on_ComboBoxZoneColorOrder_currentIndexChanged(int index); private: + /*-----------------------------------------------------*\ + | UI Pointer | + \*-----------------------------------------------------*/ Ui::OpenRGBZoneEditorDialog* ui; + + /*-----------------------------------------------------*\ + | Device pointer and zone index | + \*-----------------------------------------------------*/ RGBController* edit_dev; zone edit_zone; unsigned int edit_zone_idx; + /*-----------------------------------------------------*\ + | Zone configuration | + \*-----------------------------------------------------*/ + nlohmann::json zone_configuration; + void AddSegmentRow(QString name, unsigned int length, zone_type type, matrix_map_type matrix_map, QTreeWidget* parent); void AddSegmentRow(QString name, unsigned int length, zone_type type, matrix_map_type matrix_map, QTreeWidgetItem* parent); void AddSegmentRowInternal(QString name, unsigned int length, zone_type type, matrix_map_type matrix_map, SegmentTreeWidgetItem* new_item); diff --git a/qt/OpenRGBZoneEditorDialog/OpenRGBZoneEditorDialog.ui b/qt/OpenRGBZoneEditorDialog/OpenRGBZoneEditorDialog.ui index c24ff9256..6281763d3 100644 --- a/qt/OpenRGBZoneEditorDialog/OpenRGBZoneEditorDialog.ui +++ b/qt/OpenRGBZoneEditorDialog/OpenRGBZoneEditorDialog.ui @@ -7,7 +7,7 @@ 0 0 750 - 400 + 496 @@ -91,6 +91,60 @@ + + + + + + Reset Zone Configuration + + + + + + + + 0 + 0 + + + + Qt::Orientation::Horizontal + + + QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok + + + + + + + + + Device-Specific Zone Configuration + + + + + + true + + + + + 0 + 0 + 714 + 65 + + + + + + + + + @@ -99,12 +153,6 @@ - - - - - - @@ -112,19 +160,8 @@ - - - - Zone Matrix Map: - - - - - - - Zone Color Order: - - + + @@ -133,6 +170,13 @@ + + + + Zone Matrix Map: + + + @@ -178,33 +222,6 @@ - - - - - - Reset Zone Configuration - - - - - - - - 0 - 0 - - - - Qt::Orientation::Horizontal - - - QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok - - - - - @@ -223,12 +240,12 @@ accept() - 248 - 254 + 20 + 20 - 157 - 274 + 20 + 20 @@ -239,12 +256,12 @@ reject() - 316 - 260 + 20 + 20 - 286 - 274 + 20 + 20 diff --git a/qt/OpenRGBZoneInitializationDialog/OpenRGBZoneInitializationDialog.cpp b/qt/OpenRGBZoneInitializationDialog/OpenRGBZoneInitializationDialog.cpp index d6db60f50..3f01fddd8 100644 --- a/qt/OpenRGBZoneInitializationDialog/OpenRGBZoneInitializationDialog.cpp +++ b/qt/OpenRGBZoneInitializationDialog/OpenRGBZoneInitializationDialog.cpp @@ -186,16 +186,13 @@ void OpenRGBZoneInitializationDialog::on_save_button_clicked() } /*---------------------------------------------------------*\ - | Save the sizes | + | Save the configuration | \*---------------------------------------------------------*/ ProfileManager* profile_manager = ResourceManager::get()->GetProfileManager(); if(profile_manager != NULL) { - /*-----------------------------------------------------*\ - | Save the profile | - \*-----------------------------------------------------*/ - profile_manager->SaveSizes(); + profile_manager->SaveConfiguration(); } /*---------------------------------------------------------*\ diff --git a/qt/i18n/OpenRGB_be_BY.ts b/qt/i18n/OpenRGB_be_BY.ts index 82b4cd60c..d8baa6f88 100644 --- a/qt/i18n/OpenRGB_be_BY.ts +++ b/qt/i18n/OpenRGB_be_BY.ts @@ -1130,7 +1130,7 @@ - OpenRGBSettingsPage + Settings Load Window Geometry Загружаць геаметрыю акна @@ -1164,7 +1164,7 @@ Згортваць замест закрыцця - Save Geometry on Close + Save on Exit Захоўваць геаметрыю акна пры закрыцці @@ -1180,12 +1180,8 @@ Задаць порт сервера - Theme (restart required) - Тэма (патрабуецца перазапуск) - - - Enable Log Console (restart required) - Уключыць кансоль журнала (патрабуецца перазапуск) + Enable Log Console + Уключыць кансоль журнала Custom Arguments @@ -1212,7 +1208,7 @@ Налады драйвераў - Greyscale Tray Icon + Monochrome Tray Icon Значок вобласці апавяшчэнняў у градацыях шэрага @@ -1236,7 +1232,7 @@ Мова - Disable Key Expansion in Device View + Disable Key Expansion Адключыць пашырэнне клавіш у перадпраглядзе LED @@ -1256,8 +1252,8 @@ Задаць профіль пры ўзнаўленні працы камп'ютара - Enable Log File (restart required) - Уключыць вядзенне журнала (патрабуецца перазапуск) + Enable Log File + Уключыць вядзенне журнала A problem occurred enabling Start at Login. diff --git a/qt/i18n/OpenRGB_de_DE.ts b/qt/i18n/OpenRGB_de_DE.ts index aff2e2457..88e6421e8 100644 --- a/qt/i18n/OpenRGB_de_DE.ts +++ b/qt/i18n/OpenRGB_de_DE.ts @@ -1131,7 +1131,7 @@ - OpenRGBSettingsPage + Settings Load Window Geometry Fenster Geometrie laden @@ -1145,7 +1145,7 @@ Zonen beim erneuten Scannen überprüfen - Disable Key Expansion in Device View + Disable Key Expansion Deaktiviere Schlüsselerweiterung in der Geräteansicht @@ -1165,7 +1165,7 @@ Minimiert Starten - Greyscale Tray Icon + Monochrome Tray Icon Graues Icon @@ -1185,15 +1185,15 @@ Profil beim Schließen anwenden - Enable Log File (restart required) - Log Datei aktivieren (Programmneustart erforderlich) + Enable Log File + Log Datei aktivieren Minimize on Close Beim Schließen in die Taskleiste minimieren - Save Geometry on Close + Save on Exit Geometrie beim Schließen beibehalten @@ -1209,12 +1209,8 @@ Server Port setzen - Theme (restart required) - Stil (Programmneustart erforderlich) - - - Enable Log Console (restart required) - Log Konsole aktivieren (Programmneustart erforderlich) + Enable Log Console + Log Konsole aktivieren Drivers Settings diff --git a/qt/i18n/OpenRGB_el_GR.ts b/qt/i18n/OpenRGB_el_GR.ts index adfc9681a..1b9a334ec 100644 --- a/qt/i18n/OpenRGB_el_GR.ts +++ b/qt/i18n/OpenRGB_el_GR.ts @@ -1131,7 +1131,7 @@ - OpenRGBSettingsPage + Settings Load Window Geometry Φόρτωση γεωμετρίας παραθύρου @@ -1165,7 +1165,7 @@ Ελαχιστοποίηση στο κλείσιμο - Save Geometry on Close + Save on Exit Αποθήκευση γεωμετρίας στο κλείσιμο @@ -1181,12 +1181,8 @@ Ορισμός θύρας διακομιστή - Theme (restart required) - Θέμα (απαιτείται επανεκκίνηση) - - - Enable Log Console (restart required) - Ενεργοποίηση της κονσόλας καταγραφής (απαιτείται επανεκκίνηση) + Enable Log Console + Ενεργοποίηση της κονσόλας καταγραφής Custom Arguments @@ -1213,7 +1209,7 @@ Ρυθμίσεις οδηγών - Greyscale Tray Icon + Monochrome Tray Icon Εικονίδιο γράμμης εργάσιων σε κλίμακα του γκρι @@ -1237,7 +1233,7 @@ Γλώσσα - Disable Key Expansion in Device View + Disable Key Expansion @@ -1257,7 +1253,7 @@ - Enable Log File (restart required) + Enable Log File diff --git a/qt/i18n/OpenRGB_en_AU.ts b/qt/i18n/OpenRGB_en_AU.ts index b47a6d115..2b3e890e4 100644 --- a/qt/i18n/OpenRGB_en_AU.ts +++ b/qt/i18n/OpenRGB_en_AU.ts @@ -879,7 +879,7 @@ - OpenRGBSettingsPage + Settings Load Window Geometry @@ -905,7 +905,7 @@ Minimise On Close - Save Geometry on Close + Save on Exit @@ -921,11 +921,7 @@ - Theme (restart required) - - - - Enable Log Console (restart required) + Enable Log Console @@ -953,7 +949,7 @@ - Greyscale Tray Icon + Monochrome Tray Icon @@ -977,7 +973,7 @@ - Disable Key Expansion in Device View + Disable Key Expansion @@ -997,8 +993,8 @@ - Enable Log File (restart required) - + Enable Log File + A problem occurred enabling Start at Login. diff --git a/qt/i18n/OpenRGB_en_GB.ts b/qt/i18n/OpenRGB_en_GB.ts index 0e30df381..eed6a34ea 100644 --- a/qt/i18n/OpenRGB_en_GB.ts +++ b/qt/i18n/OpenRGB_en_GB.ts @@ -879,7 +879,7 @@ - OpenRGBSettingsPage + Settings Load Window Geometry @@ -909,7 +909,7 @@ Minimise On Close - Save Geometry on Close + Save on Exit @@ -925,11 +925,7 @@ - Theme (restart required) - - - - Enable Log Console (restart required) + Enable Log Console @@ -957,7 +953,7 @@ - Greyscale Tray Icon + Monochrome Tray Icon @@ -981,7 +977,7 @@ - Disable Key Expansion in Device View + Disable Key Expansion @@ -1001,8 +997,8 @@ - Enable Log File (restart required) - + Enable Log File + A problem occurred enabling Start at Login. diff --git a/qt/i18n/OpenRGB_en_US.ts b/qt/i18n/OpenRGB_en_US.ts index e98778158..98e732b2d 100644 --- a/qt/i18n/OpenRGB_en_US.ts +++ b/qt/i18n/OpenRGB_en_US.ts @@ -5,1404 +5,1400 @@ DMXSettingsEntry DMX Device - + Brightness Channel: - + Blue Channel: - + Name: - + Green Channel: - + Red Channel: - + Keepalive Time: - + Port: - + DetectorTableModel Name - + Enabled - + E131SettingsEntry E1.31 Device - + Start Channel: - + Number of LEDs: - + Start Universe: - + Name: - + Matrix Order: - + Matrix Height: - + Matrix Width: - + Type: - + IP (Unicast): - + Universe Size: - + Keepalive Time: - + RGB Order: - + Single - + Linear - + Matrix - + Horizontal Top Left - + Horizontal Top Right - + Horizontal Bottom Left - + Horizontal Bottom Right - + Vertical Top Left - + Vertical Top Right - + Vertical Bottom Left - + Vertical Bottom Right - + ElgatoKeyLightSettingsEntry Elgato Key Light - + IP: - + ElgatoLightStripSettingsEntry Elgato Light Strip - + IP: - + GoveeSettingsEntry Govee Device - + IP: - + KasaSmartSettingsEntry Kasa Smart Device - + IP: - + Name - + LIFXSettingsEntry LIFX Device - + IP: - + Name - + ManualDevice E1.31 (including WLED) - + QMK (built with ORGB support) - + Serial Device - + ManualDevicesSettingsPage Add Device... - + Remove - + Save and Rescan - + Save without Rescan - + NanoleafNewDeviceDialog New Nanoleaf device - + IP address: - + Port: - + NanoleafScanDialog To pair, hold the on-off button down for 5-7 seconds until the LED starts flashing in a pattern, a new entry should appear in the list below, then click the "Pair" button on the entry within 30 seconds. - + Scan - + Add manually - + Remove - + NanoleafSettingsEntry Nanoleaf Device - + IP: - + Port: - + Auth Key: - + Unpair - + Pair - + OpenRGBClientInfoPage Port: - + Connect - + IP: - + Connected Clients - + Protocol Version - + Save Connection - + Disconnect - + OpenRGBConsolePage Log level - + Refresh logs - + Clear log - + OpenRGBDeviceInfoPage Name: - + Vendor: - + Type: - + Description: - + Version: - + Location: - + Serial: - + Flags: - + OpenRGBDevicePage G: - + H: - + Speed: - + Random - + B: - + LED: - + Mode-Specific - + R: - + Dir: - + S: - + Select All - + Per-LED - + Zone: - + <html><head/><body><p align="justify">Sets all devices to<br/><b>Static</b> mode and<br/>applies the selected color.</p></body></html> - + Apply All Devices - + Colors: - + V: - + Apply Colors To Selection - + Mode: - + Brightness: - + Save To Device - + Hex: - + Edit - + Set individual LEDs to static colors. Safe for use with software-driven effects. - + Set individual LEDs to static colors. Not safe for use with software-driven effects. - + Sets the entire device or a zone to a single color. - + Gradually fades between fully off and fully on. - + Abruptly changes between fully off and fully on. - + Gradually cycles through the entire color spectrum. All lights on the device are the same color. - + Gradually cycles through the entire color spectrum. Produces a rainbow pattern that moves. - + Flashes lights when keys or buttons are pressed. - + Entire Device - + Entire Zone - + Left - + Right - + Up - + Down - + Horizontal - + Vertical - + Saved To Device - + Saving Not Supported - + All Zones - + Mode Specific - + Entire Segment - + OpenRGBDialog OpenRGB - + Devices - + Information - + Settings - + Toggle LED View - + Rescan Devices - + Save Profile - + Delete Profile - + Load Profile - + OpenRGB is detecting devices... - + Cancel - + Save Profile As... - + Save Profile with custom name - + Show/Hide - + Profiles - + Quick Colors - + Red - + Yellow - + Green - + Cyan - + Blue - + Magenta - + White - + Lights Off - + Exit - + Plugins - + General Settings - + SMBus Tools - + SDK Client - + SDK Server - + Do you really want to delete this profile? - + Log Console - + Supported Devices - + About OpenRGB - + Manually Added Devices - + OpenRGBHardwareIDsDialog Location - + Device - + Vendor - + Copy to clipboard - + Hardware IDs - + OpenRGBPluginsEntry Version: - + Name: - + Description: - + URL: - + Path: - + Enabled - + Commit: - + API Version: - + API Version Value - + OpenRGBPluginsPage Install Plugin - + Remove Plugin - + <html><head/><body>Looking for plugins? See the official list at <a href="https://openrgb.org/plugins.html">OpenRGB.org</a></body></html> - + Install OpenRGB Plugin - + Plugin files (*.dll *.dylib *.so *.so.*) - + Replace Plugin - + A plugin with this filename is already installed. Are you sure you want to replace this plugin? - + Are you sure you want to remove this plugin? - + Restart Needed - + The plugin will be fully removed after restarting OpenRGB. - + OpenRGBProfileListDialog Profile Name - + Save to an existing profile: - + Create a new profile: - + OpenRGBServerInfoPage Stop Server - + Server Port: - + Start Server - + Server Status: - + Offline - + Connected Clients: - + Server Host: - + Client IP - + Protocol Version - + Client Name - + Stopping... - + Online - + - OpenRGBSettingsPage + Settings Load Window Geometry - + Run Zone Checks on Rescan - + Start Server - + Start Minimized - + User Interface Settings: - + Start at Login - + Minimize on Close - + - Save Geometry on Close - + Save on Exit + Start Client - + Load Profile - + Set Server Port - + - Theme (restart required) - - - - Enable Log Console (restart required) - + Enable Log Console + Custom Arguments - + Log Manager Settings: - + Start at Login Status - + Start at Login Settings: - + Open Settings Folder - + Drivers Settings - + - Greyscale Tray Icon - + Monochrome Tray Icon + AMD SMBus: Reduce CPU Usage (restart required) - + Set Profile on Exit - + Shared SMBus Access (restart required) - + Set Server Host - + Language - + - Disable Key Expansion in Device View - + Disable Key Expansion + Hex Format - + Show LED View by Default - + Set Profile on Suspend - + Set Profile on Resume - + - Enable Log File (restart required) - + Enable Log File + A problem occurred enabling Start at Login. - + English - US - English - US + English - US System Default - + OpenRGBSoftwareInfoPage Build Date: - + Git Commit ID: - + Git Commit Date: - + Git Branch: - + Version: - + GitLab: - + Website: - + <a href="https://openrgb.org">https://openrgb.org</a> - + <a href="https://gitlab.com/CalcProgrammer1/OpenRGB">https://gitlab.com/CalcProgrammer1/OpenRGB</a> - + SDK Version: - + Plugin API Version: - + Qt Version Value - + Qt Version: - + OS Version: - + OS Version Value - + GNU General Public License, version 2 - + License: - + Copyright: - + Adam Honse, OpenRGB Team - + <b>OpenRGB</b>, an open-source RGB control utility - + OpenRGBSupportedDevicesPage Filter: - + Enable/Disable all - + Apply Changes - + Get Hardware IDs - + OpenRGBSystemInfoPage SMBus Adapters: - + Address: - + Read Device - + SMBus Dumper: - + 0x - + SMBus Detector: - + Detection Mode: - + Detect Devices - + Dump Device - + SMBus Reader: - + Addr: - + Reg: - + Size: - + OpenRGBZoneEditorDialog Resize Zone - + Add Segment - + Remove Segment - + Length - + OpenRGBZoneInitializationDialog Do not show again - + Save and close - + Ignore - + Zones Resizer - + <html><head/><body><p>One or more resizable zones have not been configured. Resizable zones are most commonly used for addressable RGB headers where the size of the connected device cannot be detected automatically.</p><p>Please enter the number of LEDs in each zone below.</p><p>For more information about calcuating the correct size, please check <a href="https://openrgb.org/resize.html"><span style=" text-decoration: underline; color:#0000ff;">this link.</span></a></p></body></html> - + Resize the zones - + Controller - + Zone - + Size - + PhilipsHueSettingsEntry Philips Hue Bridge - + Entertainment Mode: - + Auto Connect Group: - + IP: - + Client Key: - + Username: - + MAC: - + Unpair Bridge - + PhilipsWizSettingsEntry Philips Wiz Device - + Use Cool White - + Use Warm White - + IP: - + White Strategy: - + Average - + Minimum - + QMKORGBSettingsEntry QMK Device - + Name: - + USB PID: - + USB VID: - + ResourceManager <h2>Some internal devices may not be detected:</h2><p>One or more I2C or SMBus interfaces failed to initialize.</p><p><b>RGB DRAM modules, some motherboards' onboard RGB lighting, and RGB Graphics Cards, will not be available in OpenRGB</b> without I2C or SMBus.</p><h4>How to fix this:</h4><p>On Windows, this is usually caused by a failure to load the WinRing0 driver.</p><p>You must run OpenRGB as administrator at least once to allow WinRing0 to set up.</p><p>See <a href='https://help.openrgb.org/'>help.openrgb.org</a> for additional troubleshooting steps if you keep seeing this message.<br></p><h3>If you are not using internal RGB on a desktop this message is not important to you.</h3> - + <h2>Some internal devices may not be detected:</h2><p>One or more I2C or SMBus interfaces failed to initialize.</p><p><b>RGB DRAM modules, some motherboards' onboard RGB lighting, and RGB Graphics Cards, will not be available in OpenRGB</b> without I2C or SMBus.</p><h4>How to fix this:</h4><p>On Linux, this is usually because the i2c-dev module is not loaded.</p><p>You must load the i2c-dev module along with the correct i2c driver for your motherboard. This is usually i2c-piix4 for AMD systems and i2c-i801 for Intel systems.</p><p>See <a href='https://help.openrgb.org/'>help.openrgb.org</a> for additional troubleshooting steps if you keep seeing this message.<br></p><h3>If you are not using internal RGB on a desktop this message is not important to you.</h3> - + <h2>WARNING:</h2><p>The OpenRGB udev rules are not installed.</p><p>Most devices will not be available unless running OpenRGB as root.</p><p>If using AppImage, Flatpak, or self-compiled versions of OpenRGB you must install the udev rules manually</p><p>See <a href='https://openrgb.org/udev'>https://openrgb.org/udev</a> to install the udev rules manually</p> - + <h2>WARNING:</h2><p>Multiple OpenRGB udev rules are installed.</p><p>The udev rules file 60-openrgb.rules is installed in both /etc/udev/rules.d and /usr/lib/udev/rules.d.</p><p>Multiple udev rules files can conflict, it is recommended to remove one of them.</p> - + SerialSettingsEntry Serial Device - + Baud: - + Name: - + Number of LEDs: - + Port: - + Protocol: - + TabLabel device name - + YeelightSettingsEntry Yeelight Device - + IP: - + ? - + Music Mode: - + Override host IP: - + Left blank for auto discovering host ip - + Choose an IP... - + Choose the correct IP for the host - + diff --git a/qt/i18n/OpenRGB_es_ES.ts b/qt/i18n/OpenRGB_es_ES.ts index 75fb7e39e..fee115b30 100644 --- a/qt/i18n/OpenRGB_es_ES.ts +++ b/qt/i18n/OpenRGB_es_ES.ts @@ -1132,7 +1132,7 @@ - OpenRGBSettingsPage + Settings Load Window Geometry Cargar forma de la ventana @@ -1166,7 +1166,7 @@ Minimizar al salir - Save Geometry on Close + Save on Exit Guardar la forma de la ventana al cerrar @@ -1182,12 +1182,8 @@ Configurar puerto de red - Theme (restart required) - Tema de colores (requiere reiniciar) - - - Enable Log Console (restart required) - Activar la consola de registros (requiere reiniciar) + Enable Log Console + Activar la consola de registros Custom Arguments @@ -1214,7 +1210,7 @@ Adjustes de controladores - Greyscale Tray Icon + Monochrome Tray Icon Escala de grises icono de plato @@ -1238,7 +1234,7 @@ Idioma - Disable Key Expansion in Device View + Disable Key Expansion inutillizar la llave de Expansion en vista de depositivo @@ -1258,8 +1254,8 @@ Establecer perfil en resumen - Enable Log File (restart required) - Establecer archivo de registro (requiere reiniciar) + Enable Log File + Establecer archivo de registro A problem occurred enabling Start at Login. diff --git a/qt/i18n/OpenRGB_fr_FR.ts b/qt/i18n/OpenRGB_fr_FR.ts index d4a31f160..bee1826bc 100644 --- a/qt/i18n/OpenRGB_fr_FR.ts +++ b/qt/i18n/OpenRGB_fr_FR.ts @@ -1126,7 +1126,7 @@ - OpenRGBSettingsPage + Settings Load Window Geometry Charger la géométrie de la fenêtre @@ -1160,7 +1160,7 @@ Minimiser lors de la fermeture - Save Geometry on Close + Save on Exit Sauvegarder la géométrie de la fenêtre lors de la fermeture @@ -1176,12 +1176,8 @@ Définir le port du serveur - Theme (restart required) - Thème (nécessite un redémarrage) - - - Enable Log Console (restart required) - Activer la console de logs (nécessite un redémarrage) + Enable Log Console + Activer la console de logs Custom Arguments @@ -1208,7 +1204,7 @@ Paramètre de pilotes - Greyscale Tray Icon + Monochrome Tray Icon Icône de la barre des tâches grise @@ -1232,7 +1228,7 @@ Langue - Disable Key Expansion in Device View + Disable Key Expansion Désactiver le remplissage des touches du clavier dans la vue périphériques @@ -1252,7 +1248,7 @@ Définir le profil en sortie de veille - Enable Log File (restart required) + Enable Log File Activer la console des journaux @@ -1905,7 +1901,7 @@ - Ui::OpenRGBSettingsPage + Ui::Settings A problem occurred enabling Start at Login. Un problème est survenu pour l'activation du démarrage à la connexion. diff --git a/qt/i18n/OpenRGB_hr_HR.ts b/qt/i18n/OpenRGB_hr_HR.ts index a64d6435f..82e9732b5 100644 --- a/qt/i18n/OpenRGB_hr_HR.ts +++ b/qt/i18n/OpenRGB_hr_HR.ts @@ -1132,7 +1132,7 @@ - OpenRGBSettingsPage + Settings Load Window Geometry Učitaj geometriju prozora @@ -1166,7 +1166,7 @@ Smanji u ikonu sustava pri zatvaranju - Save Geometry on Close + Save on Exit Spremi geometriju pri zatvaranju @@ -1182,12 +1182,8 @@ Postavi ulaz poslužitelja - Theme (restart required) - Tema (potrebno je ponovno pokretanje) - - - Enable Log Console (restart required) - Omogući konzolu zapisa (potrebno je ponovno pokretanje) + Enable Log Console + Omogući konzolu zapisa Custom Arguments @@ -1214,7 +1210,7 @@ Postavke upravljačkih programa - Greyscale Tray Icon + Monochrome Tray Icon Siva ikona sustava @@ -1238,7 +1234,7 @@ Jezik - Disable Key Expansion in Device View + Disable Key Expansion @@ -1258,7 +1254,7 @@ - Enable Log File (restart required) + Enable Log File diff --git a/qt/i18n/OpenRGB_it_IT.ts b/qt/i18n/OpenRGB_it_IT.ts index 4935bbe68..340d5f28d 100644 --- a/qt/i18n/OpenRGB_it_IT.ts +++ b/qt/i18n/OpenRGB_it_IT.ts @@ -1130,7 +1130,7 @@ - OpenRGBSettingsPage + Settings Load Window Geometry Carica Geometria Finestra @@ -1164,7 +1164,7 @@ Riduci a Icona alla Chiusura - Save Geometry on Close + Save on Exit Salva Geometria Alla Chiusura @@ -1180,12 +1180,8 @@ Imposta Porta Server - Theme (restart required) - Tema (riavvio richiesto) - - - Enable Log Console (restart required) - Attiva Console Registri (riavvio richiesto) + Enable Log Console + Attiva Console Registri Custom Arguments @@ -1212,7 +1208,7 @@ Impostazioni Driver - Greyscale Tray Icon + Monochrome Tray Icon Icona in Scala di Grigi nell'Area di Notifica @@ -1236,7 +1232,7 @@ Lingua - Disable Key Expansion in Device View + Disable Key Expansion Disabilita espansione chiavi in visuale dispositivi @@ -1256,8 +1252,8 @@ Imposta Profilo alla Ripresa - Enable Log File (restart required) - Abilita File di Registro (riavvio richiesto) + Enable Log File + Abilita File di Registro A problem occurred enabling Start at Login. diff --git a/qt/i18n/OpenRGB_ja_JP.ts b/qt/i18n/OpenRGB_ja_JP.ts index cbb58a988..0793fa19e 100644 --- a/qt/i18n/OpenRGB_ja_JP.ts +++ b/qt/i18n/OpenRGB_ja_JP.ts @@ -1130,7 +1130,7 @@ - OpenRGBSettingsPage + Settings Load Window Geometry ウィンドウジオメトリをロード @@ -1140,7 +1140,7 @@ 閉じる時は最小化させる - Save Geometry on Close + Save on Exit ウィンドウジオメトリを閉じるときに保存 @@ -1152,8 +1152,8 @@ サーバースタート - Enable Log Console (restart required) - ログコンソールを有効にする(再起動が必要) + Enable Log Console + ログコンソールを有効にする Custom Arguments @@ -1171,10 +1171,6 @@ Log Manager Settings: ログマネージャ設定: - - Theme (restart required) - テーマ(再起動が必要) - Start at Login Status Start at Login Status @@ -1228,7 +1224,7 @@ AMD SMBus: CPU使用率低減 (再起動が必要) - Greyscale Tray Icon + Monochrome Tray Icon トレイアイコンをグレースケールで表示させる @@ -1236,7 +1232,7 @@ 設定フォルダを開く - Disable Key Expansion in Device View + Disable Key Expansion デバイスビューでキー拡張を無効にする @@ -1256,8 +1252,8 @@ 復帰時にプロファイルをセット - Enable Log File (restart required) - ログファイルを有効にする(再起動が必要) + Enable Log File + ログファイルを有効にする English - US diff --git a/qt/i18n/OpenRGB_ko_KR.ts b/qt/i18n/OpenRGB_ko_KR.ts index 4663190a3..baf333b5a 100644 --- a/qt/i18n/OpenRGB_ko_KR.ts +++ b/qt/i18n/OpenRGB_ko_KR.ts @@ -1130,7 +1130,7 @@ - OpenRGBSettingsPage + Settings Load Window Geometry 윈도우 지오메트리 불러오기 @@ -1164,7 +1164,7 @@ 종료되지 않고 최소화 - Save Geometry on Close + Save on Exit 닫을 때 지오메트리 저장 @@ -1180,12 +1180,8 @@ 서버 포트 설정 - Theme (restart required) - 테마 (재시작 필요) - - - Enable Log Console (restart required) - 콘솔 로그 활성화 (재시작 필요) + Enable Log Console + 콘솔 로그 활성화 Custom Arguments @@ -1212,7 +1208,7 @@ 드라이버 설정 - Greyscale Tray Icon + Monochrome Tray Icon 흑백 트레이 아이콘 @@ -1236,7 +1232,7 @@ 언어 (Language) - Disable Key Expansion in Device View + Disable Key Expansion 장치 화면에서 키 확장 비활성화 @@ -1256,7 +1252,7 @@ - Enable Log File (restart required) + Enable Log File diff --git a/qt/i18n/OpenRGB_ms_MY.ts b/qt/i18n/OpenRGB_ms_MY.ts index 504c5682f..d355cf69c 100644 --- a/qt/i18n/OpenRGB_ms_MY.ts +++ b/qt/i18n/OpenRGB_ms_MY.ts @@ -1130,7 +1130,7 @@ - OpenRGBSettingsPage + Settings Open Settings Folder Buka Folder Seting @@ -1144,8 +1144,8 @@ Seting Antara Muka Pengguna: - Enable Log Console (restart required) - Dayakan Log Konsol (Restart diperlukan) + Enable Log Console + Dayakan Log Konsol Start Server @@ -1159,16 +1159,12 @@ Start at Login Settings: Seting Mulakan Pada Log Masuk: - - Theme (restart required) - Tema (Restart diperlukan) - Drivers Settings Seting Pemacu - Save Geometry on Close + Save on Exit Simpan Geometri Pada Tutup @@ -1180,7 +1176,7 @@ Muat Profil - Greyscale Tray Icon + Monochrome Tray Icon Ikon Dulang Skala Kelabu @@ -1236,7 +1232,7 @@ Bahasa - Disable Key Expansion in Device View + Disable Key Expansion @@ -1256,7 +1252,7 @@ - Enable Log File (restart required) + Enable Log File diff --git a/qt/i18n/OpenRGB_nb_NO.ts b/qt/i18n/OpenRGB_nb_NO.ts index 190bb6f7a..9383f3294 100644 --- a/qt/i18n/OpenRGB_nb_NO.ts +++ b/qt/i18n/OpenRGB_nb_NO.ts @@ -1130,7 +1130,7 @@ - OpenRGBSettingsPage + Settings Load Window Geometry Bruk vindugeometri @@ -1144,7 +1144,7 @@ Kjør sonekontroll ved skanning - Disable Key Expansion in Device View + Disable Key Expansion Deaktiver nøkkelutvidelse i enhetsvisning @@ -1164,7 +1164,7 @@ Start minimert - Greyscale Tray Icon + Monochrome Tray Icon Grått icon @@ -1184,15 +1184,15 @@ Sett profil ved lukking - Enable Log File (restart required) - Aktiver loggfil (Omstart kreves) + Enable Log File + Aktiver loggfil Minimize on Close Minimer ved lukking - Save Geometry on Close + Save on Exit Lagre geometri ved lukking @@ -1208,12 +1208,8 @@ Sett server port - Theme (restart required) - Tema (omstart kreves) - - - Enable Log Console (restart required) - Aktiver loggkonsoll (omstart kreves) + Enable Log Console + Aktiver loggkonsoll Drivers Settings diff --git a/qt/i18n/OpenRGB_pl_PL.ts b/qt/i18n/OpenRGB_pl_PL.ts index 6300986e3..6d85e8f9b 100644 --- a/qt/i18n/OpenRGB_pl_PL.ts +++ b/qt/i18n/OpenRGB_pl_PL.ts @@ -1130,7 +1130,7 @@ - OpenRGBSettingsPage + Settings Load Window Geometry Wczytaj pozycję okna @@ -1164,7 +1164,7 @@ Zminimalizuj przy wyjściu - Save Geometry on Close + Save on Exit Zapisz pozycję przy wyjściu @@ -1180,12 +1180,8 @@ Ustaw port serwera - Theme (restart required) - Temat (wymagany restart) - - - Enable Log Console (restart required) - Włączenie Konsoli LOGów (wymagany restart) + Enable Log Console + Włączenie Konsoli LOGów Custom Arguments @@ -1212,7 +1208,7 @@ Ustawienia sterowników - Greyscale Tray Icon + Monochrome Tray Icon Szara ikona w tray'u @@ -1236,7 +1232,7 @@ Język - Disable Key Expansion in Device View + Disable Key Expansion @@ -1256,7 +1252,7 @@ - Enable Log File (restart required) + Enable Log File diff --git a/qt/i18n/OpenRGB_pt_BR.ts b/qt/i18n/OpenRGB_pt_BR.ts index ffbdf0c12..bc27c5480 100644 --- a/qt/i18n/OpenRGB_pt_BR.ts +++ b/qt/i18n/OpenRGB_pt_BR.ts @@ -1130,7 +1130,7 @@ - OpenRGBSettingsPage + Settings Load Window Geometry Carregar geometria da janela @@ -1164,7 +1164,7 @@ Minimizar ao fechar - Save Geometry on Close + Save on Exit Salvar a geometria ao fechar @@ -1180,12 +1180,8 @@ Definir porta do servidor - Theme (restart required) - Tema (reinício necessário) - - - Enable Log Console (restart required) - Ativar o console de registros (reinício necessário) + Enable Log Console + Ativar o console de registros Custom Arguments @@ -1212,7 +1208,7 @@ Configurações de drivers - Greyscale Tray Icon + Monochrome Tray Icon Ícone da bandeja cinza @@ -1236,7 +1232,7 @@ Idioma - Disable Key Expansion in Device View + Disable Key Expansion Desativar expensão de chave na visualização de dispositivos @@ -1256,8 +1252,8 @@ Definir perfil ao retomar - Enable Log File (restart required) - Ativar arquivo de registros (reinício necessário) + Enable Log File + Ativar arquivo de registros A problem occurred enabling Start at Login. diff --git a/qt/i18n/OpenRGB_ru_RU.ts b/qt/i18n/OpenRGB_ru_RU.ts index 6b9e1fec2..c619bb9b6 100644 --- a/qt/i18n/OpenRGB_ru_RU.ts +++ b/qt/i18n/OpenRGB_ru_RU.ts @@ -880,7 +880,7 @@ - OpenRGBSettingsPage + Settings Load Window Geometry Загружать геометрию окна @@ -918,15 +918,15 @@ Запускать при входе в систему - Enable Log File (restart required) - Включить ведение лога (потребуется перезапуск) + Enable Log File + Включить ведение лога Minimize on Close Сворачивать вместо закрытия - Save Geometry on Close + Save on Exit Сохранять размеры окна при закрытии @@ -942,12 +942,8 @@ Задать порт для сервера - Theme (restart required) - Тема (потребуется перезапуск) - - - Enable Log Console (restart required) - Включить консоль журналирования (потребуется перезапуск) + Enable Log Console + Включить консоль журналирования Custom Arguments @@ -974,7 +970,7 @@ Параметры драйверов - Greyscale Tray Icon + Monochrome Tray Icon Отображение значка в системном лотке в оттенках серого @@ -982,7 +978,7 @@ AMD SMBus: уменьшить загрузку ЦП (потребуется перезапуск) - Disable Key Expansion in Device View + Disable Key Expansion Отключить расширение клавиш в LED View diff --git a/qt/i18n/OpenRGB_tr_TR.ts b/qt/i18n/OpenRGB_tr_TR.ts index b38e98e09..7224a8138 100644 --- a/qt/i18n/OpenRGB_tr_TR.ts +++ b/qt/i18n/OpenRGB_tr_TR.ts @@ -879,7 +879,7 @@ - OpenRGBSettingsPage + Settings Load Window Geometry Pencere Geometrisini Yükle @@ -909,7 +909,7 @@ Kapatıldığında Simge Durumuna Küçült - Save Geometry on Close + Save on Exit Kapatırken Geometriyi Kaydet @@ -925,12 +925,8 @@ Sunucu Bağlantı Noktasını Ayarla - Theme (restart required) - Tema (yeniden başlatma gerekli) - - - Enable Log Console (restart required) - Kayıt Konsolunu Etkinleştir (yeniden başlatma gerekli) + Enable Log Console + Kayıt Konsolunu Etkinleştir Custom Arguments @@ -957,7 +953,7 @@ Sürücü Ayarları - Greyscale Tray Icon + Monochrome Tray Icon Gri Tonlu Sistem Tepsisi Simgesi @@ -981,7 +977,7 @@ Dil - Disable Key Expansion in Device View + Disable Key Expansion Cihaz Görünümünde Tuş Genişletmeyi Devre Dışı Bırak @@ -1001,8 +997,8 @@ Devam edildiğinde profil ayarla - Enable Log File (restart required) - Kayıt dosyasını etkinleştir (yeniden başlatma gerekli) + Enable Log File + Kayıt dosyasını etkinleştir A problem occurred enabling Start at Login. diff --git a/qt/i18n/OpenRGB_uk_UA.ts b/qt/i18n/OpenRGB_uk_UA.ts index e0a208971..493701bd6 100644 --- a/qt/i18n/OpenRGB_uk_UA.ts +++ b/qt/i18n/OpenRGB_uk_UA.ts @@ -1130,7 +1130,7 @@ - OpenRGBSettingsPage + Settings Load Window Geometry Завантажувати геометрію вікна @@ -1172,15 +1172,15 @@ Запускати при вході в систему - Enable Log File (restart required) - Увімкнути логування (потрібен перезапуск) + Enable Log File + Увімкнути логування Minimize on Close Згортати замість закриття - Save Geometry on Close + Save on Exit Зберігати розміри вікна при закритті @@ -1196,12 +1196,8 @@ Встановити порт для сервера - Theme (restart required) - Тема (потрібен перезапуск) - - - Enable Log Console (restart required) - Увімкнути консоль логів (потрібен перезапуск) + Enable Log Console + Увімкнути консоль логів Custom Arguments @@ -1228,7 +1224,7 @@ Налаштування драйверів - Greyscale Tray Icon + Monochrome Tray Icon Відображення значка у системному лотку в відтінках сірого @@ -1236,7 +1232,7 @@ AMD SMBus: зменшити навантаження на ЦП (потрібен перезапуск) - Disable Key Expansion in Device View + Disable Key Expansion Відключити розширення клавіш у перегляді пристроїв diff --git a/qt/i18n/OpenRGB_zh_CN.ts b/qt/i18n/OpenRGB_zh_CN.ts index f557f42a9..cde260859 100644 --- a/qt/i18n/OpenRGB_zh_CN.ts +++ b/qt/i18n/OpenRGB_zh_CN.ts @@ -1130,7 +1130,7 @@ - OpenRGBSettingsPage + Settings Minimize on Close 关闭窗口时最小化 @@ -1144,7 +1144,7 @@ 启动服务器 - Enable Log Console (restart required) + Enable Log Console 启用日志控制台(需要重新启动) @@ -1152,7 +1152,7 @@ 自定义参数 - Save Geometry on Close + Save on Exit 关闭时保存窗口大小及位置 @@ -1171,10 +1171,6 @@ Log Manager Settings: 日志管理器设置: - - Theme (restart required) - 主题(需要重新启动) - Start at Login Status 登录启动状态 @@ -1228,7 +1224,7 @@ AMD SMBus:降低 CPU 使用率(需要重新启动) - Greyscale Tray Icon + Monochrome Tray Icon 灰度托盘图标 @@ -1236,7 +1232,7 @@ 打开设置文件夹 - Disable Key Expansion in Device View + Disable Key Expansion 在设备视图中禁用快捷键扩展 @@ -1256,7 +1252,7 @@ 唤醒时设置配置文件 - Enable Log File (restart required) + Enable Log File 启用日志文件(需要重新启动) diff --git a/qt/i18n/OpenRGB_zh_TW.ts b/qt/i18n/OpenRGB_zh_TW.ts index 2ba62b273..d056d37fc 100644 --- a/qt/i18n/OpenRGB_zh_TW.ts +++ b/qt/i18n/OpenRGB_zh_TW.ts @@ -1130,7 +1130,7 @@ - OpenRGBSettingsPage + Settings Minimize on Close 關閉窗口時最小化 @@ -1144,7 +1144,7 @@ 啟動伺服器 - Enable Log Console (restart required) + Enable Log Console 啟用日誌控制台(需要重新啟動) @@ -1152,7 +1152,7 @@ 自訂參數 - Save Geometry on Close + Save on Exit 關閉時保存幾何圖形 @@ -1171,10 +1171,6 @@ Log Manager Settings: 日誌管理器設置: - - Theme (restart required) - 主題(需要重新啟動) - Start at Login Status 從登錄狀態開始 @@ -1228,7 +1224,7 @@ AMD SMBus:降低 CPU 使用率(需要重新啟動) - Greyscale Tray Icon + Monochrome Tray Icon 灰度托盤圖示 @@ -1236,7 +1232,7 @@ 打開設置文件夾 - Disable Key Expansion in Device View + Disable Key Expansion @@ -1256,7 +1252,7 @@ - Enable Log File (restart required) + Enable Log File diff --git a/qt/resources.qrc b/qt/resources.qrc index d3363808c..a697ccdae 100644 --- a/qt/resources.qrc +++ b/qt/resources.qrc @@ -2,6 +2,6 @@ org.openrgb.OpenRGB.png fonts/OpenRGB.ttf - OpenRGBGreyscale.png + OpenRGBMonochrome.png