Add variable support for scene item selection

This commit is contained in:
WarmUpTill 2022-09-17 12:24:50 +02:00 committed by WarmUpTill
parent e0d4c7244d
commit 7683957267
5 changed files with 350 additions and 166 deletions

View File

@ -140,7 +140,7 @@ bool MacroConditionSceneOrder::Save(obs_data_t *obj)
MacroCondition::Save(obj);
_scene.Save(obj);
_source.Save(obj);
_source2.Save(obj, "sceneItem2", "sceneItemTarget2", "sceneItemIdx2");
_source2.Save(obj, "sceneItemSelection2");
obs_data_set_int(obj, "condition", static_cast<int>(_condition));
obs_data_set_int(obj, "position", _position);
return true;
@ -160,7 +160,14 @@ bool MacroConditionSceneOrder::Load(obs_data_t *obj)
MacroCondition::Load(obj);
_scene.Load(obj);
_source.Load(obj);
_source2.Load(obj, "sceneItem2", "sceneItemTarget2", "sceneItemIdx2");
// Convert old data format
// TODO: Remove in future version
if (obs_data_has_user_value(obj, "sceneItem2")) {
_source2.Load(obj, "sceneItem2", "sceneItemTarget2",
"sceneItemIdx2");
} else {
_source2.Load(obj, "sceneItemSelection2");
}
_condition = static_cast<SceneOrderCondition>(
obs_data_get_int(obj, "condition"));
_position = obs_data_get_int(obj, "position");

View File

@ -2,28 +2,105 @@
#include <obs-module.h>
void SceneItemSelection::Save(obs_data_t *obj, const char *name,
const char *targetName, const char *idxName)
constexpr std::string_view typeSaveName = "type";
constexpr std::string_view itemSaveName = "item";
constexpr std::string_view idxSaveName = "idx";
constexpr std::string_view idxTypeSaveName = "idxType";
void SceneItemSelection::Save(obs_data_t *obj, const char *name) const
{
obs_data_set_int(obj, targetName, static_cast<int>(_target));
if (_target == SceneItemSelection::Target::INDIVIDUAL) {
obs_data_set_int(obj, idxName, _idx);
auto data = obs_data_create();
obs_data_set_int(data, typeSaveName.data(), static_cast<int>(_type));
obs_data_set_int(data, idxTypeSaveName.data(),
static_cast<int>(_idxType));
if (_idxType != IdxType::INDIVIDUAL) {
obs_data_set_int(data, idxSaveName.data(), _idx);
} else {
obs_data_set_int(obj, idxName, 0);
obs_data_set_int(data, idxSaveName.data(), 0);
}
obs_data_set_string(obj, name, GetWeakSourceName(_sceneItem).c_str());
if (_type == SceneItemSelection::Type::SOURCE) {
obs_data_set_string(data, itemSaveName.data(),
GetWeakSourceName(_sceneItem).c_str());
} else {
auto var = _variable.lock();
if (var) {
obs_data_set_string(data, itemSaveName.data(),
var->Name().c_str());
}
}
obs_data_set_obj(obj, name, data);
obs_data_release(data);
}
// TODO: Remove in future version
void SceneItemSelection::Load(obs_data_t *obj, const char *name,
const char *targetName, const char *idxName)
const char *typeName, const char *idxName)
{
_target = static_cast<SceneItemSelection::Target>(
obs_data_get_int(obj, targetName));
_type = Type::SOURCE;
_idxType = static_cast<IdxType>(obs_data_get_int(obj, typeName));
_idx = obs_data_get_int(obj, idxName);
auto sceneItemName = obs_data_get_string(obj, name);
_sceneItem = GetWeakSourceByName(sceneItemName);
}
void SceneItemSelection::Load(obs_data_t *obj, const char *name)
{
// TODO: Remove in future version
if (!obs_data_has_user_value(obj, name)) {
Load(obj, "sceneItem", "sceneItemTarget", "sceneItemIdx");
return;
}
auto data = obs_data_get_obj(obj, name);
_type = static_cast<Type>(obs_data_get_int(data, typeSaveName.data()));
_idxType = static_cast<IdxType>(
obs_data_get_int(data, idxTypeSaveName.data()));
_idx = obs_data_get_int(data, idxSaveName.data());
const auto itemName = obs_data_get_string(data, itemSaveName.data());
switch (_type) {
case SceneItemSelection::Type::SOURCE:
_sceneItem = GetWeakSourceByName(itemName);
break;
case SceneItemSelection::Type::VARIABLE:
_variable = GetWeakVariableByName(itemName);
break;
default:
break;
}
obs_data_release(data);
}
struct ItemInfo {
std::string name;
std::vector<obs_sceneitem_t *> items = {};
};
static bool getSceneItems(obs_scene_t *, obs_sceneitem_t *item, void *ptr)
{
ItemInfo *moveInfo = reinterpret_cast<ItemInfo *>(ptr);
auto sourceName = obs_source_get_name(obs_sceneitem_get_source(item));
if (moveInfo->name == sourceName) {
obs_sceneitem_addref(item);
moveInfo->items.push_back(item);
}
if (obs_sceneitem_is_group(item)) {
obs_scene_t *scene = obs_sceneitem_group_get_scene(item);
obs_scene_enum_items(scene, getSceneItems, ptr);
}
return true;
}
std::vector<obs_scene_item *> getSceneItemsWithName(obs_scene_t *scene,
std::string &name)
{
ItemInfo itemInfo = {name};
obs_scene_enum_items(scene, getSceneItems, &itemInfo);
return itemInfo.items;
}
struct ItemCountData {
std::string name;
int count = 0;
@ -44,7 +121,8 @@ static bool countSceneItem(obs_scene_t *, obs_sceneitem_t *item, void *ptr)
return true;
}
int getCountOfSceneItemOccurance(SceneSelection &s, std::string &name,
int getCountOfSceneItemOccurance(const SceneSelection &s,
const std::string &name,
bool enumAllScenes = true)
{
ItemCountData data{name};
@ -71,17 +149,25 @@ int getCountOfSceneItemOccurance(SceneSelection &s, std::string &name,
std::vector<obs_scene_item *>
SceneItemSelection::GetSceneItems(SceneSelection &sceneSelection)
{
std::vector<obs_scene_item *> ret;
auto s = obs_weak_source_get_source(sceneSelection.GetScene(false));
auto scene = obs_scene_from_source(s);
auto name = GetWeakSourceName(_sceneItem);
std::string name;
if (_type == Type::VARIABLE) {
auto var = _variable.lock();
if (!var) {
return ret;
}
name = var->Value();
} else {
auto name = GetWeakSourceName(_sceneItem);
}
int count = getCountOfSceneItemOccurance(sceneSelection, name, false);
auto items = getSceneItemsWithName(scene, name);
obs_source_release(s);
std::vector<obs_scene_item *> ret;
if (_target == SceneItemSelection::Target::ALL ||
_target == SceneItemSelection::Target::ANY) {
if (_idxType == SceneItemSelection::IdxType::ALL ||
_idxType == SceneItemSelection::IdxType::ANY) {
ret = items;
} else {
// Index order starts at the bottom and increases to the top
@ -102,13 +188,96 @@ SceneItemSelection::GetSceneItems(SceneSelection &sceneSelection)
std::string SceneItemSelection::ToString()
{
if (_type == Type::VARIABLE) {
auto var = _variable.lock();
if (!var) {
return "";
}
return var->Name();
}
return GetWeakSourceName(_sceneItem);
}
static bool enumSceneItem(obs_scene_t *, obs_sceneitem_t *item, void *ptr)
{
QStringList *names = reinterpret_cast<QStringList *>(ptr);
if (obs_sceneitem_is_group(item)) {
obs_scene_t *scene = obs_sceneitem_group_get_scene(item);
obs_scene_enum_items(scene, enumSceneItem, ptr);
}
auto name = obs_source_get_name(obs_sceneitem_get_source(item));
names->append(name);
return true;
}
void populateSceneItemSelection(QComboBox *list)
{
QStringList names;
obs_scene_enum_items(nullptr, enumSceneItem, &names);
names.removeDuplicates();
names.sort();
list->addItems(names);
addSelectionEntry(list, obs_module_text("AdvSceneSwitcher.selectItem"));
list->setCurrentIndex(0);
}
QStringList GetSceneItemsList(SceneSelection &s)
{
QStringList names;
if (s.GetType() != SceneSelection::Type::SCENE) {
auto enumScenes = [](void *param, obs_source_t *source) {
if (!source) {
return true;
}
QStringList *names =
reinterpret_cast<QStringList *>(param);
auto scene = obs_scene_from_source(source);
obs_scene_enum_items(scene, enumSceneItem, names);
return true;
};
obs_enum_scenes(enumScenes, &names);
} else {
auto source = obs_weak_source_get_source(s.GetScene(false));
auto scene = obs_scene_from_source(source);
obs_scene_enum_items(scene, enumSceneItem, &names);
obs_source_release(source);
}
names.removeDuplicates();
names.sort();
return names;
}
void SceneItemSelectionWidget::Reset()
{
auto previousSel = _currentSelection;
PopulateItemSelection();
SetSceneItem(previousSel);
}
void SceneItemSelectionWidget::PopulateItemSelection()
{
_sceneItems->clear();
addSelectionEntry(_sceneItems,
obs_module_text("AdvSceneSwitcher.selectItem"));
_sceneItems->insertSeparator(_sceneItems->count());
const QStringList variables = GetVariablesNameList();
addSelectionGroup(_sceneItems, variables);
_variablesEndIdx = _sceneItems->count();
const QStringList sceneItmes = GetSceneItemsList(_scene);
addSelectionGroup(_sceneItems, sceneItmes, false);
_itemsEndIdx = _sceneItems->count();
_sceneItems->setCurrentIndex(0);
}
SceneItemSelectionWidget::SceneItemSelectionWidget(QWidget *parent,
bool showAll,
AllSelectionType type)
: QWidget(parent), _showAll(showAll), _allType(type)
: QWidget(parent), _hasAllEntry(showAll), _allType(type)
{
_sceneItems = new QComboBox();
_idx = new QComboBox();
@ -123,6 +292,16 @@ SceneItemSelectionWidget::SceneItemSelectionWidget(QWidget *parent,
SLOT(SelectionChanged(const QString &)));
QWidget::connect(_idx, SIGNAL(currentIndexChanged(int)), this,
SLOT(IdxChanged(int)));
// 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 &)));
auto layout = new QHBoxLayout;
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(_idx);
@ -133,21 +312,48 @@ SceneItemSelectionWidget::SceneItemSelectionWidget(QWidget *parent,
void SceneItemSelectionWidget::SetSceneItem(const SceneItemSelection &item)
{
_sceneItems->setCurrentText(
QString::fromStdString(GetWeakSourceName(item._sceneItem)));
if (item._target == SceneItemSelection::Target::ALL) {
_allType = AllSelectionType::ALL;
_idx->setCurrentIndex(0);
} else if (item._target == SceneItemSelection::Target::ANY) {
_allType = AllSelectionType::ANY;
_idx->setCurrentIndex(0);
} else {
int itemIdx = 0;
switch (item._type) {
case SceneItemSelection::Type::SOURCE: {
int idx = item._idx;
if (_showAll) {
if (_hasAllEntry) {
idx += 1;
}
_idx->setCurrentIndex(idx);
itemIdx = findIdxInRagne(_sceneItems, _variablesEndIdx,
_itemsEndIdx,
GetWeakSourceName(item._sceneItem));
_sceneItems->setCurrentIndex(itemIdx);
break;
}
case SceneItemSelection::Type::VARIABLE: {
auto var = item._variable.lock();
if (!var) {
break;
}
itemIdx = findIdxInRagne(_sceneItems, _selectIdx,
_variablesEndIdx, var->Name());
_sceneItems->setCurrentIndex(itemIdx);
break;
}
}
switch (item._idxType) {
case SceneItemSelection::IdxType::ALL:
case SceneItemSelection::IdxType::ANY:
_allType = AllSelectionType::ALL;
_idx->setCurrentIndex(0);
break;
case SceneItemSelection::IdxType::INDIVIDUAL:
int idx = item._idx;
if (_hasAllEntry) {
idx += 1;
}
_idx->setCurrentIndex(idx);
break;
}
_currentSelection = item;
}
void SceneItemSelectionWidget::SetScene(const SceneSelection &s)
@ -155,12 +361,12 @@ void SceneItemSelectionWidget::SetScene(const SceneSelection &s)
_scene = s;
_sceneItems->clear();
_idx->hide();
populateSceneItemSelection(_sceneItems, _scene);
PopulateItemSelection();
}
void SceneItemSelectionWidget::SetShowAll(bool value)
{
_showAll = value;
_hasAllEntry = value;
}
void SceneItemSelectionWidget::SetShowAllSelectionType(AllSelectionType t)
@ -178,21 +384,37 @@ void SceneItemSelectionWidget::SceneChanged(const SceneSelection &s)
void SceneItemSelectionWidget::SelectionChanged(const QString &name)
{
SceneItemSelection s;
_sceneItem = GetWeakSourceByQString(name);
s._sceneItem = _sceneItem;
if (_allType == AllSelectionType::ALL) {
s._target = SceneItemSelection::Target::ALL;
} else {
s._target = SceneItemSelection::Target::ANY;
}
auto stdName = name.toStdString();
int sceneItemCount = getCountOfSceneItemOccurance(_scene, stdName);
int sceneItemCount =
getCountOfSceneItemOccurance(_scene, name.toStdString());
if (sceneItemCount > 1) {
_idx->show();
SetupIdxSelection(sceneItemCount);
} else {
_idx->hide();
}
if (_hasAllEntry) {
switch (_allType) {
case SceneItemSelectionWidget::AllSelectionType::ALL:
s._idxType = SceneItemSelection::IdxType::ALL;
break;
case SceneItemSelectionWidget::AllSelectionType::ANY:
s._idxType = SceneItemSelection::IdxType::ANY;
break;
}
}
const int idx = _sceneItems->currentIndex();
if (idx < _variablesEndIdx) {
s._type = SceneItemSelection::Type::VARIABLE;
s._variable = GetWeakVariableByQString(name);
} else if (idx < _itemsEndIdx) {
auto group = GetSceneGroupByQString(name);
s._type = SceneItemSelection::Type::SOURCE;
s._sceneItem = GetWeakSourceByQString(name);
}
_currentSelection = s;
emit SceneItemChanged(s);
}
@ -202,29 +424,51 @@ void SceneItemSelectionWidget::IdxChanged(int idx)
return;
}
SceneItemSelection s;
s._sceneItem = _sceneItem;
if (_showAll && idx == 0) {
if (_allType == AllSelectionType::ALL) {
s._target = SceneItemSelection::Target::ALL;
} else {
s._target = SceneItemSelection::Target::ANY;
_currentSelection._idx = idx;
if (_hasAllEntry && idx == 0) {
switch (_allType) {
case SceneItemSelectionWidget::AllSelectionType::ALL:
_currentSelection._idxType =
SceneItemSelection::IdxType::ALL;
break;
case SceneItemSelectionWidget::AllSelectionType::ANY:
_currentSelection._idxType =
SceneItemSelection::IdxType::ANY;
break;
}
s._idx = 0;
} else {
s._target = SceneItemSelection::Target::INDIVIDUAL;
if (_showAll) {
idx -= 1;
}
s._idx = idx;
}
emit SceneItemChanged(s);
if (_hasAllEntry && idx > 0) {
_currentSelection._idx -= 1;
_currentSelection._idxType =
SceneItemSelection::IdxType::INDIVIDUAL;
}
emit SceneItemChanged(_currentSelection);
}
void SceneItemSelectionWidget::ItemAdd(const QString &name)
{
blockSignals(true);
Reset();
blockSignals(false);
}
void SceneItemSelectionWidget::ItemRemove(const QString &name)
{
Reset();
}
void SceneItemSelectionWidget::ItemRename(const QString &oldName,
const QString &newName)
{
blockSignals(true);
Reset();
blockSignals(false);
}
void SceneItemSelectionWidget::SetupIdxSelection(int sceneItemCount)
{
_idx->clear();
if (_showAll) {
if (_hasAllEntry) {
if (_allType == AllSelectionType::ALL) {
_idx->addItem(obs_module_text(
"AdvSceneSwitcher.sceneItemSelection.all"));

View File

@ -1,28 +1,41 @@
#pragma once
#include "scene-selection.hpp"
#include "variable.hpp"
#include "utility.hpp"
#include <QComboBox>
#include <obs-data.h>
#include "scene-selection.hpp"
#include "utility.hpp"
class SceneItemSelection {
public:
void Save(obs_data_t *obj, const char *name = "sceneItem",
const char *targetName = "sceneItemTarget",
const char *idxName = "sceneItemIdx");
void Load(obs_data_t *obj, const char *name = "sceneItem",
const char *targetName = "sceneItemTarget",
const char *idxName = "sceneItemIdx");
void Save(obs_data_t *obj,
const char *name = "sceneItemSelection") const;
void Load(obs_data_t *obj, const char *name = "sceneItemSelection");
// TODO: Remove in future version
void Load(obs_data_t *obj, const char *name, const char *targetName,
const char *idxName);
enum class Target { ALL, ANY, INDIVIDUAL };
Target GetType() { return _target; }
enum class Type {
SOURCE,
VARIABLE,
};
enum class IdxType {
ALL,
ANY,
INDIVIDUAL,
};
Type GetType() { return _type; }
IdxType GetIndexType() { return _idxType; }
std::vector<obs_scene_item *> GetSceneItems(SceneSelection &s);
std::string ToString();
private:
OBSWeakSource _sceneItem;
Target _target = Target::ALL;
int _idx = 0;
std::weak_ptr<Variable> _variable;
Type _type = Type::SOURCE;
IdxType _idxType = IdxType::ALL;
int _idx = 0; // Multiple items with the same name can exist
friend class SceneItemSelectionWidget;
};
@ -30,9 +43,10 @@ class SceneItemSelectionWidget : public QWidget {
Q_OBJECT
public:
// Influences what is being displaye for the "all" entry
enum class AllSelectionType { ALL, ANY };
SceneItemSelectionWidget(
QWidget *parent, bool allSelection = true,
QWidget *parent, bool addAllSelection = true,
AllSelectionType allType = AllSelectionType::ALL);
void SetSceneItem(const SceneItemSelection &);
void SetScene(const SceneSelection &);
@ -45,15 +59,28 @@ private slots:
void SceneChanged(const SceneSelection &);
void SelectionChanged(const QString &name);
void IdxChanged(int);
void ItemAdd(const QString &name);
void ItemRemove(const QString &name);
void ItemRename(const QString &oldName, const QString &newName);
private:
void Reset();
void PopulateItemSelection();
void SetupIdxSelection(int);
QComboBox *_sceneItems;
QComboBox *_idx;
SceneSelection _scene;
OBSWeakSource _sceneItem;
bool _showAll = false;
SceneItemSelection _currentSelection;
bool _hasAllEntry = false;
AllSelectionType _allType = AllSelectionType::ALL;
// Order of entries
// 1. "select entry" entry
// 2. Variables
// 3. Scene items
const int _selectIdx = 0;
int _variablesEndIdx = -1;
int _itemsEndIdx = -1;
};

View File

@ -302,36 +302,6 @@ void setSourceSettings(obs_source_t *s, const std::string &settings)
obs_data_release(data);
}
struct ItemInfo {
std::string name;
std::vector<obs_sceneitem_t *> items = {};
};
static bool getSceneItems(obs_scene_t *, obs_sceneitem_t *item, void *ptr)
{
ItemInfo *moveInfo = reinterpret_cast<ItemInfo *>(ptr);
auto sourceName = obs_source_get_name(obs_sceneitem_get_source(item));
if (moveInfo->name == sourceName) {
obs_sceneitem_addref(item);
moveInfo->items.push_back(item);
}
if (obs_sceneitem_is_group(item)) {
obs_scene_t *scene = obs_sceneitem_group_get_scene(item);
obs_scene_enum_items(scene, getSceneItems, ptr);
}
return true;
}
std::vector<obs_scene_item *> getSceneItemsWithName(obs_scene_t *scene,
std::string &name)
{
ItemInfo itemInfo = {name};
obs_scene_enum_items(scene, getSceneItems, &itemInfo);
return itemInfo.items;
}
// Match json1 with pattern json2
bool matchJson(const std::string &json1, const std::string &json2,
const RegexConfig &regex)
@ -793,67 +763,6 @@ void populateFilterSelection(QComboBox *list, OBSWeakSource weakSource)
list->setCurrentIndex(0);
}
static bool enumSceneItem(obs_scene_t *, obs_sceneitem_t *item, void *ptr)
{
std::set<QString> *names = reinterpret_cast<std::set<QString> *>(ptr);
if (obs_sceneitem_is_group(item)) {
obs_scene_t *scene = obs_sceneitem_group_get_scene(item);
obs_scene_enum_items(scene, enumSceneItem, ptr);
}
auto name = obs_source_get_name(obs_sceneitem_get_source(item));
names->emplace(name);
return true;
}
void populateSceneItemSelection(QComboBox *list, OBSWeakSource sceneWeakSource)
{
std::set<QString> names;
auto s = obs_weak_source_get_source(sceneWeakSource);
auto scene = obs_scene_from_source(s);
obs_scene_enum_items(scene, enumSceneItem, &names);
obs_source_release(s);
for (auto &name : names) {
list->addItem(name);
}
list->model()->sort(0);
addSelectionEntry(list, obs_module_text("AdvSceneSwitcher.selectItem"));
list->setCurrentIndex(0);
}
void populateSceneItemSelection(QComboBox *list, SceneSelection &s)
{
std::set<QString> names;
if (s.GetType() != SceneSelection::Type::SCENE) {
auto enumScenes = [](void *param, obs_source_t *source) {
if (!source) {
return true;
}
std::set<QString> *names =
reinterpret_cast<std::set<QString> *>(param);
auto scene = obs_scene_from_source(source);
obs_scene_enum_items(scene, enumSceneItem, names);
return true;
};
obs_enum_scenes(enumScenes, &names);
} else {
auto source = obs_weak_source_get_source(s.GetScene(false));
auto scene = obs_scene_from_source(source);
obs_scene_enum_items(scene, enumSceneItem, &names);
obs_source_release(source);
}
for (auto &name : names) {
list->addItem(name);
}
list->model()->sort(0);
addSelectionEntry(list, obs_module_text("AdvSceneSwitcher.selectItem"));
list->setCurrentIndex(0);
}
void populateSourceGroupSelection(QComboBox *list)
{
std::set<QString> sourceTypeNames;

View File

@ -79,9 +79,6 @@ void populateSceneSelection(QComboBox *sel, bool addPrevious = false,
void populateSourcesWithFilterSelection(QComboBox *list);
void populateFilterSelection(QComboBox *list,
OBSWeakSource weakSource = nullptr);
void populateSceneItemSelection(QComboBox *list,
OBSWeakSource sceneWeakSource = nullptr);
void populateSceneItemSelection(QComboBox *list, SceneSelection &s);
void populateSourceGroupSelection(QComboBox *list);
void populateProfileSelection(QComboBox *list);
bool windowPosValid(QPoint pos);