Enable use of variables in filter selection

This commit is contained in:
WarmUpTill
2023-04-26 16:45:24 +02:00
committed by WarmUpTill
parent 530bbc07c5
commit 8cd818b80e
12 changed files with 441 additions and 122 deletions

View File

@@ -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<int>(_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<Type>(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

View File

@@ -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> _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

View File

@@ -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;

View File

@@ -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

View File

@@ -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<QStringList *>(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<QComboBox *>(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);
}

View File

@@ -50,6 +50,7 @@ QStringList GetMediaSourceNames();
QStringList GetVideoSourceNames();
QStringList GetSceneNames();
QStringList GetSourceNames();
QStringList GetFilterNames(OBSWeakSource weakSource);
/* Populate list helpers */