[Windows] Fix driver version detection of AMD RDNA+ GPU on Windows 10
[xbmc.git] / xbmc / settings / windows / GUIControlSettings.cpp
blobea45b0deed8fbbe965106706c11d8383f4dba244
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 "FileItemList.h"
13 #include "ServiceBroker.h"
14 #include "Util.h"
15 #include "addons/AddonManager.h"
16 #include "addons/gui/GUIWindowAddonBrowser.h"
17 #include "addons/settings/SettingUrlEncodedString.h"
18 #include "dialogs/GUIDialogColorPicker.h"
19 #include "dialogs/GUIDialogFileBrowser.h"
20 #include "dialogs/GUIDialogNumeric.h"
21 #include "dialogs/GUIDialogSelect.h"
22 #include "dialogs/GUIDialogSlider.h"
23 #include "guilib/GUIColorButtonControl.h"
24 #include "guilib/GUIComponent.h"
25 #include "guilib/GUIEditControl.h"
26 #include "guilib/GUIImage.h"
27 #include "guilib/GUIKeyboardFactory.h"
28 #include "guilib/GUILabelControl.h"
29 #include "guilib/GUIRadioButtonControl.h"
30 #include "guilib/GUISettingsSliderControl.h"
31 #include "guilib/GUISpinControlEx.h"
32 #include "guilib/GUIWindowManager.h"
33 #include "guilib/LocalizeStrings.h"
34 #include "settings/MediaSourceSettings.h"
35 #include "settings/SettingAddon.h"
36 #include "settings/SettingControl.h"
37 #include "settings/SettingDateTime.h"
38 #include "settings/SettingPath.h"
39 #include "settings/SettingUtils.h"
40 #include "settings/lib/Setting.h"
41 #include "settings/lib/SettingDefinitions.h"
42 #include "storage/MediaManager.h"
43 #include "utils/FileExtensionProvider.h"
44 #include "utils/StringUtils.h"
45 #include "utils/Variant.h"
46 #include "utils/log.h"
48 #include <set>
49 #include <utility>
51 using namespace ADDON;
53 static std::string Localize(std::uint32_t code,
54 ILocalizer* localizer,
55 const std::string& addonId = "")
57 if (localizer == nullptr)
58 return "";
60 if (!addonId.empty())
62 std::string label = g_localizeStrings.GetAddonString(addonId, code);
63 if (!label.empty())
64 return label;
67 return localizer->Localize(code);
70 template<typename TValueType>
71 static CFileItemPtr GetFileItem(const std::string& label,
72 const std::string& label2,
73 const TValueType& value,
74 const std::vector<std::pair<std::string, CVariant>>& properties,
75 const std::set<TValueType>& selectedValues)
77 CFileItemPtr item(new CFileItem(label));
78 item->SetProperty("value", value);
79 item->SetLabel2(label2);
81 for (const auto& prop : properties)
82 item->SetProperty(prop.first, prop.second);
84 if (selectedValues.find(value) != selectedValues.end())
85 item->Select(true);
87 return item;
90 template<class SettingOption>
91 static bool CompareSettingOptionAseconding(const SettingOption& lhs, const SettingOption& rhs)
93 return StringUtils::CompareNoCase(lhs.label, rhs.label) < 0;
96 template<class SettingOption>
97 static bool CompareSettingOptionDeseconding(const SettingOption& lhs, const SettingOption& rhs)
99 return StringUtils::CompareNoCase(lhs.label, rhs.label) > 0;
102 static bool GetIntegerOptions(const SettingConstPtr& setting,
103 IntegerSettingOptions& options,
104 std::set<int>& selectedOptions,
105 ILocalizer* localizer,
106 bool updateOptions)
108 std::shared_ptr<const CSettingInt> pSettingInt = NULL;
109 if (setting->GetType() == SettingType::Integer)
110 pSettingInt = std::static_pointer_cast<const CSettingInt>(setting);
111 else if (setting->GetType() == SettingType::List)
113 std::shared_ptr<const CSettingList> settingList =
114 std::static_pointer_cast<const CSettingList>(setting);
115 if (settingList->GetElementType() != SettingType::Integer)
116 return false;
118 pSettingInt = std::static_pointer_cast<const CSettingInt>(settingList->GetDefinition());
121 switch (pSettingInt->GetOptionsType())
123 case SettingOptionsType::StaticTranslatable:
125 const TranslatableIntegerSettingOptions& settingOptions =
126 pSettingInt->GetTranslatableOptions();
127 for (const auto& option : settingOptions)
128 options.emplace_back(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.emplace_back(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.emplace_back(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), m_pSetting(std::move(pSetting)), m_localizer(localizer)
302 bool CGUIControlBaseSetting::IsEnabled() const
304 return m_pSetting != NULL && m_pSetting->IsEnabled();
307 void CGUIControlBaseSetting::UpdateFromControl()
309 Update(true, true);
312 void CGUIControlBaseSetting::UpdateFromSetting(bool updateDisplayOnly /* = false */)
314 Update(false, updateDisplayOnly);
317 std::string CGUIControlBaseSetting::Localize(std::uint32_t code) const
319 return ::Localize(code, m_localizer);
322 void CGUIControlBaseSetting::Update(bool fromControl, bool updateDisplayOnly)
324 if (fromControl || updateDisplayOnly)
325 return;
327 CGUIControl* control = GetControl();
328 if (control == NULL)
329 return;
331 control->SetEnabled(IsEnabled());
332 if (m_pSetting)
333 control->SetVisible(m_pSetting->IsVisible());
334 SetValid(true);
337 CGUIControlRadioButtonSetting::CGUIControlRadioButtonSetting(CGUIRadioButtonControl* pRadioButton,
338 int id,
339 std::shared_ptr<CSetting> pSetting,
340 ILocalizer* localizer)
341 : CGUIControlBaseSetting(id, std::move(pSetting), localizer)
343 m_pRadioButton = pRadioButton;
344 if (m_pRadioButton == NULL)
345 return;
347 m_pRadioButton->SetID(id);
350 CGUIControlRadioButtonSetting::~CGUIControlRadioButtonSetting() = default;
352 bool CGUIControlRadioButtonSetting::OnClick()
354 SetValid(std::static_pointer_cast<CSettingBool>(m_pSetting)
355 ->SetValue(!std::static_pointer_cast<CSettingBool>(m_pSetting)->GetValue()));
356 return IsValid();
359 void CGUIControlRadioButtonSetting::Update(bool fromControl, bool updateDisplayOnly)
361 if (fromControl || m_pRadioButton == NULL)
362 return;
364 CGUIControlBaseSetting::Update(fromControl, updateDisplayOnly);
366 m_pRadioButton->SetSelected(std::static_pointer_cast<CSettingBool>(m_pSetting)->GetValue());
369 CGUIControlColorButtonSetting::CGUIControlColorButtonSetting(
370 CGUIColorButtonControl* pColorControl,
371 int id,
372 const std::shared_ptr<CSetting>& pSetting,
373 ILocalizer* localizer)
374 : CGUIControlBaseSetting(id, pSetting, localizer)
376 m_pColorButton = pColorControl;
377 if (!m_pColorButton)
378 return;
380 m_pColorButton->SetID(id);
383 CGUIControlColorButtonSetting::~CGUIControlColorButtonSetting() = default;
385 bool CGUIControlColorButtonSetting::OnClick()
387 if (!m_pColorButton)
388 return false;
390 std::shared_ptr<CSettingString> settingHexColor =
391 std::static_pointer_cast<CSettingString>(m_pSetting);
393 CGUIDialogColorPicker* dialog =
394 CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogColorPicker>(
395 WINDOW_DIALOG_COLOR_PICKER);
396 if (!dialog)
397 return false;
399 dialog->Reset();
400 dialog->SetHeading(CVariant{Localize(m_pSetting->GetLabel())});
401 dialog->LoadColors();
402 std::string hexColor;
403 if (settingHexColor)
404 hexColor = settingHexColor.get()->GetValue();
405 dialog->SetSelectedColor(hexColor);
406 dialog->Open();
408 if (!dialog->IsConfirmed())
409 return false;
411 SetValid(
412 std::static_pointer_cast<CSettingString>(m_pSetting)->SetValue(dialog->GetSelectedColor()));
413 return IsValid();
416 void CGUIControlColorButtonSetting::Update(bool fromControl, bool updateDisplayOnly)
418 if (fromControl || !m_pColorButton)
419 return;
421 CGUIControlBaseSetting::Update(fromControl, updateDisplayOnly);
422 // Set the color to apply to the preview color box
423 m_pColorButton->SetImageBoxColor(
424 std::static_pointer_cast<CSettingString>(m_pSetting)->GetValue());
427 CGUIControlSpinExSetting::CGUIControlSpinExSetting(CGUISpinControlEx* pSpin,
428 int id,
429 std::shared_ptr<CSetting> pSetting,
430 ILocalizer* localizer)
431 : CGUIControlBaseSetting(id, std::move(pSetting), localizer)
433 m_pSpin = pSpin;
434 if (m_pSpin == NULL)
435 return;
437 m_pSpin->SetID(id);
439 const std::string& controlFormat = m_pSetting->GetControl()->GetFormat();
440 if (controlFormat == "number")
442 std::shared_ptr<CSettingNumber> pSettingNumber =
443 std::static_pointer_cast<CSettingNumber>(m_pSetting);
444 m_pSpin->SetType(SPIN_CONTROL_TYPE_FLOAT);
445 m_pSpin->SetFloatRange(static_cast<float>(pSettingNumber->GetMinimum()),
446 static_cast<float>(pSettingNumber->GetMaximum()));
447 m_pSpin->SetFloatInterval(static_cast<float>(pSettingNumber->GetStep()));
449 else if (controlFormat == "integer")
450 m_pSpin->SetType(SPIN_CONTROL_TYPE_TEXT);
451 else if (controlFormat == "string")
453 m_pSpin->SetType(SPIN_CONTROL_TYPE_TEXT);
455 if (m_pSetting->GetType() == SettingType::Integer)
456 FillIntegerSettingControl(false);
457 else if (m_pSetting->GetType() == SettingType::Number)
459 std::shared_ptr<CSettingNumber> pSettingNumber =
460 std::static_pointer_cast<CSettingNumber>(m_pSetting);
461 std::shared_ptr<const CSettingControlFormattedRange> control =
462 std::static_pointer_cast<const CSettingControlFormattedRange>(m_pSetting->GetControl());
463 int index = 0;
464 for (double value = pSettingNumber->GetMinimum(); value <= pSettingNumber->GetMaximum();
465 value += pSettingNumber->GetStep(), index++)
467 std::string strLabel;
468 if (value == pSettingNumber->GetMinimum() && control->GetMinimumLabel() > -1)
469 strLabel = Localize(control->GetMinimumLabel());
470 else if (control->GetFormatLabel() > -1)
471 strLabel = StringUtils::Format(Localize(control->GetFormatLabel()), value);
472 else
473 strLabel = StringUtils::Format(control->GetFormatString(), value);
475 m_pSpin->AddLabel(strLabel, index);
481 CGUIControlSpinExSetting::~CGUIControlSpinExSetting() = default;
483 bool CGUIControlSpinExSetting::OnClick()
485 if (m_pSpin == NULL)
486 return false;
488 switch (m_pSetting->GetType())
490 case SettingType::Integer:
491 SetValid(std::static_pointer_cast<CSettingInt>(m_pSetting)->SetValue(m_pSpin->GetValue()));
492 break;
494 case SettingType::Number:
496 auto pSettingNumber = std::static_pointer_cast<CSettingNumber>(m_pSetting);
497 const auto& controlFormat = m_pSetting->GetControl()->GetFormat();
498 if (controlFormat == "number")
499 SetValid(pSettingNumber->SetValue(static_cast<double>(m_pSpin->GetFloatValue())));
500 else
501 SetValid(pSettingNumber->SetValue(pSettingNumber->GetMinimum() +
502 pSettingNumber->GetStep() * m_pSpin->GetValue()));
504 break;
507 case SettingType::String:
508 SetValid(std::static_pointer_cast<CSettingString>(m_pSetting)
509 ->SetValue(m_pSpin->GetStringValue()));
510 break;
512 default:
513 return false;
516 return IsValid();
519 void CGUIControlSpinExSetting::Update(bool fromControl, bool updateDisplayOnly)
521 if (fromControl || m_pSpin == NULL)
522 return;
524 CGUIControlBaseSetting::Update(fromControl, updateDisplayOnly);
526 FillControl(!updateDisplayOnly);
528 if (!updateDisplayOnly)
530 // disable the spinner if it has less than two items
531 if (!m_pSpin->IsDisabled() && (m_pSpin->GetMaximum() - m_pSpin->GetMinimum()) == 0)
532 m_pSpin->SetEnabled(false);
536 void CGUIControlSpinExSetting::FillControl(bool updateValues)
538 if (m_pSpin == NULL)
539 return;
541 if (updateValues)
542 m_pSpin->Clear();
544 const std::string& controlFormat = m_pSetting->GetControl()->GetFormat();
545 if (controlFormat == "number")
547 std::shared_ptr<CSettingNumber> pSettingNumber =
548 std::static_pointer_cast<CSettingNumber>(m_pSetting);
549 m_pSpin->SetFloatValue((float)pSettingNumber->GetValue());
551 else if (controlFormat == "integer")
552 FillIntegerSettingControl(updateValues);
553 else if (controlFormat == "string")
555 if (m_pSetting->GetType() == SettingType::Integer)
556 FillIntegerSettingControl(updateValues);
557 else if (m_pSetting->GetType() == SettingType::Number)
558 FillFloatSettingControl();
559 else if (m_pSetting->GetType() == SettingType::String)
560 FillStringSettingControl(updateValues);
564 void CGUIControlSpinExSetting::FillIntegerSettingControl(bool updateValues)
566 IntegerSettingOptions options;
567 std::set<int> selectedValues;
568 // get the integer options
569 if (!GetIntegerOptions(m_pSetting, options, selectedValues, m_localizer, updateValues) ||
570 selectedValues.size() != 1)
571 return;
573 if (updateValues)
575 // add them to the spinner
576 for (const auto& option : options)
577 m_pSpin->AddLabel(option.label, option.value);
580 // and set the current value
581 m_pSpin->SetValue(*selectedValues.begin());
584 void CGUIControlSpinExSetting::FillFloatSettingControl()
586 std::shared_ptr<CSettingNumber> pSettingNumber =
587 std::static_pointer_cast<CSettingNumber>(m_pSetting);
588 std::shared_ptr<const CSettingControlFormattedRange> control =
589 std::static_pointer_cast<const CSettingControlFormattedRange>(m_pSetting->GetControl());
590 int index = 0;
591 int currentIndex = 0;
592 for (double value = pSettingNumber->GetMinimum(); value <= pSettingNumber->GetMaximum();
593 value += pSettingNumber->GetStep(), index++)
595 if (value == pSettingNumber->GetValue())
597 currentIndex = index;
598 break;
602 m_pSpin->SetValue(currentIndex);
605 void CGUIControlSpinExSetting::FillStringSettingControl(bool updateValues)
607 StringSettingOptions options;
608 std::set<std::string> selectedValues;
609 // get the string options
610 if (!GetStringOptions(m_pSetting, options, selectedValues, m_localizer, updateValues) ||
611 selectedValues.size() != 1)
612 return;
614 if (updateValues)
616 // add them to the spinner
617 for (const auto& option : options)
618 m_pSpin->AddLabel(option.label, option.value);
621 // and set the current value
622 m_pSpin->SetStringValue(*selectedValues.begin());
625 CGUIControlListSetting::CGUIControlListSetting(CGUIButtonControl* pButton,
626 int id,
627 std::shared_ptr<CSetting> pSetting,
628 ILocalizer* localizer)
629 : CGUIControlBaseSetting(id, std::move(pSetting), localizer)
631 m_pButton = pButton;
632 if (m_pButton == NULL)
633 return;
635 m_pButton->SetID(id);
638 CGUIControlListSetting::~CGUIControlListSetting() = default;
640 bool CGUIControlListSetting::OnClick()
642 if (m_pButton == NULL)
643 return false;
645 CGUIDialogSelect* dialog =
646 CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogSelect>(
647 WINDOW_DIALOG_SELECT);
648 if (dialog == NULL)
649 return false;
651 CFileItemList options;
652 std::shared_ptr<const CSettingControlList> control =
653 std::static_pointer_cast<const CSettingControlList>(m_pSetting->GetControl());
654 bool optionsValid = GetItems(m_pSetting, options, false);
656 bool bValueAdded = false;
657 bool bAllowNewOption = false;
658 if (m_pSetting->GetType() == SettingType::List)
660 std::shared_ptr<const CSettingList> settingList =
661 std::static_pointer_cast<const CSettingList>(m_pSetting);
662 if (settingList->GetElementType() == SettingType::String)
664 bAllowNewOption = std::static_pointer_cast<const CSettingString>(settingList->GetDefinition())
665 ->AllowNewOption();
668 if (!bAllowNewOption)
670 // Do not show dialog if
671 // there are no items to be chosen
672 if (!optionsValid || options.Size() <= 0)
673 return false;
675 dialog->Reset();
676 dialog->SetHeading(CVariant{Localize(m_pSetting->GetLabel())});
677 dialog->SetItems(options);
678 dialog->SetMultiSelection(control->CanMultiSelect());
679 dialog->SetUseDetails(control->UseDetails());
680 dialog->Open();
682 if (!dialog->IsConfirmed())
683 return false;
685 else
687 // Possible to add items, as well as select from any options given
688 // Add any current values that are not options as items in list
689 std::vector<CVariant> list =
690 CSettingUtils::GetList(std::static_pointer_cast<const CSettingList>(m_pSetting));
691 for (const auto& value : list)
693 bool found = std::any_of(options.begin(), options.end(), [&](const auto& p) {
694 return p->GetProperty("value").asString() == value.asString();
696 if (!found)
698 CFileItemPtr item(new CFileItem(value.asString()));
699 item->SetProperty("value", value.asString());
700 item->Select(true);
701 options.Add(item);
705 bool bRepeat = true;
706 while (bRepeat)
708 std::string strAddButton = Localize(control->GetAddButtonLabel());
709 if (strAddButton.empty())
710 strAddButton = Localize(15019); // "ADD"
711 dialog->Reset(); // Clears AddButtonPressed
712 dialog->SetHeading(CVariant{ Localize(m_pSetting->GetLabel()) });
713 dialog->SetItems(options);
714 dialog->SetMultiSelection(control->CanMultiSelect());
715 dialog->EnableButton2(bAllowNewOption, strAddButton);
717 dialog->Open();
719 if (!dialog->IsConfirmed())
720 return false;
722 if (dialog->IsButton2Pressed())
724 // Get new list value
725 std::string strLabel;
726 bool bValidType = false;
727 while (!bValidType && CGUIKeyboardFactory::ShowAndGetInput(
728 strLabel, CVariant{ Localize(control->GetAddButtonLabel()) }, false))
730 // Validate new value is unique and truncate at any comma
731 StringUtils::Trim(strLabel);
732 strLabel = strLabel.substr(0, strLabel.find(','));
733 if (!strLabel.empty())
735 bValidType = !std::any_of(options.begin(), options.end(), [&](const auto& p) {
736 return p->GetProperty("value").asString() == strLabel;
739 if (bValidType)
740 { // Add new value to the list of options
741 CFileItemPtr pItem(new CFileItem(strLabel));
742 pItem->Select(true);
743 pItem->SetProperty("value", strLabel);
744 options.Add(pItem);
745 bValueAdded = true;
749 bRepeat = dialog->IsButton2Pressed();
753 std::vector<CVariant> values;
754 for (int i : dialog->GetSelectedItems())
756 const CFileItemPtr item = options.Get(i);
757 if (item == NULL || !item->HasProperty("value"))
758 return false;
760 values.push_back(item->GetProperty("value"));
763 bool ret = false;
764 switch (m_pSetting->GetType())
766 case SettingType::Integer:
767 if (values.size() > 1)
768 return false;
769 ret = std::static_pointer_cast<CSettingInt>(m_pSetting)
770 ->SetValue((int)values.at(0).asInteger());
771 break;
773 case SettingType::String:
774 if (values.size() > 1)
775 return false;
776 ret = std::static_pointer_cast<CSettingString>(m_pSetting)->SetValue(values.at(0).asString());
777 break;
779 case SettingType::List:
780 ret = CSettingUtils::SetList(std::static_pointer_cast<CSettingList>(m_pSetting), values);
781 break;
783 default:
784 return false;
787 if (ret)
788 UpdateFromSetting(!bValueAdded);
789 else
790 SetValid(false);
792 return IsValid();
795 void CGUIControlListSetting::Update(bool fromControl, bool updateDisplayOnly)
797 if (fromControl || m_pButton == NULL)
798 return;
800 CGUIControlBaseSetting::Update(fromControl, updateDisplayOnly);
802 CFileItemList options;
803 std::shared_ptr<const CSettingControlList> control =
804 std::static_pointer_cast<const CSettingControlList>(m_pSetting->GetControl());
805 bool optionsValid = GetItems(m_pSetting, options, !updateDisplayOnly);
807 bool bAllowNewOption = false;
808 if (m_pSetting->GetType() == SettingType::List)
810 std::shared_ptr<const CSettingList> settingList =
811 std::static_pointer_cast<const CSettingList>(m_pSetting);
812 if (settingList->GetElementType() == SettingType::String)
814 bAllowNewOption = std::static_pointer_cast<const CSettingString>(settingList->GetDefinition())
815 ->AllowNewOption();
819 std::string label2;
820 if (optionsValid && !control->HideValue())
822 SettingControlListValueFormatter formatter = control->GetFormatter();
823 if (formatter)
824 label2 = formatter(m_pSetting);
826 if (label2.empty() && bAllowNewOption)
828 const std::shared_ptr<const CSettingList> settingList =
829 std::static_pointer_cast<const CSettingList>(m_pSetting);
830 label2 = settingList->ToString();
833 if (label2.empty())
835 std::vector<std::string> labels;
836 for (int index = 0; index < options.Size(); index++)
838 const CFileItemPtr pItem = options.Get(index);
839 if (pItem->IsSelected())
840 labels.push_back(pItem->GetLabel());
843 label2 = StringUtils::Join(labels, ", ");
847 m_pButton->SetLabel2(label2);
849 if (!updateDisplayOnly)
851 // Disable the control if no items can be added and
852 // there are no items to be chosen
853 if (!m_pButton->IsDisabled() && !bAllowNewOption && (options.Size() <= 0))
854 m_pButton->SetEnabled(false);
858 bool CGUIControlListSetting::GetItems(const SettingConstPtr& setting,
859 CFileItemList& items,
860 bool updateItems) const
862 std::shared_ptr<const CSettingControlList> control =
863 std::static_pointer_cast<const CSettingControlList>(setting->GetControl());
864 const std::string& controlFormat = control->GetFormat();
866 if (controlFormat == "integer")
867 return GetIntegerItems(setting, items, updateItems);
868 else if (controlFormat == "string")
870 if (setting->GetType() == SettingType::Integer ||
871 (setting->GetType() == SettingType::List &&
872 std::static_pointer_cast<const CSettingList>(setting)->GetElementType() ==
873 SettingType::Integer))
874 return GetIntegerItems(setting, items, updateItems);
875 else if (setting->GetType() == SettingType::String ||
876 (setting->GetType() == SettingType::List &&
877 std::static_pointer_cast<const CSettingList>(setting)->GetElementType() ==
878 SettingType::String))
879 return GetStringItems(setting, items, updateItems);
881 else
882 return false;
884 return true;
887 bool CGUIControlListSetting::GetIntegerItems(const SettingConstPtr& setting,
888 CFileItemList& items,
889 bool updateItems) const
891 IntegerSettingOptions options;
892 std::set<int> selectedValues;
893 // get the integer options
894 if (!GetIntegerOptions(setting, options, selectedValues, m_localizer, updateItems))
895 return false;
897 // turn them into CFileItems and add them to the item list
898 for (const auto& option : options)
899 items.Add(
900 GetFileItem(option.label, option.label2, option.value, option.properties, selectedValues));
902 return true;
905 bool CGUIControlListSetting::GetStringItems(const SettingConstPtr& setting,
906 CFileItemList& items,
907 bool updateItems) const
909 StringSettingOptions options;
910 std::set<std::string> selectedValues;
911 // get the string options
912 if (!GetStringOptions(setting, options, selectedValues, m_localizer, updateItems))
913 return false;
915 // turn them into CFileItems and add them to the item list
916 for (const auto& option : options)
917 items.Add(
918 GetFileItem(option.label, option.label2, option.value, option.properties, selectedValues));
920 return true;
923 CGUIControlButtonSetting::CGUIControlButtonSetting(CGUIButtonControl* pButton,
924 int id,
925 std::shared_ptr<CSetting> pSetting,
926 ILocalizer* localizer)
927 : CGUIControlBaseSetting(id, std::move(pSetting), localizer)
929 m_pButton = pButton;
930 if (m_pButton == NULL)
931 return;
933 m_pButton->SetID(id);
936 CGUIControlButtonSetting::~CGUIControlButtonSetting() = default;
938 bool CGUIControlButtonSetting::OnClick()
940 if (m_pButton == NULL)
941 return false;
943 std::shared_ptr<const ISettingControl> control = m_pSetting->GetControl();
944 const std::string& controlType = control->GetType();
945 const std::string& controlFormat = control->GetFormat();
946 if (controlType == "button")
948 std::shared_ptr<const CSettingControlButton> buttonControl =
949 std::static_pointer_cast<const CSettingControlButton>(control);
950 if (controlFormat == "addon")
952 // prompt for the addon
953 std::shared_ptr<CSettingAddon> setting;
954 std::vector<std::string> addonIDs;
955 if (m_pSetting->GetType() == SettingType::List)
957 std::shared_ptr<CSettingList> settingList =
958 std::static_pointer_cast<CSettingList>(m_pSetting);
959 setting = std::static_pointer_cast<CSettingAddon>(settingList->GetDefinition());
960 for (const SettingPtr& addon : settingList->GetValue())
961 addonIDs.push_back(std::static_pointer_cast<CSettingAddon>(addon)->GetValue());
963 else
965 setting = std::static_pointer_cast<CSettingAddon>(m_pSetting);
966 addonIDs.push_back(setting->GetValue());
969 if (CGUIWindowAddonBrowser::SelectAddonID(
970 setting->GetAddonType(), addonIDs, setting->AllowEmpty(),
971 buttonControl->ShowAddonDetails(), m_pSetting->GetType() == SettingType::List,
972 buttonControl->ShowInstalledAddons(), buttonControl->ShowInstallableAddons(),
973 buttonControl->ShowMoreAddons()) != 1)
974 return false;
976 if (m_pSetting->GetType() == SettingType::List)
977 std::static_pointer_cast<CSettingList>(m_pSetting)->FromString(addonIDs);
978 else
979 SetValid(setting->SetValue(addonIDs[0]));
981 else if (controlFormat == "path" || controlFormat == "file" || controlFormat == "image")
982 SetValid(GetPath(std::static_pointer_cast<CSettingPath>(m_pSetting), m_localizer));
983 else if (controlFormat == "date")
985 std::shared_ptr<CSettingDate> settingDate =
986 std::static_pointer_cast<CSettingDate>(m_pSetting);
988 KODI::TIME::SystemTime systemdate;
989 settingDate->GetDate().GetAsSystemTime(systemdate);
990 if (CGUIDialogNumeric::ShowAndGetDate(systemdate, Localize(buttonControl->GetHeading())))
991 SetValid(settingDate->SetDate(CDateTime(systemdate)));
993 else if (controlFormat == "time")
995 std::shared_ptr<CSettingTime> settingTime =
996 std::static_pointer_cast<CSettingTime>(m_pSetting);
998 KODI::TIME::SystemTime systemtime;
999 settingTime->GetTime().GetAsSystemTime(systemtime);
1001 if (CGUIDialogNumeric::ShowAndGetTime(systemtime, Localize(buttonControl->GetHeading())))
1002 SetValid(settingTime->SetTime(CDateTime(systemtime)));
1004 else if (controlFormat == "action")
1006 // simply call the OnSettingAction callback and whoever knows what to
1007 // do can do so (based on the setting's identification)
1008 m_pSetting->OnSettingAction(m_pSetting);
1009 SetValid(true);
1012 else if (controlType == "slider")
1014 float value, min, step, max;
1015 if (m_pSetting->GetType() == SettingType::Integer)
1017 std::shared_ptr<CSettingInt> settingInt = std::static_pointer_cast<CSettingInt>(m_pSetting);
1018 value = (float)settingInt->GetValue();
1019 min = (float)settingInt->GetMinimum();
1020 step = (float)settingInt->GetStep();
1021 max = (float)settingInt->GetMaximum();
1023 else if (m_pSetting->GetType() == SettingType::Number)
1025 std::shared_ptr<CSettingNumber> settingNumber =
1026 std::static_pointer_cast<CSettingNumber>(m_pSetting);
1027 value = (float)settingNumber->GetValue();
1028 min = (float)settingNumber->GetMinimum();
1029 step = (float)settingNumber->GetStep();
1030 max = (float)settingNumber->GetMaximum();
1032 else
1033 return false;
1035 std::shared_ptr<const CSettingControlSlider> sliderControl =
1036 std::static_pointer_cast<const CSettingControlSlider>(control);
1037 CGUIDialogSlider::ShowAndGetInput(Localize(sliderControl->GetHeading()), value, min, step, max,
1038 this, NULL);
1039 SetValid(true);
1042 // update the displayed value
1043 UpdateFromSetting(true);
1045 return IsValid();
1048 void CGUIControlButtonSetting::Update(bool fromControl, bool updateDisplayOnly)
1050 if (fromControl || m_pButton == NULL)
1051 return;
1053 CGUIControlBaseSetting::Update(fromControl, updateDisplayOnly);
1055 std::string strText;
1056 std::shared_ptr<const ISettingControl> control = m_pSetting->GetControl();
1057 const std::string& controlType = control->GetType();
1058 const std::string& controlFormat = control->GetFormat();
1060 if (controlType == "button")
1062 if (!std::static_pointer_cast<const CSettingControlButton>(control)->HideValue())
1064 auto setting = m_pSetting;
1065 if (m_pSetting->GetType() == SettingType::List)
1066 setting = std::static_pointer_cast<CSettingList>(m_pSetting)->GetDefinition();
1068 switch (setting->GetType())
1070 case SettingType::String:
1072 if (controlFormat == "addon")
1074 std::vector<std::string> addonIDs;
1075 if (m_pSetting->GetType() == SettingType::List)
1077 for (const auto& addonSetting :
1078 std::static_pointer_cast<CSettingList>(m_pSetting)->GetValue())
1079 addonIDs.push_back(
1080 std::static_pointer_cast<CSettingAddon>(addonSetting)->GetValue());
1082 else
1083 addonIDs.push_back(std::static_pointer_cast<CSettingString>(setting)->GetValue());
1085 std::vector<std::string> addonNames;
1086 for (const auto& addonID : addonIDs)
1088 ADDON::AddonPtr addon;
1089 if (CServiceBroker::GetAddonMgr().GetAddon(addonID, addon,
1090 ADDON::OnlyEnabled::CHOICE_YES))
1091 addonNames.push_back(addon->Name());
1094 if (addonNames.empty())
1095 strText = g_localizeStrings.Get(231); // None
1096 else
1097 strText = StringUtils::Join(addonNames, ", ");
1099 else
1101 std::string strValue = std::static_pointer_cast<CSettingString>(setting)->GetValue();
1102 if (controlFormat == "path" || controlFormat == "file" || controlFormat == "image")
1104 std::string shortPath;
1105 if (CUtil::MakeShortenPath(strValue, shortPath, 30))
1106 strText = shortPath;
1108 else if (controlFormat == "infolabel")
1110 strText = strValue;
1111 if (strText.empty())
1112 strText = g_localizeStrings.Get(231); // None
1114 else
1115 strText = strValue;
1118 break;
1121 case SettingType::Action:
1123 // CSettingAction.
1124 // Note: This can be removed once all settings use a proper control & format combination.
1125 // CSettingAction is strictly speaking not designed to have a label2, it does not even have a value.
1126 strText = m_pButton->GetLabel2();
1128 break;
1131 default:
1132 break;
1136 else if (controlType == "slider")
1138 switch (m_pSetting->GetType())
1140 case SettingType::Integer:
1142 std::shared_ptr<const CSettingInt> settingInt =
1143 std::static_pointer_cast<CSettingInt>(m_pSetting);
1144 strText = CGUIControlSliderSetting::GetText(m_pSetting, settingInt->GetValue(),
1145 settingInt->GetMinimum(), settingInt->GetStep(),
1146 settingInt->GetMaximum(), m_localizer);
1147 break;
1150 case SettingType::Number:
1152 std::shared_ptr<const CSettingNumber> settingNumber =
1153 std::static_pointer_cast<CSettingNumber>(m_pSetting);
1154 strText = CGUIControlSliderSetting::GetText(
1155 m_pSetting, settingNumber->GetValue(), settingNumber->GetMinimum(),
1156 settingNumber->GetStep(), settingNumber->GetMaximum(), m_localizer);
1157 break;
1160 default:
1161 break;
1165 m_pButton->SetLabel2(strText);
1168 bool CGUIControlButtonSetting::GetPath(const std::shared_ptr<CSettingPath>& pathSetting,
1169 ILocalizer* localizer)
1171 if (pathSetting == NULL)
1172 return false;
1174 std::string path = pathSetting->GetValue();
1176 VECSOURCES shares;
1177 bool localSharesOnly = false;
1178 const std::vector<std::string>& sources = pathSetting->GetSources();
1179 for (const auto& source : sources)
1181 if (StringUtils::EqualsNoCase(source, "local"))
1182 localSharesOnly = true;
1183 else
1185 VECSOURCES* sources = CMediaSourceSettings::GetInstance().GetSources(source);
1186 if (sources != NULL)
1187 shares.insert(shares.end(), sources->begin(), sources->end());
1191 CServiceBroker::GetMediaManager().GetLocalDrives(shares);
1192 if (!localSharesOnly)
1193 CServiceBroker::GetMediaManager().GetNetworkLocations(shares);
1195 bool result = false;
1196 std::shared_ptr<const CSettingControlButton> control =
1197 std::static_pointer_cast<const CSettingControlButton>(pathSetting->GetControl());
1198 const auto heading = ::Localize(control->GetHeading(), localizer);
1199 if (control->GetFormat() == "file")
1200 result = CGUIDialogFileBrowser::ShowAndGetFile(
1201 shares, pathSetting->GetMasking(CServiceBroker::GetFileExtensionProvider()), heading, path,
1202 control->UseImageThumbs(), control->UseFileDirectories());
1203 else if (control->GetFormat() == "image")
1205 /* Check setting contains own masking, to filter required image type.
1206 * e.g. png only needed
1207 * <constraints>
1208 * <masking>*.png</masking>
1209 * </constraints>
1210 * <control type="button" format="image">
1211 * ...
1213 std::string ext = pathSetting->GetMasking(CServiceBroker::GetFileExtensionProvider());
1214 if (ext.empty())
1215 ext = CServiceBroker::GetFileExtensionProvider().GetPictureExtensions();
1216 result = CGUIDialogFileBrowser::ShowAndGetFile(shares, ext, heading, path, true);
1218 else
1219 result =
1220 CGUIDialogFileBrowser::ShowAndGetDirectory(shares, heading, path, pathSetting->Writable());
1222 if (!result)
1223 return false;
1225 return pathSetting->SetValue(path);
1228 void CGUIControlButtonSetting::OnSliderChange(void* data, CGUISliderControl* slider)
1230 if (slider == NULL)
1231 return;
1233 std::string strText;
1234 switch (m_pSetting->GetType())
1236 case SettingType::Integer:
1238 std::shared_ptr<CSettingInt> settingInt = std::static_pointer_cast<CSettingInt>(m_pSetting);
1239 if (settingInt->SetValue(slider->GetIntValue()))
1240 strText = CGUIControlSliderSetting::GetText(m_pSetting, settingInt->GetValue(),
1241 settingInt->GetMinimum(), settingInt->GetStep(),
1242 settingInt->GetMaximum(), m_localizer);
1243 break;
1246 case SettingType::Number:
1248 std::shared_ptr<CSettingNumber> settingNumber =
1249 std::static_pointer_cast<CSettingNumber>(m_pSetting);
1250 if (settingNumber->SetValue(static_cast<double>(slider->GetFloatValue())))
1251 strText = CGUIControlSliderSetting::GetText(
1252 m_pSetting, settingNumber->GetValue(), settingNumber->GetMinimum(),
1253 settingNumber->GetStep(), settingNumber->GetMaximum(), m_localizer);
1254 break;
1257 default:
1258 break;
1261 if (!strText.empty())
1262 slider->SetTextValue(strText);
1265 CGUIControlEditSetting::CGUIControlEditSetting(CGUIEditControl* pEdit,
1266 int id,
1267 const std::shared_ptr<CSetting>& pSetting,
1268 ILocalizer* localizer)
1269 : CGUIControlBaseSetting(id, pSetting, localizer)
1271 std::shared_ptr<const CSettingControlEdit> control =
1272 std::static_pointer_cast<const CSettingControlEdit>(pSetting->GetControl());
1273 m_pEdit = pEdit;
1274 if (m_pEdit == NULL)
1275 return;
1277 m_pEdit->SetID(id);
1278 int heading = m_pSetting->GetLabel();
1279 if (control->GetHeading() > 0)
1280 heading = control->GetHeading();
1281 if (heading < 0)
1282 heading = 0;
1284 CGUIEditControl::INPUT_TYPE inputType = CGUIEditControl::INPUT_TYPE_TEXT;
1285 const std::string& controlFormat = control->GetFormat();
1286 if (controlFormat == "string")
1288 if (control->IsHidden())
1289 inputType = CGUIEditControl::INPUT_TYPE_PASSWORD;
1291 else if (controlFormat == "integer" || controlFormat == "number")
1293 if (control->VerifyNewValue())
1294 inputType = CGUIEditControl::INPUT_TYPE_PASSWORD_NUMBER_VERIFY_NEW;
1295 else
1296 inputType = CGUIEditControl::INPUT_TYPE_NUMBER;
1298 else if (controlFormat == "ip")
1299 inputType = CGUIEditControl::INPUT_TYPE_IPADDRESS;
1300 else if (controlFormat == "md5")
1301 inputType = CGUIEditControl::INPUT_TYPE_PASSWORD_MD5;
1303 m_pEdit->SetInputType(inputType, heading);
1305 // this will automatically trigger validation so it must be executed after
1306 // having set the value of the control based on the value of the setting
1307 m_pEdit->SetInputValidation(InputValidation, this);
1310 CGUIControlEditSetting::~CGUIControlEditSetting() = default;
1312 bool CGUIControlEditSetting::OnClick()
1314 if (m_pEdit == NULL)
1315 return false;
1317 // update our string
1318 if (m_pSetting->GetControl()->GetFormat() == "urlencoded")
1320 std::shared_ptr<CSettingUrlEncodedString> urlEncodedSetting =
1321 std::static_pointer_cast<CSettingUrlEncodedString>(m_pSetting);
1322 SetValid(urlEncodedSetting->SetDecodedValue(m_pEdit->GetLabel2()));
1324 else
1325 SetValid(m_pSetting->FromString(m_pEdit->GetLabel2()));
1327 return IsValid();
1330 void CGUIControlEditSetting::Update(bool fromControl, bool updateDisplayOnly)
1332 if (fromControl || m_pEdit == NULL)
1333 return;
1335 CGUIControlBaseSetting::Update(fromControl, updateDisplayOnly);
1337 std::shared_ptr<const CSettingControlEdit> control =
1338 std::static_pointer_cast<const CSettingControlEdit>(m_pSetting->GetControl());
1340 if (control->GetFormat() == "urlencoded")
1342 std::shared_ptr<CSettingUrlEncodedString> urlEncodedSetting =
1343 std::static_pointer_cast<CSettingUrlEncodedString>(m_pSetting);
1344 m_pEdit->SetLabel2(urlEncodedSetting->GetDecodedValue());
1346 else
1347 m_pEdit->SetLabel2(m_pSetting->ToString());
1350 bool CGUIControlEditSetting::InputValidation(const std::string& input, void* data)
1352 if (data == NULL)
1353 return true;
1355 CGUIControlEditSetting* editControl = reinterpret_cast<CGUIControlEditSetting*>(data);
1356 if (editControl->GetSetting() == NULL)
1357 return true;
1359 editControl->SetValid(editControl->GetSetting()->CheckValidity(input));
1360 return editControl->IsValid();
1363 CGUIControlSliderSetting::CGUIControlSliderSetting(CGUISettingsSliderControl* pSlider,
1364 int id,
1365 std::shared_ptr<CSetting> pSetting,
1366 ILocalizer* localizer)
1367 : CGUIControlBaseSetting(id, std::move(pSetting), localizer)
1369 m_pSlider = pSlider;
1370 if (m_pSlider == NULL)
1371 return;
1373 m_pSlider->SetID(id);
1375 switch (m_pSetting->GetType())
1377 case SettingType::Integer:
1379 std::shared_ptr<CSettingInt> settingInt = std::static_pointer_cast<CSettingInt>(m_pSetting);
1380 if (m_pSetting->GetControl()->GetFormat() == "percentage")
1381 m_pSlider->SetType(SLIDER_CONTROL_TYPE_PERCENTAGE);
1382 else
1384 m_pSlider->SetType(SLIDER_CONTROL_TYPE_INT);
1385 m_pSlider->SetRange(settingInt->GetMinimum(), settingInt->GetMaximum());
1387 m_pSlider->SetIntInterval(settingInt->GetStep());
1388 break;
1391 case SettingType::Number:
1393 std::shared_ptr<CSettingNumber> settingNumber =
1394 std::static_pointer_cast<CSettingNumber>(m_pSetting);
1395 m_pSlider->SetType(SLIDER_CONTROL_TYPE_FLOAT);
1396 m_pSlider->SetFloatRange(static_cast<float>(settingNumber->GetMinimum()),
1397 static_cast<float>(settingNumber->GetMaximum()));
1398 m_pSlider->SetFloatInterval(static_cast<float>(settingNumber->GetStep()));
1399 break;
1402 default:
1403 break;
1407 CGUIControlSliderSetting::~CGUIControlSliderSetting() = default;
1409 bool CGUIControlSliderSetting::OnClick()
1411 if (m_pSlider == NULL)
1412 return false;
1414 switch (m_pSetting->GetType())
1416 case SettingType::Integer:
1417 SetValid(
1418 std::static_pointer_cast<CSettingInt>(m_pSetting)->SetValue(m_pSlider->GetIntValue()));
1419 break;
1421 case SettingType::Number:
1422 SetValid(std::static_pointer_cast<CSettingNumber>(m_pSetting)
1423 ->SetValue(static_cast<double>(m_pSlider->GetFloatValue())));
1424 break;
1426 default:
1427 return false;
1430 return IsValid();
1433 void CGUIControlSliderSetting::Update(bool fromControl, bool updateDisplayOnly)
1435 if (m_pSlider == NULL)
1436 return;
1438 CGUIControlBaseSetting::Update(fromControl, updateDisplayOnly);
1440 std::string strText;
1441 switch (m_pSetting->GetType())
1443 case SettingType::Integer:
1445 std::shared_ptr<const CSettingInt> settingInt =
1446 std::static_pointer_cast<CSettingInt>(m_pSetting);
1447 int value;
1448 if (fromControl)
1449 value = m_pSlider->GetIntValue();
1450 else
1452 value = std::static_pointer_cast<CSettingInt>(m_pSetting)->GetValue();
1453 m_pSlider->SetIntValue(value);
1456 strText = CGUIControlSliderSetting::GetText(m_pSetting, value, settingInt->GetMinimum(),
1457 settingInt->GetStep(), settingInt->GetMaximum(),
1458 m_localizer);
1459 break;
1462 case SettingType::Number:
1464 std::shared_ptr<const CSettingNumber> settingNumber =
1465 std::static_pointer_cast<CSettingNumber>(m_pSetting);
1466 double value;
1467 if (fromControl)
1468 value = static_cast<double>(m_pSlider->GetFloatValue());
1469 else
1471 value = std::static_pointer_cast<CSettingNumber>(m_pSetting)->GetValue();
1472 m_pSlider->SetFloatValue((float)value);
1475 strText = CGUIControlSliderSetting::GetText(m_pSetting, value, settingNumber->GetMinimum(),
1476 settingNumber->GetStep(),
1477 settingNumber->GetMaximum(), m_localizer);
1478 break;
1481 default:
1482 break;
1485 if (!strText.empty())
1486 m_pSlider->SetTextValue(strText);
1489 std::string CGUIControlSliderSetting::GetText(const std::shared_ptr<CSetting>& setting,
1490 const CVariant& value,
1491 const CVariant& minimum,
1492 const CVariant& step,
1493 const CVariant& maximum,
1494 ILocalizer* localizer)
1496 if (setting == NULL || !(value.isInteger() || value.isDouble()))
1497 return "";
1499 const auto control = std::static_pointer_cast<const CSettingControlSlider>(setting->GetControl());
1500 if (control == NULL)
1501 return "";
1503 SettingControlSliderFormatter formatter = control->GetFormatter();
1504 if (formatter != NULL)
1505 return formatter(control, value, minimum, step, maximum);
1507 std::string formatString = control->GetFormatString();
1508 if (control->GetFormatLabel() > -1)
1509 formatString = ::Localize(control->GetFormatLabel(), localizer);
1511 std::string formattedString;
1512 if (FormatText(formatString, value, setting->GetId(), formattedString))
1513 return formattedString;
1515 // fall back to default formatting
1516 formatString = control->GetDefaultFormatString();
1517 if (FormatText(formatString, value, setting->GetId(), formattedString))
1518 return formattedString;
1520 return "";
1523 bool CGUIControlSliderSetting::FormatText(const std::string& formatString,
1524 const CVariant& value,
1525 const std::string& settingId,
1526 std::string& formattedText)
1530 if (value.isDouble())
1531 formattedText = StringUtils::Format(formatString, value.asDouble());
1532 else
1533 formattedText = StringUtils::Format(formatString, static_cast<int>(value.asInteger()));
1535 catch (const std::runtime_error& err)
1537 CLog::Log(LOGERROR, "Invalid formatting with string \"{}\" for setting \"{}\": {}",
1538 formatString, settingId, err.what());
1539 return false;
1542 return true;
1545 CGUIControlRangeSetting::CGUIControlRangeSetting(CGUISettingsSliderControl* pSlider,
1546 int id,
1547 std::shared_ptr<CSetting> pSetting,
1548 ILocalizer* localizer)
1549 : CGUIControlBaseSetting(id, std::move(pSetting), localizer)
1551 m_pSlider = pSlider;
1552 if (m_pSlider == NULL)
1553 return;
1555 m_pSlider->SetID(id);
1556 m_pSlider->SetRangeSelection(true);
1558 if (m_pSetting->GetType() == SettingType::List)
1560 std::shared_ptr<CSettingList> settingList = std::static_pointer_cast<CSettingList>(m_pSetting);
1561 SettingConstPtr listDefintion = settingList->GetDefinition();
1562 switch (listDefintion->GetType())
1564 case SettingType::Integer:
1566 std::shared_ptr<const CSettingInt> listDefintionInt =
1567 std::static_pointer_cast<const CSettingInt>(listDefintion);
1568 if (m_pSetting->GetControl()->GetFormat() == "percentage")
1569 m_pSlider->SetType(SLIDER_CONTROL_TYPE_PERCENTAGE);
1570 else
1572 m_pSlider->SetType(SLIDER_CONTROL_TYPE_INT);
1573 m_pSlider->SetRange(listDefintionInt->GetMinimum(), listDefintionInt->GetMaximum());
1575 m_pSlider->SetIntInterval(listDefintionInt->GetStep());
1576 break;
1579 case SettingType::Number:
1581 std::shared_ptr<const CSettingNumber> listDefinitionNumber =
1582 std::static_pointer_cast<const CSettingNumber>(listDefintion);
1583 m_pSlider->SetType(SLIDER_CONTROL_TYPE_FLOAT);
1584 m_pSlider->SetFloatRange(static_cast<float>(listDefinitionNumber->GetMinimum()),
1585 static_cast<float>(listDefinitionNumber->GetMaximum()));
1586 m_pSlider->SetFloatInterval(static_cast<float>(listDefinitionNumber->GetStep()));
1587 break;
1590 default:
1591 break;
1596 CGUIControlRangeSetting::~CGUIControlRangeSetting() = default;
1598 bool CGUIControlRangeSetting::OnClick()
1600 if (m_pSlider == NULL || m_pSetting->GetType() != SettingType::List)
1601 return false;
1603 std::shared_ptr<CSettingList> settingList = std::static_pointer_cast<CSettingList>(m_pSetting);
1604 const SettingList& settingListValues = settingList->GetValue();
1605 if (settingListValues.size() != 2)
1606 return false;
1608 std::vector<CVariant> values;
1609 SettingConstPtr listDefintion = settingList->GetDefinition();
1610 switch (listDefintion->GetType())
1612 case SettingType::Integer:
1613 values.emplace_back(m_pSlider->GetIntValue(CGUISliderControl::RangeSelectorLower));
1614 values.emplace_back(m_pSlider->GetIntValue(CGUISliderControl::RangeSelectorUpper));
1615 break;
1617 case SettingType::Number:
1618 values.emplace_back(m_pSlider->GetFloatValue(CGUISliderControl::RangeSelectorLower));
1619 values.emplace_back(m_pSlider->GetFloatValue(CGUISliderControl::RangeSelectorUpper));
1620 break;
1622 default:
1623 return false;
1626 if (values.size() != 2)
1627 return false;
1629 SetValid(CSettingUtils::SetList(settingList, values));
1630 return IsValid();
1633 void CGUIControlRangeSetting::Update(bool fromControl, bool updateDisplayOnly)
1635 if (m_pSlider == NULL || m_pSetting->GetType() != SettingType::List)
1636 return;
1638 CGUIControlBaseSetting::Update(fromControl, updateDisplayOnly);
1640 std::shared_ptr<CSettingList> settingList = std::static_pointer_cast<CSettingList>(m_pSetting);
1641 const SettingList& settingListValues = settingList->GetValue();
1642 if (settingListValues.size() != 2)
1643 return;
1645 SettingConstPtr listDefintion = settingList->GetDefinition();
1646 std::shared_ptr<const CSettingControlRange> controlRange =
1647 std::static_pointer_cast<const CSettingControlRange>(m_pSetting->GetControl());
1648 const std::string& controlFormat = controlRange->GetFormat();
1650 std::string strText;
1651 std::string strTextLower, strTextUpper;
1652 std::string formatString =
1653 Localize(controlRange->GetFormatLabel() > -1 ? controlRange->GetFormatLabel() : 21469);
1654 std::string valueFormat = controlRange->GetValueFormat();
1655 if (controlRange->GetValueFormatLabel() > -1)
1656 valueFormat = Localize(controlRange->GetValueFormatLabel());
1658 switch (listDefintion->GetType())
1660 case SettingType::Integer:
1662 int valueLower, valueUpper;
1663 if (fromControl)
1665 valueLower = m_pSlider->GetIntValue(CGUISliderControl::RangeSelectorLower);
1666 valueUpper = m_pSlider->GetIntValue(CGUISliderControl::RangeSelectorUpper);
1668 else
1670 valueLower = std::static_pointer_cast<CSettingInt>(settingListValues[0])->GetValue();
1671 valueUpper = std::static_pointer_cast<CSettingInt>(settingListValues[1])->GetValue();
1672 m_pSlider->SetIntValue(valueLower, CGUISliderControl::RangeSelectorLower);
1673 m_pSlider->SetIntValue(valueUpper, CGUISliderControl::RangeSelectorUpper);
1676 if (controlFormat == "date" || controlFormat == "time")
1678 CDateTime dateLower((time_t)valueLower);
1679 CDateTime dateUpper((time_t)valueUpper);
1681 if (controlFormat == "date")
1683 if (valueFormat.empty())
1685 strTextLower = dateLower.GetAsLocalizedDate();
1686 strTextUpper = dateUpper.GetAsLocalizedDate();
1688 else
1690 strTextLower = dateLower.GetAsLocalizedDate(valueFormat);
1691 strTextUpper = dateUpper.GetAsLocalizedDate(valueFormat);
1694 else
1696 if (valueFormat.empty())
1697 valueFormat = "mm:ss";
1699 strTextLower = dateLower.GetAsLocalizedTime(valueFormat);
1700 strTextUpper = dateUpper.GetAsLocalizedTime(valueFormat);
1703 else
1705 strTextLower = StringUtils::Format(valueFormat, valueLower);
1706 strTextUpper = StringUtils::Format(valueFormat, valueUpper);
1709 if (valueLower != valueUpper)
1710 strText = StringUtils::Format(formatString, strTextLower, strTextUpper);
1711 else
1712 strText = strTextLower;
1713 break;
1716 case SettingType::Number:
1718 double valueLower, valueUpper;
1719 if (fromControl)
1721 valueLower =
1722 static_cast<double>(m_pSlider->GetFloatValue(CGUISliderControl::RangeSelectorLower));
1723 valueUpper =
1724 static_cast<double>(m_pSlider->GetFloatValue(CGUISliderControl::RangeSelectorUpper));
1726 else
1728 valueLower = std::static_pointer_cast<CSettingNumber>(settingListValues[0])->GetValue();
1729 valueUpper = std::static_pointer_cast<CSettingNumber>(settingListValues[1])->GetValue();
1730 m_pSlider->SetFloatValue((float)valueLower, CGUISliderControl::RangeSelectorLower);
1731 m_pSlider->SetFloatValue((float)valueUpper, CGUISliderControl::RangeSelectorUpper);
1734 strTextLower = StringUtils::Format(valueFormat, valueLower);
1735 if (valueLower != valueUpper)
1737 strTextUpper = StringUtils::Format(valueFormat, valueUpper);
1738 strText = StringUtils::Format(formatString, strTextLower, strTextUpper);
1740 else
1741 strText = strTextLower;
1742 break;
1745 default:
1746 strText.clear();
1747 break;
1750 if (!strText.empty())
1751 m_pSlider->SetTextValue(strText);
1754 CGUIControlSeparatorSetting::CGUIControlSeparatorSetting(CGUIImage* pImage,
1755 int id,
1756 ILocalizer* localizer)
1757 : CGUIControlBaseSetting(id, NULL, localizer)
1759 m_pImage = pImage;
1760 if (m_pImage == NULL)
1761 return;
1763 m_pImage->SetID(id);
1766 CGUIControlSeparatorSetting::~CGUIControlSeparatorSetting() = default;
1768 CGUIControlGroupTitleSetting::CGUIControlGroupTitleSetting(CGUILabelControl* pLabel,
1769 int id,
1770 ILocalizer* localizer)
1771 : CGUIControlBaseSetting(id, NULL, localizer)
1773 m_pLabel = pLabel;
1774 if (m_pLabel == NULL)
1775 return;
1777 m_pLabel->SetID(id);
1780 CGUIControlGroupTitleSetting::~CGUIControlGroupTitleSetting() = default;
1782 CGUIControlLabelSetting::CGUIControlLabelSetting(CGUIButtonControl* pButton,
1783 int id,
1784 std::shared_ptr<CSetting> pSetting,
1785 ILocalizer* localizer)
1786 : CGUIControlBaseSetting(id, std::move(pSetting), localizer)
1788 m_pButton = pButton;
1789 if (m_pButton == NULL)
1790 return;
1792 m_pButton->SetID(id);
1793 UpdateFromSetting();