From 368185019eadbca3a0f297861687ba8045fb6de7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dennis=20S=C3=A4dtler?= Date: Mon, 27 Jan 2025 03:07:37 +0100 Subject: [PATCH] frontend: Add support loading/saving additional canvases --- frontend/cmake/ui-widgets.cmake | 1 + frontend/widgets/OBSBasic.cpp | 3 +- frontend/widgets/OBSBasic.hpp | 18 +++++++ frontend/widgets/OBSBasic_Canvases.cpp | 47 +++++++++++++++++++ .../widgets/OBSBasic_SceneCollections.cpp | 18 ++++++- 5 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 frontend/widgets/OBSBasic_Canvases.cpp diff --git a/frontend/cmake/ui-widgets.cmake b/frontend/cmake/ui-widgets.cmake index 20befdeb0..4eeec3940 100644 --- a/frontend/cmake/ui-widgets.cmake +++ b/frontend/cmake/ui-widgets.cmake @@ -15,6 +15,7 @@ target_sources( widgets/OBSBasic.cpp widgets/OBSBasic.hpp widgets/OBSBasic_Browser.cpp + widgets/OBSBasic_Canvases.cpp widgets/OBSBasic_Clipboard.cpp widgets/OBSBasic_ContextToolbar.cpp widgets/OBSBasic_Docks.cpp diff --git a/frontend/widgets/OBSBasic.cpp b/frontend/widgets/OBSBasic.cpp index 072e2b235..e56b7e277 100644 --- a/frontend/widgets/OBSBasic.cpp +++ b/frontend/widgets/OBSBasic.cpp @@ -842,7 +842,7 @@ void OBSBasic::InitOBSCallbacks() { ProfileScope("OBSBasic::InitOBSCallbacks"); - signalHandlers.reserve(signalHandlers.size() + 9); + signalHandlers.reserve(signalHandlers.size() + 10); signalHandlers.emplace_back(obs_get_signal_handler(), "source_create", OBSBasic::SourceCreated, this); signalHandlers.emplace_back(obs_get_signal_handler(), "source_remove", OBSBasic::SourceRemoved, this); signalHandlers.emplace_back(obs_get_signal_handler(), "source_activate", OBSBasic::SourceActivated, this); @@ -866,6 +866,7 @@ void OBSBasic::InitOBSCallbacks() Qt::QueuedConnection); }, this); + signalHandlers.emplace_back(obs_get_signal_handler(), "canvas_remove", OBSBasic::CanvasRemoved, this); } #define STARTUP_SEPARATOR "==== Startup complete ===============================================" diff --git a/frontend/widgets/OBSBasic.hpp b/frontend/widgets/OBSBasic.hpp index 244eaae54..1cfe14f1a 100644 --- a/frontend/widgets/OBSBasic.hpp +++ b/frontend/widgets/OBSBasic.hpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -1108,6 +1109,23 @@ public: std::optional GetSceneCollectionByName(const std::string &collectionName) const; std::optional GetSceneCollectionByFileName(const std::string &fileName) const; + /* ------------------------------------- + * MARK: - OBSBasic_Canvases + * ------------------------------------- + */ +private: + std::vector canvases; + + static void CanvasRemoved(void *data, calldata_t *params); + +public: + const std::vector &GetCanvases() const noexcept { return canvases; } + + const OBS::Canvas &AddCanvas(const std::string &name, obs_video_info *ovi = nullptr, int flags = 0); + +public slots: + bool RemoveCanvas(obs_canvas_t *canvas); + /* ------------------------------------- * MARK: - OBSBasic_SceneItems * ------------------------------------- diff --git a/frontend/widgets/OBSBasic_Canvases.cpp b/frontend/widgets/OBSBasic_Canvases.cpp new file mode 100644 index 000000000..35e25afec --- /dev/null +++ b/frontend/widgets/OBSBasic_Canvases.cpp @@ -0,0 +1,47 @@ +/****************************************************************************** + Copyright (C) 2025 by Dennis Sädtler + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +******************************************************************************/ + +#include "OBSBasic.hpp" + +void OBSBasic::CanvasRemoved(void *data, calldata_t *params) +{ + obs_canvas_t *canvas = static_cast(calldata_ptr(params, "canvas")); + QMetaObject::invokeMethod(static_cast(data), "RemoveCanvas", Q_ARG(OBSCanvas, OBSCanvas(canvas))); +} + +const OBS::Canvas &OBSBasic::AddCanvas(const std::string &name, obs_video_info *ovi, int flags) +{ + OBSCanvas canvas = obs_canvas_create(name.c_str(), ovi, flags); + auto &it = canvases.emplace_back(canvas); + OnEvent(OBS_FRONTEND_EVENT_CANVAS_ADDED); + return it; +} + +bool OBSBasic::RemoveCanvas(obs_canvas_t *canvas) +{ + if (!canvas) + return false; + + auto canvas_it = std::find(std::begin(canvases), std::end(canvases), canvas); + if (canvas_it != std::end(canvases)) { + canvases.erase(canvas_it); + OnEvent(OBS_FRONTEND_EVENT_CANVAS_REMOVED); + return true; + } + + return false; +} diff --git a/frontend/widgets/OBSBasic_SceneCollections.cpp b/frontend/widgets/OBSBasic_SceneCollections.cpp index 228cf8652..b637c861d 100644 --- a/frontend/widgets/OBSBasic_SceneCollections.cpp +++ b/frontend/widgets/OBSBasic_SceneCollections.cpp @@ -808,7 +808,8 @@ static void SaveAudioDevice(const char *name, int channel, obs_data_t *parent, v static obs_data_t *GenerateSaveData(obs_data_array_t *sceneOrder, obs_data_array_t *quickTransitionData, int transitionDuration, obs_data_array_t *transitions, OBSScene &scene, - OBSSource &curProgramScene, obs_data_array_t *savedProjectorList) + OBSSource &curProgramScene, obs_data_array_t *savedProjectorList, + obs_data_array_t *savedCanvases) { obs_data_t *saveData = obs_data_create(); @@ -865,6 +866,7 @@ static obs_data_t *GenerateSaveData(obs_data_array_t *sceneOrder, obs_data_array obs_data_set_array(saveData, "quick_transitions", quickTransitionData); obs_data_set_array(saveData, "transitions", transitions); obs_data_set_array(saveData, "saved_projectors", savedProjectorList); + obs_data_set_array(saveData, "canvases", savedCanvases); obs_data_array_release(sourcesArray); obs_data_array_release(groupsArray); @@ -885,8 +887,10 @@ void OBSBasic::Save(SceneCollection &collection) OBSDataArrayAutoRelease transitions = SaveTransitions(); OBSDataArrayAutoRelease quickTrData = SaveQuickTransitions(); OBSDataArrayAutoRelease savedProjectorList = SaveProjectors(); + OBSDataArrayAutoRelease savedCanvases = OBS::Canvas::SaveCanvases(canvases); OBSDataAutoRelease saveData = GenerateSaveData(sceneOrder, quickTrData, ui->transitionDuration->value(), - transitions, scene, curProgramScene, savedProjectorList); + transitions, scene, curProgramScene, savedProjectorList, + savedCanvases); obs_data_set_bool(saveData, "preview_locked", ui->preview->Locked()); obs_data_set_bool(saveData, "scaling_enabled", ui->preview->IsFixedScaling()); @@ -1171,6 +1175,7 @@ void OBSBasic::LoadData(obs_data_t *data, SceneCollection &collection) OBSDataArrayAutoRelease sources = obs_data_get_array(data, "sources"); OBSDataArrayAutoRelease groups = obs_data_get_array(data, "groups"); OBSDataArrayAutoRelease transitions = obs_data_get_array(data, "transitions"); + OBSDataArrayAutoRelease collection_canvases = obs_data_get_array(data, "canvases"); const char *sceneName = obs_data_get_string(data, "current_scene"); const char *programSceneName = obs_data_get_string(data, "current_program_scene"); const char *transitionName = obs_data_get_string(data, "current_transition"); @@ -1207,6 +1212,9 @@ void OBSBasic::LoadData(obs_data_t *data, SceneCollection &collection) LoadAudioDevice(AUX_AUDIO_3, 5, data); LoadAudioDevice(AUX_AUDIO_4, 6, data); + if (collection_canvases) + canvases = OBS::Canvas::LoadCanvases(collection_canvases); + if (!sources) { sources = std::move(groups); } else { @@ -1525,6 +1533,12 @@ void OBSBasic::ClearSceneData() obs_enum_scenes(cb, nullptr); obs_enum_sources(cb, nullptr); + for (const auto &canvas : canvases) { + obs_canvas_enum_scenes(canvas, cb, nullptr); + } + + canvases.clear(); + OnEvent(OBS_FRONTEND_EVENT_SCENE_COLLECTION_CLEANUP); undo_s.clear();