From 078d62fa181227537c858e0466eaf3e8ce7642e8 Mon Sep 17 00:00:00 2001 From: WarmUpTill <19472752+WarmUpTill@users.noreply.github.com> Date: Mon, 6 Oct 2025 19:28:05 +0200 Subject: [PATCH] Add canvas support to scene selection --- CMakeLists.txt | 2 + data/locale/en-US.ini | 1 + lib/utils/canvas-helpers.cpp | 296 +++++++++++++++++++++++++++++++++ lib/utils/canvas-helpers.hpp | 61 +++++++ lib/utils/scene-selection.cpp | 299 ++++++++++++++++++++++++---------- lib/utils/scene-selection.hpp | 21 ++- 6 files changed, 593 insertions(+), 87 deletions(-) create mode 100644 lib/utils/canvas-helpers.cpp create mode 100644 lib/utils/canvas-helpers.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ebdd41f9..aedee8e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -170,6 +170,8 @@ target_sources( lib/utils/auto-update-tooltip-label.hpp lib/utils/backup.cpp lib/utils/backup.hpp + lib/utils/canvas-helpers.cpp + lib/utils/canvas-helpers.hpp lib/utils/condition-logic.cpp lib/utils/condition-logic.hpp lib/utils/curl-helper.cpp diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 4bbd1233..77fd92bf 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -2290,6 +2290,7 @@ AdvSceneSwitcher.tempVar.cursor.x="Cursor position (X)" AdvSceneSwitcher.tempVar.cursor.y="Cursor position (Y)" AdvSceneSwitcher.selectScene="--select scene--" +AdvSceneSwitcher.selectCanvas="--select canvas--" AdvSceneSwitcher.selectPreviousScene="Previous Scene" AdvSceneSwitcher.selectCurrentScene="Current Scene" AdvSceneSwitcher.selectPreviewScene="Preview Scene" diff --git a/lib/utils/canvas-helpers.cpp b/lib/utils/canvas-helpers.cpp new file mode 100644 index 00000000..58a92d18 --- /dev/null +++ b/lib/utils/canvas-helpers.cpp @@ -0,0 +1,296 @@ +#include "canvas-helpers.hpp" +#include "obs-module-helper.hpp" +#include "scene-group.hpp" +#include "scene-switch-helpers.hpp" +#include "selection-helpers.hpp" +#include "source-helpers.hpp" +#include "ui-helpers.hpp" +#include "utility.hpp" +#include "variable.hpp" + +#include + +#include + +#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0) +Q_DECLARE_METATYPE(advss::OBSWeakCanvas); +#else +Q_DECLARE_METATYPE(OBSWeakCanvas); +#endif + +namespace advss { + +void CanvasSelection::Populate() +{ +#if LIBOBS_API_VER >= MAKE_SEMANTIC_VERSION(31, 1, 0) + static const auto enumCanvases = [](void *listPtr, + obs_canvas_t *canvas) -> bool { + auto list = static_cast(listPtr); + OBSWeakCanvas weakCanvas = obs_canvas_get_weak_canvas(canvas); + obs_weak_canvas_release(weakCanvas); + QVariant variant; + variant.setValue(weakCanvas); + list->addItem(obs_canvas_get_name(canvas), variant); + return true; + }; + obs_enum_canvases(enumCanvases, this); +#endif +} + +CanvasSelection::CanvasSelection(QWidget *parent) + : FilterComboBox(parent, + obs_module_text("AdvSceneSwitcher.selectScene")) +{ + setSizeAdjustPolicy(QComboBox::AdjustToContents); + + Populate(); + + connect(this, &FilterComboBox::currentIndexChanged, this, + [this]() { emit CanvasChanged(GetCanvas()); }); +} + +void CanvasSelection::SetCanvas(const OBSWeakCanvas &canvas) +{ + QVariant variant; + variant.setValue(canvas); + setCurrentIndex(findData(variant)); +} + +OBSWeakCanvas CanvasSelection::GetCanvas() +{ + return itemData(currentIndex()).value(); +} + +int GetCanvasCount() +{ +#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0) + return 1; +#else + static const auto enumCanvases = [](void *countPtr, + obs_canvas_t *canvas) -> bool { + auto count = static_cast(countPtr); + (*count)++; + return true; + }; + int count = 0; + obs_enum_canvases(enumCanvases, &count); + return count; +#endif +} + +OBSWeakCanvas GetWeakCanvasByName(const char *name) +{ +#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0) + return OBSWeakCanvas(); +#else + struct Data { + OBSWeakCanvas canvas; + const std::string name; + }; + + static const auto enumCanvases = [](void *dataPtr, + obs_canvas_t *canvas) -> bool { + auto data = static_cast(dataPtr); + if (data->name != obs_canvas_get_name(canvas)) { + return true; + } + + data->canvas = obs_canvas_get_weak_canvas(canvas); + obs_weak_canvas_release(data->canvas); + return false; + }; + Data data{nullptr, name}; + obs_enum_canvases(enumCanvases, &data); + return data.canvas; +#endif +} + +std::string GetWeakCanvasName(const OBSWeakCanvas &weakCanvas) +{ +#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0) + return "Main"; +#else + OBSCanvasAutoRelease canvas = obs_weak_canvas_get_canvas(weakCanvas); + return canvas ? obs_canvas_get_name(canvas) : ""; +#endif +} + +bool IsMainCanvas(obs_weak_canvas_t *weakCanvas) +{ +#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0) + return true; +#else + if (!weakCanvas) { + return false; + } + + OBSCanvasAutoRelease canvas = obs_weak_canvas_get_canvas(weakCanvas); + OBSCanvasAutoRelease main = obs_get_main_canvas(); + return canvas == main; +#endif +} + +OBSWeakSource GetActiveCanvasScene(const OBSWeakCanvas &weakCanvas) +{ +#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0) + OBSCanvasAutoRelease canvas; +#else + if (!weakCanvas) { + return nullptr; + } + + OBSCanvasAutoRelease canvas = obs_weak_canvas_get_canvas(weakCanvas); + if (!canvas) { + return nullptr; + } +#endif + + static const auto enumCanvasScenes = [](void *scenePtr, + obs_source_t *source) -> bool { + auto scene = static_cast(scenePtr); + if (!obs_source_active(source)) { + return true; + } + + *scene = obs_source_get_weak_source(source); + obs_weak_source_release(*scene); + return false; + }; + + OBSWeakSource scene; + obs_canvas_enum_scenes(canvas, enumCanvasScenes, &scene); + return scene; +} + +OBSWeakSource GetSceneAtIndex(const OBSWeakCanvas &weakCanvas, int idx) +{ + if (idx < 0) { + return nullptr; + } + +#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0) + OBSCanvas canvas; +#else + if (!weakCanvas) { + return nullptr; + } + + OBSCanvas canvas = OBSGetStrongRef(weakCanvas); + if (!canvas) { + return nullptr; + } +#endif + + struct Data { + const int idx; + int currentIdx; + OBSSource scene; + }; + + static const auto enumCanvasScenes = [](void *dataPtr, + obs_source_t *source) -> bool { + auto data = static_cast(dataPtr); + if (data->idx != data->currentIdx) { + data->currentIdx++; + return true; + } + + data->scene = source; + return false; + }; + + Data data{idx, 0, nullptr}; + obs_canvas_enum_scenes(canvas, enumCanvasScenes, &data); + + return OBSGetWeakRef(data.scene); +} + +int GetIndexOfScene(const OBSWeakCanvas &weakCanvas, const OBSWeakSource &scene) +{ + if (!scene) { + return 0; + } + +#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0) + OBSCanvas canvas; +#else + if (!weakCanvas) { + return 0; + } + + OBSCanvas canvas = OBSGetStrongRef(weakCanvas); + if (!canvas) { + return 0; + } +#endif + + struct Data { + int idx; + OBSSource scene; + }; + + static const auto enumCanvasScenes = [](void *dataPtr, + obs_source_t *source) -> bool { + auto data = static_cast(dataPtr); + if (source == data->scene) { + return false; + } + + data->idx++; + return true; + }; + + Data data{0, OBSGetStrongRef(scene)}; + obs_canvas_enum_scenes(canvas, enumCanvasScenes, &data); + + return data.idx; +} + +#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0) + +obs_canvas_t *obs_canvas_get_ref(obs_canvas_t *) +{ + return nullptr; +} + +void obs_canvas_release(obs_canvas_t *) {} + +void obs_weak_canvas_addref(obs_weak_canvas_t *) {} + +void obs_weak_canvas_release(obs_weak_canvas_t *) {} + +OBSCanvas OBSGetStrongRef(obs_weak_object_t *weak) +{ + return {}; +} + +obs_weak_canvas_t *obs_canvas_get_weak_canvas(obs_canvas_t *) +{ + return nullptr; +} + +obs_canvas_t *obs_weak_canvas_get_canvas(obs_weak_canvas_t *) +{ + return nullptr; +} + +void obs_canvas_enum_scenes(obs_canvas_t *, + bool (*enum_proc)(void *, obs_source_t *), + void *param) +{ + obs_enum_scenes(enum_proc, param); +} + +OBSCanvas OBSGetStrongRef(obs_weak_canvas_t *) +{ + return OBSCanvas(); +} + +obs_canvas_t *obs_get_main_canvas() +{ + return nullptr; +} + +#endif + +} // namespace advss diff --git a/lib/utils/canvas-helpers.hpp b/lib/utils/canvas-helpers.hpp new file mode 100644 index 00000000..8644252f --- /dev/null +++ b/lib/utils/canvas-helpers.hpp @@ -0,0 +1,61 @@ +#pragma once +#include "filter-combo-box.hpp" + +#include + +namespace advss { + +#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0) +class EXPORT obs_canvas_t {}; +class EXPORT obs_weak_canvas_t {}; + +EXPORT obs_canvas_t *obs_canvas_get_ref(obs_canvas_t *); +EXPORT void obs_canvas_release(obs_canvas_t *); +EXPORT void obs_weak_canvas_addref(obs_weak_canvas_t *); +EXPORT void obs_weak_canvas_release(obs_weak_canvas_t *); + +using OBSCanvas = + OBSSafeRef; +using OBSWeakCanvas = OBSRef; +using OBSCanvasAutoRelease = + OBSRefAutoRelease; +using OBSWeakCanvasAutoRelease = + OBSRefAutoRelease; + +EXPORT obs_weak_canvas_t *obs_canvas_get_weak_canvas(obs_canvas_t *); +EXPORT obs_canvas_t *obs_weak_canvas_get_canvas(obs_weak_canvas_t *); +EXPORT void obs_canvas_enum_scenes(obs_canvas_t *, + bool (*enum_proc)(void *, obs_source_t *), + void *param); +EXPORT OBSCanvas OBSGetStrongRef(obs_weak_canvas_t *); +EXPORT OBSWeakCanvas OBSGetWeakRef(obs_canvas_t *); +EXPORT obs_canvas_t *obs_get_main_canvas(); + +#endif + +EXPORT int GetCanvasCount(); +EXPORT OBSWeakCanvas GetWeakCanvasByName(const char *name); +EXPORT std::string GetWeakCanvasName(const OBSWeakCanvas &canvas); +EXPORT bool IsMainCanvas(obs_weak_canvas_t *canvas); +EXPORT OBSWeakSource GetActiveCanvasScene(const OBSWeakCanvas &canvas); +EXPORT OBSWeakSource GetSceneAtIndex(const OBSWeakCanvas &weakCanvas, int idx); +EXPORT int GetIndexOfScene(const OBSWeakCanvas &weakCanvas, + const OBSWeakSource &scene); + +class CanvasSelection : public FilterComboBox { + Q_OBJECT + +public: + EXPORT CanvasSelection(QWidget *parent); + EXPORT void SetCanvas(const OBSWeakCanvas &); + EXPORT OBSWeakCanvas GetCanvas(); + +signals: + void CanvasChanged(const OBSWeakCanvas &); + +private: + void Populate(); +}; + +} // namespace advss diff --git a/lib/utils/scene-selection.cpp b/lib/utils/scene-selection.cpp index 1f45589d..2765ec90 100644 --- a/lib/utils/scene-selection.cpp +++ b/lib/utils/scene-selection.cpp @@ -10,15 +10,18 @@ #include +#include + namespace advss { constexpr std::string_view typeSaveName = "type"; constexpr std::string_view nameSaveName = "name"; constexpr std::string_view selectionSaveName = "sceneSelection"; +constexpr std::string_view canvasSaveName = "canvasSelection"; void SceneSelection::Save(obs_data_t *obj) const { - auto data = obs_data_create(); + OBSDataAutoRelease data = obs_data_create(); obs_data_set_int(data, typeSaveName.data(), static_cast(_type)); switch (_type) { case Type::SCENE: @@ -41,8 +44,31 @@ void SceneSelection::Save(obs_data_t *obj) const default: break; } + obs_data_set_string(data, canvasSaveName.data(), + GetWeakCanvasName(_canvas).c_str()); obs_data_set_obj(obj, selectionSaveName.data(), data); - obs_data_release(data); +} + +static OBSWeakSource getWeakSceneSourceByName(const OBSWeakCanvas &weakCanvas, + const char *name) +{ +#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0) + return GetWeakSourceByName(name); +#else + if (!weakCanvas) { + return nullptr; + } + + OBSCanvasAutoRelease canvas = obs_weak_canvas_get_canvas(weakCanvas); + if (!canvas) { + return nullptr; + } + + OBSSourceAutoRelease source = + obs_canvas_get_source_by_name(canvas, name); + OBSWeakSource scene = OBSGetWeakRef(source); + return scene; +#endif } void SceneSelection::Load(obs_data_t *obj, const char *name, @@ -51,10 +77,15 @@ void SceneSelection::Load(obs_data_t *obj, const char *name, // TODO: Remove in future version if (!obs_data_has_user_value(obj, selectionSaveName.data())) { _type = static_cast(obs_data_get_int(obj, typeName)); + + OBSCanvasAutoRelease mainCanvas = obs_get_main_canvas(); + _canvas = obs_canvas_get_weak_canvas(mainCanvas); + obs_weak_canvas_release(_canvas); + auto targetName = obs_data_get_string(obj, name); switch (_type) { case Type::SCENE: - _scene = GetWeakSourceByName(targetName); + _scene = getWeakSceneSourceByName(_canvas, targetName); break; case Type::GROUP: _group = GetSceneGroupByName(targetName); @@ -69,12 +100,23 @@ void SceneSelection::Load(obs_data_t *obj, const char *name, return; } - auto data = obs_data_get_obj(obj, selectionSaveName.data()); + OBSDataAutoRelease data = + obs_data_get_obj(obj, selectionSaveName.data()); + + if (obs_data_has_user_value(data, canvasSaveName.data())) { + _canvas = GetWeakCanvasByName( + obs_data_get_string(data, canvasSaveName.data())); + } else { + OBSCanvasAutoRelease mainCanvas = obs_get_main_canvas(); + _canvas = obs_canvas_get_weak_canvas(mainCanvas); + obs_weak_canvas_release(_canvas); + } + _type = static_cast(obs_data_get_int(data, typeSaveName.data())); auto targetName = obs_data_get_string(data, nameSaveName.data()); switch (_type) { case Type::SCENE: - _scene = GetWeakSourceByName(targetName); + _scene = getWeakSceneSourceByName(_canvas, targetName); break; case Type::GROUP: _group = GetSceneGroupByName(targetName); @@ -91,15 +133,18 @@ void SceneSelection::Load(obs_data_t *obj, const char *name, default: break; } - obs_data_release(data); } -static bool IsScene(const OBSWeakSource &source) +static bool isScene(const OBSWeakSource &source) { - auto s = obs_weak_source_get_source(source); - bool ret = !!obs_scene_from_source(s); - obs_source_release(s); - return ret; + OBSSourceAutoRelease s = obs_weak_source_get_source(source); + return !!obs_scene_from_source(s); +} + +void SceneSelection::SetScene(const OBSWeakSource &scene) +{ + _type = Type::SCENE; + _scene = scene; } OBSWeakSource SceneSelection::GetScene(bool advance) const @@ -116,23 +161,30 @@ OBSWeakSource SceneSelection::GetScene(bool advance) const } return _group->getCurrentScene(); case Type::PREVIOUS: + if (!IsMainCanvas(_canvas)) { + return nullptr; + } return GetPreviousScene(); case Type::CURRENT: - return GetCurrentScene(); + if (IsMainCanvas(_canvas)) { + return GetCurrentScene(); + } else { + return GetActiveCanvasScene(_canvas); + } case Type::PREVIEW: { - auto s = obs_frontend_get_current_preview_scene(); - auto scene = obs_source_get_weak_source(s); - obs_weak_source_release(scene); - obs_source_release(s); - return scene; + OBSSourceAutoRelease s = + obs_frontend_get_current_preview_scene(); + OBSWeakSourceAutoRelease scene = obs_source_get_weak_source(s); + return scene.Get(); } case Type::VARIABLE: { auto var = _variable.lock(); if (!var) { return nullptr; } - auto scene = GetWeakSourceByName(var->Value().c_str()); - if (IsScene(scene)) { + auto scene = + getWeakSceneSourceByName(_canvas, var->Value().c_str()); + if (isScene(scene)) { return scene; } return nullptr; @@ -190,8 +242,23 @@ void SceneSelection::ResolveVariables() SceneSelection SceneSelectionWidget::CurrentSelection() { SceneSelection s; - const int idx = currentIndex(); - const auto name = currentText(); + + static auto mainCanvas = obs_get_main_canvas(); + static auto mainCanvasWeak = obs_canvas_get_weak_canvas(mainCanvas); + [[maybe_unused]] static const bool _ = []() { + // Let's just hope we don't have to deal with selecting scenes + // when the OBS main canvas gets deleted and release the + // references here already to avoid reporting leaks on shutdown + obs_canvas_release(mainCanvas); + obs_weak_canvas_release(mainCanvasWeak); + return true; + }(); + + s._canvas = _forceMainCanvas ? OBSWeakCanvas(mainCanvasWeak) + : _canvas->GetCanvas(); + + const int idx = _scenes->currentIndex(); + const auto name = _scenes->currentText(); if (idx == -1 || name.isEmpty()) { return s; } @@ -214,7 +281,8 @@ SceneSelection SceneSelectionWidget::CurrentSelection() s._group = GetSceneGroupByQString(name); } else if (idx < _scenesEndIdx) { s._type = SceneSelection::Type::SCENE; - s._scene = GetWeakSourceByQString(name); + s._scene = getWeakSceneSourceByName(s._canvas, + name.toStdString().c_str()); } return s; } @@ -234,20 +302,6 @@ static QStringList getOrderList(bool current, bool previous, bool preview) return list; } -static QStringList getScenesList() -{ - QStringList list; - char **scenes = obs_frontend_get_scene_names(); - char **temp = scenes; - while (*temp) { - const char *name = *temp; - list << name; - temp++; - } - bfree(scenes); - return list; -} - static QStringList getSceneGroupsList() { QStringList list; @@ -258,72 +312,108 @@ static QStringList getSceneGroupsList() return list; } +static QStringList getCanvasScenesList(obs_weak_canvas_t *weakCanvas) +{ +#if LIBOBS_API_VER >= MAKE_SEMANTIC_VERSION(31, 1, 0) + if (!weakCanvas) { + return {}; + } +#endif + + OBSCanvasAutoRelease canvas = obs_weak_canvas_get_canvas(weakCanvas); + static const auto enumCanvasScenes = [](void *listPtr, + obs_source_t *source) -> bool { + auto list = static_cast(listPtr); + *list << obs_source_get_name(source); + return true; + }; + + QStringList list; + obs_canvas_enum_scenes(canvas, enumCanvasScenes, &list); + return list; +} + void SceneSelectionWidget::Reset() { auto previousSel = _currentSelection; - PopulateSelection(); + PopulateSceneSelection(_currentSelection._canvas); SetScene(previousSel); } -void SceneSelectionWidget::PopulateSelection() +void SceneSelectionWidget::PopulateSceneSelection(obs_weak_canvas_t *canvas) { - clear(); - if (_current || _previous) { - const QStringList order = - getOrderList(_current, _previous, _preview); - AddSelectionGroup(this, order); + _scenes->clear(); + if ((_current || _previous)) { + const bool isMain = IsMainCanvas(canvas); + const QStringList order = getOrderList( + _current, _previous && isMain, _preview && isMain); + AddSelectionGroup(_scenes, order); } - _placeholderEndIdx = count(); + _placeholderEndIdx = _scenes->count(); if (_variables) { const QStringList variables = GetVariablesNameList(); - AddSelectionGroup(this, variables); + AddSelectionGroup(_scenes, variables); } - _variablesEndIdx = count(); + _variablesEndIdx = _scenes->count(); if (_sceneGroups) { const QStringList sceneGroups = getSceneGroupsList(); - AddSelectionGroup(this, sceneGroups); + AddSelectionGroup(_scenes, sceneGroups); } - _groupsEndIdx = count(); + _groupsEndIdx = _scenes->count(); - const QStringList scenes = getScenesList(); - AddSelectionGroup(this, scenes); - _scenesEndIdx = count(); + const QStringList scenes = getCanvasScenesList(canvas); + AddSelectionGroup(_scenes, scenes); + _scenesEndIdx = _scenes->count(); // Remove last separator - removeItem(count() - 1); - setCurrentIndex(-1); + _scenes->removeItem(_scenes->count() - 1); + _scenes->setCurrentIndex(-1); + + _isPopulated = true; + + Resize(); } SceneSelectionWidget::SceneSelectionWidget(QWidget *parent, bool variables, bool sceneGroups, bool previous, bool current, bool preview) - : FilterComboBox(parent, - obs_module_text("AdvSceneSwitcher.selectScene")), + : QWidget(parent), + _scenes(new FilterComboBox( + this, obs_module_text("AdvSceneSwitcher.selectScene"))), + _canvas(new CanvasSelection(this)), _current(current), _previous(previous), _preview(preview), _variables(variables), _sceneGroups(sceneGroups) { - setDuplicatesEnabled(true); - PopulateSelection(); + _scenes->setSizeAdjustPolicy(QComboBox::AdjustToContents); + _scenes->setDuplicatesEnabled(true); - QWidget::connect(this, SIGNAL(currentIndexChanged(int)), this, + QWidget::connect(_scenes, SIGNAL(currentIndexChanged(int)), this, SLOT(SelectionChanged(int))); + QWidget::connect(_canvas, SIGNAL(CanvasChanged(const OBSWeakCanvas &)), + this, SLOT(CanvasChangedSlot(const OBSWeakCanvas &))); + QWidget::connect(_canvas, SIGNAL(CanvasChanged(const OBSWeakCanvas &)), + this, SIGNAL(CanvasChanged(const OBSWeakCanvas &))); - // Scene groups - QWidget::connect(GetSettingsWindow(), - SIGNAL(SceneGroupAdded(const QString &)), this, - SLOT(ItemAdd(const QString &))); - QWidget::connect(GetSettingsWindow(), - SIGNAL(SceneGroupRemoved(const QString &)), this, - SLOT(ItemRemove(const QString &))); - QWidget::connect( - GetSettingsWindow(), - SIGNAL(SceneGroupRenamed(const QString &, const QString &)), - this, SLOT(ItemRename(const QString &, const QString &))); + auto settingsWindow = GetSettingsWindow(); + if (settingsWindow) { + QWidget::connect(settingsWindow, + SIGNAL(SceneGroupAdded(const QString &)), this, + SLOT(ItemAdd(const QString &))); + QWidget::connect(settingsWindow, + SIGNAL(SceneGroupRemoved(const QString &)), + this, SLOT(ItemRemove(const QString &))); + QWidget::connect( + settingsWindow, + SIGNAL(SceneGroupRenamed(const QString &, + const QString &)), + this, + SLOT(ItemRename(const QString &, const QString &))); + } // Variables QWidget::connect(VariableSignalManager::Instance(), @@ -335,19 +425,37 @@ SceneSelectionWidget::SceneSelectionWidget(QWidget *parent, bool variables, QWidget::connect(VariableSignalManager::Instance(), SIGNAL(Rename(const QString &, const QString &)), this, SLOT(ItemRename(const QString &, const QString &))); + + auto layout = new QHBoxLayout(); + layout->addWidget(_canvas); + layout->addWidget(_scenes); + setLayout(layout); + setContentsMargins(0, 0, 0, 0); + layout->setContentsMargins(0, 0, 0, 0); + + if (GetCanvasCount() <= 1) { + _canvas->hide(); + } + + Resize(); } void SceneSelectionWidget::SetScene(const SceneSelection &s) { int idx = -1; + _canvas->SetCanvas(s._canvas); + if (!_isPopulated) { + PopulateSceneSelection(s._canvas); + } + switch (s.GetType()) { case SceneSelection::Type::SCENE: { if (_scenesEndIdx == -1) { idx = -1; break; } - idx = FindIdxInRagne(this, _groupsEndIdx, _scenesEndIdx, + idx = FindIdxInRagne(_scenes, _groupsEndIdx, _scenesEndIdx, s.ToString()); break; } @@ -356,7 +464,7 @@ void SceneSelectionWidget::SetScene(const SceneSelection &s) idx = -1; break; } - idx = FindIdxInRagne(this, _variablesEndIdx, _groupsEndIdx, + idx = FindIdxInRagne(_scenes, _variablesEndIdx, _groupsEndIdx, s.ToString()); break; } @@ -367,7 +475,7 @@ void SceneSelectionWidget::SetScene(const SceneSelection &s) } idx = FindIdxInRagne( - this, _selectIdx, _placeholderEndIdx, + _scenes, _selectIdx, _placeholderEndIdx, obs_module_text( "AdvSceneSwitcher.selectPreviousScene")); break; @@ -379,7 +487,7 @@ void SceneSelectionWidget::SetScene(const SceneSelection &s) } idx = FindIdxInRagne( - this, _selectIdx, _placeholderEndIdx, + _scenes, _selectIdx, _placeholderEndIdx, obs_module_text("AdvSceneSwitcher.selectCurrentScene")); break; } @@ -390,7 +498,7 @@ void SceneSelectionWidget::SetScene(const SceneSelection &s) } idx = FindIdxInRagne( - this, _selectIdx, _placeholderEndIdx, + _scenes, _selectIdx, _placeholderEndIdx, obs_module_text("AdvSceneSwitcher.selectPreviewScene")); break; } @@ -399,22 +507,31 @@ void SceneSelectionWidget::SetScene(const SceneSelection &s) idx = -1; break; } - idx = FindIdxInRagne(this, _placeholderEndIdx, _variablesEndIdx, - s.ToString()); + idx = FindIdxInRagne(_scenes, _placeholderEndIdx, + _variablesEndIdx, s.ToString()); break; default: idx = -1; break; } } - setCurrentIndex(idx); + _scenes->setCurrentIndex(idx); _currentSelection = s; + + Resize(); +} + +void SceneSelectionWidget::LockToMainCanvas() +{ + _forceMainCanvas = true; + _canvas->hide(); } void SceneSelectionWidget::showEvent(QShowEvent *event) { - FilterComboBox::showEvent(event); - const QSignalBlocker b(this); + QWidget::showEvent(event); + const QSignalBlocker b1(_scenes); + const QSignalBlocker b2(_canvas); Reset(); } @@ -442,9 +559,16 @@ void SceneSelectionWidget::SelectionChanged(int) emit SceneChanged(_currentSelection); } +void SceneSelectionWidget::CanvasChangedSlot(const OBSWeakCanvas &) +{ + _currentSelection = CurrentSelection(); + Reset(); +} + void SceneSelectionWidget::ItemAdd(const QString &) { - const QSignalBlocker b(this); + const QSignalBlocker b1(_scenes); + const QSignalBlocker b2(_canvas); Reset(); } @@ -456,7 +580,7 @@ bool SceneSelectionWidget::NameUsed(const QString &name) return true; } return _currentSelection._type == SceneSelection::Type::VARIABLE && - currentText() == name; + _scenes->currentText() == name; } void SceneSelectionWidget::ItemRemove(const QString &name) @@ -470,8 +594,19 @@ void SceneSelectionWidget::ItemRemove(const QString &name) void SceneSelectionWidget::ItemRename(const QString &, const QString &) { - const QSignalBlocker b(this); + const QSignalBlocker b1(_scenes); + const QSignalBlocker b2(_canvas); Reset(); } +void SceneSelectionWidget::Resize() +{ + _scenes->adjustSize(); + _scenes->updateGeometry(); + _canvas->adjustSize(); + _canvas->updateGeometry(); + adjustSize(); + updateGeometry(); +} + } // namespace advss diff --git a/lib/utils/scene-selection.hpp b/lib/utils/scene-selection.hpp index e40ce6eb..ee797540 100644 --- a/lib/utils/scene-selection.hpp +++ b/lib/utils/scene-selection.hpp @@ -1,7 +1,5 @@ #pragma once -#include "filter-combo-box.hpp" - -#include +#include "canvas-helpers.hpp" namespace advss { @@ -24,19 +22,22 @@ public: }; EXPORT Type GetType() const { return _type; } + EXPORT void SetScene(const OBSWeakSource &scene); EXPORT OBSWeakSource GetScene(bool advance = true) const; + EXPORT OBSWeakCanvas GetCanvas() const { return _canvas; }; EXPORT std::string ToString(bool resolve = false) const; EXPORT void ResolveVariables(); private: OBSWeakSource _scene; + OBSWeakCanvas _canvas; SceneGroup *_group = nullptr; std::weak_ptr _variable; Type _type = Type::SCENE; friend class SceneSelectionWidget; }; -class SceneSelectionWidget : public FilterComboBox { +class SceneSelectionWidget : public QWidget { Q_OBJECT public: @@ -45,15 +46,18 @@ public: bool previous = false, bool current = false, bool preview = false); EXPORT void SetScene(const SceneSelection &); + void LockToMainCanvas(); protected: void showEvent(QShowEvent *event) override; signals: void SceneChanged(const SceneSelection &); + void CanvasChanged(const OBSWeakCanvas &); private slots: EXPORT void SelectionChanged(int); + EXPORT void CanvasChangedSlot(const OBSWeakCanvas &); EXPORT void ItemAdd(const QString &name); EXPORT void ItemRemove(const QString &name); EXPORT void ItemRename(const QString &oldName, const QString &newName); @@ -61,11 +65,15 @@ private slots: private: void Reset(); SceneSelection CurrentSelection(); - void PopulateSelection(); + void PopulateSceneSelection(obs_weak_canvas_t *canvas); bool IsCurrentSceneSelected(const QString &name); bool IsPreviousSceneSelected(const QString &name); bool IsPreviewSceneSelected(const QString &name); bool NameUsed(const QString &name); + void Resize(); + + FilterComboBox *_scenes; + CanvasSelection *_canvas; bool _current; bool _previous; @@ -73,7 +81,10 @@ private: bool _variables; bool _sceneGroups; + bool _forceMainCanvas = false; + SceneSelection _currentSelection; + bool _isPopulated = false; // Order of entries // 1. "select entry" entry