From c0826fbe833f45689ecaa0580a5b9c017cc9bd2d 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 | 1 - JsonUtils.cpp | 71 + JsonUtils.h | 22 + LogManager.cpp | 45 +- NetworkClient.cpp | 52 + NetworkClient.h | 4 + NetworkProtocol.h | 8 + NetworkServer.cpp | 137 +- NetworkServer.h | 3 + OpenRGB.pro | 10 +- ProfileManager.cpp | 113 +- ProfileManager.h | 20 +- RGBController/RGBController.cpp | 311 +++- RGBController/RGBController.h | 66 +- RGBController/RGBController_Network.cpp | 55 + RGBController/RGBController_Network.h | 10 +- ResourceManager.cpp | 63 +- SettingsManager.cpp | 160 ++- SettingsManager.h | 85 +- 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 | 442 ++++-- qt/OpenRGBDialog/OpenRGBDialog.h | 11 +- .../OpenRGBDynamicSettingsWidget.cpp | 479 +++++++ .../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 +- 72 files changed, 3305 insertions(+), 3024 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..b15eb2479 100644 --- a/Documentation/OpenRGBSDK.md +++ b/Documentation/OpenRGBSDK.md @@ -206,7 +206,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 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..96ed75616 100644 --- a/NetworkClient.cpp +++ b/NetworkClient.cpp @@ -494,6 +494,32 @@ 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_SaveSettings() { NetPacketHeader request_hdr; @@ -718,6 +744,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 +1542,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..a1570bbda 100644 --- a/NetworkClient.h +++ b/NetworkClient.h @@ -109,6 +109,7 @@ public: | SettingsManager functions | \*-----------------------------------------------------*/ std::string SettingsManager_GetSettings(std::string settings_key); + std::string SettingsManager_GetSettingsSchema(std::string settings_key); void SettingsManager_SaveSettings(); void SettingsManager_SetSettings(std::string settings_json_str); @@ -132,6 +133,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..bb225960c 100644 --- a/NetworkProtocol.h +++ b/NetworkProtocol.h @@ -149,6 +149,8 @@ enum 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 + = 253, /* Get settings schema for given key in JSON format */ /*----------------------------------------------------------------------------------------------------------*\ | RGBController functions | @@ -167,6 +169,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..48bb8390a 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,10 @@ 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_SET_SETTINGS: status = ProcessRequest_SettingsManager_SetSettings(client_info, header.pkt_size, data); break; @@ -1424,6 +1429,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 +1761,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 +1808,37 @@ 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_SetSettings(NetworkClientInfo* client_info, unsigned int data_size, char* data) { if(data == NULL) @@ -1880,9 +1925,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 +1960,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 +2010,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 +2052,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 +2083,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 +3183,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..4d0b4d483 100644 --- a/NetworkServer.h +++ b/NetworkServer.h @@ -238,6 +238,7 @@ 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_SetSettings(NetworkClientInfo* client_info, unsigned int data_size, char* data); NetPacketStatus ProcessRequest_SettingsManager_SaveSettings(NetworkClientInfo* client_info); @@ -246,6 +247,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/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..d31e5728e 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); @@ -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..fc13d41c5 100644 --- a/ResourceManager.cpp +++ b/ResourceManager.cpp @@ -144,10 +144,71 @@ 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["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..880e02afe 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,77 @@ 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_SetSettings(settings_json.dump()); + } + else + { + mutex.lock(); + settings_data[settings_key].update(new_settings, true); + mutex.unlock(); + } + + SignalSettingsManagerUpdate(SETTINGSMANAGER_UPDATE_REASON_SETTINGS_UPDATED); +} + void SettingsManager::SetSettings(std::string settings_key, json new_settings) { bool ui_settings_key = false; @@ -119,6 +188,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 +197,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 +286,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..469e038ea 100644 --- a/SettingsManager.h +++ b/SettingsManager.h @@ -17,17 +17,36 @@ #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 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 +58,51 @@ 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 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..4eb9cae40 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,44 @@ void OpenRGBDialog::SetDialogMessage(PLogMessage msg) dialog_message = QString::fromStdString(msg->buffer); } +void OpenRGBDialog::SetLanguage(std::string language) +{ + QApplication* app = static_cast(QApplication::instance()); + QMap language_map; + QDirIterator language_files(":/i18n/", QDirIterator::Subdirectories); + bool loaded = false; + + while(language_files.hasNext()) + { + if(translator.load(language_files.next())) + { + language_map.insert(translator.translate("Settings", "English - US"), language_files.filePath()); + } + } + + QString language_file = language_map[QString::fromStdString(language)]; + + app->removeTranslator(&translator); + + if(language == "System Default") + { + QLocale locale = QLocale(QLocale::system()); + QLocale::setDefault(locale); + + loaded = translator.load(":/i18n/" + QString("OpenRGB_%1.qm").arg(locale.name())); + } + else + { + loaded = translator.load(language_file); + } + + if(loaded) + { + app->installTranslator(&translator); + LOG_DEBUG("[OpenRGBDialog] Changed Language to %s from the %s file\n", language.c_str(), language_file.toStdString().c_str()); + } +} + void OpenRGBDialog::UpdateActiveProfile() { ProfileManager* profile_manager = ResourceManager::get()->GetProfileManager(); @@ -1414,6 +1461,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 +1898,7 @@ void OpenRGBDialog::SetTrayIcon(bool tray_icon) { if(tray_icon) { - trayIcon->setIcon(QIcon(":OpenRGBGreyscale.png")); + trayIcon->setIcon(QIcon(":OpenRGBMonochrome.png")); } else { @@ -1880,14 +2040,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..4fa8d11a4 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 language); 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..3d388f574 --- /dev/null +++ b/qt/OpenRGBDynamicSettingsWidget/OpenRGBDynamicSettingsWidget.cpp @@ -0,0 +1,479 @@ + +#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); + } + + ((QComboBox*)right_widget)->setCurrentText(QString::number(value)); + + 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())) + { + language_map.insert(translator.translate("Settings", "English - US"), file.filePath()); + } + } + + ((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()); + } + + ((QComboBox*)right_widget)->setCurrentText(QString::fromStdString(value)); + + 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)->currentText().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