aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarrett Brown <themagnificentmrb@gmail.com>2023-02-22 22:29:07 -0800
committerGarrett Brown <themagnificentmrb@gmail.com>2023-03-02 18:08:56 -0800
commitf08d4b7153e0bfa6e77d4d2dfc0d84daef6f9bcf (patch)
tree291ebb0eb9b256173a89dd0063cec73ec45645e0
parent985c290dfd7b5b06c826dd0aaa72160ef3ce60d3 (diff)
downloadxbmc-f08d4b7153e0bfa6e77d4d2dfc0d84daef6f9bcf.tar.xz
Peripherals: Allow changing joystick appearance
-rw-r--r--addons/resource.language.en_gb/resources/strings.po1
-rw-r--r--system/peripherals.xml5
-rw-r--r--xbmc/input/joysticks/interfaces/IButtonMap.h18
-rw-r--r--xbmc/peripherals/Peripherals.cpp10
-rw-r--r--xbmc/peripherals/Peripherals.h6
-rw-r--r--xbmc/peripherals/addons/AddonButtonMap.cpp14
-rw-r--r--xbmc/peripherals/addons/AddonButtonMap.h12
-rw-r--r--xbmc/peripherals/devices/Peripheral.cpp20
-rw-r--r--xbmc/peripherals/devices/Peripheral.h12
-rw-r--r--xbmc/peripherals/devices/PeripheralJoystick.cpp126
-rw-r--r--xbmc/peripherals/devices/PeripheralJoystick.h12
-rw-r--r--xbmc/peripherals/devices/PeripheralKeyboard.cpp3
-rw-r--r--xbmc/peripherals/devices/PeripheralMouse.cpp3
-rw-r--r--xbmc/peripherals/dialogs/GUIDialogPeripheralSettings.cpp84
-rw-r--r--xbmc/peripherals/dialogs/GUIDialogPeripheralSettings.h7
-rw-r--r--xbmc/peripherals/dialogs/GUIDialogPeripherals.cpp2
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 76c0ba4dbf..02979e95d0 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());