SceneSwitcher/plugins/base/macro-action-transition.cpp
2025-06-20 22:29:35 +02:00

391 lines
11 KiB
C++

#include "macro-action-transition.hpp"
#include "layout-helpers.hpp"
#include <obs-frontend-api.h>
namespace advss {
const std::string MacroActionTransition::id = "transition";
bool MacroActionTransition::_registered = MacroActionFactory::Register(
MacroActionTransition::id,
{MacroActionTransition::Create, MacroActionTransitionEdit::Create,
"AdvSceneSwitcher.action.transition"});
const static std::map<MacroActionTransition::Type, std::string> actionTypes = {
{MacroActionTransition::Type::SCENE,
"AdvSceneSwitcher.action.transition.type.scene"},
{MacroActionTransition::Type::SCENE_OVERRIDE,
"AdvSceneSwitcher.action.transition.type.sceneOverride"},
{MacroActionTransition::Type::SOURCE_SHOW,
"AdvSceneSwitcher.action.transition.type.sourceShow"},
{MacroActionTransition::Type::SOURCE_HIDE,
"AdvSceneSwitcher.action.transition.type.sourceHide"},
};
void MacroActionTransition::SetSceneTransition()
{
if (_setTransitionType) {
OBSSourceAutoRelease transition =
obs_weak_source_get_source(_transition.GetTransition());
obs_frontend_set_current_transition(transition);
}
if (_setDuration) {
obs_frontend_set_transition_duration(_duration.Seconds() *
1000);
}
}
void MacroActionTransition::SetTransitionOverride()
{
OBSSourceAutoRelease scene =
obs_weak_source_get_source(_scene.GetScene());
OBSDataAutoRelease data = obs_source_get_private_settings(scene);
if (_setTransitionType) {
obs_data_set_string(data, "transition",
_transition.ToString().c_str());
}
if (_setDuration) {
obs_data_set_int(data, "transition_duration",
_duration.Milliseconds());
}
}
#if (LIBOBS_API_VER >= MAKE_SEMANTIC_VERSION(27, 0, 0)) && \
(LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(28, 0, 0))
static void obs_sceneitem_set_transition(obs_sceneitem_t *item, bool show,
obs_source_t *transition)
{
if (show) {
obs_sceneitem_set_show_transition(item, transition);
} else {
obs_sceneitem_set_hide_transition(item, transition);
}
}
static void obs_sceneitem_set_transition_duration(obs_sceneitem_t *item,
bool show,
uint32_t duration_ms)
{
if (show) {
obs_sceneitem_set_show_transition_duration(item, duration_ms);
} else {
obs_sceneitem_set_hide_transition_duration(item, duration_ms);
}
}
#endif
static void setSceneItemTransition(const OBSSceneItem &item,
const OBSSourceAutoRelease &transition,
bool show)
{
OBSDataAutoRelease settings = obs_source_get_settings(transition);
if (!transition || !settings) {
// Set transition to "None"
obs_sceneitem_set_transition(item, show, nullptr);
return;
}
// We cannot share the transition source between
// scene items without introducing strange graphical
// artifacts so we have to create new ones here
OBSSourceAutoRelease transitionSource = obs_source_create_private(
obs_source_get_id(transition), obs_source_get_name(transition),
settings);
obs_sceneitem_set_transition(item, show, transitionSource);
}
void MacroActionTransition::SetSourceTransition(bool show)
{
#if LIBOBS_API_VER >= MAKE_SEMANTIC_VERSION(27, 0, 0)
OBSSourceAutoRelease transition =
obs_weak_source_get_source(_transition.GetTransition());
const auto items = _source.GetSceneItems(_scene);
for (const auto &item : items) {
if (_setTransitionType) {
setSceneItemTransition(item, transition, show);
}
if (_setDuration) {
obs_sceneitem_set_transition_duration(
item, show, _duration.Milliseconds());
}
}
#endif
}
bool MacroActionTransition::PerformAction()
{
switch (_type) {
case Type::SCENE:
SetSceneTransition();
break;
case Type::SCENE_OVERRIDE:
SetTransitionOverride();
break;
case Type::SOURCE_SHOW:
SetSourceTransition(true);
break;
case Type::SOURCE_HIDE:
SetSourceTransition(false);
break;
}
return true;
}
void MacroActionTransition::LogAction() const
{
std::string msgBegin;
switch (_type) {
case Type::SCENE:
msgBegin += "set scene transition";
break;
case Type::SCENE_OVERRIDE:
msgBegin += "set scene override transition of " +
_scene.ToString(true);
break;
case Type::SOURCE_SHOW:
msgBegin += "set source show transition of " +
_source.ToString(true) + " on scene " +
_scene.ToString(true);
break;
case Type::SOURCE_HIDE:
msgBegin += "set source hide transition of " +
_source.ToString(true) + " on scene " +
_scene.ToString(true);
break;
}
if (_setDuration) {
ablog(LOG_INFO, "%s duration to %s", msgBegin.c_str(),
_duration.ToString().c_str());
}
if (_setTransitionType) {
ablog(LOG_INFO, "%s type to \"%s\"", msgBegin.c_str(),
_transition.ToString().c_str());
}
}
bool MacroActionTransition::Save(obs_data_t *obj) const
{
MacroAction::Save(obj);
obs_data_set_int(obj, "actionType", static_cast<int>(_type));
_source.Save(obj);
_scene.Save(obj);
_duration.Save(obj);
_transition.Save(obj);
obs_data_set_bool(obj, "setDuration", _setDuration);
obs_data_set_bool(obj, "setType", _setTransitionType);
return true;
}
bool MacroActionTransition::Load(obs_data_t *obj)
{
MacroAction::Load(obj);
_type = static_cast<Type>(obs_data_get_int(obj, "actionType"));
_source.Load(obj);
_scene.Load(obj);
_duration.Load(obj);
_transition.Load(obj);
_setDuration = obs_data_get_bool(obj, "setDuration");
_setTransitionType = obs_data_get_bool(obj, "setType");
return true;
}
std::string MacroActionTransition::GetShortDesc() const
{
std::string msgBegin;
switch (_type) {
case Type::SCENE:
return _transition.ToString();
case Type::SCENE_OVERRIDE:
return _scene.ToString() + " - " + _transition.ToString();
case Type::SOURCE_SHOW:
return _scene.ToString() + " - " + _source.ToString() + " - " +
_transition.ToString();
case Type::SOURCE_HIDE:
return _scene.ToString() + " - " + _source.ToString() + " - " +
_transition.ToString();
}
return "";
}
std::shared_ptr<MacroAction> MacroActionTransition::Create(Macro *m)
{
return std::make_shared<MacroActionTransition>(m);
}
std::shared_ptr<MacroAction> MacroActionTransition::Copy() const
{
return std::make_shared<MacroActionTransition>(*this);
}
void MacroActionTransition::ResolveVariablesToFixedValues()
{
_source.ResolveVariables();
_scene.ResolveVariables();
_duration.ResolveVariables();
}
static inline void populateActionSelection(QComboBox *list)
{
for (const auto &[_, name] : actionTypes) {
list->addItem(obs_module_text(name.c_str()));
}
}
MacroActionTransitionEdit::MacroActionTransitionEdit(
QWidget *parent, std::shared_ptr<MacroActionTransition> entryData)
: QWidget(parent),
_actions(new QComboBox),
_sources(new SceneItemSelectionWidget(parent, false)),
_scenes(new SceneSelectionWidget(this, true, false, false, true)),
_setTransition(new QCheckBox),
_setDuration(new QCheckBox),
_transitions(new TransitionSelectionWidget(this, false)),
_duration(new DurationSelection(this, false)),
_transitionLayout(new QHBoxLayout),
_durationLayout(new QHBoxLayout)
{
populateActionSelection(_actions);
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
SLOT(ActionChanged(int)));
QWidget::connect(_sources,
SIGNAL(SceneItemChanged(const SceneItemSelection &)),
this, SLOT(SourceChanged(const SceneItemSelection &)));
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
_sources, SLOT(SceneChanged(const SceneSelection &)));
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
this, SLOT(SceneChanged(const SceneSelection &)));
QWidget::connect(_transitions,
SIGNAL(TransitionChanged(const TransitionSelection &)),
this,
SLOT(TransitionChanged(const TransitionSelection &)));
QWidget::connect(_duration, SIGNAL(DurationChanged(const Duration &)),
this, SLOT(DurationChanged(const Duration &)));
QWidget::connect(_setTransition, SIGNAL(stateChanged(int)), this,
SLOT(SetTransitionChanged(int)));
QWidget::connect(_setDuration, SIGNAL(stateChanged(int)), this,
SLOT(SetDurationChanged(int)));
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{type}}", _actions},
{"{{sources}}", _sources},
{"{{scenes}}", _scenes},
{"{{transitions}}", _transitions},
{"{{duration}}", _duration},
{"{{setTransition}}", _setTransition},
{"{{setDuration}}", _setDuration},
};
QHBoxLayout *typeLayout = new QHBoxLayout;
PlaceWidgets(obs_module_text(
"AdvSceneSwitcher.action.transition.entry.line1"),
typeLayout, widgetPlaceholders);
PlaceWidgets(obs_module_text(
"AdvSceneSwitcher.action.transition.entry.line2"),
_transitionLayout, widgetPlaceholders);
PlaceWidgets(obs_module_text(
"AdvSceneSwitcher.action.transition.entry.line3"),
_durationLayout, widgetPlaceholders);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(typeLayout);
mainLayout->addLayout(_transitionLayout);
mainLayout->addLayout(_durationLayout);
setLayout(mainLayout);
_entryData = entryData;
UpdateEntryData();
_loading = false;
}
void MacroActionTransitionEdit::UpdateEntryData()
{
if (!_entryData) {
return;
}
_actions->setCurrentIndex(static_cast<int>(_entryData->_type));
_scenes->SetScene(_entryData->_scene);
_sources->SetSceneItem((_entryData->_source));
_setDuration->setChecked(_entryData->_setDuration);
_duration->SetDuration(_entryData->_duration);
_setTransition->setChecked(_entryData->_setTransitionType);
_transitions->SetTransition(_entryData->_transition);
_transitions->setEnabled(_entryData->_setTransitionType);
_duration->setEnabled(_entryData->_setDuration);
SetWidgetVisibility();
}
void MacroActionTransitionEdit::SourceChanged(const SceneItemSelection &item)
{
GUARD_LOADING_AND_LOCK();
_entryData->_source = item;
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
adjustSize();
updateGeometry();
}
void MacroActionTransitionEdit::ActionChanged(int value)
{
GUARD_LOADING_AND_LOCK();
_entryData->_type = static_cast<MacroActionTransition::Type>(value);
SetWidgetVisibility();
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
}
void MacroActionTransitionEdit::SceneChanged(const SceneSelection &s)
{
GUARD_LOADING_AND_LOCK();
_entryData->_scene = s;
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
}
void MacroActionTransitionEdit::TransitionChanged(const TransitionSelection &t)
{
GUARD_LOADING_AND_LOCK();
_entryData->_transition = t;
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
}
void MacroActionTransitionEdit::DurationChanged(const Duration &dur)
{
GUARD_LOADING_AND_LOCK();
_entryData->_duration = dur;
}
void MacroActionTransitionEdit::SetWidgetVisibility()
{
_sources->setVisible(
_entryData->_type == MacroActionTransition::Type::SOURCE_HIDE ||
_entryData->_type == MacroActionTransition::Type::SOURCE_SHOW);
_scenes->setVisible(_entryData->_type !=
MacroActionTransition::Type::SCENE);
adjustSize();
}
void MacroActionTransitionEdit::SetTransitionChanged(int state)
{
GUARD_LOADING_AND_LOCK();
_entryData->_setTransitionType = state;
_transitions->setEnabled(state);
if (state) {
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
} else {
emit HeaderInfoChanged("");
}
}
void MacroActionTransitionEdit::SetDurationChanged(int state)
{
GUARD_LOADING_AND_LOCK();
_entryData->_setDuration = state;
_duration->setEnabled(state);
}
} // namespace advss