From a82bce947f07ddfc8018267dbc692004e1d929d7 Mon Sep 17 00:00:00 2001 From: WarmUpTill Date: Wed, 7 Jun 2023 14:17:22 +0200 Subject: [PATCH] Rework scene item selection Added support for: * Index based scelection * Type based selection * Name pattern based selection --- data/locale/en-US.ini | 16 + src/utils/scene-item-selection.cpp | 1062 +++++++++++++++++++++------- src/utils/scene-item-selection.hpp | 122 +++- 3 files changed, 913 insertions(+), 287 deletions(-) diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 4aa0e8c4..71050ea3 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -1147,6 +1147,22 @@ AdvSceneSwitcher.enterURL="--enter URL--" AdvSceneSwitcher.selectHotkey="--select hotkey--" AdvSceneSwitcher.invaildEntriesWillNotBeSaved="invalid entries will not be saved" AdvSceneSwitcher.selectWindowTip="Use \"OBS\" to specify OBS window\nUse \"Task Switching\"to specify ALT + TAB" + +AdvSceneSwitcher.sceneItemSelection.configure="Configure scene item selection type" +AdvSceneSwitcher.sceneItemSelection.type.sourceName="Source name" +AdvSceneSwitcher.sceneItemSelection.type.sourceName.entry="{{nameConflictIndex}}{{sourceName}}" +AdvSceneSwitcher.sceneItemSelection.type.sourceVariable="Variable name" +AdvSceneSwitcher.sceneItemSelection.type.sourceVariable.entry="{{nameConflictIndex}}{{variable}}" +AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern="Source name matches pattern" +AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.entry="{{nameConflictIndex}}matching{{pattern}}{{regex}}" +AdvSceneSwitcher.sceneItemSelection.type.sourceGroup="Sources of type" +AdvSceneSwitcher.sceneItemSelection.type.sourceGroup.entry="{{nameConflictIndex}}Source type{{sourceGroups}}" +AdvSceneSwitcher.sceneItemSelection.type.index="Source with index" +AdvSceneSwitcher.sceneItemSelection.type.index.entry="{{index}}source" +AdvSceneSwitcher.sceneItemSelection.type.indexRange="Sources in index range" +AdvSceneSwitcher.sceneItemSelection.type.indexRange.entry="Sources from{{index}}to{{indexEnd}}" +AdvSceneSwitcher.sceneItemSelection.type.all="All sources" +AdvSceneSwitcher.sceneItemSelection.type.all.entry="All sources" AdvSceneSwitcher.sceneItemSelection.all="All" AdvSceneSwitcher.sceneItemSelection.any="Any" diff --git a/src/utils/scene-item-selection.cpp b/src/utils/scene-item-selection.cpp index ea6d29b0..8c676167 100644 --- a/src/utils/scene-item-selection.cpp +++ b/src/utils/scene-item-selection.cpp @@ -1,120 +1,110 @@ #include "scene-item-selection.hpp" - -#include +#include "obs-module-helper.hpp" namespace advss { constexpr std::string_view typeSaveName = "type"; constexpr std::string_view itemSaveName = "item"; -constexpr std::string_view idxSaveName = "idx"; -constexpr std::string_view idxTypeSaveName = "idxType"; +constexpr std::string_view indexSaveName = "index"; +constexpr std::string_view indexEndSaveName = "indexEnd"; +constexpr std::string_view nameConflictIndexSaveName = "idx"; +constexpr std::string_view nameConflictIndexSelectionSaveName = "idxType"; +constexpr std::string_view patternSaveName = "pattern"; -void SceneItemSelection::Save(obs_data_t *obj, const char *name) const -{ - auto data = obs_data_create(); - obs_data_set_int(data, typeSaveName.data(), static_cast(_type)); - obs_data_set_int(data, idxTypeSaveName.data(), - static_cast(_idxType)); - if (_idxType == IdxType::INDIVIDUAL) { - obs_data_set_int(data, idxSaveName.data(), _idx); - } else { - obs_data_set_int(data, idxSaveName.data(), 0); - } - 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 *typeName, const char *idxName) -{ - _type = Type::SOURCE; - _idxType = static_cast(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(obs_data_get_int(data, typeSaveName.data())); - _idxType = static_cast( - 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 items = {}; +const static std::map types = { + {SceneItemSelection::Type::SOURCE_NAME, + "AdvSceneSwitcher.sceneItemSelection.type.sourceName"}, + {SceneItemSelection::Type::VARIABLE_NAME, + "AdvSceneSwitcher.sceneItemSelection.type.sourceVariable"}, + {SceneItemSelection::Type::SOURCE_NAME_PATTERN, + "AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern"}, + {SceneItemSelection::Type::SOURCE_GROUP, + "AdvSceneSwitcher.sceneItemSelection.type.sourceGroup"}, + {SceneItemSelection::Type::INDEX, + "AdvSceneSwitcher.sceneItemSelection.type.index"}, + {SceneItemSelection::Type::INDEX_RANGE, + "AdvSceneSwitcher.sceneItemSelection.type.indexRange"}, + {SceneItemSelection::Type::ALL, + "AdvSceneSwitcher.sceneItemSelection.type.all"}, }; -static bool getSceneItems(obs_scene_t *, obs_sceneitem_t *item, void *ptr) +/* ------------------------------------------------------------------------- */ + +struct NameMatchData { + std::string name; + std::vector items = {}; +}; + +static bool getSceneItemsByNameHelper(obs_scene_t *, obs_sceneitem_t *item, + void *ptr) { - ItemInfo *moveInfo = reinterpret_cast(ptr); + auto itemInfo = reinterpret_cast(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 (itemInfo->name == sourceName) { + itemInfo->items.emplace_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); + obs_scene_enum_items(scene, getSceneItemsByNameHelper, ptr); } return true; } -static std::vector -getSceneItemsWithName(obs_scene_t *scene, const std::string &name) +static std::vector getSceneItemsWithName(obs_scene_t *scene, + const std::string &name) { - ItemInfo itemInfo = {name}; - obs_scene_enum_items(scene, getSceneItems, &itemInfo); + NameMatchData itemInfo = {name}; + obs_scene_enum_items(scene, getSceneItemsByNameHelper, &itemInfo); return itemInfo.items; } +struct NamePatternMatchData { + std::string pattern; + const RegexConfig &conf; + std::vector items = {}; +}; + +static bool matchesRegex(const RegexConfig &conf, const std::string &msg, + const std::string &expr) +{ + auto regex = conf.GetRegularExpression(expr); + if (!regex.isValid()) { + return false; + } + auto match = regex.match(QString::fromStdString(msg)); + return match.hasMatch(); +} + +static bool getSceneItemsByPatternHelper(obs_scene_t *, obs_sceneitem_t *item, + void *ptr) +{ + auto data = reinterpret_cast(ptr); + auto sourceName = obs_source_get_name(obs_sceneitem_get_source(item)); + if (matchesRegex(data->conf, sourceName, data->pattern)) { + data->items.emplace_back(item); + } + + if (obs_sceneitem_is_group(item)) { + obs_scene_t *scene = obs_sceneitem_group_get_scene(item); + obs_scene_enum_items(scene, getSceneItemsByPatternHelper, ptr); + } + + return true; +} + struct ItemCountData { std::string name; int count = 0; }; -static bool countSceneItem(obs_scene_t *, obs_sceneitem_t *item, void *ptr) +static bool countSceneItemName(obs_scene_t *, obs_sceneitem_t *item, void *ptr) { auto data = reinterpret_cast(ptr); - if (obs_sceneitem_is_group(item)) { obs_scene_t *scene = obs_sceneitem_group_get_scene(item); - obs_scene_enum_items(scene, countSceneItem, ptr); + obs_scene_enum_items(scene, countSceneItemName, ptr); } auto name = obs_source_get_name(obs_sceneitem_get_source(item)); if (name == data->name) { @@ -135,62 +125,360 @@ static int getCountOfSceneItemOccurance(const SceneSelection &s, } auto data = reinterpret_cast(param); auto scene = obs_scene_from_source(source); - obs_scene_enum_items(scene, countSceneItem, data); + obs_scene_enum_items(scene, countSceneItemName, data); return true; }; obs_enum_scenes(enumScenes, &data); } else { auto source = obs_weak_source_get_source(s.GetScene(false)); auto scene = obs_scene_from_source(source); - obs_scene_enum_items(scene, countSceneItem, &data); + obs_scene_enum_items(scene, countSceneItemName, &data); obs_source_release(source); } return data.count; } -std::vector -SceneItemSelection::GetSceneItems(SceneSelection &sceneSelection) const +struct IdxData { + int idxStart = 0; + int idxEnd = -1; + int curIdx = 0; + std::vector items = {}; +}; + +static bool getSceneItemAtIdx(obs_scene_t *, obs_sceneitem_t *item, void *ptr) { - std::vector ret; - auto s = obs_weak_source_get_source(sceneSelection.GetScene(false)); + auto data = reinterpret_cast(ptr); + if (obs_sceneitem_is_group(item)) { + obs_scene_t *scene = obs_sceneitem_group_get_scene(item); + obs_scene_enum_items(scene, getSceneItemAtIdx, ptr); + } + if (data->curIdx > data->idxEnd) { + return false; + } + if (data->curIdx >= data->idxStart && data->curIdx <= data->idxEnd) { + data->items.emplace_back(item); + } + data->curIdx++; + return true; +} + +static bool getTotalSceneItemCountHelper(obs_scene_t *, obs_sceneitem_t *item, + void *ptr) +{ + auto count = reinterpret_cast(ptr); + + if (obs_sceneitem_is_group(item)) { + obs_scene_t *scene = obs_sceneitem_group_get_scene(item); + obs_scene_enum_items(scene, getTotalSceneItemCountHelper, ptr); + } + *count = *count + 1; + return true; +} + +static int getTotalSceneItemCountOnScene(const OBSWeakSource &sceneWeakSource) +{ + auto s = obs_weak_source_get_source(sceneWeakSource); auto scene = obs_scene_from_source(s); + int count = 0; + obs_scene_enum_items(scene, getTotalSceneItemCountHelper, &count); + obs_source_release(s); + return count; +} + +struct GroupData { + std::string type; + std::vector items = {}; +}; + +static bool getSceneItemsOfType(obs_scene_t *, obs_sceneitem_t *item, void *ptr) +{ + auto data = reinterpret_cast(ptr); + auto sourceTypeName = obs_source_get_display_name( + obs_source_get_id(obs_sceneitem_get_source(item))); + if (sourceTypeName && data->type == sourceTypeName) { + data->items.emplace_back(item); + } + + if (obs_sceneitem_is_group(item)) { + obs_scene_t *scene = obs_sceneitem_group_get_scene(item); + obs_scene_enum_items(scene, getSceneItemsOfType, ptr); + } + + return true; +} + +static bool getAllSceneItems(obs_scene_t *, obs_sceneitem_t *item, void *ptr) +{ + auto items = reinterpret_cast *>(ptr); + items->emplace_back(item); + + if (obs_sceneitem_is_group(item)) { + obs_scene_t *scene = obs_sceneitem_group_get_scene(item); + obs_scene_enum_items(scene, getAllSceneItems, ptr); + } + + return true; +} + +/* ------------------------------------------------------------------------- */ + +void SceneItemSelection::Save(obs_data_t *obj, const char *name) const +{ + auto data = obs_data_create(); + obs_data_set_int(data, typeSaveName.data(), static_cast(_type)); + obs_data_set_int(data, nameConflictIndexSelectionSaveName.data(), + static_cast(_nameConflictSelectionType)); + if (_nameConflictSelectionType == NameConflictSelection::INDIVIDUAL) { + obs_data_set_int(data, nameConflictIndexSaveName.data(), + _nameConflictSelectionIndex); + } else { + obs_data_set_int(data, nameConflictIndexSaveName.data(), 0); + } + + switch (_type) { + case SceneItemSelection::Type::SOURCE_NAME: + obs_data_set_string(data, itemSaveName.data(), + GetWeakSourceName(_source).c_str()); + break; + case SceneItemSelection::Type::VARIABLE_NAME: { + auto var = _variable.lock(); + if (var) { + obs_data_set_string(data, itemSaveName.data(), + var->Name().c_str()); + } + break; + } + case SceneItemSelection::Type::SOURCE_NAME_PATTERN: + _pattern.Save(data, patternSaveName.data()); + _regex.Save(data); + break; + case SceneItemSelection::Type::SOURCE_GROUP: + obs_data_set_string(obj, "sourceGroup", _sourceGroup.c_str()); + break; + case SceneItemSelection::Type::INDEX: + _index.Save(data, indexSaveName.data()); + break; + case SceneItemSelection::Type::INDEX_RANGE: + _index.Save(data, indexSaveName.data()); + _index.Save(data, indexEndSaveName.data()); + break; + default: + break; + } + + 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 *typeName, const char *idxName) +{ + _type = Type::SOURCE_NAME; + _nameConflictSelectionType = static_cast( + obs_data_get_int(obj, typeName)); + _nameConflictSelectionIndex = obs_data_get_int(obj, idxName); + auto sceneItemName = obs_data_get_string(obj, name); + _source = 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(obs_data_get_int(data, typeSaveName.data())); + _nameConflictSelectionType = static_cast( + obs_data_get_int(data, + nameConflictIndexSelectionSaveName.data())); + _nameConflictSelectionIndex = + obs_data_get_int(data, nameConflictIndexSaveName.data()); + const auto itemName = obs_data_get_string(data, itemSaveName.data()); + switch (_type) { + case SceneItemSelection::Type::SOURCE_NAME: + _source = GetWeakSourceByName(itemName); + break; + case SceneItemSelection::Type::VARIABLE_NAME: + _variable = GetWeakVariableByName(itemName); + break; + case SceneItemSelection::Type::SOURCE_NAME_PATTERN: + _pattern.Load(data, patternSaveName.data()); + _regex.Load(data); + _regex.SetEnabled(true); // No reason to disable it + break; + case SceneItemSelection::Type::SOURCE_GROUP: + _sourceGroup = obs_data_get_string(obj, "sourceGroup"); + break; + case SceneItemSelection::Type::INDEX: + _index.Load(data, indexSaveName.data()); + break; + case SceneItemSelection::Type::INDEX_RANGE: + _index.Load(data, indexSaveName.data()); + _indexEnd.Load(data, indexEndSaveName.data()); + break; + default: + break; + } + obs_data_release(data); +} + +void SceneItemSelection::SetSourceTypeSelection(const char *type) +{ + _type = Type::SOURCE_GROUP; + _sourceGroup = type; +} + +void SceneItemSelection::ReduceBadedOnIndexSelection( + std::vector &items) const +{ + if (_nameConflictSelectionType == + SceneItemSelection::NameConflictSelection::ALL || + _nameConflictSelectionType == + SceneItemSelection::NameConflictSelection::ANY) { + return; + } + // Index order starts at the bottom and increases to the top + // As this might be confusing reverse that order internally + int idx = items.size() - 1 - _nameConflictSelectionIndex; + if (idx < 0 || idx >= (int)items.size()) { + items.clear(); + return; + } + + items = {items[idx]}; +} + +std::vector SceneItemSelection::GetSceneItemsByName( + const SceneSelection &sceneSelection) const +{ + auto s = obs_weak_source_get_source(sceneSelection.GetScene(false)); + OBSSceneAutoRelease scene = obs_scene_from_source(s); std::string name; - if (_type == Type::VARIABLE) { + if (_type == Type::VARIABLE_NAME) { auto var = _variable.lock(); if (!var) { - return ret; + return {}; } name = var->Value(); } else { - name = GetWeakSourceName(_sceneItem); + name = GetWeakSourceName(_source); } int count = getCountOfSceneItemOccurance(sceneSelection, name, false); auto items = getSceneItemsWithName(scene, name); + ReduceBadedOnIndexSelection(items); + return items; +} + +std::vector SceneItemSelection::GetSceneItemsByPattern( + const SceneSelection &sceneSelection) const +{ + auto s = obs_weak_source_get_source(sceneSelection.GetScene(false)); + auto scene = obs_scene_from_source(s); + NamePatternMatchData data{_pattern, _regex}; + obs_scene_enum_items(scene, getSceneItemsByPatternHelper, &data); obs_source_release(s); + ReduceBadedOnIndexSelection(data.items); + return data.items; +} - if (_idxType == SceneItemSelection::IdxType::ALL || - _idxType == SceneItemSelection::IdxType::ANY) { - ret = items; - } else { - // Index order starts at the bottom and increases to the top - // As this might be confusing reverse that order internally - int idx = count - 1 - _idx; - - if (idx >= 0 && idx < (int)items.size()) { - obs_sceneitem_addref(items[idx]); - ret.emplace_back(items[idx]); - } - - for (auto item : items) { - obs_sceneitem_release(item); - } +std::vector SceneItemSelection::GetSceneItemsByGroup( + const SceneSelection &sceneSelection) const +{ + if (_sourceGroup.empty()) { + return {}; } - return ret; + + auto s = obs_weak_source_get_source(sceneSelection.GetScene(false)); + auto scene = obs_scene_from_source(s); + GroupData data{_sourceGroup}; + obs_scene_enum_items(scene, getSceneItemsOfType, &data); + obs_source_release(s); + ReduceBadedOnIndexSelection(data.items); + return data.items; +} + +std::vector SceneItemSelection::GetSceneItemsByIdx( + const SceneSelection &sceneSelection) const +{ + if (!_index.HasValidValue()) { + return {}; + } + + auto sceneWeakSource = sceneSelection.GetScene(false); + int count = getTotalSceneItemCountOnScene(sceneWeakSource); + if (count == 0) { + return {}; + } + + // Index order starts at the bottom and increases to the top + // As this might be confusing reverse that order internally + // + // Also subtract 1 as the user facing index starts at 1 + int idx = count - _index.GetValue(); + int idxEnd = _type == Type::INDEX_RANGE ? count - _indexEnd.GetValue() + : idx; + if (idx > idxEnd) { + std::swap(idx, idxEnd); + } + + IdxData data{idx, idxEnd}; + auto s = obs_weak_source_get_source(sceneWeakSource); + auto scene = obs_scene_from_source(s); + obs_scene_enum_items(scene, getSceneItemAtIdx, &data); + obs_source_release(s); + return data.items; +} + +std::vector +SceneItemSelection::GetAllSceneItems(const SceneSelection &sceneSelection) const +{ + auto s = obs_weak_source_get_source(sceneSelection.GetScene(false)); + auto scene = obs_scene_from_source(s); + std::vector items; + obs_scene_enum_items(scene, getAllSceneItems, &items); + obs_source_release(s); + return items; +} + +SceneItemSelection::NameConflictSelection +SceneItemSelection::GetIndexType() const +{ + return _nameConflictSelectionType; +} + +std::vector +SceneItemSelection::GetSceneItems(const SceneSelection &sceneSelection) const +{ + switch (_type) { + case Type::SOURCE_NAME: + case Type::VARIABLE_NAME: + return GetSceneItemsByName(sceneSelection); + case Type::SOURCE_NAME_PATTERN: + return GetSceneItemsByPattern(sceneSelection); + case Type::SOURCE_GROUP: + return GetSceneItemsByGroup(sceneSelection); + case Type::INDEX: + case Type::INDEX_RANGE: + return GetSceneItemsByIdx(sceneSelection); + case Type::ALL: + return GetAllSceneItems(sceneSelection); + default: + break; + } + + return {}; } std::string SceneItemSelection::ToString(bool resolve) const { - if (_type == Type::VARIABLE) { + switch (_type) { + case Type::SOURCE_NAME: + return GetWeakSourceName(_source); + case Type::VARIABLE_NAME: { auto var = _variable.lock(); if (!var) { return ""; @@ -200,33 +488,59 @@ std::string SceneItemSelection::ToString(bool resolve) const } return var->Name(); } - return GetWeakSourceName(_sceneItem); + case Type::SOURCE_NAME_PATTERN: + if (resolve) { + return std::string(obs_module_text( + "AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern")) + + " \"" + std::string(_pattern) + "\""; + } + return ""; + case Type::SOURCE_GROUP: + if (resolve) { + return std::string(obs_module_text( + "AdvSceneSwitcher.sceneItemSelection.type.sourceGroup")) + + " \"" + std::string(_sourceGroup) + "\""; + } + return _sourceGroup; + case Type::INDEX: + if (resolve) { + return std::string(obs_module_text( + "AdvSceneSwitcher.sceneItemSelection.type.index")) + + " " + std::to_string(_index); + } + return ""; + case Type::INDEX_RANGE: + if (resolve) { + return std::string(obs_module_text( + "AdvSceneSwitcher.sceneItemSelection.type.indexRange")) + + " " + std::to_string(_index) + " - " + + std::to_string(_indexEnd); + } + return ""; + case Type::ALL: + return obs_module_text( + "AdvSceneSwitcher.sceneItemSelection.all"); + default: + break; + } + + return ""; } -static bool enumSceneItem(obs_scene_t *, obs_sceneitem_t *item, void *ptr) +static bool populateSceneItemSelectionHelper(obs_scene_t *, + obs_sceneitem_t *item, void *ptr) { - QStringList *names = reinterpret_cast(ptr); - + auto names = reinterpret_cast(ptr); if (obs_sceneitem_is_group(item)) { obs_scene_t *scene = obs_sceneitem_group_get_scene(item); - obs_scene_enum_items(scene, enumSceneItem, ptr); + obs_scene_enum_items(scene, populateSceneItemSelectionHelper, + ptr); } auto name = obs_source_get_name(obs_sceneitem_get_source(item)); names->append(name); return true; } -static 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; @@ -235,10 +549,10 @@ QStringList GetSceneItemsList(SceneSelection &s) if (!source) { return true; } - QStringList *names = - reinterpret_cast(param); + auto names = reinterpret_cast(param); auto scene = obs_scene_from_source(source); - obs_scene_enum_items(scene, enumSceneItem, names); + obs_scene_enum_items( + scene, populateSceneItemSelectionHelper, names); return true; }; @@ -246,7 +560,8 @@ QStringList GetSceneItemsList(SceneSelection &s) } 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_scene_enum_items(scene, populateSceneItemSelectionHelper, + &names); obs_source_release(source); } @@ -255,113 +570,131 @@ QStringList GetSceneItemsList(SceneSelection &s) return names; } -void SceneItemSelectionWidget::Reset() -{ - auto previousSel = _currentSelection; - PopulateItemSelection(); - SetSceneItem(previousSel); -} - void SceneItemSelectionWidget::PopulateItemSelection() { - _sceneItems->clear(); - const QStringList variables = GetVariablesNameList(); - AddSelectionGroup(_sceneItems, variables); - _variablesEndIdx = _sceneItems->count(); - const QStringList sceneItmes = GetSceneItemsList(_scene); - AddSelectionGroup(_sceneItems, sceneItmes, false); - _itemsEndIdx = _sceneItems->count(); - _sceneItems->setCurrentIndex(-1); + AddSelectionGroup(_sources, sceneItmes, false); + _sources->setCurrentIndex(-1); +} + +static inline void populateMessageTypeSelection(QComboBox *list) +{ + for (const auto &[type, name] : types) { + list->addItem(obs_module_text(name.c_str()), + static_cast(type)); + } } SceneItemSelectionWidget::SceneItemSelectionWidget(QWidget *parent, bool showAll, Placeholder type) - : QWidget(parent), _hasPlaceholderEntry(showAll), _placeholder(type) + : QWidget(parent), + _controlsLayout(new QHBoxLayout), + _sources(new FilterComboBox( + this, obs_module_text("AdvSceneSwitcher.selectItem"))), + _variables(new VariableSelection(this)), + _nameConflictIndex(new QComboBox(this)), + _index(new VariableSpinBox(this)), + _indexEnd(new VariableSpinBox(this)), + _sourceGroups(new QComboBox(this)), + _pattern(new VariableLineEdit(this)), + _regex(new RegexConfigWidget(this, false)), + _changeType(new QPushButton(this)), + _hasPlaceholderEntry(showAll), + _placeholder(type) { - _sceneItems = new FilterComboBox( - this, obs_module_text("AdvSceneSwitcher.selectItem")); - _idx = new QComboBox(); + _sources->setSizeAdjustPolicy(QComboBox::AdjustToContents); + _nameConflictIndex->setSizeAdjustPolicy(QComboBox::AdjustToContents); - _sceneItems->setSizeAdjustPolicy(QComboBox::AdjustToContents); - _idx->setSizeAdjustPolicy(QComboBox::AdjustToContents); + _changeType->setMaximumWidth(22); + SetButtonIcon(_changeType, ":/settings/images/settings/general.svg"); + _changeType->setFlat(true); + _changeType->setToolTip(obs_module_text( + "AdvSceneSwitcher.sceneItemSelection.configure")); - populateSceneItemSelection(_sceneItems); + _index->setMinimum(1); + _index->setSuffix("."); + _indexEnd->setMinimum(1); + _indexEnd->setSuffix("."); - QWidget::connect(_sceneItems, SIGNAL(currentIndexChanged(int)), this, - SLOT(SelectionChanged(int))); - 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 &))); + PopulateSourceGroupSelection(_sourceGroups); + + QWidget::connect(_sources, SIGNAL(currentIndexChanged(int)), this, + SLOT(SourceChanged(int))); + QWidget::connect(_variables, SIGNAL(SelectionChanged(const QString &)), + this, SLOT(VariableChanged(const QString &))); + QWidget::connect(_nameConflictIndex, SIGNAL(currentIndexChanged(int)), + this, SLOT(NameConflictIndexChanged(int))); + QWidget::connect(_sourceGroups, + SIGNAL(currentTextChanged(const QString &)), this, + SLOT(SourceGroupChanged(const QString &))); QWidget::connect( - window(), - SIGNAL(VariableRenamed(const QString &, const QString &)), this, - SLOT(ItemRename(const QString &, const QString &))); + _index, + SIGNAL(NumberVariableChanged(const NumberVariable &)), + this, SLOT(IndexChanged(const NumberVariable &))); + QWidget::connect( + _indexEnd, + SIGNAL(NumberVariableChanged(const NumberVariable &)), + this, SLOT(IndexEndChanged(const NumberVariable &))); + QWidget::connect(_pattern, SIGNAL(editingFinished()), this, + SLOT(PatternChanged())); + QWidget::connect(_regex, SIGNAL(RegexConfigChanged(RegexConfig)), this, + SLOT(RegexChanged(RegexConfig))); + QWidget::connect(_changeType, SIGNAL(clicked()), this, + SLOT(ChangeType())); + _controlsLayout->setContentsMargins(0, 0, 0, 0); auto layout = new QHBoxLayout; layout->setContentsMargins(0, 0, 0, 0); - layout->addWidget(_idx); - layout->addWidget(_sceneItems); + layout->addLayout(_controlsLayout); + layout->addWidget(_changeType); setLayout(layout); - _idx->hide(); + _nameConflictIndex->hide(); } void SceneItemSelectionWidget::SetSceneItem(const SceneItemSelection &item) { - int itemIdx = -1; - switch (item._type) { - case SceneItemSelection::Type::SOURCE: { - int idx = item._idx; - if (_hasPlaceholderEntry) { - idx += 1; - } - _idx->setCurrentIndex(idx); - itemIdx = FindIdxInRagne(_sceneItems, _variablesEndIdx, - _itemsEndIdx, - GetWeakSourceName(item._sceneItem)); - _sceneItems->setCurrentIndex(itemIdx); - break; + int idx = item._nameConflictSelectionIndex; + if (_hasPlaceholderEntry) { + idx += 1; } - case SceneItemSelection::Type::VARIABLE: { + _nameConflictIndex->setCurrentIndex(idx); + _sources->setCurrentText( + QString::fromStdString(GetWeakSourceName(item._source))); + _variables->SetVariable(item._variable); + _index->SetValue(item._index); + _indexEnd->SetValue(item._indexEnd); + _sourceGroups->setCurrentIndex(_sourceGroups->findText( + QString::fromStdString(item._sourceGroup))); + _pattern->setText(item._pattern); + _regex->SetRegexConfig(item._regex); - auto var = item._variable.lock(); - if (!var) { - break; - } - itemIdx = FindIdxInRagne(_sceneItems, _selectIdx, - _variablesEndIdx, var->Name()); - _sceneItems->setCurrentIndex(itemIdx); - break; - } - } + SetNameConflictVisibility(); - switch (item._idxType) { - case SceneItemSelection::IdxType::ALL: - case SceneItemSelection::IdxType::ANY: + switch (item._nameConflictSelectionType) { + case SceneItemSelection::NameConflictSelection::ALL: + case SceneItemSelection::NameConflictSelection::ANY: _placeholder = Placeholder::ALL; - _idx->setCurrentIndex(0); + _nameConflictIndex->setCurrentIndex(0); break; - case SceneItemSelection::IdxType::INDIVIDUAL: - int idx = item._idx; + case SceneItemSelection::NameConflictSelection::INDIVIDUAL: + int idx = item._nameConflictSelectionIndex; if (_hasPlaceholderEntry) { idx += 1; } - _idx->setCurrentIndex(idx); + _nameConflictIndex->setCurrentIndex(idx); break; } _currentSelection = item; + + SetWidgetVisibility(); } void SceneItemSelectionWidget::SetScene(const SceneSelection &s) { _scene = s; - _sceneItems->clear(); - _idx->hide(); + _sources->clear(); + _nameConflictIndex->hide(); PopulateItemSelection(); } @@ -375,11 +708,11 @@ void SceneItemSelectionWidget::SetPlaceholderType(Placeholder t, { _placeholder = t; if (resetSelection) { - _sceneItems->setCurrentIndex(-1); + _sources->setCurrentIndex(-1); } else { - auto count = _idx->count() - 1; - const QSignalBlocker b(_idx); - SetupIdxSelection(count > 0 ? count : 1); + auto count = _nameConflictIndex->count() - 1; + const QSignalBlocker b(_nameConflictIndex); + SetupNameConflictIdxSelection(count > 0 ? count : 1); } } @@ -389,115 +722,324 @@ void SceneItemSelectionWidget::SceneChanged(const SceneSelection &s) adjustSize(); } -SceneItemSelection SceneItemSelectionWidget::CurrentSelection() +void SceneItemSelectionWidget::SetNameConflictVisibility() { - SceneItemSelection s; - const int idx = _sceneItems->currentIndex(); - const auto name = _sceneItems->currentText(); + int sceneItemCount = 0; - int sceneItemCount = - getCountOfSceneItemOccurance(_scene, name.toStdString()); - if (sceneItemCount > 1) { - _idx->show(); - SetupIdxSelection(sceneItemCount); - } else { - _idx->hide(); - } - - if (_hasPlaceholderEntry) { - switch (_placeholder) { - case SceneItemSelectionWidget::Placeholder::ALL: - s._idxType = SceneItemSelection::IdxType::ALL; - break; - case SceneItemSelectionWidget::Placeholder::ANY: - s._idxType = SceneItemSelection::IdxType::ANY; + switch (_currentSelection._type) { + case SceneItemSelection::Type::SOURCE_NAME: + case SceneItemSelection::Type::VARIABLE_NAME: { + QString name = ""; + if (_currentSelection._type == + SceneItemSelection::Type::VARIABLE_NAME) { + auto var = _currentSelection._variable.lock(); + if (var) { + name = QString::fromStdString(var->Value()); + } + } + if (_currentSelection._type == + SceneItemSelection::Type::SOURCE_NAME) { + name = _sources->currentText(); + } + if (name.isEmpty()) { break; } + sceneItemCount = getCountOfSceneItemOccurance( + _scene, name.toStdString()); + break; } - if (idx == -1 || name.isEmpty()) { - return s; + case SceneItemSelection::Type::SOURCE_NAME_PATTERN: + case SceneItemSelection::Type::SOURCE_GROUP: + sceneItemCount = + getTotalSceneItemCountOnScene(_scene.GetScene(false)); + break; } - if (idx < _variablesEndIdx) { - s._type = SceneItemSelection::Type::VARIABLE; - s._variable = GetWeakVariableByQString(name); - } else if (idx < _itemsEndIdx) { - s._type = SceneItemSelection::Type::SOURCE; - s._sceneItem = GetWeakSourceByQString(name); + if (_currentSelection._type == + SceneItemSelection::Type::SOURCE_NAME_PATTERN) { + int sceneItemCount = + getTotalSceneItemCountOnScene(_scene.GetScene(false)); + if (sceneItemCount == 0) { + _nameConflictIndex->hide(); + return; + } + SetupNameConflictIdxSelection(sceneItemCount); + _nameConflictIndex->show(); + return; } - return s; + if (sceneItemCount == 0) { + _nameConflictIndex->hide(); + return; + } + if (sceneItemCount > 1) { + SetupNameConflictIdxSelection(sceneItemCount); + _nameConflictIndex->show(); + } else { + _nameConflictIndex->hide(); + } } -void SceneItemSelectionWidget::SelectionChanged(int) +void SceneItemSelectionWidget::VariableChanged(const QString &text) { - _currentSelection = CurrentSelection(); + _currentSelection._variable = GetWeakVariableByQString(text); + SetNameConflictVisibility(); emit SceneItemChanged(_currentSelection); } -void SceneItemSelectionWidget::IdxChanged(int idx) +void SceneItemSelectionWidget::SourceChanged(int) +{ + _currentSelection._source = + GetWeakSourceByQString(_sources->currentText()); + SetNameConflictVisibility(); + emit SceneItemChanged(_currentSelection); +} + +void SceneItemSelectionWidget::IndexChanged(const IntVariable &index) +{ + _currentSelection._index = index; + emit SceneItemChanged(_currentSelection); +} + +void SceneItemSelectionWidget::IndexEndChanged(const IntVariable &index) +{ + _currentSelection._indexEnd = index; + emit SceneItemChanged(_currentSelection); +} + +void SceneItemSelectionWidget::NameConflictIndexChanged(int idx) { if (idx < 0) { return; } - _currentSelection._idx = idx; + _currentSelection._nameConflictSelectionIndex = idx; if (_hasPlaceholderEntry && idx == 0) { switch (_placeholder) { case SceneItemSelectionWidget::Placeholder::ALL: - _currentSelection._idxType = - SceneItemSelection::IdxType::ALL; + _currentSelection._nameConflictSelectionType = + SceneItemSelection::NameConflictSelection::ALL; break; case SceneItemSelectionWidget::Placeholder::ANY: - _currentSelection._idxType = - SceneItemSelection::IdxType::ANY; + _currentSelection._nameConflictSelectionType = + SceneItemSelection::NameConflictSelection::ANY; break; } } if (_hasPlaceholderEntry && idx > 0) { - _currentSelection._idx -= 1; - _currentSelection._idxType = - SceneItemSelection::IdxType::INDIVIDUAL; + _currentSelection._nameConflictSelectionIndex -= 1; + _currentSelection._nameConflictSelectionType = + SceneItemSelection::NameConflictSelection::INDIVIDUAL; } emit SceneItemChanged(_currentSelection); } -void SceneItemSelectionWidget::ItemAdd(const QString &) +void SceneItemSelectionWidget::PatternChanged() { - blockSignals(true); - Reset(); - blockSignals(false); + _currentSelection._pattern = _pattern->text().toStdString(); + emit SceneItemChanged(_currentSelection); } -void SceneItemSelectionWidget::ItemRemove(const QString &) +void SceneItemSelectionWidget::RegexChanged(RegexConfig regex) { - Reset(); + regex.SetEnabled(true); // No reason for it to be disabled + _currentSelection._regex = regex; + emit SceneItemChanged(_currentSelection); } -void SceneItemSelectionWidget::ItemRename(const QString &, const QString &) +void SceneItemSelectionWidget::SourceGroupChanged(const QString &text) { - blockSignals(true); - Reset(); - blockSignals(false); + if (text == obs_module_text("AdvSceneSwitcher.selectItem")) { + _currentSelection._sourceGroup = ""; + } else { + _currentSelection._sourceGroup = text.toStdString(); + } + emit SceneItemChanged(_currentSelection); } -void SceneItemSelectionWidget::SetupIdxSelection(int sceneItemCount) +void SceneItemSelectionWidget::ChangeType() { - _idx->clear(); + bool accepted = SceneItemTypeSelection::AskForSettings( + this, _currentSelection._type); + if (!accepted) { + return; + } + + SetNameConflictVisibility(); + SetWidgetVisibility(); + emit SceneItemChanged(_currentSelection); +} + +void SceneItemSelectionWidget::SetupNameConflictIdxSelection(int sceneItemCount) +{ + _nameConflictIndex->clear(); if (_hasPlaceholderEntry) { if (_placeholder == Placeholder::ALL) { - _idx->addItem(obs_module_text( + _nameConflictIndex->addItem(obs_module_text( "AdvSceneSwitcher.sceneItemSelection.all")); } else { - _idx->addItem(obs_module_text( + _nameConflictIndex->addItem(obs_module_text( "AdvSceneSwitcher.sceneItemSelection.any")); } } for (int i = 1; i <= sceneItemCount; ++i) { - _idx->addItem(QString::number(i) + "."); + _nameConflictIndex->addItem(QString::number(i) + "."); } adjustSize(); + updateGeometry(); +} + +void SceneItemSelectionWidget::ClearWidgets() +{ + _controlsLayout->removeWidget(_nameConflictIndex); + _controlsLayout->removeWidget(_sources); + _controlsLayout->removeWidget(_variables); + _controlsLayout->removeWidget(_pattern); + _controlsLayout->removeWidget(_regex); + _controlsLayout->removeWidget(_sourceGroups); + _controlsLayout->removeWidget(_index); + _controlsLayout->removeWidget(_indexEnd); + ClearLayout(_controlsLayout); +} + +void SceneItemSelectionWidget::SetWidgetVisibility() +{ + ClearWidgets(); + const std::unordered_map widgetMap = { + {"{{nameConflictIndex}}", _nameConflictIndex}, + {"{{sourceName}}", _sources}, + {"{{variable}}", _variables}, + {"{{pattern}}", _pattern}, + {"{{regex}}", _regex}, + {"{{sourceGroups}}", _sourceGroups}, + {"{{index}}", _index}, + {"{{indexEnd}}", _indexEnd}, + }; + + switch (_currentSelection._type) { + case SceneItemSelection::Type::SOURCE_NAME: + PlaceWidgets( + obs_module_text( + "AdvSceneSwitcher.sceneItemSelection.type.sourceName.entry"), + _controlsLayout, widgetMap, false); + break; + case SceneItemSelection::Type::VARIABLE_NAME: + PlaceWidgets( + obs_module_text( + "AdvSceneSwitcher.sceneItemSelection.type.sourceVariable.entry"), + _controlsLayout, widgetMap, false); + break; + case SceneItemSelection::Type::SOURCE_NAME_PATTERN: + PlaceWidgets( + obs_module_text( + "AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.entry"), + _controlsLayout, widgetMap, false); + break; + case SceneItemSelection::Type::SOURCE_GROUP: + PlaceWidgets( + obs_module_text( + "AdvSceneSwitcher.sceneItemSelection.type.sourceGroup.entry"), + _controlsLayout, widgetMap, false); + break; + case SceneItemSelection::Type::INDEX: + PlaceWidgets( + obs_module_text( + "AdvSceneSwitcher.sceneItemSelection.type.index.entry"), + _controlsLayout, widgetMap, false); + break; + case SceneItemSelection::Type::INDEX_RANGE: + PlaceWidgets( + obs_module_text( + "AdvSceneSwitcher.sceneItemSelection.type.indexRange.entry"), + _controlsLayout, widgetMap, false); + break; + case SceneItemSelection::Type::ALL: + PlaceWidgets( + obs_module_text( + "AdvSceneSwitcher.sceneItemSelection.type.all.entry"), + _controlsLayout, widgetMap, false); + break; + default: + break; + } + + // Name based + _sources->setVisible(_currentSelection._type == + SceneItemSelection::Type::SOURCE_NAME); + _variables->setVisible(_currentSelection._type == + SceneItemSelection::Type::VARIABLE_NAME); + + const bool isRegexSelection = + _currentSelection._type == + SceneItemSelection::Type::SOURCE_NAME_PATTERN; + _pattern->setVisible(isRegexSelection); + _regex->setVisible(isRegexSelection); + + const bool isNameSelection = + _currentSelection._type == + SceneItemSelection::Type::VARIABLE_NAME || + _currentSelection._type == + SceneItemSelection::Type::SOURCE_NAME; + + // Group based + _sourceGroups->setVisible(_currentSelection._type == + SceneItemSelection::Type::SOURCE_GROUP); + + if (!isNameSelection && !isRegexSelection && + _currentSelection._type != SceneItemSelection::Type::SOURCE_GROUP) { + _nameConflictIndex->hide(); + } + + // Index based + _index->setVisible(_currentSelection._type == + SceneItemSelection::Type::INDEX || + _currentSelection._type == + SceneItemSelection::Type::INDEX_RANGE); + _indexEnd->setVisible(_currentSelection._type == + SceneItemSelection::Type::INDEX_RANGE); + + adjustSize(); + updateGeometry(); +} + +SceneItemTypeSelection::SceneItemTypeSelection( + QWidget *parent, const SceneItemSelection::Type &type) + : QDialog(parent), + _typeSelection(new QComboBox(this)), + _buttonbox(new QDialogButtonBox(QDialogButtonBox::Ok | + QDialogButtonBox::Cancel)) +{ + setModal(true); + setWindowModality(Qt::WindowModality::WindowModal); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + populateMessageTypeSelection(_typeSelection); + _typeSelection->setCurrentIndex( + _typeSelection->findData(static_cast(type))); + + QWidget::connect(_buttonbox, &QDialogButtonBox::accepted, this, + &QDialog::accept); + QWidget::connect(_buttonbox, &QDialogButtonBox::rejected, this, + &QDialog::reject); + auto layout = new QVBoxLayout(); + layout->addWidget(_typeSelection); + layout->addWidget(_buttonbox, Qt::AlignHCenter); + setLayout(layout); +} + +bool SceneItemTypeSelection::AskForSettings(QWidget *parent, + SceneItemSelection::Type &type) +{ + SceneItemTypeSelection dialog(parent, type); + dialog.setWindowTitle(obs_module_text("AdvSceneSwitcher.windowTitle")); + if (dialog.exec() != DialogCode::Accepted) { + return false; + } + + type = static_cast( + dialog._typeSelection->currentData().toInt()); + return true; } } // namespace advss diff --git a/src/utils/scene-item-selection.hpp b/src/utils/scene-item-selection.hpp index a333e951..5bce9414 100644 --- a/src/utils/scene-item-selection.hpp +++ b/src/utils/scene-item-selection.hpp @@ -1,7 +1,10 @@ #pragma once #include "scene-selection.hpp" -#include "variable.hpp" #include "filter-combo-box.hpp" +#include "variable-spinbox.hpp" +#include "variable-line-edit.hpp" +#include "variable-string.hpp" +#include "regex-config.hpp" #include "utility.hpp" #include @@ -18,26 +21,64 @@ public: const char *idxName); enum class Type { - SOURCE, - VARIABLE, + SOURCE_NAME, + VARIABLE_NAME, + SOURCE_NAME_PATTERN = 10, + SOURCE_GROUP = 20, + INDEX = 30, + INDEX_RANGE = 40, + ALL = 50, }; - enum class IdxType { + + // Name conflicts can happen if multiple instances of a given source are + // present in a given scene. + // + // If that is the case, the user has the option to specify if all / any + // or a given individual instance of the source based on its index shall + // be returned. + enum class NameConflictSelection { ALL, ANY, INDIVIDUAL, }; Type GetType() const { return _type; } - IdxType GetIndexType() const { return _idxType; } - std::vector GetSceneItems(SceneSelection &s) const; + NameConflictSelection GetIndexType() const; + std::vector GetSceneItems(const SceneSelection &) const; std::string ToString(bool resolve = false) const; + // TODO: Remove in future version + // + // Only exists to enable backwards compatabilty with older versions of + // scene item visibility action + void SetSourceTypeSelection(const char *); + private: - OBSWeakSource _sceneItem; + std::vector + GetSceneItemsByName(const SceneSelection &) const; + std::vector + GetSceneItemsByPattern(const SceneSelection &) const; + std::vector + GetSceneItemsByGroup(const SceneSelection &) const; + std::vector + GetSceneItemsByIdx(const SceneSelection &) const; + std::vector + GetAllSceneItems(const SceneSelection &) const; + + void ReduceBadedOnIndexSelection(std::vector &) const; + + Type _type = Type::SOURCE_NAME; + + OBSWeakSource _source; std::weak_ptr _variable; - Type _type = Type::SOURCE; - IdxType _idxType = IdxType::ALL; - int _idx = 0; // Multiple items with the same name can exist + IntVariable _index = 1; + IntVariable _indexEnd = 1; + NameConflictSelection _nameConflictSelectionType = + NameConflictSelection::ALL; + int _nameConflictSelectionIndex = 0; + std::string _sourceGroup; + StringVariable _pattern = ".*"; + RegexConfig _regex = RegexConfig(true); friend class SceneItemSelectionWidget; }; @@ -56,34 +97,61 @@ signals: void SceneItemChanged(const SceneItemSelection &); private slots: + // Name based void SceneChanged(const SceneSelection &); - void SelectionChanged(int); - void IdxChanged(int); - void ItemAdd(const QString &name); - void ItemRemove(const QString &name); - void ItemRename(const QString &oldName, const QString &newName); + void VariableChanged(const QString &); + void SourceChanged(int); + void NameConflictIndexChanged(int); + void PatternChanged(); + void RegexChanged(RegexConfig); + + // Source group based + void SourceGroupChanged(const QString &); + + // Index based + void IndexChanged(const NumberVariable &); + void IndexEndChanged(const NumberVariable &); + + void ChangeType(); private: - void Reset(); - SceneItemSelection CurrentSelection(); + void ClearWidgets(); void PopulateItemSelection(); - void SetupIdxSelection(int); + void SetupNameConflictIdxSelection(int); + void SetNameConflictVisibility(); + void SetWidgetVisibility(); - FilterComboBox *_sceneItems; - QComboBox *_idx; + QHBoxLayout *_controlsLayout; + FilterComboBox *_sources; + VariableSelection *_variables; + QComboBox *_nameConflictIndex; + VariableSpinBox *_index; + VariableSpinBox *_indexEnd; + QComboBox *_sourceGroups; + VariableLineEdit *_pattern; + RegexConfigWidget *_regex; + QPushButton *_changeType; SceneSelection _scene; SceneItemSelection _currentSelection; bool _hasPlaceholderEntry = false; Placeholder _placeholder = Placeholder::ALL; - // Order of entries - // 1. "select entry" entry - // 2. Variables - // 3. Scene items - const int _selectIdx = 0; - int _variablesEndIdx = -1; - int _itemsEndIdx = -1; + bool _showTypeSelection = false; +}; + +class SceneItemTypeSelection : public QDialog { + Q_OBJECT + +public: + SceneItemTypeSelection(QWidget *parent, + const SceneItemSelection::Type &type); + static bool AskForSettings(QWidget *parent, + SceneItemSelection::Type &type); + +private: + QComboBox *_typeSelection; + QDialogButtonBox *_buttonbox; }; } // namespace advss