mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-08-30 13:15:43 -05:00
Restructure "src/" folder
Moving files from the "src/" folder into "src/legacy", "src/macro-core", and "src/utils" was necessary as it was becoming a bit too cluttered.
This commit is contained in:
807
src/legacy/switch-sequence.cpp
Normal file
807
src/legacy/switch-sequence.cpp
Normal file
@@ -0,0 +1,807 @@
|
||||
#include <QFileDialog>
|
||||
#include <QTextStream>
|
||||
#include <QScrollArea>
|
||||
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
constexpr auto max_extend_text_size = 150;
|
||||
|
||||
bool SceneSequenceSwitch::pause = false;
|
||||
static QMetaObject::Connection addPulse;
|
||||
|
||||
void AdvSceneSwitcher::on_sceneSequenceAdd_clicked()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->sceneSequenceSwitches.emplace_back();
|
||||
|
||||
listAddClicked(ui->sceneSequenceSwitches,
|
||||
new SequenceWidget(
|
||||
this, &switcher->sceneSequenceSwitches.back()),
|
||||
ui->sceneSequenceAdd, &addPulse);
|
||||
|
||||
ui->sequenceHelp->setVisible(false);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_sceneSequenceRemove_clicked()
|
||||
{
|
||||
QListWidgetItem *item = ui->sceneSequenceSwitches->currentItem();
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
int idx = ui->sceneSequenceSwitches->currentRow();
|
||||
auto &switches = switcher->sceneSequenceSwitches;
|
||||
switches.erase(switches.begin() + idx);
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_sceneSequenceUp_clicked()
|
||||
{
|
||||
int index = ui->sceneSequenceSwitches->currentRow();
|
||||
if (!listMoveUp(ui->sceneSequenceSwitches)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SequenceWidget *s1 =
|
||||
(SequenceWidget *)ui->sceneSequenceSwitches->itemWidget(
|
||||
ui->sceneSequenceSwitches->item(index));
|
||||
SequenceWidget *s2 =
|
||||
(SequenceWidget *)ui->sceneSequenceSwitches->itemWidget(
|
||||
ui->sceneSequenceSwitches->item(index - 1));
|
||||
SequenceWidget::swapSwitchData(s1, s2);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
std::swap(switcher->sceneSequenceSwitches[index],
|
||||
switcher->sceneSequenceSwitches[index - 1]);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_sceneSequenceDown_clicked()
|
||||
{
|
||||
int index = ui->sceneSequenceSwitches->currentRow();
|
||||
|
||||
if (!listMoveDown(ui->sceneSequenceSwitches)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SequenceWidget *s1 =
|
||||
(SequenceWidget *)ui->sceneSequenceSwitches->itemWidget(
|
||||
ui->sceneSequenceSwitches->item(index));
|
||||
SequenceWidget *s2 =
|
||||
(SequenceWidget *)ui->sceneSequenceSwitches->itemWidget(
|
||||
ui->sceneSequenceSwitches->item(index + 1));
|
||||
SequenceWidget::swapSwitchData(s1, s2);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
std::swap(switcher->sceneSequenceSwitches[index],
|
||||
switcher->sceneSequenceSwitches[index + 1]);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_sceneSequenceSave_clicked()
|
||||
{
|
||||
QString directory = QFileDialog::getSaveFileName(
|
||||
this,
|
||||
tr(obs_module_text(
|
||||
"AdvSceneSwitcher.sceneSequenceTab.saveTitle")),
|
||||
QDir::currentPath(),
|
||||
tr(obs_module_text(
|
||||
"AdvSceneSwitcher.sceneSequenceTab.fileType")));
|
||||
if (directory.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
QFile file(directory);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
return;
|
||||
}
|
||||
|
||||
obs_data_t *obj = obs_data_create();
|
||||
switcher->saveSceneSequenceSwitches(obj);
|
||||
obs_data_save_json(obj, file.fileName().toUtf8().constData());
|
||||
obs_data_release(obj);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_sceneSequenceLoad_clicked()
|
||||
{
|
||||
QString directory = QFileDialog::getOpenFileName(
|
||||
this,
|
||||
tr(obs_module_text(
|
||||
"AdvSceneSwitcher.sceneSequenceTab.loadTitle")),
|
||||
QDir::currentPath(),
|
||||
tr(obs_module_text(
|
||||
"AdvSceneSwitcher.sceneSequenceTab.fileType")));
|
||||
if (directory.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QFile file(directory);
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
return;
|
||||
}
|
||||
|
||||
obs_data_t *obj = obs_data_create_from_json_file(
|
||||
file.fileName().toUtf8().constData());
|
||||
|
||||
if (!obj) {
|
||||
DisplayMessage(obs_module_text(
|
||||
"AdvSceneSwitcher.sceneSequenceTab.loadFail"));
|
||||
return;
|
||||
}
|
||||
|
||||
switcher->loadSceneSequenceSwitches(obj);
|
||||
|
||||
obs_data_release(obj);
|
||||
|
||||
DisplayMessage(obs_module_text(
|
||||
"AdvSceneSwitcher.sceneSequenceTab.loadSuccess"));
|
||||
close();
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::OpenSequenceExtendEdit(SequenceWidget *sw)
|
||||
{
|
||||
QDialog edit;
|
||||
QScrollArea scrollArea;
|
||||
SequenceWidget editWidget(this, sw->getSwitchData(), false, true,
|
||||
false);
|
||||
scrollArea.setMinimumWidth(1000);
|
||||
scrollArea.setSizePolicy(QSizePolicy::MinimumExpanding,
|
||||
QSizePolicy::MinimumExpanding);
|
||||
scrollArea.setWidget(&editWidget);
|
||||
scrollArea.setWidgetResizable(true);
|
||||
QHBoxLayout layout;
|
||||
layout.setSizeConstraint(QLayout::SetMinimumSize);
|
||||
layout.addWidget(&scrollArea);
|
||||
edit.setLayout(&layout);
|
||||
edit.setWindowTitle(obs_module_text(
|
||||
"AdvSceneSwitcher.sceneSequenceTab.extendEdit"));
|
||||
edit.exec();
|
||||
|
||||
sw->UpdateWidgetStatus(true);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_sequenceEdit_clicked()
|
||||
{
|
||||
int index = ui->sceneSequenceSwitches->currentRow();
|
||||
if (index == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
SequenceWidget *currentWidget =
|
||||
(SequenceWidget *)ui->sceneSequenceSwitches->itemWidget(
|
||||
ui->sceneSequenceSwitches->item(index));
|
||||
|
||||
OpenSequenceExtendEdit(currentWidget);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_sceneSequenceSwitches_itemDoubleClicked(
|
||||
QListWidgetItem *item)
|
||||
{
|
||||
SequenceWidget *currentWidget =
|
||||
(SequenceWidget *)ui->sceneSequenceSwitches->itemWidget(item);
|
||||
OpenSequenceExtendEdit(currentWidget);
|
||||
}
|
||||
|
||||
bool SwitcherData::checkSceneSequence(OBSWeakSource &scene,
|
||||
OBSWeakSource &transition, int &linger,
|
||||
bool &setPrevSceneAfterLinger)
|
||||
{
|
||||
if (SceneSequenceSwitch::pause) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool match = false;
|
||||
|
||||
for (SceneSequenceSwitch &s : sceneSequenceSwitches) {
|
||||
// Continue the active uninterruptible sequence and skip others
|
||||
if (uninterruptibleSceneSequenceActive &&
|
||||
s.activeSequence == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool matched = s.checkMatch(linger);
|
||||
|
||||
if (!match && matched) {
|
||||
match = matched;
|
||||
|
||||
if (s.activeSequence) {
|
||||
scene = s.activeSequence->getScene();
|
||||
transition = s.activeSequence->transition;
|
||||
setPrevSceneAfterLinger =
|
||||
s.activeSequence->usePreviousScene;
|
||||
} else {
|
||||
scene = s.getScene();
|
||||
transition = s.transition;
|
||||
setPrevSceneAfterLinger = s.usePreviousScene;
|
||||
if (verbose) {
|
||||
s.logMatch();
|
||||
}
|
||||
}
|
||||
|
||||
s.advanceActiveSequence();
|
||||
if (verbose) {
|
||||
s.logAdvanceSequence();
|
||||
}
|
||||
|
||||
// Ignore other switching methods if sequence is not
|
||||
// interruptible and has not reached its end
|
||||
if (s.activeSequence) {
|
||||
uninterruptibleSceneSequenceActive =
|
||||
!s.interruptible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!match) {
|
||||
uninterruptibleSceneSequenceActive = false;
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
void SwitcherData::saveSceneSequenceSwitches(obs_data_t *obj)
|
||||
{
|
||||
obs_data_array_t *sceneSequenceArray = obs_data_array_create();
|
||||
for (SceneSequenceSwitch &s : sceneSequenceSwitches) {
|
||||
obs_data_t *array_obj = obs_data_create();
|
||||
|
||||
s.save(array_obj);
|
||||
obs_data_array_push_back(sceneSequenceArray, array_obj);
|
||||
|
||||
obs_data_release(array_obj);
|
||||
}
|
||||
obs_data_set_array(obj, "sceneRoundTrip", sceneSequenceArray);
|
||||
obs_data_array_release(sceneSequenceArray);
|
||||
}
|
||||
|
||||
void SwitcherData::loadSceneSequenceSwitches(obs_data_t *obj)
|
||||
{
|
||||
sceneSequenceSwitches.clear();
|
||||
|
||||
obs_data_array_t *sceneSequenceArray =
|
||||
obs_data_get_array(obj, "sceneRoundTrip");
|
||||
size_t count = obs_data_array_count(sceneSequenceArray);
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
obs_data_t *array_obj =
|
||||
obs_data_array_item(sceneSequenceArray, i);
|
||||
|
||||
sceneSequenceSwitches.emplace_back();
|
||||
sceneSequenceSwitches.back().load(array_obj);
|
||||
|
||||
obs_data_release(array_obj);
|
||||
}
|
||||
obs_data_array_release(sceneSequenceArray);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupSequenceTab()
|
||||
{
|
||||
for (auto &s : switcher->sceneSequenceSwitches) {
|
||||
QListWidgetItem *item;
|
||||
item = new QListWidgetItem(ui->sceneSequenceSwitches);
|
||||
ui->sceneSequenceSwitches->addItem(item);
|
||||
SequenceWidget *sw = new SequenceWidget(this, &s);
|
||||
item->setSizeHint(sw->minimumSizeHint());
|
||||
ui->sceneSequenceSwitches->setItemWidget(item, sw);
|
||||
}
|
||||
|
||||
if (switcher->sceneSequenceSwitches.size() == 0) {
|
||||
if (!switcher->disableHints) {
|
||||
addPulse = PulseWidget(ui->sceneSequenceAdd,
|
||||
QColor(Qt::green));
|
||||
}
|
||||
ui->sequenceHelp->setVisible(true);
|
||||
} else {
|
||||
ui->sequenceHelp->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
bool SceneSequenceSwitch::initialized()
|
||||
{
|
||||
return SceneSwitcherEntry::initialized() && startScene;
|
||||
}
|
||||
|
||||
bool SceneSequenceSwitch::valid()
|
||||
{
|
||||
return !initialized() ||
|
||||
(SceneSwitcherEntry::valid() && WeakSourceValid(startScene));
|
||||
}
|
||||
|
||||
void SceneSequenceSwitch::save(obs_data_t *obj, bool saveExt)
|
||||
{
|
||||
SceneSwitcherEntry::save(obj);
|
||||
|
||||
obs_data_set_int(obj, "startTargetType",
|
||||
static_cast<int>(startTargetType));
|
||||
obs_data_set_string(obj, "startScene",
|
||||
GetWeakSourceName(startScene).c_str());
|
||||
delay.Save(obj, "delay");
|
||||
obs_data_set_bool(obj, "interruptible", interruptible);
|
||||
|
||||
if (saveExt) {
|
||||
auto cur = extendedSequence.get();
|
||||
|
||||
obs_data_array_t *extendScenes = obs_data_array_create();
|
||||
while (cur) {
|
||||
obs_data_t *array_obj = obs_data_create();
|
||||
cur->save(array_obj, false);
|
||||
obs_data_array_push_back(extendScenes, array_obj);
|
||||
obs_data_release(array_obj);
|
||||
cur = cur->extendedSequence.get();
|
||||
}
|
||||
obs_data_set_array(obj, "extendScenes", extendScenes);
|
||||
obs_data_array_release(extendScenes);
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSequenceSwitch::load(obs_data_t *obj, bool saveExt)
|
||||
{
|
||||
SceneSwitcherEntry::load(obj);
|
||||
startTargetType = static_cast<SwitchTargetType>(
|
||||
obs_data_get_int(obj, "startTargetType"));
|
||||
const char *scene = obs_data_get_string(obj, "startScene");
|
||||
startScene = GetWeakSourceByName(scene);
|
||||
delay.Load(obj, "delay");
|
||||
|
||||
interruptible = obs_data_get_bool(obj, "interruptible");
|
||||
|
||||
if (saveExt) {
|
||||
auto cur = this;
|
||||
|
||||
obs_data_array_t *extendScenes =
|
||||
obs_data_get_array(obj, "extendScenes");
|
||||
size_t count = obs_data_array_count(extendScenes);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
obs_data_t *array_obj =
|
||||
obs_data_array_item(extendScenes, i);
|
||||
|
||||
cur->extendedSequence =
|
||||
std::make_unique<SceneSequenceSwitch>();
|
||||
|
||||
cur->extendedSequence->load(array_obj, false);
|
||||
|
||||
cur = cur->extendedSequence.get();
|
||||
obs_data_release(array_obj);
|
||||
}
|
||||
obs_data_array_release(extendScenes);
|
||||
}
|
||||
}
|
||||
|
||||
bool SceneSequenceSwitch::reduce()
|
||||
{
|
||||
// Reset activeSequence just in case it was one of the deleted entries
|
||||
activeSequence = nullptr;
|
||||
|
||||
if (!extendedSequence) {
|
||||
return true;
|
||||
}
|
||||
if (extendedSequence->reduce()) {
|
||||
extendedSequence.reset(nullptr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SceneSequenceSwitch *SceneSequenceSwitch::extend()
|
||||
{
|
||||
if (extendedSequence) {
|
||||
return extendedSequence->extend();
|
||||
}
|
||||
extendedSequence = std::make_unique<SceneSequenceSwitch>();
|
||||
extendedSequence->startScene = scene;
|
||||
if (targetType == SwitchTargetType::SceneGroup) {
|
||||
extendedSequence->startScene = nullptr;
|
||||
extendedSequence->startTargetType =
|
||||
SwitchTargetType::SceneGroup;
|
||||
}
|
||||
return extendedSequence.get();
|
||||
}
|
||||
|
||||
bool SceneSequenceSwitch::checkMatch(int &linger, SceneSequenceSwitch *root)
|
||||
{
|
||||
if (!initialized()) {
|
||||
if (root) {
|
||||
root->activeSequence = nullptr;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool match = false;
|
||||
|
||||
// We cannot rely on switcher->currentScene for this information.
|
||||
// Depending on the transition length the frontend event for the scene
|
||||
// change of the previous element in the sequence might not yet have
|
||||
// been received, which would lead to the sequencence being aborted.
|
||||
// Thus we have to use obs_frontend_get_current_scene() here.
|
||||
auto sceneSource = obs_frontend_get_current_scene();
|
||||
auto currentScene = obs_source_get_weak_source(sceneSource);
|
||||
obs_weak_source_release(currentScene);
|
||||
obs_source_release(sceneSource);
|
||||
|
||||
if (activeSequence) {
|
||||
return activeSequence->checkMatch(linger, this);
|
||||
}
|
||||
|
||||
if (startScene == currentScene) {
|
||||
if (interruptible) {
|
||||
match = checkDurationMatchInterruptible();
|
||||
} else {
|
||||
match = true;
|
||||
prepareUninterruptibleMatch(linger);
|
||||
}
|
||||
} else {
|
||||
delay.Reset();
|
||||
|
||||
if (root) {
|
||||
root->activeSequence = nullptr;
|
||||
logSequenceCanceled();
|
||||
}
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
bool SceneSequenceSwitch::checkDurationMatchInterruptible()
|
||||
{
|
||||
if (delay.DurationReached()) {
|
||||
delay.Reset();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SceneSequenceSwitch::prepareUninterruptibleMatch(int &linger)
|
||||
{
|
||||
int dur = delay.seconds * 1000;
|
||||
if (dur > 0) {
|
||||
linger = dur;
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSequenceSwitch::advanceActiveSequence()
|
||||
{
|
||||
// Set start Scene
|
||||
OBSWeakSource currentSceneGroupScene = nullptr;
|
||||
if (targetType == SwitchTargetType::SceneGroup && group) {
|
||||
currentSceneGroupScene = group->getCurrentScene();
|
||||
}
|
||||
|
||||
if (activeSequence) {
|
||||
activeSequence = activeSequence->extendedSequence.get();
|
||||
} else {
|
||||
activeSequence = extendedSequence.get();
|
||||
}
|
||||
|
||||
if (activeSequence) {
|
||||
if (activeSequence->startTargetType ==
|
||||
SwitchTargetType::SceneGroup) {
|
||||
activeSequence->startScene = currentSceneGroupScene;
|
||||
}
|
||||
if (activeSequence->targetType == SwitchTargetType::Scene &&
|
||||
!activeSequence->scene) {
|
||||
blog(LOG_WARNING,
|
||||
"cannot advance sequence - null scene set");
|
||||
activeSequence = nullptr;
|
||||
return;
|
||||
}
|
||||
if (activeSequence->targetType ==
|
||||
SwitchTargetType::SceneGroup &&
|
||||
activeSequence->group &&
|
||||
activeSequence->group->scenes.empty()) {
|
||||
blog(LOG_WARNING,
|
||||
"cannot advance sequence - no scenes specified in '%s'",
|
||||
activeSequence->group->name.c_str());
|
||||
activeSequence = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
// Reinit delay in case it was previously set
|
||||
activeSequence->delay.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSequenceSwitch::logAdvanceSequence()
|
||||
{
|
||||
if (activeSequence) {
|
||||
std::string targetName =
|
||||
GetWeakSourceName(activeSequence->scene);
|
||||
|
||||
if (activeSequence->targetType ==
|
||||
SwitchTargetType::SceneGroup &&
|
||||
activeSequence->group) {
|
||||
targetName = activeSequence->group->name;
|
||||
}
|
||||
|
||||
blog(LOG_INFO, "continuing sequence with '%s' -> '%s'",
|
||||
GetWeakSourceName(activeSequence->startScene).c_str(),
|
||||
targetName.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSequenceSwitch::logSequenceCanceled()
|
||||
{
|
||||
blog(LOG_INFO, "unexpected scene change - cancel sequence");
|
||||
}
|
||||
|
||||
QString makeExtendText(SceneSequenceSwitch *s, int curLen = 0)
|
||||
{
|
||||
if (!s) {
|
||||
return "";
|
||||
}
|
||||
|
||||
QString ext = "";
|
||||
|
||||
ext = QString::fromStdString(s->delay.ToString()) + " ";
|
||||
|
||||
QString sceneName = GetWeakSourceName(s->scene).c_str();
|
||||
if (s->targetType == SwitchTargetType::SceneGroup && s->group) {
|
||||
sceneName = QString::fromStdString(s->group->name);
|
||||
}
|
||||
if (sceneName.isEmpty()) {
|
||||
sceneName = obs_module_text("AdvSceneSwitcher.selectScene");
|
||||
}
|
||||
ext += " -> [" + sceneName + "]";
|
||||
|
||||
if (ext.length() + curLen > max_extend_text_size) {
|
||||
return "...";
|
||||
}
|
||||
|
||||
if (s->extendedSequence.get()) {
|
||||
return ext +=
|
||||
" | " + makeExtendText(s->extendedSequence.get(),
|
||||
curLen + ext.length());
|
||||
} else {
|
||||
return ext;
|
||||
}
|
||||
}
|
||||
|
||||
SequenceWidget::SequenceWidget(QWidget *parent, SceneSequenceSwitch *s,
|
||||
bool extendSequence, bool editExtendMode,
|
||||
bool showExtendText)
|
||||
: SwitchWidget(parent, s, !extendSequence, true)
|
||||
{
|
||||
this->setParent(parent);
|
||||
|
||||
delay = new DurationSelection();
|
||||
startScenes = new QComboBox();
|
||||
interruptible = new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.sceneSequenceTab.interruptible"));
|
||||
extendText = new QLabel();
|
||||
extend = new QPushButton();
|
||||
reduce = new QPushButton();
|
||||
|
||||
extend->setProperty("themeID",
|
||||
QVariant(QStringLiteral("addIconSmall")));
|
||||
reduce->setProperty("themeID",
|
||||
QVariant(QStringLiteral("removeIconSmall")));
|
||||
|
||||
extend->setMaximumSize(22, 22);
|
||||
reduce->setMaximumSize(22, 22);
|
||||
|
||||
// We need to extend the generic SwitchWidget::SceneChanged()
|
||||
// with our own SequenceWidget::SceneChanged()
|
||||
// so the old singal / slot needs to be disconnected
|
||||
scenes->disconnect();
|
||||
QWidget::connect(scenes, SIGNAL(currentTextChanged(const QString &)),
|
||||
this, SLOT(SceneChanged(const QString &)));
|
||||
|
||||
QWidget::connect(delay, SIGNAL(DurationChanged(double)), this,
|
||||
SLOT(DelayChanged(double)));
|
||||
QWidget::connect(delay, SIGNAL(UnitChanged(DurationUnit)), this,
|
||||
SLOT(DelayUnitsChanged(DurationUnit)));
|
||||
QWidget::connect(startScenes,
|
||||
SIGNAL(currentTextChanged(const QString &)), this,
|
||||
SLOT(StartSceneChanged(const QString &)));
|
||||
QWidget::connect(interruptible, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(InterruptibleChanged(int)));
|
||||
|
||||
QWidget::connect(extend, SIGNAL(clicked()), this,
|
||||
SLOT(ExtendClicked()));
|
||||
QWidget::connect(reduce, SIGNAL(clicked()), this,
|
||||
SLOT(ReduceClicked()));
|
||||
|
||||
populateSceneSelection(startScenes);
|
||||
interruptible->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.sceneSequenceTab.interruptibleHint"));
|
||||
|
||||
// The extended sequence widgets never exist on their own and are always
|
||||
// place inside a non-extend sequence widget
|
||||
if (extendSequence) {
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{scenes}}", scenes},
|
||||
{"{{delay}}", delay},
|
||||
{"{{transitions}}", transitions}};
|
||||
placeWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.sceneSequenceTab.extendEntry"),
|
||||
mainLayout, widgetPlaceholders);
|
||||
setLayout(mainLayout);
|
||||
} else {
|
||||
QHBoxLayout *startSequence = new QHBoxLayout;
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{startScenes}}", startScenes},
|
||||
{"{{scenes}}", scenes},
|
||||
{"{{delay}}", delay},
|
||||
{"{{transitions}}", transitions},
|
||||
{"{{interruptible}}", interruptible}};
|
||||
placeWidgets(obs_module_text(
|
||||
"AdvSceneSwitcher.sceneSequenceTab.entry"),
|
||||
startSequence, widgetPlaceholders);
|
||||
|
||||
// The exetend widgets placed here
|
||||
extendSequenceLayout = new QVBoxLayout;
|
||||
if (s) {
|
||||
if (!editExtendMode) {
|
||||
extendText->setText(makeExtendText(
|
||||
s->extendedSequence.get()));
|
||||
} else {
|
||||
auto cur = s->extendedSequence.get();
|
||||
while (cur != nullptr) {
|
||||
extendSequenceLayout->addWidget(
|
||||
new SequenceWidget(parent, cur,
|
||||
true, true));
|
||||
cur = cur->extendedSequence.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QHBoxLayout *extendSequenceControlsLayout = new QHBoxLayout;
|
||||
if (editExtendMode) {
|
||||
extendSequenceControlsLayout->addWidget(extend);
|
||||
extendSequenceControlsLayout->addWidget(reduce);
|
||||
}
|
||||
extendSequenceControlsLayout->addStretch();
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(startSequence);
|
||||
mainLayout->addLayout(extendSequenceLayout);
|
||||
mainLayout->addWidget(extendText);
|
||||
mainLayout->addLayout(extendSequenceControlsLayout);
|
||||
setLayout(mainLayout);
|
||||
}
|
||||
|
||||
switchData = s;
|
||||
UpdateWidgetStatus(showExtendText);
|
||||
|
||||
loading = false;
|
||||
}
|
||||
|
||||
SceneSequenceSwitch *SequenceWidget::getSwitchData()
|
||||
{
|
||||
return switchData;
|
||||
}
|
||||
|
||||
void SequenceWidget::setSwitchData(SceneSequenceSwitch *s)
|
||||
{
|
||||
switchData = s;
|
||||
}
|
||||
|
||||
void SequenceWidget::swapSwitchData(SequenceWidget *s1, SequenceWidget *s2)
|
||||
{
|
||||
SwitchWidget::swapSwitchData(s1, s2);
|
||||
|
||||
SceneSequenceSwitch *t = s1->getSwitchData();
|
||||
s1->setSwitchData(s2->getSwitchData());
|
||||
s2->setSwitchData(t);
|
||||
}
|
||||
|
||||
void SequenceWidget::DelayChanged(double sec)
|
||||
{
|
||||
if (loading || !switchData) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->delay.seconds = sec;
|
||||
}
|
||||
|
||||
void SequenceWidget::DelayUnitsChanged(DurationUnit unit)
|
||||
{
|
||||
if (loading || !switchData) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->delay.displayUnit = unit;
|
||||
}
|
||||
|
||||
void SequenceWidget::setExtendedSequenceStartScene()
|
||||
{
|
||||
switchData->extendedSequence->startScene = switchData->scene;
|
||||
switchData->extendedSequence->startTargetType = SwitchTargetType::Scene;
|
||||
|
||||
if (switchData->targetType == SwitchTargetType::SceneGroup) {
|
||||
switchData->extendedSequence->startScene = nullptr;
|
||||
switchData->extendedSequence->startTargetType =
|
||||
SwitchTargetType::SceneGroup;
|
||||
}
|
||||
}
|
||||
|
||||
void SequenceWidget::SceneChanged(const QString &text)
|
||||
{
|
||||
if (loading || !switchData) {
|
||||
return;
|
||||
}
|
||||
|
||||
SwitchWidget::SceneChanged(text);
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
if (switchData->extendedSequence) {
|
||||
setExtendedSequenceStartScene();
|
||||
}
|
||||
}
|
||||
|
||||
void SequenceWidget::StartSceneChanged(const QString &text)
|
||||
{
|
||||
if (loading || !switchData) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->startScene = GetWeakSourceByQString(text);
|
||||
}
|
||||
|
||||
void SequenceWidget::InterruptibleChanged(int state)
|
||||
{
|
||||
if (loading || !switchData) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->interruptible = state;
|
||||
|
||||
auto cur = switchData->extendedSequence.get();
|
||||
while (cur != nullptr) {
|
||||
cur->interruptible = state;
|
||||
cur = cur->extendedSequence.get();
|
||||
}
|
||||
}
|
||||
|
||||
void SequenceWidget::UpdateWidgetStatus(bool showExtendText)
|
||||
{
|
||||
if (showExtendText) {
|
||||
extendText->setText(
|
||||
makeExtendText(switchData->extendedSequence.get()));
|
||||
}
|
||||
|
||||
delay->SetDuration(switchData->delay);
|
||||
startScenes->setCurrentText(
|
||||
GetWeakSourceName(switchData->startScene).c_str());
|
||||
interruptible->setChecked(switchData->interruptible);
|
||||
|
||||
SwitchWidget::showSwitchData();
|
||||
}
|
||||
|
||||
void SequenceWidget::ExtendClicked()
|
||||
{
|
||||
if (loading || !switchData) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto es = switchData->extend();
|
||||
|
||||
SequenceWidget *ew = new SequenceWidget(this->parentWidget(), es, true);
|
||||
extendSequenceLayout->addWidget(ew);
|
||||
}
|
||||
|
||||
void SequenceWidget::ReduceClicked()
|
||||
{
|
||||
if (loading || !switchData) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->reduce();
|
||||
|
||||
int count = extendSequenceLayout->count();
|
||||
auto item = extendSequenceLayout->takeAt(count - 1);
|
||||
if (item) {
|
||||
item->widget()->setVisible(false);
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user