diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 35927948..aad5dbaf 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -507,6 +507,7 @@ AdvSceneSwitcher.condition.source.type.showing="Is showing" AdvSceneSwitcher.condition.source.type.settingsMatch="Settings match" AdvSceneSwitcher.condition.source.type.settingsChanged="Settings changed" AdvSceneSwitcher.condition.source.type.individualSettingMatches="Setting value matches" +AdvSceneSwitcher.condition.source.type.individualSettingListSelectionMatches="Settings value list selection matches" AdvSceneSwitcher.condition.source.type.individualSettingChanged="Setting value changed" AdvSceneSwitcher.condition.source.type.width="Width" AdvSceneSwitcher.condition.source.type.height="Height" @@ -530,6 +531,7 @@ AdvSceneSwitcher.condition.filter.type.showing="Is disabled" AdvSceneSwitcher.condition.filter.type.settingsMatch="Settings match" AdvSceneSwitcher.condition.filter.type.settingsChanged="Settings changed" AdvSceneSwitcher.condition.filter.type.individualSettingMatches="Settings value matches" +AdvSceneSwitcher.condition.filter.type.individualSettingListSelectionMatches="Settings value list selection matches" AdvSceneSwitcher.condition.filter.type.individualSettingChanged="Settings value changed" AdvSceneSwitcher.condition.filter.refresh="Refresh" AdvSceneSwitcher.condition.filter.refresh.tooltip="Repopulate the filter settings selection with the settings of the filter which's name matches the variable value." @@ -887,6 +889,7 @@ AdvSceneSwitcher.action.filter.entry="On{{sources}}{{actions}}{{filters}}{{refre AdvSceneSwitcher.action.filter.entry.settings="{{settings}}{{settingsInputMethod}}{{settingValue}}{{tempVar}}" AdvSceneSwitcher.action.filter.getSettings="Get current settings" AdvSceneSwitcher.action.filter.inputMethod.individualManual="Set to fixed value" +AdvSceneSwitcher.action.filter.inputMethod.individualListEntryManual="Set to list entry" AdvSceneSwitcher.action.filter.inputMethod.individualTempvar="Set to macro property" AdvSceneSwitcher.action.filter.inputMethod.json="Set setting JSON string" AdvSceneSwitcher.action.source="Source" @@ -917,6 +920,7 @@ AdvSceneSwitcher.action.source.deinterlaceMode.yadif2x="Yadif 2x" AdvSceneSwitcher.action.source.deinterlaceOrder.topFieldFirst="Top Field First" AdvSceneSwitcher.action.source.deinterlaceOrder.bottomFieldFirst="Bottom Field First" AdvSceneSwitcher.action.source.inputMethod.individualManual="Set to fixed value" +AdvSceneSwitcher.action.source.inputMethod.individualListEntryManual="Set to list entry" AdvSceneSwitcher.action.source.inputMethod.individualTempvar="Set to macro property" AdvSceneSwitcher.action.source.inputMethod.json="Set setting JSON string" AdvSceneSwitcher.action.source.refresh="Refresh" diff --git a/lib/utils/ui-helpers.cpp b/lib/utils/ui-helpers.cpp index 902086aa..d40b2135 100644 --- a/lib/utils/ui-helpers.cpp +++ b/lib/utils/ui-helpers.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -104,6 +105,19 @@ int FindIdxInRagne(QComboBox *list, int start, int stop, return foundIdx; } +void SetRowVisibleByValue(QComboBox *list, const QString &value, bool show) +{ + int index = list->findText(value); + if (index == -1) { + return; + } + + auto view = qobject_cast(list->view()); + if (view) { + view->setRowHidden(index, !show); + } +} + QWidget *GetSettingsWindow() { return SettingsWindowIsOpened() ? AdvSceneSwitcher::window : nullptr; diff --git a/lib/utils/ui-helpers.hpp b/lib/utils/ui-helpers.hpp index 19c2ebae..6172a153 100644 --- a/lib/utils/ui-helpers.hpp +++ b/lib/utils/ui-helpers.hpp @@ -20,9 +20,12 @@ EXPORT QObject *HighlightWidget(QWidget *widget, QColor startColor, EXPORT void SetHeightToContentHeight(QListWidget *list); EXPORT void SetButtonIcon(QAbstractButton *button, const char *path); + EXPORT int FindIdxInRagne(QComboBox *list, int start, int stop, const std::string &value, Qt::MatchFlags = Qt::MatchExactly | Qt::MatchCaseSensitive); +EXPORT void SetRowVisibleByValue(QComboBox *list, const QString &value, + bool show); EXPORT bool DisplayMessage(const QString &msg, bool question = false, bool modal = true); diff --git a/plugins/base/macro-action-filter.cpp b/plugins/base/macro-action-filter.cpp index bddfd04d..c01c8b66 100644 --- a/plugins/base/macro-action-filter.cpp +++ b/plugins/base/macro-action-filter.cpp @@ -3,6 +3,7 @@ #include "json-helpers.hpp" #include "source-settings-helpers.hpp" #include "selection-helpers.hpp" +#include "ui-helpers.hpp" namespace advss { @@ -26,10 +27,13 @@ const static std::map actionTypes = { "AdvSceneSwitcher.action.filter.type.pressSettingsButton"}, }; -const static std::map +const static std::vector< + std::pair> inputMethods = { {MacroActionFilter::SettingsInputMethod::INDIVIDUAL_MANUAL, "AdvSceneSwitcher.action.filter.inputMethod.individualManual"}, + {MacroActionFilter::SettingsInputMethod::INDIVIDUAL_LIST_ENTRY, + "AdvSceneSwitcher.action.filter.inputMethod.individualListEntryManual"}, {MacroActionFilter::SettingsInputMethod::INDIVIDUAL_TEMPVAR, "AdvSceneSwitcher.action.filter.inputMethod.individualTempvar"}, {MacroActionFilter::SettingsInputMethod::JSON_STRING, @@ -59,6 +63,10 @@ static void performActionHelper( case MacroActionFilter::SettingsInputMethod::INDIVIDUAL_MANUAL: SetSourceSetting(source, setting, manualSettingValue); break; + case MacroActionFilter::SettingsInputMethod::INDIVIDUAL_LIST_ENTRY: + SetSourceSettingListEntryValueByName( + source, setting, manualSettingValue); + break; case MacroActionFilter::SettingsInputMethod::INDIVIDUAL_TEMPVAR: { auto var = tempVar.GetTempVariable(macro); if (!var) { @@ -373,6 +381,16 @@ void MacroActionFilterEdit::GetSettingsClicked() .value_or("")); break; } + case MacroActionFilter::SettingsInputMethod::INDIVIDUAL_LIST_ENTRY: { + const auto filters = + _entryData->_filter.GetFilters(_entryData->_source); + _manualSettingValue->setPlainText( + GetSourceSettingListEntryName( + filters.empty() ? nullptr : filters.at(0), + _entryData->_setting) + .value_or("")); + break; + } case MacroActionFilter::SettingsInputMethod::INDIVIDUAL_TEMPVAR: break; case MacroActionFilter::SettingsInputMethod::JSON_STRING: { @@ -415,6 +433,7 @@ void MacroActionFilterEdit::SelectionChanged(const SourceSetting &setting) { GUARD_LOADING_AND_LOCK(); _entryData->_setting = setting; + SetWidgetVisibility(); } void MacroActionFilterEdit::ManualSettingsValueChanged() @@ -440,6 +459,22 @@ void MacroActionFilterEdit::ButtonChanged(const SourceSettingButton &button) _entryData->_button = button; } +static QString GetIndividualListEntryName() +{ + static const auto matchesInput = + [](const std::pair &p) { + return p.first == + MacroActionFilter::SettingsInputMethod:: + INDIVIDUAL_LIST_ENTRY; + }; + static const QString listValueText( + obs_module_text(std::find_if(inputMethods.begin(), + inputMethods.end(), matchesInput) + ->second.c_str())); + return listValueText; +} + void MacroActionFilterEdit::SetWidgetVisibility() { SetLayoutVisible(_settingsLayout, @@ -464,9 +499,16 @@ void MacroActionFilterEdit::SetWidgetVisibility() MacroActionFilter::SettingsInputMethod:: INDIVIDUAL_TEMPVAR); + SetRowVisibleByValue(_settingsInputMethods, + GetIndividualListEntryName(), + _entryData->_setting.IsList()); + if (_entryData->_action == MacroActionFilter::Action::SETTINGS && - _entryData->_settingsInputMethod == - MacroActionFilter::SettingsInputMethod::INDIVIDUAL_MANUAL) { + (_entryData->_settingsInputMethod == + MacroActionFilter::SettingsInputMethod::INDIVIDUAL_MANUAL || + _entryData->_settingsInputMethod == + MacroActionFilter::SettingsInputMethod:: + INDIVIDUAL_LIST_ENTRY)) { RemoveStretchIfPresent(_settingsLayout); _manualSettingValue->show(); } else { @@ -475,8 +517,12 @@ void MacroActionFilterEdit::SetWidgetVisibility() } _refreshSettingSelection->setVisible( - _entryData->_settingsInputMethod == - MacroActionFilter::SettingsInputMethod::INDIVIDUAL_MANUAL && + (_entryData->_settingsInputMethod == + MacroActionFilter::SettingsInputMethod:: + INDIVIDUAL_MANUAL || + _entryData->_settingsInputMethod == + MacroActionFilter::SettingsInputMethod:: + INDIVIDUAL_LIST_ENTRY) && (_entryData->_source.GetType() == SourceSelection::Type::VARIABLE || _entryData->_filter.GetType() == diff --git a/plugins/base/macro-action-filter.hpp b/plugins/base/macro-action-filter.hpp index e6eebed4..19da4425 100644 --- a/plugins/base/macro-action-filter.hpp +++ b/plugins/base/macro-action-filter.hpp @@ -36,6 +36,7 @@ public: INDIVIDUAL_MANUAL, INDIVIDUAL_TEMPVAR, JSON_STRING, + INDIVIDUAL_LIST_ENTRY, }; SettingsInputMethod _settingsInputMethod = SettingsInputMethod::INDIVIDUAL_MANUAL; diff --git a/plugins/base/macro-action-source.cpp b/plugins/base/macro-action-source.cpp index a3abd4f1..f7ae5743 100644 --- a/plugins/base/macro-action-source.cpp +++ b/plugins/base/macro-action-source.cpp @@ -3,6 +3,7 @@ #include "json-helpers.hpp" #include "selection-helpers.hpp" #include "source-settings-helpers.hpp" +#include "ui-helpers.hpp" #include @@ -67,10 +68,13 @@ const static std::map "AdvSceneSwitcher.action.source.deinterlaceOrder.bottomFieldFirst"}, }; -const static std::map +static const std::vector< + std::pair> inputMethods = { {MacroActionSource::SettingsInputMethod::INDIVIDUAL_MANUAL, "AdvSceneSwitcher.action.source.inputMethod.individualManual"}, + {MacroActionSource::SettingsInputMethod::INDIVIDUAL_LIST_ENTRY, + "AdvSceneSwitcher.action.source.inputMethod.individualListEntryManual"}, {MacroActionSource::SettingsInputMethod::INDIVIDUAL_TEMPVAR, "AdvSceneSwitcher.action.source.inputMethod.individualTempvar"}, {MacroActionSource::SettingsInputMethod::JSON_STRING, @@ -119,6 +123,10 @@ bool MacroActionSource::PerformAction() case SettingsInputMethod::INDIVIDUAL_MANUAL: SetSourceSetting(s, _setting, _manualSettingValue); break; + case SettingsInputMethod::INDIVIDUAL_LIST_ENTRY: + SetSourceSettingListEntryValueByName( + s, _setting, _manualSettingValue); + break; case SettingsInputMethod::INDIVIDUAL_TEMPVAR: { auto var = _tempVar.GetTempVariable(GetMacro()); if (!var) { @@ -263,9 +271,8 @@ static inline void populateActionSelection(QComboBox *list) } } -template -static inline void populateModeSelection(QComboBox *list, - const std::map &modes) +template +static inline void populateModeSelection(QComboBox *list, const T &modes) { list->clear(); for (const auto &[value, name] : modes) { @@ -343,7 +350,7 @@ MacroActionSourceEdit::MacroActionSourceEdit( auto entryLayout = new QHBoxLayout; entryLayout->setContentsMargins(0, 0, 0, 0); - std::unordered_map widgetPlaceholders = { + const std::unordered_map widgetPlaceholders = { {"{{sources}}", _sources}, {"{{actions}}", _actions}, {"{{settings}}", _sourceSettings}, @@ -444,6 +451,13 @@ void MacroActionSourceEdit::GetSettingsClicked() _entryData->_setting) .value_or("")); break; + case MacroActionSource::SettingsInputMethod::INDIVIDUAL_LIST_ENTRY: + _manualSettingValue->setPlainText( + GetSourceSettingListEntryName( + _entryData->_source.GetSource(), + _entryData->_setting) + .value_or("")); + break; case MacroActionSource::SettingsInputMethod::INDIVIDUAL_TEMPVAR: break; case MacroActionSource::SettingsInputMethod::JSON_STRING: @@ -497,6 +511,7 @@ void MacroActionSourceEdit::SelectionChanged(const SourceSetting &setting) { GUARD_LOADING_AND_LOCK(); _entryData->_setting = setting; + SetWidgetVisibility(); } void MacroActionSourceEdit::ManualSettingsValueChanged() @@ -514,6 +529,22 @@ void MacroActionSourceEdit::RefreshVariableSourceSelectionValue() _sourceSettings->SetSource(_entryData->_source.GetSource()); } +static QString GetIndividualListEntryName() +{ + static const auto matchesInput = + [](const std::pair &p) { + return p.first == + MacroActionSource::SettingsInputMethod:: + INDIVIDUAL_LIST_ENTRY; + }; + static const QString listValueText( + obs_module_text(std::find_if(inputMethods.begin(), + inputMethods.end(), matchesInput) + ->second.c_str())); + return listValueText; +} + void MacroActionSourceEdit::SetWidgetVisibility() { SetLayoutVisible(_settingsLayout, @@ -532,6 +563,11 @@ void MacroActionSourceEdit::SetWidgetVisibility() _entryData->_settingsInputMethod != MacroActionSource::SettingsInputMethod:: INDIVIDUAL_TEMPVAR); + + SetRowVisibleByValue(_settingsInputMethods, + GetIndividualListEntryName(), + _entryData->_setting.IsList()); + _tempVars->setVisible(_entryData->_action == MacroActionSource::Action::SETTINGS && _entryData->_settingsInputMethod == @@ -539,8 +575,11 @@ void MacroActionSourceEdit::SetWidgetVisibility() INDIVIDUAL_TEMPVAR); if (_entryData->_action == MacroActionSource::Action::SETTINGS && - _entryData->_settingsInputMethod == - MacroActionSource::SettingsInputMethod::INDIVIDUAL_MANUAL) { + (_entryData->_settingsInputMethod == + MacroActionSource::SettingsInputMethod::INDIVIDUAL_MANUAL || + _entryData->_settingsInputMethod == + MacroActionSource::SettingsInputMethod:: + INDIVIDUAL_LIST_ENTRY)) { RemoveStretchIfPresent(_settingsLayout); _manualSettingValue->show(); } else { @@ -563,8 +602,12 @@ void MacroActionSourceEdit::SetWidgetVisibility() MacroActionSource::Action::DEINTERLACE_FIELD_ORDER); _refreshSettingSelection->setVisible( - _entryData->_settingsInputMethod == - MacroActionSource::SettingsInputMethod::INDIVIDUAL_MANUAL && + (_entryData->_settingsInputMethod == + MacroActionSource::SettingsInputMethod:: + INDIVIDUAL_MANUAL || + _entryData->_settingsInputMethod == + MacroActionSource::SettingsInputMethod:: + INDIVIDUAL_LIST_ENTRY) && _entryData->_source.GetType() == SourceSelection::Type::VARIABLE); diff --git a/plugins/base/macro-action-source.hpp b/plugins/base/macro-action-source.hpp index e1452ce7..64543d33 100644 --- a/plugins/base/macro-action-source.hpp +++ b/plugins/base/macro-action-source.hpp @@ -52,6 +52,7 @@ public: INDIVIDUAL_MANUAL, INDIVIDUAL_TEMPVAR, JSON_STRING, + INDIVIDUAL_LIST_ENTRY, }; SettingsInputMethod _settingsInputMethod = SettingsInputMethod::INDIVIDUAL_MANUAL; diff --git a/plugins/base/macro-condition-filter.cpp b/plugins/base/macro-condition-filter.cpp index 23df67bf..7b171f7d 100644 --- a/plugins/base/macro-condition-filter.cpp +++ b/plugins/base/macro-condition-filter.cpp @@ -4,6 +4,7 @@ #include "text-helpers.hpp" #include "source-settings-helpers.hpp" #include "selection-helpers.hpp" +#include "ui-helpers.hpp" #include @@ -16,7 +17,7 @@ bool MacroConditionFilter::_registered = MacroConditionFactory::Register( {MacroConditionFilter::Create, MacroConditionFilterEdit::Create, "AdvSceneSwitcher.condition.filter"}); -const static std::map +static const std::vector> filterConditionTypes = { {MacroConditionFilter::Condition::ENABLED, "AdvSceneSwitcher.condition.filter.type.active"}, @@ -30,6 +31,9 @@ const static std::map "AdvSceneSwitcher.condition.filter.type.individualSettingMatches"}, {MacroConditionFilter::Condition::INDIVIDUAL_SETTING_CHANGED, "AdvSceneSwitcher.condition.filter.type.individualSettingChanged"}, + {MacroConditionFilter::Condition:: + INDIVIDUAL_SETTING_LIST_ENTRY_MATCH, + "AdvSceneSwitcher.condition.filter.type.individualSettingListSelectionMatches"}, }; bool MacroConditionFilter::CheckConditionHelper(const OBSWeakSource &filter) @@ -73,6 +77,18 @@ bool MacroConditionFilter::CheckConditionHelper(const OBSWeakSource &filter) SetTempVarValue("setting", *value); break; } + case Condition::INDIVIDUAL_SETTING_LIST_ENTRY_MATCH: { + const auto entryName = + GetSourceSettingListEntryName(filter, _setting); + if (!entryName) { + return false; + } + ret = _regex.Enabled() ? _regex.Matches(*entryName, _settings) + : entryName == std::string(_settings); + SetVariableValue(*entryName); + SetTempVarValue("setting", *entryName); + break; + } case Condition::INDIVIDUAL_SETTING_CHANGED: { auto value = GetSourceSettingValue(filter, _setting); if (!value) { @@ -168,6 +184,7 @@ void MacroConditionFilter::SetupTempVars() "AdvSceneSwitcher.tempVar.filter.settings")); break; case Condition::INDIVIDUAL_SETTING_MATCH: + case Condition::INDIVIDUAL_SETTING_LIST_ENTRY_MATCH: case Condition::INDIVIDUAL_SETTING_CHANGED: AddTempvar("setting", obs_module_text( @@ -180,8 +197,9 @@ void MacroConditionFilter::SetupTempVars() static inline void populateConditionSelection(QComboBox *list) { - for (const auto &[_, name] : filterConditionTypes) { - list->addItem(obs_module_text(name.c_str())); + for (const auto &[value, name] : filterConditionTypes) { + list->addItem(obs_module_text(name.c_str()), + static_cast(value)); } } @@ -232,7 +250,7 @@ MacroConditionFilterEdit::MacroConditionFilterEdit( QWidget::connect(_refreshSettingSelection, SIGNAL(clicked()), this, SLOT(RefreshVariableSourceSelectionValue())); - std::unordered_map widgetPlaceholders = { + const std::unordered_map widgetPlaceholders = { {"{{sources}}", _sources}, {"{{filters}}", _filters}, {"{{conditions}}", _conditions}, @@ -292,8 +310,8 @@ void MacroConditionFilterEdit::FilterChanged(const FilterSelection &filter) void MacroConditionFilterEdit::ConditionChanged(int index) { GUARD_LOADING_AND_LOCK(); - _entryData->SetCondition( - static_cast(index)); + _entryData->SetCondition(static_cast( + _conditions->itemData(index).toInt())); SetWidgetVisibility(); } @@ -315,6 +333,14 @@ void MacroConditionFilterEdit::GetSettingsClicked() if (_entryData->GetCondition() == MacroConditionFilter::Condition::SETTINGS_MATCH) { value = FormatJsonString(GetSourceSettings(filters.at(0))); + } else if (_entryData->GetCondition() == + MacroConditionFilter::Condition:: + INDIVIDUAL_SETTING_LIST_ENTRY_MATCH) { + value = QString::fromStdString( + GetSourceSettingListEntryName( + filters.empty() ? nullptr : filters.at(0), + _entryData->_setting) + .value_or("")); } else { value = QString::fromStdString( GetSourceSettingValue(filters.at(0), @@ -351,6 +377,7 @@ void MacroConditionFilterEdit::SettingSelectionChanged( { GUARD_LOADING_AND_LOCK(); _entryData->_setting = setting; + SetWidgetVisibility(); } void MacroConditionFilterEdit::RefreshVariableSourceSelectionValue() @@ -360,29 +387,59 @@ void MacroConditionFilterEdit::RefreshVariableSourceSelectionValue() _settingSelection->SetSource(filters.empty() ? nullptr : filters.at(0)); } +static QString GetIndividualListEntryName() +{ + static const auto matchesInput = + [](const std::pair + &p) { + return p.first == + MacroConditionFilter::Condition:: + INDIVIDUAL_SETTING_LIST_ENTRY_MATCH; + }; + static const QString listValueText(obs_module_text( + std::find_if(filterConditionTypes.begin(), + filterConditionTypes.end(), matchesInput) + ->second.c_str())); + return listValueText; +} + void MacroConditionFilterEdit::SetWidgetVisibility() { const bool showSettingsControls = _entryData->GetCondition() == MacroConditionFilter::Condition::SETTINGS_MATCH || _entryData->GetCondition() == - MacroConditionFilter::Condition::INDIVIDUAL_SETTING_MATCH; + MacroConditionFilter::Condition::INDIVIDUAL_SETTING_MATCH || + _entryData->GetCondition() == + MacroConditionFilter::Condition:: + INDIVIDUAL_SETTING_LIST_ENTRY_MATCH; _settings->setVisible(showSettingsControls); _getSettings->setVisible(showSettingsControls); _regex->setVisible(showSettingsControls); _settingSelection->setVisible( _entryData->GetCondition() == MacroConditionFilter::Condition::INDIVIDUAL_SETTING_MATCH || + _entryData->GetCondition() == + MacroConditionFilter::Condition:: + INDIVIDUAL_SETTING_LIST_ENTRY_MATCH || _entryData->GetCondition() == MacroConditionFilter::Condition:: INDIVIDUAL_SETTING_CHANGED); _refreshSettingSelection->setVisible( - _entryData->GetCondition() == - MacroConditionFilter::Condition::INDIVIDUAL_SETTING_MATCH && + (_entryData->GetCondition() == + MacroConditionFilter::Condition:: + INDIVIDUAL_SETTING_MATCH || + _entryData->GetCondition() == + MacroConditionFilter::Condition:: + INDIVIDUAL_SETTING_LIST_ENTRY_MATCH) && (_entryData->_source.GetType() == SourceSelection::Type::VARIABLE || _entryData->_filter.GetType() == FilterSelection::Type::VARIABLE)); + + SetRowVisibleByValue(_conditions, GetIndividualListEntryName(), + _entryData->_setting.IsList()); + adjustSize(); updateGeometry(); } @@ -395,8 +452,8 @@ void MacroConditionFilterEdit::UpdateEntryData() _sources->SetSource(_entryData->_source); _filters->SetFilter(_entryData->_source, _entryData->_filter); - _conditions->setCurrentIndex( - static_cast(_entryData->GetCondition())); + _conditions->setCurrentIndex(_conditions->findData( + static_cast(_entryData->GetCondition()))); _settings->setPlainText(_entryData->_settings); _regex->SetRegexConfig(_entryData->_regex); const auto filters = diff --git a/plugins/base/macro-condition-filter.hpp b/plugins/base/macro-condition-filter.hpp index 313718c5..364fc56e 100644 --- a/plugins/base/macro-condition-filter.hpp +++ b/plugins/base/macro-condition-filter.hpp @@ -32,6 +32,7 @@ public: SETTINGS_CHANGED, INDIVIDUAL_SETTING_MATCH, INDIVIDUAL_SETTING_CHANGED, + INDIVIDUAL_SETTING_LIST_ENTRY_MATCH, }; void SetCondition(Condition); Condition GetCondition() const { return _condition; } diff --git a/plugins/base/macro-condition-source.cpp b/plugins/base/macro-condition-source.cpp index 79898334..9fcc0cbb 100644 --- a/plugins/base/macro-condition-source.cpp +++ b/plugins/base/macro-condition-source.cpp @@ -4,6 +4,7 @@ #include "text-helpers.hpp" #include "selection-helpers.hpp" #include "source-settings-helpers.hpp" +#include "ui-helpers.hpp" namespace advss { @@ -14,7 +15,7 @@ bool MacroConditionSource::_registered = MacroConditionFactory::Register( {MacroConditionSource::Create, MacroConditionSourceEdit::Create, "AdvSceneSwitcher.condition.source"}); -static const std::map +static const std::vector> sourceConditionTypes = { {MacroConditionSource::Condition::ACTIVE, "AdvSceneSwitcher.condition.source.type.active"}, @@ -26,6 +27,9 @@ static const std::map "AdvSceneSwitcher.condition.source.type.settingsChanged"}, {MacroConditionSource::Condition::INDIVIDUAL_SETTING_MATCH, "AdvSceneSwitcher.condition.source.type.individualSettingMatches"}, + {MacroConditionSource::Condition:: + INDIVIDUAL_SETTING_LIST_ENTRY_MATCH, + "AdvSceneSwitcher.condition.source.type.individualSettingListSelectionMatches"}, {MacroConditionSource::Condition::INDIVIDUAL_SETTING_CHANGED, "AdvSceneSwitcher.condition.source.type.individualSettingChanged"}, {MacroConditionSource::Condition::HEIGHT, @@ -105,6 +109,18 @@ bool MacroConditionSource::CheckCondition() SetTempVarValue("setting", *value); break; } + case Condition::INDIVIDUAL_SETTING_LIST_ENTRY_MATCH: { + const auto entryName = GetSourceSettingListEntryName( + _source.GetSource(), _setting); + if (!entryName) { + return false; + } + ret = _regex.Enabled() ? _regex.Matches(*entryName, _settings) + : entryName == std::string(_settings); + SetVariableValue(*entryName); + SetTempVarValue("setting", *entryName); + break; + } case Condition::INDIVIDUAL_SETTING_CHANGED: { const auto value = GetSourceSettingValue(_source.GetSource(), _setting); @@ -200,6 +216,7 @@ void MacroConditionSource::SetupTempVars() "AdvSceneSwitcher.tempVar.source.settings")); break; case Condition::INDIVIDUAL_SETTING_MATCH: + case Condition::INDIVIDUAL_SETTING_LIST_ENTRY_MATCH: case Condition::INDIVIDUAL_SETTING_CHANGED: AddTempvar("setting", obs_module_text( @@ -221,11 +238,11 @@ void MacroConditionSource::SetupTempVars() } template -static inline void populateSelection(QComboBox *list, - const std::map &map) +static inline void populateSelection(QComboBox *list, const T &map) { - for (const auto &[_, name] : map) { - list->addItem(obs_module_text(name.c_str())); + for (const auto &[value, name] : map) { + list->addItem(obs_module_text(name.c_str()), + static_cast(value)); } } @@ -333,8 +350,8 @@ void MacroConditionSourceEdit::SourceChanged(const SourceSelection &source) void MacroConditionSourceEdit::ConditionChanged(int index) { GUARD_LOADING_AND_LOCK(); - _entryData->SetCondition( - static_cast(index)); + _entryData->SetCondition(static_cast( + _conditions->itemData(index).toInt())); SetWidgetVisibility(); } @@ -349,6 +366,14 @@ void MacroConditionSourceEdit::GetSettingsClicked() MacroConditionSource::Condition::ALL_SETTINGS_MATCH) { value = FormatJsonString( GetSourceSettings(_entryData->_source.GetSource())); + } else if (_entryData->GetCondition() == + MacroConditionSource::Condition:: + INDIVIDUAL_SETTING_LIST_ENTRY_MATCH) { + value = QString::fromStdString( + GetSourceSettingListEntryName( + _entryData->_source.GetSource(), + _entryData->_setting) + .value_or("")); } else { value = QString::fromStdString( GetSourceSettingValue(_entryData->_source.GetSource(), @@ -385,6 +410,7 @@ void MacroConditionSourceEdit::SettingSelectionChanged( { GUARD_LOADING_AND_LOCK(); _entryData->_setting = setting; + SetWidgetVisibility(); } void MacroConditionSourceEdit::RefreshVariableSourceSelectionValue() @@ -405,19 +431,41 @@ void MacroConditionSourceEdit::CompareMethodChanged(int index) static_cast(index); } +static QString GetIndividualListEntryName() +{ + static const auto matchesInput = + [](const std::pair + &p) { + return p.first == + MacroConditionSource::Condition:: + INDIVIDUAL_SETTING_LIST_ENTRY_MATCH; + }; + static const QString listValueText(obs_module_text( + std::find_if(sourceConditionTypes.begin(), + sourceConditionTypes.end(), matchesInput) + ->second.c_str())); + return listValueText; +} + void MacroConditionSourceEdit::SetWidgetVisibility() { const bool settingsMatch = _entryData->GetCondition() == MacroConditionSource::Condition::ALL_SETTINGS_MATCH || _entryData->GetCondition() == - MacroConditionSource::Condition::INDIVIDUAL_SETTING_MATCH; + MacroConditionSource::Condition::INDIVIDUAL_SETTING_MATCH || + _entryData->GetCondition() == + MacroConditionSource::Condition:: + INDIVIDUAL_SETTING_LIST_ENTRY_MATCH; _settings->setVisible(settingsMatch); _getSettings->setVisible(settingsMatch); _regex->setVisible(settingsMatch); _settingSelection->setVisible( _entryData->GetCondition() == MacroConditionSource::Condition::INDIVIDUAL_SETTING_MATCH || + _entryData->GetCondition() == + MacroConditionSource::Condition:: + INDIVIDUAL_SETTING_LIST_ENTRY_MATCH || _entryData->GetCondition() == MacroConditionSource::Condition:: INDIVIDUAL_SETTING_CHANGED); @@ -432,8 +480,12 @@ void MacroConditionSourceEdit::SetWidgetVisibility() : ""); _refreshSettingSelection->setVisible( - _entryData->GetCondition() == - MacroConditionSource::Condition::INDIVIDUAL_SETTING_MATCH && + (_entryData->GetCondition() == + MacroConditionSource::Condition:: + INDIVIDUAL_SETTING_MATCH || + _entryData->GetCondition() == + MacroConditionSource::Condition:: + INDIVIDUAL_SETTING_LIST_ENTRY_MATCH) && _entryData->_source.GetType() == SourceSelection::Type::VARIABLE); @@ -445,6 +497,9 @@ void MacroConditionSourceEdit::SetWidgetVisibility() _size->setVisible(isSizeCheck); _sizeCompareMethods->setVisible(isSizeCheck); + SetRowVisibleByValue(_conditions, GetIndividualListEntryName(), + _entryData->_setting.IsList()); + adjustSize(); updateGeometry(); } @@ -456,8 +511,8 @@ void MacroConditionSourceEdit::UpdateEntryData() } _sources->SetSource(_entryData->_source); - _conditions->setCurrentIndex( - static_cast(_entryData->GetCondition())); + _conditions->setCurrentIndex(_conditions->findData( + static_cast(_entryData->GetCondition()))); _settings->setPlainText(_entryData->_settings); _regex->SetRegexConfig(_entryData->_regex); _settingSelection->SetSelection(_entryData->_source.GetSource(), diff --git a/plugins/base/macro-condition-source.hpp b/plugins/base/macro-condition-source.hpp index 88f41b75..89f90810 100644 --- a/plugins/base/macro-condition-source.hpp +++ b/plugins/base/macro-condition-source.hpp @@ -33,6 +33,7 @@ public: INDIVIDUAL_SETTING_CHANGED, HEIGHT, WIDTH, + INDIVIDUAL_SETTING_LIST_ENTRY_MATCH, }; void SetCondition(Condition); Condition GetCondition() const { return _condition; } diff --git a/plugins/base/utils/source-setting.cpp b/plugins/base/utils/source-setting.cpp index 8acee1a8..9ca3d17a 100644 --- a/plugins/base/utils/source-setting.cpp +++ b/plugins/base/utils/source-setting.cpp @@ -9,12 +9,16 @@ Q_DECLARE_METATYPE(advss::SourceSetting); +using properties_delete_t = decltype(&obs_properties_destroy); +using properties_t = std::unique_ptr; + namespace advss { -SourceSetting::SourceSetting(const std::string &id, +SourceSetting::SourceSetting(const std::string &id, obs_property_type type, const std::string &description, const std::string &longDescription) : _id(id), + _type(type), _description(description), _longDescription(longDescription) { @@ -24,6 +28,7 @@ bool SourceSetting::Save(obs_data_t *obj) const { OBSDataAutoRelease data = obs_data_create(); obs_data_set_string(data, "id", _id.c_str()); + obs_data_set_int(data, "type", _type); obs_data_set_string(data, "description", _description.c_str()); obs_data_set_obj(obj, "sourceSetting", data); return true; @@ -33,10 +38,21 @@ bool SourceSetting::Load(obs_data_t *obj) { OBSDataAutoRelease data = obs_data_get_obj(obj, "sourceSetting"); _id = obs_data_get_string(data, "id"); + _type = static_cast(obs_data_get_int(data, "type")); _description = obs_data_get_string(data, "description"); return true; } +static bool isListType(obs_property_type type) +{ + return type == OBS_PROPERTY_LIST || type == OBS_PROPERTY_EDITABLE_LIST; +} + +bool SourceSetting::IsList() const +{ + return isListType(_type); +} + bool SourceSetting::operator==(const SourceSetting &other) const { return _id == other._id; @@ -85,7 +101,7 @@ static void addSettingsHelper(obs_property_t *property, if (!property) { continue; } - auto type = obs_property_get_type(property); + const auto type = obs_property_get_type(property); if (type == OBS_PROPERTY_GROUP) { auto group = obs_property_group_content(property); auto description = obs_property_description(property); @@ -110,7 +126,8 @@ static void addSettingsHelper(obs_property_t *property, prefix + description + obs_module_text(getPropertySuffix(type)); auto longDescription = obs_property_long_description(property); - SourceSetting setting(name, descriptionWithPrefixAndSuffix, + SourceSetting setting(name, type, + descriptionWithPrefixAndSuffix, longDescription ? longDescription : ""); settings.emplace_back(setting); } while (obs_property_next(&property)); @@ -118,19 +135,20 @@ static void addSettingsHelper(obs_property_t *property, std::vector GetSoruceSettings(obs_source_t *source) { - auto properties = obs_source_properties(source); + properties_t properties(obs_source_properties(source), + obs_properties_destroy); if (!properties) { return {}; } std::vector settings; - auto it = obs_properties_first(properties); + + auto it = obs_properties_first(properties.get()); addSettingsHelper(it, settings); - obs_properties_destroy(properties); return settings; } -std::optional GetSourceSettingValue(const OBSWeakSource &ws, - const SourceSetting &setting) +static std::optional +getDataJsonWithDefaults(const OBSWeakSource &ws) { OBSSourceAutoRelease source = obs_weak_source_get_source(ws); OBSDataAutoRelease data = obs_source_get_settings(source); @@ -143,10 +161,139 @@ std::optional GetSourceSettingValue(const OBSWeakSource &ws, if (!json) { return {}; } - auto value = GetJsonField(json, setting.GetID()); + return json; +} + +std::optional GetSourceSettingValue(const OBSWeakSource &source, + const SourceSetting &setting) +{ + const auto json = getDataJsonWithDefaults(source); + if (!json) { + return {}; + } + auto value = GetJsonField(*json, setting.GetID()); return value; } +static obs_property_t *findListPropertyByIdHelper(obs_property_t *property, + const std::string &id) +{ + do { + if (!property) { + continue; + } + + const auto type = obs_property_get_type(property); + if (type == OBS_PROPERTY_GROUP) { + auto group = obs_property_group_content(property); + findListPropertyByIdHelper(obs_properties_first(group), + id); + continue; + } + + if (!isListType(type)) { + continue; + } + + auto name = obs_property_name(property); + if (name != id) { + continue; + } + + return property; + + } while (obs_property_next(&property)); + + return nullptr; +} + +static std::pair +findListPropertyById(const obs_source_t *source, const std::string &id) +{ + // Note: + // Using obs_source_properties() here might cause flickering for some + // sources, as this will call obs_properties_apply_settings() + // implicitly. + // So, we use obs_get_source_properties() instead. + // + // 20250617: This might cause issues with the move plugin as it doesn't + // handle obs_get_source_properties() properly in the move filter + auto properties = obs_get_source_properties(obs_source_get_id(source)); + if (!properties) { + return {nullptr, properties_t(nullptr, obs_properties_destroy)}; + } + auto property = obs_properties_first(properties); + return {findListPropertyByIdHelper(property, id), + properties_t(nullptr, obs_properties_destroy)}; +} + +static std::pair +findListPropertyById(const OBSWeakSource &ws, const std::string &id) +{ + OBSSourceAutoRelease source = obs_weak_source_get_source(ws); + return findListPropertyById(source.Get(), id); +} + +std::optional +GetSourceSettingListEntryName(const OBSWeakSource &source, + const SourceSetting &setting) +{ + if (!setting.IsList()) { + return {}; + } + + const auto json = getDataJsonWithDefaults(source); + if (!json) { + return {}; + } + + const auto &[property, properties] = + findListPropertyById(source, setting.GetID()); + if (!property) { + return {}; + } + + const auto type = obs_property_list_format(property); + if (type == OBS_COMBO_FORMAT_INVALID) { + return {}; + } + + auto currentValue = GetJsonField(*json, setting.GetID()); + if (!currentValue) { + return {}; + } + + const auto count = obs_property_list_item_count(property); + for (size_t i = 0; i < count; i++) { + std::string value; + switch (type) { + case OBS_COMBO_FORMAT_INT: + value = std::to_string( + obs_property_list_item_int(property, i)); + break; + case OBS_COMBO_FORMAT_FLOAT: + value = std::to_string( + obs_property_list_item_float(property, i)); + break; + case OBS_COMBO_FORMAT_STRING: + value = obs_property_list_item_string(property, i); + break; + case OBS_COMBO_FORMAT_BOOL: + value = std::to_string( + obs_property_list_item_bool(property, i)); + break; + default: + break; + } + + if (value == currentValue) { + return obs_property_list_item_name(property, i); + } + } + + return {}; +} + void SetSourceSetting(obs_source_t *source, const SourceSetting &setting, const std::string &value) { @@ -233,6 +380,63 @@ void SetSourceSetting(obs_source_t *source, const SourceSetting &setting, obs_source_update(source, data); } +void SetSourceSettingListEntryValueByName(obs_source_t *source, + const SourceSetting &setting, + const std::string &name) +{ + if (!setting.IsList()) { + return; + } + + const auto &[property, properties] = + findListPropertyById(source, setting.GetID()); + if (!property) { + return; + } + + const auto type = obs_property_list_format(property); + if (type == OBS_COMBO_FORMAT_INVALID) { + return; + } + + const auto count = obs_property_list_item_count(property); + bool found = false; + size_t idx = 0; + for (; idx < count; idx++) { + if (obs_property_list_item_name(property, idx) == name) { + found = true; + break; + } + } + + if (!found) { + return; + } + + std::string value; + switch (type) { + case OBS_COMBO_FORMAT_INT: + value = std::to_string( + obs_property_list_item_int(property, idx)); + break; + case OBS_COMBO_FORMAT_FLOAT: + value = std::to_string( + obs_property_list_item_float(property, idx)); + break; + case OBS_COMBO_FORMAT_STRING: + value = obs_property_list_item_string(property, idx); + break; + case OBS_COMBO_FORMAT_BOOL: + value = std::to_string( + obs_property_list_item_bool(property, idx)); + break; + default: + break; + } + + SetSourceSetting(source, setting, value); +} + SourceSettingSelection::SourceSettingSelection(QWidget *parent) : QWidget(parent), _settings(new FilterComboBox( diff --git a/plugins/base/utils/source-setting.hpp b/plugins/base/utils/source-setting.hpp index 0b78841d..343a6e31 100644 --- a/plugins/base/utils/source-setting.hpp +++ b/plugins/base/utils/source-setting.hpp @@ -14,15 +14,18 @@ namespace advss { class SourceSetting { public: SourceSetting() = default; - SourceSetting(const std::string &id, const std::string &description, + SourceSetting(const std::string &id, obs_property_type type, + const std::string &description, const std::string &longDescription = ""); bool Save(obs_data_t *obj) const; bool Load(obs_data_t *obj); std::string GetID() const { return _id; } - EXPORT bool operator==(const SourceSetting &other) const; + bool IsList() const; + bool operator==(const SourceSetting &other) const; private: std::string _id = ""; + obs_property_type _type = OBS_PROPERTY_INVALID; std::string _description = ""; std::string _longDescription = ""; @@ -32,8 +35,14 @@ private: std::vector GetSoruceSettings(obs_source_t *source); std::optional GetSourceSettingValue(const OBSWeakSource &source, const SourceSetting &setting); +std::optional +GetSourceSettingListEntryName(const OBSWeakSource &source, + const SourceSetting &setting); void SetSourceSetting(obs_source_t *source, const SourceSetting &setting, const std::string &value); +void SetSourceSettingListEntryValueByName(obs_source_t *source, + const SourceSetting &setting, + const std::string &name); class SourceSettingSelection : public QWidget { Q_OBJECT diff --git a/tests/mocks/ui-helpers.cpp b/tests/mocks/ui-helpers.cpp index ea2d5625..0d049280 100644 --- a/tests/mocks/ui-helpers.cpp +++ b/tests/mocks/ui-helpers.cpp @@ -20,6 +20,11 @@ int FindIdxInRagne(QComboBox *list, int start, int stop, return -1; } +void SetRowMatchingValueVisible(QComboBox *list, const QString &value, + bool show) +{ +} + bool DisplayMessage(const QString &msg, bool question, bool modal) { return false;