diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e51f813..00f36af5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -251,6 +251,8 @@ target_sources( src/utils/log-helper.hpp src/utils/file-selection.cpp src/utils/file-selection.hpp + src/utils/filter-selection.cpp + src/utils/filter-selection.hpp src/utils/macro-list.cpp src/utils/macro-list.hpp src/utils/math-helpers.cpp diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 33a8140e..7a47351f 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -319,7 +319,7 @@ AdvSceneSwitcher.condition.filter.type.settings="Settings match" AdvSceneSwitcher.condition.filter.getSettings="Get current settings" AdvSceneSwitcher.condition.filter.entry.line1="On {{sources}} {{filters}} {{conditions}}" AdvSceneSwitcher.condition.filter.entry.line2="{{settings}}" -AdvSceneSwitcher.condition.filter.entry.line3="{{regex}} {{getSettings}}" +AdvSceneSwitcher.condition.filter.entry.line3="{{regex}}{{getSettings}}" AdvSceneSwitcher.condition.sceneOrder="Scene item order" AdvSceneSwitcher.condition.sceneOrder.type.above="Is above" AdvSceneSwitcher.condition.sceneOrder.type.below="Is below" diff --git a/src/macro-core/macro-action-filter.cpp b/src/macro-core/macro-action-filter.cpp index f7e20249..b0b27ca6 100644 --- a/src/macro-core/macro-action-filter.cpp +++ b/src/macro-core/macro-action-filter.cpp @@ -19,24 +19,9 @@ const static std::map actionTypes = { "AdvSceneSwitcher.action.filter.type.settings"}, }; -void MacroActionFilter::ResolveVariables() -{ - if (_source.GetType() == SourceSelection::Type::SOURCE) { - return; - } - - std::string name = GetWeakSourceName(_filter); - if (!name.empty()) { - _filterName = name; - } - _filter = GetWeakFilterByName(_source.GetSource(), _filterName.c_str()); -} - bool MacroActionFilter::PerformAction() { - ResolveVariables(); - - auto s = obs_weak_source_get_source(_filter); + auto s = obs_weak_source_get_source(_filter.GetFilter(_source)); switch (_action) { case Action::ENABLE: obs_source_set_enabled(s, true); @@ -60,7 +45,7 @@ void MacroActionFilter::LogAction() const if (it != actionTypes.end()) { vblog(LOG_INFO, "performed action \"%s\" for filter \"%s\" on source \"%s\"", - it->second.c_str(), GetWeakSourceName(_filter).c_str(), + it->second.c_str(), _filter.ToString().c_str(), _source.ToString(true).c_str()); } else { blog(LOG_WARNING, "ignored unknown filter action %d", @@ -72,7 +57,7 @@ bool MacroActionFilter::Save(obs_data_t *obj) const { MacroAction::Save(obj); _source.Save(obj); - obs_data_set_string(obj, "filter", _filterName.c_str()); + _filter.Save(obj, "filter"); obs_data_set_int(obj, "action", static_cast(_action)); _settings.Save(obj, "settings"); return true; @@ -82,9 +67,7 @@ bool MacroActionFilter::Load(obs_data_t *obj) { MacroAction::Load(obj); _source.Load(obj); - _filterName = obs_data_get_string(obj, "filter"); - _filter = GetWeakFilterByQString(_source.GetSource(), - _filterName.c_str()); + _filter.Load(obj, _source, "filter"); _action = static_cast(obs_data_get_int(obj, "action")); _settings.Load(obj, "settings"); return true; @@ -92,8 +75,8 @@ bool MacroActionFilter::Load(obs_data_t *obj) std::string MacroActionFilter::GetShortDesc() const { - if (_filter && !_source.ToString().empty()) { - return _source.ToString() + " - " + GetWeakSourceName(_filter); + if (!_filter.ToString().empty() && !_source.ToString().empty()) { + return _source.ToString() + " - " + _filter.ToString(); } return ""; } @@ -109,7 +92,7 @@ MacroActionFilterEdit::MacroActionFilterEdit( QWidget *parent, std::shared_ptr entryData) : QWidget(parent), _sources(new SourceSelectionWidget(this, QStringList(), true)), - _filters(new QComboBox()), + _filters(new FilterSelectionWidget(this, _sources, true)), _actions(new QComboBox()), _getSettings(new QPushButton(obs_module_text( "AdvSceneSwitcher.action.filter.getSettings"))), @@ -127,8 +110,9 @@ MacroActionFilterEdit::MacroActionFilterEdit( QWidget::connect(_sources, SIGNAL(SourceChanged(const SourceSelection &)), this, SLOT(SourceChanged(const SourceSelection &))); - QWidget::connect(_filters, SIGNAL(currentTextChanged(const QString &)), - this, SLOT(FilterChanged(const QString &))); + QWidget::connect(_filters, + SIGNAL(FilterChanged(const FilterSelection &)), this, + SLOT(FilterChanged(const FilterSelection &))); QWidget::connect(_getSettings, SIGNAL(clicked()), this, SLOT(GetSettingsClicked())); QWidget::connect(_settings, SIGNAL(textChanged()), this, @@ -147,6 +131,7 @@ MacroActionFilterEdit::MacroActionFilterEdit( QHBoxLayout *buttonLayout = new QHBoxLayout; buttonLayout->addWidget(_getSettings); buttonLayout->addStretch(); + buttonLayout->setContentsMargins(0, 0, 0, 0); QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addLayout(entryLayout); @@ -167,9 +152,7 @@ void MacroActionFilterEdit::UpdateEntryData() _actions->setCurrentIndex(static_cast(_entryData->_action)); _sources->SetSource(_entryData->_source); - PopulateFilterSelection(_filters, _entryData->_source.GetSource()); - _filters->setCurrentText( - GetWeakSourceName(_entryData->_filter).c_str()); + _filters->SetFilter(_entryData->_source, _entryData->_filter); _settings->setPlainText(_entryData->_settings); SetWidgetVisibility(_entryData->_action == MacroActionFilter::Action::SETTINGS); @@ -183,25 +166,19 @@ void MacroActionFilterEdit::SourceChanged(const SourceSelection &source) if (_loading || !_entryData) { return; } - { - auto lock = LockContext(); - _entryData->_source = source; - } - _filters->clear(); - PopulateFilterSelection(_filters, _entryData->_source.GetSource()); - _filters->adjustSize(); + + auto lock = LockContext(); + _entryData->_source = source; } -void MacroActionFilterEdit::FilterChanged(const QString &text) +void MacroActionFilterEdit::FilterChanged(const FilterSelection &filter) { if (_loading || !_entryData) { return; } auto lock = LockContext(); - _entryData->_filterName = text.toStdString(); - _entryData->_filter = - GetWeakFilterByQString(_entryData->_source.GetSource(), text); + _entryData->_filter = filter; emit HeaderInfoChanged( QString::fromStdString(_entryData->GetShortDesc())); } @@ -220,13 +197,13 @@ void MacroActionFilterEdit::ActionChanged(int value) void MacroActionFilterEdit::GetSettingsClicked() { - if (_loading || !_entryData || !_entryData->_source.GetSource() || - !_entryData->_filter) { + if (_loading || !_entryData || + !_entryData->_filter.GetFilter(_entryData->_source)) { return; } - _settings->setPlainText( - FormatJsonString(GetSourceSettings(_entryData->_filter))); + _settings->setPlainText(FormatJsonString(GetSourceSettings( + _entryData->_filter.GetFilter(_entryData->_source)))); } void MacroActionFilterEdit::SettingsChanged() @@ -247,6 +224,7 @@ void MacroActionFilterEdit::SetWidgetVisibility(bool showSettings) _settings->setVisible(showSettings); _getSettings->setVisible(showSettings); adjustSize(); + updateGeometry(); } } // namespace advss diff --git a/src/macro-core/macro-action-filter.hpp b/src/macro-core/macro-action-filter.hpp index 2b506ddb..61501461 100644 --- a/src/macro-core/macro-action-filter.hpp +++ b/src/macro-core/macro-action-filter.hpp @@ -2,6 +2,7 @@ #include "macro-action-edit.hpp" #include "variable-text-edit.hpp" #include "source-selection.hpp" +#include "filter-selection.hpp" #include #include @@ -30,18 +31,13 @@ public: }; SourceSelection _source; - OBSWeakSource _filter; + FilterSelection _filter; Action _action = Action::ENABLE; StringVariable _settings = ""; private: - void ResolveVariables(); - std::string _filterName = ""; - static bool _registered; static const std::string id; - - friend class MacroActionFilterEdit; }; class MacroActionFilterEdit : public QWidget { @@ -62,7 +58,7 @@ public: private slots: void SourceChanged(const SourceSelection &); - void FilterChanged(const QString &); + void FilterChanged(const FilterSelection &); void ActionChanged(int value); void GetSettingsClicked(); void SettingsChanged(); @@ -71,7 +67,7 @@ signals: protected: SourceSelectionWidget *_sources; - QComboBox *_filters; + FilterSelectionWidget *_filters; QComboBox *_actions; QPushButton *_getSettings; VariableTextEdit *_settings; diff --git a/src/macro-core/macro-condition-filter.cpp b/src/macro-core/macro-condition-filter.cpp index d311001a..9c608e65 100644 --- a/src/macro-core/macro-condition-filter.cpp +++ b/src/macro-core/macro-condition-filter.cpp @@ -22,47 +22,34 @@ static std::map "AdvSceneSwitcher.condition.filter.type.settings"}, }; -void MacroConditionFilter::ResolveVariables() -{ - if (_source.GetType() == SourceSelection::Type::SOURCE) { - return; - } - - std::string name = GetWeakSourceName(_filter); - if (!name.empty()) { - _filterName = name; - } - _filter = GetWeakFilterByName(_source.GetSource(), _filterName.c_str()); -} - bool MacroConditionFilter::CheckCondition() { - ResolveVariables(); - if (!_source.GetSource()) { + auto filterWeakSource = _filter.GetFilter(_source); + if (!filterWeakSource) { return false; } + auto filterSource = obs_weak_source_get_source(filterWeakSource); bool ret = false; - auto s = obs_weak_source_get_source(_filter); - switch (_condition) { case Condition::ENABLED: - ret = obs_source_enabled(s); + ret = obs_source_enabled(filterSource); break; case Condition::DISABLED: - ret = !obs_source_enabled(s); + ret = !obs_source_enabled(filterSource); break; case Condition::SETTINGS: - ret = CompareSourceSettings(_filter, _settings, _regex); + ret = CompareSourceSettings(filterWeakSource, _settings, + _regex); if (IsReferencedInVars()) { - SetVariableValue(GetSourceSettings(_filter)); + SetVariableValue(GetSourceSettings(filterWeakSource)); } break; default: break; } - obs_source_release(s); + obs_source_release(filterSource); if (GetVariableValue().empty()) { SetVariableValue(ret ? "true" : "false"); @@ -75,7 +62,7 @@ bool MacroConditionFilter::Save(obs_data_t *obj) const { MacroCondition::Save(obj); _source.Save(obj); - obs_data_set_string(obj, "filter", _filterName.c_str()); + _filter.Save(obj, "filter"); obs_data_set_int(obj, "condition", static_cast(_condition)); _settings.Save(obj, "settings"); _regex.Save(obj); @@ -86,9 +73,7 @@ bool MacroConditionFilter::Load(obs_data_t *obj) { MacroCondition::Load(obj); _source.Load(obj); - _filterName = obs_data_get_string(obj, "filter"); - _filter = GetWeakFilterByQString(_source.GetSource(), - _filterName.c_str()); + _filter.Load(obj, _source, "filter"); _condition = static_cast(obs_data_get_int(obj, "condition")); _settings.Load(obj, "settings"); _regex.Load(obj); @@ -102,8 +87,8 @@ bool MacroConditionFilter::Load(obs_data_t *obj) std::string MacroConditionFilter::GetShortDesc() const { - if (_filter && !_source.ToString().empty()) { - return _source.ToString() + " - " + GetWeakSourceName(_filter); + if (!_filter.ToString().empty() && !_source.ToString().empty()) { + return _source.ToString() + " - " + _filter.ToString(); } return ""; } @@ -119,14 +104,13 @@ MacroConditionFilterEdit::MacroConditionFilterEdit( QWidget *parent, std::shared_ptr entryData) : QWidget(parent), _sources(new SourceSelectionWidget(this, QStringList(), true)), - _filters(new QComboBox()), + _filters(new FilterSelectionWidget(this, _sources, true)), _conditions(new QComboBox()), _getSettings(new QPushButton(obs_module_text( "AdvSceneSwitcher.condition.filter.getSettings"))), _settings(new VariableTextEdit(this)), _regex(new RegexConfigWidget(parent)) { - _filters->setSizeAdjustPolicy(QComboBox::AdjustToContents); populateConditionSelection(_conditions); auto sources = GetSourcesWithFilterNames(); sources.sort(); @@ -135,8 +119,9 @@ MacroConditionFilterEdit::MacroConditionFilterEdit( QWidget::connect(_sources, SIGNAL(SourceChanged(const SourceSelection &)), this, SLOT(SourceChanged(const SourceSelection &))); - QWidget::connect(_filters, SIGNAL(currentTextChanged(const QString &)), - this, SLOT(FilterChanged(const QString &))); + QWidget::connect(_filters, + SIGNAL(FilterChanged(const FilterSelection &)), this, + SLOT(FilterChanged(const FilterSelection &))); QWidget::connect(_conditions, SIGNAL(currentIndexChanged(int)), this, SLOT(ConditionChanged(int))); QWidget::connect(_getSettings, SIGNAL(clicked()), this, @@ -146,20 +131,23 @@ MacroConditionFilterEdit::MacroConditionFilterEdit( QWidget::connect(_regex, SIGNAL(RegexConfigChanged(RegexConfig)), this, SLOT(RegexChanged(RegexConfig))); - QHBoxLayout *line1Layout = new QHBoxLayout; - QHBoxLayout *line2Layout = new QHBoxLayout; - QHBoxLayout *line3Layout = new QHBoxLayout; std::unordered_map widgetPlaceholders = { {"{{sources}}", _sources}, {"{{filters}}", _filters}, {"{{conditions}}", _conditions}, {"{{settings}}", _settings}, {"{{getSettings}}", _getSettings}, {"{{regex}}", _regex}, }; + auto line1Layout = new QHBoxLayout; + line1Layout->setContentsMargins(0, 0, 0, 0); PlaceWidgets(obs_module_text( "AdvSceneSwitcher.condition.filter.entry.line1"), line1Layout, widgetPlaceholders); + auto line2Layout = new QHBoxLayout; + line2Layout->setContentsMargins(0, 0, 0, 0); PlaceWidgets(obs_module_text( "AdvSceneSwitcher.condition.filter.entry.line2"), line2Layout, widgetPlaceholders, false); + auto line3Layout = new QHBoxLayout; + line3Layout->setContentsMargins(0, 0, 0, 0); PlaceWidgets(obs_module_text( "AdvSceneSwitcher.condition.filter.entry.line3"), line3Layout, widgetPlaceholders); @@ -180,25 +168,19 @@ void MacroConditionFilterEdit::SourceChanged(const SourceSelection &source) if (_loading || !_entryData) { return; } - { - auto lock = LockContext(); - _entryData->_source = source; - } - _filters->clear(); - PopulateFilterSelection(_filters, _entryData->_source.GetSource()); - _filters->adjustSize(); + + auto lock = LockContext(); + _entryData->_source = source; } -void MacroConditionFilterEdit::FilterChanged(const QString &text) +void MacroConditionFilterEdit::FilterChanged(const FilterSelection &filter) { if (_loading || !_entryData) { return; } auto lock = LockContext(); - _entryData->_filterName = text.toStdString(); - _entryData->_filter = - GetWeakFilterByQString(_entryData->_source.GetSource(), text); + _entryData->_filter = filter; emit HeaderInfoChanged( QString::fromStdString(_entryData->GetShortDesc())); } @@ -218,11 +200,13 @@ void MacroConditionFilterEdit::ConditionChanged(int index) void MacroConditionFilterEdit::GetSettingsClicked() { - if (_loading || !_entryData || !_entryData->_source.GetSource()) { + if (_loading || !_entryData || + !_entryData->_filter.GetFilter(_entryData->_source)) { return; } - QString json = FormatJsonString(GetSourceSettings(_entryData->_filter)); + QString json = FormatJsonString(GetSourceSettings( + _entryData->_filter.GetFilter(_entryData->_source))); if (_entryData->_regex.Enabled()) { json = EscapeForRegex(json); } @@ -261,6 +245,7 @@ void MacroConditionFilterEdit::SetSettingsSelectionVisible(bool visible) _getSettings->setVisible(visible); _regex->setVisible(visible); adjustSize(); + updateGeometry(); } void MacroConditionFilterEdit::UpdateEntryData() @@ -270,9 +255,7 @@ void MacroConditionFilterEdit::UpdateEntryData() } _sources->SetSource(_entryData->_source); - PopulateFilterSelection(_filters, _entryData->_source.GetSource()); - _filters->setCurrentText( - GetWeakSourceName(_entryData->_filter).c_str()); + _filters->SetFilter(_entryData->_source, _entryData->_filter); _conditions->setCurrentIndex(static_cast(_entryData->_condition)); _settings->setPlainText(_entryData->_settings); _regex->SetRegexConfig(_entryData->_regex); diff --git a/src/macro-core/macro-condition-filter.hpp b/src/macro-core/macro-condition-filter.hpp index 3aae6078..5d0e6965 100644 --- a/src/macro-core/macro-condition-filter.hpp +++ b/src/macro-core/macro-condition-filter.hpp @@ -3,6 +3,7 @@ #include "variable-text-edit.hpp" #include "regex-config.hpp" #include "source-selection.hpp" +#include "filter-selection.hpp" #include #include @@ -30,19 +31,14 @@ public: }; SourceSelection _source; - OBSWeakSource _filter; + FilterSelection _filter; Condition _condition = Condition::ENABLED; StringVariable _settings = ""; RegexConfig _regex; private: - void ResolveVariables(); - std::string _filterName = ""; - static bool _registered; static const std::string id; - - friend class MacroConditionFilterEdit; }; class MacroConditionFilterEdit : public QWidget { @@ -63,7 +59,7 @@ public: private slots: void SourceChanged(const SourceSelection &); - void FilterChanged(const QString &text); + void FilterChanged(const FilterSelection &); void ConditionChanged(int cond); void GetSettingsClicked(); void SettingsChanged(); @@ -73,7 +69,7 @@ signals: protected: SourceSelectionWidget *_sources; - QComboBox *_filters; + FilterSelectionWidget *_filters; QComboBox *_conditions; QPushButton *_getSettings; VariableTextEdit *_settings; diff --git a/src/utils/filter-selection.cpp b/src/utils/filter-selection.cpp new file mode 100644 index 00000000..8719353f --- /dev/null +++ b/src/utils/filter-selection.cpp @@ -0,0 +1,260 @@ +#include "filter-selection.hpp" +#include "obs-module-helper.hpp" + +namespace advss { + +constexpr std::string_view typeSaveName = "type"; +constexpr std::string_view nameSaveName = "name"; + +void FilterSelection::Save(obs_data_t *obj, const char *name) const +{ + auto data = obs_data_create(); + obs_data_set_int(data, typeSaveName.data(), static_cast(_type)); + switch (_type) { + case Type::SOURCE: + obs_data_set_string(data, nameSaveName.data(), + _filter ? GetWeakSourceName(_filter).c_str() + : _filterName.c_str()); + break; + case Type::VARIABLE: { + auto var = _variable.lock(); + if (!var) { + break; + } + obs_data_set_string(data, nameSaveName.data(), + var->Name().c_str()); + break; + } + default: + break; + } + obs_data_set_obj(obj, name, data); + obs_data_release(data); +} + +void FilterSelection::Load(obs_data_t *obj, const SourceSelection &source, + const char *name) +{ + auto data = obs_data_get_obj(obj, name); + _type = static_cast(obs_data_get_int(data, typeSaveName.data())); + _filterName = obs_data_get_string(data, nameSaveName.data()); + switch (_type) { + case Type::SOURCE: + _filter = GetWeakFilterByName(source.GetSource(), + _filterName.c_str()); + break; + case Type::VARIABLE: + _variable = GetWeakVariableByName(_filterName); + break; + default: + break; + } + if (!obs_data_has_user_value(data, typeSaveName.data())) { + LoadFallback(obj, source, name); + } + obs_data_release(data); +} + +void FilterSelection::LoadFallback(obs_data_t *obj, + const SourceSelection &source, + const char *name) +{ + blog(LOG_INFO, "Falling back to Load() without variable support"); + _type = Type::SOURCE; + _filter = GetWeakFilterByName(source.GetSource(), name); + _filterName = obs_data_get_string(obj, name); +} + +OBSWeakSource FilterSelection::GetFilter(const SourceSelection &source) const +{ + switch (_type) { + case Type::SOURCE: + return GetWeakFilterByName( + source.GetSource(), + _filter ? GetWeakSourceName(_filter).c_str() + : _filterName.c_str()); + case Type::VARIABLE: { + auto var = _variable.lock(); + if (!var) { + return nullptr; + } + return GetWeakFilterByName(source.GetSource(), + var->Value().c_str()); + } + default: + break; + } + return nullptr; +} + +std::string FilterSelection::ToString(bool resolve) const +{ + switch (_type) { + case Type::SOURCE: + return _filter ? GetWeakSourceName(_filter) : _filterName; + case Type::VARIABLE: { + auto var = _variable.lock(); + if (!var) { + return ""; + } + if (resolve) { + return var->Name() + "[" + var->Value() + "]"; + } + return var->Name(); + } + default: + break; + } + return ""; +} + +FilterSelection FilterSelectionWidget::CurrentSelection() +{ + FilterSelection s; + const int idx = currentIndex(); + const auto name = currentText(); + + if (idx < _variablesEndIdx) { + s._type = FilterSelection::Type::VARIABLE; + s._variable = GetWeakVariableByQString(name); + } else if (idx < _filterEndIdx) { + s._type = FilterSelection::Type::SOURCE; + s._filter = GetWeakSourceByQString(name); + s._filterName = name.toStdString(); + } + return s; +} + +void FilterSelectionWidget::Reset() +{ + auto previousSelection = _currentSelection; + PopulateSelection(); + SetFilter(_source, previousSelection); +} + +void FilterSelectionWidget::PopulateSelection() +{ + const QSignalBlocker b(this); + clear(); + AddSelectionEntry(this, + obs_module_text("AdvSceneSwitcher.selectFilter")); + insertSeparator(count()); + + if (_addVariables) { + const QStringList variables = GetVariablesNameList(); + AddSelectionGroup(this, variables); + } + _variablesEndIdx = count(); + + AddSelectionGroup(this, GetFilterNames(_source.GetSource())); + _filterEndIdx = count(); + + // Remove last separator + removeItem(count() - 1); + setCurrentIndex(0); +} + +FilterSelectionWidget::FilterSelectionWidget(QWidget *parent, + SourceSelectionWidget *sources, + bool addVariables) + : QComboBox(parent), _addVariables(addVariables) +{ + setDuplicatesEnabled(true); + + QWidget::connect(this, SIGNAL(currentTextChanged(const QString &)), + this, SLOT(SelectionChanged(const QString &))); + QWidget::connect(sources, + SIGNAL(SourceChanged(const SourceSelection &)), this, + SLOT(SourceChanged(const SourceSelection &))); + + // Variables + QWidget::connect(window(), SIGNAL(VariableAdded(const QString &)), this, + SLOT(ItemAdd(const QString &))); + QWidget::connect(window(), SIGNAL(VariableRemoved(const QString &)), + this, SLOT(ItemRemove(const QString &))); + QWidget::connect( + window(), + SIGNAL(VariableRenamed(const QString &, const QString &)), this, + SLOT(ItemRename(const QString &, const QString &))); +} + +void FilterSelectionWidget::SetFilter(const SourceSelection &source, + const FilterSelection &filter) +{ + _source = source; + PopulateSelection(); + + int idx = 0; + + switch (filter.GetType()) { + case FilterSelection::Type::SOURCE: { + if (_filterEndIdx == -1) { + idx = 0; + break; + } + idx = FindIdxInRagne(this, _variablesEndIdx, _filterEndIdx, + filter.ToString()); + break; + } + case FilterSelection::Type::VARIABLE: { + if (_variablesEndIdx == -1) { + idx = 0; + break; + } + idx = FindIdxInRagne(this, _selectIdx, _variablesEndIdx, + filter.ToString()); + break; + default: + idx = 0; + break; + } + } + setCurrentIndex(idx); + _currentSelection = filter; +} + +void FilterSelectionWidget::SourceChanged(const SourceSelection &source) +{ + if (source == _source) { + return; + } + _source = source; + _currentSelection = FilterSelection(); + Reset(); + emit FilterChanged(_currentSelection); +} + +void FilterSelectionWidget::SelectionChanged(const QString &) +{ + emit FilterChanged(CurrentSelection()); +} + +void FilterSelectionWidget::ItemAdd(const QString &) +{ + const QSignalBlocker b(this); + Reset(); +} + +bool FilterSelectionWidget::NameUsed(const QString &name) +{ + return _currentSelection._type == FilterSelection::Type::VARIABLE && + currentText() == name; +} + +void FilterSelectionWidget::ItemRemove(const QString &name) +{ + if (NameUsed(name)) { + _currentSelection = FilterSelection(); + emit FilterChanged(_currentSelection); + } + const QSignalBlocker b(this); + Reset(); +} + +void FilterSelectionWidget::ItemRename(const QString &, const QString &) +{ + const QSignalBlocker b(this); + Reset(); +} + +} // namespace advss diff --git a/src/utils/filter-selection.hpp b/src/utils/filter-selection.hpp new file mode 100644 index 00000000..031fb212 --- /dev/null +++ b/src/utils/filter-selection.hpp @@ -0,0 +1,74 @@ +#pragma once +#include "source-selection.hpp" + +namespace advss { + +class FilterSelection { +public: + void Save(obs_data_t *obj, const char *name = "filter") const; + void Load(obs_data_t *obj, const SourceSelection &source, + const char *name = "filter"); + + enum class Type { + SOURCE, + VARIABLE, + }; + + Type GetType() const { return _type; } + OBSWeakSource GetFilter(const SourceSelection &source) const; + std::string ToString(bool resolve = false) const; + +private: + // TODO: Remove in future version + // Used for backwards compatability to older settings versions + void LoadFallback(obs_data_t *obj, const SourceSelection &source, + const char *name); + + OBSWeakSource _filter; + // Storing the name separately as depending on the source selection + // the filter source might not be available at the moment. + std::string _filterName = ""; + std::weak_ptr _variable; + Type _type = Type::SOURCE; + friend class FilterSelectionWidget; +}; + +class FilterSelectionWidget : public QComboBox { + Q_OBJECT + +public: + FilterSelectionWidget(QWidget *parent, SourceSelectionWidget *sources, + bool addVariables = true); + void SetFilter(const SourceSelection &, const FilterSelection &); + +signals: + void FilterChanged(const FilterSelection &); + +public slots: + void SourceChanged(const SourceSelection &); +private slots: + void SelectionChanged(const QString &name); + void ItemAdd(const QString &name); + void ItemRemove(const QString &name); + void ItemRename(const QString &oldName, const QString &newName); + +private: + void Reset(); + FilterSelection CurrentSelection(); + void PopulateSelection(); + bool NameUsed(const QString &name); + + bool _addVariables; + FilterSelection _currentSelection; + SourceSelection _source; + + // Order of entries + // 1. "select entry" entry + // 2. Variables + // 3. Regular filters + const int _selectIdx = 0; + int _variablesEndIdx = -1; + int _filterEndIdx = -1; +}; + +} // namespace advss diff --git a/src/utils/source-selection.cpp b/src/utils/source-selection.cpp index 9693a67c..80cf12e9 100644 --- a/src/utils/source-selection.cpp +++ b/src/utils/source-selection.cpp @@ -105,6 +105,21 @@ std::string SourceSelection::ToString(bool resolve) const return ""; } +bool SourceSelection::operator==(const SourceSelection &other) const +{ + if (_type != other._type) { + return false; + } + + if (_type == Type::SOURCE) { + return _source == other._source; + } + + auto v1 = _variable.lock(); + auto v2 = other._variable.lock(); + return v1 == v2; +} + SourceSelection SourceSelectionWidget::CurrentSelection() { SourceSelection s; diff --git a/src/utils/source-selection.hpp b/src/utils/source-selection.hpp index 0c0c8de3..198f8e2c 100644 --- a/src/utils/source-selection.hpp +++ b/src/utils/source-selection.hpp @@ -22,6 +22,8 @@ public: void SetSource(OBSWeakSource); std::string ToString(bool resolve = false) const; + bool operator==(const SourceSelection &) const; + private: // TODO: Remove in future version // Used for backwards compatability to older settings versions diff --git a/src/utils/utility.cpp b/src/utils/utility.cpp index 3434d78a..88c73ec9 100644 --- a/src/utils/utility.cpp +++ b/src/utils/utility.cpp @@ -511,6 +511,25 @@ QStringList GetSourceNames() return list; } +QStringList GetFilterNames(OBSWeakSource weakSource) +{ + if (!weakSource) { + return {}; + } + + QStringList list; + auto enumFilters = [](obs_source_t *, obs_source_t *filter, void *ptr) { + auto name = obs_source_get_name(filter); + QStringList *list = reinterpret_cast(ptr); + *list << QString(name); + }; + + auto s = obs_weak_source_get_source(weakSource); + obs_source_enum_filters(s, enumFilters, &list); + obs_source_release(s); + return list; +} + void PopulateSourceSelection(QComboBox *list, bool addSelect) { auto sources = GetSourceNames(); @@ -815,18 +834,11 @@ void PopulateSourcesWithFilterSelection(QComboBox *list) void PopulateFilterSelection(QComboBox *list, OBSWeakSource weakSource) { - auto enumFilters = [](obs_source_t *, obs_source_t *filter, void *ptr) { - QComboBox *list = reinterpret_cast(ptr); - auto name = obs_source_get_name(filter); - list->addItem(name); - }; - - auto s = obs_weak_source_get_source(weakSource); - obs_source_enum_filters(s, enumFilters, list); - list->model()->sort(0); + auto filters = GetFilterNames(weakSource); + filters.sort(); + list->addItems(filters); AddSelectionEntry(list, obs_module_text("AdvSceneSwitcher.selectFilter")); - obs_source_release(s); list->setCurrentIndex(0); } diff --git a/src/utils/utility.hpp b/src/utils/utility.hpp index b46f0176..70313d71 100644 --- a/src/utils/utility.hpp +++ b/src/utils/utility.hpp @@ -50,6 +50,7 @@ QStringList GetMediaSourceNames(); QStringList GetVideoSourceNames(); QStringList GetSceneNames(); QStringList GetSourceNames(); +QStringList GetFilterNames(OBSWeakSource weakSource); /* Populate list helpers */