diff options
author | Garrett Brown <themagnificentmrb@gmail.com> | 2023-02-22 22:29:07 -0800 |
---|---|---|
committer | Garrett Brown <themagnificentmrb@gmail.com> | 2023-03-02 17:46:04 -0800 |
commit | 0b4ec3a278baa875ab1eff6200ffc3c8c6a1e3f5 (patch) | |
tree | b48209a2b7f41fa842e9b9c637cbbaf8ce43f29b | |
parent | d61b2cfed0e7dfcfd142628932956caa332baaa4 (diff) |
Peripherals: Allow changing joystick appearance
-rw-r--r-- | addons/resource.language.en_gb/resources/strings.po | 1 | ||||
-rw-r--r-- | system/peripherals.xml | 5 | ||||
-rw-r--r-- | xbmc/input/joysticks/interfaces/IButtonMap.h | 18 | ||||
-rw-r--r-- | xbmc/peripherals/Peripherals.cpp | 10 | ||||
-rw-r--r-- | xbmc/peripherals/Peripherals.h | 6 | ||||
-rw-r--r-- | xbmc/peripherals/addons/AddonButtonMap.cpp | 14 | ||||
-rw-r--r-- | xbmc/peripherals/addons/AddonButtonMap.h | 12 | ||||
-rw-r--r-- | xbmc/peripherals/devices/Peripheral.cpp | 20 | ||||
-rw-r--r-- | xbmc/peripherals/devices/Peripheral.h | 12 | ||||
-rw-r--r-- | xbmc/peripherals/devices/PeripheralJoystick.cpp | 126 | ||||
-rw-r--r-- | xbmc/peripherals/devices/PeripheralJoystick.h | 12 | ||||
-rw-r--r-- | xbmc/peripherals/devices/PeripheralKeyboard.cpp | 3 | ||||
-rw-r--r-- | xbmc/peripherals/devices/PeripheralMouse.cpp | 3 | ||||
-rw-r--r-- | xbmc/peripherals/dialogs/GUIDialogPeripheralSettings.cpp | 84 | ||||
-rw-r--r-- | xbmc/peripherals/dialogs/GUIDialogPeripheralSettings.h | 7 | ||||
-rw-r--r-- | xbmc/peripherals/dialogs/GUIDialogPeripherals.cpp | 2 |
16 files changed, 318 insertions, 17 deletions
diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po index b4bf45268d..b82716caf5 100644 --- a/addons/resource.language.en_gb/resources/strings.po +++ b/addons/resource.language.en_gb/resources/strings.po @@ -2264,6 +2264,7 @@ msgctxt "#479" msgid "Skin & language" msgstr "" +#: system/peripherals.xml #: system/settings/settings.xml #: addons/skin.estuary/xml/Includes.xml msgctxt "#480" diff --git a/system/peripherals.xml b/system/peripherals.xml index c91d977a8b..a110c0db60 100644 --- a/system/peripherals.xml +++ b/system/peripherals.xml @@ -58,8 +58,9 @@ </peripheral> <peripheral class="joystick" name="joystick" mapTo="joystick"> - <setting key="left_stick_deadzone" type="float" label="35078" order="1" value="0.2" min="0.0" step="0.05" max="1.0" /> - <setting key="right_stick_deadzone" type="float" label="35079" order="2" value="0.2" min="0.0" step="0.05" max="1.0" /> + <setting key="appearance" type="addon" addontype="kodi.game.controller" label="480" order="1"/> + <setting key="left_stick_deadzone" type="float" label="35078" order="2" value="0.2" min="0.0" step="0.05" max="1.0" /> + <setting key="right_stick_deadzone" type="float" label="35079" order="3" value="0.2" min="0.0" step="0.05" max="1.0" /> </peripheral> </peripherals> diff --git a/xbmc/input/joysticks/interfaces/IButtonMap.h b/xbmc/input/joysticks/interfaces/IButtonMap.h index caa547c38b..0b4b7d507b 100644 --- a/xbmc/input/joysticks/interfaces/IButtonMap.h +++ b/xbmc/input/joysticks/interfaces/IButtonMap.h @@ -67,6 +67,24 @@ public: virtual bool IsEmpty(void) const = 0; /*! + * \brief Get the ID of the controller profile that best represents the + * appearance of the peripheral + * + * \return The controller ID, or empty if the appearance is unknown + */ + virtual std::string GetAppearance() const = 0; + + /*! + * \brief Set the ID of the controller that best represents the appearance + * of the peripheral + * + * \param controllerId The controller ID, or empty to unset the appearance + * + * \return True if the appearance was set, false on error + */ + virtual bool SetAppearance(const std::string& controllerId) const = 0; + + /*! * \brief Get the feature associated with a driver primitive * * Multiple primitives can be mapped to the same feature. For example, diff --git a/xbmc/peripherals/Peripherals.cpp b/xbmc/peripherals/Peripherals.cpp index bbef820791..3dc5ca6a9c 100644 --- a/xbmc/peripherals/Peripherals.cpp +++ b/xbmc/peripherals/Peripherals.cpp @@ -12,6 +12,7 @@ #include "EventScanner.h" #include "addons/AddonButtonMap.h" #include "addons/AddonManager.h" +#include "addons/addoninfo/AddonInfo.h" #include "addons/addoninfo/AddonType.h" #include "addons/gui/GUIDialogAddonSettings.h" #include "addons/gui/GUIWindowAddonBrowser.h" @@ -51,6 +52,7 @@ #include "messaging/ApplicationMessenger.h" #include "messaging/ThreadMessage.h" #include "peripherals/dialogs/GUIDialogPeripherals.h" +#include "settings/SettingAddon.h" #include "settings/Settings.h" #include "settings/SettingsComponent.h" #include "settings/lib/Setting.h" @@ -615,6 +617,14 @@ void CPeripherals::GetSettingsFromMappingsFile( setting = std::make_shared<CSettingInt>(strKey, iLabelId, iValue, enums); } } + else if (StringUtils::EqualsNoCase(strSettingsType, "addon")) + { + std::string addonFilter = XMLUtils::GetAttribute(currentNode, "addontype"); + ADDON::AddonType addonType = ADDON::CAddonInfo::TranslateType(addonFilter); + std::string strValue = XMLUtils::GetAttribute(currentNode, "value"); + setting = std::make_shared<CSettingAddon>(strKey, iLabelId, strValue); + static_cast<CSettingAddon&>(*setting).SetAddonType(addonType); + } else { std::string strValue = XMLUtils::GetAttribute(currentNode, "value"); diff --git a/xbmc/peripherals/Peripherals.h b/xbmc/peripherals/Peripherals.h index 9c07a8d1fa..d9931d7699 100644 --- a/xbmc/peripherals/Peripherals.h +++ b/xbmc/peripherals/Peripherals.h @@ -341,6 +341,11 @@ public: */ KODI::GAME::CControllerManager& GetControllerProfiles() { return m_controllerProfiles; } + /*! + * \brief Get a mutex that allows for add-on install tasks to block on each other + */ + CCriticalSection& GetAddonInstallMutex() { return m_addonInstallMutex; } + private: bool LoadMappings(); bool GetMappingForDevice(const CPeripheralBus& bus, PeripheralScanResult& result) const; @@ -361,5 +366,6 @@ private: std::unique_ptr<CEventScanner> m_eventScanner; mutable CCriticalSection m_critSectionBusses; mutable CCriticalSection m_critSectionMappings; + CCriticalSection m_addonInstallMutex; }; } // namespace PERIPHERALS diff --git a/xbmc/peripherals/addons/AddonButtonMap.cpp b/xbmc/peripherals/addons/AddonButtonMap.cpp index 3f5fed7db7..f2c894ca4d 100644 --- a/xbmc/peripherals/addons/AddonButtonMap.cpp +++ b/xbmc/peripherals/addons/AddonButtonMap.cpp @@ -46,6 +46,7 @@ std::string CAddonButtonMap::Location(void) const bool CAddonButtonMap::Load(void) { + std::string controllerAppearance; FeatureMap features; DriverMap driverMap; PrimitiveVector ignoredPrimitives; @@ -70,6 +71,7 @@ bool CAddonButtonMap::Load(void) { std::unique_lock<CCriticalSection> lock(m_mutex); + m_controllerAppearance = std::move(controllerAppearance); m_features = std::move(features); m_driverMap = std::move(driverMap); m_ignoredPrimitives = CPeripheralAddonTranslator::TranslatePrimitives(ignoredPrimitives); @@ -91,6 +93,18 @@ bool CAddonButtonMap::IsEmpty(void) const return m_driverMap.empty(); } +std::string CAddonButtonMap::GetAppearance() const +{ + std::unique_lock<CCriticalSection> lock(m_mutex); + + return m_controllerAppearance; +} + +bool CAddonButtonMap::SetAppearance(const std::string& controllerId) const +{ + return false; +} + bool CAddonButtonMap::GetFeature(const CDriverPrimitive& primitive, FeatureName& feature) { std::unique_lock<CCriticalSection> lock(m_mutex); diff --git a/xbmc/peripherals/addons/AddonButtonMap.h b/xbmc/peripherals/addons/AddonButtonMap.h index 44b574d0a8..b6a629fef5 100644 --- a/xbmc/peripherals/addons/AddonButtonMap.h +++ b/xbmc/peripherals/addons/AddonButtonMap.h @@ -39,6 +39,10 @@ public: bool IsEmpty(void) const override; + std::string GetAppearance() const override; + + bool SetAppearance(const std::string& controllerId) const override; + bool GetFeature(const KODI::JOYSTICK::CDriverPrimitive& primitive, KODI::JOYSTICK::FeatureName& feature) override; @@ -122,12 +126,18 @@ private: static JOYSTICK_FEATURE_PRIMITIVE GetPrimitiveIndex(KODI::JOYSTICK::WHEEL_DIRECTION dir); static JOYSTICK_FEATURE_PRIMITIVE GetPrimitiveIndex(KODI::JOYSTICK::THROTTLE_DIRECTION dir); + // Construction parameters CPeripheral* const m_device; - std::weak_ptr<CPeripheralAddon> m_addon; + const std::weak_ptr<CPeripheralAddon> m_addon; const std::string m_strControllerId; + + // Button map state + std::string m_controllerAppearance; FeatureMap m_features; DriverMap m_driverMap; JoystickPrimitiveVector m_ignoredPrimitives; + + // Synchronization parameters mutable CCriticalSection m_mutex; }; } // namespace PERIPHERALS diff --git a/xbmc/peripherals/devices/Peripheral.cpp b/xbmc/peripherals/devices/Peripheral.cpp index 103d88dcdc..2c656a392b 100644 --- a/xbmc/peripherals/devices/Peripheral.cpp +++ b/xbmc/peripherals/devices/Peripheral.cpp @@ -20,6 +20,7 @@ #include "peripherals/addons/PeripheralAddon.h" #include "peripherals/bus/PeripheralBus.h" #include "peripherals/bus/virtual/PeripheralBusAddon.h" +#include "settings/SettingAddon.h" #include "settings/lib/Setting.h" #include "utils/FileUtils.h" #include "utils/StringUtils.h" @@ -269,12 +270,21 @@ void CPeripheral::AddSetting(const std::string& strKey, const SettingConstPtr& s break; case SettingType::String: { - std::shared_ptr<const CSettingString> mappedSetting = - std::static_pointer_cast<const CSettingString>(setting); - std::shared_ptr<CSettingString> stringSetting = - std::make_shared<CSettingString>(strKey, *mappedSetting); - if (stringSetting) + if (std::dynamic_pointer_cast<const CSettingAddon>(setting)) + { + std::shared_ptr<const CSettingAddon> mappedSetting = + std::static_pointer_cast<const CSettingAddon>(setting); + std::shared_ptr<CSettingAddon> addonSetting = + std::make_shared<CSettingAddon>(strKey, *mappedSetting); + addonSetting->SetVisible(mappedSetting->IsVisible()); + deviceSetting.m_setting = addonSetting; + } + else { + std::shared_ptr<const CSettingString> mappedSetting = + std::static_pointer_cast<const CSettingString>(setting); + std::shared_ptr<CSettingString> stringSetting = + std::make_shared<CSettingString>(strKey, *mappedSetting); stringSetting->SetVisible(mappedSetting->IsVisible()); deviceSetting.m_setting = stringSetting; } diff --git a/xbmc/peripherals/devices/Peripheral.h b/xbmc/peripherals/devices/Peripheral.h index 053898a7ae..8c4049b67a 100644 --- a/xbmc/peripherals/devices/Peripheral.h +++ b/xbmc/peripherals/devices/Peripheral.h @@ -257,9 +257,16 @@ public: * * \return The controller profile, or empty if unknown */ - virtual KODI::GAME::ControllerPtr ControllerProfile() const + virtual KODI::GAME::ControllerPtr ControllerProfile() const { return m_controllerProfile; } + + /*! + * \brief Set the controller profile for this peripheral + * + * \param controller The new controller profile + */ + virtual void SetControllerProfile(const KODI::GAME::ControllerPtr& controller) { - return KODI::GAME::ControllerPtr{}; + m_controllerProfile = controller; } protected: @@ -294,5 +301,6 @@ protected: std::map<KODI::MOUSE::IMouseInputHandler*, std::unique_ptr<KODI::MOUSE::IMouseDriverHandler>> m_mouseHandlers; std::map<KODI::JOYSTICK::IButtonMapper*, std::unique_ptr<CAddonButtonMapping>> m_buttonMappers; + KODI::GAME::ControllerPtr m_controllerProfile; }; } // namespace PERIPHERALS diff --git a/xbmc/peripherals/devices/PeripheralJoystick.cpp b/xbmc/peripherals/devices/PeripheralJoystick.cpp index 2e64eb2871..e2087a7bc7 100644 --- a/xbmc/peripherals/devices/PeripheralJoystick.cpp +++ b/xbmc/peripherals/devices/PeripheralJoystick.cpp @@ -8,6 +8,9 @@ #include "PeripheralJoystick.h" +#include "ServiceBroker.h" +#include "addons/AddonInstaller.h" +#include "addons/AddonManager.h" #include "application/Application.h" #include "games/GameServices.h" #include "games/controllers/Controller.h" @@ -65,6 +68,10 @@ CPeripheralJoystick::~CPeripheralJoystick(void) m_appInput.reset(); m_deadzoneFilter.reset(); m_buttonMap.reset(); + + // Wait for remaining install tasks + for (std::future<void>& task : m_installTasks) + task.wait(); } bool CPeripheralJoystick::InitialiseFeature(const PeripheralFeature feature) @@ -95,6 +102,7 @@ bool CPeripheralJoystick::InitialiseFeature(const PeripheralFeature feature) if (m_buttonMap->Load()) { InitializeDeadzoneFiltering(*m_buttonMap); + InitializeControllerProfile(*m_buttonMap); } else { @@ -128,6 +136,54 @@ void CPeripheralJoystick::InitializeDeadzoneFiltering(IButtonMap& buttonMap) m_deadzoneFilter.reset(new CDeadzoneFilter(&buttonMap, this)); } +void CPeripheralJoystick::InitializeControllerProfile(IButtonMap& buttonMap) +{ + const std::string controllerId = buttonMap.GetAppearance(); + if (controllerId.empty()) + return; + + auto controller = m_manager.GetControllerProfiles().GetController(controllerId); + if (controller) + CPeripheral::SetControllerProfile(controller); + else + { + std::unique_lock<CCriticalSection> lock(m_controllerInstallMutex); + + // Deposit controller into queue + m_controllersToInstall.emplace(controllerId); + + // Clean up finished install tasks + m_installTasks.erase(std::remove_if(m_installTasks.begin(), m_installTasks.end(), + [](std::future<void>& task) { + return task.wait_for(std::chrono::seconds(0)) == + std::future_status::ready; + }), + m_installTasks.end()); + + // Install controller off-thread + std::future<void> installTask = std::async(std::launch::async, [this]() { + // Withdraw controller from queue + std::string controllerToInstall; + { + std::unique_lock<CCriticalSection> lock(m_controllerInstallMutex); + if (!m_controllersToInstall.empty()) + { + controllerToInstall = m_controllersToInstall.front(); + m_controllersToInstall.pop(); + } + } + + // Do the install + GAME::ControllerPtr controller = InstallAsync(controllerToInstall); + if (controller) + CPeripheral::SetControllerProfile(controller); + }); + + // Hold the task to prevent the destructor from completing during an install + m_installTasks.emplace_back(std::move(installTask)); + } +} + void CPeripheralJoystick::OnUserNotification() { IInputReceiver* inputReceiver = m_appInput->GetInputReceiver(m_rumbleGenerator->ControllerID()); @@ -192,11 +248,38 @@ IKeymap* CPeripheralJoystick::GetKeymap(const std::string& controllerId) GAME::ControllerPtr CPeripheralJoystick::ControllerProfile() const { - //! @todo Allow the user to change which controller profile represents their - // controller. For now, just use the default. + // Button map has the freshest state + if (m_buttonMap) + { + const std::string controllerId = m_buttonMap->GetAppearance(); + if (!controllerId.empty()) + { + auto controller = m_manager.GetControllerProfiles().GetController(controllerId); + if (controller) + return controller; + } + } + + // Fall back to last set controller profile + if (m_controllerProfile) + return m_controllerProfile; + + // Fall back to default controller return m_manager.GetControllerProfiles().GetDefaultController(); } +void CPeripheralJoystick::SetControllerProfile(const KODI::GAME::ControllerPtr& controller) +{ + CPeripheral::SetControllerProfile(controller); + + // Save preference to buttonmap + if (m_buttonMap) + { + if (m_buttonMap->SetAppearance(controller->ID())) + m_buttonMap->SaveButtonMap(); + } +} + bool CPeripheralJoystick::OnButtonMotion(unsigned int buttonIndex, bool bPressed) { // Silence debug log if controllers are not enabled @@ -413,3 +496,42 @@ void CPeripheralJoystick::SetSupportsPowerOff(bool bSupportsPowerOff) else if (std::find(m_features.begin(), m_features.end(), FEATURE_POWER_OFF) == m_features.end()) m_features.push_back(FEATURE_POWER_OFF); } + +GAME::ControllerPtr CPeripheralJoystick::InstallAsync(const std::string& controllerId) +{ + GAME::ControllerPtr controller; + + // Only 1 install at a time. Remaining installs will wake when this one + // is done. + std::unique_lock<CCriticalSection> lockInstall(m_manager.GetAddonInstallMutex()); + + CLog::LogF(LOGDEBUG, "Installing {}", controllerId); + + if (InstallSync(controllerId)) + controller = m_manager.GetControllerProfiles().GetController(controllerId); + else + CLog::LogF(LOGERROR, "Failed to install {}", controllerId); + + return controller; +} + +bool CPeripheralJoystick::InstallSync(const std::string& controllerId) +{ + // If the addon isn't installed we need to install it + bool installed = CServiceBroker::GetAddonMgr().IsAddonInstalled(controllerId); + if (!installed) + { + ADDON::AddonPtr installedAddon; + installed = ADDON::CAddonInstaller::GetInstance().InstallModal( + controllerId, installedAddon, ADDON::InstallModalPrompt::CHOICE_NO); + } + + if (installed) + { + // Make sure add-on is enabled + if (CServiceBroker::GetAddonMgr().IsAddonDisabled(controllerId)) + CServiceBroker::GetAddonMgr().EnableAddon(controllerId); + } + + return installed; +} diff --git a/xbmc/peripherals/devices/PeripheralJoystick.h b/xbmc/peripherals/devices/PeripheralJoystick.h index 3b19abf135..aa55ad7fd7 100644 --- a/xbmc/peripherals/devices/PeripheralJoystick.h +++ b/xbmc/peripherals/devices/PeripheralJoystick.h @@ -10,11 +10,14 @@ #include "Peripheral.h" #include "XBDateTime.h" +#include "games/controllers/ControllerTypes.h" #include "input/joysticks/JoystickTypes.h" #include "input/joysticks/interfaces/IDriverReceiver.h" #include "threads/CriticalSection.h" +#include <future> #include <memory> +#include <queue> #include <string> #include <vector> @@ -58,6 +61,7 @@ public: IKeymap* GetKeymap(const std::string& controllerId) override; CDateTime LastActive() override { return m_lastActive; } KODI::GAME::ControllerPtr ControllerProfile() const override; + void SetControllerProfile(const KODI::GAME::ControllerPtr& controller) override; bool OnButtonMotion(unsigned int buttonIndex, bool bPressed); bool OnHatMotion(unsigned int hatIndex, KODI::JOYSTICK::HAT_STATE state); @@ -105,9 +109,14 @@ public: protected: void InitializeDeadzoneFiltering(KODI::JOYSTICK::IButtonMap& buttonMap); + void InitializeControllerProfile(KODI::JOYSTICK::IButtonMap& buttonMap); void PowerOff(); + // Helper functions + KODI::GAME::ControllerPtr InstallAsync(const std::string& controllerId); + static bool InstallSync(const std::string& controllerId); + struct DriverHandler { KODI::JOYSTICK::IDriverHandler* handler; @@ -123,6 +132,8 @@ protected: unsigned int m_motorCount; bool m_supportsPowerOff; CDateTime m_lastActive; + std::queue<std::string> m_controllersToInstall; + std::vector<std::future<void>> m_installTasks; // Input clients std::unique_ptr<KODI::JOYSTICK::CKeymapHandling> m_appInput; @@ -134,5 +145,6 @@ protected: // Synchronization parameters CCriticalSection m_handlerMutex; + CCriticalSection m_controllerInstallMutex; }; } // namespace PERIPHERALS diff --git a/xbmc/peripherals/devices/PeripheralKeyboard.cpp b/xbmc/peripherals/devices/PeripheralKeyboard.cpp index 61e0355230..271d8b16c5 100644 --- a/xbmc/peripherals/devices/PeripheralKeyboard.cpp +++ b/xbmc/peripherals/devices/PeripheralKeyboard.cpp @@ -81,6 +81,9 @@ void CPeripheralKeyboard::UnregisterKeyboardDriverHandler( GAME::ControllerPtr CPeripheralKeyboard::ControllerProfile() const { + if (m_controllerProfile) + return m_controllerProfile; + return m_manager.GetControllerProfiles().GetDefaultKeyboard(); } diff --git a/xbmc/peripherals/devices/PeripheralMouse.cpp b/xbmc/peripherals/devices/PeripheralMouse.cpp index 9809616ca7..4f2623603f 100644 --- a/xbmc/peripherals/devices/PeripheralMouse.cpp +++ b/xbmc/peripherals/devices/PeripheralMouse.cpp @@ -76,6 +76,9 @@ void CPeripheralMouse::UnregisterMouseDriverHandler(MOUSE::IMouseDriverHandler* GAME::ControllerPtr CPeripheralMouse::ControllerProfile() const { + if (m_controllerProfile) + return m_controllerProfile; + return m_manager.GetControllerProfiles().GetDefaultMouse(); } diff --git a/xbmc/peripherals/dialogs/GUIDialogPeripheralSettings.cpp b/xbmc/peripherals/dialogs/GUIDialogPeripheralSettings.cpp index 83cb14475a..73816df648 100644 --- a/xbmc/peripherals/dialogs/GUIDialogPeripheralSettings.cpp +++ b/xbmc/peripherals/dialogs/GUIDialogPeripheralSettings.cpp @@ -12,17 +12,25 @@ #include "ServiceBroker.h" #include "addons/Skin.h" #include "dialogs/GUIDialogYesNo.h" +#include "games/controllers/Controller.h" +#include "games/controllers/ControllerManager.h" #include "guilib/GUIMessage.h" #include "peripherals/Peripherals.h" +#include "settings/SettingAddon.h" #include "settings/lib/Setting.h" #include "settings/lib/SettingSection.h" #include "utils/Variant.h" #include "utils/log.h" +#include <string_view> #include <utility> +using namespace KODI; using namespace PERIPHERALS; +// Settings for peripherals +constexpr std::string_view SETTING_APPEARANCE = "appearance"; + CGUIDialogPeripheralSettings::CGUIDialogPeripheralSettings() : CGUIDialogSettingsManualBase(WINDOW_DIALOG_PERIPHERAL_SETTINGS, "DialogSettings.xml"), m_item(NULL) @@ -49,6 +57,16 @@ bool CGUIDialogPeripheralSettings::OnMessage(CGUIMessage& message) return CGUIDialogSettingsManualBase::OnMessage(message); } +void CGUIDialogPeripheralSettings::RegisterPeripheralManager(CPeripherals& manager) +{ + m_manager = &manager; +} + +void CGUIDialogPeripheralSettings::UnregisterPeripheralManager() +{ + m_manager = nullptr; +} + void CGUIDialogPeripheralSettings::SetFileItem(const CFileItem* item) { if (item == NULL) @@ -67,14 +85,43 @@ void CGUIDialogPeripheralSettings::OnSettingChanged(const std::shared_ptr<const CGUIDialogSettingsManualBase::OnSettingChanged(setting); + const std::string& settingId = setting->GetId(); + // we need to copy the new value of the setting from the copy to the // original setting std::map<std::string, std::shared_ptr<CSetting>>::iterator itSetting = - m_settingsMap.find(setting->GetId()); + m_settingsMap.find(settingId); if (itSetting == m_settingsMap.end()) return; itSetting->second->FromString(setting->ToString()); + + // Get peripheral associated with this setting + PeripheralPtr peripheral; + if (m_item != nullptr) + peripheral = CServiceBroker::GetPeripherals().GetByPath(m_item->GetPath()); + + if (!peripheral) + return; + + if (settingId == SETTING_APPEARANCE) + { + // Get the controller profile of the new appearance + GAME::ControllerPtr controller; + + if (setting->GetType() == SettingType::String) + { + std::shared_ptr<const CSettingString> settingString = + std::static_pointer_cast<const CSettingString>(setting); + const std::string& addonId = settingString->GetValue(); + + if (m_manager != nullptr) + controller = m_manager->GetControllerProfiles().GetController(addonId); + } + + if (controller) + peripheral->SetControllerProfile(controller); + } } bool CGUIDialogPeripheralSettings::Save() @@ -208,11 +255,38 @@ void CGUIDialogPeripheralSettings::InitializeSettings() case SettingType::String: { - std::shared_ptr<CSettingString> settingString = std::make_shared<CSettingString>( - setting->GetId(), *std::static_pointer_cast<CSettingString>(setting)); - settingString->SetControl(GetEditControl("string")); + if (auto settingAsAddon = std::dynamic_pointer_cast<const CSettingAddon>(setting)) + { + std::shared_ptr<CSettingAddon> settingAddon = + std::make_shared<CSettingAddon>(setting->GetId(), *settingAsAddon); + + // Control properties + const std::string format = "addon"; + const bool delayed = false; + const int heading = -1; + const bool hideValue = false; + const bool showInstalledAddons = true; + const bool showInstallableAddons = true; + const bool showMoreAddons = false; + + settingAddon->SetControl(GetButtonControl(format, delayed, heading, hideValue, + showInstalledAddons, showInstallableAddons, + showMoreAddons)); + + GAME::ControllerPtr controller = peripheral->ControllerProfile(); + if (controller) + settingAddon->SetValue(controller->ID()); + + settingCopy = std::static_pointer_cast<CSetting>(settingAddon); + } + else + { + std::shared_ptr<CSettingString> settingString = std::make_shared<CSettingString>( + setting->GetId(), *std::static_pointer_cast<CSettingString>(setting)); + settingString->SetControl(GetEditControl("string")); - settingCopy = std::static_pointer_cast<CSetting>(settingString); + settingCopy = std::static_pointer_cast<CSetting>(settingString); + } break; } diff --git a/xbmc/peripherals/dialogs/GUIDialogPeripheralSettings.h b/xbmc/peripherals/dialogs/GUIDialogPeripheralSettings.h index 89022aa85f..33ad2eee52 100644 --- a/xbmc/peripherals/dialogs/GUIDialogPeripheralSettings.h +++ b/xbmc/peripherals/dialogs/GUIDialogPeripheralSettings.h @@ -14,6 +14,8 @@ class CFileItem; namespace PERIPHERALS { +class CPeripherals; + class CGUIDialogPeripheralSettings : public CGUIDialogSettingsManualBase { public: @@ -23,6 +25,9 @@ public: // specializations of CGUIControl bool OnMessage(CGUIMessage& message) override; + void RegisterPeripheralManager(CPeripherals& manager); + void UnregisterPeripheralManager(); + virtual void SetFileItem(const CFileItem* item); protected: @@ -38,6 +43,8 @@ protected: // specialization of CGUIDialogSettingsManualBase void InitializeSettings() override; + // Dialog state + CPeripherals* m_manager{nullptr}; CFileItem* m_item; bool m_initialising = false; std::map<std::string, std::shared_ptr<CSetting>> m_settingsMap; diff --git a/xbmc/peripherals/dialogs/GUIDialogPeripherals.cpp b/xbmc/peripherals/dialogs/GUIDialogPeripherals.cpp index 6acce44509..7594cb2a96 100644 --- a/xbmc/peripherals/dialogs/GUIDialogPeripherals.cpp +++ b/xbmc/peripherals/dialogs/GUIDialogPeripherals.cpp @@ -118,7 +118,9 @@ void CGUIDialogPeripherals::Show(CPeripherals& manager) // Open settings dialog pSettingsDialog->SetFileItem(pItem.get()); + pSettingsDialog->RegisterPeripheralManager(manager); pSettingsDialog->Open(); + pSettingsDialog->UnregisterPeripheralManager(); } } } while (pDialog->IsConfirmed()); |