diff options
18 files changed, 303 insertions, 91 deletions
diff --git a/Kodi.xcodeproj/project.pbxproj b/Kodi.xcodeproj/project.pbxproj index 68df9e9cec..ed0ac02d9a 100644 --- a/Kodi.xcodeproj/project.pbxproj +++ b/Kodi.xcodeproj/project.pbxproj @@ -319,6 +319,8 @@ 68AE5C321C9243A000C4D527 /* ControllerLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68AE5C281C9243A000C4D527 /* ControllerLayout.cpp */; }; 68AE5C331C9243A000C4D527 /* ControllerTranslator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68AE5C2A1C9243A000C4D527 /* ControllerTranslator.cpp */; }; 68AE5C341C9243A000C4D527 /* ControllerTranslator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68AE5C2A1C9243A000C4D527 /* ControllerTranslator.cpp */; }; + 68B7E5E81D5FA9B300A5AEC0 /* GUIFeatureControls.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68B7E5E61D5FA9B300A5AEC0 /* GUIFeatureControls.cpp */; }; + 68B7E5E91D5FA9B300A5AEC0 /* GUIFeatureControls.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68B7E5E61D5FA9B300A5AEC0 /* GUIFeatureControls.cpp */; }; 761170901C8B85F8006C6366 /* AddonGUIRenderingControl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7611708C1C8B85F8006C6366 /* AddonGUIRenderingControl.cpp */; }; 761170911C8B85F8006C6366 /* AddonGUIWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7611708E1C8B85F8006C6366 /* AddonGUIWindow.cpp */; }; 76AEFB361C8F79BD00EF2EC0 /* AddonInterfaces.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EDED2E991C878F61000F5E80 /* AddonInterfaces.cpp */; }; @@ -2832,6 +2834,8 @@ 68AE5C2A1C9243A000C4D527 /* ControllerTranslator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ControllerTranslator.cpp; path = games/controllers/ControllerTranslator.cpp; sourceTree = "<group>"; }; 68AE5C2B1C9243A000C4D527 /* ControllerTranslator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ControllerTranslator.h; path = games/controllers/ControllerTranslator.h; sourceTree = "<group>"; }; 68AE5C2C1C9243A000C4D527 /* ControllerTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ControllerTypes.h; path = games/controllers/ControllerTypes.h; sourceTree = "<group>"; }; + 68B7E5E61D5FA9B300A5AEC0 /* GUIFeatureControls.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GUIFeatureControls.cpp; path = games/controllers/guicontrols/GUIFeatureControls.cpp; sourceTree = "<group>"; }; + 68B7E5E71D5FA9B300A5AEC0 /* GUIFeatureControls.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GUIFeatureControls.h; path = games/controllers/guicontrols/GUIFeatureControls.h; sourceTree = "<group>"; }; 6E97BDBF0DA2B620003A2A89 /* EventClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EventClient.h; sourceTree = "<group>"; }; 6E97BDC00DA2B620003A2A89 /* EventPacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EventPacket.h; sourceTree = "<group>"; }; 6E97BDC10DA2B620003A2A89 /* EventServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EventServer.h; sourceTree = "<group>"; }; @@ -6220,6 +6224,8 @@ 68AE5C121C92438E00C4D527 /* GUIControllerButton.h */, 68AE5C131C92438E00C4D527 /* GUIFeatureButton.cpp */, 68AE5C141C92438E00C4D527 /* GUIFeatureButton.h */, + 68B7E5E61D5FA9B300A5AEC0 /* GUIFeatureControls.cpp */, + 68B7E5E71D5FA9B300A5AEC0 /* GUIFeatureControls.h */, 68AE5C151C92438E00C4D527 /* GUIGameController.cpp */, 68AE5C161C92438E00C4D527 /* GUIGameController.h */, 68AE5C171C92438E00C4D527 /* GUIScalarFeatureButton.cpp */, @@ -10327,6 +10333,7 @@ F5E1138014357F3800175026 /* PeripheralCecAdapter.cpp in Sources */, DF673AA51443819600A5A509 /* AddonManager.cpp in Sources */, 7C8E022B1BA35D0B0072E8B2 /* GUIContainerBuiltins.cpp in Sources */, + 68B7E5E81D5FA9B300A5AEC0 /* GUIFeatureControls.cpp in Sources */, DFDE5D511AE5658200EE53AD /* PictureScalingAlgorithm.cpp in Sources */, F5BD02F6148D3A7E001B5583 /* CryptThreading.cpp in Sources */, DF5276E1151BAEDA00B5B63B /* Base64.cpp in Sources */, @@ -11066,6 +11073,7 @@ E4991285174E5D9900741B6D /* DirectoryNodeAlbumTop100Song.cpp in Sources */, 395C2A051A9CD25100EBC7AD /* ContextItemAddonInvoker.cpp in Sources */, E4991286174E5D9900741B6D /* DirectoryNodeArtist.cpp in Sources */, + 68B7E5E91D5FA9B300A5AEC0 /* GUIFeatureControls.cpp in Sources */, DF29BCEF1B5D911800904347 /* BaseEvent.cpp in Sources */, E4991287174E5D9900741B6D /* DirectoryNodeGrouped.cpp in Sources */, E4991288174E5D9900741B6D /* DirectoryNodeOverview.cpp in Sources */, diff --git a/addons/game.controller.default/resources/layout.xml b/addons/game.controller.default/resources/layout.xml index b8df0e6b41..0ceab7b62b 100644 --- a/addons/game.controller.default/resources/layout.xml +++ b/addons/game.controller.default/resources/layout.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <layout name="default" label="30000" image="layout.png"> - <category name="face"> + <category name="face" label="35074"> <button name="a" type="digital" label="30001" geometry="circle" x="651" y="266" radius="32"/> <button name="b" type="digital" label="30002" geometry="circle" x="709" y="210" radius="32"/> <button name="x" type="digital" label="30003" geometry="circle" x="583" y="210" radius="32"/> @@ -15,15 +15,15 @@ <button name="leftthumb" type="digital" label="30008" geometry="rectangle" x1="131" y1="0" x2="194" y2="40"/> <button name="rightthumb" type="digital" label="30009" geometry="rectangle" x1="567" y1="0" x2="631" y2="40"/> </category> - <category name="shoulder"> + <category name="shoulder" label="35075"> <button name="leftbumper" type="digital" label="30014" geometry="rectangle" x1="272" y1="321" x2="316" y2="365"/> <button name="rightbumper" type="digital" label="30015" geometry="rectangle" x1="198" y1="321" x2="242" y2="365"/> </category> - <category name="triggers"> + <category name="triggers" label="35076"> <button name="lefttrigger" type="analog" label="30016" geometry="rectangle" x1="36" y1="40" x2="207" y2="108"/> <button name="righttrigger" type="analog" label="30017" geometry="rectangle" x1="556" y1="40" x2="728" y2="108"/> </category> - <category name="analogsticks"> + <category name="analogsticks" label="35077"> <analogstick name="leftstick" label="30008" geometry="circle" x="500" y="342" r="52"/> <analogstick name="rightstick" label="30009" geometry="circle" x="500" y="342" r="52"/> </category> diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po index 19d04d7457..397c7ff26e 100644 --- a/addons/resource.language.en_gb/resources/strings.po +++ b/addons/resource.language.en_gb/resources/strings.po @@ -16042,7 +16042,29 @@ msgctxt "#35064" msgid "Pair your controllers with the various input devices of different game systems." msgstr "" -#empty strings from id 35065 to 35087 +#empty strings from id 35065 to 35073 + +#. Label for buttons that appear on the face of the controller. Used in the controller mapping dialog. +msgctxt "#35074" +msgid "Face buttons" +msgstr "" + +#. Label for buttons that appear on the shoulders of the controller. Used in the controller mapping dialog. +msgctxt "#35075" +msgid "Shoulder buttons" +msgstr "" + +#. Label for triggers on the controller. Used in the controller mapping dialog. +msgctxt "#35076" +msgid "Triggers" +msgstr "" + +#. Label for analog sticks on the controller. Used in the controller mapping dialog. +msgctxt "#35077" +msgid "Analog sticks" +msgstr "" + +#empty strings from id 35078 to 35087 #. Name of the setting that enables/disables powering off controllers on exit #: system/settings/settings.xml diff --git a/addons/skin.estuary/1080i/DialogGameControllers.xml b/addons/skin.estuary/1080i/DialogGameControllers.xml index f420abdbec..10db3bf47a 100644 --- a/addons/skin.estuary/1080i/DialogGameControllers.xml +++ b/addons/skin.estuary/1080i/DialogGameControllers.xml @@ -123,6 +123,22 @@ <texturefocus colordiffuse="button_focus">lists/focus.png</texturefocus> <texturenofocus>lists/separator.png</texturenofocus> </control> + <control type="label" id="8"> + <description>Feature group title</description> + <height>60</height> + <width>330</width> + <label>-</label> + <align>center</align> + <aligny>center</aligny> + <font>font12_title</font> + <textcolor>grey</textcolor> + <shadowcolor>black</shadowcolor> + </control> + <control type="image" id="9"> + <description>Feature separator image</description> + <height>3</height> + <texture colordiffuse="AAAAAAAA" border="3">dialogs/separator-grey.png</texture> + </control> <control type="grouplist" id="9001"> <left>1360</left> <top>110</top> diff --git a/xbmc/games/controllers/ControllerDefinitions.h b/xbmc/games/controllers/ControllerDefinitions.h index 366d49734f..8ade354737 100644 --- a/xbmc/games/controllers/ControllerDefinitions.h +++ b/xbmc/games/controllers/ControllerDefinitions.h @@ -21,7 +21,7 @@ #define LAYOUT_XML_ROOT "layout" -#define LAYOUT_XML_ELM_CATEGORY "category" +#define LAYOUT_XML_ELM_GROUP "category" #define LAYOUT_XML_ELM_BUTTON "button" #define LAYOUT_XML_ELM_ANALOG_STICK "analogstick" @@ -32,13 +32,7 @@ #define LAYOUT_XML_ATTR_LAYOUT_IMAGE "image" #define LAYOUT_XML_ATTR_LAYOUT_OVERLAY "overlay" -#define LAYOUT_XML_ATTR_CATEGORY_NAME "name" - -#define LAYOUT_XML_VALUE_CATEGORY_FACE "face" -#define LAYOUT_XML_VALUE_CATEGORY_SHOULDER "shoulder" -#define LAYOUT_XML_VALUE_CATEGORY_TRIGGERS "triggers" -#define LAYOUT_XML_VALUE_CATEGORY_ANALOG_STICKS "analogsticks" -#define LAYOUT_XML_VALUE_CATEGORY_HAPTICS "haptics" +#define LAYOUT_XML_ATTR_GROUP_LABEL "label" #define LAYOUT_XML_ATTR_FEATURE_NAME "name" #define LAYOUT_XML_ATTR_FEATURE_LABEL "label" diff --git a/xbmc/games/controllers/ControllerFeature.cpp b/xbmc/games/controllers/ControllerFeature.cpp index 4c6eadf9b7..e0500eaeba 100644 --- a/xbmc/games/controllers/ControllerFeature.cpp +++ b/xbmc/games/controllers/ControllerFeature.cpp @@ -34,7 +34,7 @@ using namespace JOYSTICK; void CControllerFeature::Reset(void) { m_type = FEATURE_TYPE::UNKNOWN; - m_category = FEATURE_CATEGORY::UNKNOWN; + m_group.clear(); m_strName.clear(); m_strLabel.clear(); m_labelId = 0; @@ -46,7 +46,7 @@ CControllerFeature& CControllerFeature::operator=(const CControllerFeature& rhs) if (this != &rhs) { m_type = rhs.m_type; - m_category = rhs.m_category; + m_group = rhs.m_group; m_strName = rhs.m_strName; m_strLabel = rhs.m_strLabel; m_labelId = rhs.m_labelId; @@ -55,7 +55,7 @@ CControllerFeature& CControllerFeature::operator=(const CControllerFeature& rhs) return *this; } -bool CControllerFeature::Deserialize(const TiXmlElement* pElement, const CController* controller, const std::string& strCategory) +bool CControllerFeature::Deserialize(const TiXmlElement* pElement, const CController* controller, const std::string& strGroup) { Reset(); @@ -72,8 +72,8 @@ bool CControllerFeature::Deserialize(const TiXmlElement* pElement, const CContro return false; } - // Category was obtained from parent XML node - m_category = CControllerTranslator::TranslateCategory(strCategory); + // Group was obtained from parent XML node + m_group = strGroup; // Name m_strName = XMLUtils::GetAttribute(pElement, LAYOUT_XML_ATTR_FEATURE_NAME); diff --git a/xbmc/games/controllers/ControllerFeature.h b/xbmc/games/controllers/ControllerFeature.h index b68b02d4db..7a2ae4336e 100644 --- a/xbmc/games/controllers/ControllerFeature.h +++ b/xbmc/games/controllers/ControllerFeature.h @@ -40,17 +40,17 @@ public: CControllerFeature& operator=(const CControllerFeature& rhs); JOYSTICK::FEATURE_TYPE Type(void) const { return m_type; } - JOYSTICK::FEATURE_CATEGORY Category(void) const { return m_category; } + const std::string& Group(void) const { return m_group; } const std::string& Name(void) const { return m_strName; } const std::string& Label(void) const { return m_strLabel; } unsigned int LabelID(void) const { return m_labelId; } JOYSTICK::INPUT_TYPE InputType(void) const { return m_inputType; } - bool Deserialize(const TiXmlElement* pElement, const CController* controller, const std::string& strCategory); + bool Deserialize(const TiXmlElement* pElement, const CController* controller, const std::string& strGroup); private: JOYSTICK::FEATURE_TYPE m_type; - JOYSTICK::FEATURE_CATEGORY m_category; + std::string m_group; std::string m_strName; std::string m_strLabel; unsigned int m_labelId; diff --git a/xbmc/games/controllers/ControllerLayout.cpp b/xbmc/games/controllers/ControllerLayout.cpp index 6ee6200b01..6d1bbadc9f 100644 --- a/xbmc/games/controllers/ControllerLayout.cpp +++ b/xbmc/games/controllers/ControllerLayout.cpp @@ -19,7 +19,9 @@ */ #include "ControllerLayout.h" +#include "Controller.h" #include "ControllerDefinitions.h" +#include "guilib/LocalizeStrings.h" #include "utils/log.h" #include "utils/XMLUtils.h" @@ -100,18 +102,32 @@ bool CControllerLayout::Deserialize(const TiXmlElement* pElement, const CControl CLog::Log(LOGDEBUG, "<%s> tag has no \"%s\" attribute", LAYOUT_XML_ROOT, LAYOUT_XML_ATTR_LAYOUT_OVERLAY); // Features - for (const TiXmlElement* pCategory = pElement->FirstChildElement(); pCategory != nullptr; pCategory = pCategory->NextSiblingElement()) + for (const TiXmlElement* pGroup = pElement->FirstChildElement(); pGroup != nullptr; pGroup = pGroup->NextSiblingElement()) { - if (std::string(pCategory->Value()) != std::string(LAYOUT_XML_ELM_CATEGORY)) + if (pGroup->ValueStr() != LAYOUT_XML_ELM_GROUP) + { + CLog::Log(LOGDEBUG, "<%s> tag is misnamed: <%s>", LAYOUT_XML_ELM_GROUP, pGroup->Value() ? pGroup->Value() : ""); continue; + } + + // Group + std::string strGroup; - const std::string strCategoryName = XMLUtils::GetAttribute(pCategory, LAYOUT_XML_ATTR_CATEGORY_NAME); + std::string strGroupLabel = XMLUtils::GetAttribute(pGroup, LAYOUT_XML_ATTR_GROUP_LABEL); + if (!strGroupLabel.empty()) + { + unsigned int categoryId; + std::istringstream(strGroupLabel) >> categoryId; + strGroup = g_localizeStrings.GetAddonString(controller->ID(), categoryId); + if (strGroup.empty()) + strGroup = g_localizeStrings.Get(categoryId); + } - for (const TiXmlElement* pFeature = pCategory->FirstChildElement(); pFeature != nullptr; pFeature = pFeature->NextSiblingElement()) + for (const TiXmlElement* pFeature = pGroup->FirstChildElement(); pFeature != nullptr; pFeature = pFeature->NextSiblingElement()) { CControllerFeature feature; - if (!feature.Deserialize(pFeature, controller, strCategoryName)) + if (!feature.Deserialize(pFeature, controller, strGroup)) return false; m_features.push_back(feature); diff --git a/xbmc/games/controllers/ControllerTranslator.cpp b/xbmc/games/controllers/ControllerTranslator.cpp index 275b87aaf4..692960e720 100644 --- a/xbmc/games/controllers/ControllerTranslator.cpp +++ b/xbmc/games/controllers/ControllerTranslator.cpp @@ -48,32 +48,6 @@ FEATURE_TYPE CControllerTranslator::TranslateFeatureType(const std::string& strT return FEATURE_TYPE::UNKNOWN; } -const char* CControllerTranslator::TranslateCategory(FEATURE_CATEGORY category) -{ - switch (category) - { - case FEATURE_CATEGORY::FACE: return LAYOUT_XML_VALUE_CATEGORY_FACE; - case FEATURE_CATEGORY::SHOULDER: return LAYOUT_XML_VALUE_CATEGORY_SHOULDER; - case FEATURE_CATEGORY::TRIGGERS: return LAYOUT_XML_VALUE_CATEGORY_TRIGGERS; - case FEATURE_CATEGORY::ANALOG_STICKS: return LAYOUT_XML_VALUE_CATEGORY_ANALOG_STICKS; - case FEATURE_CATEGORY::HAPTICS: return LAYOUT_XML_VALUE_CATEGORY_HAPTICS; - default: - break; - } - return ""; -} - -FEATURE_CATEGORY CControllerTranslator::TranslateCategory(const std::string& strCategory) -{ - if (strCategory == LAYOUT_XML_VALUE_CATEGORY_FACE) return FEATURE_CATEGORY::FACE; - if (strCategory == LAYOUT_XML_VALUE_CATEGORY_SHOULDER) return FEATURE_CATEGORY::SHOULDER; - if (strCategory == LAYOUT_XML_VALUE_CATEGORY_TRIGGERS) return FEATURE_CATEGORY::TRIGGERS; - if (strCategory == LAYOUT_XML_VALUE_CATEGORY_ANALOG_STICKS) return FEATURE_CATEGORY::ANALOG_STICKS; - if (strCategory == LAYOUT_XML_VALUE_CATEGORY_HAPTICS) return FEATURE_CATEGORY::HAPTICS; - - return FEATURE_CATEGORY::UNKNOWN; -} - const char* CControllerTranslator::TranslateInputType(INPUT_TYPE type) { switch (type) diff --git a/xbmc/games/controllers/ControllerTranslator.h b/xbmc/games/controllers/ControllerTranslator.h index c2c70b3030..c7436134e4 100644 --- a/xbmc/games/controllers/ControllerTranslator.h +++ b/xbmc/games/controllers/ControllerTranslator.h @@ -33,9 +33,6 @@ public: static const char* TranslateFeatureType(JOYSTICK::FEATURE_TYPE type); static JOYSTICK::FEATURE_TYPE TranslateFeatureType(const std::string& strType); - static const char* TranslateCategory(JOYSTICK::FEATURE_CATEGORY category); - static JOYSTICK::FEATURE_CATEGORY TranslateCategory(const std::string& strCategory); - static const char* TranslateInputType(JOYSTICK::INPUT_TYPE type); static JOYSTICK::INPUT_TYPE TranslateInputType(const std::string& strType); }; diff --git a/xbmc/games/controllers/guicontrols/CMakeLists.txt b/xbmc/games/controllers/guicontrols/CMakeLists.txt index dafd43cea4..c719a88fd0 100644 --- a/xbmc/games/controllers/guicontrols/CMakeLists.txt +++ b/xbmc/games/controllers/guicontrols/CMakeLists.txt @@ -1,12 +1,14 @@ set(SOURCES GUIAnalogStickButton.cpp GUIControllerButton.cpp GUIFeatureButton.cpp + GUIFeatureControls.cpp GUIGameController.cpp GUIScalarFeatureButton.cpp) set(HEADERS GUIAnalogStickButton.h GUIControllerButton.h GUIFeatureButton.h + GUIFeatureControls.h GUIGameController.h GUIScalarFeatureButton.h) diff --git a/xbmc/games/controllers/guicontrols/GUIFeatureControls.cpp b/xbmc/games/controllers/guicontrols/GUIFeatureControls.cpp new file mode 100644 index 0000000000..46866732c4 --- /dev/null +++ b/xbmc/games/controllers/guicontrols/GUIFeatureControls.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2016 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this Program; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include "GUIFeatureControls.h" +#include "games/controllers/windows/GUIControllerDefines.h" + +using namespace GAME; + +CGUIFeatureGroupTitle::CGUIFeatureGroupTitle(const CGUILabelControl& groupTitleTemplate, const std::string& groupName, unsigned int featureIndex) : + CGUILabelControl(groupTitleTemplate) +{ + // Initialize CGUILabelControl + SetLabel(groupName); + SetID(CONTROL_FEATURE_GROUPS_START + featureIndex); + SetVisible(true); + AllocResources(); +} + +CGUIFeatureSeparator::CGUIFeatureSeparator(const CGUIImage& separatorTemplate, unsigned int featureIndex) : + CGUIImage(separatorTemplate) +{ + // Initialize CGUIImage + SetID(CONTROL_FEATURE_SEPARATORS_START + featureIndex); + SetVisible(true); + AllocResources(); +} diff --git a/xbmc/games/controllers/guicontrols/GUIFeatureControls.h b/xbmc/games/controllers/guicontrols/GUIFeatureControls.h new file mode 100644 index 0000000000..beccc94fbd --- /dev/null +++ b/xbmc/games/controllers/guicontrols/GUIFeatureControls.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2016 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this Program; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ +#pragma once + +#include "guilib/GUILabelControl.h" +#include "guilib/GUIImage.h" + +#include <string> + +namespace GAME +{ + class CGUIFeatureGroupTitle : public CGUILabelControl + { + public: + CGUIFeatureGroupTitle(const CGUILabelControl& groupTitleTemplate, const std::string& groupName, unsigned int featureIndex); + + virtual ~CGUIFeatureGroupTitle(void) { } + }; + + class CGUIFeatureSeparator : public CGUIImage + { + public: + CGUIFeatureSeparator(const CGUIImage& separatorTemplate, unsigned int featureIndex); + + virtual ~CGUIFeatureSeparator(void) { } + }; +} diff --git a/xbmc/games/controllers/guicontrols/Makefile b/xbmc/games/controllers/guicontrols/Makefile index c9e2b3090a..c00d858b0c 100644 --- a/xbmc/games/controllers/guicontrols/Makefile +++ b/xbmc/games/controllers/guicontrols/Makefile @@ -1,6 +1,7 @@ SRCS=GUIAnalogStickButton.cpp \ GUIControllerButton.cpp \ GUIFeatureButton.cpp \ + GUIFeatureControls.cpp \ GUIGameController.cpp \ GUIScalarFeatureButton.cpp \ diff --git a/xbmc/games/controllers/windows/GUIControllerDefines.h b/xbmc/games/controllers/windows/GUIControllerDefines.h index 17d83d7567..54e1e28ac6 100644 --- a/xbmc/games/controllers/windows/GUIControllerDefines.h +++ b/xbmc/games/controllers/windows/GUIControllerDefines.h @@ -29,6 +29,8 @@ #define CONTROL_CONTROLLER_LIST 3 #define CONTROL_FEATURE_LIST 5 #define CONTROL_FEATURE_BUTTON_TEMPLATE 7 +#define CONTROL_FEATURE_GROUP_TITLE 8 +#define CONTROL_FEATURE_SEPARATOR 9 #define CONTROL_CONTROLLER_BUTTON_TEMPLATE 10 #define CONTROL_HELP_BUTTON 17 #define CONTROL_CLOSE_BUTTON 18 @@ -43,3 +45,7 @@ #define CONTROL_CONTROLLER_BUTTONS_END (CONTROL_CONTROLLER_BUTTONS_START + MAX_CONTROLLER_COUNT) #define CONTROL_FEATURE_BUTTONS_START CONTROL_CONTROLLER_BUTTONS_END #define CONTROL_FEATURE_BUTTONS_END (CONTROL_FEATURE_BUTTONS_START + MAX_FEATURE_COUNT) +#define CONTROL_FEATURE_GROUPS_START CONTROL_FEATURE_BUTTONS_END +#define CONTROL_FEATURE_GROUPS_END (CONTROL_FEATURE_GROUPS_START + MAX_FEATURE_COUNT) +#define CONTROL_FEATURE_SEPARATORS_START CONTROL_FEATURE_GROUPS_END +#define CONTROL_FEATURE_SEPARATORS_END (CONTROL_FEATURE_SEPARATORS_START + MAX_FEATURE_COUNT) diff --git a/xbmc/games/controllers/windows/GUIFeatureList.cpp b/xbmc/games/controllers/windows/GUIFeatureList.cpp index 862055bb4c..4aa114c870 100644 --- a/xbmc/games/controllers/windows/GUIFeatureList.cpp +++ b/xbmc/games/controllers/windows/GUIFeatureList.cpp @@ -19,13 +19,17 @@ */ #include "GUIFeatureList.h" + #include "GUIConfigurationWizard.h" #include "GUIControllerDefines.h" #include "games/controllers/guicontrols/GUIAnalogStickButton.h" +#include "games/controllers/guicontrols/GUIFeatureControls.h" #include "games/controllers/guicontrols/GUIScalarFeatureButton.h" #include "games/controllers/Controller.h" #include "guilib/GUIButtonControl.h" #include "guilib/GUIControlGroupList.h" +#include "guilib/GUIImage.h" +#include "guilib/GUILabelControl.h" #include "guilib/GUIWindow.h" using namespace GAME; @@ -34,6 +38,8 @@ CGUIFeatureList::CGUIFeatureList(CGUIWindow* window) : m_window(window), m_guiList(nullptr), m_guiButtonTemplate(nullptr), + m_guiGroupTitle(nullptr), + m_guiFeatureSeparator(nullptr), m_wizard(new CGUIConfigurationWizard) { } @@ -48,11 +54,19 @@ 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); - return m_guiList && m_guiButtonTemplate; + 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) @@ -61,6 +75,8 @@ void CGUIFeatureList::Deinitialize(void) m_guiList = nullptr; m_guiButtonTemplate = nullptr; + m_guiGroupTitle = nullptr; + m_guiFeatureSeparator = nullptr; } void CGUIFeatureList::Load(const ControllerPtr& controller) @@ -70,35 +86,48 @@ void CGUIFeatureList::Load(const ControllerPtr& controller) CleanupButtons(); + // Set new controller m_controller = controller; + // Get features const std::vector<CControllerFeature>& features = controller->Layout().Features(); - for (unsigned int buttonIndex = 0; buttonIndex < features.size(); buttonIndex++) + // Split into groups + auto featureGroups = GetFeatureGroups(features); + + // Create controls + unsigned int featureIndex = 0; + for (auto itGroup = featureGroups.begin(); itGroup != featureGroups.end(); ++itGroup) { - const CControllerFeature& feature = features[buttonIndex]; + const std::string& groupName = itGroup->groupName; - CGUIButtonControl* pButton = nullptr; - switch (feature.Type()) + // Create buttons + std::vector<CGUIButtonControl*> buttons = GetButtons(itGroup->features, featureIndex); + if (!buttons.empty()) { - case JOYSTICK::FEATURE_TYPE::SCALAR: + // Add a separator if the group list isn't empty + if (m_guiFeatureSeparator && m_guiList->GetTotalSize() > 0) { - pButton = new CGUIScalarFeatureButton(*m_guiButtonTemplate, m_wizard, feature, buttonIndex); - break; + CGUIFeatureSeparator* pSeparator = new CGUIFeatureSeparator(*m_guiFeatureSeparator, featureIndex); + m_guiList->AddControl(pSeparator); } - case JOYSTICK::FEATURE_TYPE::ANALOG_STICK: + + // Add the group title + if (m_guiGroupTitle && !groupName.empty()) { - pButton = new CGUIAnalogStickButton(*m_guiButtonTemplate, m_wizard, feature, buttonIndex); - break; + CGUIFeatureGroupTitle* pGroupTitle = new CGUIFeatureGroupTitle(*m_guiGroupTitle, groupName, featureIndex); + m_guiList->AddControl(pGroupTitle); } - default: - break; + + // Add the buttons + for (CGUIButtonControl* pButton : buttons) + m_guiList->AddControl(pButton); + + featureIndex += itGroup->features.size(); } - if (pButton) - m_guiList->AddControl(pButton); // Just in case - if (buttonIndex >= MAX_FEATURE_COUNT) + if (featureIndex >= MAX_FEATURE_COUNT) break; } } @@ -112,10 +141,8 @@ void CGUIFeatureList::OnSelect(unsigned int index) for ( ; index < featureCount; index++) { IFeatureButton* control = GetButtonControl(index); - if (!control) - break; - - buttons.push_back(control); + if (control) + buttons.push_back(control); } m_wizard->Run(m_controller->ID(), buttons); @@ -135,3 +162,67 @@ void CGUIFeatureList::CleanupButtons(void) if (m_guiList) m_guiList->ClearAll(); } + +std::vector<CGUIFeatureList::FeatureGroup> CGUIFeatureList::GetFeatureGroups(const std::vector<CControllerFeature>& features) +{ + std::vector<CGUIFeatureList::FeatureGroup> groups; + + // Get group names + std::vector<std::string> groupNames; + for (const CControllerFeature& feature : features) + { + if (std::find(groupNames.begin(), groupNames.end(), feature.Group()) == groupNames.end()) + groupNames.push_back(feature.Group()); + } + + // Divide features into groups + for (std::string& groupName : groupNames) + { + FeatureGroup group = { groupName }; + for (const CControllerFeature& feature : features) + { + if (feature.Group() == groupName) + group.features.push_back(feature); + } + groups.emplace_back(std::move(group)); + } + + return groups; +} + +std::vector<CGUIButtonControl*> CGUIFeatureList::GetButtons(const std::vector<CControllerFeature>& features, unsigned int startIndex) +{ + std::vector<CGUIButtonControl*> buttons; + + // Create buttons + unsigned int featureIndex = startIndex; + for (const CControllerFeature& feature : features) + { + CGUIButtonControl* pButton = nullptr; + + // Create button + switch (feature.Type()) + { + case JOYSTICK::FEATURE_TYPE::SCALAR: + { + pButton = new CGUIScalarFeatureButton(*m_guiButtonTemplate, m_wizard, feature, featureIndex); + break; + } + case JOYSTICK::FEATURE_TYPE::ANALOG_STICK: + { + pButton = new CGUIAnalogStickButton(*m_guiButtonTemplate, m_wizard, feature, featureIndex); + break; + } + default: + break; + } + + // If successful, add button to result + if (pButton) + buttons.push_back(pButton); + + featureIndex++; + } + + return buttons; +} diff --git a/xbmc/games/controllers/windows/GUIFeatureList.h b/xbmc/games/controllers/windows/GUIFeatureList.h index eb4b890d6e..e5ed44d649 100644 --- a/xbmc/games/controllers/windows/GUIFeatureList.h +++ b/xbmc/games/controllers/windows/GUIFeatureList.h @@ -20,11 +20,13 @@ #pragma once #include "IConfigurationWindow.h" +#include "games/controllers/ControllerFeature.h" #include "games/controllers/ControllerTypes.h" -#include "threads/Thread.h" class CGUIButtonControl; class CGUIControlGroupList; +class CGUIImage; +class CGUILabelControl; class CGUIWindow; namespace GAME @@ -47,10 +49,21 @@ namespace GAME void CleanupButtons(void); + // Helper functions + struct FeatureGroup + { + std::string groupName; + std::vector<CControllerFeature> features; + }; + static std::vector<FeatureGroup> GetFeatureGroups(const std::vector<CControllerFeature>& features); + std::vector<CGUIButtonControl*> GetButtons(const std::vector<CControllerFeature>& features, unsigned int startIndex); + // GUI stuff CGUIWindow* const m_window; CGUIControlGroupList* m_guiList; CGUIButtonControl* m_guiButtonTemplate; + CGUILabelControl* m_guiGroupTitle; + CGUIImage* m_guiFeatureSeparator; // Game window stuff ControllerPtr m_controller; diff --git a/xbmc/input/joysticks/JoystickTypes.h b/xbmc/input/joysticks/JoystickTypes.h index 25e15162cc..fff53f141f 100644 --- a/xbmc/input/joysticks/JoystickTypes.h +++ b/xbmc/input/joysticks/JoystickTypes.h @@ -52,21 +52,6 @@ namespace JOYSTICK }; /*! - * \brief Types of categories that features can belong to - * - * Used to separate lists of features in the GUI. - */ - enum class FEATURE_CATEGORY - { - UNKNOWN, - FACE, - SHOULDER, - TRIGGERS, - ANALOG_STICKS, - HAPTICS, - }; - - /*! * \brief Direction arrows on the hat (directional pad) */ enum class HAT_DIRECTION |