summaryrefslogtreecommitdiffstats
path: root/xbmc/games/controllers/windows/GUIFeatureList.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/games/controllers/windows/GUIFeatureList.cpp')
-rw-r--r--xbmc/games/controllers/windows/GUIFeatureList.cpp297
1 files changed, 297 insertions, 0 deletions
diff --git a/xbmc/games/controllers/windows/GUIFeatureList.cpp b/xbmc/games/controllers/windows/GUIFeatureList.cpp
new file mode 100644
index 0000000..d43c16d
--- /dev/null
+++ b/xbmc/games/controllers/windows/GUIFeatureList.cpp
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2014-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "GUIFeatureList.h"
+
+#include "GUIConfigurationWizard.h"
+#include "GUIControllerDefines.h"
+#include "games/addons/GameClient.h"
+#include "games/addons/input/GameClientInput.h"
+#include "games/controllers/Controller.h"
+#include "games/controllers/guicontrols/GUIFeatureButton.h"
+#include "games/controllers/guicontrols/GUIFeatureControls.h"
+#include "games/controllers/guicontrols/GUIFeatureFactory.h"
+#include "games/controllers/guicontrols/GUIFeatureTranslator.h"
+#include "games/controllers/input/PhysicalFeature.h"
+#include "guilib/GUIButtonControl.h"
+#include "guilib/GUIControlGroupList.h"
+#include "guilib/GUIImage.h"
+#include "guilib/GUILabelControl.h"
+#include "guilib/GUIWindow.h"
+#include "guilib/LocalizeStrings.h"
+
+using namespace KODI;
+using namespace GAME;
+
+CGUIFeatureList::CGUIFeatureList(CGUIWindow* window, GameClientPtr gameClient)
+ : m_window(window),
+ m_guiList(nullptr),
+ m_guiButtonTemplate(nullptr),
+ m_guiGroupTitle(nullptr),
+ m_guiFeatureSeparator(nullptr),
+ m_gameClient(std::move(gameClient)),
+ m_wizard(new CGUIConfigurationWizard)
+{
+}
+
+CGUIFeatureList::~CGUIFeatureList(void)
+{
+ Deinitialize();
+ delete m_wizard;
+}
+
+bool CGUIFeatureList::Initialize(void)
+{
+ m_guiList = dynamic_cast<CGUIControlGroupList*>(m_window->GetControl(CONTROL_FEATURE_LIST));
+ m_guiButtonTemplate =
+ dynamic_cast<CGUIButtonControl*>(m_window->GetControl(CONTROL_FEATURE_BUTTON_TEMPLATE));
+ m_guiGroupTitle =
+ dynamic_cast<CGUILabelControl*>(m_window->GetControl(CONTROL_FEATURE_GROUP_TITLE));
+ m_guiFeatureSeparator = dynamic_cast<CGUIImage*>(m_window->GetControl(CONTROL_FEATURE_SEPARATOR));
+
+ if (m_guiButtonTemplate)
+ m_guiButtonTemplate->SetVisible(false);
+
+ if (m_guiGroupTitle)
+ m_guiGroupTitle->SetVisible(false);
+
+ if (m_guiFeatureSeparator)
+ m_guiFeatureSeparator->SetVisible(false);
+
+ return m_guiList != nullptr && m_guiButtonTemplate != nullptr;
+}
+
+void CGUIFeatureList::Deinitialize(void)
+{
+ CleanupButtons();
+
+ m_guiList = nullptr;
+ m_guiButtonTemplate = nullptr;
+ m_guiGroupTitle = nullptr;
+ m_guiFeatureSeparator = nullptr;
+}
+
+void CGUIFeatureList::Load(const ControllerPtr& controller)
+{
+ if (m_controller && m_controller->ID() == controller->ID())
+ return; // Already loaded
+
+ CleanupButtons();
+
+ // Set new controller
+ m_controller = controller;
+
+ // Get features
+ const std::vector<CPhysicalFeature>& features = controller->Features();
+
+ // Split into groups
+ auto featureGroups = GetFeatureGroups(features);
+
+ // Create controls
+ m_buttonCount = 0;
+ for (auto itGroup = featureGroups.begin(); itGroup != featureGroups.end(); ++itGroup)
+ {
+ const std::string& groupName = itGroup->groupName;
+ const bool bIsVirtualKey = itGroup->bIsVirtualKey;
+
+ std::vector<CGUIButtonControl*> buttons;
+
+ // Create buttons
+ if (bIsVirtualKey)
+ {
+ CGUIButtonControl* button = GetSelectKeyButton(itGroup->features, m_buttonCount);
+ if (button != nullptr)
+ buttons.push_back(button);
+ }
+ else
+ {
+ buttons = GetButtons(itGroup->features, m_buttonCount);
+ }
+
+ // Just in case
+ if (m_buttonCount + buttons.size() >= MAX_FEATURE_COUNT)
+ break;
+
+ // Add a separator if the group list isn't empty
+ if (m_guiFeatureSeparator && m_guiList->GetTotalSize() > 0)
+ {
+ CGUIFeatureSeparator* pSeparator =
+ new CGUIFeatureSeparator(*m_guiFeatureSeparator, m_buttonCount);
+ m_guiList->AddControl(pSeparator);
+ }
+
+ // Add the group title
+ if (m_guiGroupTitle && !groupName.empty())
+ {
+ CGUIFeatureGroupTitle* pGroupTitle =
+ new CGUIFeatureGroupTitle(*m_guiGroupTitle, groupName, m_buttonCount);
+ m_guiList->AddControl(pGroupTitle);
+ }
+
+ // Add the buttons
+ for (CGUIButtonControl* pButton : buttons)
+ m_guiList->AddControl(pButton);
+
+ m_buttonCount += static_cast<unsigned int>(buttons.size());
+ }
+}
+
+void CGUIFeatureList::OnSelect(unsigned int buttonIndex)
+{
+ // Generate list of buttons for the wizard
+ std::vector<IFeatureButton*> buttons;
+ for (; buttonIndex < m_buttonCount; buttonIndex++)
+ {
+ IFeatureButton* control = GetButtonControl(buttonIndex);
+ if (control == nullptr)
+ continue;
+
+ if (control->AllowWizard())
+ buttons.push_back(control);
+ else
+ {
+ // Only map this button if it's the only one
+ if (buttons.empty())
+ buttons.push_back(control);
+ break;
+ }
+ }
+
+ m_wizard->Run(m_controller->ID(), buttons);
+}
+
+IFeatureButton* CGUIFeatureList::GetButtonControl(unsigned int buttonIndex)
+{
+ CGUIControl* control = m_guiList->GetControl(CONTROL_FEATURE_BUTTONS_START + buttonIndex);
+
+ return static_cast<IFeatureButton*>(dynamic_cast<CGUIFeatureButton*>(control));
+}
+
+void CGUIFeatureList::CleanupButtons(void)
+{
+ m_buttonCount = 0;
+
+ m_wizard->Abort(true);
+ m_wizard->UnregisterKeys();
+
+ if (m_guiList)
+ m_guiList->ClearAll();
+}
+
+std::vector<CGUIFeatureList::FeatureGroup> CGUIFeatureList::GetFeatureGroups(
+ const std::vector<CPhysicalFeature>& features) const
+{
+ std::vector<FeatureGroup> groups;
+
+ // Get group names
+ std::vector<std::string> groupNames;
+ for (const CPhysicalFeature& feature : features)
+ {
+ // Skip features not supported by the game client
+ if (m_gameClient)
+ {
+ if (!m_gameClient->Input().HasFeature(m_controller->ID(), feature.Name()))
+ continue;
+ }
+
+ bool bAdded = false;
+
+ if (!groups.empty())
+ {
+ FeatureGroup& previousGroup = *groups.rbegin();
+ if (feature.CategoryLabel() == previousGroup.groupName)
+ {
+ // Add feature to previous group
+ previousGroup.features.emplace_back(feature);
+ bAdded = true;
+
+ // If feature is a key, add it to the preceding virtual group as well
+ if (feature.Category() == JOYSTICK::FEATURE_CATEGORY::KEY && groups.size() >= 2)
+ {
+ FeatureGroup& virtualGroup = *(groups.rbegin() + 1);
+ if (virtualGroup.bIsVirtualKey)
+ virtualGroup.features.emplace_back(feature);
+ }
+ }
+ }
+
+ if (!bAdded)
+ {
+ // If feature is a key, create a virtual group that allows the user to
+ // select which key to map
+ if (feature.Category() == JOYSTICK::FEATURE_CATEGORY::KEY)
+ {
+ FeatureGroup virtualGroup;
+ virtualGroup.groupName = g_localizeStrings.Get(35166); // "All keys"
+ virtualGroup.bIsVirtualKey = true;
+ virtualGroup.features.emplace_back(feature);
+ groups.emplace_back(std::move(virtualGroup));
+ }
+
+ // Create new group and add feature
+ FeatureGroup group;
+ group.groupName = feature.CategoryLabel();
+ group.features.emplace_back(feature);
+ groups.emplace_back(std::move(group));
+ }
+ }
+
+ // If there are no features, add an empty group
+ if (groups.empty())
+ {
+ FeatureGroup group;
+ group.groupName = g_localizeStrings.Get(35022); // "Nothing to map"
+ groups.emplace_back(std::move(group));
+ }
+
+ return groups;
+}
+
+bool CGUIFeatureList::HasButton(JOYSTICK::FEATURE_TYPE type) const
+{
+ return CGUIFeatureTranslator::GetButtonType(type) != BUTTON_TYPE::UNKNOWN;
+}
+
+std::vector<CGUIButtonControl*> CGUIFeatureList::GetButtons(
+ const std::vector<CPhysicalFeature>& features, unsigned int startIndex)
+{
+ std::vector<CGUIButtonControl*> buttons;
+
+ // Create buttons
+ unsigned int buttonIndex = startIndex;
+ for (const CPhysicalFeature& feature : features)
+ {
+ BUTTON_TYPE buttonType = CGUIFeatureTranslator::GetButtonType(feature.Type());
+
+ CGUIButtonControl* pButton = CGUIFeatureFactory::CreateButton(buttonType, *m_guiButtonTemplate,
+ m_wizard, feature, buttonIndex);
+
+ // If successful, add button to result
+ if (pButton != nullptr)
+ {
+ buttons.push_back(pButton);
+ buttonIndex++;
+ }
+ }
+
+ return buttons;
+}
+
+CGUIButtonControl* CGUIFeatureList::GetSelectKeyButton(
+ const std::vector<CPhysicalFeature>& features, unsigned int buttonIndex)
+{
+ // Expose keycodes to the wizard
+ for (const CPhysicalFeature& feature : features)
+ {
+ if (feature.Type() == JOYSTICK::FEATURE_TYPE::KEY)
+ m_wizard->RegisterKey(feature);
+ }
+
+ return CGUIFeatureFactory::CreateButton(BUTTON_TYPE::SELECT_KEY, *m_guiButtonTemplate, m_wizard,
+ CPhysicalFeature(), buttonIndex);
+}