Compare commits

..

4 Commits

Author SHA1 Message Date
WarmUpTill
e1020a1909 Fix poad load steps being executed too frequently
Some checks failed
debian-build / build (push) Has been cancelled
Push to master / Check Formatting 🔍 (push) Has been cancelled
Push to master / Build Project 🧱 (push) Has been cancelled
Push to master / Create Release 🛫 (push) Has been cancelled
2025-10-30 20:48:33 +01:00
WarmUpTill
8b0bd4193b Fix temp var save / loading not working 2025-10-30 20:48:33 +01:00
WarmUpTill
d55bb6bc86 Fall back to obs_frontend_get_current_scene()
Some checks failed
debian-build / build (push) Has been cancelled
Push to master / Check Formatting 🔍 (push) Has been cancelled
Push to master / Build Project 🧱 (push) Has been cancelled
Push to master / Create Release 🛫 (push) Has been cancelled
If there wasn't any scene change yet GetCurrentScene() would always
return nullptr and break various scene checks.
For example, this could happen when startup up a fresh OBS install for
the first time.
2025-10-29 12:26:44 +01:00
WarmUpTill
0583331bfd Fix scene selection not working without secondary canvases 2025-10-29 12:26:44 +01:00
21 changed files with 82 additions and 226 deletions

View File

@@ -495,7 +495,7 @@ AdvSceneSwitcher.action.file.type.write="Schreiben"
AdvSceneSwitcher.action.file.type.append="Anhängen" AdvSceneSwitcher.action.file.type.append="Anhängen"
AdvSceneSwitcher.action.file.entry="{{actions}} in {{filePath}}:" AdvSceneSwitcher.action.file.entry="{{actions}} in {{filePath}}:"
AdvSceneSwitcher.action.studioMode="Studio-Modus" AdvSceneSwitcher.action.studioMode="Studio-Modus"
AdvSceneSwitcher.action.studioMode.type.transitionWithSwap="Vorschau- und Programm-Szene tauschen" AdvSceneSwitcher.action.studioMode.type.swap="Vorschau- und Programm-Szene tauschen"
AdvSceneSwitcher.action.studioMode.type.setScene="Vorschau-Szene einstellen auf" AdvSceneSwitcher.action.studioMode.type.setScene="Vorschau-Szene einstellen auf"
AdvSceneSwitcher.action.studioMode.type.enable="Studio-Modus aktivieren" AdvSceneSwitcher.action.studioMode.type.enable="Studio-Modus aktivieren"
AdvSceneSwitcher.action.studioMode.type.disable="Studio-Modus deaktivieren" AdvSceneSwitcher.action.studioMode.type.disable="Studio-Modus deaktivieren"

View File

@@ -1055,17 +1055,7 @@ AdvSceneSwitcher.action.file.type.write="Write"
AdvSceneSwitcher.action.file.type.append="Append" AdvSceneSwitcher.action.file.type.append="Append"
AdvSceneSwitcher.action.file.entry="{{actions}}to{{filePath}}:" AdvSceneSwitcher.action.file.entry="{{actions}}to{{filePath}}:"
AdvSceneSwitcher.action.studioMode="Studio mode" AdvSceneSwitcher.action.studioMode="Studio mode"
AdvSceneSwitcher.action.studioMode.type.transition="Transition" AdvSceneSwitcher.action.studioMode.type.swap="Swap preview and program scene"
AdvSceneSwitcher.action.studioMode.type.transitionWithSwap="Swap preview and program scene"
AdvSceneSwitcher.action.studioMode.type.transitionSwap.enable="Enable preview/program scene swapping after transition"
AdvSceneSwitcher.action.studioMode.type.transitionSwap.disable="Disable preview/program scene swapping after transition"
AdvSceneSwitcher.action.studioMode.type.transitionSwap.toggle="Toggle preview/program scene swapping after transition"
AdvSceneSwitcher.action.studioMode.type.duplicateScene.enable="Enable scene duplication"
AdvSceneSwitcher.action.studioMode.type.duplicateScene.disable="Disable scene duplication"
AdvSceneSwitcher.action.studioMode.type.duplicateScene.toggle="Toggle scene duplication"
AdvSceneSwitcher.action.studioMode.type.duplicateSource.enable="Enable source duplication"
AdvSceneSwitcher.action.studioMode.type.duplicateSource.disable="Disable source duplication"
AdvSceneSwitcher.action.studioMode.type.duplicateSource.toggle="Toggle source duplication"
AdvSceneSwitcher.action.studioMode.type.setScene="Set preview scene to" AdvSceneSwitcher.action.studioMode.type.setScene="Set preview scene to"
AdvSceneSwitcher.action.studioMode.type.enable="Enable studio mode" AdvSceneSwitcher.action.studioMode.type.enable="Enable studio mode"
AdvSceneSwitcher.action.studioMode.type.disable="Disable studio mode" AdvSceneSwitcher.action.studioMode.type.disable="Disable studio mode"

View File

@@ -413,7 +413,7 @@ AdvSceneSwitcher.action.file.type.write="Escribir"
AdvSceneSwitcher.action.file.type.append="Agregar" AdvSceneSwitcher.action.file.type.append="Agregar"
AdvSceneSwitcher.action.file.entry="{{actions}} a {{filePath}}:" AdvSceneSwitcher.action.file.entry="{{actions}} a {{filePath}}:"
AdvSceneSwitcher.action.studioMode="Modo estudio" AdvSceneSwitcher.action.studioMode="Modo estudio"
AdvSceneSwitcher.action.studioMode.type.transitionWithSwap="Intercambiar vista previa y escena del programa" AdvSceneSwitcher.action.studioMode.type.swap="Intercambiar vista previa y escena del programa"
AdvSceneSwitcher.action.studioMode.type.setScene="Establecer escena de vista previa en" AdvSceneSwitcher.action.studioMode.type.setScene="Establecer escena de vista previa en"
AdvSceneSwitcher.action.studioMode.type.enable="Activar modo estudio" AdvSceneSwitcher.action.studioMode.type.enable="Activar modo estudio"
AdvSceneSwitcher.action.studioMode.type.disable="Deshabilitar el modo de estudio" AdvSceneSwitcher.action.studioMode.type.disable="Deshabilitar el modo de estudio"

View File

@@ -613,7 +613,7 @@ AdvSceneSwitcher.action.file.type.write="Écrire"
AdvSceneSwitcher.action.file.type.append="Ajouter" AdvSceneSwitcher.action.file.type.append="Ajouter"
AdvSceneSwitcher.action.file.entry="{{actions}}vers{{filePath}}:" AdvSceneSwitcher.action.file.entry="{{actions}}vers{{filePath}}:"
AdvSceneSwitcher.action.studioMode="Mode studio" AdvSceneSwitcher.action.studioMode="Mode studio"
AdvSceneSwitcher.action.studioMode.type.transitionWithSwap="Permuter la scène de prévisualisation et la scène du programme" AdvSceneSwitcher.action.studioMode.type.swap="Permuter la scène de prévisualisation et la scène du programme"
AdvSceneSwitcher.action.studioMode.type.setScene="Définir la scène de prévisualisation sur" AdvSceneSwitcher.action.studioMode.type.setScene="Définir la scène de prévisualisation sur"
AdvSceneSwitcher.action.studioMode.type.enable="Activer le mode studio" AdvSceneSwitcher.action.studioMode.type.enable="Activer le mode studio"
AdvSceneSwitcher.action.studioMode.type.disable="Désactiver le mode studio" AdvSceneSwitcher.action.studioMode.type.disable="Désactiver le mode studio"

View File

@@ -1016,7 +1016,7 @@ AdvSceneSwitcher.action.file="ファイル"
; AdvSceneSwitcher.action.file.type.append="Append" ; AdvSceneSwitcher.action.file.type.append="Append"
AdvSceneSwitcher.action.file.entry="{{actions}}から{{filePath}}へ:" AdvSceneSwitcher.action.file.entry="{{actions}}から{{filePath}}へ:"
AdvSceneSwitcher.action.studioMode="スタジオモード" AdvSceneSwitcher.action.studioMode="スタジオモード"
AdvSceneSwitcher.action.studioMode.type.transitionWithSwap="プレビューと番組シーンの入れ替え" AdvSceneSwitcher.action.studioMode.type.swap="プレビューと番組シーンの入れ替え"
AdvSceneSwitcher.action.studioMode.type.setScene="プレビューシーンを設定する" AdvSceneSwitcher.action.studioMode.type.setScene="プレビューシーンを設定する"
AdvSceneSwitcher.action.studioMode.type.enable="スタジオモードを有効にする" AdvSceneSwitcher.action.studioMode.type.enable="スタジオモードを有効にする"
AdvSceneSwitcher.action.studioMode.type.disable="スタジオモードを無効にする" AdvSceneSwitcher.action.studioMode.type.disable="スタジオモードを無効にする"

View File

@@ -923,7 +923,7 @@ AdvSceneSwitcher.action.file.type.write="Escrever"
AdvSceneSwitcher.action.file.type.append="Anexar" AdvSceneSwitcher.action.file.type.append="Anexar"
AdvSceneSwitcher.action.file.entry="{{actions}}para{{filePath}}:" AdvSceneSwitcher.action.file.entry="{{actions}}para{{filePath}}:"
AdvSceneSwitcher.action.studioMode="Modo estúdio" AdvSceneSwitcher.action.studioMode="Modo estúdio"
AdvSceneSwitcher.action.studioMode.type.transitionWithSwap="Trocar cena de visualização e programa" AdvSceneSwitcher.action.studioMode.type.swap="Trocar cena de visualização e programa"
AdvSceneSwitcher.action.studioMode.type.setScene="Definir cena de visualização para" AdvSceneSwitcher.action.studioMode.type.setScene="Definir cena de visualização para"
AdvSceneSwitcher.action.studioMode.type.enable="Habilitar modo estúdio" AdvSceneSwitcher.action.studioMode.type.enable="Habilitar modo estúdio"
AdvSceneSwitcher.action.studioMode.type.disable="Desabilitar modo estúdio" AdvSceneSwitcher.action.studioMode.type.disable="Desabilitar modo estúdio"

View File

@@ -984,7 +984,7 @@ AdvSceneSwitcher.action.file.type.write="覆盖写入"
AdvSceneSwitcher.action.file.type.append="追加写入" AdvSceneSwitcher.action.file.type.append="追加写入"
AdvSceneSwitcher.action.file.entry="{{actions}} 到 {{filePath}}:" AdvSceneSwitcher.action.file.entry="{{actions}} 到 {{filePath}}:"
AdvSceneSwitcher.action.studioMode="工作室模式" AdvSceneSwitcher.action.studioMode="工作室模式"
AdvSceneSwitcher.action.studioMode.type.transitionWithSwap="切换预览和程序场景" AdvSceneSwitcher.action.studioMode.type.swap="切换预览和程序场景"
AdvSceneSwitcher.action.studioMode.type.setScene="将预览场景设置为" AdvSceneSwitcher.action.studioMode.type.setScene="将预览场景设置为"
AdvSceneSwitcher.action.studioMode.type.enable="启用工作室模式" AdvSceneSwitcher.action.studioMode.type.enable="启用工作室模式"
AdvSceneSwitcher.action.studioMode.type.disable="停用工作室模式" AdvSceneSwitcher.action.studioMode.type.disable="停用工作室模式"

View File

@@ -459,7 +459,7 @@ void SwitcherData::LoadSettings(obs_data_t *obj)
LoadHotkeys(obj); LoadHotkeys(obj);
LoadUISettings(obj); LoadUISettings(obj);
RunPostLoadSteps(); RunAndClearPostLoadSteps();
// Reset on startup and scene collection change // Reset on startup and scene collection change
ResetLastOpenedTab(); ResetLastOpenedTab();

View File

@@ -117,7 +117,7 @@ void MacroActionEdit::ActionSelectionChanged(const QString &text)
*_entryData = MacroActionFactory::Create(id, macro); *_entryData = MacroActionFactory::Create(id, macro);
(*_entryData)->SetIndex(idx); (*_entryData)->SetIndex(idx);
(*_entryData)->PostLoad(); (*_entryData)->PostLoad();
RunPostLoadSteps(); RunAndClearPostLoadSteps();
} }
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData); auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)), QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),

View File

@@ -239,7 +239,7 @@ void MacroConditionEdit::ConditionSelectionChanged(const QString &text)
(*_entryData)->SetIndex(idx); (*_entryData)->SetIndex(idx);
(*_entryData)->SetLogicType(logic); (*_entryData)->SetLogicType(logic);
(*_entryData)->PostLoad(); (*_entryData)->PostLoad();
RunPostLoadSteps(); RunAndClearPostLoadSteps();
} }
auto widget = auto widget =
MacroConditionFactory::CreateWidget(id, this, *_entryData); MacroConditionFactory::CreateWidget(id, this, *_entryData);

View File

@@ -1080,7 +1080,7 @@ void MacroEdit::AddMacroAction(Macro *macro, int idx, const std::string &id,
macro->Actions().at(idx)->Load(data); macro->Actions().at(idx)->Load(data);
} }
macro->Actions().at(idx)->PostLoad(); macro->Actions().at(idx)->PostLoad();
RunPostLoadSteps(); RunAndClearPostLoadSteps();
macro->UpdateActionIndices(); macro->UpdateActionIndices();
ui->actionsList->Insert( ui->actionsList->Insert(
idx, idx,
@@ -1383,7 +1383,7 @@ void MacroEdit::AddMacroElseAction(Macro *macro, int idx, const std::string &id,
macro->ElseActions().at(idx)->Load(data); macro->ElseActions().at(idx)->Load(data);
} }
macro->ElseActions().at(idx)->PostLoad(); macro->ElseActions().at(idx)->PostLoad();
RunPostLoadSteps(); RunAndClearPostLoadSteps();
macro->UpdateElseActionIndices(); macro->UpdateElseActionIndices();
ui->elseActionsList->Insert( ui->elseActionsList->Insert(
idx, new MacroActionEdit( idx, new MacroActionEdit(
@@ -1583,7 +1583,7 @@ void MacroEdit::AddMacroCondition(Macro *macro, int idx, const std::string &id,
macro->Conditions().at(idx)->Load(data); macro->Conditions().at(idx)->Load(data);
} }
macro->Conditions().at(idx)->PostLoad(); macro->Conditions().at(idx)->PostLoad();
RunPostLoadSteps(); RunAndClearPostLoadSteps();
(*cond)->SetLogicType(logic); (*cond)->SetLogicType(logic);
macro->UpdateConditionIndices(); macro->UpdateConditionIndices();
ui->conditionsList->Insert( ui->conditionsList->Insert(

View File

@@ -416,7 +416,7 @@ void AdvSceneSwitcher::ImportMacros()
OBSDataAutoRelease array_obj = obs_data_array_item(array, i); OBSDataAutoRelease array_obj = obs_data_array_item(array, i);
auto macro = std::make_shared<Macro>(); auto macro = std::make_shared<Macro>();
macro->Load(array_obj); macro->Load(array_obj);
RunPostLoadSteps(); RunAndClearPostLoadSteps();
if (macroNameExists(macro->Name()) && if (macroNameExists(macro->Name()) &&
!ResolveMacroImportNameConflict(macro)) { !ResolveMacroImportNameConflict(macro)) {
@@ -444,7 +444,7 @@ void AdvSceneSwitcher::ImportMacros()
for (const auto &macro : importedMacros) { for (const auto &macro : importedMacros) {
macro->PostLoad(); macro->PostLoad();
} }
RunPostLoadSteps(); RunAndClearPostLoadSteps();
ui->macros->Reset(GetMacros(), ui->macros->Reset(GetMacros(),
GetGlobalMacroSettings()._highlightExecuted); GetGlobalMacroSettings()._highlightExecuted);
@@ -752,7 +752,7 @@ void AdvSceneSwitcher::CopyMacro()
newMacro->Load(data); newMacro->Load(data);
newMacro->PostLoad(); newMacro->PostLoad();
newMacro->SetName(name); newMacro->SetName(name);
RunPostLoadSteps(); RunAndClearPostLoadSteps();
Macro::PrepareMoveToGroup(macro->Parent(), newMacro); Macro::PrepareMoveToGroup(macro->Parent(), newMacro);
ui->macros->Add(newMacro, macro); ui->macros->Add(newMacro, macro);

View File

@@ -113,7 +113,7 @@ void ActionQueue::Add(const std::shared_ptr<MacroAction> &action)
action->Save(data); action->Save(data);
copy->Load(data); copy->Load(data);
copy->PostLoad(); copy->PostLoad();
RunPostLoadSteps(); RunAndClearPostLoadSteps();
copy->ResolveVariablesToFixedValues(); copy->ResolveVariablesToFixedValues();
_actions.emplace_back(copy); _actions.emplace_back(copy);
} else { } else {

View File

@@ -113,12 +113,13 @@ void RunLoadSteps(obs_data_t *obj)
} }
} }
void RunPostLoadSteps() void RunAndClearPostLoadSteps()
{ {
std::lock_guard<std::mutex> lock(postLoadMutex); std::lock_guard<std::mutex> lock(postLoadMutex);
for (const auto &func : getPostLoadSteps()) { for (const auto &func : getPostLoadSteps()) {
func(); func();
} }
getPostLoadSteps().clear();
} }
void ClearPostLoadSteps() void ClearPostLoadSteps()

View File

@@ -14,7 +14,7 @@ EXPORT void AddPostLoadStep(std::function<void()>);
EXPORT void AddIntervalResetStep(std::function<void()>); EXPORT void AddIntervalResetStep(std::function<void()>);
void RunSaveSteps(obs_data_t *); void RunSaveSteps(obs_data_t *);
void RunLoadSteps(obs_data_t *); void RunLoadSteps(obs_data_t *);
EXPORT void RunPostLoadSteps(); EXPORT void RunAndClearPostLoadSteps();
void ClearPostLoadSteps(); void ClearPostLoadSteps();
EXPORT void AddPluginInitStep(std::function<void()>); EXPORT void AddPluginInitStep(std::function<void()>);

View File

@@ -239,22 +239,26 @@ void SceneSelection::ResolveVariables()
_type = Type::SCENE; _type = Type::SCENE;
} }
SceneSelection SceneSelectionWidget::CurrentSelection() static obs_weak_canvas_t *getWeakRefToMainCanvas()
{ {
SceneSelection s; static auto canvas = obs_get_main_canvas();
static auto weakCanvas = obs_canvas_get_weak_canvas(canvas);
static auto mainCanvas = obs_get_main_canvas();
static auto mainCanvasWeak = obs_canvas_get_weak_canvas(mainCanvas);
[[maybe_unused]] static const bool _ = []() { [[maybe_unused]] static const bool _ = []() {
// Let's just hope we don't have to deal with selecting scenes // Let's just hope we don't have to deal with selecting scenes
// when the OBS main canvas gets deleted and release the // when the OBS main canvas gets deleted and release the
// references here already to avoid reporting leaks on shutdown // references here already to avoid reporting leaks on shutdown
obs_canvas_release(mainCanvas); obs_canvas_release(canvas);
obs_weak_canvas_release(mainCanvasWeak); obs_weak_canvas_release(weakCanvas);
return true; return true;
}(); }();
return weakCanvas;
}
s._canvas = _forceMainCanvas ? OBSWeakCanvas(mainCanvasWeak) SceneSelection SceneSelectionWidget::CurrentSelection()
{
SceneSelection s;
s._canvas = _forceMainCanvas ? OBSWeakCanvas(getWeakRefToMainCanvas())
: _canvas->GetCanvas(); : _canvas->GetCanvas();
const int idx = _scenes->currentIndex(); const int idx = _scenes->currentIndex();
@@ -342,6 +346,10 @@ void SceneSelectionWidget::Reset()
void SceneSelectionWidget::PopulateSceneSelection(obs_weak_canvas_t *canvas) void SceneSelectionWidget::PopulateSceneSelection(obs_weak_canvas_t *canvas)
{ {
if (_forceMainCanvas) {
canvas = getWeakRefToMainCanvas();
}
_scenes->clear(); _scenes->clear();
if ((_current || _previous)) { if ((_current || _previous)) {
const bool isMain = IsMainCanvas(canvas); const bool isMain = IsMainCanvas(canvas);
@@ -418,7 +426,7 @@ SceneSelectionWidget::SceneSelectionWidget(QWidget *parent, bool variables,
layout->setContentsMargins(0, 0, 0, 0); layout->setContentsMargins(0, 0, 0, 0);
if (GetCanvasCount() <= 1) { if (GetCanvasCount() <= 1) {
_canvas->hide(); LockToMainCanvas();
} }
Resize(); Resize();

View File

@@ -199,7 +199,17 @@ std::chrono::high_resolution_clock::time_point GetLastSceneChangeTime()
OBSWeakSource GetCurrentScene() OBSWeakSource GetCurrentScene()
{ {
return switcher->currentScene; if (switcher->currentScene) {
return switcher->currentScene;
}
// If there wasn't any scene switch yet switcher->currentScene will be
// null and we must use obs_frontend_get_current_scene() instead
OBSSourceAutoRelease currentSceneSource =
obs_frontend_get_current_scene();
OBSWeakSourceAutoRelease currentSceneWeakSource =
obs_source_get_weak_source(currentSceneSource);
return currentSceneWeakSource.Get();
} }
OBSWeakSource GetPreviousScene() OBSWeakSource GetPreviousScene()

View File

@@ -202,6 +202,8 @@ static void appendNestedMacros(std::deque<std::shared_ptr<Macro>> &macros,
dynamic_cast<MacroActionMacro *>(action.get()); dynamic_cast<MacroActionMacro *>(action.get());
if (nestedMacroAction) { if (nestedMacroAction) {
macros.push_back(nestedMacroAction->_nestedMacro); macros.push_back(nestedMacroAction->_nestedMacro);
appendNestedMacros(
macros, nestedMacroAction->_nestedMacro.get());
} }
} }
for (const auto &action : macro->ElseActions()) { for (const auto &action : macro->ElseActions()) {
@@ -209,6 +211,8 @@ static void appendNestedMacros(std::deque<std::shared_ptr<Macro>> &macros,
dynamic_cast<MacroActionMacro *>(action.get()); dynamic_cast<MacroActionMacro *>(action.get());
if (nestedMacroAction) { if (nestedMacroAction) {
macros.push_back(nestedMacroAction->_nestedMacro); macros.push_back(nestedMacroAction->_nestedMacro);
appendNestedMacros(
macros, nestedMacroAction->_nestedMacro.get());
} }
} }
} }
@@ -301,8 +305,13 @@ void TempVariableRef::Save(obs_data_t *obj, Macro *macro,
void TempVariableRef::Load(obs_data_t *obj, Macro *macroPtr, const char *name) void TempVariableRef::Load(obs_data_t *obj, Macro *macroPtr, const char *name)
{ {
std::deque<std::shared_ptr<Macro>> allMacros = GetMacros();
for (const auto &topLevelMacro : GetMacros()) {
appendNestedMacros(allMacros, topLevelMacro.get());
}
std::weak_ptr<Macro> macro; std::weak_ptr<Macro> macro;
for (const auto &macroShared : GetMacros()) { for (const auto &macroShared : allMacros) {
if (macroShared.get() == macroPtr) { if (macroShared.get() == macroPtr) {
macro = macroShared; macro = macroShared;
break; break;
@@ -340,7 +349,7 @@ void TempVariableRef::PostLoad(int idx, SegmentType type,
return; return;
} }
Macro *macro = nullptr; auto macro = childMacro.get();
for (int i = 0; i < _depth; i++) { for (int i = 0; i < _depth; i++) {
macro = getParentMacro(childMacro.get()); macro = getParentMacro(childMacro.get());
} }

View File

@@ -75,7 +75,7 @@ private:
void PostLoad(int idx, SegmentType, const std::weak_ptr<Macro> &); void PostLoad(int idx, SegmentType, const std::weak_ptr<Macro> &);
std::string _id = ""; std::string _id = "";
std::weak_ptr<MacroSegment> _segment; std::weak_ptr<MacroSegment> _segment = {};
int _depth = 0; int _depth = 0;
friend TempVariable; friend TempVariable;

View File

@@ -2,7 +2,6 @@
#include "layout-helpers.hpp" #include "layout-helpers.hpp"
#include <obs-frontend-api.h> #include <obs-frontend-api.h>
#include <util/config-file.h>
namespace advss { namespace advss {
@@ -14,64 +13,16 @@ bool MacroActionSudioMode::_registered = MacroActionFactory::Register(
"AdvSceneSwitcher.action.studioMode"}); "AdvSceneSwitcher.action.studioMode"});
const static std::map<MacroActionSudioMode::Action, std::string> actionTypes = { const static std::map<MacroActionSudioMode::Action, std::string> actionTypes = {
{MacroActionSudioMode::Action::TRANSITION, {MacroActionSudioMode::Action::SWAP_SCENE,
"AdvSceneSwitcher.action.studioMode.type.transition"}, "AdvSceneSwitcher.action.studioMode.type.swap"},
{MacroActionSudioMode::Action::TRANSITION_WITH_SWAP, {MacroActionSudioMode::Action::SET_SCENE,
"AdvSceneSwitcher.action.studioMode.type.transitionWithSwap"}, "AdvSceneSwitcher.action.studioMode.type.setScene"},
{MacroActionSudioMode::Action::ENALBE_TRANSITION_SWAP,
"AdvSceneSwitcher.action.studioMode.type.transitionSwap.enable"},
{MacroActionSudioMode::Action::DISABLE_TRANSITION_SWAP,
"AdvSceneSwitcher.action.studioMode.type.transitionSwap.disable"},
{MacroActionSudioMode::Action::TOGGLE_TRANSITION_SWAP,
"AdvSceneSwitcher.action.studioMode.type.transitionSwap.toggle"},
{MacroActionSudioMode::Action::ENALBE_DUPLICATE_SCENE,
"AdvSceneSwitcher.action.studioMode.type.duplicateScene.enable"},
{MacroActionSudioMode::Action::DISABLE_DUPLICATE_SCENE,
"AdvSceneSwitcher.action.studioMode.type.duplicateScene.disable"},
{MacroActionSudioMode::Action::TOGGLE_DUPLICATE_SCENE,
"AdvSceneSwitcher.action.studioMode.type.duplicateScene.toggle"},
{MacroActionSudioMode::Action::ENALBE_DUPLICATE_SOURCE,
"AdvSceneSwitcher.action.studioMode.type.duplicateSource.enable"},
{MacroActionSudioMode::Action::DISABLE_DUPLICATE_SOURCE,
"AdvSceneSwitcher.action.studioMode.type.duplicateSource.disable"},
{MacroActionSudioMode::Action::TOGGLE_DUPLICATE_SOURCE,
"AdvSceneSwitcher.action.studioMode.type.duplicateSource.toggle"},
{MacroActionSudioMode::Action::ENABLE_STUDIO_MODE, {MacroActionSudioMode::Action::ENABLE_STUDIO_MODE,
"AdvSceneSwitcher.action.studioMode.type.enable"}, "AdvSceneSwitcher.action.studioMode.type.enable"},
{MacroActionSudioMode::Action::DISABLE_STUDIO_MODE, {MacroActionSudioMode::Action::DISABLE_STUDIO_MODE,
"AdvSceneSwitcher.action.studioMode.type.disable"}, "AdvSceneSwitcher.action.studioMode.type.disable"},
{MacroActionSudioMode::Action::TOGGLE_STUDIO_MODE,
"AdvSceneSwitcher.action.studioMode.type.toggle"},
{MacroActionSudioMode::Action::SET_SCENE,
"AdvSceneSwitcher.action.studioMode.type.setScene"},
}; };
template<typename Func, typename... Args>
static void setConfigValueHelper(Func func, Args... args)
{
auto config = obs_frontend_get_user_config();
func(config, args...);
if (config_save(config) != CONFIG_SUCCESS) {
blog(LOG_WARNING, "failed to save user config!");
}
}
template<typename Func, typename... Args>
static auto getConfigValueHelper(Func func, Func defaultFunc, Args... args)
-> std::optional<std::invoke_result_t<Func, config_t *, Args...>>
{
using Ret = std::invoke_result_t<Func, config_t *, Args...>;
auto config = obs_frontend_get_user_config();
if (config_has_user_value(config, args...)) {
return func(config, args...);
}
if (config_has_default_value(config, args...)) {
return defaultFunc(config, args...);
}
return std::optional<Ret>{};
}
// Calling obs_frontend_set_preview_program_mode() directly from a thread that // Calling obs_frontend_set_preview_program_mode() directly from a thread that
// is not the main OBS UI thread will lead to undefined behaviour, so we have // is not the main OBS UI thread will lead to undefined behaviour, so we have
// to use this helper function instead - copied from obs-websocket plugin // to use this helper function instead - copied from obs-websocket plugin
@@ -91,78 +42,14 @@ static void enableStudioMode(bool enable)
bool MacroActionSudioMode::PerformAction() bool MacroActionSudioMode::PerformAction()
{ {
obs_frontend_get_user_config();
switch (_action) { switch (_action) {
case Action::TRANSITION: case Action::SWAP_SCENE:
obs_frontend_preview_program_trigger_transition(); obs_frontend_preview_program_trigger_transition();
break; break;
case Action::TRANSITION_WITH_SWAP: { case Action::SET_SCENE: {
auto swapEnabled = getConfigValueHelper(config_get_bool, auto s = obs_weak_source_get_source(_scene.GetScene());
config_get_default_bool, obs_frontend_set_current_preview_scene(s);
"BasicWindow", obs_source_release(s);
"SwapScenesMode");
if (swapEnabled.has_value() && *swapEnabled == true) {
obs_frontend_preview_program_trigger_transition();
break;
}
setConfigValueHelper(config_set_bool, "BasicWindow",
"SwapScenesMode", true);
obs_frontend_preview_program_trigger_transition();
setConfigValueHelper(config_set_bool, "BasicWindow",
"SwapScenesMode", false);
break;
}
case Action::ENALBE_TRANSITION_SWAP:
setConfigValueHelper(config_set_bool, "BasicWindow",
"SwapScenesMode", true);
break;
case Action::DISABLE_TRANSITION_SWAP:
setConfigValueHelper(config_set_bool, "BasicWindow",
"SwapScenesMode", false);
break;
case Action::TOGGLE_TRANSITION_SWAP: {
const auto enabled = getConfigValueHelper(
config_get_bool, config_get_default_bool, "BasicWindow",
"SwapScenesMode");
setConfigValueHelper(config_set_bool, "BasicWindow",
"SwapScenesMode",
enabled.has_value() && !*enabled);
break;
}
case Action::ENALBE_DUPLICATE_SCENE:
setConfigValueHelper(config_set_bool, "BasicWindow",
"SceneDuplicationMode", true);
break;
case Action::DISABLE_DUPLICATE_SCENE:
setConfigValueHelper(config_set_bool, "BasicWindow",
"SceneDuplicationMode", false);
break;
case Action::TOGGLE_DUPLICATE_SCENE: {
const auto enabled = getConfigValueHelper(
config_get_bool, config_get_default_bool, "BasicWindow",
"SceneDuplicationMode");
setConfigValueHelper(config_set_bool, "BasicWindow",
"SceneDuplicationMode",
enabled.has_value() && !*enabled);
break;
}
case Action::ENALBE_DUPLICATE_SOURCE:
setConfigValueHelper(config_set_bool, "BasicWindow",
"EditPropertiesMode", true);
break;
case Action::DISABLE_DUPLICATE_SOURCE:
setConfigValueHelper(config_set_bool, "BasicWindow",
"EditPropertiesMode", false);
break;
case Action::TOGGLE_DUPLICATE_SOURCE: {
const auto enabled = getConfigValueHelper(
config_get_bool, config_get_default_bool, "BasicWindow",
"EditPropertiesMode");
setConfigValueHelper(config_set_bool, "BasicWindow",
"EditPropertiesMode",
enabled.has_value() && !*enabled);
break; break;
} }
case Action::ENABLE_STUDIO_MODE: case Action::ENABLE_STUDIO_MODE:
@@ -171,15 +58,6 @@ bool MacroActionSudioMode::PerformAction()
case Action::DISABLE_STUDIO_MODE: case Action::DISABLE_STUDIO_MODE:
enableStudioMode(false); enableStudioMode(false);
break; break;
case Action::TOGGLE_STUDIO_MODE:
enableStudioMode(!obs_frontend_preview_program_mode_active());
break;
case Action::SET_SCENE: {
auto s = obs_weak_source_get_source(_scene.GetScene());
obs_frontend_set_current_preview_scene(s);
obs_source_release(s);
break;
}
default: default:
break; break;
} }
@@ -204,7 +82,6 @@ bool MacroActionSudioMode::Save(obs_data_t *obj) const
MacroAction::Save(obj); MacroAction::Save(obj);
obs_data_set_int(obj, "action", static_cast<int>(_action)); obs_data_set_int(obj, "action", static_cast<int>(_action));
_scene.Save(obj); _scene.Save(obj);
obs_data_set_int(obj, "version", 1);
return true; return true;
} }
@@ -213,34 +90,6 @@ bool MacroActionSudioMode::Load(obs_data_t *obj)
MacroAction::Load(obj); MacroAction::Load(obj);
_action = static_cast<Action>(obs_data_get_int(obj, "action")); _action = static_cast<Action>(obs_data_get_int(obj, "action"));
_scene.Load(obj); _scene.Load(obj);
if (!obs_data_has_user_value(obj, "version")) {
enum class OldAction {
SWAP_SCENE,
SET_SCENE,
ENABLE_STUDIO_MODE,
DISABLE_STUDIO_MODE,
};
switch (static_cast<OldAction>(
obs_data_get_int(obj, "action"))) {
case OldAction::SWAP_SCENE:
_action = Action::TRANSITION_WITH_SWAP;
break;
case OldAction::SET_SCENE:
_action = Action::SET_SCENE;
break;
case OldAction::ENABLE_STUDIO_MODE:
_action = Action::ENABLE_STUDIO_MODE;
break;
case OldAction::DISABLE_STUDIO_MODE:
_action = Action::DISABLE_STUDIO_MODE;
break;
default:
break;
}
}
return true; return true;
} }
@@ -287,11 +136,15 @@ MacroActionStudioModeEdit::MacroActionStudioModeEdit(
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)), QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
this, SLOT(SceneChanged(const SceneSelection &))); this, SLOT(SceneChanged(const SceneSelection &)));
auto layout = new QHBoxLayout; std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{actions}}", _actions},
{"{{scenes}}", _scenes},
};
QHBoxLayout *mainLayout = new QHBoxLayout;
PlaceWidgets( PlaceWidgets(
obs_module_text("AdvSceneSwitcher.action.studioMode.entry"), obs_module_text("AdvSceneSwitcher.action.studioMode.entry"),
layout, {{"{{actions}}", _actions}, {"{{scenes}}", _scenes}}); mainLayout, widgetPlaceholders);
setLayout(layout); setLayout(mainLayout);
_entryData = entryData; _entryData = entryData;
UpdateEntryData(); UpdateEntryData();

View File

@@ -18,28 +18,13 @@ public:
void ResolveVariablesToFixedValues(); void ResolveVariablesToFixedValues();
enum class Action { enum class Action {
TRANSITION = 10, SWAP_SCENE,
TRANSITION_WITH_SWAP = 20, SET_SCENE, // TODO: Remove in future version as the
// functionality moved to the scene switch action
ENALBE_TRANSITION_SWAP = 30, ENABLE_STUDIO_MODE,
DISABLE_TRANSITION_SWAP = 40, DISABLE_STUDIO_MODE,
TOGGLE_TRANSITION_SWAP = 50,
ENALBE_DUPLICATE_SCENE = 60,
DISABLE_DUPLICATE_SCENE = 70,
TOGGLE_DUPLICATE_SCENE = 80,
ENALBE_DUPLICATE_SOURCE = 90,
DISABLE_DUPLICATE_SOURCE = 100,
TOGGLE_DUPLICATE_SOURCE = 110,
ENABLE_STUDIO_MODE = 120,
DISABLE_STUDIO_MODE = 130,
TOGGLE_STUDIO_MODE = 140,
SET_SCENE = 1000, // Deprecated
}; };
Action _action = Action::TRANSITION; Action _action = Action::SWAP_SCENE;
SceneSelection _scene; SceneSelection _scene;
private: private: