diff options
Diffstat (limited to '')
-rw-r--r-- | xbmc/settings/dialogs/GUIDialogSettingsBase.cpp | 972 |
1 files changed, 972 insertions, 0 deletions
diff --git a/xbmc/settings/dialogs/GUIDialogSettingsBase.cpp b/xbmc/settings/dialogs/GUIDialogSettingsBase.cpp new file mode 100644 index 0000000..32d3958 --- /dev/null +++ b/xbmc/settings/dialogs/GUIDialogSettingsBase.cpp @@ -0,0 +1,972 @@ +/* + * 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 "GUIDialogSettingsBase.h" + +#include "GUIUserMessages.h" +#include "ServiceBroker.h" +#include "dialogs/GUIDialogYesNo.h" +#include "guilib/GUIColorButtonControl.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUIControlGroupList.h" +#include "guilib/GUIEditControl.h" +#include "guilib/GUIImage.h" +#include "guilib/GUILabelControl.h" +#include "guilib/GUIRadioButtonControl.h" +#include "guilib/GUISettingsSliderControl.h" +#include "guilib/GUISpinControlEx.h" +#include "guilib/GUIToggleButtonControl.h" +#include "guilib/GUIWindowManager.h" +#include "guilib/LocalizeStrings.h" +#include "input/Key.h" +#include "settings/SettingControl.h" +#include "settings/lib/SettingSection.h" +#include "settings/windows/GUIControlSettings.h" +#include "utils/StringUtils.h" +#include "utils/Variant.h" + +#include <set> +#include <string> +#include <vector> + +#if defined(TARGET_WINDOWS) // disable 4355: 'this' used in base member initializer list +#pragma warning(push) +#pragma warning(disable : 4355) +#endif // defined(TARGET_WINDOWS) + +#define CATEGORY_GROUP_ID 3 +#define SETTINGS_GROUP_ID 5 + +#define CONTROL_DEFAULT_BUTTON 7 +#define CONTROL_DEFAULT_RADIOBUTTON 8 +#define CONTROL_DEFAULT_SPIN 9 +#define CONTROL_DEFAULT_CATEGORY_BUTTON 10 +#define CONTROL_DEFAULT_SEPARATOR 11 +#define CONTROL_DEFAULT_EDIT 12 +#define CONTROL_DEFAULT_SLIDER 13 +#define CONTROL_DEFAULT_SETTING_LABEL 14 +#define CONTROL_DEFAULT_COLORBUTTON 15 + +CGUIDialogSettingsBase::CGUIDialogSettingsBase(int windowId, const std::string& xmlFile) + : CGUIDialog(windowId, xmlFile), + m_iSetting(0), + m_iCategory(0), + m_resetSetting(NULL), + m_dummyCategory(NULL), + m_pOriginalSpin(NULL), + m_pOriginalSlider(NULL), + m_pOriginalRadioButton(NULL), + m_pOriginalColorButton(nullptr), + m_pOriginalCategoryButton(NULL), + m_pOriginalButton(NULL), + m_pOriginalEdit(NULL), + m_pOriginalImage(NULL), + m_pOriginalGroupTitle(NULL), + m_newOriginalEdit(false), + m_delayedTimer(this), + m_confirmed(false), + m_focusedControl(0), + m_fadedControl(0) +{ + m_loadType = KEEP_IN_MEMORY; +} + +CGUIDialogSettingsBase::~CGUIDialogSettingsBase() +{ + FreeControls(); + DeleteControls(); +} + +bool CGUIDialogSettingsBase::OnMessage(CGUIMessage& message) +{ + switch (message.GetMessage()) + { + case GUI_MSG_WINDOW_INIT: + { + m_delayedSetting.reset(); + if (message.GetParam1() != WINDOW_INVALID) + { // coming to this window first time (ie not returning back from some other window) + // so we reset our section and control states + m_iCategory = 0; + ResetControlStates(); + } + + if (AllowResettingSettings()) + { + m_resetSetting = std::make_shared<CSettingAction>(SETTINGS_RESET_SETTING_ID); + m_resetSetting->SetLabel(10041); + m_resetSetting->SetHelp(10045); + m_resetSetting->SetControl(CreateControl("button")); + } + + m_dummyCategory = std::make_shared<CSettingCategory>(SETTINGS_EMPTY_CATEGORY_ID); + m_dummyCategory->SetLabel(10046); + m_dummyCategory->SetHelp(10047); + break; + } + + case GUI_MSG_WINDOW_DEINIT: + { + // cancel any delayed changes + if (m_delayedSetting != NULL) + { + m_delayedTimer.Stop(); + CGUIMessage message(GUI_MSG_UPDATE_ITEM, GetID(), m_delayedSetting->GetID()); + OnMessage(message); + } + + CGUIDialog::OnMessage(message); + FreeControls(); + return true; + } + + case GUI_MSG_FOCUSED: + { + CGUIDialog::OnMessage(message); + m_focusedControl = GetFocusedControlID(); + + // cancel any delayed changes + if (m_delayedSetting != NULL && m_delayedSetting->GetID() != m_focusedControl) + { + m_delayedTimer.Stop(); + // param1 = 1 for "reset the control if it's invalid" + CGUIMessage message(GUI_MSG_UPDATE_ITEM, GetID(), m_delayedSetting->GetID(), 1); + CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(message, GetID()); + } + // update the value of the previous setting (in case it was invalid) + else if (m_iSetting >= CONTROL_SETTINGS_START_CONTROL && + m_iSetting < (int)(CONTROL_SETTINGS_START_CONTROL + m_settingControls.size())) + { + BaseSettingControlPtr control = GetSettingControl(m_iSetting); + if (control != NULL && control->GetSetting() != NULL && !control->IsValid()) + { + // param1 = 1 for "reset the control if it's invalid" + // param2 = 1 for "only update the current value" + CGUIMessage message(GUI_MSG_UPDATE_ITEM, GetID(), m_iSetting, 1, 1); + CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(message, GetID()); + } + } + + CVariant description; + + // check if we have changed the category and need to create new setting controls + if (m_focusedControl >= CONTROL_SETTINGS_START_BUTTONS && + m_focusedControl < (int)(CONTROL_SETTINGS_START_BUTTONS + m_categories.size())) + { + int categoryIndex = m_focusedControl - CONTROL_SETTINGS_START_BUTTONS; + SettingCategoryPtr category = m_categories.at(categoryIndex); + if (categoryIndex != m_iCategory) + { + if (!category->CanAccess()) + { + // unable to go to this category - focus the previous one + SET_CONTROL_FOCUS(CONTROL_SETTINGS_START_BUTTONS + m_iCategory, 0); + return false; + } + + m_iCategory = categoryIndex; + CreateSettings(); + } + + description = category->GetHelp(); + } + else if (m_focusedControl >= CONTROL_SETTINGS_START_CONTROL && + m_focusedControl < (int)(CONTROL_SETTINGS_START_CONTROL + m_settingControls.size())) + { + m_iSetting = m_focusedControl; + std::shared_ptr<CSetting> setting = GetSettingControl(m_focusedControl)->GetSetting(); + if (setting != NULL) + description = setting->GetHelp(); + } + + // set the description of the currently focused category/setting + if (description.isInteger() || (description.isString() && !description.empty())) + SetDescription(description); + + return true; + } + + case GUI_MSG_CLICKED: + { + int iControl = message.GetSenderId(); + if (iControl == CONTROL_SETTINGS_OKAY_BUTTON) + { + if (OnOkay()) + { + Close(); + return true; + } + + return false; + } + + if (iControl == CONTROL_SETTINGS_CANCEL_BUTTON) + { + OnCancel(); + Close(); + return true; + } + + BaseSettingControlPtr control = GetSettingControl(iControl); + if (control != NULL) + OnClick(control); + + break; + } + + case GUI_MSG_UPDATE_ITEM: + { + if (m_delayedSetting != NULL && m_delayedSetting->GetID() == message.GetControlId()) + { + // first get the delayed setting and reset its member variable + // to avoid handling the delayed setting twice in case the OnClick() + // performed later causes the window to be deinitialized (e.g. when + // changing the language) + BaseSettingControlPtr delayedSetting = m_delayedSetting; + m_delayedSetting.reset(); + + // if updating the setting fails and param1 has been specifically set + // we need to call OnSettingChanged() to restore a valid value in the + // setting control + if (!delayedSetting->OnClick() && message.GetParam1() != 0) + OnSettingChanged(delayedSetting->GetSetting()); + return true; + } + + if (message.GetControlId() >= CONTROL_SETTINGS_START_CONTROL && + message.GetControlId() < (int)(CONTROL_SETTINGS_START_CONTROL + m_settingControls.size())) + { + BaseSettingControlPtr settingControl = GetSettingControl(message.GetControlId()); + if (settingControl.get() != NULL && settingControl->GetSetting() != NULL) + { + settingControl->UpdateFromSetting(message.GetParam2() != 0); + return true; + } + } + break; + } + + case GUI_MSG_UPDATE: + { + if (IsActive() && HasID(message.GetSenderId())) + { + int focusedControl = GetFocusedControlID(); + CreateSettings(); + SET_CONTROL_FOCUS(focusedControl, 0); + } + break; + } + + default: + break; + } + + return CGUIDialog::OnMessage(message); +} + +bool CGUIDialogSettingsBase::OnAction(const CAction& action) +{ + switch (action.GetID()) + { + case ACTION_SETTINGS_RESET: + { + OnResetSettings(); + return true; + } + + case ACTION_DELETE_ITEM: + { + if (m_iSetting >= CONTROL_SETTINGS_START_CONTROL && + m_iSetting < (int)(CONTROL_SETTINGS_START_CONTROL + m_settingControls.size())) + { + auto settingControl = GetSettingControl(m_iSetting); + if (settingControl != nullptr) + { + std::shared_ptr<CSetting> setting = settingControl->GetSetting(); + if (setting != nullptr) + { + setting->Reset(); + return true; + } + } + } + break; + } + + default: + break; + } + + return CGUIDialog::OnAction(action); +} + +bool CGUIDialogSettingsBase::OnBack(int actionID) +{ + m_lastControlID = 0; // don't save the control as we go to a different window each time + + // if the setting dialog is not a window but a dialog we need to close differently + if (!IsDialog()) + return CGUIWindow::OnBack(actionID); + + return CGUIDialog::OnBack(actionID); +} + +void CGUIDialogSettingsBase::DoProcess(unsigned int currentTime, CDirtyRegionList& dirtyregions) +{ + // update alpha status of current button + CGUIControl* control = GetFirstFocusableControl(CONTROL_SETTINGS_START_BUTTONS + m_iCategory); + if (control) + { + if (m_fadedControl && + (m_fadedControl != control->GetID() || m_fadedControl == m_focusedControl)) + { + if (control->GetControlType() == CGUIControl::GUICONTROL_BUTTON) + static_cast<CGUIButtonControl*>(control)->SetAlpha(0xFF); + else + static_cast<CGUIButtonControl*>(control)->SetSelected(false); + m_fadedControl = 0; + } + + if (!control->HasFocus()) + { + m_fadedControl = control->GetID(); + if (control->GetControlType() == CGUIControl::GUICONTROL_BUTTON) + static_cast<CGUIButtonControl*>(control)->SetAlpha(0x80); + else if (control->GetControlType() == CGUIControl::GUICONTROL_TOGGLEBUTTON) + static_cast<CGUIButtonControl*>(control)->SetSelected(true); + else + m_fadedControl = 0; + + if (m_fadedControl) + control->SetFocus(true); + } + } + CGUIDialog::DoProcess(currentTime, dirtyregions); +} + +void CGUIDialogSettingsBase::OnInitWindow() +{ + m_confirmed = false; + SetupView(); + CGUIDialog::OnInitWindow(); +} + +void CGUIDialogSettingsBase::SetupControls(bool createSettings /* = true */) +{ + // cleanup first, if necessary + FreeControls(); + + // get all controls + m_pOriginalSpin = dynamic_cast<CGUISpinControlEx*>(GetControl(CONTROL_DEFAULT_SPIN)); + m_pOriginalSlider = dynamic_cast<CGUISettingsSliderControl*>(GetControl(CONTROL_DEFAULT_SLIDER)); + m_pOriginalRadioButton = + dynamic_cast<CGUIRadioButtonControl*>(GetControl(CONTROL_DEFAULT_RADIOBUTTON)); + m_pOriginalCategoryButton = + dynamic_cast<CGUIButtonControl*>(GetControl(CONTROL_DEFAULT_CATEGORY_BUTTON)); + m_pOriginalButton = dynamic_cast<CGUIButtonControl*>(GetControl(CONTROL_DEFAULT_BUTTON)); + m_pOriginalImage = dynamic_cast<CGUIImage*>(GetControl(CONTROL_DEFAULT_SEPARATOR)); + m_pOriginalEdit = dynamic_cast<CGUIEditControl*>(GetControl(CONTROL_DEFAULT_EDIT)); + m_pOriginalGroupTitle = + dynamic_cast<CGUILabelControl*>(GetControl(CONTROL_DEFAULT_SETTING_LABEL)); + m_pOriginalColorButton = + dynamic_cast<CGUIColorButtonControl*>(GetControl(CONTROL_DEFAULT_COLORBUTTON)); + + // if there's no edit control but there's a button control use that instead + if (m_pOriginalEdit == nullptr && m_pOriginalButton != nullptr) + { + m_pOriginalEdit = new CGUIEditControl(*m_pOriginalButton); + m_newOriginalEdit = true; + } + + // hide all default controls by default + if (m_pOriginalSpin != nullptr) + m_pOriginalSpin->SetVisible(false); + if (m_pOriginalSlider != nullptr) + m_pOriginalSlider->SetVisible(false); + if (m_pOriginalRadioButton != nullptr) + m_pOriginalRadioButton->SetVisible(false); + if (m_pOriginalButton != nullptr) + m_pOriginalButton->SetVisible(false); + if (m_pOriginalCategoryButton != nullptr) + m_pOriginalCategoryButton->SetVisible(false); + if (m_pOriginalEdit != nullptr) + m_pOriginalEdit->SetVisible(false); + if (m_pOriginalImage != nullptr) + m_pOriginalImage->SetVisible(false); + if (m_pOriginalGroupTitle != nullptr) + m_pOriginalGroupTitle->SetVisible(false); + if (m_pOriginalColorButton != nullptr) + m_pOriginalColorButton->SetVisible(false); + + // get the section + SettingSectionPtr section = GetSection(); + if (section == NULL) + return; + + // update the screen string + if (section->GetLabel() >= 0) + SetHeading(section->GetLabel()); + + // get the categories we need + m_categories = section->GetCategories((SettingLevel)GetSettingLevel()); + if (m_categories.empty()) + m_categories.push_back(m_dummyCategory); + + if (m_pOriginalCategoryButton != NULL) + { + // setup our control groups... + CGUIControlGroupList* group = + dynamic_cast<CGUIControlGroupList*>(GetControl(CATEGORY_GROUP_ID)); + if (!group) + return; + + // go through the categories and create the necessary buttons + int buttonIdOffset = 0; + for (SettingCategoryList::const_iterator category = m_categories.begin(); + category != m_categories.end(); ++category) + { + CGUIButtonControl* pButton = NULL; + if (m_pOriginalCategoryButton->GetControlType() == CGUIControl::GUICONTROL_TOGGLEBUTTON) + pButton = new CGUIToggleButtonControl( + *static_cast<CGUIToggleButtonControl*>(m_pOriginalCategoryButton)); + else if (m_pOriginalCategoryButton->GetControlType() == CGUIControl::GUICONTROL_COLORBUTTON) + pButton = new CGUIColorButtonControl( + *static_cast<CGUIColorButtonControl*>(m_pOriginalCategoryButton)); + else + pButton = new CGUIButtonControl(*m_pOriginalCategoryButton); + pButton->SetLabel(GetSettingsLabel(*category)); + pButton->SetID(CONTROL_SETTINGS_START_BUTTONS + buttonIdOffset); + pButton->SetVisible(true); + pButton->AllocResources(); + + group->AddControl(pButton); + buttonIdOffset++; + } + } + + if (createSettings) + CreateSettings(); + + // set focus correctly depending on whether there are categories visible or not + if (m_pOriginalCategoryButton == NULL && + (m_defaultControl <= 0 || m_defaultControl == CATEGORY_GROUP_ID)) + m_defaultControl = SETTINGS_GROUP_ID; + else if (m_pOriginalCategoryButton != NULL && m_defaultControl <= 0) + m_defaultControl = CATEGORY_GROUP_ID; +} + +void CGUIDialogSettingsBase::FreeControls() +{ + // clear the category group + CGUIControlGroupList* control = + dynamic_cast<CGUIControlGroupList*>(GetControl(CATEGORY_GROUP_ID)); + if (control) + { + control->FreeResources(); + control->ClearAll(); + } + m_categories.clear(); + FreeSettingsControls(); +} + +void CGUIDialogSettingsBase::DeleteControls() +{ + if (m_newOriginalEdit) + { + delete m_pOriginalEdit; + m_pOriginalEdit = NULL; + } + + m_resetSetting.reset(); + m_dummyCategory.reset(); +} + +void CGUIDialogSettingsBase::FreeSettingsControls() +{ + // clear the settings group + CGUIControlGroupList* control = + dynamic_cast<CGUIControlGroupList*>(GetControl(SETTINGS_GROUP_ID)); + if (control) + { + control->FreeResources(); + control->ClearAll(); + } + + for (std::vector<BaseSettingControlPtr>::iterator control = m_settingControls.begin(); + control != m_settingControls.end(); ++control) + (*control)->Clear(); + + m_settingControls.clear(); +} + +void CGUIDialogSettingsBase::OnTimeout() +{ + UpdateSettingControl(m_delayedSetting, true); +} + +void CGUIDialogSettingsBase::OnSettingChanged(const std::shared_ptr<const CSetting>& setting) +{ + if (setting == NULL || setting->GetType() == SettingType::Unknown || + setting->GetType() == SettingType::Action) + return; + + UpdateSettingControl(setting->GetId(), true); +} + +void CGUIDialogSettingsBase::OnSettingPropertyChanged( + const std::shared_ptr<const CSetting>& setting, const char* propertyName) +{ + if (setting == NULL || propertyName == NULL) + return; + + UpdateSettingControl(setting->GetId()); +} + +std::string CGUIDialogSettingsBase::GetLocalizedString(uint32_t labelId) const +{ + return g_localizeStrings.Get(labelId); +} + +void CGUIDialogSettingsBase::SetupView() +{ + SetupControls(); +} + +std::set<std::string> CGUIDialogSettingsBase::CreateSettings() +{ + FreeSettingsControls(); + + std::set<std::string> settingMap; + + if (m_categories.size() <= 0) + return settingMap; + + if (m_iCategory < 0 || m_iCategory >= (int)m_categories.size()) + m_iCategory = 0; + + CGUIControlGroupList* group = dynamic_cast<CGUIControlGroupList*>(GetControl(SETTINGS_GROUP_ID)); + if (group == NULL) + return settingMap; + + SettingCategoryPtr category = m_categories.at(m_iCategory); + if (category == NULL) + return settingMap; + + // set the description of the current category + SetDescription(category->GetHelp()); + + const SettingGroupList& groups = category->GetGroups((SettingLevel)GetSettingLevel()); + int iControlID = CONTROL_SETTINGS_START_CONTROL; + bool first = true; + for (SettingGroupList::const_iterator groupIt = groups.begin(); groupIt != groups.end(); + ++groupIt) + { + if (*groupIt == NULL) + continue; + + const SettingList& settings = (*groupIt)->GetSettings((SettingLevel)GetSettingLevel()); + if (settings.size() <= 0) + continue; + + std::shared_ptr<const CSettingControlTitle> title = + std::dynamic_pointer_cast<const CSettingControlTitle>((*groupIt)->GetControl()); + bool hideSeparator = title ? title->IsSeparatorHidden() : false; + bool separatorBelowGroupLabel = title ? title->IsSeparatorBelowLabel() : false; + int groupLabel = (*groupIt)->GetLabel(); + + // hide the separator for the first settings grouplist if it + // is the very first item in the list (also above the label) + if (first) + { + first = false; + if (groupLabel <= 0) + hideSeparator = true; + } + else if (!separatorBelowGroupLabel && !hideSeparator) + AddSeparator(group->GetWidth(), iControlID); + + if (groupLabel > 0) + AddGroupLabel(*groupIt, group->GetWidth(), iControlID); + + if (separatorBelowGroupLabel && !hideSeparator) + AddSeparator(group->GetWidth(), iControlID); + + for (SettingList::const_iterator settingIt = settings.begin(); settingIt != settings.end(); + ++settingIt) + { + const std::shared_ptr<CSetting>& pSetting = *settingIt; + settingMap.insert(pSetting->GetId()); + AddSetting(pSetting, group->GetWidth(), iControlID); + } + } + + if (AllowResettingSettings() && !settingMap.empty()) + { + // add "Reset" control + AddSeparator(group->GetWidth(), iControlID); + AddSetting(m_resetSetting, group->GetWidth(), iControlID); + } + + // update our settings (turns controls on/off as appropriate) + UpdateSettings(); + + group->SetInvalid(); + + return settingMap; +} + +std::string CGUIDialogSettingsBase::GetSettingsLabel(const std::shared_ptr<ISetting>& pSetting) +{ + return GetLocalizedString(pSetting->GetLabel()); +} + +void CGUIDialogSettingsBase::UpdateSettings() +{ + for (std::vector<BaseSettingControlPtr>::iterator it = m_settingControls.begin(); + it != m_settingControls.end(); ++it) + { + BaseSettingControlPtr pSettingControl = *it; + std::shared_ptr<CSetting> pSetting = pSettingControl->GetSetting(); + CGUIControl* pControl = pSettingControl->GetControl(); + if (pSetting == NULL || pControl == NULL) + continue; + + pSettingControl->UpdateFromSetting(); + } +} + +CGUIControl* CGUIDialogSettingsBase::AddSetting(const std::shared_ptr<CSetting>& pSetting, + float width, + int& iControlID) +{ + if (pSetting == NULL) + return NULL; + + BaseSettingControlPtr pSettingControl; + CGUIControl* pControl = NULL; + + // determine the label and any possible indentation in case of sub settings + std::string label = GetSettingsLabel(pSetting); + int parentLevels = 0; + std::shared_ptr<CSetting> parentSetting = GetSetting(pSetting->GetParent()); + while (parentSetting != NULL) + { + parentLevels++; + parentSetting = GetSetting(parentSetting->GetParent()); + } + + if (parentLevels > 0) + { + // add additional 2 spaces indentation for anything past one level + std::string indentation; + for (int index = 1; index < parentLevels; index++) + indentation.append(" "); + label = StringUtils::Format(g_localizeStrings.Get(168), indentation, label); + } + + // create the proper controls + if (!pSetting->GetControl()) + return NULL; + + std::string controlType = pSetting->GetControl()->GetType(); + if (controlType == "toggle") + { + if (m_pOriginalRadioButton != NULL) + pControl = m_pOriginalRadioButton->Clone(); + if (pControl == NULL) + return NULL; + + static_cast<CGUIRadioButtonControl*>(pControl)->SetLabel(label); + pSettingControl.reset(new CGUIControlRadioButtonSetting( + static_cast<CGUIRadioButtonControl*>(pControl), iControlID, pSetting, this)); + } + else if (controlType == "spinner") + { + if (m_pOriginalSpin != NULL) + pControl = new CGUISpinControlEx(*m_pOriginalSpin); + if (pControl == NULL) + return NULL; + + static_cast<CGUISpinControlEx*>(pControl)->SetText(label); + pSettingControl.reset(new CGUIControlSpinExSetting(static_cast<CGUISpinControlEx*>(pControl), + iControlID, pSetting, this)); + } + else if (controlType == "edit") + { + if (m_pOriginalEdit != NULL) + pControl = new CGUIEditControl(*m_pOriginalEdit); + if (pControl == NULL) + return NULL; + + static_cast<CGUIEditControl*>(pControl)->SetLabel(label); + pSettingControl.reset(new CGUIControlEditSetting(static_cast<CGUIEditControl*>(pControl), + iControlID, pSetting, this)); + } + else if (controlType == "list") + { + if (m_pOriginalButton != NULL) + pControl = new CGUIButtonControl(*m_pOriginalButton); + if (pControl == NULL) + return NULL; + + static_cast<CGUIButtonControl*>(pControl)->SetLabel(label); + pSettingControl.reset(new CGUIControlListSetting(static_cast<CGUIButtonControl*>(pControl), + iControlID, pSetting, this)); + } + else if (controlType == "button" || controlType == "slider") + { + if (controlType == "button" || + std::static_pointer_cast<const CSettingControlSlider>(pSetting->GetControl())->UsePopup()) + { + if (m_pOriginalButton != NULL) + pControl = new CGUIButtonControl(*m_pOriginalButton); + if (pControl == NULL) + return NULL; + + static_cast<CGUIButtonControl*>(pControl)->SetLabel(label); + pSettingControl.reset(new CGUIControlButtonSetting(static_cast<CGUIButtonControl*>(pControl), + iControlID, pSetting, this)); + } + else + { + if (m_pOriginalSlider != NULL) + pControl = m_pOriginalSlider->Clone(); + if (pControl == NULL) + return NULL; + + static_cast<CGUISettingsSliderControl*>(pControl)->SetText(label); + pSettingControl.reset(new CGUIControlSliderSetting( + static_cast<CGUISettingsSliderControl*>(pControl), iControlID, pSetting, this)); + } + } + else if (controlType == "range") + { + if (m_pOriginalSlider != NULL) + pControl = m_pOriginalSlider->Clone(); + if (pControl == NULL) + return NULL; + + static_cast<CGUISettingsSliderControl*>(pControl)->SetText(label); + pSettingControl.reset(new CGUIControlRangeSetting( + static_cast<CGUISettingsSliderControl*>(pControl), iControlID, pSetting, this)); + } + else if (controlType == "label") + { + if (m_pOriginalButton != NULL) + pControl = new CGUIButtonControl(*m_pOriginalButton); + if (pControl == NULL) + return NULL; + + static_cast<CGUIButtonControl*>(pControl)->SetLabel(label); + pSettingControl.reset(new CGUIControlLabelSetting(static_cast<CGUIButtonControl*>(pControl), + iControlID, pSetting, this)); + } + else if (controlType == "colorbutton") + { + if (m_pOriginalColorButton) + pControl = m_pOriginalColorButton->Clone(); + if (pControl == nullptr) + return nullptr; + + static_cast<CGUIColorButtonControl*>(pControl)->SetLabel(label); + pSettingControl.reset(new CGUIControlColorButtonSetting( + static_cast<CGUIColorButtonControl*>(pControl), iControlID, pSetting, this)); + } + else + return nullptr; + + if (pSetting->GetControl()->GetDelayed()) + pSettingControl->SetDelayed(); + + return AddSettingControl(pControl, pSettingControl, width, iControlID); +} + +CGUIControl* CGUIDialogSettingsBase::AddSeparator(float width, int& iControlID) +{ + if (m_pOriginalImage == NULL) + return NULL; + + CGUIControl* pControl = new CGUIImage(*m_pOriginalImage); + if (pControl == NULL) + return NULL; + + return AddSettingControl(pControl, + BaseSettingControlPtr(new CGUIControlSeparatorSetting( + static_cast<CGUIImage*>(pControl), iControlID, this)), + width, iControlID); +} + +CGUIControl* CGUIDialogSettingsBase::AddGroupLabel(const std::shared_ptr<CSettingGroup>& group, + float width, + int& iControlID) +{ + if (m_pOriginalGroupTitle == NULL) + return NULL; + + CGUIControl* pControl = new CGUILabelControl(*m_pOriginalGroupTitle); + if (pControl == NULL) + return NULL; + + static_cast<CGUILabelControl*>(pControl)->SetLabel(GetSettingsLabel(group)); + + return AddSettingControl(pControl, + BaseSettingControlPtr(new CGUIControlGroupTitleSetting( + static_cast<CGUILabelControl*>(pControl), iControlID, this)), + width, iControlID); +} + +CGUIControl* CGUIDialogSettingsBase::AddSettingControl(CGUIControl* pControl, + BaseSettingControlPtr pSettingControl, + float width, + int& iControlID) +{ + if (pControl == NULL) + { + pSettingControl.reset(); + return NULL; + } + + pControl->SetID(iControlID++); + pControl->SetVisible(true); + pControl->SetWidth(width); + + CGUIControlGroupList* group = dynamic_cast<CGUIControlGroupList*>(GetControl(SETTINGS_GROUP_ID)); + if (group != NULL) + { + pControl->AllocResources(); + group->AddControl(pControl); + } + m_settingControls.push_back(pSettingControl); + + return pControl; +} + +void CGUIDialogSettingsBase::SetHeading(const CVariant& label) +{ + SetControlLabel(CONTROL_SETTINGS_LABEL, label); +} + +void CGUIDialogSettingsBase::SetDescription(const CVariant& label) +{ + SetControlLabel(CONTROL_SETTINGS_DESCRIPTION, label); +} + +void CGUIDialogSettingsBase::OnResetSettings() +{ + if (CGUIDialogYesNo::ShowAndGetInput(CVariant{10041}, CVariant{10042})) + { + for (std::vector<BaseSettingControlPtr>::iterator it = m_settingControls.begin(); + it != m_settingControls.end(); ++it) + { + std::shared_ptr<CSetting> setting = (*it)->GetSetting(); + if (setting != NULL) + setting->Reset(); + } + } +} + +void CGUIDialogSettingsBase::OnClick(const BaseSettingControlPtr& pSettingControl) +{ + if (AllowResettingSettings() && + pSettingControl->GetSetting()->GetId() == SETTINGS_RESET_SETTING_ID) + { + OnAction(CAction(ACTION_SETTINGS_RESET)); + return; + } + + // we need to first set the delayed setting and then execute OnClick() + // because OnClick() triggers OnSettingChanged() and there we need to + // know if the changed setting is delayed or not + if (pSettingControl->IsDelayed()) + { + m_delayedSetting = pSettingControl; + // for some controls we need to update its displayed data/text before + // OnClick() is called after the delay timer has expired because + // otherwise the displayed value of the control does not match with + // the user's interaction + pSettingControl->UpdateFromControl(); + + // either start or restart the delay timer which will result in a call to + // the control's OnClick() method to update the setting's value + if (m_delayedTimer.IsRunning()) + m_delayedTimer.Restart(); + else + m_delayedTimer.Start(GetDelayMs()); + + return; + } + + // if changing the setting fails + // we need to restore the proper state + if (!pSettingControl->OnClick()) + pSettingControl->UpdateFromSetting(); +} + +void CGUIDialogSettingsBase::UpdateSettingControl(const std::string& settingId, + bool updateDisplayOnly /* = false */) +{ + if (settingId.empty()) + return; + + return UpdateSettingControl(GetSettingControl(settingId), updateDisplayOnly); +} + +void CGUIDialogSettingsBase::UpdateSettingControl(const BaseSettingControlPtr& pSettingControl, + bool updateDisplayOnly /* = false */) +{ + if (pSettingControl == NULL) + return; + + // we send a thread message so that it's processed the following frame (some settings won't + // like being changed during Render()) + // param2 = 1 for "only update the current value" + CGUIMessage message(GUI_MSG_UPDATE_ITEM, GetID(), pSettingControl->GetID(), 0, + updateDisplayOnly ? 1 : 0); + CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(message, GetID()); +} + +void CGUIDialogSettingsBase::SetControlLabel(int controlId, const CVariant& label) +{ + if (GetControl(controlId) == NULL) + return; + + if (label.isString()) + SET_CONTROL_LABEL(controlId, label.asString()); + else if (label.isInteger() && label.asInteger() >= 0) + { + int labelId = static_cast<uint32_t>(label.asInteger()); + std::string localizedString = GetLocalizedString(labelId); + if (!localizedString.empty()) + SET_CONTROL_LABEL(controlId, localizedString); + else + SET_CONTROL_LABEL(controlId, labelId); + } + else + SET_CONTROL_LABEL(controlId, ""); +} + +BaseSettingControlPtr CGUIDialogSettingsBase::GetSettingControl(const std::string& strSetting) +{ + for (std::vector<BaseSettingControlPtr>::iterator control = m_settingControls.begin(); + control != m_settingControls.end(); ++control) + { + if ((*control)->GetSetting() != NULL && (*control)->GetSetting()->GetId() == strSetting) + return *control; + } + + return BaseSettingControlPtr(); +} + +BaseSettingControlPtr CGUIDialogSettingsBase::GetSettingControl(int controlId) +{ + if (controlId < CONTROL_SETTINGS_START_CONTROL || + controlId >= (int)(CONTROL_SETTINGS_START_CONTROL + m_settingControls.size())) + return BaseSettingControlPtr(); + + return m_settingControls[controlId - CONTROL_SETTINGS_START_CONTROL]; +} |