[PVR][Estuary] Timer settings dialog: Show client name in timer type selection dialog...
[xbmc.git] / xbmc / settings / windows / GUIControlSettings.cpp
blobfcbf1fa9086e1fc47e888994a406e461a8b95ee1
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "GUIControlSettings.h"
11 #include "FileItem.h"
12 #include "ServiceBroker.h"
13 #include "Util.h"
14 #include "addons/AddonManager.h"
15 #include "addons/gui/GUIWindowAddonBrowser.h"
16 #include "addons/settings/SettingUrlEncodedString.h"
17 #include "dialogs/GUIDialogColorPicker.h"
18 #include "dialogs/GUIDialogFileBrowser.h"
19 #include "dialogs/GUIDialogNumeric.h"
20 #include "dialogs/GUIDialogSelect.h"
21 #include "dialogs/GUIDialogSlider.h"
22 #include "guilib/GUIColorButtonControl.h"
23 #include "guilib/GUIComponent.h"
24 #include "guilib/GUIEditControl.h"
25 #include "guilib/GUIImage.h"
26 #include "guilib/GUIKeyboardFactory.h"
27 #include "guilib/GUILabelControl.h"
28 #include "guilib/GUIRadioButtonControl.h"
29 #include "guilib/GUISettingsSliderControl.h"
30 #include "guilib/GUISpinControlEx.h"
31 #include "guilib/GUIWindowManager.h"
32 #include "guilib/LocalizeStrings.h"
33 #include "settings/MediaSourceSettings.h"
34 #include "settings/SettingAddon.h"
35 #include "settings/SettingControl.h"
36 #include "settings/SettingDateTime.h"
37 #include "settings/SettingPath.h"
38 #include "settings/SettingUtils.h"
39 #include "settings/lib/Setting.h"
40 #include "settings/lib/SettingDefinitions.h"
41 #include "storage/MediaManager.h"
42 #include "utils/FileExtensionProvider.h"
43 #include "utils/StringUtils.h"
44 #include "utils/Variant.h"
45 #include "utils/log.h"
47 #include <set>
48 #include <utility>
50 using namespace ADDON;
52 static std::string Localize(std::uint32_t code,
53 ILocalizer* localizer,
54 const std::string& addonId = "")
56 if (localizer == nullptr)
57 return "";
59 if (!addonId.empty())
61 std::string label = g_localizeStrings.GetAddonString(addonId, code);
62 if (!label.empty())
63 return label;
66 return localizer->Localize(code);
69 template<typename TValueType>
70 static CFileItemPtr GetFileItem(const std::string& label,
71 const std::string& label2,
72 const TValueType& value,
73 const std::vector<std::pair<std::string, CVariant>>& properties,
74 const std::set<TValueType>& selectedValues)
76 CFileItemPtr item(new CFileItem(label));
77 item->SetProperty("value", value);
78 item->SetLabel2(label2);
80 for (const auto& prop : properties)
81 item->SetProperty(prop.first, prop.second);
83 if (selectedValues.find(value) != selectedValues.end())
84 item->Select(true);
86 return item;
89 template<class SettingOption>
90 static bool CompareSettingOptionAseconding(const SettingOption& lhs, const SettingOption& rhs)
92 return StringUtils::CompareNoCase(lhs.label, rhs.label) < 0;
95 template<class SettingOption>
96 static bool CompareSettingOptionDeseconding(const SettingOption& lhs, const SettingOption& rhs)
98 return StringUtils::CompareNoCase(lhs.label, rhs.label) > 0;
101 static bool GetIntegerOptions(const SettingConstPtr& setting,
102 IntegerSettingOptions& options,
103 std::set<int>& selectedOptions,
104 ILocalizer* localizer,
105 bool updateOptions)
107 std::shared_ptr<const CSettingInt> pSettingInt = NULL;
108 if (setting->GetType() == SettingType::Integer)
109 pSettingInt = std::static_pointer_cast<const CSettingInt>(setting);
110 else if (setting->GetType() == SettingType::List)
112 std::shared_ptr<const CSettingList> settingList =
113 std::static_pointer_cast<const CSettingList>(setting);
114 if (settingList->GetElementType() != SettingType::Integer)
115 return false;
117 pSettingInt = std::static_pointer_cast<const CSettingInt>(settingList->GetDefinition());
120 switch (pSettingInt->GetOptionsType())
122 case SettingOptionsType::StaticTranslatable:
124 const TranslatableIntegerSettingOptions& settingOptions =
125 pSettingInt->GetTranslatableOptions();
126 for (const auto& option : settingOptions)
127 options.push_back(
128 IntegerSettingOption(Localize(option.label, localizer, option.addonId), option.value));
129 break;
132 case SettingOptionsType::Static:
134 const IntegerSettingOptions& settingOptions = pSettingInt->GetOptions();
135 options.insert(options.end(), settingOptions.begin(), settingOptions.end());
136 break;
139 case SettingOptionsType::Dynamic:
141 IntegerSettingOptions settingOptions;
142 if (updateOptions)
143 settingOptions = std::const_pointer_cast<CSettingInt>(pSettingInt)->UpdateDynamicOptions();
144 else
145 settingOptions = pSettingInt->GetDynamicOptions();
146 options.insert(options.end(), settingOptions.begin(), settingOptions.end());
147 break;
150 case SettingOptionsType::Unknown:
151 default:
153 std::shared_ptr<const CSettingControlFormattedRange> control =
154 std::static_pointer_cast<const CSettingControlFormattedRange>(pSettingInt->GetControl());
155 for (int i = pSettingInt->GetMinimum(); i <= pSettingInt->GetMaximum();
156 i += pSettingInt->GetStep())
158 std::string strLabel;
159 if (i == pSettingInt->GetMinimum() && control->GetMinimumLabel() > -1)
160 strLabel = Localize(control->GetMinimumLabel(), localizer);
161 else if (control->GetFormatLabel() > -1)
162 strLabel = StringUtils::Format(Localize(control->GetFormatLabel(), localizer), i);
163 else
164 strLabel = StringUtils::Format(control->GetFormatString(), i);
166 options.push_back(IntegerSettingOption(strLabel, i));
169 break;
173 switch (pSettingInt->GetOptionsSort())
175 case SettingOptionsSort::Ascending:
176 std::sort(options.begin(), options.end(),
177 CompareSettingOptionAseconding<IntegerSettingOption>);
178 break;
180 case SettingOptionsSort::Descending:
181 std::sort(options.begin(), options.end(),
182 CompareSettingOptionDeseconding<IntegerSettingOption>);
183 break;
185 case SettingOptionsSort::NoSorting:
186 default:
187 break;
190 // this must be done after potentially calling CSettingInt::UpdateDynamicOptions() because it can
191 // change the value of the setting
192 if (setting->GetType() == SettingType::Integer)
193 selectedOptions.insert(pSettingInt->GetValue());
194 else if (setting->GetType() == SettingType::List)
196 std::vector<CVariant> list =
197 CSettingUtils::GetList(std::static_pointer_cast<const CSettingList>(setting));
198 for (const auto& itValue : list)
199 selectedOptions.insert((int)itValue.asInteger());
201 else
202 return false;
204 return true;
207 static bool GetStringOptions(const SettingConstPtr& setting,
208 StringSettingOptions& options,
209 std::set<std::string>& selectedOptions,
210 ILocalizer* localizer,
211 bool updateOptions)
213 std::shared_ptr<const CSettingString> pSettingString = NULL;
214 if (setting->GetType() == SettingType::String)
215 pSettingString = std::static_pointer_cast<const CSettingString>(setting);
216 else if (setting->GetType() == SettingType::List)
218 std::shared_ptr<const CSettingList> settingList =
219 std::static_pointer_cast<const CSettingList>(setting);
220 if (settingList->GetElementType() != SettingType::String)
221 return false;
223 pSettingString = std::static_pointer_cast<const CSettingString>(settingList->GetDefinition());
226 switch (pSettingString->GetOptionsType())
228 case SettingOptionsType::StaticTranslatable:
230 const TranslatableStringSettingOptions& settingOptions =
231 pSettingString->GetTranslatableOptions();
232 for (const auto& option : settingOptions)
233 options.push_back(StringSettingOption(Localize(option.first, localizer), option.second));
234 break;
237 case SettingOptionsType::Static:
239 const StringSettingOptions& settingOptions = pSettingString->GetOptions();
240 options.insert(options.end(), settingOptions.begin(), settingOptions.end());
241 break;
244 case SettingOptionsType::Dynamic:
246 StringSettingOptions settingOptions;
247 if (updateOptions)
248 settingOptions =
249 std::const_pointer_cast<CSettingString>(pSettingString)->UpdateDynamicOptions();
250 else
251 settingOptions = pSettingString->GetDynamicOptions();
252 options.insert(options.end(), settingOptions.begin(), settingOptions.end());
253 break;
256 case SettingOptionsType::Unknown:
257 default:
258 return false;
261 switch (pSettingString->GetOptionsSort())
263 case SettingOptionsSort::Ascending:
264 std::sort(options.begin(), options.end(),
265 CompareSettingOptionAseconding<StringSettingOption>);
266 break;
268 case SettingOptionsSort::Descending:
269 std::sort(options.begin(), options.end(),
270 CompareSettingOptionDeseconding<StringSettingOption>);
271 break;
273 case SettingOptionsSort::NoSorting:
274 default:
275 break;
278 // this must be done after potentially calling CSettingString::UpdateDynamicOptions() because it
279 // can change the value of the setting
280 if (setting->GetType() == SettingType::String)
281 selectedOptions.insert(pSettingString->GetValue());
282 else if (setting->GetType() == SettingType::List)
284 std::vector<CVariant> list =
285 CSettingUtils::GetList(std::static_pointer_cast<const CSettingList>(setting));
286 for (const auto& itValue : list)
287 selectedOptions.insert(itValue.asString());
289 else
290 return false;
292 return true;
295 CGUIControlBaseSetting::CGUIControlBaseSetting(int id,
296 std::shared_ptr<CSetting> pSetting,
297 ILocalizer* localizer)
298 : m_id(id),
299 m_pSetting(std::move(pSetting)),
300 m_localizer(localizer),
301 m_delayed(false),
302 m_valid(true)
306 bool CGUIControlBaseSetting::IsEnabled() const
308 return m_pSetting != NULL && m_pSetting->IsEnabled();
311 void CGUIControlBaseSetting::UpdateFromControl()
313 Update(true, true);
316 void CGUIControlBaseSetting::UpdateFromSetting(bool updateDisplayOnly /* = false */)
318 Update(false, updateDisplayOnly);
321 std::string CGUIControlBaseSetting::Localize(std::uint32_t code) const
323 return ::Localize(code, m_localizer);
326 void CGUIControlBaseSetting::Update(bool fromControl, bool updateDisplayOnly)
328 if (fromControl || updateDisplayOnly)
329 return;
331 CGUIControl* control = GetControl();
332 if (control == NULL)
333 return;
335 control->SetEnabled(IsEnabled());
336 if (m_pSetting)
337 control->SetVisible(m_pSetting->IsVisible());
338 SetValid(true);
341 CGUIControlRadioButtonSetting::CGUIControlRadioButtonSetting(CGUIRadioButtonControl* pRadioButton,
342 int id,
343 std::shared_ptr<CSetting> pSetting,
344 ILocalizer* localizer)
345 : CGUIControlBaseSetting(id, std::move(pSetting), localizer)
347 m_pRadioButton = pRadioButton;
348 if (m_pRadioButton == NULL)
349 return;
351 m_pRadioButton->SetID(id);
354 CGUIControlRadioButtonSetting::~CGUIControlRadioButtonSetting() = default;
356 bool CGUIControlRadioButtonSetting::OnClick()
358 SetValid(std::static_pointer_cast<CSettingBool>(m_pSetting)
359 ->SetValue(!std::static_pointer_cast<CSettingBool>(m_pSetting)->GetValue()));
360 return IsValid();
363 void CGUIControlRadioButtonSetting::Update(bool fromControl, bool updateDisplayOnly)
365 if (fromControl || m_pRadioButton == NULL)
366 return;
368 CGUIControlBaseSetting::Update(fromControl, updateDisplayOnly);
370 m_pRadioButton->SetSelected(std::static_pointer_cast<CSettingBool>(m_pSetting)->GetValue());
373 CGUIControlColorButtonSetting::CGUIControlColorButtonSetting(
374 CGUIColorButtonControl* pColorControl,
375 int id,
376 const std::shared_ptr<CSetting>& pSetting,
377 ILocalizer* localizer)
378 : CGUIControlBaseSetting(id, pSetting, localizer)
380 m_pColorButton = pColorControl;
381 if (!m_pColorButton)
382 return;
384 m_pColorButton->SetID(id);
387 CGUIControlColorButtonSetting::~CGUIControlColorButtonSetting() = default;
389 bool CGUIControlColorButtonSetting::OnClick()
391 if (!m_pColorButton)
392 return false;
394 std::shared_ptr<CSettingString> settingHexColor =
395 std::static_pointer_cast<CSettingString>(m_pSetting);
397 CGUIDialogColorPicker* dialog =
398 CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogColorPicker>(
399 WINDOW_DIALOG_COLOR_PICKER);
400 if (!dialog)
401 return false;
403 dialog->Reset();
404 dialog->SetHeading(CVariant{Localize(m_pSetting->GetLabel())});
405 dialog->LoadColors();
406 std::string hexColor;
407 if (settingHexColor)
408 hexColor = settingHexColor.get()->GetValue();
409 dialog->SetSelectedColor(hexColor);
410 dialog->Open();
412 if (!dialog->IsConfirmed())
413 return false;
415 SetValid(
416 std::static_pointer_cast<CSettingString>(m_pSetting)->SetValue(dialog->GetSelectedColor()));
417 return IsValid();
420 void CGUIControlColorButtonSetting::Update(bool fromControl, bool updateDisplayOnly)
422 if (fromControl || !m_pColorButton)
423 return;
425 CGUIControlBaseSetting::Update(fromControl, updateDisplayOnly);
426 // Set the color to apply to the preview color box
427 m_pColorButton->SetImageBoxColor(
428 std::static_pointer_cast<CSettingString>(m_pSetting)->GetValue());
431 CGUIControlSpinExSetting::CGUIControlSpinExSetting(CGUISpinControlEx* pSpin,
432 int id,
433 std::shared_ptr<CSetting> pSetting,
434 ILocalizer* localizer)
435 : CGUIControlBaseSetting(id, std::move(pSetting), localizer)
437 m_pSpin = pSpin;
438 if (m_pSpin == NULL)
439 return;
441 m_pSpin->SetID(id);
443 const std::string& controlFormat = m_pSetting->GetControl()->GetFormat();
444 if (controlFormat == "number")
446 std::shared_ptr<CSettingNumber> pSettingNumber =
447 std::static_pointer_cast<CSettingNumber>(m_pSetting);
448 m_pSpin->SetType(SPIN_CONTROL_TYPE_FLOAT);
449 m_pSpin->SetFloatRange(static_cast<float>(pSettingNumber->GetMinimum()),
450 static_cast<float>(pSettingNumber->GetMaximum()));
451 m_pSpin->SetFloatInterval(static_cast<float>(pSettingNumber->GetStep()));
453 else if (controlFormat == "integer")
454 m_pSpin->SetType(SPIN_CONTROL_TYPE_TEXT);
455 else if (controlFormat == "string")
457 m_pSpin->SetType(SPIN_CONTROL_TYPE_TEXT);
459 if (m_pSetting->GetType() == SettingType::Integer)
460 FillIntegerSettingControl(false);
461 else if (m_pSetting->GetType() == SettingType::Number)
463 std::shared_ptr<CSettingNumber> pSettingNumber =
464 std::static_pointer_cast<CSettingNumber>(m_pSetting);
465 std::shared_ptr<const CSettingControlFormattedRange> control =
466 std::static_pointer_cast<const CSettingControlFormattedRange>(m_pSetting->GetControl());
467 int index = 0;
468 for (double value = pSettingNumber->GetMinimum(); value <= pSettingNumber->GetMaximum();
469 value += pSettingNumber->GetStep(), index++)
471 std::string strLabel;
472 if (value == pSettingNumber->GetMinimum() && control->GetMinimumLabel() > -1)
473 strLabel = Localize(control->GetMinimumLabel());
474 else if (control->GetFormatLabel() > -1)
475 strLabel = StringUtils::Format(Localize(control->GetFormatLabel()), value);
476 else
477 strLabel = StringUtils::Format(control->GetFormatString(), value);
479 m_pSpin->AddLabel(strLabel, index);
485 CGUIControlSpinExSetting::~CGUIControlSpinExSetting() = default;
487 bool CGUIControlSpinExSetting::OnClick()
489 if (m_pSpin == NULL)
490 return false;
492 switch (m_pSetting->GetType())
494 case SettingType::Integer:
495 SetValid(std::static_pointer_cast<CSettingInt>(m_pSetting)->SetValue(m_pSpin->GetValue()));
496 break;
498 case SettingType::Number:
500 auto pSettingNumber = std::static_pointer_cast<CSettingNumber>(m_pSetting);
501 const auto& controlFormat = m_pSetting->GetControl()->GetFormat();
502 if (controlFormat == "number")
503 SetValid(pSettingNumber->SetValue(static_cast<double>(m_pSpin->GetFloatValue())));
504 else
505 SetValid(pSettingNumber->SetValue(pSettingNumber->GetMinimum() +
506 pSettingNumber->GetStep() * m_pSpin->GetValue()));
508 break;
511 case SettingType::String:
512 SetValid(std::static_pointer_cast<CSettingString>(m_pSetting)
513 ->SetValue(m_pSpin->GetStringValue()));
514 break;
516 default:
517 return false;
520 return IsValid();
523 void CGUIControlSpinExSetting::Update(bool fromControl, bool updateDisplayOnly)
525 if (fromControl || m_pSpin == NULL)
526 return;
528 CGUIControlBaseSetting::Update(fromControl, updateDisplayOnly);
530 FillControl(!updateDisplayOnly);
532 if (!updateDisplayOnly)
534 // disable the spinner if it has less than two items
535 if (!m_pSpin->IsDisabled() && (m_pSpin->GetMaximum() - m_pSpin->GetMinimum()) == 0)
536 m_pSpin->SetEnabled(false);
540 void CGUIControlSpinExSetting::FillControl(bool updateValues)
542 if (m_pSpin == NULL)
543 return;
545 if (updateValues)
546 m_pSpin->Clear();
548 const std::string& controlFormat = m_pSetting->GetControl()->GetFormat();
549 if (controlFormat == "number")
551 std::shared_ptr<CSettingNumber> pSettingNumber =
552 std::static_pointer_cast<CSettingNumber>(m_pSetting);
553 m_pSpin->SetFloatValue((float)pSettingNumber->GetValue());
555 else if (controlFormat == "integer")
556 FillIntegerSettingControl(updateValues);
557 else if (controlFormat == "string")
559 if (m_pSetting->GetType() == SettingType::Integer)
560 FillIntegerSettingControl(updateValues);
561 else if (m_pSetting->GetType() == SettingType::Number)
562 FillFloatSettingControl();
563 else if (m_pSetting->GetType() == SettingType::String)
564 FillStringSettingControl(updateValues);
568 void CGUIControlSpinExSetting::FillIntegerSettingControl(bool updateValues)
570 IntegerSettingOptions options;
571 std::set<int> selectedValues;
572 // get the integer options
573 if (!GetIntegerOptions(m_pSetting, options, selectedValues, m_localizer, updateValues) ||
574 selectedValues.size() != 1)
575 return;
577 if (updateValues)
579 // add them to the spinner
580 for (const auto& option : options)
581 m_pSpin->AddLabel(option.label, option.value);
584 // and set the current value
585 m_pSpin->SetValue(*selectedValues.begin());
588 void CGUIControlSpinExSetting::FillFloatSettingControl()
590 std::shared_ptr<CSettingNumber> pSettingNumber =
591 std::static_pointer_cast<CSettingNumber>(m_pSetting);
592 std::shared_ptr<const CSettingControlFormattedRange> control =
593 std::static_pointer_cast<const CSettingControlFormattedRange>(m_pSetting->GetControl());
594 int index = 0;
595 int currentIndex = 0;
596 for (double value = pSettingNumber->GetMinimum(); value <= pSettingNumber->GetMaximum();
597 value += pSettingNumber->GetStep(), index++)
599 if (value == pSettingNumber->GetValue())
601 currentIndex = index;
602 break;
606 m_pSpin->SetValue(currentIndex);
609 void CGUIControlSpinExSetting::FillStringSettingControl(bool updateValues)
611 StringSettingOptions options;
612 std::set<std::string> selectedValues;
613 // get the string options
614 if (!GetStringOptions(m_pSetting, options, selectedValues, m_localizer, updateValues) ||
615 selectedValues.size() != 1)
616 return;
618 if (updateValues)
620 // add them to the spinner
621 for (const auto& option : options)
622 m_pSpin->AddLabel(option.label, option.value);
625 // and set the current value
626 m_pSpin->SetStringValue(*selectedValues.begin());
629 CGUIControlListSetting::CGUIControlListSetting(CGUIButtonControl* pButton,
630 int id,
631 std::shared_ptr<CSetting> pSetting,
632 ILocalizer* localizer)
633 : CGUIControlBaseSetting(id, std::move(pSetting), localizer)
635 m_pButton = pButton;
636 if (m_pButton == NULL)
637 return;
639 m_pButton->SetID(id);
642 CGUIControlListSetting::~CGUIControlListSetting() = default;
644 bool CGUIControlListSetting::OnClick()
646 if (m_pButton == NULL)
647 return false;
649 CGUIDialogSelect* dialog =
650 CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogSelect>(
651 WINDOW_DIALOG_SELECT);
652 if (dialog == NULL)
653 return false;
655 CFileItemList options;
656 std::shared_ptr<const CSettingControlList> control =
657 std::static_pointer_cast<const CSettingControlList>(m_pSetting->GetControl());
658 bool optionsValid = GetItems(m_pSetting, options, false);
660 bool bValueAdded = false;
661 bool bAllowNewOption = false;
662 if (m_pSetting->GetType() == SettingType::List)
664 std::shared_ptr<const CSettingList> settingList =
665 std::static_pointer_cast<const CSettingList>(m_pSetting);
666 if (settingList->GetElementType() == SettingType::String)
668 bAllowNewOption = std::static_pointer_cast<const CSettingString>(settingList->GetDefinition())
669 ->AllowNewOption();
672 if (!bAllowNewOption)
674 // Do not show dialog if
675 // there are no items to be chosen
676 if (!optionsValid || options.Size() <= 0)
677 return false;
679 dialog->Reset();
680 dialog->SetHeading(CVariant{Localize(m_pSetting->GetLabel())});
681 dialog->SetItems(options);
682 dialog->SetMultiSelection(control->CanMultiSelect());
683 dialog->SetUseDetails(control->UseDetails());
684 dialog->Open();
686 if (!dialog->IsConfirmed())
687 return false;
689 else
691 // Possible to add items, as well as select from any options given
692 // Add any current values that are not options as items in list
693 std::vector<CVariant> list =
694 CSettingUtils::GetList(std::static_pointer_cast<const CSettingList>(m_pSetting));
695 for (const auto& value : list)
697 bool found = std::any_of(options.begin(), options.end(), [&](const auto& p) {
698 return p->GetProperty("value").asString() == value.asString();
700 if (!found)
702 CFileItemPtr item(new CFileItem(value.asString()));
703 item->SetProperty("value", value.asString());
704 item->Select(true);
705 options.Add(item);
709 bool bRepeat = true;
710 while (bRepeat)
712 std::string strAddButton = Localize(control->GetAddButtonLabel());
713 if (strAddButton.empty())
714 strAddButton = Localize(15019); // "ADD"
715 dialog->Reset(); // Clears AddButtonPressed
716 dialog->SetHeading(CVariant{ Localize(m_pSetting->GetLabel()) });
717 dialog->SetItems(options);
718 dialog->SetMultiSelection(control->CanMultiSelect());
719 dialog->EnableButton2(bAllowNewOption, strAddButton);
721 dialog->Open();
723 if (!dialog->IsConfirmed())
724 return false;
726 if (dialog->IsButton2Pressed())
728 // Get new list value
729 std::string strLabel;
730 bool bValidType = false;
731 while (!bValidType && CGUIKeyboardFactory::ShowAndGetInput(
732 strLabel, CVariant{ Localize(control->GetAddButtonLabel()) }, false))
734 // Validate new value is unique and truncate at any comma
735 StringUtils::Trim(strLabel);
736 strLabel = strLabel.substr(0, strLabel.find(','));
737 if (!strLabel.empty())
739 bValidType = !std::any_of(options.begin(), options.end(), [&](const auto& p) {
740 return p->GetProperty("value").asString() == strLabel;
743 if (bValidType)
744 { // Add new value to the list of options
745 CFileItemPtr pItem(new CFileItem(strLabel));
746 pItem->Select(true);
747 pItem->SetProperty("value", strLabel);
748 options.Add(pItem);
749 bValueAdded = true;
753 bRepeat = dialog->IsButton2Pressed();
757 std::vector<CVariant> values;
758 for (int i : dialog->GetSelectedItems())
760 const CFileItemPtr item = options.Get(i);
761 if (item == NULL || !item->HasProperty("value"))
762 return false;
764 values.push_back(item->GetProperty("value"));
767 bool ret = false;
768 switch (m_pSetting->GetType())
770 case SettingType::Integer:
771 if (values.size() > 1)
772 return false;
773 ret = std::static_pointer_cast<CSettingInt>(m_pSetting)
774 ->SetValue((int)values.at(0).asInteger());
775 break;
777 case SettingType::String:
778 if (values.size() > 1)
779 return false;
780 ret = std::static_pointer_cast<CSettingString>(m_pSetting)->SetValue(values.at(0).asString());
781 break;
783 case SettingType::List:
784 ret = CSettingUtils::SetList(std::static_pointer_cast<CSettingList>(m_pSetting), values);
785 break;
787 default:
788 return false;
791 if (ret)
792 UpdateFromSetting(!bValueAdded);
793 else
794 SetValid(false);
796 return IsValid();
799 void CGUIControlListSetting::Update(bool fromControl, bool updateDisplayOnly)
801 if (fromControl || m_pButton == NULL)
802 return;
804 CGUIControlBaseSetting::Update(fromControl, updateDisplayOnly);
806 CFileItemList options;
807 std::shared_ptr<const CSettingControlList> control =
808 std::static_pointer_cast<const CSettingControlList>(m_pSetting->GetControl());
809 bool optionsValid = GetItems(m_pSetting, options, !updateDisplayOnly);
811 bool bAllowNewOption = false;
812 if (m_pSetting->GetType() == SettingType::List)
814 std::shared_ptr<const CSettingList> settingList =
815 std::static_pointer_cast<const CSettingList>(m_pSetting);
816 if (settingList->GetElementType() == SettingType::String)
818 bAllowNewOption = std::static_pointer_cast<const CSettingString>(settingList->GetDefinition())
819 ->AllowNewOption();
823 std::string label2;
824 if (optionsValid && !control->HideValue())
826 SettingControlListValueFormatter formatter = control->GetFormatter();
827 if (formatter)
828 label2 = formatter(m_pSetting);
830 if (label2.empty() && bAllowNewOption)
832 const std::shared_ptr<const CSettingList> settingList =
833 std::static_pointer_cast<const CSettingList>(m_pSetting);
834 label2 = settingList->ToString();
837 if (label2.empty())
839 std::vector<std::string> labels;
840 for (int index = 0; index < options.Size(); index++)
842 const CFileItemPtr pItem = options.Get(index);
843 if (pItem->IsSelected())
844 labels.push_back(pItem->GetLabel());
847 label2 = StringUtils::Join(labels, ", ");
851 m_pButton->SetLabel2(label2);
853 if (!updateDisplayOnly)
855 // Disable the control if no items can be added and
856 // there are no items to be chosen
857 if (!m_pButton->IsDisabled() && !bAllowNewOption && (options.Size() <= 0))
858 m_pButton->SetEnabled(false);
862 bool CGUIControlListSetting::GetItems(const SettingConstPtr& setting,
863 CFileItemList& items,
864 bool updateItems) const
866 std::shared_ptr<const CSettingControlList> control =
867 std::static_pointer_cast<const CSettingControlList>(setting->GetControl());
868 const std::string& controlFormat = control->GetFormat();
870 if (controlFormat == "integer")
871 return GetIntegerItems(setting, items, updateItems);
872 else if (controlFormat == "string")
874 if (setting->GetType() == SettingType::Integer ||
875 (setting->GetType() == SettingType::List &&
876 std::static_pointer_cast<const CSettingList>(setting)->GetElementType() ==
877 SettingType::Integer))
878 return GetIntegerItems(setting, items, updateItems);
879 else if (setting->GetType() == SettingType::String ||
880 (setting->GetType() == SettingType::List &&
881 std::static_pointer_cast<const CSettingList>(setting)->GetElementType() ==
882 SettingType::String))
883 return GetStringItems(setting, items, updateItems);
885 else
886 return false;
888 return true;
891 bool CGUIControlListSetting::GetIntegerItems(const SettingConstPtr& setting,
892 CFileItemList& items,
893 bool updateItems) const
895 IntegerSettingOptions options;
896 std::set<int> selectedValues;
897 // get the integer options
898 if (!GetIntegerOptions(setting, options, selectedValues, m_localizer, updateItems))
899 return false;
901 // turn them into CFileItems and add them to the item list
902 for (const auto& option : options)
903 items.Add(
904 GetFileItem(option.label, option.label2, option.value, option.properties, selectedValues));
906 return true;
909 bool CGUIControlListSetting::GetStringItems(const SettingConstPtr& setting,
910 CFileItemList& items,
911 bool updateItems) const
913 StringSettingOptions options;
914 std::set<std::string> selectedValues;
915 // get the string options
916 if (!GetStringOptions(setting, options, selectedValues, m_localizer, updateItems))
917 return false;
919 // turn them into CFileItems and add them to the item list
920 for (const auto& option : options)
921 items.Add(
922 GetFileItem(option.label, option.label2, option.value, option.properties, selectedValues));
924 return true;
927 CGUIControlButtonSetting::CGUIControlButtonSetting(CGUIButtonControl* pButton,
928 int id,
929 std::shared_ptr<CSetting> pSetting,
930 ILocalizer* localizer)
931 : CGUIControlBaseSetting(id, std::move(pSetting), localizer)
933 m_pButton = pButton;
934 if (m_pButton == NULL)
935 return;
937 m_pButton->SetID(id);
940 CGUIControlButtonSetting::~CGUIControlButtonSetting() = default;
942 bool CGUIControlButtonSetting::OnClick()
944 if (m_pButton == NULL)
945 return false;
947 std::shared_ptr<const ISettingControl> control = m_pSetting->GetControl();
948 const std::string& controlType = control->GetType();
949 const std::string& controlFormat = control->GetFormat();
950 if (controlType == "button")
952 std::shared_ptr<const CSettingControlButton> buttonControl =
953 std::static_pointer_cast<const CSettingControlButton>(control);
954 if (controlFormat == "addon")
956 // prompt for the addon
957 std::shared_ptr<CSettingAddon> setting;
958 std::vector<std::string> addonIDs;
959 if (m_pSetting->GetType() == SettingType::List)
961 std::shared_ptr<CSettingList> settingList =
962 std::static_pointer_cast<CSettingList>(m_pSetting);
963 setting = std::static_pointer_cast<CSettingAddon>(settingList->GetDefinition());
964 for (const SettingPtr& addon : settingList->GetValue())
965 addonIDs.push_back(std::static_pointer_cast<CSettingAddon>(addon)->GetValue());
967 else
969 setting = std::static_pointer_cast<CSettingAddon>(m_pSetting);
970 addonIDs.push_back(setting->GetValue());
973 if (CGUIWindowAddonBrowser::SelectAddonID(
974 setting->GetAddonType(), addonIDs, setting->AllowEmpty(),
975 buttonControl->ShowAddonDetails(), m_pSetting->GetType() == SettingType::List,
976 buttonControl->ShowInstalledAddons(), buttonControl->ShowInstallableAddons(),
977 buttonControl->ShowMoreAddons()) != 1)
978 return false;
980 if (m_pSetting->GetType() == SettingType::List)
981 std::static_pointer_cast<CSettingList>(m_pSetting)->FromString(addonIDs);
982 else
983 SetValid(setting->SetValue(addonIDs[0]));
985 else if (controlFormat == "path" || controlFormat == "file" || controlFormat == "image")
986 SetValid(GetPath(std::static_pointer_cast<CSettingPath>(m_pSetting), m_localizer));
987 else if (controlFormat == "date")
989 std::shared_ptr<CSettingDate> settingDate =
990 std::static_pointer_cast<CSettingDate>(m_pSetting);
992 KODI::TIME::SystemTime systemdate;
993 settingDate->GetDate().GetAsSystemTime(systemdate);
994 if (CGUIDialogNumeric::ShowAndGetDate(systemdate, Localize(buttonControl->GetHeading())))
995 SetValid(settingDate->SetDate(CDateTime(systemdate)));
997 else if (controlFormat == "time")
999 std::shared_ptr<CSettingTime> settingTime =
1000 std::static_pointer_cast<CSettingTime>(m_pSetting);
1002 KODI::TIME::SystemTime systemtime;
1003 settingTime->GetTime().GetAsSystemTime(systemtime);
1005 if (CGUIDialogNumeric::ShowAndGetTime(systemtime, Localize(buttonControl->GetHeading())))
1006 SetValid(settingTime->SetTime(CDateTime(systemtime)));
1008 else if (controlFormat == "action")
1010 // simply call the OnSettingAction callback and whoever knows what to
1011 // do can do so (based on the setting's identification)
1012 m_pSetting->OnSettingAction(m_pSetting);
1013 SetValid(true);
1016 else if (controlType == "slider")
1018 float value, min, step, max;
1019 if (m_pSetting->GetType() == SettingType::Integer)
1021 std::shared_ptr<CSettingInt> settingInt = std::static_pointer_cast<CSettingInt>(m_pSetting);
1022 value = (float)settingInt->GetValue();
1023 min = (float)settingInt->GetMinimum();
1024 step = (float)settingInt->GetStep();
1025 max = (float)settingInt->GetMaximum();
1027 else if (m_pSetting->GetType() == SettingType::Number)
1029 std::shared_ptr<CSettingNumber> settingNumber =
1030 std::static_pointer_cast<CSettingNumber>(m_pSetting);
1031 value = (float)settingNumber->GetValue();
1032 min = (float)settingNumber->GetMinimum();
1033 step = (float)settingNumber->GetStep();
1034 max = (float)settingNumber->GetMaximum();
1036 else
1037 return false;
1039 std::shared_ptr<const CSettingControlSlider> sliderControl =
1040 std::static_pointer_cast<const CSettingControlSlider>(control);
1041 CGUIDialogSlider::ShowAndGetInput(Localize(sliderControl->GetHeading()), value, min, step, max,
1042 this, NULL);
1043 SetValid(true);
1046 // update the displayed value
1047 UpdateFromSetting(true);
1049 return IsValid();
1052 void CGUIControlButtonSetting::Update(bool fromControl, bool updateDisplayOnly)
1054 if (fromControl || m_pButton == NULL)
1055 return;
1057 CGUIControlBaseSetting::Update(fromControl, updateDisplayOnly);
1059 std::string strText;
1060 std::shared_ptr<const ISettingControl> control = m_pSetting->GetControl();
1061 const std::string& controlType = control->GetType();
1062 const std::string& controlFormat = control->GetFormat();
1064 if (controlType == "button")
1066 if (!std::static_pointer_cast<const CSettingControlButton>(control)->HideValue())
1068 auto setting = m_pSetting;
1069 if (m_pSetting->GetType() == SettingType::List)
1070 setting = std::static_pointer_cast<CSettingList>(m_pSetting)->GetDefinition();
1072 switch (setting->GetType())
1074 case SettingType::String:
1076 if (controlFormat == "addon")
1078 std::vector<std::string> addonIDs;
1079 if (m_pSetting->GetType() == SettingType::List)
1081 for (const auto& addonSetting :
1082 std::static_pointer_cast<CSettingList>(m_pSetting)->GetValue())
1083 addonIDs.push_back(
1084 std::static_pointer_cast<CSettingAddon>(addonSetting)->GetValue());
1086 else
1087 addonIDs.push_back(std::static_pointer_cast<CSettingString>(setting)->GetValue());
1089 std::vector<std::string> addonNames;
1090 for (const auto& addonID : addonIDs)
1092 ADDON::AddonPtr addon;
1093 if (CServiceBroker::GetAddonMgr().GetAddon(addonID, addon,
1094 ADDON::OnlyEnabled::CHOICE_YES))
1095 addonNames.push_back(addon->Name());
1098 if (addonNames.empty())
1099 strText = g_localizeStrings.Get(231); // None
1100 else
1101 strText = StringUtils::Join(addonNames, ", ");
1103 else
1105 std::string strValue = std::static_pointer_cast<CSettingString>(setting)->GetValue();
1106 if (controlFormat == "path" || controlFormat == "file" || controlFormat == "image")
1108 std::string shortPath;
1109 if (CUtil::MakeShortenPath(strValue, shortPath, 30))
1110 strText = shortPath;
1112 else if (controlFormat == "infolabel")
1114 strText = strValue;
1115 if (strText.empty())
1116 strText = g_localizeStrings.Get(231); // None
1118 else
1119 strText = strValue;
1122 break;
1125 case SettingType::Action:
1127 // CSettingAction.
1128 // Note: This can be removed once all settings use a proper control & format combination.
1129 // CSettingAction is strictly speaking not designed to have a label2, it does not even have a value.
1130 strText = m_pButton->GetLabel2();
1132 break;
1135 default:
1136 break;
1140 else if (controlType == "slider")
1142 switch (m_pSetting->GetType())
1144 case SettingType::Integer:
1146 std::shared_ptr<const CSettingInt> settingInt =
1147 std::static_pointer_cast<CSettingInt>(m_pSetting);
1148 strText = CGUIControlSliderSetting::GetText(m_pSetting, settingInt->GetValue(),
1149 settingInt->GetMinimum(), settingInt->GetStep(),
1150 settingInt->GetMaximum(), m_localizer);
1151 break;
1154 case SettingType::Number:
1156 std::shared_ptr<const CSettingNumber> settingNumber =
1157 std::static_pointer_cast<CSettingNumber>(m_pSetting);
1158 strText = CGUIControlSliderSetting::GetText(
1159 m_pSetting, settingNumber->GetValue(), settingNumber->GetMinimum(),
1160 settingNumber->GetStep(), settingNumber->GetMaximum(), m_localizer);
1161 break;
1164 default:
1165 break;
1169 m_pButton->SetLabel2(strText);
1172 bool CGUIControlButtonSetting::GetPath(const std::shared_ptr<CSettingPath>& pathSetting,
1173 ILocalizer* localizer)
1175 if (pathSetting == NULL)
1176 return false;
1178 std::string path = pathSetting->GetValue();
1180 VECSOURCES shares;
1181 bool localSharesOnly = false;
1182 const std::vector<std::string>& sources = pathSetting->GetSources();
1183 for (const auto& source : sources)
1185 if (StringUtils::EqualsNoCase(source, "local"))
1186 localSharesOnly = true;
1187 else
1189 VECSOURCES* sources = CMediaSourceSettings::GetInstance().GetSources(source);
1190 if (sources != NULL)
1191 shares.insert(shares.end(), sources->begin(), sources->end());
1195 CServiceBroker::GetMediaManager().GetLocalDrives(shares);
1196 if (!localSharesOnly)
1197 CServiceBroker::GetMediaManager().GetNetworkLocations(shares);
1199 bool result = false;
1200 std::shared_ptr<const CSettingControlButton> control =
1201 std::static_pointer_cast<const CSettingControlButton>(pathSetting->GetControl());
1202 const auto heading = ::Localize(control->GetHeading(), localizer);
1203 if (control->GetFormat() == "file")
1204 result = CGUIDialogFileBrowser::ShowAndGetFile(
1205 shares, pathSetting->GetMasking(CServiceBroker::GetFileExtensionProvider()), heading, path,
1206 control->UseImageThumbs(), control->UseFileDirectories());
1207 else if (control->GetFormat() == "image")
1209 /* Check setting contains own masking, to filter required image type.
1210 * e.g. png only needed
1211 * <constraints>
1212 * <masking>*.png</masking>
1213 * </constraints>
1214 * <control type="button" format="image">
1215 * ...
1217 std::string ext = pathSetting->GetMasking(CServiceBroker::GetFileExtensionProvider());
1218 if (ext.empty())
1219 ext = CServiceBroker::GetFileExtensionProvider().GetPictureExtensions();
1220 result = CGUIDialogFileBrowser::ShowAndGetFile(shares, ext, heading, path, true);
1222 else
1223 result =
1224 CGUIDialogFileBrowser::ShowAndGetDirectory(shares, heading, path, pathSetting->Writable());
1226 if (!result)
1227 return false;
1229 return pathSetting->SetValue(path);
1232 void CGUIControlButtonSetting::OnSliderChange(void* data, CGUISliderControl* slider)
1234 if (slider == NULL)
1235 return;
1237 std::string strText;
1238 switch (m_pSetting->GetType())
1240 case SettingType::Integer:
1242 std::shared_ptr<CSettingInt> settingInt = std::static_pointer_cast<CSettingInt>(m_pSetting);
1243 if (settingInt->SetValue(slider->GetIntValue()))
1244 strText = CGUIControlSliderSetting::GetText(m_pSetting, settingInt->GetValue(),
1245 settingInt->GetMinimum(), settingInt->GetStep(),
1246 settingInt->GetMaximum(), m_localizer);
1247 break;
1250 case SettingType::Number:
1252 std::shared_ptr<CSettingNumber> settingNumber =
1253 std::static_pointer_cast<CSettingNumber>(m_pSetting);
1254 if (settingNumber->SetValue(static_cast<double>(slider->GetFloatValue())))
1255 strText = CGUIControlSliderSetting::GetText(
1256 m_pSetting, settingNumber->GetValue(), settingNumber->GetMinimum(),
1257 settingNumber->GetStep(), settingNumber->GetMaximum(), m_localizer);
1258 break;
1261 default:
1262 break;
1265 if (!strText.empty())
1266 slider->SetTextValue(strText);
1269 CGUIControlEditSetting::CGUIControlEditSetting(CGUIEditControl* pEdit,
1270 int id,
1271 const std::shared_ptr<CSetting>& pSetting,
1272 ILocalizer* localizer)
1273 : CGUIControlBaseSetting(id, pSetting, localizer)
1275 std::shared_ptr<const CSettingControlEdit> control =
1276 std::static_pointer_cast<const CSettingControlEdit>(pSetting->GetControl());
1277 m_pEdit = pEdit;
1278 if (m_pEdit == NULL)
1279 return;
1281 m_pEdit->SetID(id);
1282 int heading = m_pSetting->GetLabel();
1283 if (control->GetHeading() > 0)
1284 heading = control->GetHeading();
1285 if (heading < 0)
1286 heading = 0;
1288 CGUIEditControl::INPUT_TYPE inputType = CGUIEditControl::INPUT_TYPE_TEXT;
1289 const std::string& controlFormat = control->GetFormat();
1290 if (controlFormat == "string")
1292 if (control->IsHidden())
1293 inputType = CGUIEditControl::INPUT_TYPE_PASSWORD;
1295 else if (controlFormat == "integer" || controlFormat == "number")
1297 if (control->VerifyNewValue())
1298 inputType = CGUIEditControl::INPUT_TYPE_PASSWORD_NUMBER_VERIFY_NEW;
1299 else
1300 inputType = CGUIEditControl::INPUT_TYPE_NUMBER;
1302 else if (controlFormat == "ip")
1303 inputType = CGUIEditControl::INPUT_TYPE_IPADDRESS;
1304 else if (controlFormat == "md5")
1305 inputType = CGUIEditControl::INPUT_TYPE_PASSWORD_MD5;
1307 m_pEdit->SetInputType(inputType, heading);
1309 // this will automatically trigger validation so it must be executed after
1310 // having set the value of the control based on the value of the setting
1311 m_pEdit->SetInputValidation(InputValidation, this);
1314 CGUIControlEditSetting::~CGUIControlEditSetting() = default;
1316 bool CGUIControlEditSetting::OnClick()
1318 if (m_pEdit == NULL)
1319 return false;
1321 // update our string
1322 if (m_pSetting->GetControl()->GetFormat() == "urlencoded")
1324 std::shared_ptr<CSettingUrlEncodedString> urlEncodedSetting =
1325 std::static_pointer_cast<CSettingUrlEncodedString>(m_pSetting);
1326 SetValid(urlEncodedSetting->SetDecodedValue(m_pEdit->GetLabel2()));
1328 else
1329 SetValid(m_pSetting->FromString(m_pEdit->GetLabel2()));
1331 return IsValid();
1334 void CGUIControlEditSetting::Update(bool fromControl, bool updateDisplayOnly)
1336 if (fromControl || m_pEdit == NULL)
1337 return;
1339 CGUIControlBaseSetting::Update(fromControl, updateDisplayOnly);
1341 std::shared_ptr<const CSettingControlEdit> control =
1342 std::static_pointer_cast<const CSettingControlEdit>(m_pSetting->GetControl());
1344 if (control->GetFormat() == "urlencoded")
1346 std::shared_ptr<CSettingUrlEncodedString> urlEncodedSetting =
1347 std::static_pointer_cast<CSettingUrlEncodedString>(m_pSetting);
1348 m_pEdit->SetLabel2(urlEncodedSetting->GetDecodedValue());
1350 else
1351 m_pEdit->SetLabel2(m_pSetting->ToString());
1354 bool CGUIControlEditSetting::InputValidation(const std::string& input, void* data)
1356 if (data == NULL)
1357 return true;
1359 CGUIControlEditSetting* editControl = reinterpret_cast<CGUIControlEditSetting*>(data);
1360 if (editControl->GetSetting() == NULL)
1361 return true;
1363 editControl->SetValid(editControl->GetSetting()->CheckValidity(input));
1364 return editControl->IsValid();
1367 CGUIControlSliderSetting::CGUIControlSliderSetting(CGUISettingsSliderControl* pSlider,
1368 int id,
1369 std::shared_ptr<CSetting> pSetting,
1370 ILocalizer* localizer)
1371 : CGUIControlBaseSetting(id, std::move(pSetting), localizer)
1373 m_pSlider = pSlider;
1374 if (m_pSlider == NULL)
1375 return;
1377 m_pSlider->SetID(id);
1379 switch (m_pSetting->GetType())
1381 case SettingType::Integer:
1383 std::shared_ptr<CSettingInt> settingInt = std::static_pointer_cast<CSettingInt>(m_pSetting);
1384 if (m_pSetting->GetControl()->GetFormat() == "percentage")
1385 m_pSlider->SetType(SLIDER_CONTROL_TYPE_PERCENTAGE);
1386 else
1388 m_pSlider->SetType(SLIDER_CONTROL_TYPE_INT);
1389 m_pSlider->SetRange(settingInt->GetMinimum(), settingInt->GetMaximum());
1391 m_pSlider->SetIntInterval(settingInt->GetStep());
1392 break;
1395 case SettingType::Number:
1397 std::shared_ptr<CSettingNumber> settingNumber =
1398 std::static_pointer_cast<CSettingNumber>(m_pSetting);
1399 m_pSlider->SetType(SLIDER_CONTROL_TYPE_FLOAT);
1400 m_pSlider->SetFloatRange(static_cast<float>(settingNumber->GetMinimum()),
1401 static_cast<float>(settingNumber->GetMaximum()));
1402 m_pSlider->SetFloatInterval(static_cast<float>(settingNumber->GetStep()));
1403 break;
1406 default:
1407 break;
1411 CGUIControlSliderSetting::~CGUIControlSliderSetting() = default;
1413 bool CGUIControlSliderSetting::OnClick()
1415 if (m_pSlider == NULL)
1416 return false;
1418 switch (m_pSetting->GetType())
1420 case SettingType::Integer:
1421 SetValid(
1422 std::static_pointer_cast<CSettingInt>(m_pSetting)->SetValue(m_pSlider->GetIntValue()));
1423 break;
1425 case SettingType::Number:
1426 SetValid(std::static_pointer_cast<CSettingNumber>(m_pSetting)
1427 ->SetValue(static_cast<double>(m_pSlider->GetFloatValue())));
1428 break;
1430 default:
1431 return false;
1434 return IsValid();
1437 void CGUIControlSliderSetting::Update(bool fromControl, bool updateDisplayOnly)
1439 if (m_pSlider == NULL)
1440 return;
1442 CGUIControlBaseSetting::Update(fromControl, updateDisplayOnly);
1444 std::string strText;
1445 switch (m_pSetting->GetType())
1447 case SettingType::Integer:
1449 std::shared_ptr<const CSettingInt> settingInt =
1450 std::static_pointer_cast<CSettingInt>(m_pSetting);
1451 int value;
1452 if (fromControl)
1453 value = m_pSlider->GetIntValue();
1454 else
1456 value = std::static_pointer_cast<CSettingInt>(m_pSetting)->GetValue();
1457 m_pSlider->SetIntValue(value);
1460 strText = CGUIControlSliderSetting::GetText(m_pSetting, value, settingInt->GetMinimum(),
1461 settingInt->GetStep(), settingInt->GetMaximum(),
1462 m_localizer);
1463 break;
1466 case SettingType::Number:
1468 std::shared_ptr<const CSettingNumber> settingNumber =
1469 std::static_pointer_cast<CSettingNumber>(m_pSetting);
1470 double value;
1471 if (fromControl)
1472 value = static_cast<double>(m_pSlider->GetFloatValue());
1473 else
1475 value = std::static_pointer_cast<CSettingNumber>(m_pSetting)->GetValue();
1476 m_pSlider->SetFloatValue((float)value);
1479 strText = CGUIControlSliderSetting::GetText(m_pSetting, value, settingNumber->GetMinimum(),
1480 settingNumber->GetStep(),
1481 settingNumber->GetMaximum(), m_localizer);
1482 break;
1485 default:
1486 break;
1489 if (!strText.empty())
1490 m_pSlider->SetTextValue(strText);
1493 std::string CGUIControlSliderSetting::GetText(const std::shared_ptr<CSetting>& setting,
1494 const CVariant& value,
1495 const CVariant& minimum,
1496 const CVariant& step,
1497 const CVariant& maximum,
1498 ILocalizer* localizer)
1500 if (setting == NULL || !(value.isInteger() || value.isDouble()))
1501 return "";
1503 const auto control = std::static_pointer_cast<const CSettingControlSlider>(setting->GetControl());
1504 if (control == NULL)
1505 return "";
1507 SettingControlSliderFormatter formatter = control->GetFormatter();
1508 if (formatter != NULL)
1509 return formatter(control, value, minimum, step, maximum);
1511 std::string formatString = control->GetFormatString();
1512 if (control->GetFormatLabel() > -1)
1513 formatString = ::Localize(control->GetFormatLabel(), localizer);
1515 std::string formattedString;
1516 if (FormatText(formatString, value, setting->GetId(), formattedString))
1517 return formattedString;
1519 // fall back to default formatting
1520 formatString = control->GetDefaultFormatString();
1521 if (FormatText(formatString, value, setting->GetId(), formattedString))
1522 return formattedString;
1524 return "";
1527 bool CGUIControlSliderSetting::FormatText(const std::string& formatString,
1528 const CVariant& value,
1529 const std::string& settingId,
1530 std::string& formattedText)
1534 if (value.isDouble())
1535 formattedText = StringUtils::Format(formatString, value.asDouble());
1536 else
1537 formattedText = StringUtils::Format(formatString, static_cast<int>(value.asInteger()));
1539 catch (const std::runtime_error& err)
1541 CLog::Log(LOGERROR, "Invalid formatting with string \"{}\" for setting \"{}\": {}",
1542 formatString, settingId, err.what());
1543 return false;
1546 return true;
1549 CGUIControlRangeSetting::CGUIControlRangeSetting(CGUISettingsSliderControl* pSlider,
1550 int id,
1551 std::shared_ptr<CSetting> pSetting,
1552 ILocalizer* localizer)
1553 : CGUIControlBaseSetting(id, std::move(pSetting), localizer)
1555 m_pSlider = pSlider;
1556 if (m_pSlider == NULL)
1557 return;
1559 m_pSlider->SetID(id);
1560 m_pSlider->SetRangeSelection(true);
1562 if (m_pSetting->GetType() == SettingType::List)
1564 std::shared_ptr<CSettingList> settingList = std::static_pointer_cast<CSettingList>(m_pSetting);
1565 SettingConstPtr listDefintion = settingList->GetDefinition();
1566 switch (listDefintion->GetType())
1568 case SettingType::Integer:
1570 std::shared_ptr<const CSettingInt> listDefintionInt =
1571 std::static_pointer_cast<const CSettingInt>(listDefintion);
1572 if (m_pSetting->GetControl()->GetFormat() == "percentage")
1573 m_pSlider->SetType(SLIDER_CONTROL_TYPE_PERCENTAGE);
1574 else
1576 m_pSlider->SetType(SLIDER_CONTROL_TYPE_INT);
1577 m_pSlider->SetRange(listDefintionInt->GetMinimum(), listDefintionInt->GetMaximum());
1579 m_pSlider->SetIntInterval(listDefintionInt->GetStep());
1580 break;
1583 case SettingType::Number:
1585 std::shared_ptr<const CSettingNumber> listDefinitionNumber =
1586 std::static_pointer_cast<const CSettingNumber>(listDefintion);
1587 m_pSlider->SetType(SLIDER_CONTROL_TYPE_FLOAT);
1588 m_pSlider->SetFloatRange(static_cast<float>(listDefinitionNumber->GetMinimum()),
1589 static_cast<float>(listDefinitionNumber->GetMaximum()));
1590 m_pSlider->SetFloatInterval(static_cast<float>(listDefinitionNumber->GetStep()));
1591 break;
1594 default:
1595 break;
1600 CGUIControlRangeSetting::~CGUIControlRangeSetting() = default;
1602 bool CGUIControlRangeSetting::OnClick()
1604 if (m_pSlider == NULL || m_pSetting->GetType() != SettingType::List)
1605 return false;
1607 std::shared_ptr<CSettingList> settingList = std::static_pointer_cast<CSettingList>(m_pSetting);
1608 const SettingList& settingListValues = settingList->GetValue();
1609 if (settingListValues.size() != 2)
1610 return false;
1612 std::vector<CVariant> values;
1613 SettingConstPtr listDefintion = settingList->GetDefinition();
1614 switch (listDefintion->GetType())
1616 case SettingType::Integer:
1617 values.emplace_back(m_pSlider->GetIntValue(CGUISliderControl::RangeSelectorLower));
1618 values.emplace_back(m_pSlider->GetIntValue(CGUISliderControl::RangeSelectorUpper));
1619 break;
1621 case SettingType::Number:
1622 values.emplace_back(m_pSlider->GetFloatValue(CGUISliderControl::RangeSelectorLower));
1623 values.emplace_back(m_pSlider->GetFloatValue(CGUISliderControl::RangeSelectorUpper));
1624 break;
1626 default:
1627 return false;
1630 if (values.size() != 2)
1631 return false;
1633 SetValid(CSettingUtils::SetList(settingList, values));
1634 return IsValid();
1637 void CGUIControlRangeSetting::Update(bool fromControl, bool updateDisplayOnly)
1639 if (m_pSlider == NULL || m_pSetting->GetType() != SettingType::List)
1640 return;
1642 CGUIControlBaseSetting::Update(fromControl, updateDisplayOnly);
1644 std::shared_ptr<CSettingList> settingList = std::static_pointer_cast<CSettingList>(m_pSetting);
1645 const SettingList& settingListValues = settingList->GetValue();
1646 if (settingListValues.size() != 2)
1647 return;
1649 SettingConstPtr listDefintion = settingList->GetDefinition();
1650 std::shared_ptr<const CSettingControlRange> controlRange =
1651 std::static_pointer_cast<const CSettingControlRange>(m_pSetting->GetControl());
1652 const std::string& controlFormat = controlRange->GetFormat();
1654 std::string strText;
1655 std::string strTextLower, strTextUpper;
1656 std::string formatString =
1657 Localize(controlRange->GetFormatLabel() > -1 ? controlRange->GetFormatLabel() : 21469);
1658 std::string valueFormat = controlRange->GetValueFormat();
1659 if (controlRange->GetValueFormatLabel() > -1)
1660 valueFormat = Localize(controlRange->GetValueFormatLabel());
1662 switch (listDefintion->GetType())
1664 case SettingType::Integer:
1666 int valueLower, valueUpper;
1667 if (fromControl)
1669 valueLower = m_pSlider->GetIntValue(CGUISliderControl::RangeSelectorLower);
1670 valueUpper = m_pSlider->GetIntValue(CGUISliderControl::RangeSelectorUpper);
1672 else
1674 valueLower = std::static_pointer_cast<CSettingInt>(settingListValues[0])->GetValue();
1675 valueUpper = std::static_pointer_cast<CSettingInt>(settingListValues[1])->GetValue();
1676 m_pSlider->SetIntValue(valueLower, CGUISliderControl::RangeSelectorLower);
1677 m_pSlider->SetIntValue(valueUpper, CGUISliderControl::RangeSelectorUpper);
1680 if (controlFormat == "date" || controlFormat == "time")
1682 CDateTime dateLower((time_t)valueLower);
1683 CDateTime dateUpper((time_t)valueUpper);
1685 if (controlFormat == "date")
1687 if (valueFormat.empty())
1689 strTextLower = dateLower.GetAsLocalizedDate();
1690 strTextUpper = dateUpper.GetAsLocalizedDate();
1692 else
1694 strTextLower = dateLower.GetAsLocalizedDate(valueFormat);
1695 strTextUpper = dateUpper.GetAsLocalizedDate(valueFormat);
1698 else
1700 if (valueFormat.empty())
1701 valueFormat = "mm:ss";
1703 strTextLower = dateLower.GetAsLocalizedTime(valueFormat);
1704 strTextUpper = dateUpper.GetAsLocalizedTime(valueFormat);
1707 else
1709 strTextLower = StringUtils::Format(valueFormat, valueLower);
1710 strTextUpper = StringUtils::Format(valueFormat, valueUpper);
1713 if (valueLower != valueUpper)
1714 strText = StringUtils::Format(formatString, strTextLower, strTextUpper);
1715 else
1716 strText = strTextLower;
1717 break;
1720 case SettingType::Number:
1722 double valueLower, valueUpper;
1723 if (fromControl)
1725 valueLower =
1726 static_cast<double>(m_pSlider->GetFloatValue(CGUISliderControl::RangeSelectorLower));
1727 valueUpper =
1728 static_cast<double>(m_pSlider->GetFloatValue(CGUISliderControl::RangeSelectorUpper));
1730 else
1732 valueLower = std::static_pointer_cast<CSettingNumber>(settingListValues[0])->GetValue();
1733 valueUpper = std::static_pointer_cast<CSettingNumber>(settingListValues[1])->GetValue();
1734 m_pSlider->SetFloatValue((float)valueLower, CGUISliderControl::RangeSelectorLower);
1735 m_pSlider->SetFloatValue((float)valueUpper, CGUISliderControl::RangeSelectorUpper);
1738 strTextLower = StringUtils::Format(valueFormat, valueLower);
1739 if (valueLower != valueUpper)
1741 strTextUpper = StringUtils::Format(valueFormat, valueUpper);
1742 strText = StringUtils::Format(formatString, strTextLower, strTextUpper);
1744 else
1745 strText = strTextLower;
1746 break;
1749 default:
1750 strText.clear();
1751 break;
1754 if (!strText.empty())
1755 m_pSlider->SetTextValue(strText);
1758 CGUIControlSeparatorSetting::CGUIControlSeparatorSetting(CGUIImage* pImage,
1759 int id,
1760 ILocalizer* localizer)
1761 : CGUIControlBaseSetting(id, NULL, localizer)
1763 m_pImage = pImage;
1764 if (m_pImage == NULL)
1765 return;
1767 m_pImage->SetID(id);
1770 CGUIControlSeparatorSetting::~CGUIControlSeparatorSetting() = default;
1772 CGUIControlGroupTitleSetting::CGUIControlGroupTitleSetting(CGUILabelControl* pLabel,
1773 int id,
1774 ILocalizer* localizer)
1775 : CGUIControlBaseSetting(id, NULL, localizer)
1777 m_pLabel = pLabel;
1778 if (m_pLabel == NULL)
1779 return;
1781 m_pLabel->SetID(id);
1784 CGUIControlGroupTitleSetting::~CGUIControlGroupTitleSetting() = default;
1786 CGUIControlLabelSetting::CGUIControlLabelSetting(CGUIButtonControl* pButton,
1787 int id,
1788 std::shared_ptr<CSetting> pSetting,
1789 ILocalizer* localizer)
1790 : CGUIControlBaseSetting(id, std::move(pSetting), localizer)
1792 m_pButton = pButton;
1793 if (m_pButton == NULL)
1794 return;
1796 m_pButton->SetID(id);
1797 UpdateFromSetting();