Compare commits

...

2 Commits

Author SHA1 Message Date
WarmUpTill
214821b69f UI rework (#44)
* rework general tab UI

* rework audio tab UI

* rework media tab UI

* rework time tab UI

* rework random tab UI

* rework window tab UI

* rework sreen region tab UI

* rework sequence tab UI

* rework transition tab UI

* adjust log messages to new format

* fix include path and warning

* highlight widgets to guide users (can be disabled)

* add helper frame for screen region tab

* rename main SceneSwitcher widget to AdvSceneSwitcher to resolve naming conflicts with the frontend tools on certain platforms (e.g. Debian 10)

* add media state 'any'

* adjust media switch handling to support vlc source
2020-10-31 16:25:44 +01:00
WarmUpTill
7edb6eb6c1 add handling of window title of metro apps 2020-10-24 15:23:08 +02:00
36 changed files with 4036 additions and 4172 deletions

View File

@@ -46,7 +46,7 @@ if(BUILD_OUT_OF_TREE)
src/headers/switch-time.hpp src/headers/switch-time.hpp
src/headers/switch-transitions.hpp src/headers/switch-transitions.hpp
src/headers/switch-window.hpp src/headers/switch-window.hpp
src/headers/swtich-sequence.hpp src/headers/switch-sequence.hpp
src/headers/switch-generic.hpp src/headers/switch-generic.hpp
) )
@@ -70,7 +70,9 @@ if(BUILD_OUT_OF_TREE)
src/switch-random.cpp src/switch-random.cpp
src/switch-time.cpp src/switch-time.cpp
src/switch-audio.cpp src/switch-audio.cpp
src/switch-generic.cpp
src/curl-helper.cpp src/curl-helper.cpp
src/volume-control.cpp
) )
set(advanced-scene-switcher_UI set(advanced-scene-switcher_UI
@@ -194,7 +196,7 @@ else ()
src/headers/switch-time.hpp src/headers/switch-time.hpp
src/headers/switch-transitions.hpp src/headers/switch-transitions.hpp
src/headers/switch-window.hpp src/headers/switch-window.hpp
src/headers/swtich-sequence.hpp src/headers/switch-sequence.hpp
src/headers/switch-generic.hpp src/headers/switch-generic.hpp
) )
@@ -218,6 +220,7 @@ else ()
src/switch-random.cpp src/switch-random.cpp
src/switch-time.cpp src/switch-time.cpp
src/switch-audio.cpp src/switch-audio.cpp
src/switch-generic.cpp
src/curl-helper.cpp src/curl-helper.cpp
src/volume-control.cpp src/volume-control.cpp
) )

File diff suppressed because it is too large Load Diff

View File

@@ -1,21 +1,13 @@
#include <QMainWindow> #include <QMainWindow>
#include <QDir>
#include <QAction> #include <QAction>
#include <QtGui/qstandarditemmodel.h>
#include <condition_variable> #include <QPropertyAnimation>
#include <chrono> #include <QGraphicsColorizeEffect>
#include <vector>
#include <mutex>
#include <thread>
#include <obs-frontend-api.h> #include <obs-frontend-api.h>
#include <obs-module.h>
#include <obs.hpp>
#include <util/util.hpp> #include <util/util.hpp>
#include "headers/switcher-data-structs.hpp"
#include "headers/advanced-scene-switcher.hpp" #include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp"
#include "headers/curl-helper.hpp" #include "headers/curl-helper.hpp"
SwitcherData *switcher = nullptr; SwitcherData *switcher = nullptr;
@@ -23,8 +15,8 @@ SwitcherData *switcher = nullptr;
/******************************************************************************** /********************************************************************************
* Create the Advanced Scene Switcher settings window * Create the Advanced Scene Switcher settings window
********************************************************************************/ ********************************************************************************/
SceneSwitcher::SceneSwitcher(QWidget *parent) AdvSceneSwitcher::AdvSceneSwitcher(QWidget *parent)
: QDialog(parent), ui(new Ui_SceneSwitcher) : QDialog(parent), ui(new Ui_AdvSceneSwitcher)
{ {
ui->setupUi(this); ui->setupUi(this);
@@ -34,46 +26,7 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
loadUI(); loadUI();
} }
void SceneSwitcher::populateSceneSelection(QComboBox *sel, bool addPrevious) void AdvSceneSwitcher::loadUI()
{
BPtr<char *> scenes = obs_frontend_get_scene_names();
char **temp = scenes;
while (*temp) {
const char *name = *temp;
sel->addItem(name);
temp++;
}
if (addPrevious)
sel->addItem(previous_scene_name);
}
void SceneSwitcher::populateTransitionSelection(QComboBox *sel)
{
obs_frontend_source_list *transitions = new obs_frontend_source_list();
obs_frontend_get_transitions(transitions);
for (size_t i = 0; i < transitions->sources.num; i++) {
const char *name =
obs_source_get_name(transitions->sources.array[i]);
sel->addItem(name);
}
obs_frontend_source_list_free(transitions);
}
void SceneSwitcher::populateWindowSelection(QComboBox *sel)
{
std::vector<std::string> windows;
GetWindowList(windows);
sort(windows.begin(), windows.end());
for (std::string &window : windows) {
sel->addItem(window.c_str());
}
}
void SceneSwitcher::loadUI()
{ {
#if __APPLE__ #if __APPLE__
setMinimumHeight(700); setMinimumHeight(700);
@@ -97,6 +50,210 @@ void SceneSwitcher::loadUI()
loading = false; loading = false;
} }
/********************************************************************************
* UI helpers
********************************************************************************/
void addSelectionEntry(QComboBox *sel, const char *description,
const char *tooltip = "")
{
sel->addItem(description);
if (strcmp(tooltip, "") != 0) {
sel->setItemData(0, tooltip, Qt::ToolTipRole);
}
QStandardItemModel *model =
qobject_cast<QStandardItemModel *>(sel->model());
QModelIndex firstIndex =
model->index(0, sel->modelColumn(), sel->rootModelIndex());
QStandardItem *firstItem = model->itemFromIndex(firstIndex);
firstItem->setSelectable(false);
firstItem->setEnabled(false);
}
void AdvSceneSwitcher::populateSceneSelection(QComboBox *sel, bool addPrevious,
bool addSelect)
{
if (addSelect)
addSelectionEntry(sel, "--select scene--",
"invalid entries will not be saved");
BPtr<char *> scenes = obs_frontend_get_scene_names();
char **temp = scenes;
while (*temp) {
const char *name = *temp;
sel->addItem(name);
temp++;
}
if (addPrevious)
sel->addItem(previous_scene_name);
}
void AdvSceneSwitcher::populateTransitionSelection(QComboBox *sel,
bool addSelect)
{
if (addSelect)
addSelectionEntry(sel, "--select transition--");
obs_frontend_source_list *transitions = new obs_frontend_source_list();
obs_frontend_get_transitions(transitions);
for (size_t i = 0; i < transitions->sources.num; i++) {
const char *name =
obs_source_get_name(transitions->sources.array[i]);
sel->addItem(name);
}
obs_frontend_source_list_free(transitions);
}
void AdvSceneSwitcher::populateWindowSelection(QComboBox *sel, bool addSelect)
{
if (addSelect)
addSelectionEntry(sel, "--select window--");
std::vector<std::string> windows;
GetWindowList(windows);
sort(windows.begin(), windows.end());
for (std::string &window : windows) {
sel->addItem(window.c_str());
}
#ifdef WIN32
sel->setItemData(
0,
"Use \"OBS\" to specify OBS window\nUse \"Task Switching\"to specify ALT + TAB",
Qt::ToolTipRole);
#endif
}
void AdvSceneSwitcher::populateAudioSelection(QComboBox *sel, bool addSelect)
{
if (addSelect)
addSelectionEntry(sel, "--select audio source--",
"invalid entries will not be saved");
auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */
{
QComboBox *combo = reinterpret_cast<QComboBox *>(data);
uint32_t flags = obs_source_get_output_flags(source);
if ((flags & OBS_SOURCE_AUDIO) != 0) {
const char *name = obs_source_get_name(source);
combo->addItem(name);
}
return true;
};
obs_enum_sources(sourceEnum, sel);
}
void AdvSceneSwitcher::populateMediaSelection(QComboBox *sel, bool addSelect)
{
if (addSelect)
addSelectionEntry(sel, "--select media source--",
"invalid entries will not be saved");
auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */
{
QComboBox *combo = reinterpret_cast<QComboBox *>(data);
std::string sourceId = obs_source_get_id(source);
if (sourceId.compare("ffmpeg_source") == 0 ||
sourceId.compare("vlc_source") == 0) {
const char *name = obs_source_get_name(source);
combo->addItem(name);
}
return true;
};
obs_enum_sources(sourceEnum, sel);
}
void AdvSceneSwitcher::populateProcessSelection(QComboBox *sel, bool addSelect)
{
if (addSelect)
addSelectionEntry(sel, "--select process--");
QStringList processes;
GetProcessList(processes);
for (QString &process : processes)
sel->addItem(process);
}
bool AdvSceneSwitcher::listMoveUp(QListWidget *list)
{
int index = list->currentRow();
if (index == -1 || index == 0)
return false;
QWidget *row = list->itemWidget(list->currentItem());
QListWidgetItem *itemN = list->currentItem()->clone();
list->insertItem(index - 1, itemN);
list->setItemWidget(itemN, row);
list->takeItem(index + 1);
list->setCurrentRow(index - 1);
return true;
}
bool AdvSceneSwitcher::listMoveDown(QListWidget *list)
{
int index = list->currentRow();
if (index == -1 || index == list->count() - 1)
return false;
QWidget *row = list->itemWidget(list->currentItem());
QListWidgetItem *itemN = list->currentItem()->clone();
list->insertItem(index + 2, itemN);
list->setItemWidget(itemN, row);
list->takeItem(index);
list->setCurrentRow(index + 1);
return true;
}
QMetaObject::Connection AdvSceneSwitcher::PulseWidget(QWidget *widget,
QColor endColor,
QColor startColor,
QString specifier)
{
if (switcher->disableHints)
return QMetaObject::Connection();
widget->setStyleSheet(specifier + "{ \
border-style: outset; \
border-width: 2px; \
border-radius: 10px; \
border-color: rgb(0,0,0,0) \
}");
QGraphicsColorizeEffect *eEffect = new QGraphicsColorizeEffect(widget);
widget->setGraphicsEffect(eEffect);
QPropertyAnimation *paAnimation =
new QPropertyAnimation(eEffect, "color");
paAnimation->setStartValue(startColor);
paAnimation->setEndValue(endColor);
paAnimation->setDuration(1000);
// play backward to return to original state on timer end
paAnimation->setDirection(QAbstractAnimation::Backward);
auto con = QWidget::connect(
paAnimation, &QPropertyAnimation::finished, [paAnimation]() {
QTimer::singleShot(1000, [paAnimation] {
paAnimation->start();
});
});
paAnimation->start();
return con;
}
/******************************************************************************** /********************************************************************************
* Saving and loading * Saving and loading
********************************************************************************/ ********************************************************************************/
@@ -169,7 +326,7 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
********************************************************************************/ ********************************************************************************/
void SwitcherData::Thread() void SwitcherData::Thread()
{ {
blog(LOG_INFO, "Advanced Scene Switcher started"); blog(LOG_INFO, "started");
int sleep = 0; int sleep = 0;
while (true) { while (true) {
@@ -182,15 +339,11 @@ void SwitcherData::Thread()
if (sleep > interval) { if (sleep > interval) {
duration = std::chrono::milliseconds(sleep); duration = std::chrono::milliseconds(sleep);
if (verbose) if (verbose)
blog(LOG_INFO, blog(LOG_INFO, "sleep for %d", sleep);
"Advanced Scene Switcher sleep for %d",
sleep);
} else { } else {
duration = std::chrono::milliseconds(interval); duration = std::chrono::milliseconds(interval);
if (verbose) if (verbose)
blog(LOG_INFO, blog(LOG_INFO, "sleep for %d", interval);
"Advanced Scene Switcher sleep for %d",
interval);
} }
sleep = 0; sleep = 0;
switcher->Prune(); switcher->Prune();
@@ -239,7 +392,7 @@ void SwitcherData::Thread()
break; break;
case round_trip_func: case round_trip_func:
checkSceneSequence(match, scene, transition, checkSceneSequence(match, scene, transition,
lock); lock);
if (sceneChangedDuringWait()) //scene might have changed during the sleep if (sceneChangedDuringWait()) //scene might have changed during the sleep
{ {
goto startLoop; goto startLoop;
@@ -279,7 +432,7 @@ void SwitcherData::Thread()
} }
} }
endLoop: endLoop:
blog(LOG_INFO, "Advanced Scene Switcher stopped"); blog(LOG_INFO, "stopped");
} }
void switchScene(OBSWeakSource &scene, OBSWeakSource &transition, void switchScene(OBSWeakSource &scene, OBSWeakSource &transition,
@@ -304,8 +457,7 @@ void switchScene(OBSWeakSource &scene, OBSWeakSource &transition,
lock.lock(); lock.lock();
if (switcher->verbose) if (switcher->verbose)
blog(LOG_INFO, blog(LOG_INFO, "switched scene");
"Advanced Scene Switcher switched scene");
} }
obs_source_release(currentSource); obs_source_release(currentSource);
obs_source_release(source); obs_source_release(source);
@@ -378,8 +530,9 @@ void handleSceneChange(SwitcherData *s)
s->PreviousScene2 = ws; s->PreviousScene2 = ws;
} }
//reset autostart //reset events only hanled on scene change
s->autoStartedRecently = false; s->autoStartedRecently = false;
s->changedDefTransitionRecently = false;
} }
void setLiveTime(SwitcherData *s) void setLiveTime(SwitcherData *s)
@@ -429,7 +582,7 @@ extern "C" void InitSceneSwitcher()
QMainWindow *window = QMainWindow *window =
(QMainWindow *)obs_frontend_get_main_window(); (QMainWindow *)obs_frontend_get_main_window();
SceneSwitcher ss(window); AdvSceneSwitcher ss(window);
ss.exec(); ss.exec();
}; };

View File

@@ -23,11 +23,11 @@ bool resolveCurl()
(cleanupFunction)loaded_curl_lib->resolve("curl_easy_cleanup"); (cleanupFunction)loaded_curl_lib->resolve("curl_easy_cleanup");
if (f_curl_init && f_curl_setopt && f_curl_perform && f_curl_cleanup) { if (f_curl_init && f_curl_setopt && f_curl_perform && f_curl_cleanup) {
blog(LOG_INFO, "curl loaded successfully"); blog(LOG_INFO, "[adv-ss] curl loaded successfully");
return true; return true;
} }
blog(LOG_INFO, "curl symbols not resolved"); blog(LOG_INFO, "[adv-ss] curl symbols not resolved");
return false; return false;
} }
@@ -43,13 +43,13 @@ bool loadCurl()
#endif #endif
for (QString path : locations) { for (QString path : locations) {
blog(LOG_INFO, "trying '%s'", path.toUtf8().constData()); blog(LOG_INFO, "[adv-ss] trying '%s'", path.toUtf8().constData());
QFileInfo libPath( QFileInfo libPath(
QDir(path).absoluteFilePath(curl_library_name)); QDir(path).absoluteFilePath(curl_library_name));
if (libPath.exists() && libPath.isFile()) { if (libPath.exists() && libPath.isFile()) {
QString libFilePath = libPath.absoluteFilePath(); QString libFilePath = libPath.absoluteFilePath();
blog(LOG_INFO, "found curl library at '%s'", blog(LOG_INFO, "[adv-ss] found curl library at '%s'",
libFilePath.toUtf8().constData()); libFilePath.toUtf8().constData());
loaded_curl_lib = new QLibrary(libFilePath, nullptr); loaded_curl_lib = new QLibrary(libFilePath, nullptr);
@@ -62,6 +62,6 @@ bool loadCurl()
} }
} }
blog(LOG_ERROR, "can't find the curl library"); blog(LOG_WARNING, "[adv-ss] can't find the curl library");
return false; return false;
} }

View File

@@ -1,16 +1,17 @@
#include <obs-module.h>
#include <QFileDialog> #include <QFileDialog>
#include <QTextStream>
#include <QMessageBox> #include <QMessageBox>
#include "headers/advanced-scene-switcher.hpp" #include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp"
void SceneSwitcher::on_close_clicked() QMetaObject::Connection inactivePluse;
void AdvSceneSwitcher::on_close_clicked()
{ {
done(0); done(0);
} }
void SceneSwitcher::UpdateNonMatchingScene(const QString &name) void AdvSceneSwitcher::UpdateNonMatchingScene(const QString &name)
{ {
obs_source_t *scene = obs_get_source_by_name(name.toUtf8().constData()); obs_source_t *scene = obs_get_source_by_name(name.toUtf8().constData());
obs_weak_source_t *ws = obs_source_get_weak_source(scene); obs_weak_source_t *ws = obs_source_get_weak_source(scene);
@@ -21,7 +22,7 @@ void SceneSwitcher::UpdateNonMatchingScene(const QString &name)
obs_source_release(scene); obs_source_release(scene);
} }
void SceneSwitcher::on_noMatchDontSwitch_clicked() void AdvSceneSwitcher::on_noMatchDontSwitch_clicked()
{ {
if (loading) if (loading)
return; return;
@@ -29,9 +30,10 @@ void SceneSwitcher::on_noMatchDontSwitch_clicked()
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->switchIfNotMatching = NO_SWITCH; switcher->switchIfNotMatching = NO_SWITCH;
ui->noMatchSwitchScene->setEnabled(false); ui->noMatchSwitchScene->setEnabled(false);
ui->randomDisabledWarning->setVisible(true);
} }
void SceneSwitcher::on_noMatchSwitch_clicked() void AdvSceneSwitcher::on_noMatchSwitch_clicked()
{ {
if (loading) if (loading)
return; return;
@@ -40,9 +42,10 @@ void SceneSwitcher::on_noMatchSwitch_clicked()
switcher->switchIfNotMatching = SWITCH; switcher->switchIfNotMatching = SWITCH;
ui->noMatchSwitchScene->setEnabled(true); ui->noMatchSwitchScene->setEnabled(true);
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText()); UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
ui->randomDisabledWarning->setVisible(true);
} }
void SceneSwitcher::on_noMatchRandomSwitch_clicked() void AdvSceneSwitcher::on_noMatchRandomSwitch_clicked()
{ {
if (loading) if (loading)
return; return;
@@ -50,9 +53,10 @@ void SceneSwitcher::on_noMatchRandomSwitch_clicked()
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->switchIfNotMatching = RANDOM_SWITCH; switcher->switchIfNotMatching = RANDOM_SWITCH;
ui->noMatchSwitchScene->setEnabled(false); ui->noMatchSwitchScene->setEnabled(false);
ui->randomDisabledWarning->setVisible(false);
} }
void SceneSwitcher::on_startupBehavior_currentIndexChanged(int index) void AdvSceneSwitcher::on_startupBehavior_currentIndexChanged(int index)
{ {
if (loading) if (loading)
return; return;
@@ -61,7 +65,8 @@ void SceneSwitcher::on_startupBehavior_currentIndexChanged(int index)
switcher->startupBehavior = (StartupBehavior)index; switcher->startupBehavior = (StartupBehavior)index;
} }
void SceneSwitcher::on_noMatchSwitchScene_currentTextChanged(const QString &text) void AdvSceneSwitcher::on_noMatchSwitchScene_currentTextChanged(
const QString &text)
{ {
if (loading) if (loading)
return; return;
@@ -70,7 +75,7 @@ void SceneSwitcher::on_noMatchSwitchScene_currentTextChanged(const QString &text
UpdateNonMatchingScene(text); UpdateNonMatchingScene(text);
} }
void SceneSwitcher::on_checkInterval_valueChanged(int value) void AdvSceneSwitcher::on_checkInterval_valueChanged(int value)
{ {
if (loading) if (loading)
return; return;
@@ -79,19 +84,22 @@ void SceneSwitcher::on_checkInterval_valueChanged(int value)
switcher->interval = value; switcher->interval = value;
} }
void SceneSwitcher::SetStarted() void AdvSceneSwitcher::SetStarted()
{ {
ui->toggleStartButton->setText("Stop"); ui->toggleStartButton->setText("Stop");
ui->pluginRunningText->setText("Active"); ui->pluginRunningText->setText("Active");
ui->pluginRunningText->disconnect(inactivePluse);
} }
void SceneSwitcher::SetStopped() void AdvSceneSwitcher::SetStopped()
{ {
ui->toggleStartButton->setText("Start"); ui->toggleStartButton->setText("Start");
ui->pluginRunningText->setText("Inactive"); ui->pluginRunningText->setText("Inactive");
inactivePluse = PulseWidget(ui->pluginRunningText, QColor(Qt::red),
QColor(0, 0, 0, 0), "QLabel ");
} }
void SceneSwitcher::on_toggleStartButton_clicked() void AdvSceneSwitcher::on_toggleStartButton_clicked()
{ {
if (switcher->th && switcher->th->isRunning()) { if (switcher->th && switcher->th->isRunning()) {
switcher->Stop(); switcher->Stop();
@@ -102,12 +110,12 @@ void SceneSwitcher::on_toggleStartButton_clicked()
} }
} }
void SceneSwitcher::closeEvent(QCloseEvent *) void AdvSceneSwitcher::closeEvent(QCloseEvent *)
{ {
obs_frontend_save(); obs_frontend_save();
} }
void SceneSwitcher::on_autoStopScenes_currentTextChanged(const QString &text) void AdvSceneSwitcher::on_autoStopScenes_currentTextChanged(const QString &text)
{ {
if (loading) if (loading)
return; return;
@@ -116,7 +124,7 @@ void SceneSwitcher::on_autoStopScenes_currentTextChanged(const QString &text)
UpdateAutoStopScene(text); UpdateAutoStopScene(text);
} }
void SceneSwitcher::on_autoStopSceneCheckBox_stateChanged(int state) void AdvSceneSwitcher::on_autoStopSceneCheckBox_stateChanged(int state)
{ {
if (loading) if (loading)
return; return;
@@ -133,7 +141,7 @@ void SceneSwitcher::on_autoStopSceneCheckBox_stateChanged(int state)
} }
} }
void SceneSwitcher::UpdateAutoStopScene(const QString &name) void AdvSceneSwitcher::UpdateAutoStopScene(const QString &name)
{ {
obs_source_t *scene = obs_get_source_by_name(name.toUtf8().constData()); obs_source_t *scene = obs_get_source_by_name(name.toUtf8().constData());
obs_weak_source_t *ws = obs_source_get_weak_source(scene); obs_weak_source_t *ws = obs_source_get_weak_source(scene);
@@ -159,7 +167,7 @@ void SwitcherData::autoStopStreamAndRecording()
obs_weak_source_release(ws); obs_weak_source_release(ws);
} }
void SceneSwitcher::on_autoStartType_currentIndexChanged(int index) void AdvSceneSwitcher::on_autoStartType_currentIndexChanged(int index)
{ {
if (loading) if (loading)
return; return;
@@ -167,7 +175,7 @@ void SceneSwitcher::on_autoStartType_currentIndexChanged(int index)
switcher->autoStartType = (AutoStartType)index; switcher->autoStartType = (AutoStartType)index;
} }
void SceneSwitcher::on_autoStartScenes_currentTextChanged(const QString &text) void AdvSceneSwitcher::on_autoStartScenes_currentTextChanged(const QString &text)
{ {
if (loading) if (loading)
return; return;
@@ -176,7 +184,7 @@ void SceneSwitcher::on_autoStartScenes_currentTextChanged(const QString &text)
UpdateAutoStartScene(text); UpdateAutoStartScene(text);
} }
void SceneSwitcher::on_autoStartSceneCheckBox_stateChanged(int state) void AdvSceneSwitcher::on_autoStartSceneCheckBox_stateChanged(int state)
{ {
if (loading) if (loading)
return; return;
@@ -196,7 +204,7 @@ void SceneSwitcher::on_autoStartSceneCheckBox_stateChanged(int state)
} }
} }
void SceneSwitcher::UpdateAutoStartScene(const QString &name) void AdvSceneSwitcher::UpdateAutoStartScene(const QString &name)
{ {
obs_source_t *scene = obs_get_source_by_name(name.toUtf8().constData()); obs_source_t *scene = obs_get_source_by_name(name.toUtf8().constData());
obs_weak_source_t *ws = obs_source_get_weak_source(scene); obs_weak_source_t *ws = obs_source_get_weak_source(scene);
@@ -231,16 +239,21 @@ void SwitcherData::autoStartStreamRecording()
autoStartedRecently = true; autoStartedRecently = true;
} }
void SceneSwitcher::on_verboseLogging_stateChanged(int state) void AdvSceneSwitcher::on_verboseLogging_stateChanged(int state)
{ {
if (loading) if (loading)
return; return;
std::lock_guard<std::mutex> lock(switcher->m);
switcher->verbose = state; switcher->verbose = state;
} }
void SceneSwitcher::on_exportSettings_clicked() void AdvSceneSwitcher::on_uiHintsDisable_stateChanged(int state)
{
if (loading)
return;
switcher->disableHints = state;
}
void AdvSceneSwitcher::on_exportSettings_clicked()
{ {
QString directory = QFileDialog::getSaveFileName( QString directory = QFileDialog::getSaveFileName(
this, tr("Export Advanced Scene Switcher settings to file ..."), this, tr("Export Advanced Scene Switcher settings to file ..."),
@@ -274,7 +287,7 @@ void SceneSwitcher::on_exportSettings_clicked()
obs_data_release(obj); obs_data_release(obj);
} }
void SceneSwitcher::on_importSettings_clicked() void AdvSceneSwitcher::on_importSettings_clicked()
{ {
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
@@ -378,13 +391,13 @@ int findTabIndex(QTabBar *bar, int pos)
} }
} }
if (at == -1) if (at == -1)
blog(LOG_INFO, "Advanced Scene Switcher failed to find tab %s", blog(LOG_INFO, "failed to find tab %s",
tabName.toUtf8().constData()); tabName.toUtf8().constData());
return at; return at;
} }
void SceneSwitcher::setTabOrder() void AdvSceneSwitcher::setTabOrder()
{ {
QTabBar *bar = ui->tabWidget->tabBar(); QTabBar *bar = ui->tabWidget->tabBar();
for (int i = 0; i < bar->count(); ++i) { for (int i = 0; i < bar->count(); ++i) {
@@ -394,10 +407,10 @@ void SceneSwitcher::setTabOrder()
bar->moveTab(curPos, i); bar->moveTab(curPos, i);
} }
connect(bar, &QTabBar::tabMoved, this, &SceneSwitcher::on_tabMoved); connect(bar, &QTabBar::tabMoved, this, &AdvSceneSwitcher::on_tabMoved);
} }
void SceneSwitcher::on_tabMoved(int from, int to) void AdvSceneSwitcher::on_tabMoved(int from, int to)
{ {
if (loading) if (loading)
return; return;
@@ -432,6 +445,7 @@ void SwitcherData::saveGeneralSettings(obs_data_t *obj)
autoStartSceneName.c_str()); autoStartSceneName.c_str());
obs_data_set_bool(obj, "verbose", switcher->verbose); obs_data_set_bool(obj, "verbose", switcher->verbose);
obs_data_set_bool(obj, "disableHints", switcher->disableHints);
obs_data_set_int(obj, "priority0", obs_data_set_int(obj, "priority0",
switcher->functionNamesByPriority[0]); switcher->functionNamesByPriority[0]);
@@ -503,6 +517,7 @@ void SwitcherData::loadGeneralSettings(obs_data_t *obj)
switcher->autoStartScene = GetWeakSourceByName(autoStartScene.c_str()); switcher->autoStartScene = GetWeakSourceByName(autoStartScene.c_str());
switcher->verbose = obs_data_get_bool(obj, "verbose"); switcher->verbose = obs_data_get_bool(obj, "verbose");
switcher->disableHints = obs_data_get_bool(obj, "disableHints");
obs_data_set_default_int(obj, "priority0", default_priority_0); obs_data_set_default_int(obj, "priority0", default_priority_0);
obs_data_set_default_int(obj, "priority1", default_priority_1); obs_data_set_default_int(obj, "priority1", default_priority_1);
@@ -590,7 +605,7 @@ void SwitcherData::loadGeneralSettings(obs_data_t *obj)
(int)(obs_data_get_int(obj, "audioTabPos"))); (int)(obs_data_get_int(obj, "audioTabPos")));
} }
void SceneSwitcher::setupGeneralTab() void AdvSceneSwitcher::setupGeneralTab()
{ {
populateSceneSelection(ui->noMatchSwitchScene, false); populateSceneSelection(ui->noMatchSwitchScene, false);
populateSceneSelection(ui->autoStopScenes, false); populateSceneSelection(ui->autoStopScenes, false);
@@ -638,6 +653,7 @@ void SceneSwitcher::setupGeneralTab()
} }
ui->verboseLogging->setChecked(switcher->verbose); ui->verboseLogging->setChecked(switcher->verbose);
ui->uiHintsDisable->setChecked(switcher->disableHints);
for (int p : switcher->functionNamesByPriority) { for (int p : switcher->functionNamesByPriority) {
std::string s = ""; std::string s = "";

View File

@@ -1,63 +1,44 @@
#pragma once #pragma once
#include <QDialog>
#include <memory>
#include <vector>
#include <string>
#ifdef BUILD_OUT_OF_TREE #ifdef BUILD_OUT_OF_TREE
#include "../../forms/ui_advanced-scene-switcher.h" #include "../../forms/ui_advanced-scene-switcher.h"
#else #else
#include "ui_advanced-scene-switcher.h" #include "ui_advanced-scene-switcher.h"
#endif #endif
#include "switcher-data-structs.hpp" #include "switcher-data-structs.hpp"
#include "volume-control.hpp"
#define blog(level, msg, ...) blog(level, "[adv-ss] " msg, ##__VA_ARGS__)
class QCloseEvent; class QCloseEvent;
/******************************************************************************* /*******************************************************************************
* Advanced Scene Switcher window * Advanced Scene Switcher window
*******************************************************************************/ *******************************************************************************/
class SceneSwitcher : public QDialog { class AdvSceneSwitcher : public QDialog {
Q_OBJECT Q_OBJECT
public: public:
std::unique_ptr<Ui_SceneSwitcher> ui; std::unique_ptr<Ui_AdvSceneSwitcher> ui;
VolControl *volMeter = nullptr;
bool loading = true; bool loading = true;
SceneSwitcher(QWidget *parent); AdvSceneSwitcher(QWidget *parent);
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
void SetStarted(); void SetStarted();
void SetStopped(); void SetStopped();
int FindByData(const QString &window);
int ScreenRegionFindByData(const QString &region);
int PauseScenesFindByData(const QString &scene); int PauseScenesFindByData(const QString &scene);
int PauseWindowsFindByData(const QString &window); int PauseWindowsFindByData(const QString &window);
int IgnoreWindowsFindByData(const QString &window); int IgnoreWindowsFindByData(const QString &window);
int SceneSequenceFindByData(const QString &scene1);
int SceneTransitionsFindByData(const QString &scene1,
const QString &scene2);
int DefaultTransitionsFindByData(const QString &scene);
int executableFindByData(const QString &exe);
int IgnoreIdleWindowsFindByData(const QString &window); int IgnoreIdleWindowsFindByData(const QString &window);
int randomFindByData(const QString &scene);
int timeFindByData(const timeTrigger &trigger, const QTime &time);
int audioFindByData(const QString &source, const int &volume);
void UpdateNonMatchingScene(const QString &name); void UpdateNonMatchingScene(const QString &name);
void UpdateAutoStopScene(const QString &name); void UpdateAutoStopScene(const QString &name);
void UpdateAutoStartScene(const QString &name); void UpdateAutoStartScene(const QString &name);
void UpdateIdleDataTransition(const QString &name); void UpdateIdleDataTransition(const QString &name);
void UpdateIdleDataScene(const QString &name); void UpdateIdleDataScene(const QString &name);
void SetAudioVolumeMeter(const QString &name);
void loadUI(); void loadUI();
void populateSceneSelection(QComboBox *sel, bool addPrevious);
void populateTransitionSelection(QComboBox *sel);
void populateWindowSelection(QComboBox *sel);
void setupGeneralTab(); void setupGeneralTab();
void setupTitleTab(); void setupTitleTab();
void setupExecutableTab(); void setupExecutableTab();
@@ -73,12 +54,31 @@ public:
void setupAudioTab(); void setupAudioTab();
void setTabOrder(); void setTabOrder();
static void populateSceneSelection(QComboBox *sel,
bool addPrevious = false,
bool addSelect = true);
static void populateTransitionSelection(QComboBox *sel,
bool addSelect = true);
static void populateWindowSelection(QComboBox *sel,
bool addSelect = true);
static void populateAudioSelection(QComboBox *sel,
bool addSelect = true);
static void populateMediaSelection(QComboBox *sel,
bool addSelect = true);
static void populateProcessSelection(QComboBox *sel,
bool addSelect = true);
QMetaObject::Connection PulseWidget(QWidget *widget, QColor endColor,
QColor = QColor(0, 0, 0, 0),
QString specifier = "QLabel ");
bool listMoveUp(QListWidget *list);
bool listMoveDown(QListWidget *list);
public slots: public slots:
void on_switches_currentRowChanged(int idx); void on_windowUp_clicked();
void on_up_clicked(); void on_windowDown_clicked();
void on_down_clicked(); void on_windowAdd_clicked();
void on_add_clicked(); void on_windowRemove_clicked();
void on_remove_clicked();
void on_noMatchDontSwitch_clicked(); void on_noMatchDontSwitch_clicked();
void on_noMatchSwitch_clicked(); void on_noMatchSwitch_clicked();
void on_noMatchRandomSwitch_clicked(); void on_noMatchRandomSwitch_clicked();
@@ -88,7 +88,8 @@ public slots:
void on_toggleStartButton_clicked(); void on_toggleStartButton_clicked();
void on_tabMoved(int from, int to); void on_tabMoved(int from, int to);
void on_screenRegions_currentRowChanged(int idx); void on_screenRegionSwitches_currentRowChanged(int idx);
void on_showFrame_clicked();
void on_screenRegionAdd_clicked(); void on_screenRegionAdd_clicked();
void on_screenRegionRemove_clicked(); void on_screenRegionRemove_clicked();
void on_screenRegionUp_clicked(); void on_screenRegionUp_clicked();
@@ -106,14 +107,12 @@ public slots:
void on_ignoreWindowsAdd_clicked(); void on_ignoreWindowsAdd_clicked();
void on_ignoreWindowsRemove_clicked(); void on_ignoreWindowsRemove_clicked();
void on_sceneSequences_currentRowChanged(int idx);
void on_sceneSequenceAdd_clicked(); void on_sceneSequenceAdd_clicked();
void on_sceneSequenceRemove_clicked(); void on_sceneSequenceRemove_clicked();
void on_sceneSequenceSave_clicked(); void on_sceneSequenceSave_clicked();
void on_sceneSequenceLoad_clicked(); void on_sceneSequenceLoad_clicked();
void on_sceneSequenceUp_clicked(); void on_sceneSequenceUp_clicked();
void on_sceneSequenceDown_clicked(); void on_sceneSequenceDown_clicked();
void on_sceneSequenceDelayUnits_currentIndexChanged(int index);
void on_autoStopSceneCheckBox_stateChanged(int state); void on_autoStopSceneCheckBox_stateChanged(int state);
void on_autoStopScenes_currentTextChanged(const QString &text); void on_autoStopScenes_currentTextChanged(const QString &text);
@@ -123,16 +122,19 @@ public slots:
void on_autoStartScenes_currentTextChanged(const QString &text); void on_autoStartScenes_currentTextChanged(const QString &text);
void on_verboseLogging_stateChanged(int state); void on_verboseLogging_stateChanged(int state);
void on_uiHintsDisable_stateChanged(int state);
void on_exportSettings_clicked(); void on_exportSettings_clicked();
void on_importSettings_clicked(); void on_importSettings_clicked();
void on_sceneTransitions_currentRowChanged(int idx);
void on_transitionsAdd_clicked(); void on_transitionsAdd_clicked();
void on_transitionsRemove_clicked(); void on_transitionsRemove_clicked();
void on_defaultTransitions_currentRowChanged(int idx); void on_transitionsUp_clicked();
void on_transitionsDown_clicked();
void on_defaultTransitionsAdd_clicked(); void on_defaultTransitionsAdd_clicked();
void on_defaultTransitionsRemove_clicked(); void on_defaultTransitionsRemove_clicked();
void on_defaultTransitionsUp_clicked();
void on_defaultTransitionsDown_clicked();
void on_transitionOverridecheckBox_stateChanged(int state); void on_transitionOverridecheckBox_stateChanged(int state);
void on_browseButton_clicked(); void on_browseButton_clicked();
@@ -146,7 +148,6 @@ public slots:
void on_executableDown_clicked(); void on_executableDown_clicked();
void on_executableAdd_clicked(); void on_executableAdd_clicked();
void on_executableRemove_clicked(); void on_executableRemove_clicked();
void on_executables_currentRowChanged(int idx);
void on_idleCheckBox_stateChanged(int state); void on_idleCheckBox_stateChanged(int state);
void on_idleTransitions_currentTextChanged(const QString &text); void on_idleTransitions_currentTextChanged(const QString &text);
@@ -158,7 +159,6 @@ public slots:
void on_randomAdd_clicked(); void on_randomAdd_clicked();
void on_randomRemove_clicked(); void on_randomRemove_clicked();
void on_randomScenesList_currentRowChanged(int idx);
void on_fileAdd_clicked(); void on_fileAdd_clicked();
void on_fileRemove_clicked(); void on_fileRemove_clicked();
@@ -167,14 +167,11 @@ public slots:
void on_fileUp_clicked(); void on_fileUp_clicked();
void on_fileDown_clicked(); void on_fileDown_clicked();
void on_mediaSwitches_currentRowChanged(int idx);
void on_mediaAdd_clicked(); void on_mediaAdd_clicked();
void on_mediaRemove_clicked(); void on_mediaRemove_clicked();
void on_mediaUp_clicked(); void on_mediaUp_clicked();
void on_mediaDown_clicked(); void on_mediaDown_clicked();
void on_mediaTimeRestrictions_currentIndexChanged(int idx);
void on_timeSwitches_currentRowChanged(int idx);
void on_timeAdd_clicked(); void on_timeAdd_clicked();
void on_timeRemove_clicked(); void on_timeRemove_clicked();
void on_timeUp_clicked(); void on_timeUp_clicked();
@@ -184,8 +181,6 @@ public slots:
void on_audioRemove_clicked(); void on_audioRemove_clicked();
void on_audioUp_clicked(); void on_audioUp_clicked();
void on_audioDown_clicked(); void on_audioDown_clicked();
void on_audioSwitches_currentRowChanged(int idx);
void on_audioSources_currentTextChanged(const QString &text);
void on_priorityUp_clicked(); void on_priorityUp_clicked();
void on_priorityDown_clicked(); void on_priorityDown_clicked();
@@ -226,13 +221,6 @@ bool isInFocus(const QString &executable);
/******************************************************************************** /********************************************************************************
* Sceneswitch helper * Sceneswitch helper
********************************************************************************/ ********************************************************************************/
struct obs_weak_source;
typedef struct obs_weak_source obs_weak_source_t;
typedef struct transitionData {
std::string name = "";
int duration = 0;
} transitionData;
void setNextTransition(OBSWeakSource &targetScene, obs_source_t *currentSource, void setNextTransition(OBSWeakSource &targetScene, obs_source_t *currentSource,
OBSWeakSource &transition, OBSWeakSource &transition,

View File

@@ -1,115 +1,65 @@
#pragma once #pragma once
#include <string> #include <QSpinBox>
#include "utility.hpp"
#include "switch-generic.hpp" #include "switch-generic.hpp"
#include "volume-control.hpp"
constexpr auto audio_func = 8; constexpr auto audio_func = 8;
constexpr auto default_priority_8 = audio_func; constexpr auto default_priority_8 = audio_func;
struct AudioSwitch : virtual SceneSwitcherEntry { struct AudioSwitch : virtual SceneSwitcherEntry {
OBSWeakSource audioSource; OBSWeakSource audioSource = nullptr;
int volumeThreshold; int volumeThreshold = 0;
float peak; float peak = -1;
std::string audioSwitchStr; obs_volmeter_t *volmeter = nullptr;
obs_volmeter_t *volmeter;
const char *getType() { return "audio"; } const char *getType() { return "audio"; }
bool initialized();
bool valid();
static void setVolumeLevel(void *data, static void setVolumeLevel(void *data,
const float magnitude[MAX_AUDIO_CHANNELS], const float magnitude[MAX_AUDIO_CHANNELS],
const float peak[MAX_AUDIO_CHANNELS], const float peak[MAX_AUDIO_CHANNELS],
const float inputPeak[MAX_AUDIO_CHANNELS]) const float inputPeak[MAX_AUDIO_CHANNELS]);
{ void resetVolmeter();
UNUSED_PARAMETER(magnitude);
UNUSED_PARAMETER(inputPeak);
AudioSwitch *s = static_cast<AudioSwitch *>(data);
s->peak = peak[0]; AudioSwitch(){};
for (int i = 1; i < MAX_AUDIO_CHANNELS; i++) AudioSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
if (peak[i] > s->peak) OBSWeakSource audioSource_, int volumeThreshold_,
s->peak = peak[i]; bool usePreviousScene_);
} AudioSwitch(const AudioSwitch &other);
AudioSwitch(AudioSwitch &&other);
bool valid() ~AudioSwitch();
{ AudioSwitch &operator=(const AudioSwitch &other);
return (usePreviousScene || WeakSourceValid(scene)) && AudioSwitch &operator=(AudioSwitch &&other) noexcept;
WeakSourceValid(audioSource) && friend void swap(AudioSwitch &first, AudioSwitch &second);
WeakSourceValid(transition);
}
inline AudioSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
OBSWeakSource audioSource_, int volumeThreshold_,
bool usePreviousScene_, std::string audioSwitchStr_)
: SceneSwitcherEntry(scene_, transition_, usePreviousScene_),
audioSource(audioSource_),
volumeThreshold(volumeThreshold_),
audioSwitchStr(audioSwitchStr_)
{
volmeter = obs_volmeter_create(OBS_FADER_LOG);
obs_volmeter_add_callback(volmeter, setVolumeLevel, this);
obs_source_t *as = obs_weak_source_get_source(audioSource);
if (!obs_volmeter_attach_source(volmeter, as)) {
const char *name = obs_source_get_name(as);
blog(LOG_WARNING,
"failed to attach volmeter to source %s", name);
}
obs_source_release(as);
}
AudioSwitch(const AudioSwitch &other)
: SceneSwitcherEntry(other.scene, other.transition,
other.usePreviousScene),
audioSource(other.audioSource),
volumeThreshold(other.volumeThreshold),
audioSwitchStr(other.audioSwitchStr)
{
volmeter = obs_volmeter_create(OBS_FADER_LOG);
obs_volmeter_add_callback(volmeter, setVolumeLevel, this);
obs_source_t *as =
obs_weak_source_get_source(other.audioSource);
if (!obs_volmeter_attach_source(volmeter, as)) {
const char *name = obs_source_get_name(as);
blog(LOG_WARNING,
"failed to attach volmeter to source %s", name);
}
obs_source_release(as);
}
AudioSwitch(AudioSwitch &&other)
: SceneSwitcherEntry(other.scene, other.transition,
other.usePreviousScene),
audioSource(other.audioSource),
volumeThreshold(other.volumeThreshold),
audioSwitchStr(other.audioSwitchStr),
volmeter(other.volmeter)
{
other.volmeter = nullptr;
}
inline ~AudioSwitch()
{
obs_volmeter_remove_callback(volmeter, setVolumeLevel, this);
obs_volmeter_destroy(volmeter);
}
AudioSwitch &operator=(const AudioSwitch &other)
{
return *this = AudioSwitch(other);
}
AudioSwitch &operator=(AudioSwitch &&other) noexcept
{
if (this == &other) {
return *this;
}
obs_volmeter_destroy(volmeter);
volmeter = other.volmeter;
other.volmeter = nullptr;
return *this;
}
}; };
static inline QString MakeAudioSwitchName(const QString &scene, class AudioSwitchWidget : public SwitchWidget {
const QString &transition, Q_OBJECT
const QString &audioSrouce,
const int &volume); public:
AudioSwitchWidget(AudioSwitch *s);
void UpdateVolmeterSource();
AudioSwitch *getSwitchData();
void setSwitchData(AudioSwitch *s);
static void swapSwitchData(AudioSwitchWidget *as1,
AudioSwitchWidget *as2);
private slots:
void SourceChanged(const QString &text);
void VolumeThresholdChanged(int vol);
private:
QComboBox *audioSources;
QSpinBox *audioVolumeThreshold;
VolControl *volMeter;
QLabel *whenLabel;
QLabel *aboveLabel;
QLabel *switchLabel;
QLabel *usingLabel;
AudioSwitch *switchData;
};

View File

@@ -1,20 +1,19 @@
#pragma once #pragma once
#include <string> #include <QCheckBox>
#include "utility.hpp"
#include "switch-generic.hpp" #include "switch-generic.hpp"
constexpr auto exe_func = 3; constexpr auto exe_func = 3;
constexpr auto default_priority_3 = exe_func; constexpr auto default_priority_3 = exe_func;
struct ExecutableSceneSwitch : SceneSwitcherEntry { struct ExecutableSwitch : SceneSwitcherEntry {
QString exe; QString exe = "";
bool inFocus; bool inFocus = false;
const char *getType() { return "exec"; } const char *getType() { return "exec"; }
inline ExecutableSceneSwitch(OBSWeakSource scene_, inline ExecutableSwitch(){};
OBSWeakSource transition_, inline ExecutableSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
const QString &exe_, bool inFocus_) const QString &exe_, bool inFocus_)
: SceneSwitcherEntry(scene_, transition_), : SceneSwitcherEntry(scene_, transition_),
exe(exe_), exe(exe_),
inFocus(inFocus_) inFocus(inFocus_)
@@ -22,7 +21,28 @@ struct ExecutableSceneSwitch : SceneSwitcherEntry {
} }
}; };
static inline QString MakeSwitchNameExecutable(const QString &scene, class ExecutableSwitchWidget : public SwitchWidget {
const QString &value, Q_OBJECT
const QString &transition,
bool inFocus); public:
ExecutableSwitchWidget(ExecutableSwitch *s);
ExecutableSwitch *getSwitchData();
void setSwitchData(ExecutableSwitch *s);
static void swapSwitchData(ExecutableSwitchWidget *s1,
ExecutableSwitchWidget *s2);
private slots:
void ProcessChanged(const QString &text);
void FocusChanged(int state);
private:
QComboBox *processes;
QCheckBox *requiresFocus;
QLabel *whenLabel;
QLabel *switchLabel;
QLabel *usingLabel;
ExecutableSwitch *switchData;
};

View File

@@ -1,6 +1,4 @@
#pragma once #pragma once
#include <string>
#include "utility.hpp"
#include "switch-generic.hpp" #include "switch-generic.hpp"
constexpr auto read_file_func = 0; constexpr auto read_file_func = 0;

View File

@@ -1,48 +1,50 @@
#pragma once #pragma once
#include <string>
#include <obs.hpp> #include <obs.hpp>
#include <QComboBox>
struct SceneSwitcherEntry { struct SceneSwitcherEntry {
OBSWeakSource scene; OBSWeakSource scene = nullptr;
OBSWeakSource transition; OBSWeakSource transition = nullptr;
bool usePreviousScene; bool usePreviousScene = false;
virtual bool valid()
{
return (usePreviousScene || WeakSourceValid(scene)) &&
WeakSourceValid(transition);
}
virtual const char *getType() = 0; virtual const char *getType() = 0;
virtual bool initialized();
virtual bool valid();
virtual void logMatch();
// TODO inline SceneSwitcherEntry() {}
//virtual bool checkMatch() = 0;
virtual void logMatch()
{
obs_source_t *s = obs_weak_source_get_source(scene);
const char *sceneName = obs_source_get_name(s);
obs_source_release(s);
blog(LOG_INFO,
"Advanced Scene Switcher match for '%s' - switch to scene '%s'",
getType(), sceneName);
}
inline SceneSwitcherEntry() : usePreviousScene(false) {}
inline SceneSwitcherEntry(OBSWeakSource scene_, inline SceneSwitcherEntry(OBSWeakSource scene_,
OBSWeakSource transition_, OBSWeakSource transition_,
bool usePreviousScene_) bool usePreviousScene_ = false)
: scene(scene_), : scene(scene_),
transition(transition_), transition(transition_),
usePreviousScene(usePreviousScene_) usePreviousScene(usePreviousScene_)
{ {
} }
inline SceneSwitcherEntry(OBSWeakSource scene_,
OBSWeakSource transition_) virtual ~SceneSwitcherEntry() {}
: scene(scene_), };
transition(transition_),
usePreviousScene(false) class SwitchWidget : public QWidget {
{ Q_OBJECT
}
public:
SwitchWidget(SceneSwitcherEntry *s, bool usePreviousScene = true);
virtual SceneSwitcherEntry *getSwitchData();
virtual void setSwitchData(SceneSwitcherEntry *s);
static void swapSwitchData(SwitchWidget *s1, SwitchWidget *s2);
private slots:
void SceneChanged(const QString &text);
void TransitionChanged(const QString &text);
protected:
bool loading = true;
QComboBox *scenes;
QComboBox *transitions;
SceneSwitcherEntry *switchData;
}; };

View File

@@ -1,6 +1,4 @@
#pragma once #pragma once
#include <string>
#include "utility.hpp"
#include "switch-generic.hpp" #include "switch-generic.hpp"
constexpr auto default_idle_time = 60; constexpr auto default_idle_time = 60;

View File

@@ -1,6 +1,4 @@
#pragma once #pragma once
#include <string>
#include "utility.hpp"
#include "switch-generic.hpp" #include "switch-generic.hpp"
constexpr auto media_func = 6; constexpr auto media_func = 6;
@@ -15,36 +13,67 @@ typedef enum {
} time_restriction; } time_restriction;
struct MediaSwitch : SceneSwitcherEntry { struct MediaSwitch : SceneSwitcherEntry {
OBSWeakSource source; OBSWeakSource source = nullptr;
obs_media_state state; obs_media_state state = OBS_MEDIA_STATE_NONE;
time_restriction restriction; bool anyState = false;
int64_t time; time_restriction restriction = TIME_RESTRICTION_NONE;
bool matched; int64_t time = 0;
std::string mediaSwitchStr; std::atomic<bool> stopped = false;
std::atomic<bool> ended = false;
const char *getType() { return "meida"; } // workaround to enable use of "ended" to specify end of VLC playlist
bool previousStateEnded = false;
bool valid() const char *getType() { return "media"; }
{ bool initialized();
return (usePreviousScene || WeakSourceValid(scene)) && bool valid();
WeakSourceValid(source) && WeakSourceValid(transition);
}
void clearSignalHandler();
void resetSignalHandler();
static void MediaStopped(void *data, calldata_t *);
static void MediaEnded(void *data, calldata_t *);
inline MediaSwitch(){};
inline MediaSwitch(OBSWeakSource scene_, OBSWeakSource source_, inline MediaSwitch(OBSWeakSource scene_, OBSWeakSource source_,
OBSWeakSource transition_, obs_media_state state_, OBSWeakSource transition_, obs_media_state state_,
time_restriction restriction_, uint64_t time_, time_restriction restriction_, uint64_t time_,
bool usePreviousScene_, std::string mediaSwitchStr_) bool usePreviousScene_);
: SceneSwitcherEntry(scene_, transition_, usePreviousScene_), MediaSwitch(const MediaSwitch &other);
source(source_), MediaSwitch(MediaSwitch &&other);
state(state_), ~MediaSwitch();
restriction(restriction_), MediaSwitch &operator=(const MediaSwitch &other);
time(time_), MediaSwitch &operator=(MediaSwitch &&other) noexcept;
mediaSwitchStr(mediaSwitchStr_) friend void swap(MediaSwitch &first, MediaSwitch &second);
{
}
}; };
static inline QString class MediaSwitchWidget : public SwitchWidget {
MakeMediaSwitchName(const QString &source, const QString &scene, Q_OBJECT
const QString &transition, obs_media_state state,
time_restriction restriction, uint64_t time); public:
MediaSwitchWidget(MediaSwitch *s);
MediaSwitch *getSwitchData();
void setSwitchData(MediaSwitch *s);
static void swapSwitchData(MediaSwitchWidget *s1,
MediaSwitchWidget *s2);
private slots:
void SourceChanged(const QString &text);
void StateChanged(int index);
void TimeRestrictionChanged(int index);
void TimeChanged(int time);
private:
QComboBox *meidaSources;
QComboBox *states;
QComboBox *timeRestrictions;
QSpinBox *time;
QLabel *whenLabel;
QLabel *stateLabel;
QLabel *andLabel;
QLabel *switchLabel;
QLabel *usingLabel;
MediaSwitch *switchData;
};

View File

@@ -1,23 +1,39 @@
#pragma once #pragma once
#include <string>
#include "utility.hpp"
#include "switch-generic.hpp" #include "switch-generic.hpp"
struct RandomSwitch : SceneSwitcherEntry { struct RandomSwitch : SceneSwitcherEntry {
double delay; double delay = 0.0;
std::string randomSwitchStr;
const char *getType() { return "random"; } const char *getType() { return "random"; }
inline RandomSwitch() {}
inline RandomSwitch(OBSWeakSource scene_, OBSWeakSource transition_, inline RandomSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
double delay_, std::string str) double delay_)
: SceneSwitcherEntry(scene_, transition_), : SceneSwitcherEntry(scene_, transition_), delay(delay_)
delay(delay_),
randomSwitchStr(str)
{ {
} }
}; };
static inline QString MakeRandomSwitchName(const QString &scene, class RandomSwitchWidget : public SwitchWidget {
const QString &transition, Q_OBJECT
double &delay);
public:
RandomSwitchWidget(RandomSwitch *s);
RandomSwitch *getSwitchData();
void setSwitchData(RandomSwitch *s);
static void swapSwitchData(RandomSwitchWidget *s1,
RandomSwitchWidget *s2);
private slots:
void DelayChanged(double d);
private:
QDoubleSpinBox *delay;
QLabel *switchLabel;
QLabel *usingLabel;
QLabel *forLabel;
RandomSwitch *switchData;
};

View File

@@ -1,32 +1,62 @@
#pragma once #pragma once
#include <string> #include <QSpinBox>
#include "utility.hpp"
#include "switch-generic.hpp" #include "switch-generic.hpp"
constexpr auto screen_region_func = 4; constexpr auto screen_region_func = 4;
constexpr auto default_priority_4 = screen_region_func; constexpr auto default_priority_4 = screen_region_func;
struct ScreenRegionSwitch : SceneSwitcherEntry { struct ScreenRegionSwitch : SceneSwitcherEntry {
int minX, minY, maxX, maxY; int minX = 0, minY = 0, maxX = 0, maxY = 0;
std::string regionStr;
const char *getType() { return "region"; } const char *getType() { return "region"; }
inline ScreenRegionSwitch(){};
inline ScreenRegionSwitch(OBSWeakSource scene_, inline ScreenRegionSwitch(OBSWeakSource scene_,
OBSWeakSource transition_, int minX_, OBSWeakSource transition_, int minX_,
int minY_, int maxX_, int maxY_, int minY_, int maxX_, int maxY_)
std::string regionStr_)
: SceneSwitcherEntry(scene_, transition_), : SceneSwitcherEntry(scene_, transition_),
minX(minX_), minX(minX_),
minY(minY_), minY(minY_),
maxX(maxX_), maxX(maxX_),
maxY(maxY_), maxY(maxY_)
regionStr(regionStr_)
{ {
} }
}; };
static inline QString MakeScreenRegionSwitchName(const QString &scene, class ScreenRegionWidget : public SwitchWidget {
const QString &transition, Q_OBJECT
int minX, int minY, int maxX,
int maxY); public:
ScreenRegionWidget(ScreenRegionSwitch *s);
ScreenRegionSwitch *getSwitchData();
void setSwitchData(ScreenRegionSwitch *s);
static void swapSwitchData(ScreenRegionWidget *s1,
ScreenRegionWidget *s2);
void showFrame();
void hideFrame();
private slots:
void MinXChanged(int pos);
void MinYChanged(int pos);
void MaxXChanged(int pos);
void MaxYChanged(int pos);
private:
QSpinBox *minX;
QSpinBox *minY;
QSpinBox *maxX;
QSpinBox *maxY;
QFrame helperFrame;
QLabel *cursorLabel;
QLabel *xLabel;
QLabel *switchLabel;
QLabel *usingLabel;
ScreenRegionSwitch *switchData;
void drawFrame();
};

View File

@@ -0,0 +1,64 @@
#pragma once
#include "switch-generic.hpp"
constexpr auto round_trip_func = 1;
constexpr auto default_priority_1 = round_trip_func;
typedef enum {
SECONDS,
MINUTES,
HOURS,
} delay_units;
struct SceneSequenceSwitch : SceneSwitcherEntry {
OBSWeakSource startScene = nullptr;
double delay = 0;
int delayMultiplier = 1;
const char *getType() { return "sequence"; }
bool initialized();
bool valid();
void logSleep(int dur);
inline SceneSequenceSwitch(){};
inline SceneSequenceSwitch(OBSWeakSource startScene_,
OBSWeakSource scene_,
OBSWeakSource transition_, double delay_,
int delayMultiplier_, bool usePreviousScene_)
: SceneSwitcherEntry(scene_, transition_, usePreviousScene_),
startScene(startScene_),
delay(delay_),
delayMultiplier(delayMultiplier_)
{
}
};
class SequenceWidget : public SwitchWidget {
Q_OBJECT
public:
SequenceWidget(SceneSequenceSwitch *s);
SceneSequenceSwitch *getSwitchData();
void setSwitchData(SceneSequenceSwitch *s);
static void swapSwitchData(SequenceWidget *s1, SequenceWidget *s2);
void UpdateDelay();
private slots:
void DelayChanged(double delay);
void DelayUnitsChanged(int idx);
void StartSceneChanged(const QString &text);
private:
QDoubleSpinBox *delay;
QComboBox *delayUnits;
QComboBox *startScenes;
QLabel *whenLabel;
QLabel *switchLabel;
QLabel *afterLabel;
QLabel *usingLabel;
SceneSequenceSwitch *switchData;
};

View File

@@ -1,7 +1,6 @@
#pragma once #pragma once
#include <string> #include <QTimeEdit>
#include <QDateTime>
#include "utility.hpp"
#include "switch-generic.hpp" #include "switch-generic.hpp"
constexpr auto time_func = 7; constexpr auto time_func = 7;
@@ -20,24 +19,43 @@ typedef enum {
} timeTrigger; } timeTrigger;
struct TimeSwitch : SceneSwitcherEntry { struct TimeSwitch : SceneSwitcherEntry {
timeTrigger trigger; timeTrigger trigger = ANY_DAY;
QTime time; QTime time = QTime();
std::string timeSwitchStr;
const char *getType() { return "time"; } const char *getType() { return "time"; }
inline TimeSwitch(){};
inline TimeSwitch(OBSWeakSource scene_, OBSWeakSource transition_, inline TimeSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
timeTrigger trigger_, QTime time_, timeTrigger trigger_, QTime time_,
bool usePreviousScene_, std::string timeSwitchStr_) bool usePreviousScene_)
: SceneSwitcherEntry(scene_, transition_, usePreviousScene_), : SceneSwitcherEntry(scene_, transition_, usePreviousScene_),
trigger(trigger_), trigger(trigger_),
time(time_), time(time_)
timeSwitchStr(timeSwitchStr_)
{ {
} }
}; };
static inline QString MakeTimeSwitchName(const QString &scene, class TimeSwitchWidget : public SwitchWidget {
const QString &transition, Q_OBJECT
const timeTrigger &trigger,
const QTime &time); public:
TimeSwitchWidget(TimeSwitch *s);
TimeSwitch *getSwitchData();
void setSwitchData(TimeSwitch *s);
static void swapSwitchData(TimeSwitchWidget *s1, TimeSwitchWidget *s2);
private slots:
void TriggerChanged(int index);
void TimeChanged(const QTime &time);
private:
QComboBox *triggers;
QTimeEdit *time;
QLabel *atLabel;
QLabel *switchLabel;
QLabel *usingLabel;
TimeSwitch *switchData;
};

View File

@@ -1,47 +1,71 @@
#pragma once #pragma once
#include <string>
#include "utility.hpp"
#include "switch-generic.hpp" #include "switch-generic.hpp"
struct SceneTransition : SceneSwitcherEntry { struct SceneTransition : SceneSwitcherEntry {
OBSWeakSource scene2; OBSWeakSource scene2 = nullptr;
std::string sceneTransitionStr;
const char *getType() { return "transition"; } const char *getType() { return "transition"; }
bool initialized();
bool valid();
bool valid() inline SceneTransition(){};
{
return (WeakSourceValid(scene) && WeakSourceValid(scene2)) &&
WeakSourceValid(transition);
}
inline SceneTransition(OBSWeakSource scene_, OBSWeakSource scene2_, inline SceneTransition(OBSWeakSource scene_, OBSWeakSource scene2_,
OBSWeakSource transition_, OBSWeakSource transition_)
std::string sceneTransitionStr_) : SceneSwitcherEntry(scene_, transition_), scene2(scene2_)
: SceneSwitcherEntry(scene_, transition_),
scene2(scene2_),
sceneTransitionStr(sceneTransitionStr_)
{ {
} }
}; };
static inline QString MakeSceneTransitionName(const QString &scene1,
const QString &scene2,
const QString &transition);
struct DefaultSceneTransition : SceneSwitcherEntry { struct DefaultSceneTransition : SceneSwitcherEntry {
std::string sceneTransitionStr;
const char *getType() { return "def_transition"; } const char *getType() { return "def_transition"; }
inline DefaultSceneTransition(){};
inline DefaultSceneTransition(OBSWeakSource scene_, inline DefaultSceneTransition(OBSWeakSource scene_,
OBSWeakSource transition_, OBSWeakSource transition_)
std::string sceneTransitionStr_) : SceneSwitcherEntry(scene_, transition_)
: SceneSwitcherEntry(scene_, transition_),
sceneTransitionStr(sceneTransitionStr_)
{ {
} }
}; };
static inline QString MakeDefaultSceneTransitionName(const QString &scene, class TransitionSwitchWidget : public SwitchWidget {
const QString &transition); Q_OBJECT
public:
TransitionSwitchWidget(SceneTransition *s);
SceneTransition *getSwitchData();
void setSwitchData(SceneTransition *s);
static void swapSwitchData(TransitionSwitchWidget *s1,
TransitionSwitchWidget *s2);
private slots:
void Scene2Changed(const QString &text);
private:
QComboBox *scenes2;
QLabel *switchLabel;
QLabel *toLabel;
QLabel *usingLabel;
SceneTransition *switchData;
};
class DefTransitionSwitchWidget : public SwitchWidget {
Q_OBJECT
public:
DefTransitionSwitchWidget(DefaultSceneTransition *s);
DefaultSceneTransition *getSwitchData();
void setSwitchData(DefaultSceneTransition *s);
static void swapSwitchData(DefTransitionSwitchWidget *s1,
DefTransitionSwitchWidget *s2);
private:
QLabel *whenLabel;
QLabel *switchLabel;
DefaultSceneTransition *switchData;
};

View File

@@ -1,22 +1,21 @@
#pragma once #pragma once
#include <string>
#include "utility.hpp"
#include "switch-generic.hpp" #include "switch-generic.hpp"
constexpr auto window_title_func = 5; constexpr auto window_title_func = 5;
constexpr auto default_priority_5 = window_title_func; constexpr auto default_priority_5 = window_title_func;
struct WindowSceneSwitch : SceneSwitcherEntry { struct WindowSwitch : SceneSwitcherEntry {
std::string window; std::string window = "";
bool fullscreen; bool fullscreen = false;
bool maximized; bool maximized = false;
bool focus; bool focus = true;
const char *getType() { return "window"; } const char *getType() { return "window"; }
inline WindowSceneSwitch(OBSWeakSource scene_, const char *window_, inline WindowSwitch() {}
OBSWeakSource transition_, bool fullscreen_, inline WindowSwitch(OBSWeakSource scene_, const char *window_,
bool maximized_, bool focus_) OBSWeakSource transition_, bool fullscreen_,
bool maximized_, bool focus_)
: SceneSwitcherEntry(scene_, transition_), : SceneSwitcherEntry(scene_, transition_),
window(window_), window(window_),
fullscreen(fullscreen_), fullscreen(fullscreen_),
@@ -26,8 +25,28 @@ struct WindowSceneSwitch : SceneSwitcherEntry {
} }
}; };
static inline QString MakeWindowSwitchName(const QString &scene, class WindowSwitchWidget : public SwitchWidget {
const QString &value, Q_OBJECT
const QString &transition,
bool fullscreen, bool maximized, public:
bool focus); WindowSwitchWidget(WindowSwitch *s);
WindowSwitch *getSwitchData();
void setSwitchData(WindowSwitch *s);
static void swapSwitchData(WindowSwitchWidget *s1,
WindowSwitchWidget *s2);
private slots:
void WindowChanged(const QString &text);
void FullscreenChanged(int state);
void MaximizedChanged(int state);
void FocusChanged(int state);
private:
QComboBox *windows;
QCheckBox *fullscreen;
QCheckBox *maximized;
QCheckBox *focused;
WindowSwitch *switchData;
};

View File

@@ -1,7 +1,7 @@
#pragma once #pragma once
#include <condition_variable> #include <condition_variable>
#include <string>
#include <vector> #include <vector>
#include <deque>
#include <mutex> #include <mutex>
#include <QDateTime> #include <QDateTime>
#include <QThread> #include <QThread>
@@ -17,7 +17,7 @@
#include "switch-time.hpp" #include "switch-time.hpp"
#include "switch-transitions.hpp" #include "switch-transitions.hpp"
#include "switch-window.hpp" #include "switch-window.hpp"
#include "swtich-sequence.hpp" #include "switch-sequence.hpp"
constexpr auto default_interval = 300; constexpr auto default_interval = 300;
constexpr auto previous_scene_name = "Previous Scene"; constexpr auto previous_scene_name = "Previous Scene";
@@ -30,6 +30,12 @@ typedef enum {
RECORINDGSTREAMING = 2 RECORINDGSTREAMING = 2
} AutoStartType; } AutoStartType;
typedef struct transitionData {
std::string name = "";
int duration = 0;
} transitionData;
class SwitcherThread; class SwitcherThread;
/******************************************************************************** /********************************************************************************
@@ -45,6 +51,8 @@ struct SwitcherData {
std::condition_variable transitionCv; std::condition_variable transitionCv;
bool stop = false; bool stop = false;
bool verbose = false; bool verbose = false;
bool disableHints = false;
bool showFrame = false;
bool tansitionOverrideOverride = false; bool tansitionOverrideOverride = false;
int interval = default_interval; int interval = default_interval;
@@ -57,11 +65,11 @@ struct SwitcherData {
NoMatch switchIfNotMatching = NO_SWITCH; NoMatch switchIfNotMatching = NO_SWITCH;
StartupBehavior startupBehavior = PERSIST; StartupBehavior startupBehavior = PERSIST;
std::vector<WindowSceneSwitch> windowSwitches; std::deque<WindowSwitch> windowSwitches;
std::vector<std::string> ignoreIdleWindows; std::vector<std::string> ignoreIdleWindows;
std::string lastTitle; std::string lastTitle;
std::vector<ScreenRegionSwitch> screenRegionSwitches; std::deque<ScreenRegionSwitch> screenRegionSwitches;
std::vector<OBSWeakSource> pauseScenesSwitches; std::vector<OBSWeakSource> pauseScenesSwitches;
@@ -69,17 +77,17 @@ struct SwitcherData {
std::vector<std::string> ignoreWindowsSwitches; std::vector<std::string> ignoreWindowsSwitches;
std::vector<SceneSequenceSwitch> sceneSequenceSwitches; std::deque<SceneSequenceSwitch> sceneSequenceSwitches;
int sceneSequenceMultiplier = 1;
std::vector<RandomSwitch> randomSwitches; std::deque<RandomSwitch> randomSwitches;
IdleData idleData;
FileIOData fileIO; FileIOData fileIO;
IdleData idleData;
std::vector<FileSwitch> fileSwitches; std::vector<FileSwitch> fileSwitches;
CURL *curl = nullptr; CURL *curl = nullptr;
std::vector<ExecutableSceneSwitch> executableSwitches; std::deque<ExecutableSwitch> executableSwitches;
bool autoStopEnable = false; bool autoStopEnable = false;
OBSWeakSource autoStopScene; OBSWeakSource autoStopScene;
@@ -89,15 +97,16 @@ struct SwitcherData {
OBSWeakSource autoStartScene; OBSWeakSource autoStartScene;
bool autoStartedRecently = false; bool autoStartedRecently = false;
std::vector<SceneTransition> sceneTransitions; std::deque<SceneTransition> sceneTransitions;
std::vector<DefaultSceneTransition> defaultSceneTransitions; std::deque<DefaultSceneTransition> defaultSceneTransitions;
bool changedDefTransitionRecently = false;
std::vector<MediaSwitch> mediaSwitches; std::deque<MediaSwitch> mediaSwitches;
std::vector<TimeSwitch> timeSwitches; std::deque<TimeSwitch> timeSwitches;
QDateTime liveTime; QDateTime liveTime;
std::vector<AudioSwitch> audioSwitches; std::deque<AudioSwitch> audioSwitches;
std::vector<int> functionNamesByPriority = std::vector<int>{ std::vector<int> functionNamesByPriority = std::vector<int>{
default_priority_0, default_priority_1, default_priority_2, default_priority_0, default_priority_1, default_priority_2,
@@ -150,8 +159,8 @@ struct SwitcherData {
void autoStartStreamRecording(); void autoStartStreamRecording();
bool checkPause(); bool checkPause();
void checkSceneSequence(bool &match, OBSWeakSource &scene, void checkSceneSequence(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition, OBSWeakSource &transition,
std::unique_lock<std::mutex> &lock); std::unique_lock<std::mutex> &lock);
void checkIdleSwitch(bool &match, OBSWeakSource &scene, void checkIdleSwitch(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition); OBSWeakSource &transition);
void checkWindowTitleSwitch(bool &match, OBSWeakSource &scene, void checkWindowTitleSwitch(bool &match, OBSWeakSource &scene,

View File

@@ -1,44 +0,0 @@
#pragma once
#include <string>
#include "utility.hpp"
#include "switch-generic.hpp"
constexpr auto round_trip_func = 1;
constexpr auto default_priority_1 = round_trip_func;
struct SceneSequenceSwitch : SceneSwitcherEntry {
OBSWeakSource startScene;
double delay;
std::string sceneSequenceStr;
const char *getType() { return "sequence"; }
bool valid()
{
return WeakSourceValid(startScene) &&
(usePreviousScene || WeakSourceValid(scene)) &&
WeakSourceValid(transition);
}
void logSleep(int dur)
{
blog(LOG_INFO, "Advanced Scene Switcher sequence sleep %d",
dur);
}
inline SceneSequenceSwitch(OBSWeakSource startScene_,
OBSWeakSource scene_,
OBSWeakSource transition_, double delay_,
bool usePreviousScene_, std::string str)
: SceneSwitcherEntry(scene_, transition_, usePreviousScene_),
startScene(startScene_),
delay(delay_),
sceneSequenceStr(str)
{
}
};
static inline QString MakeSceneSequenceSwitchName(const QString &scene1,
const QString &scene2,
const QString &transition,
double delay);

View File

@@ -1,187 +1,80 @@
#include "headers/advanced-scene-switcher.hpp" #include "headers/advanced-scene-switcher.hpp"
#include "headers/volume-control.hpp" #include "headers/volume-control.hpp"
#include "headers/utility.hpp"
void SceneSwitcher::on_audioSwitches_currentRowChanged(int idx) static QMetaObject::Connection addPulse;
void AdvSceneSwitcher::on_audioAdd_clicked()
{ {
if (loading) ui->audioAdd->disconnect(addPulse);
return;
if (idx == -1)
return;
QListWidgetItem *item = ui->audioSwitches->item(idx);
QString audioScenestr = item->data(Qt::UserRole).toString();
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->audioSwitches) { switcher->audioSwitches.emplace_back();
if (audioScenestr.compare(s.audioSwitchStr.c_str()) == 0) {
QString sceneName = GetWeakSourceName(s.scene).c_str(); QListWidgetItem *item;
QString audioSrouceName = item = new QListWidgetItem(ui->audioSwitches);
GetWeakSourceName(s.audioSource).c_str(); ui->audioSwitches->addItem(item);
QString transitionName = AudioSwitchWidget *sw =
GetWeakSourceName(s.transition).c_str(); new AudioSwitchWidget(&switcher->audioSwitches.back());
ui->audioScenes->setCurrentText(sceneName); item->setSizeHint(sw->minimumSizeHint());
ui->audioTransitions->setCurrentText(transitionName); ui->audioSwitches->setItemWidget(item, sw);
ui->audioSources->setCurrentText(audioSrouceName);
ui->audioVolumeThreshold->setValue(s.volumeThreshold);
volMeter->GetSlider()->setValue(s.volumeThreshold);
break;
}
}
} }
void SceneSwitcher::on_audioSources_currentTextChanged(const QString &text) void AdvSceneSwitcher::on_audioRemove_clicked()
{
SetAudioVolumeMeter(text);
}
void SceneSwitcher::SetAudioVolumeMeter(const QString &name)
{
obs_source_t *soruce =
obs_get_source_by_name(name.toUtf8().constData());
if (!soruce) {
return;
}
if (volMeter) {
ui->audioControlLayout->removeWidget(volMeter);
delete volMeter;
}
volMeter = new VolControl(soruce);
ui->audioControlLayout->addWidget(volMeter);
obs_source_release(soruce);
QWidget::connect(volMeter->GetSlider(), SIGNAL(valueChanged(int)),
ui->audioVolumeThreshold, SLOT(setValue(int)));
QWidget::connect(ui->audioVolumeThreshold, SIGNAL(valueChanged(int)),
volMeter->GetSlider(), SLOT(setValue(int)));
}
int SceneSwitcher::audioFindByData(const QString &source, const int &volume)
{
QRegExp rx(MakeAudioSwitchName(QStringLiteral(".*"),
QStringLiteral(".*"), source, volume));
int count = ui->audioSwitches->count();
for (int i = 0; i < count; i++) {
QListWidgetItem *item = ui->audioSwitches->item(i);
QString str = item->data(Qt::UserRole).toString();
if (rx.exactMatch(str))
return i;
}
return -1;
}
void SceneSwitcher::on_audioAdd_clicked()
{
QString sceneName = ui->audioScenes->currentText();
QString transitionName = ui->audioTransitions->currentText();
QString audioSourceName = ui->audioSources->currentText();
int vol = ui->audioVolumeThreshold->value();
if (sceneName.isEmpty() || audioSourceName.isEmpty())
return;
OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource audioSource = GetWeakSourceByQString(audioSourceName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QString text = MakeAudioSwitchName(sceneName, transitionName,
audioSourceName, vol);
QVariant v = QVariant::fromValue(text);
int idx = audioFindByData(audioSourceName, vol);
if (idx == -1) {
std::lock_guard<std::mutex> lock(switcher->m);
switcher->audioSwitches.emplace_back(
source, transition, audioSource, vol,
(sceneName == QString(previous_scene_name)),
text.toUtf8().constData());
QListWidgetItem *item =
new QListWidgetItem(text, ui->audioSwitches);
item->setData(Qt::UserRole, v);
} else {
QListWidgetItem *item = ui->audioSwitches->item(idx);
item->setText(text);
item->setData(Qt::UserRole, v);
{
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->audioSwitches) {
if (s.audioSource == audioSource &&
s.volumeThreshold == vol) {
s.scene = source;
s.transition = transition;
s.usePreviousScene =
(sceneName ==
QString(previous_scene_name));
s.audioSwitchStr =
text.toUtf8().constData();
break;
}
}
}
}
}
void SceneSwitcher::on_audioRemove_clicked()
{ {
QListWidgetItem *item = ui->audioSwitches->currentItem(); QListWidgetItem *item = ui->audioSwitches->currentItem();
if (!item) if (!item)
return; return;
std::string text =
item->data(Qt::UserRole).toString().toUtf8().constData();
{ {
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
int idx = ui->audioSwitches->currentRow();
auto &switches = switcher->audioSwitches; auto &switches = switcher->audioSwitches;
switches.erase(switches.begin() + idx);
for (auto it = switches.begin(); it != switches.end(); ++it) {
auto &s = *it;
if (s.audioSwitchStr == text) {
switches.erase(it);
break;
}
}
} }
delete item; delete item;
} }
void SceneSwitcher::on_audioUp_clicked() void AdvSceneSwitcher::on_audioUp_clicked()
{ {
int index = ui->audioSwitches->currentRow(); int index = ui->audioSwitches->currentRow();
if (index != -1 && index != 0) { if (!listMoveUp(ui->audioSwitches))
ui->audioSwitches->insertItem( return;
index - 1, ui->audioSwitches->takeItem(index));
ui->audioSwitches->setCurrentRow(index - 1);
std::lock_guard<std::mutex> lock(switcher->m); AudioSwitchWidget *s1 =
(AudioSwitchWidget *)ui->audioSwitches->itemWidget(
ui->audioSwitches->item(index));
AudioSwitchWidget *s2 =
(AudioSwitchWidget *)ui->audioSwitches->itemWidget(
ui->audioSwitches->item(index - 1));
AudioSwitchWidget::swapSwitchData(s1, s2);
iter_swap(switcher->audioSwitches.begin() + index, std::lock_guard<std::mutex> lock(switcher->m);
switcher->audioSwitches.begin() + index - 1);
} std::swap(switcher->audioSwitches[index],
switcher->audioSwitches[index - 1]);
} }
void SceneSwitcher::on_audioDown_clicked() void AdvSceneSwitcher::on_audioDown_clicked()
{ {
int index = ui->audioSwitches->currentRow(); int index = ui->audioSwitches->currentRow();
if (index != -1 && index != ui->audioSwitches->count() - 1) {
ui->audioSwitches->insertItem(
index + 1, ui->audioSwitches->takeItem(index));
ui->audioSwitches->setCurrentRow(index + 1);
std::lock_guard<std::mutex> lock(switcher->m); if (!listMoveDown(ui->audioSwitches))
return;
iter_swap(switcher->audioSwitches.begin() + index, AudioSwitchWidget *s1 =
switcher->audioSwitches.begin() + index + 1); (AudioSwitchWidget *)ui->audioSwitches->itemWidget(
} ui->audioSwitches->item(index));
AudioSwitchWidget *s2 =
(AudioSwitchWidget *)ui->audioSwitches->itemWidget(
ui->audioSwitches->item(index + 1));
AudioSwitchWidget::swapSwitchData(s1, s2);
std::lock_guard<std::mutex> lock(switcher->m);
std::swap(switcher->audioSwitches[index],
switcher->audioSwitches[index + 1]);
} }
void SwitcherData::checkAudioSwitch(bool &match, OBSWeakSource &scene, void SwitcherData::checkAudioSwitch(bool &match, OBSWeakSource &scene,
@@ -191,12 +84,15 @@ void SwitcherData::checkAudioSwitch(bool &match, OBSWeakSource &scene,
return; return;
for (AudioSwitch &s : audioSwitches) { for (AudioSwitch &s : audioSwitches) {
if (!s.initialized())
continue;
obs_source_t *as = obs_weak_source_get_source(s.audioSource); obs_source_t *as = obs_weak_source_get_source(s.audioSource);
bool audioActive = obs_source_active(as); bool audioActive = obs_source_active(as);
obs_source_release(as); obs_source_release(as);
// peak will have a value from -60 db to 0 db // peak will have a value from -60 db to 0 db
bool volumeThresholdreached = (s.peak + 60) * 1.7 > bool volumeThresholdreached = ((double)s.peak + 60) * 1.7 >
s.volumeThreshold; s.volumeThreshold;
if (volumeThresholdreached && audioActive) { if (volumeThresholdreached && audioActive) {
@@ -222,7 +118,8 @@ void SwitcherData::saveAudioSwitches(obs_data_t *obj)
obs_weak_source_get_source(s.transition); obs_weak_source_get_source(s.transition);
obs_source_t *audioSrouce = obs_source_t *audioSrouce =
obs_weak_source_get_source(s.audioSource); obs_weak_source_get_source(s.audioSource);
if ((s.usePreviousScene || sceneSource) && transition) { if ((s.usePreviousScene || sceneSource) && transition &&
audioSrouce) {
const char *sceneName = const char *sceneName =
obs_source_get_name(sceneSource); obs_source_get_name(sceneSource);
const char *transitionName = const char *transitionName =
@@ -268,68 +165,278 @@ void SwitcherData::loadAudioSwitches(obs_data_t *obj)
obs_data_get_string(array_obj, "audioSource"); obs_data_get_string(array_obj, "audioSource");
int vol = obs_data_get_int(array_obj, "volume"); int vol = obs_data_get_int(array_obj, "volume");
std::string audioSwitchStr =
MakeAudioSwitchName(scene, transition, audioSource, vol)
.toUtf8()
.constData();
switcher->audioSwitches.emplace_back( switcher->audioSwitches.emplace_back(
GetWeakSourceByName(scene), GetWeakSourceByName(scene),
GetWeakTransitionByName(transition), GetWeakTransitionByName(transition),
GetWeakSourceByName(audioSource), vol, GetWeakSourceByName(audioSource), vol,
(strcmp(scene, previous_scene_name) == 0), (strcmp(scene, previous_scene_name) == 0));
audioSwitchStr);
obs_data_release(array_obj); obs_data_release(array_obj);
} }
obs_data_array_release(audioArray); obs_data_array_release(audioArray);
} }
void SceneSwitcher::setupAudioTab() void AdvSceneSwitcher::setupAudioTab()
{ {
populateSceneSelection(ui->audioScenes, true);
populateTransitionSelection(ui->audioTransitions);
auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */
{
QComboBox *combo = reinterpret_cast<QComboBox *>(data);
uint32_t flags = obs_source_get_output_flags(source);
if ((flags & OBS_SOURCE_AUDIO) != 0) {
const char *name = obs_source_get_name(source);
combo->addItem(name);
}
return true;
};
obs_enum_sources(sourceEnum, ui->audioSources);
for (auto &s : switcher->audioSwitches) { for (auto &s : switcher->audioSwitches) {
std::string sceneName = (s.usePreviousScene) QListWidgetItem *item;
? previous_scene_name item = new QListWidgetItem(ui->audioSwitches);
: GetWeakSourceName(s.scene); ui->audioSwitches->addItem(item);
std::string transitionName = GetWeakSourceName(s.transition); AudioSwitchWidget *sw = new AudioSwitchWidget(&s);
std::string audioSourceName = GetWeakSourceName(s.audioSource); item->setSizeHint(sw->minimumSizeHint());
QString listText = MakeAudioSwitchName(sceneName.c_str(), ui->audioSwitches->setItemWidget(item, sw);
transitionName.c_str(),
audioSourceName.c_str(),
s.volumeThreshold);
QListWidgetItem *item =
new QListWidgetItem(listText, ui->audioSwitches);
item->setData(Qt::UserRole, listText);
} }
if (switcher->audioSwitches.size() == 0)
addPulse = PulseWidget(ui->audioAdd, QColor(Qt::green));
} }
static inline QString MakeAudioSwitchName(const QString &scene, void AudioSwitch::setVolumeLevel(void *data,
const QString &transition, const float magnitude[MAX_AUDIO_CHANNELS],
const QString &audioSrouce, const float peak[MAX_AUDIO_CHANNELS],
const int &volume) const float inputPeak[MAX_AUDIO_CHANNELS])
{ {
QString switchName = QStringLiteral("When volume of ") + audioSrouce + UNUSED_PARAMETER(magnitude);
QStringLiteral(" is above ") + UNUSED_PARAMETER(inputPeak);
QString::number(volume) + AudioSwitch *s = static_cast<AudioSwitch *>(data);
QStringLiteral("% switch to ") + scene +
QStringLiteral(" using ") + transition; s->peak = peak[0];
return switchName; for (int i = 1; i < MAX_AUDIO_CHANNELS; i++)
if (peak[i] > s->peak)
s->peak = peak[i];
}
void AudioSwitch::resetVolmeter()
{
obs_volmeter_remove_callback(volmeter, setVolumeLevel, this);
obs_volmeter_destroy(volmeter);
volmeter = obs_volmeter_create(OBS_FADER_LOG);
obs_volmeter_add_callback(volmeter, setVolumeLevel, this);
obs_source_t *as = obs_weak_source_get_source(audioSource);
if (!obs_volmeter_attach_source(volmeter, as)) {
const char *name = obs_source_get_name(as);
blog(LOG_WARNING, "failed to attach volmeter to source %s",
name);
}
obs_source_release(as);
}
bool AudioSwitch::initialized()
{
return SceneSwitcherEntry::initialized() && audioSource;
}
bool AudioSwitch::valid()
{
return !initialized() ||
(SceneSwitcherEntry::valid() && WeakSourceValid(audioSource));
}
AudioSwitch::AudioSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
OBSWeakSource audioSource_, int volumeThreshold_,
bool usePreviousScene_)
: SceneSwitcherEntry(scene_, transition_, usePreviousScene_),
audioSource(audioSource_),
volumeThreshold(volumeThreshold_)
{
volmeter = obs_volmeter_create(OBS_FADER_LOG);
obs_volmeter_add_callback(volmeter, setVolumeLevel, this);
obs_source_t *as = obs_weak_source_get_source(audioSource);
if (!obs_volmeter_attach_source(volmeter, as)) {
const char *name = obs_source_get_name(as);
blog(LOG_WARNING, "failed to attach volmeter to source %s",
name);
}
obs_source_release(as);
}
AudioSwitch::AudioSwitch(const AudioSwitch &other)
: SceneSwitcherEntry(other.scene, other.transition,
other.usePreviousScene),
audioSource(other.audioSource),
volumeThreshold(other.volumeThreshold)
{
volmeter = obs_volmeter_create(OBS_FADER_LOG);
obs_volmeter_add_callback(volmeter, setVolumeLevel, this);
obs_source_t *as = obs_weak_source_get_source(other.audioSource);
if (!obs_volmeter_attach_source(volmeter, as)) {
const char *name = obs_source_get_name(as);
blog(LOG_WARNING, "failed to attach volmeter to source %s",
name);
}
obs_source_release(as);
}
AudioSwitch::AudioSwitch(AudioSwitch &&other)
: SceneSwitcherEntry(other.scene, other.transition,
other.usePreviousScene),
audioSource(other.audioSource),
volumeThreshold(other.volumeThreshold),
volmeter(other.volmeter)
{
other.volmeter = nullptr;
}
AudioSwitch::~AudioSwitch()
{
obs_volmeter_remove_callback(volmeter, setVolumeLevel, this);
obs_volmeter_destroy(volmeter);
}
AudioSwitch &AudioSwitch::operator=(const AudioSwitch &other)
{
AudioSwitch t(other);
swap(*this, t);
return *this = AudioSwitch(other);
}
AudioSwitch &AudioSwitch::operator=(AudioSwitch &&other) noexcept
{
if (this == &other) {
return *this;
}
swap(*this, other);
obs_volmeter_remove_callback(other.volmeter, setVolumeLevel, this);
obs_volmeter_destroy(other.volmeter);
other.volmeter = nullptr;
return *this;
}
void swap(AudioSwitch &first, AudioSwitch &second)
{
std::swap(first.scene, second.scene);
std::swap(first.transition, second.transition);
std::swap(first.usePreviousScene, second.usePreviousScene);
std::swap(first.audioSource, second.audioSource);
std::swap(first.volumeThreshold, second.volumeThreshold);
std::swap(first.peak, second.peak);
std::swap(first.volmeter, second.volmeter);
first.resetVolmeter();
second.resetVolmeter();
}
AudioSwitchWidget::AudioSwitchWidget(AudioSwitch *s) : SwitchWidget(s)
{
audioSources = new QComboBox();
audioVolumeThreshold = new QSpinBox();
obs_source_t *soruce = nullptr;
if (s)
soruce = obs_weak_source_get_source(s->audioSource);
volMeter = new VolControl(soruce);
obs_source_release(soruce);
whenLabel = new QLabel("When the volume of");
aboveLabel = new QLabel("is above");
switchLabel = new QLabel("switch to");
usingLabel = new QLabel("using");
audioVolumeThreshold->setSuffix("%");
audioVolumeThreshold->setMaximum(100);
audioVolumeThreshold->setMinimum(0);
QWidget::connect(volMeter->GetSlider(), SIGNAL(valueChanged(int)),
audioVolumeThreshold, SLOT(setValue(int)));
QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)),
volMeter->GetSlider(), SLOT(setValue(int)));
QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)), this,
SLOT(VolumeThresholdChanged(int)));
QWidget::connect(audioSources,
SIGNAL(currentTextChanged(const QString &)), this,
SLOT(SourceChanged(const QString &)));
AdvSceneSwitcher::populateAudioSelection(audioSources);
if (s) {
audioSources->setCurrentText(
GetWeakSourceName(s->audioSource).c_str());
audioVolumeThreshold->setValue(s->volumeThreshold);
}
setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *switchLayout = new QHBoxLayout;
switchLayout->addWidget(whenLabel);
switchLayout->addWidget(audioSources);
switchLayout->addWidget(aboveLabel);
switchLayout->addWidget(audioVolumeThreshold);
switchLayout->addWidget(switchLabel);
switchLayout->addWidget(scenes);
switchLayout->addWidget(usingLabel);
switchLayout->addWidget(transitions);
switchLayout->addStretch();
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(switchLayout);
mainLayout->addWidget(volMeter);
setLayout(mainLayout);
switchData = s;
loading = false;
}
AudioSwitch *AudioSwitchWidget::getSwitchData()
{
return switchData;
}
void AudioSwitchWidget::setSwitchData(AudioSwitch *s)
{
switchData = s;
}
void AudioSwitchWidget::swapSwitchData(AudioSwitchWidget *s1,
AudioSwitchWidget *s2)
{
SwitchWidget::swapSwitchData(s1, s2);
AudioSwitch *t = s1->getSwitchData();
s1->setSwitchData(s2->getSwitchData());
s2->setSwitchData(t);
}
void AudioSwitchWidget::UpdateVolmeterSource()
{
delete volMeter;
obs_source_t *soruce =
obs_weak_source_get_source(switchData->audioSource);
volMeter = new VolControl(soruce);
obs_source_release(soruce);
QLayout *layout = this->layout();
layout->addWidget(volMeter);
QWidget::connect(volMeter->GetSlider(), SIGNAL(valueChanged(int)),
audioVolumeThreshold, SLOT(setValue(int)));
QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)),
volMeter->GetSlider(), SLOT(setValue(int)));
// Slider will default to 0 so set it manually once
volMeter->GetSlider()->setValue(switchData->volumeThreshold);
}
void AudioSwitchWidget::SourceChanged(const QString &text)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->audioSource = GetWeakSourceByQString(text);
switchData->resetVolmeter();
UpdateVolmeterSource();
}
void AudioSwitchWidget::VolumeThresholdChanged(int vol)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->volumeThreshold = vol;
} }

View File

@@ -1,148 +1,81 @@
#include "headers/advanced-scene-switcher.hpp" #include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp"
int SceneSwitcher::executableFindByData(const QString &exe) static QMetaObject::Connection addPulse;
void AdvSceneSwitcher::on_executableAdd_clicked()
{ {
int count = ui->executables->count(); ui->executableAdd->disconnect(addPulse);
for (int i = 0; i < count; i++) {
QListWidgetItem *item = ui->executables->item(i);
QString itemExe = item->data(Qt::UserRole).toString();
if (itemExe == exe)
return i;
}
return -1;
}
void SceneSwitcher::on_executables_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem *item = ui->executables->item(idx);
QString exec = item->data(Qt::UserRole).toString();
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->executableSwitches) { switcher->executableSwitches.emplace_back();
if (exec.compare(s.exe) == 0) {
QString sceneName = GetWeakSourceName(s.scene).c_str(); QListWidgetItem *item;
QString transitionName = item = new QListWidgetItem(ui->executables);
GetWeakSourceName(s.transition).c_str(); ui->executables->addItem(item);
ui->executableScenes->setCurrentText(sceneName); ExecutableSwitchWidget *sw = new ExecutableSwitchWidget(
ui->executable->setCurrentText(exec); &switcher->executableSwitches.back());
ui->executableTransitions->setCurrentText( item->setSizeHint(sw->minimumSizeHint());
transitionName); ui->executables->setItemWidget(item, sw);
ui->requiresFocusCheckBox->setChecked(s.inFocus);
break;
}
}
} }
void SceneSwitcher::on_executableUp_clicked() void AdvSceneSwitcher::on_executableRemove_clicked()
{
int index = ui->executables->currentRow();
if (index != -1 && index != 0) {
ui->executables->insertItem(index - 1,
ui->executables->takeItem(index));
ui->executables->setCurrentRow(index - 1);
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(switcher->executableSwitches.begin() + index,
switcher->executableSwitches.begin() + index - 1);
}
}
void SceneSwitcher::on_executableDown_clicked()
{
int index = ui->executables->currentRow();
if (index != -1 && index != ui->executables->count() - 1) {
ui->executables->insertItem(index + 1,
ui->executables->takeItem(index));
ui->executables->setCurrentRow(index + 1);
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(switcher->executableSwitches.begin() + index,
switcher->executableSwitches.begin() + index + 1);
}
}
void SceneSwitcher::on_executableAdd_clicked()
{
QString sceneName = ui->executableScenes->currentText();
QString exeName = ui->executable->currentText();
QString transitionName = ui->executableTransitions->currentText();
bool inFocus = ui->requiresFocusCheckBox->isChecked();
if (exeName.isEmpty() || sceneName.isEmpty())
return;
OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QVariant v = QVariant::fromValue(exeName);
QString text = MakeSwitchNameExecutable(sceneName, exeName,
transitionName, inFocus);
int idx = executableFindByData(exeName);
if (idx == -1) {
std::lock_guard<std::mutex> lock(switcher->m);
switcher->executableSwitches.emplace_back(
source, transition, exeName.toUtf8().constData(),
inFocus);
QListWidgetItem *item =
new QListWidgetItem(text, ui->executables);
item->setData(Qt::UserRole, v);
} else {
QListWidgetItem *item = ui->executables->item(idx);
item->setText(text);
{
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->executableSwitches) {
if (s.exe == exeName) {
s.scene = source;
s.transition = transition;
s.inFocus = inFocus;
break;
}
}
}
}
}
void SceneSwitcher::on_executableRemove_clicked()
{ {
QListWidgetItem *item = ui->executables->currentItem(); QListWidgetItem *item = ui->executables->currentItem();
if (!item) if (!item)
return; return;
QString exe = item->data(Qt::UserRole).toString();
{ {
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
int idx = ui->executables->currentRow();
auto &switches = switcher->executableSwitches; auto &switches = switcher->executableSwitches;
switches.erase(switches.begin() + idx);
for (auto it = switches.begin(); it != switches.end(); ++it) {
auto &s = *it;
if (s.exe == exe) {
switches.erase(it);
break;
}
}
} }
delete item; delete item;
} }
void AdvSceneSwitcher::on_executableUp_clicked()
{
int index = ui->executables->currentRow();
if (!listMoveUp(ui->executables))
return;
ExecutableSwitchWidget *s1 =
(ExecutableSwitchWidget *)ui->executables->itemWidget(
ui->executables->item(index));
ExecutableSwitchWidget *s2 =
(ExecutableSwitchWidget *)ui->executables->itemWidget(
ui->executables->item(index - 1));
ExecutableSwitchWidget::swapSwitchData(s1, s2);
std::lock_guard<std::mutex> lock(switcher->m);
std::swap(switcher->executableSwitches[index],
switcher->executableSwitches[index - 1]);
}
void AdvSceneSwitcher::on_executableDown_clicked()
{
int index = ui->executables->currentRow();
if (!listMoveDown(ui->executables))
return;
ExecutableSwitchWidget *s1 =
(ExecutableSwitchWidget *)ui->executables->itemWidget(
ui->executables->item(index));
ExecutableSwitchWidget *s2 =
(ExecutableSwitchWidget *)ui->executables->itemWidget(
ui->executables->item(index + 1));
ExecutableSwitchWidget::swapSwitchData(s1, s2);
std::lock_guard<std::mutex> lock(switcher->m);
std::swap(switcher->executableSwitches[index],
switcher->executableSwitches[index + 1]);
}
void SwitcherData::checkExeSwitch(bool &match, OBSWeakSource &scene, void SwitcherData::checkExeSwitch(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition) OBSWeakSource &transition)
{ {
@@ -170,7 +103,9 @@ void SwitcherData::checkExeSwitch(bool &match, OBSWeakSource &scene,
// Check for match // Check for match
GetProcessList(runningProcesses); GetProcessList(runningProcesses);
for (ExecutableSceneSwitch &s : executableSwitches) { for (ExecutableSwitch &s : executableSwitches) {
if (!s.initialized())
continue;
// True if executable switch is running (direct) // True if executable switch is running (direct)
bool equals = runningProcesses.contains(s.exe); bool equals = runningProcesses.contains(s.exe);
// True if executable switch is running (regex) // True if executable switch is running (regex)
@@ -199,7 +134,7 @@ void SwitcherData::checkExeSwitch(bool &match, OBSWeakSource &scene,
void SwitcherData::saveExecutableSwitches(obs_data_t *obj) void SwitcherData::saveExecutableSwitches(obs_data_t *obj)
{ {
obs_data_array_t *executableArray = obs_data_array_create(); obs_data_array_t *executableArray = obs_data_array_create();
for (ExecutableSceneSwitch &s : switcher->executableSwitches) { for (ExecutableSwitch &s : switcher->executableSwitches) {
obs_data_t *array_obj = obs_data_create(); obs_data_t *array_obj = obs_data_create();
obs_source_t *source = obs_weak_source_get_source(s.scene); obs_source_t *source = obs_weak_source_get_source(s.scene);
@@ -217,10 +152,9 @@ void SwitcherData::saveExecutableSwitches(obs_data_t *obj)
s.exe.toUtf8()); s.exe.toUtf8());
obs_data_set_bool(array_obj, "infocus", s.inFocus); obs_data_set_bool(array_obj, "infocus", s.inFocus);
obs_data_array_push_back(executableArray, array_obj); obs_data_array_push_back(executableArray, array_obj);
obs_source_release(source);
obs_source_release(transition);
} }
obs_source_release(source);
obs_source_release(transition);
obs_data_release(array_obj); obs_data_release(array_obj);
} }
obs_data_set_array(obj, "executableSwitches", executableArray); obs_data_set_array(obj, "executableSwitches", executableArray);
@@ -253,39 +187,98 @@ void SwitcherData::loadExecutableSwitches(obs_data_t *obj)
obs_data_array_release(executableArray); obs_data_array_release(executableArray);
} }
void SceneSwitcher::setupExecutableTab() void AdvSceneSwitcher::setupExecutableTab()
{ {
populateSceneSelection(ui->executableScenes, false);
populateTransitionSelection(ui->executableTransitions);
QStringList processes;
GetProcessList(processes);
for (QString &process : processes)
ui->executable->addItem(process);
for (auto &s : switcher->executableSwitches) { for (auto &s : switcher->executableSwitches) {
std::string sceneName = GetWeakSourceName(s.scene); QListWidgetItem *item;
std::string transitionName = GetWeakSourceName(s.transition); item = new QListWidgetItem(ui->executables);
QString text = MakeSwitchNameExecutable(sceneName.c_str(), ui->executables->addItem(item);
s.exe, ExecutableSwitchWidget *sw = new ExecutableSwitchWidget(&s);
transitionName.c_str(), item->setSizeHint(sw->minimumSizeHint());
s.inFocus); ui->executables->setItemWidget(item, sw);
QListWidgetItem *item =
new QListWidgetItem(text, ui->executables);
item->setData(Qt::UserRole, s.exe);
} }
if (switcher->executableSwitches.size() == 0)
addPulse = PulseWidget(ui->executableAdd, QColor(Qt::green));
} }
static inline QString MakeSwitchNameExecutable(const QString &scene, ExecutableSwitchWidget::ExecutableSwitchWidget(ExecutableSwitch *s)
const QString &value, : SwitchWidget(s, false)
const QString &transition,
bool inFocus)
{ {
if (!inFocus) processes = new QComboBox();
return QStringLiteral("[") + scene + QStringLiteral(", ") + requiresFocus = new QCheckBox("only if focused");
transition + QStringLiteral("]: ") + value;
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition + whenLabel = new QLabel("When");
QStringLiteral("]: ") + value + switchLabel = new QLabel("is running switch to");
QStringLiteral(" (only if focused)"); usingLabel = new QLabel("using");
QWidget::connect(processes, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(ProcessChanged(const QString &)));
QWidget::connect(requiresFocus, SIGNAL(stateChanged(int)), this,
SLOT(FocusChanged(int)));
AdvSceneSwitcher::populateProcessSelection(processes);
processes->setEditable(true);
processes->setMaxVisibleItems(20);
if (s) {
processes->setCurrentText(s->exe);
requiresFocus->setChecked(s->inFocus);
}
setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(whenLabel);
mainLayout->addWidget(processes);
mainLayout->addWidget(switchLabel);
mainLayout->addWidget(scenes);
mainLayout->addWidget(usingLabel);
mainLayout->addWidget(transitions);
mainLayout->addWidget(requiresFocus);
mainLayout->addStretch();
setLayout(mainLayout);
switchData = s;
loading = false;
}
ExecutableSwitch *ExecutableSwitchWidget::getSwitchData()
{
return switchData;
}
void ExecutableSwitchWidget::setSwitchData(ExecutableSwitch *s)
{
switchData = s;
}
void ExecutableSwitchWidget::swapSwitchData(ExecutableSwitchWidget *s1,
ExecutableSwitchWidget *s2)
{
SwitchWidget::swapSwitchData(s1, s2);
ExecutableSwitch *t = s1->getSwitchData();
s1->setSwitchData(s2->getSwitchData());
s2->setSwitchData(t);
}
void ExecutableSwitchWidget::ProcessChanged(const QString &text)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->exe = text;
}
void ExecutableSwitchWidget::FocusChanged(int state)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->inFocus = state;
} }

View File

@@ -5,11 +5,12 @@
#include "headers/advanced-scene-switcher.hpp" #include "headers/advanced-scene-switcher.hpp"
#include "headers/curl-helper.hpp" #include "headers/curl-helper.hpp"
#include "headers/utility.hpp"
#define LOCAL_FILE_IDX 0 #define LOCAL_FILE_IDX 0
#define REMOTE_FILE_IDX 1 #define REMOTE_FILE_IDX 1
void SceneSwitcher::on_browseButton_clicked() void AdvSceneSwitcher::on_browseButton_clicked()
{ {
QString path = QFileDialog::getOpenFileName( QString path = QFileDialog::getOpenFileName(
this, tr("Select a file to write to ..."), QDir::currentPath(), this, tr("Select a file to write to ..."), QDir::currentPath(),
@@ -18,7 +19,7 @@ void SceneSwitcher::on_browseButton_clicked()
ui->writePathLineEdit->setText(path); ui->writePathLineEdit->setText(path);
} }
void SceneSwitcher::on_readFileCheckBox_stateChanged(int state) void AdvSceneSwitcher::on_readFileCheckBox_stateChanged(int state)
{ {
if (loading) if (loading)
return; return;
@@ -35,7 +36,7 @@ void SceneSwitcher::on_readFileCheckBox_stateChanged(int state)
} }
} }
void SceneSwitcher::on_readPathLineEdit_textChanged(const QString &text) void AdvSceneSwitcher::on_readPathLineEdit_textChanged(const QString &text)
{ {
if (loading) if (loading)
return; return;
@@ -49,7 +50,7 @@ void SceneSwitcher::on_readPathLineEdit_textChanged(const QString &text)
switcher->fileIO.readPath = text.toUtf8().constData(); switcher->fileIO.readPath = text.toUtf8().constData();
} }
void SceneSwitcher::on_writePathLineEdit_textChanged(const QString &text) void AdvSceneSwitcher::on_writePathLineEdit_textChanged(const QString &text)
{ {
if (loading) if (loading)
return; return;
@@ -63,7 +64,7 @@ void SceneSwitcher::on_writePathLineEdit_textChanged(const QString &text)
switcher->fileIO.writePath = text.toUtf8().constData(); switcher->fileIO.writePath = text.toUtf8().constData();
} }
void SceneSwitcher::on_browseButton_2_clicked() void AdvSceneSwitcher::on_browseButton_2_clicked()
{ {
QString path = QFileDialog::getOpenFileName( QString path = QFileDialog::getOpenFileName(
this, tr("Select a file to read from ..."), QDir::currentPath(), this, tr("Select a file to read from ..."), QDir::currentPath(),
@@ -223,7 +224,7 @@ void SwitcherData::checkFileContent(bool &match, OBSWeakSource &scene,
} }
} }
void SceneSwitcher::on_browseButton_3_clicked() void AdvSceneSwitcher::on_browseButton_3_clicked()
{ {
QString path = QFileDialog::getOpenFileName( QString path = QFileDialog::getOpenFileName(
this, tr("Select a file to read from ..."), QDir::currentPath(), this, tr("Select a file to read from ..."), QDir::currentPath(),
@@ -232,7 +233,7 @@ void SceneSwitcher::on_browseButton_3_clicked()
ui->filePathLineEdit->setText(path); ui->filePathLineEdit->setText(path);
} }
void SceneSwitcher::on_fileType_currentIndexChanged(int idx) void AdvSceneSwitcher::on_fileType_currentIndexChanged(int idx)
{ {
if (idx == -1) if (idx == -1)
return; return;
@@ -248,7 +249,7 @@ void SceneSwitcher::on_fileType_currentIndexChanged(int idx)
} }
} }
void SceneSwitcher::on_fileAdd_clicked() void AdvSceneSwitcher::on_fileAdd_clicked()
{ {
QString sceneName = ui->fileScenes->currentText(); QString sceneName = ui->fileScenes->currentText();
QString transitionName = ui->fileTransitions->currentText(); QString transitionName = ui->fileTransitions->currentText();
@@ -280,7 +281,7 @@ void SceneSwitcher::on_fileAdd_clicked()
useRegex, useTime); useRegex, useTime);
} }
void SceneSwitcher::on_fileRemove_clicked() void AdvSceneSwitcher::on_fileRemove_clicked()
{ {
QListWidgetItem *item = ui->fileScenesList->currentItem(); QListWidgetItem *item = ui->fileScenesList->currentItem();
if (!item) if (!item)
@@ -299,7 +300,7 @@ void SceneSwitcher::on_fileRemove_clicked()
qDeleteAll(ui->fileScenesList->selectedItems()); qDeleteAll(ui->fileScenesList->selectedItems());
} }
void SceneSwitcher::on_fileScenesList_currentRowChanged(int idx) void AdvSceneSwitcher::on_fileScenesList_currentRowChanged(int idx)
{ {
if (loading) if (loading)
return; return;
@@ -327,7 +328,7 @@ void SceneSwitcher::on_fileScenesList_currentRowChanged(int idx)
ui->fileContentTimeCheckBox->setChecked(s.useTime); ui->fileContentTimeCheckBox->setChecked(s.useTime);
} }
void SceneSwitcher::on_fileUp_clicked() void AdvSceneSwitcher::on_fileUp_clicked()
{ {
int index = ui->fileScenesList->currentRow(); int index = ui->fileScenesList->currentRow();
if (index != -1 && index != 0) { if (index != -1 && index != 0) {
@@ -342,7 +343,7 @@ void SceneSwitcher::on_fileUp_clicked()
} }
} }
void SceneSwitcher::on_fileDown_clicked() void AdvSceneSwitcher::on_fileDown_clicked()
{ {
int index = ui->fileScenesList->currentRow(); int index = ui->fileScenesList->currentRow();
if (index != -1 && index != ui->fileScenesList->count() - 1) { if (index != -1 && index != ui->fileScenesList->count() - 1) {
@@ -380,10 +381,9 @@ void SwitcherData::saveFileSwitches(obs_data_t *obj)
obs_data_set_bool(array_obj, "useRegex", s.useRegex); obs_data_set_bool(array_obj, "useRegex", s.useRegex);
obs_data_set_bool(array_obj, "useTime", s.useTime); obs_data_set_bool(array_obj, "useTime", s.useTime);
obs_data_array_push_back(fileArray, array_obj); obs_data_array_push_back(fileArray, array_obj);
obs_source_release(source);
obs_source_release(transition);
} }
obs_source_release(source);
obs_source_release(transition);
obs_data_release(array_obj); obs_data_release(array_obj);
} }
obs_data_set_array(obj, "fileSwitches", fileArray); obs_data_set_array(obj, "fileSwitches", fileArray);
@@ -431,7 +431,7 @@ void SwitcherData::loadFileSwitches(obs_data_t *obj)
switcher->fileIO.writePath = obs_data_get_string(obj, "writePath"); switcher->fileIO.writePath = obs_data_get_string(obj, "writePath");
} }
void SceneSwitcher::setupFileTab() void AdvSceneSwitcher::setupFileTab()
{ {
populateSceneSelection(ui->fileScenes, false); populateSceneSelection(ui->fileScenes, false);
populateTransitionSelection(ui->fileTransitions); populateTransitionSelection(ui->fileTransitions);

89
src/switch-generic.cpp Normal file
View File

@@ -0,0 +1,89 @@
#include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp"
bool SceneSwitcherEntry::initialized()
{
return (usePreviousScene || WeakSourceValid(scene)) && transition;
}
bool SceneSwitcherEntry::valid()
{
return !initialized() ||
((usePreviousScene || WeakSourceValid(scene)) &&
WeakSourceValid(transition));
}
void SceneSwitcherEntry::logMatch()
{
const char *sceneName = previous_scene_name;
if (!usePreviousScene) {
obs_source_t *s = obs_weak_source_get_source(scene);
sceneName = obs_source_get_name(s);
obs_source_release(s);
}
blog(LOG_INFO, "match for '%s' - switch to scene '%s'", getType(),
sceneName);
}
SwitchWidget::SwitchWidget(SceneSwitcherEntry *s, bool usePreviousScene)
{
scenes = new QComboBox();
transitions = new QComboBox();
QWidget::connect(scenes, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(SceneChanged(const QString &)));
QWidget::connect(transitions,
SIGNAL(currentTextChanged(const QString &)), this,
SLOT(TransitionChanged(const QString &)));
AdvSceneSwitcher::populateSceneSelection(scenes, usePreviousScene);
AdvSceneSwitcher::populateTransitionSelection(transitions);
if (s) {
if (s->usePreviousScene)
scenes->setCurrentText(previous_scene_name);
else
scenes->setCurrentText(
GetWeakSourceName(s->scene).c_str());
transitions->setCurrentText(
GetWeakSourceName(s->transition).c_str());
}
switchData = s;
}
SceneSwitcherEntry *SwitchWidget::getSwitchData()
{
return switchData;
}
void SwitchWidget::setSwitchData(SceneSwitcherEntry *s)
{
switchData = s;
}
void SwitchWidget::swapSwitchData(SwitchWidget *s1, SwitchWidget *s2)
{
SceneSwitcherEntry *t = s1->getSwitchData();
s1->setSwitchData(s2->getSwitchData());
s2->setSwitchData(t);
}
void SwitchWidget::SceneChanged(const QString &text)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->usePreviousScene = text.compare(previous_scene_name) == 0;
if (switchData->usePreviousScene)
return;
switchData->scene = GetWeakSourceByQString(text);
}
void SwitchWidget::TransitionChanged(const QString &text)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->transition = GetWeakTransitionByQString(text);
}

View File

@@ -1,6 +1,7 @@
#include <regex> #include <regex>
#include "headers/advanced-scene-switcher.hpp" #include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp"
void SwitcherData::checkIdleSwitch(bool &match, OBSWeakSource &scene, void SwitcherData::checkIdleSwitch(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition) OBSWeakSource &transition)
@@ -50,7 +51,7 @@ void SwitcherData::checkIdleSwitch(bool &match, OBSWeakSource &scene,
idleData.alreadySwitched = false; idleData.alreadySwitched = false;
} }
void SceneSwitcher::on_idleCheckBox_stateChanged(int state) void AdvSceneSwitcher::on_idleCheckBox_stateChanged(int state)
{ {
if (loading) if (loading)
return; return;
@@ -74,13 +75,13 @@ void SceneSwitcher::on_idleCheckBox_stateChanged(int state)
} }
} }
void SceneSwitcher::UpdateIdleDataTransition(const QString &name) void AdvSceneSwitcher::UpdateIdleDataTransition(const QString &name)
{ {
obs_weak_source_t *transition = GetWeakTransitionByQString(name); obs_weak_source_t *transition = GetWeakTransitionByQString(name);
switcher->idleData.transition = transition; switcher->idleData.transition = transition;
} }
void SceneSwitcher::UpdateIdleDataScene(const QString &name) void AdvSceneSwitcher::UpdateIdleDataScene(const QString &name)
{ {
switcher->idleData.usePreviousScene = (name == previous_scene_name); switcher->idleData.usePreviousScene = (name == previous_scene_name);
obs_source_t *scene = obs_get_source_by_name(name.toUtf8().constData()); obs_source_t *scene = obs_get_source_by_name(name.toUtf8().constData());
@@ -92,7 +93,7 @@ void SceneSwitcher::UpdateIdleDataScene(const QString &name)
obs_source_release(scene); obs_source_release(scene);
} }
void SceneSwitcher::on_idleTransitions_currentTextChanged(const QString &text) void AdvSceneSwitcher::on_idleTransitions_currentTextChanged(const QString &text)
{ {
if (loading) if (loading)
return; return;
@@ -101,7 +102,7 @@ void SceneSwitcher::on_idleTransitions_currentTextChanged(const QString &text)
UpdateIdleDataTransition(text); UpdateIdleDataTransition(text);
} }
void SceneSwitcher::on_idleScenes_currentTextChanged(const QString &text) void AdvSceneSwitcher::on_idleScenes_currentTextChanged(const QString &text)
{ {
if (loading) if (loading)
return; return;
@@ -110,7 +111,7 @@ void SceneSwitcher::on_idleScenes_currentTextChanged(const QString &text)
UpdateIdleDataScene(text); UpdateIdleDataScene(text);
} }
void SceneSwitcher::on_idleSpinBox_valueChanged(int i) void AdvSceneSwitcher::on_idleSpinBox_valueChanged(int i)
{ {
if (loading) if (loading)
return; return;
@@ -118,7 +119,7 @@ void SceneSwitcher::on_idleSpinBox_valueChanged(int i)
switcher->idleData.time = i; switcher->idleData.time = i;
} }
void SceneSwitcher::on_ignoreIdleWindows_currentRowChanged(int idx) void AdvSceneSwitcher::on_ignoreIdleWindows_currentRowChanged(int idx)
{ {
if (loading) if (loading)
return; return;
@@ -138,7 +139,7 @@ void SceneSwitcher::on_ignoreIdleWindows_currentRowChanged(int idx)
} }
} }
void SceneSwitcher::on_ignoreIdleAdd_clicked() void AdvSceneSwitcher::on_ignoreIdleAdd_clicked()
{ {
QString windowName = ui->ignoreIdleWindowsWindows->currentText(); QString windowName = ui->ignoreIdleWindowsWindows->currentText();
@@ -162,7 +163,7 @@ void SceneSwitcher::on_ignoreIdleAdd_clicked()
} }
} }
void SceneSwitcher::on_ignoreIdleRemove_clicked() void AdvSceneSwitcher::on_ignoreIdleRemove_clicked()
{ {
QListWidgetItem *item = ui->ignoreIdleWindows->currentItem(); QListWidgetItem *item = ui->ignoreIdleWindows->currentItem();
if (!item) if (!item)
@@ -187,7 +188,7 @@ void SceneSwitcher::on_ignoreIdleRemove_clicked()
delete item; delete item;
} }
int SceneSwitcher::IgnoreIdleWindowsFindByData(const QString &window) int AdvSceneSwitcher::IgnoreIdleWindowsFindByData(const QString &window)
{ {
int count = ui->ignoreIdleWindows->count(); int count = ui->ignoreIdleWindows->count();
int idx = -1; int idx = -1;
@@ -264,7 +265,7 @@ void SwitcherData::loadIdleSwitches(obs_data_t *obj)
(idleSceneName == previous_scene_name); (idleSceneName == previous_scene_name);
} }
void SceneSwitcher::setupIdleTab() void AdvSceneSwitcher::setupIdleTab()
{ {
populateSceneSelection(ui->idleScenes, true); populateSceneSelection(ui->idleScenes, true);
populateTransitionSelection(ui->idleTransitions); populateTransitionSelection(ui->idleTransitions);

View File

@@ -1,164 +1,157 @@
#include "headers/advanced-scene-switcher.hpp" #include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp"
void SceneSwitcher::on_mediaSwitches_currentRowChanged(int idx) static QMetaObject::Connection addPulse;
void AdvSceneSwitcher::on_mediaAdd_clicked()
{ {
if (loading) ui->mediaAdd->disconnect(addPulse);
return;
if (idx == -1)
return;
QListWidgetItem *item = ui->mediaSwitches->item(idx);
QString mediaSceneStr = item->data(Qt::UserRole).toString();
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->mediaSwitches) { switcher->mediaSwitches.emplace_back();
if (mediaSceneStr.compare(s.mediaSwitchStr.c_str()) == 0) {
QString sceneName = GetWeakSourceName(s.scene).c_str(); QListWidgetItem *item;
QString sourceName = item = new QListWidgetItem(ui->mediaSwitches);
GetWeakSourceName(s.source).c_str(); ui->mediaSwitches->addItem(item);
QString transitionName = MediaSwitchWidget *sw =
GetWeakSourceName(s.transition).c_str(); new MediaSwitchWidget(&switcher->mediaSwitches.back());
ui->mediaScenes->setCurrentText(sceneName); item->setSizeHint(sw->minimumSizeHint());
ui->mediaSources->setCurrentText(sourceName); ui->mediaSwitches->setItemWidget(item, sw);
ui->mediaTransitions->setCurrentText(transitionName);
ui->mediaStates->setCurrentIndex(s.state);
ui->mediaTimeRestrictions->setCurrentIndex(
s.restriction);
ui->mediaTime->setValue(s.time);
break;
}
}
} }
void SceneSwitcher::on_mediaAdd_clicked() void AdvSceneSwitcher::on_mediaRemove_clicked()
{
QString sourceName = ui->mediaSources->currentText();
QString sceneName = ui->mediaScenes->currentText();
QString transitionName = ui->mediaTransitions->currentText();
obs_media_state state =
(obs_media_state)ui->mediaStates->currentIndex();
time_restriction restriction =
(time_restriction)ui->mediaTimeRestrictions->currentIndex();
uint64_t time = ui->mediaTime->value();
if (sceneName.isEmpty() || transitionName.isEmpty() ||
sourceName.isEmpty())
return;
OBSWeakSource source = GetWeakSourceByQString(sourceName);
OBSWeakSource scene = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QString switchText = MakeMediaSwitchName(sourceName, sceneName,
transitionName, state,
restriction, time);
QVariant v = QVariant::fromValue(switchText);
QListWidgetItem *item =
new QListWidgetItem(switchText, ui->mediaSwitches);
item->setData(Qt::UserRole, v);
std::lock_guard<std::mutex> lock(switcher->m);
switcher->mediaSwitches.emplace_back(
scene, source, transition, state, restriction, time,
(sceneName == QString(previous_scene_name)),
switchText.toUtf8().constData());
}
void SceneSwitcher::on_mediaRemove_clicked()
{ {
QListWidgetItem *item = ui->mediaSwitches->currentItem(); QListWidgetItem *item = ui->mediaSwitches->currentItem();
if (!item) if (!item)
return; return;
std::string mediaStr =
item->data(Qt::UserRole).toString().toUtf8().constData();
{ {
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
int idx = ui->mediaSwitches->currentRow();
auto &switches = switcher->mediaSwitches; auto &switches = switcher->mediaSwitches;
switches.erase(switches.begin() + idx);
for (auto it = switches.begin(); it != switches.end(); ++it) {
auto &s = *it;
if (s.mediaSwitchStr == mediaStr) {
switches.erase(it);
break;
}
}
} }
delete item; delete item;
} }
void SceneSwitcher::on_mediaUp_clicked() void AdvSceneSwitcher::on_mediaUp_clicked()
{ {
int index = ui->mediaSwitches->currentRow(); int index = ui->mediaSwitches->currentRow();
if (index != -1 && index != 0) { if (!listMoveUp(ui->mediaSwitches))
ui->mediaSwitches->insertItem(
index - 1, ui->mediaSwitches->takeItem(index));
ui->mediaSwitches->setCurrentRow(index - 1);
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(switcher->mediaSwitches.begin() + index,
switcher->mediaSwitches.begin() + index - 1);
}
}
void SceneSwitcher::on_mediaDown_clicked()
{
int index = ui->mediaSwitches->currentRow();
if (index != -1 && index != ui->mediaSwitches->count() - 1) {
ui->mediaSwitches->insertItem(
index + 1, ui->mediaSwitches->takeItem(index));
ui->mediaSwitches->setCurrentRow(index + 1);
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(switcher->mediaSwitches.begin() + index,
switcher->mediaSwitches.begin() + index + 1);
}
}
void SceneSwitcher::on_mediaTimeRestrictions_currentIndexChanged(int idx)
{
if (idx == -1)
return; return;
if ((time_restriction)ui->mediaTimeRestrictions->currentIndex() == MediaSwitchWidget *s1 =
TIME_RESTRICTION_NONE) { (MediaSwitchWidget *)ui->mediaSwitches->itemWidget(
ui->mediaTime->setDisabled(true); ui->mediaSwitches->item(index));
} else { MediaSwitchWidget *s2 =
ui->mediaTime->setDisabled(false); (MediaSwitchWidget *)ui->mediaSwitches->itemWidget(
} ui->mediaSwitches->item(index - 1));
MediaSwitchWidget::swapSwitchData(s1, s2);
std::lock_guard<std::mutex> lock(switcher->m);
std::swap(switcher->mediaSwitches[index],
switcher->mediaSwitches[index - 1]);
}
void AdvSceneSwitcher::on_mediaDown_clicked()
{
int index = ui->mediaSwitches->currentRow();
if (!listMoveDown(ui->mediaSwitches))
return;
MediaSwitchWidget *s1 =
(MediaSwitchWidget *)ui->mediaSwitches->itemWidget(
ui->mediaSwitches->item(index));
MediaSwitchWidget *s2 =
(MediaSwitchWidget *)ui->mediaSwitches->itemWidget(
ui->mediaSwitches->item(index + 1));
MediaSwitchWidget::swapSwitchData(s1, s2);
std::lock_guard<std::mutex> lock(switcher->m);
std::swap(switcher->mediaSwitches[index],
switcher->mediaSwitches[index + 1]);
} }
void SwitcherData::checkMediaSwitch(bool &match, OBSWeakSource &scene, void SwitcherData::checkMediaSwitch(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition) OBSWeakSource &transition)
{ {
for (MediaSwitch &mediaSwitch : mediaSwitches) { for (MediaSwitch &mediaSwitch : mediaSwitches) {
if (!mediaSwitch.initialized())
continue;
obs_source_t *source = obs_source_t *source =
obs_weak_source_get_source(mediaSwitch.source); obs_weak_source_get_source(mediaSwitch.source);
auto duration = obs_source_media_get_duration(source); auto duration = obs_source_media_get_duration(source);
auto time = obs_source_media_get_time(source); auto time = obs_source_media_get_time(source);
obs_media_state state = obs_source_media_get_state(source); obs_media_state state = obs_source_media_get_state(source);
bool matched = obs_source_release(source);
state == mediaSwitch.state &&
(mediaSwitch.restriction == TIME_RESTRICTION_NONE || bool matchedStopped = mediaSwitch.state ==
(mediaSwitch.restriction == TIME_RESTRICTION_LONGER && OBS_MEDIA_STATE_STOPPED &&
time > mediaSwitch.time) || mediaSwitch.stopped;
(mediaSwitch.restriction == TIME_RESTRICTION_SHORTER &&
time < mediaSwitch.time) || // The signal for the state ended is intentionally not used here
(mediaSwitch.restriction == // so matchedEnded can be used to specify the end of a VLC playlist
TIME_RESTRICTION_REMAINING_SHORTER && // by two consequtive matches of OBS_MEDIA_STATE_ENDED
duration > time && //
duration - time < mediaSwitch.time) || // This was done to reduce the likelyhood of interpreting a single
(mediaSwitch.restriction == // OBS_MEDIA_STATE_ENDED caught by obs_source_media_get_state()
TIME_RESTRICTION_REMAINING_LONGER && // as the end of the playlist of the VLC source, while actually being
duration > time && // in the middle of switching to the next item of the playlist
duration - time > mediaSwitch.time)); //
if (matched && !mediaSwitch.matched) { // If there is a separate obs_media_sate in the future for the
// "end of playlist reached" signal the line below can be used
// and an additional check for this new singal can be introduced
//
// bool matchedEnded = mediaSwitch.state == OBS_MEDIA_STATE_ENDED &&
// mediaSwitch.ended;
bool matchedEnded = false;
if (state == OBS_MEDIA_STATE_ENDED) {
matchedEnded = mediaSwitch.previousStateEnded;
mediaSwitch.previousStateEnded = true;
} else {
mediaSwitch.previousStateEnded = false;
}
// reset for next check
mediaSwitch.stopped = false;
mediaSwitch.ended = false;
bool matchedState = ((state == mediaSwitch.state) ||
mediaSwitch.anyState) ||
matchedStopped || matchedEnded;
bool matchedTimeNone =
(mediaSwitch.restriction == TIME_RESTRICTION_NONE);
bool matchedTimeLonger =
(mediaSwitch.restriction == TIME_RESTRICTION_LONGER) &&
(time > mediaSwitch.time);
bool matchedTimeShorter =
(mediaSwitch.restriction == TIME_RESTRICTION_SHORTER) &&
(time < mediaSwitch.time);
bool matchedTimeRemainLonger =
(mediaSwitch.restriction ==
TIME_RESTRICTION_REMAINING_LONGER) &&
(duration > time && duration - time > mediaSwitch.time);
bool matchedTimeRemainShorter =
(mediaSwitch.restriction ==
TIME_RESTRICTION_REMAINING_SHORTER) &&
(duration > time && duration - time < mediaSwitch.time);
bool matchedTime = matchedTimeNone || matchedTimeLonger ||
matchedTimeShorter ||
matchedTimeRemainLonger ||
matchedTimeRemainShorter;
bool matched = matchedState && matchedTime;
if (matched) {
match = true; match = true;
scene = (mediaSwitch.usePreviousScene) scene = (mediaSwitch.usePreviousScene)
? previousScene ? previousScene
@@ -167,9 +160,8 @@ void SwitcherData::checkMediaSwitch(bool &match, OBSWeakSource &scene,
if (verbose) if (verbose)
mediaSwitch.logMatch(); mediaSwitch.logMatch();
break;
} }
mediaSwitch.matched = matched;
obs_source_release(source);
} }
} }
@@ -233,113 +225,311 @@ void SwitcherData::loadMediaSwitches(obs_data_t *obj)
"restriction"); "restriction");
uint64_t time = obs_data_get_int(array_obj, "time"); uint64_t time = obs_data_get_int(array_obj, "time");
std::string mediaStr = MakeMediaSwitchName(source, scene,
transition, state,
restriction, time)
.toUtf8()
.constData();
switcher->mediaSwitches.emplace_back( switcher->mediaSwitches.emplace_back(
GetWeakSourceByName(scene), GetWeakSourceByName(source), GetWeakSourceByName(scene), GetWeakSourceByName(source),
GetWeakTransitionByName(transition), state, restriction, GetWeakTransitionByName(transition), state, restriction,
time, (strcmp(scene, previous_scene_name) == 0), time, (strcmp(scene, previous_scene_name) == 0));
mediaStr);
obs_data_release(array_obj); obs_data_release(array_obj);
} }
obs_data_array_release(mediaArray); obs_data_array_release(mediaArray);
} }
void SceneSwitcher::setupMediaTab() void AdvSceneSwitcher::setupMediaTab()
{ {
populateSceneSelection(ui->mediaScenes, true);
populateTransitionSelection(ui->mediaTransitions);
auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */
{
QComboBox *combo = reinterpret_cast<QComboBox *>(data);
std::string sourceId = obs_source_get_id(source);
if (sourceId.compare("ffmpeg_source") == 0 ||
sourceId.compare("vlc_source") == 0) {
const char *name = obs_source_get_name(source);
combo->addItem(name);
}
return true;
};
obs_enum_sources(sourceEnum, ui->mediaSources);
ui->mediaStates->addItem("None");
ui->mediaStates->addItem("Playing");
ui->mediaStates->addItem("Opening");
ui->mediaStates->addItem("Buffering");
ui->mediaStates->addItem("Paused");
ui->mediaStates->addItem("Stopped");
ui->mediaStates->addItem("Ended");
ui->mediaStates->addItem("Error");
ui->mediaTimeRestrictions->addItem("None");
ui->mediaTimeRestrictions->addItem("Time shorter");
ui->mediaTimeRestrictions->addItem("Time longer");
ui->mediaTimeRestrictions->addItem("Time remaining shorter");
ui->mediaTimeRestrictions->addItem("Time remaining longer");
for (auto &s : switcher->mediaSwitches) { for (auto &s : switcher->mediaSwitches) {
std::string sourceName = GetWeakSourceName(s.source); QListWidgetItem *item;
std::string sceneName = (s.usePreviousScene) item = new QListWidgetItem(ui->mediaSwitches);
? previous_scene_name ui->mediaSwitches->addItem(item);
: GetWeakSourceName(s.scene); MediaSwitchWidget *sw = new MediaSwitchWidget(&s);
std::string transitionName = GetWeakSourceName(s.transition); item->setSizeHint(sw->minimumSizeHint());
QString listText = MakeMediaSwitchName( ui->mediaSwitches->setItemWidget(item, sw);
sourceName.c_str(), sceneName.c_str(),
transitionName.c_str(), s.state, s.restriction, s.time);
QListWidgetItem *item =
new QListWidgetItem(listText, ui->mediaSwitches);
item->setData(Qt::UserRole, listText);
} }
if (switcher->mediaSwitches.size() == 0)
addPulse = PulseWidget(ui->mediaAdd, QColor(Qt::green));
} }
static inline QString bool MediaSwitch::initialized()
MakeMediaSwitchName(const QString &source, const QString &scene,
const QString &transition, obs_media_state state,
time_restriction restriction, uint64_t time)
{ {
QString switchName = QStringLiteral("Switch to ") + scene + return SceneSwitcherEntry::initialized() && source;
QStringLiteral(" using ") + transition + }
QStringLiteral(" if ") + source +
QStringLiteral(" state is "); bool MediaSwitch::valid()
if (state == OBS_MEDIA_STATE_NONE) { {
switchName += QStringLiteral("none"); return !initialized() ||
} else if (state == OBS_MEDIA_STATE_PLAYING) { (SceneSwitcherEntry::valid() && WeakSourceValid(source));
switchName += QStringLiteral("playing"); }
} else if (state == OBS_MEDIA_STATE_OPENING) {
switchName += QStringLiteral("opening"); void MediaSwitch::clearSignalHandler()
} else if (state == OBS_MEDIA_STATE_BUFFERING) { {
switchName += QStringLiteral("buffering"); obs_source_t *mediasource = obs_weak_source_get_source(source);
} else if (state == OBS_MEDIA_STATE_PAUSED) { signal_handler_t *sh = obs_source_get_signal_handler(mediasource);
switchName += QStringLiteral("paused"); signal_handler_disconnect(sh, "media_stopped", MediaStopped, this);
} else if (state == OBS_MEDIA_STATE_STOPPED) { signal_handler_disconnect(sh, "media_ended", MediaEnded, this);
switchName += QStringLiteral("stopped"); obs_source_release(mediasource);
} else if (state == OBS_MEDIA_STATE_ENDED) { }
switchName += QStringLiteral("ended");
} else if (state == OBS_MEDIA_STATE_ERROR) { void MediaSwitch::resetSignalHandler()
switchName += QStringLiteral("error"); {
} obs_source_t *mediasource = obs_weak_source_get_source(source);
if (restriction == TIME_RESTRICTION_SHORTER) { signal_handler_t *sh = obs_source_get_signal_handler(mediasource);
switchName += QStringLiteral(" and time shorter than "); signal_handler_disconnect(sh, "media_stopped", MediaStopped, this);
} else if (restriction == TIME_RESTRICTION_LONGER) { signal_handler_disconnect(sh, "media_ended", MediaEnded, this);
switchName += QStringLiteral(" and time longer than "); signal_handler_connect(sh, "media_stopped", MediaStopped, this);
} else if (restriction == TIME_RESTRICTION_REMAINING_SHORTER) { signal_handler_connect(sh, "media_ended", MediaEnded, this);
switchName += obs_source_release(mediasource);
QStringLiteral(" and time remaining shorter than "); }
} else if (restriction == TIME_RESTRICTION_REMAINING_LONGER) {
switchName += void MediaSwitch::MediaStopped(void *data, calldata_t *)
QStringLiteral(" and time remaining longer than "); {
} MediaSwitch *media = static_cast<MediaSwitch *>(data);
if (restriction != TIME_RESTRICTION_NONE) { media->stopped = true;
switchName += std::to_string(time).c_str(); }
switchName += QStringLiteral(" ms");
} void MediaSwitch::MediaEnded(void *data, calldata_t *)
return switchName; {
MediaSwitch *media = static_cast<MediaSwitch *>(data);
media->ended = true;
}
inline MediaSwitch::MediaSwitch(OBSWeakSource scene_, OBSWeakSource source_,
OBSWeakSource transition_,
obs_media_state state_,
time_restriction restriction_, uint64_t time_,
bool usePreviousScene_)
: SceneSwitcherEntry(scene_, transition_, usePreviousScene_),
source(source_),
state(state_),
restriction(restriction_),
time(time_)
{
anyState = state > 7;
obs_source_t *mediasource = obs_weak_source_get_source(source);
signal_handler_t *sh = obs_source_get_signal_handler(mediasource);
signal_handler_connect(sh, "media_stopped", MediaStopped, this);
signal_handler_connect(sh, "media_ended", MediaEnded, this);
obs_source_release(mediasource);
}
MediaSwitch::MediaSwitch(const MediaSwitch &other)
: SceneSwitcherEntry(other.scene, other.transition,
other.usePreviousScene),
source(other.source),
state(other.state),
restriction(other.restriction),
time(other.time)
{
anyState = state > 7;
obs_source_t *mediasource = obs_weak_source_get_source(source);
signal_handler_t *sh = obs_source_get_signal_handler(mediasource);
signal_handler_connect(sh, "media_stopped", MediaStopped, this);
signal_handler_connect(sh, "media_ended", MediaEnded, this);
obs_source_release(mediasource);
}
MediaSwitch::MediaSwitch(MediaSwitch &&other)
: SceneSwitcherEntry(other.scene, other.transition,
other.usePreviousScene),
source(other.source),
state(other.state),
anyState(other.anyState),
restriction(other.restriction),
time(other.time)
{
}
MediaSwitch::~MediaSwitch()
{
obs_source_t *mediasource = obs_weak_source_get_source(source);
signal_handler_t *sh = obs_source_get_signal_handler(mediasource);
signal_handler_disconnect(sh, "media_stopped", MediaStopped, this);
signal_handler_disconnect(sh, "media_ended", MediaEnded, this);
obs_source_release(mediasource);
}
MediaSwitch &MediaSwitch::operator=(const MediaSwitch &other)
{
MediaSwitch t(other);
swap(*this, t);
return *this = MediaSwitch(other);
}
MediaSwitch &MediaSwitch::operator=(MediaSwitch &&other) noexcept
{
if (this == &other) {
return *this;
}
swap(*this, other);
obs_source_t *mediasource = obs_weak_source_get_source(other.source);
signal_handler_t *sh = obs_source_get_signal_handler(mediasource);
signal_handler_disconnect(sh, "media_stopped", MediaStopped, &other);
signal_handler_disconnect(sh, "media_ended", MediaEnded, &other);
obs_source_release(mediasource);
return *this;
}
void swap(MediaSwitch &first, MediaSwitch &second)
{
std::swap(first.scene, second.scene);
std::swap(first.transition, second.transition);
std::swap(first.usePreviousScene, second.usePreviousScene);
std::swap(first.source, second.source);
std::swap(first.state, second.state);
std::swap(first.restriction, second.restriction);
std::swap(first.time, second.time);
std::swap(first.anyState, second.anyState);
first.resetSignalHandler();
second.resetSignalHandler();
}
void populateMediaStates(QComboBox *list)
{
list->addItem("None");
list->addItem("Playing");
list->addItem("Opening");
list->addItem("Buffering");
list->addItem("Paused");
list->addItem("Stopped");
list->addItem("Ended");
list->addItem("Error");
list->addItem("Any");
}
void populateTimeRestrictions(QComboBox *list)
{
list->addItem("None");
list->addItem("Time shorter");
list->addItem("Time longer");
list->addItem("Time remaining shorter");
list->addItem("Time remaining longer");
}
MediaSwitchWidget::MediaSwitchWidget(MediaSwitch *s) : SwitchWidget(s)
{
meidaSources = new QComboBox();
states = new QComboBox();
timeRestrictions = new QComboBox();
time = new QSpinBox();
whenLabel = new QLabel("When");
stateLabel = new QLabel("state is");
andLabel = new QLabel("and");
switchLabel = new QLabel("switch to");
usingLabel = new QLabel("using");
time->setSuffix("ms");
time->setMaximum(99999999);
time->setMinimum(0);
QWidget::connect(meidaSources,
SIGNAL(currentTextChanged(const QString &)), this,
SLOT(SourceChanged(const QString &)));
QWidget::connect(states, SIGNAL(currentIndexChanged(int)), this,
SLOT(StateChanged(int)));
QWidget::connect(timeRestrictions, SIGNAL(currentIndexChanged(int)),
this, SLOT(TimeRestrictionChanged(int)));
QWidget::connect(time, SIGNAL(valueChanged(int)), this,
SLOT(TimeChanged(int)));
AdvSceneSwitcher::populateMediaSelection(meidaSources);
populateMediaStates(states);
populateTimeRestrictions(timeRestrictions);
if (s) {
meidaSources->setCurrentText(
GetWeakSourceName(s->source).c_str());
states->setCurrentIndex(s->state);
timeRestrictions->setCurrentIndex(s->restriction);
time->setValue(s->time);
if (s->restriction == TIME_RESTRICTION_NONE)
time->setDisabled(true);
}
setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(whenLabel);
mainLayout->addWidget(meidaSources);
mainLayout->addWidget(stateLabel);
mainLayout->addWidget(states);
mainLayout->addWidget(andLabel);
mainLayout->addWidget(timeRestrictions);
mainLayout->addWidget(time);
mainLayout->addWidget(switchLabel);
mainLayout->addWidget(scenes);
mainLayout->addWidget(usingLabel);
mainLayout->addWidget(transitions);
mainLayout->addStretch();
setLayout(mainLayout);
switchData = s;
loading = false;
}
MediaSwitch *MediaSwitchWidget::getSwitchData()
{
return switchData;
}
void MediaSwitchWidget::setSwitchData(MediaSwitch *s)
{
switchData = s;
}
void MediaSwitchWidget::swapSwitchData(MediaSwitchWidget *s1,
MediaSwitchWidget *s2)
{
SwitchWidget::swapSwitchData(s1, s2);
MediaSwitch *t = s1->getSwitchData();
s1->setSwitchData(s2->getSwitchData());
s2->setSwitchData(t);
}
void MediaSwitchWidget::SourceChanged(const QString &text)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->clearSignalHandler();
switchData->source = GetWeakSourceByQString(text);
switchData->resetSignalHandler();
}
void MediaSwitchWidget::StateChanged(int index)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->state = (obs_media_state)index;
switchData->anyState = switchData->state > 7;
}
void MediaSwitchWidget::TimeRestrictionChanged(int index)
{
if (loading || !switchData)
return;
if ((time_restriction)index == TIME_RESTRICTION_NONE)
time->setDisabled(true);
else
time->setDisabled(false);
std::lock_guard<std::mutex> lock(switcher->m);
switchData->restriction = (time_restriction)index;
}
void MediaSwitchWidget::TimeChanged(int time)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->time = time;
} }

View File

@@ -1,8 +1,9 @@
#include <regex> #include <regex>
#include "headers/advanced-scene-switcher.hpp" #include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp"
void SceneSwitcher::on_pauseScenesAdd_clicked() void AdvSceneSwitcher::on_pauseScenesAdd_clicked()
{ {
QString sceneName = ui->pauseScenesScenes->currentText(); QString sceneName = ui->pauseScenesScenes->currentText();
@@ -26,7 +27,7 @@ void SceneSwitcher::on_pauseScenesAdd_clicked()
} }
} }
void SceneSwitcher::on_pauseScenesRemove_clicked() void AdvSceneSwitcher::on_pauseScenesRemove_clicked()
{ {
QListWidgetItem *item = ui->pauseScenes->currentItem(); QListWidgetItem *item = ui->pauseScenes->currentItem();
if (!item) if (!item)
@@ -51,7 +52,7 @@ void SceneSwitcher::on_pauseScenesRemove_clicked()
delete item; delete item;
} }
void SceneSwitcher::on_pauseWindowsAdd_clicked() void AdvSceneSwitcher::on_pauseWindowsAdd_clicked()
{ {
QString windowName = ui->pauseWindowsWindows->currentText(); QString windowName = ui->pauseWindowsWindows->currentText();
@@ -75,7 +76,7 @@ void SceneSwitcher::on_pauseWindowsAdd_clicked()
} }
} }
void SceneSwitcher::on_pauseWindowsRemove_clicked() void AdvSceneSwitcher::on_pauseWindowsRemove_clicked()
{ {
QListWidgetItem *item = ui->pauseWindows->currentItem(); QListWidgetItem *item = ui->pauseWindows->currentItem();
if (!item) if (!item)
@@ -100,7 +101,7 @@ void SceneSwitcher::on_pauseWindowsRemove_clicked()
delete item; delete item;
} }
void SceneSwitcher::on_pauseScenes_currentRowChanged(int idx) void AdvSceneSwitcher::on_pauseScenes_currentRowChanged(int idx)
{ {
if (loading) if (loading)
return; return;
@@ -121,7 +122,7 @@ void SceneSwitcher::on_pauseScenes_currentRowChanged(int idx)
} }
} }
void SceneSwitcher::on_pauseWindows_currentRowChanged(int idx) void AdvSceneSwitcher::on_pauseWindows_currentRowChanged(int idx)
{ {
if (loading) if (loading)
return; return;
@@ -141,7 +142,7 @@ void SceneSwitcher::on_pauseWindows_currentRowChanged(int idx)
} }
} }
int SceneSwitcher::PauseScenesFindByData(const QString &scene) int AdvSceneSwitcher::PauseScenesFindByData(const QString &scene)
{ {
int count = ui->pauseScenes->count(); int count = ui->pauseScenes->count();
int idx = -1; int idx = -1;
@@ -159,7 +160,7 @@ int SceneSwitcher::PauseScenesFindByData(const QString &scene)
return idx; return idx;
} }
int SceneSwitcher::PauseWindowsFindByData(const QString &window) int AdvSceneSwitcher::PauseWindowsFindByData(const QString &window)
{ {
int count = ui->pauseWindows->count(); int count = ui->pauseWindows->count();
int idx = -1; int idx = -1;
@@ -223,7 +224,7 @@ bool SwitcherData::checkPause()
} }
if (verbose && pause) if (verbose && pause)
blog(LOG_INFO, "Advanced Scene Switcher pause match"); blog(LOG_INFO, "pause match");
return pause; return pause;
} }
@@ -239,9 +240,8 @@ void SwitcherData::savePauseSwitches(obs_data_t *obj)
const char *n = obs_source_get_name(source); const char *n = obs_source_get_name(source);
obs_data_set_string(array_obj, "pauseScene", n); obs_data_set_string(array_obj, "pauseScene", n);
obs_data_array_push_back(pauseScenesArray, array_obj); obs_data_array_push_back(pauseScenesArray, array_obj);
obs_source_release(source);
} }
obs_source_release(source);
obs_data_release(array_obj); obs_data_release(array_obj);
} }
obs_data_set_array(obj, "pauseScenes", pauseScenesArray); obs_data_set_array(obj, "pauseScenes", pauseScenesArray);
@@ -300,7 +300,7 @@ void SwitcherData::loadPauseSwitches(obs_data_t *obj)
obs_data_array_release(pauseWindowsArray); obs_data_array_release(pauseWindowsArray);
} }
void SceneSwitcher::setupPauseTab() void AdvSceneSwitcher::setupPauseTab()
{ {
populateSceneSelection(ui->pauseScenesScenes, false); populateSceneSelection(ui->pauseScenesScenes, false);
populateWindowSelection(ui->pauseWindowsWindows); populateWindowSelection(ui->pauseWindowsWindows);

View File

@@ -2,7 +2,7 @@
#include "headers/advanced-scene-switcher.hpp" #include "headers/advanced-scene-switcher.hpp"
void SceneSwitcher::on_threadPriority_currentTextChanged(const QString &text) void AdvSceneSwitcher::on_threadPriority_currentTextChanged(const QString &text)
{ {
if (loading || ui->threadPriority->count() != if (loading || ui->threadPriority->count() !=
(int)switcher->threadPriorities.size()) (int)switcher->threadPriorities.size())
@@ -18,7 +18,7 @@ void SceneSwitcher::on_threadPriority_currentTextChanged(const QString &text)
} }
} }
void SceneSwitcher::on_priorityUp_clicked() void AdvSceneSwitcher::on_priorityUp_clicked()
{ {
int currentIndex = ui->priorityList->currentRow(); int currentIndex = ui->priorityList->currentRow();
if (currentIndex != -1 && currentIndex != 0) { if (currentIndex != -1 && currentIndex != 0) {
@@ -35,7 +35,7 @@ void SceneSwitcher::on_priorityUp_clicked()
} }
} }
void SceneSwitcher::on_priorityDown_clicked() void AdvSceneSwitcher::on_priorityDown_clicked()
{ {
int currentIndex = ui->priorityList->currentRow(); int currentIndex = ui->priorityList->currentRow();
if (currentIndex != -1 && if (currentIndex != -1 &&

View File

@@ -1,115 +1,37 @@
#include <random> #include <random>
#include "headers/advanced-scene-switcher.hpp" #include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp"
void SceneSwitcher::on_randomScenesList_currentRowChanged(int idx) static QMetaObject::Connection addPulse;
void AdvSceneSwitcher::on_randomAdd_clicked()
{ {
if (loading) ui->randomAdd->disconnect(addPulse);
return;
if (idx == -1)
return;
QListWidgetItem *item = ui->randomScenesList->item(idx);
QString randomSceneStr = item->data(Qt::UserRole).toString();
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->randomSwitches) { switcher->randomSwitches.emplace_back();
if (randomSceneStr.compare(s.randomSwitchStr.c_str()) == 0) {
QString sceneName = GetWeakSourceName(s.scene).c_str(); QListWidgetItem *item;
QString transitionName = item = new QListWidgetItem(ui->randomSwitches);
GetWeakSourceName(s.transition).c_str(); ui->randomSwitches->addItem(item);
ui->randomScenes->setCurrentText(sceneName); RandomSwitchWidget *sw =
ui->randomSpinBox->setValue(s.delay); new RandomSwitchWidget(&switcher->randomSwitches.back());
ui->randomTransitions->setCurrentText(transitionName); item->setSizeHint(sw->minimumSizeHint());
break; ui->randomSwitches->setItemWidget(item, sw);
}
}
} }
int SceneSwitcher::randomFindByData(const QString &randomStr) void AdvSceneSwitcher::on_randomRemove_clicked()
{ {
int count = ui->randomScenesList->count(); QListWidgetItem *item = ui->randomSwitches->currentItem();
for (int i = 0; i < count; i++) {
QListWidgetItem *item = ui->randomScenesList->item(i);
QString str = item->data(Qt::UserRole).toString();
if (str == randomStr)
return i;
}
return -1;
}
void SceneSwitcher::on_randomAdd_clicked()
{
QString sceneName = ui->randomScenes->currentText();
QString transitionName = ui->randomTransitions->currentText();
double delay = ui->randomSpinBox->value();
if (sceneName.isEmpty())
return;
OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QString text = MakeRandomSwitchName(sceneName, transitionName, delay);
QVariant v = QVariant::fromValue(text);
int idx = randomFindByData(text);
if (idx == -1) {
std::lock_guard<std::mutex> lock(switcher->m);
switcher->randomSwitches.emplace_back(
source, transition, delay, text.toUtf8().constData());
QListWidgetItem *item =
new QListWidgetItem(text, ui->randomScenesList);
item->setData(Qt::UserRole, v);
} else {
QListWidgetItem *item = ui->randomScenesList->item(idx);
item->setText(text);
{
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->randomSwitches) {
if (s.scene == source) {
s.delay = delay;
s.transition = transition;
s.randomSwitchStr =
text.toUtf8().constData();
;
break;
}
}
}
ui->randomScenesList->sortItems();
}
}
void SceneSwitcher::on_randomRemove_clicked()
{
QListWidgetItem *item = ui->randomScenesList->currentItem();
if (!item) if (!item)
return; return;
std::string text =
item->data(Qt::UserRole).toString().toUtf8().constData();
{ {
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
int idx = ui->randomSwitches->currentRow();
auto &switches = switcher->randomSwitches; auto &switches = switcher->randomSwitches;
switches.erase(switches.begin() + idx);
for (auto it = switches.begin(); it != switches.end(); ++it) {
auto &s = *it;
if (s.randomSwitchStr == text) {
switches.erase(it);
break;
}
}
} }
delete item; delete item;
@@ -121,11 +43,14 @@ void SwitcherData::checkRandom(bool &match, OBSWeakSource &scene,
if (randomSwitches.size() == 0) if (randomSwitches.size() == 0)
return; return;
std::vector<RandomSwitch> rs(randomSwitches); std::deque<RandomSwitch> rs(randomSwitches);
std::random_device rng; std::random_device rng;
std::mt19937 urng(rng()); std::mt19937 urng(rng());
std::shuffle(rs.begin(), rs.end(), urng); std::shuffle(rs.begin(), rs.end(), urng);
for (RandomSwitch &r : rs) { for (RandomSwitch &r : rs) {
if (!r.initialized())
continue;
if (r.scene == lastRandomScene) if (r.scene == lastRandomScene)
continue; continue;
scene = r.scene; scene = r.scene;
@@ -159,10 +84,9 @@ void SwitcherData::saveRandomSwitches(obs_data_t *obj)
transitionName); transitionName);
obs_data_set_double(array_obj, "delay", s.delay); obs_data_set_double(array_obj, "delay", s.delay);
obs_data_array_push_back(randomArray, array_obj); obs_data_array_push_back(randomArray, array_obj);
obs_source_release(source);
obs_source_release(transition);
} }
obs_source_release(source);
obs_source_release(transition);
obs_data_release(array_obj); obs_data_release(array_obj);
} }
obs_data_set_array(obj, "randomSwitches", randomArray); obs_data_set_array(obj, "randomSwitches", randomArray);
@@ -185,43 +109,97 @@ void SwitcherData::loadRandomSwitches(obs_data_t *obj)
obs_data_get_string(array_obj, "transition"); obs_data_get_string(array_obj, "transition");
double delay = obs_data_get_double(array_obj, "delay"); double delay = obs_data_get_double(array_obj, "delay");
std::string randomSwitchStr =
MakeRandomSwitchName(scene, transition, delay)
.toUtf8()
.constData();
switcher->randomSwitches.emplace_back( switcher->randomSwitches.emplace_back(
GetWeakSourceByName(scene), GetWeakSourceByName(scene),
GetWeakTransitionByName(transition), delay, GetWeakTransitionByName(transition), delay);
randomSwitchStr);
obs_data_release(array_obj); obs_data_release(array_obj);
} }
obs_data_array_release(randomArray); obs_data_array_release(randomArray);
} }
void SceneSwitcher::setupRandomTab() void AdvSceneSwitcher::setupRandomTab()
{ {
populateSceneSelection(ui->randomScenes, false);
populateTransitionSelection(ui->randomTransitions);
for (auto &s : switcher->randomSwitches) { for (auto &s : switcher->randomSwitches) {
std::string sceneName = GetWeakSourceName(s.scene); QListWidgetItem *item;
std::string transitionName = GetWeakSourceName(s.transition); item = new QListWidgetItem(ui->randomSwitches);
QString text = MakeRandomSwitchName( ui->randomSwitches->addItem(item);
sceneName.c_str(), transitionName.c_str(), s.delay); RandomSwitchWidget *sw = new RandomSwitchWidget(&s);
item->setSizeHint(sw->minimumSizeHint());
QListWidgetItem *item = ui->randomSwitches->setItemWidget(item, sw);
new QListWidgetItem(text, ui->randomScenesList);
item->setData(Qt::UserRole, text);
} }
if (switcher->randomSwitches.size() == 0)
addPulse = PulseWidget(ui->randomAdd, QColor(Qt::green));
if (switcher->switchIfNotMatching != RANDOM_SWITCH)
PulseWidget(ui->randomDisabledWarning, QColor(Qt::red),
QColor(0, 0, 0, 0), "QLabel ");
else
ui->randomDisabledWarning->setVisible(false);
} }
static inline QString MakeRandomSwitchName(const QString &scene, RandomSwitchWidget::RandomSwitchWidget(RandomSwitch *s) : SwitchWidget(s, false)
const QString &transition,
double &delay)
{ {
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition + delay = new QDoubleSpinBox();
QStringLiteral("]: ") + QString::number(delay) +
QStringLiteral(" seconds"); switchLabel = new QLabel("If no switch condition is met switch to ");
usingLabel = new QLabel("using");
forLabel = new QLabel("for");
QWidget::connect(delay, SIGNAL(valueChanged(double)), this,
SLOT(DelayChanged(double)));
delay->setSuffix("s");
delay->setMaximum(999999999.9);
if (s) {
delay->setValue(s->delay);
}
setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(switchLabel);
mainLayout->addWidget(scenes);
mainLayout->addWidget(usingLabel);
mainLayout->addWidget(transitions);
mainLayout->addWidget(forLabel);
mainLayout->addWidget(delay);
mainLayout->addStretch();
setLayout(mainLayout);
switchData = s;
loading = false;
}
RandomSwitch *RandomSwitchWidget::getSwitchData()
{
return switchData;
}
void RandomSwitchWidget::setSwitchData(RandomSwitch *s)
{
switchData = s;
}
void RandomSwitchWidget::swapSwitchData(RandomSwitchWidget *s1,
RandomSwitchWidget *s2)
{
SwitchWidget::swapSwitchData(s1, s2);
RandomSwitch *t = s1->getSwitchData();
s1->setSwitchData(s2->getSwitchData());
s2->setSwitchData(t);
}
void RandomSwitchWidget::DelayChanged(double d)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->delay = d;
} }

View File

@@ -1,6 +1,127 @@
#include <QTimer> #include <QTimer>
#include "headers/advanced-scene-switcher.hpp" #include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp"
static QMetaObject::Connection addPulse;
void clearFrames(QListWidget *list)
{
for (int i = 0; i < list->count(); ++i) {
ScreenRegionWidget *sw =
(ScreenRegionWidget *)list->itemWidget(list->item(i));
sw->hideFrame();
}
}
void showCurrentFrame(QListWidget *list)
{
QListWidgetItem *item = list->currentItem();
if (!item)
return;
ScreenRegionWidget *sw = (ScreenRegionWidget *)list->itemWidget(item);
sw->showFrame();
}
void AdvSceneSwitcher::on_showFrame_clicked()
{
switcher->showFrame = !switcher->showFrame;
if (switcher->showFrame) {
ui->showFrame->setText("Hide guide frames");
showCurrentFrame(ui->screenRegionSwitches);
} else {
ui->showFrame->setText("Show guide frames");
clearFrames(ui->screenRegionSwitches);
}
}
void AdvSceneSwitcher::on_screenRegionSwitches_currentRowChanged(int idx)
{
UNUSED_PARAMETER(idx);
if (loading)
return;
if (switcher->showFrame) {
clearFrames(ui->screenRegionSwitches);
showCurrentFrame(ui->screenRegionSwitches);
}
}
void AdvSceneSwitcher::on_screenRegionAdd_clicked()
{
ui->screenRegionAdd->disconnect(addPulse);
std::lock_guard<std::mutex> lock(switcher->m);
switcher->screenRegionSwitches.emplace_back();
QListWidgetItem *item;
item = new QListWidgetItem(ui->screenRegionSwitches);
ui->screenRegionSwitches->addItem(item);
ScreenRegionWidget *sw =
new ScreenRegionWidget(&switcher->screenRegionSwitches.back());
item->setSizeHint(sw->minimumSizeHint());
ui->screenRegionSwitches->setItemWidget(item, sw);
}
void AdvSceneSwitcher::on_screenRegionRemove_clicked()
{
QListWidgetItem *item = ui->screenRegionSwitches->currentItem();
if (!item)
return;
{
std::lock_guard<std::mutex> lock(switcher->m);
int idx = ui->screenRegionSwitches->currentRow();
auto &switches = switcher->screenRegionSwitches;
switches.erase(switches.begin() + idx);
}
delete item;
}
void AdvSceneSwitcher::on_screenRegionUp_clicked()
{
int index = ui->screenRegionSwitches->currentRow();
if (!listMoveUp(ui->screenRegionSwitches))
return;
ScreenRegionWidget *s1 =
(ScreenRegionWidget *)ui->screenRegionSwitches->itemWidget(
ui->screenRegionSwitches->item(index));
ScreenRegionWidget *s2 =
(ScreenRegionWidget *)ui->screenRegionSwitches->itemWidget(
ui->screenRegionSwitches->item(index - 1));
ScreenRegionWidget::swapSwitchData(s1, s2);
std::lock_guard<std::mutex> lock(switcher->m);
std::swap(switcher->screenRegionSwitches[index],
switcher->screenRegionSwitches[index - 1]);
}
void AdvSceneSwitcher::on_screenRegionDown_clicked()
{
int index = ui->screenRegionSwitches->currentRow();
if (!listMoveDown(ui->screenRegionSwitches))
return;
ScreenRegionWidget *s1 =
(ScreenRegionWidget *)ui->screenRegionSwitches->itemWidget(
ui->screenRegionSwitches->item(index));
ScreenRegionWidget *s2 =
(ScreenRegionWidget *)ui->screenRegionSwitches->itemWidget(
ui->screenRegionSwitches->item(index + 1));
ScreenRegionWidget::swapSwitchData(s1, s2);
std::lock_guard<std::mutex> lock(switcher->m);
std::swap(switcher->screenRegionSwitches[index],
switcher->screenRegionSwitches[index + 1]);
}
void SwitcherData::checkScreenRegionSwitch(bool &match, OBSWeakSource &scene, void SwitcherData::checkScreenRegionSwitch(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition) OBSWeakSource &transition)
@@ -9,6 +130,9 @@ void SwitcherData::checkScreenRegionSwitch(bool &match, OBSWeakSource &scene,
int minRegionSize = 99999; int minRegionSize = 99999;
for (auto &s : screenRegionSwitches) { for (auto &s : screenRegionSwitches) {
if (!s.initialized())
continue;
if (cursorPos.first >= s.minX && cursorPos.second >= s.minY && if (cursorPos.first >= s.minX && cursorPos.second >= s.minY &&
cursorPos.first <= s.maxX && cursorPos.second <= s.maxY) { cursorPos.first <= s.maxX && cursorPos.second <= s.maxY) {
int regionSize = (s.maxX - s.minX) + (s.maxY - s.minY); int regionSize = (s.maxX - s.minX) + (s.maxY - s.minY);
@@ -26,170 +150,13 @@ void SwitcherData::checkScreenRegionSwitch(bool &match, OBSWeakSource &scene,
} }
} }
void SceneSwitcher::updateScreenRegionCursorPos() void AdvSceneSwitcher::updateScreenRegionCursorPos()
{ {
std::pair<int, int> position = getCursorPos(); std::pair<int, int> position = getCursorPos();
ui->cursorXPosition->setText(QString::number(position.first)); ui->cursorXPosition->setText(QString::number(position.first));
ui->cursorYPosition->setText(QString::number(position.second)); ui->cursorYPosition->setText(QString::number(position.second));
} }
void SceneSwitcher::on_screenRegionAdd_clicked()
{
QString sceneName = ui->screenRegionScenes->currentText();
QString transitionName = ui->screenRegionsTransitions->currentText();
if (sceneName.isEmpty())
return;
int minX = ui->screenRegionMinX->value();
int minY = ui->screenRegionMinY->value();
int maxX = ui->screenRegionMaxX->value();
int maxY = ui->screenRegionMaxY->value();
std::string regionStr =
std::to_string(minX) + ", " + std::to_string(minY) + " x " +
std::to_string(maxX) + ", " + std::to_string(maxY);
QString region = QString::fromStdString(regionStr);
OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QVariant v = QVariant::fromValue(region);
QString text = MakeScreenRegionSwitchName(sceneName, transitionName,
minX, minY, maxX, maxY);
int idx = ScreenRegionFindByData(region);
if (idx == -1) {
QListWidgetItem *item =
new QListWidgetItem(text, ui->screenRegions);
item->setData(Qt::UserRole, v);
std::lock_guard<std::mutex> lock(switcher->m);
switcher->screenRegionSwitches.emplace_back(
source, transition, minX, minY, maxX, maxY, regionStr);
} else {
QListWidgetItem *item = ui->screenRegions->item(idx);
item->setText(text);
std::string curRegion = region.toUtf8().constData();
{
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->screenRegionSwitches) {
if (s.regionStr == curRegion) {
s.scene = source;
s.transition = transition;
break;
}
}
}
}
}
void SceneSwitcher::on_screenRegionRemove_clicked()
{
QListWidgetItem *item = ui->screenRegions->currentItem();
if (!item)
return;
std::string region =
item->data(Qt::UserRole).toString().toUtf8().constData();
{
std::lock_guard<std::mutex> lock(switcher->m);
auto &switches = switcher->screenRegionSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it) {
auto &s = *it;
if (s.regionStr == region) {
switches.erase(it);
break;
}
}
}
delete item;
}
void SceneSwitcher::on_screenRegions_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem *item = ui->screenRegions->item(idx);
QString region = item->data(Qt::UserRole).toString();
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->screenRegionSwitches) {
if (region.compare(s.regionStr.c_str()) == 0) {
std::string name = GetWeakSourceName(s.scene);
std::string transitionName =
GetWeakSourceName(s.transition);
ui->screenRegionScenes->setCurrentText(name.c_str());
ui->screenRegionsTransitions->setCurrentText(
transitionName.c_str());
ui->screenRegionMinX->setValue(s.minX);
ui->screenRegionMinY->setValue(s.minY);
ui->screenRegionMaxX->setValue(s.maxX);
ui->screenRegionMaxY->setValue(s.maxY);
break;
}
}
}
int SceneSwitcher::ScreenRegionFindByData(const QString &region)
{
int count = ui->screenRegions->count();
int idx = -1;
for (int i = 0; i < count; i++) {
QListWidgetItem *item = ui->screenRegions->item(i);
QString itemRegion = item->data(Qt::UserRole).toString();
if (itemRegion == region) {
idx = i;
break;
}
}
return idx;
}
void SceneSwitcher::on_screenRegionUp_clicked()
{
int index = ui->screenRegions->currentRow();
if (index != -1 && index != 0) {
ui->screenRegions->insertItem(
index - 1, ui->screenRegions->takeItem(index));
ui->screenRegions->setCurrentRow(index - 1);
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(switcher->screenRegionSwitches.begin() + index,
switcher->screenRegionSwitches.begin() + index - 1);
}
}
void SceneSwitcher::on_screenRegionDown_clicked()
{
int index = ui->screenRegions->currentRow();
if (index != -1 && index != ui->screenRegions->count() - 1) {
ui->screenRegions->insertItem(
index + 1, ui->screenRegions->takeItem(index));
ui->screenRegions->setCurrentRow(index + 1);
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(switcher->screenRegionSwitches.begin() + index,
switcher->screenRegionSwitches.begin() + index + 1);
}
}
void SwitcherData::saveScreenRegionSwitches(obs_data_t *obj) void SwitcherData::saveScreenRegionSwitches(obs_data_t *obj)
{ {
obs_data_array_t *screenRegionArray = obs_data_array_create(); obs_data_array_t *screenRegionArray = obs_data_array_create();
@@ -212,10 +179,9 @@ void SwitcherData::saveScreenRegionSwitches(obs_data_t *obj)
obs_data_set_int(array_obj, "maxX", s.maxX); obs_data_set_int(array_obj, "maxX", s.maxX);
obs_data_set_int(array_obj, "maxY", s.maxY); obs_data_set_int(array_obj, "maxY", s.maxY);
obs_data_array_push_back(screenRegionArray, array_obj); obs_data_array_push_back(screenRegionArray, array_obj);
obs_source_release(source);
obs_source_release(transition);
} }
obs_source_release(source);
obs_source_release(transition);
obs_data_release(array_obj); obs_data_release(array_obj);
} }
obs_data_set_array(obj, "screenRegion", screenRegionArray); obs_data_set_array(obj, "screenRegion", screenRegionArray);
@@ -243,39 +209,30 @@ void SwitcherData::loadScreenRegionSwitches(obs_data_t *obj)
int maxX = obs_data_get_int(array_obj, "maxX"); int maxX = obs_data_get_int(array_obj, "maxX");
int maxY = obs_data_get_int(array_obj, "maxY"); int maxY = obs_data_get_int(array_obj, "maxY");
std::string regionStr =
MakeScreenRegionSwitchName(scene, transition, minX,
minY, maxX, maxY)
.toUtf8()
.constData();
switcher->screenRegionSwitches.emplace_back( switcher->screenRegionSwitches.emplace_back(
GetWeakSourceByName(scene), GetWeakSourceByName(scene),
GetWeakTransitionByName(transition), minX, minY, maxX, GetWeakTransitionByName(transition), minX, minY, maxX,
maxY, regionStr); maxY);
obs_data_release(array_obj); obs_data_release(array_obj);
} }
obs_data_array_release(screenRegionArray); obs_data_array_release(screenRegionArray);
} }
void SceneSwitcher::setupRegionTab() void AdvSceneSwitcher::setupRegionTab()
{ {
populateSceneSelection(ui->screenRegionScenes, false);
populateTransitionSelection(ui->screenRegionsTransitions);
for (auto &s : switcher->screenRegionSwitches) { for (auto &s : switcher->screenRegionSwitches) {
std::string sceneName = GetWeakSourceName(s.scene); QListWidgetItem *item;
std::string transitionName = GetWeakSourceName(s.transition); item = new QListWidgetItem(ui->screenRegionSwitches);
QString text = MakeScreenRegionSwitchName( ui->screenRegionSwitches->addItem(item);
sceneName.c_str(), transitionName.c_str(), s.minX, ScreenRegionWidget *sw = new ScreenRegionWidget(&s);
s.minY, s.maxX, s.maxY); item->setSizeHint(sw->minimumSizeHint());
ui->screenRegionSwitches->setItemWidget(item, sw);
QListWidgetItem *item =
new QListWidgetItem(text, ui->screenRegions);
item->setData(Qt::UserRole, s.regionStr.c_str());
} }
if (switcher->screenRegionSwitches.size() == 0)
addPulse = PulseWidget(ui->screenRegionAdd, QColor(Qt::green));
// screen region cursor position // screen region cursor position
QTimer *screenRegionTimer = new QTimer(this); QTimer *screenRegionTimer = new QTimer(this);
connect(screenRegionTimer, SIGNAL(timeout()), this, connect(screenRegionTimer, SIGNAL(timeout()), this,
@@ -283,14 +240,155 @@ void SceneSwitcher::setupRegionTab()
screenRegionTimer->start(1000); screenRegionTimer->start(1000);
} }
static inline QString MakeScreenRegionSwitchName(const QString &scene, ScreenRegionWidget::ScreenRegionWidget(ScreenRegionSwitch *s)
const QString &transition, : SwitchWidget(s, false)
int minX, int minY, int maxX,
int maxY)
{ {
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition + minX = new QSpinBox();
QStringLiteral("]: ") + QString::number(minX) + minY = new QSpinBox();
QStringLiteral(", ") + QString::number(minY) + maxX = new QSpinBox();
QStringLiteral(" x ") + QString::number(maxX) + maxY = new QSpinBox();
QStringLiteral(", ") + QString::number(maxY);
cursorLabel = new QLabel("If cursor is in");
xLabel = new QLabel("x");
switchLabel = new QLabel("switch to");
usingLabel = new QLabel("using");
minX->setPrefix("Min X: ");
minY->setPrefix("Min Y: ");
maxX->setPrefix("Max X: ");
maxY->setPrefix("Max Y: ");
minX->setMinimum(-1000000);
minY->setMinimum(-1000000);
maxX->setMinimum(-1000000);
maxY->setMinimum(-1000000);
minX->setMaximum(1000000);
minY->setMaximum(1000000);
maxX->setMaximum(1000000);
maxY->setMaximum(1000000);
QWidget::connect(minX, SIGNAL(valueChanged(int)), this,
SLOT(MinXChanged(int)));
QWidget::connect(minY, SIGNAL(valueChanged(int)), this,
SLOT(MinYChanged(int)));
QWidget::connect(maxX, SIGNAL(valueChanged(int)), this,
SLOT(MaxXChanged(int)));
QWidget::connect(maxY, SIGNAL(valueChanged(int)), this,
SLOT(MaxYChanged(int)));
if (s) {
minX->setValue(s->minX);
minY->setValue(s->minY);
maxX->setValue(s->maxX);
maxY->setValue(s->maxY);
}
setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(cursorLabel);
mainLayout->addWidget(minX);
mainLayout->addWidget(minY);
mainLayout->addWidget(xLabel);
mainLayout->addWidget(maxX);
mainLayout->addWidget(maxY);
mainLayout->addWidget(switchLabel);
mainLayout->addWidget(scenes);
mainLayout->addWidget(usingLabel);
mainLayout->addWidget(transitions);
mainLayout->addStretch();
setLayout(mainLayout);
switchData = s;
loading = false;
}
ScreenRegionSwitch *ScreenRegionWidget::getSwitchData()
{
return switchData;
}
void ScreenRegionWidget::setSwitchData(ScreenRegionSwitch *s)
{
switchData = s;
}
void ScreenRegionWidget::swapSwitchData(ScreenRegionWidget *s1,
ScreenRegionWidget *s2)
{
SwitchWidget::swapSwitchData(s1, s2);
ScreenRegionSwitch *t = s1->getSwitchData();
s1->setSwitchData(s2->getSwitchData());
s2->setSwitchData(t);
}
void ScreenRegionWidget::showFrame()
{
drawFrame();
helperFrame.show();
}
void ScreenRegionWidget::hideFrame()
{
helperFrame.hide();
}
void ScreenRegionWidget::MinXChanged(int pos)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->minX = pos;
drawFrame();
}
void ScreenRegionWidget::MinYChanged(int pos)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->minY = pos;
drawFrame();
}
void ScreenRegionWidget::MaxXChanged(int pos)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->maxX = pos;
drawFrame();
}
void ScreenRegionWidget::MaxYChanged(int pos)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->maxY = pos;
drawFrame();
}
void ScreenRegionWidget::drawFrame()
{
helperFrame.setFrameStyle(QFrame::Box | QFrame::Plain);
helperFrame.setWindowFlags(Qt::FramelessWindowHint | Qt::Tool |
Qt::WindowTransparentForInput |
Qt::WindowDoesNotAcceptFocus |
Qt::WindowStaysOnTopHint);
helperFrame.setAttribute(Qt::WA_TranslucentBackground, true);
if (switchData)
helperFrame.setGeometry(switchData->minX, switchData->minY,
switchData->maxX - switchData->minX,
switchData->maxY - switchData->minY);
} }

View File

@@ -3,132 +3,84 @@
#include <QMessageBox> #include <QMessageBox>
#include "headers/advanced-scene-switcher.hpp" #include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp"
constexpr auto seconds_index = 0; static QMetaObject::Connection addPulse;
constexpr auto minutes_index = 1;
constexpr auto hours_index = 2;
void SceneSwitcher::on_sceneSequenceDelayUnits_currentIndexChanged(int index) void AdvSceneSwitcher::on_sceneSequenceAdd_clicked()
{ {
if (loading) ui->sceneSequenceAdd->disconnect(addPulse);
return;
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->sceneSequenceSwitches.emplace_back();
double val = ui->sceneSequenceSpinBox->value(); QListWidgetItem *item;
item = new QListWidgetItem(ui->sceneSequenceSwitches);
switch (switcher->sceneSequenceMultiplier) { ui->sceneSequenceSwitches->addItem(item);
case 1: SequenceWidget *sw =
val /= pow(60, index); new SequenceWidget(&switcher->sceneSequenceSwitches.back());
break; item->setSizeHint(sw->minimumSizeHint());
case 60: ui->sceneSequenceSwitches->setItemWidget(item, sw);
val /= pow(60, index - 1);
break;
case 3600:
val /= pow(60, index - 2);
break;
}
ui->sceneSequenceSpinBox->setValue(val);
switch (index) {
case seconds_index:
switcher->sceneSequenceMultiplier = 1;
break;
case minutes_index:
switcher->sceneSequenceMultiplier = 60;
break;
case hours_index:
switcher->sceneSequenceMultiplier = 3600;
break;
}
} }
void SceneSwitcher::on_sceneSequenceAdd_clicked() void AdvSceneSwitcher::on_sceneSequenceRemove_clicked()
{ {
QString scene1Name = ui->sceneSequenceScenes1->currentText(); QListWidgetItem *item = ui->sceneSequenceSwitches->currentItem();
QString scene2Name = ui->sceneSequenceScenes2->currentText();
QString transitionName = ui->sceneSequenceTransitions->currentText();
if (scene1Name.isEmpty() || scene2Name.isEmpty())
return;
double delay = ui->sceneSequenceSpinBox->value() *
switcher->sceneSequenceMultiplier;
if (scene1Name == scene2Name)
return;
OBSWeakSource source1 = GetWeakSourceByQString(scene1Name);
OBSWeakSource source2 = GetWeakSourceByQString(scene2Name);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QString text = MakeSceneSequenceSwitchName(scene1Name, scene2Name,
transitionName, delay);
QVariant v = QVariant::fromValue(text);
int idx = SceneSequenceFindByData(scene1Name);
if (idx == -1) {
QListWidgetItem *item =
new QListWidgetItem(text, ui->sceneSequences);
item->setData(Qt::UserRole, v);
std::lock_guard<std::mutex> lock(switcher->m);
switcher->sceneSequenceSwitches.emplace_back(
source1, source2, transition, delay,
(scene2Name == QString(previous_scene_name)),
text.toUtf8().constData());
} else {
QListWidgetItem *item = ui->sceneSequences->item(idx);
item->setText(text);
{
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->sceneSequenceSwitches) {
if (s.startScene == source1) {
s.scene = source2;
s.delay = delay;
s.transition = transition;
s.usePreviousScene =
(scene2Name ==
QString(previous_scene_name));
s.sceneSequenceStr =
text.toUtf8().constData();
break;
}
}
}
}
}
void SceneSwitcher::on_sceneSequenceRemove_clicked()
{
QListWidgetItem *item = ui->sceneSequences->currentItem();
if (!item) if (!item)
return; return;
std::string text =
item->data(Qt::UserRole).toString().toUtf8().constData();
{ {
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
int idx = ui->sceneSequenceSwitches->currentRow();
auto &switches = switcher->sceneSequenceSwitches; auto &switches = switcher->sceneSequenceSwitches;
switches.erase(switches.begin() + idx);
for (auto it = switches.begin(); it != switches.end(); ++it) {
auto &s = *it;
if (s.sceneSequenceStr == text) {
switches.erase(it);
break;
}
}
} }
delete item; delete item;
} }
void SceneSwitcher::on_sceneSequenceSave_clicked() 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( QString directory = QFileDialog::getSaveFileName(
this, tr("Save Scene Sequence to file ..."), this, tr("Save Scene Sequence to file ..."),
@@ -145,51 +97,7 @@ void SceneSwitcher::on_sceneSequenceSave_clicked()
obs_data_release(obj); obs_data_release(obj);
} }
// to be removed once support for old file format is dropped void AdvSceneSwitcher::on_sceneSequenceLoad_clicked()
bool oldSceneRoundTripLoad(QFile *file)
{
QTextStream in(file);
std::vector<QString> lines;
std::vector<SceneSequenceSwitch> newSceneRoundTripSwitch;
while (!in.atEnd()) {
QString line = in.readLine();
lines.push_back(line);
if (lines.size() == 5) {
OBSWeakSource scene1 = GetWeakSourceByQString(lines[0]);
OBSWeakSource scene2 = GetWeakSourceByQString(lines[1]);
OBSWeakSource transition =
GetWeakTransitionByQString(lines[4]);
if (WeakSourceValid(scene1) &&
((lines[1] == QString(previous_scene_name)) ||
(WeakSourceValid(scene2))) &&
WeakSourceValid(transition)) {
newSceneRoundTripSwitch.emplace_back(
SceneSequenceSwitch(
GetWeakSourceByQString(lines[0]),
GetWeakSourceByQString(lines[1]),
GetWeakTransitionByQString(
lines[4]),
lines[2].toDouble() / 1000.,
(lines[1] ==
QString(previous_scene_name)),
lines[3].toStdString()));
}
lines.clear();
}
}
if (lines.size() != 0 || newSceneRoundTripSwitch.size() == 0)
return false;
switcher->sceneSequenceSwitches.clear();
switcher->sceneSequenceSwitches = newSceneRoundTripSwitch;
return true;
}
void SceneSwitcher::on_sceneSequenceLoad_clicked()
{ {
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
@@ -208,23 +116,9 @@ void SceneSwitcher::on_sceneSequenceLoad_clicked()
if (!obj) { if (!obj) {
QMessageBox Msgbox; QMessageBox Msgbox;
QString txt = Msgbox.setText(
"Advanced Scene Switcher failed to import settings!\n"; "Advanced Scene Switcher failed to import settings!");
txt += "Falling back to old format.";
Msgbox.setText(txt);
Msgbox.exec(); Msgbox.exec();
if (oldSceneRoundTripLoad(&file)) {
QString txt =
"Advanced Scene Switcher settings imported successfully!\n";
txt += "Please resave settings as support for old format will be dropped in next version.";
Msgbox.setText(txt);
Msgbox.exec();
close();
} else {
Msgbox.setText(
"Advanced Scene Switcher failed to import settings!");
Msgbox.exec();
}
return; return;
} }
switcher->loadSceneSequenceSwitches(obj); switcher->loadSceneSequenceSwitches(obj);
@@ -238,13 +132,16 @@ void SceneSwitcher::on_sceneSequenceLoad_clicked()
} }
void SwitcherData::checkSceneSequence(bool &match, OBSWeakSource &scene, void SwitcherData::checkSceneSequence(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition, OBSWeakSource &transition,
std::unique_lock<std::mutex> &lock) std::unique_lock<std::mutex> &lock)
{ {
obs_source_t *currentSource = obs_frontend_get_current_scene(); obs_source_t *currentSource = obs_frontend_get_current_scene();
obs_weak_source_t *ws = obs_source_get_weak_source(currentSource); obs_weak_source_t *ws = obs_source_get_weak_source(currentSource);
for (SceneSequenceSwitch &s : sceneSequenceSwitches) { for (SceneSequenceSwitch &s : sceneSequenceSwitches) {
if (!s.initialized())
continue;
if (s.startScene == ws) { if (s.startScene == ws) {
int dur = s.delay * 1000 - interval; int dur = s.delay * 1000 - interval;
if (dur > 0) { if (dur > 0) {
@@ -277,87 +174,6 @@ void SwitcherData::checkSceneSequence(bool &match, OBSWeakSource &scene,
obs_weak_source_release(ws); obs_weak_source_release(ws);
} }
void SceneSwitcher::on_sceneSequences_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem *item = ui->sceneSequences->item(idx);
QString sceneSequence = item->text();
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->sceneSequenceSwitches) {
if (sceneSequence.compare(s.sceneSequenceStr.c_str()) == 0) {
std::string scene1 = GetWeakSourceName(s.startScene);
std::string scene2 = GetWeakSourceName(s.scene);
std::string transitionName =
GetWeakSourceName(s.transition);
double delay = s.delay /
switcher->sceneSequenceMultiplier;
ui->sceneSequenceScenes1->setCurrentText(
scene1.c_str());
ui->sceneSequenceScenes2->setCurrentText(
scene2.c_str());
ui->sceneSequenceTransitions->setCurrentText(
transitionName.c_str());
ui->sceneSequenceSpinBox->setValue(delay);
break;
}
}
}
int SceneSwitcher::SceneSequenceFindByData(const QString &scene1)
{
QRegExp rx(scene1 + " ->.*");
int count = ui->sceneSequences->count();
int idx = -1;
for (int i = 0; i < count; i++) {
QListWidgetItem *item = ui->sceneSequences->item(i);
QString itemString = item->data(Qt::UserRole).toString();
if (rx.exactMatch(itemString)) {
idx = i;
break;
}
}
return idx;
}
void SceneSwitcher::on_sceneSequenceUp_clicked()
{
int index = ui->sceneSequences->currentRow();
if (index != -1 && index != 0) {
ui->sceneSequences->insertItem(
index - 1, ui->sceneSequences->takeItem(index));
ui->sceneSequences->setCurrentRow(index - 1);
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(switcher->sceneSequenceSwitches.begin() + index,
switcher->sceneSequenceSwitches.begin() + index - 1);
}
}
void SceneSwitcher::on_sceneSequenceDown_clicked()
{
int index = ui->sceneSequences->currentRow();
if (index != -1 && index != ui->sceneSequences->count() - 1) {
ui->sceneSequences->insertItem(
index + 1, ui->sceneSequences->takeItem(index));
ui->sceneSequences->setCurrentRow(index + 1);
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(switcher->sceneSequenceSwitches.begin() + index,
switcher->sceneSequenceSwitches.begin() + index + 1);
}
}
void SwitcherData::saveSceneSequenceSwitches(obs_data_t *obj) void SwitcherData::saveSceneSequenceSwitches(obs_data_t *obj)
{ {
obs_data_array_t *sceneSequenceArray = obs_data_array_create(); obs_data_array_t *sceneSequenceArray = obs_data_array_create();
@@ -383,13 +199,14 @@ void SwitcherData::saveSceneSequenceSwitches(obs_data_t *obj)
obs_data_set_string(array_obj, "transition", obs_data_set_string(array_obj, "transition",
transitionName); transitionName);
obs_data_set_double(array_obj, "delay", s.delay); obs_data_set_double(array_obj, "delay", s.delay);
obs_data_array_push_back(sceneSequenceArray, obs_data_set_int(array_obj, "delayMultiplier",
array_obj); s.delayMultiplier);
obs_source_release(source1); obs_data_array_push_back(sceneSequenceArray, array_obj);
obs_source_release(source2);
obs_source_release(transition);
} }
obs_source_release(source1);
obs_source_release(source2);
obs_source_release(transition);
obs_data_release(array_obj); obs_data_release(array_obj);
} }
obs_data_set_array(obj, "sceneRoundTrip", sceneSequenceArray); obs_data_set_array(obj, "sceneRoundTrip", sceneSequenceArray);
@@ -414,94 +231,189 @@ void SwitcherData::loadSceneSequenceSwitches(obs_data_t *obj)
obs_data_get_string(array_obj, "sceneRoundTripScene2"); obs_data_get_string(array_obj, "sceneRoundTripScene2");
const char *transition = const char *transition =
obs_data_get_string(array_obj, "transition"); obs_data_get_string(array_obj, "transition");
double delay = obs_data_get_double(array_obj, "delay");
double delay = 0; int delayMultiplier =
obs_data_get_int(array_obj, "delayMultiplier");
// To be removed in future version if (delayMultiplier == 0 ||
// to be compatible with older versions (delayMultiplier != 1 && delayMultiplier % 60 != 0))
if (!obs_data_has_user_value(array_obj, "delay")) { delayMultiplier = 1;
delay = double(obs_data_get_int(array_obj,
"sceneRoundTripDelay"));
delay = delay * 1000. +
double(obs_data_get_int(
array_obj, "sceneRoundTripDelayMs"));
delay /= 1000.;
} else {
delay = obs_data_get_double(array_obj, "delay");
}
std::string str = MakeSceneSequenceSwitchName(
scene1, scene2, transition, delay)
.toUtf8()
.constData();
const char *sceneSequenceStr = str.c_str();
switcher->sceneSequenceSwitches.emplace_back( switcher->sceneSequenceSwitches.emplace_back(
GetWeakSourceByName(scene1), GetWeakSourceByName(scene1),
GetWeakSourceByName(scene2), GetWeakSourceByName(scene2),
GetWeakTransitionByName(transition), delay, GetWeakTransitionByName(transition), delay,
(strcmp(scene2, previous_scene_name) == 0), delayMultiplier,
sceneSequenceStr); (strcmp(scene2, previous_scene_name) == 0));
obs_data_release(array_obj); obs_data_release(array_obj);
} }
obs_data_array_release(sceneSequenceArray); obs_data_array_release(sceneSequenceArray);
} }
void SceneSwitcher::setupSequenceTab() void AdvSceneSwitcher::setupSequenceTab()
{ {
populateSceneSelection(ui->sceneSequenceScenes1, false);
populateSceneSelection(ui->sceneSequenceScenes2, true);
populateTransitionSelection(ui->sceneSequenceTransitions);
double smallestDelay = double(switcher->interval) / 1000;
for (auto &s : switcher->sceneSequenceSwitches) { for (auto &s : switcher->sceneSequenceSwitches) {
std::string sceneName1 = GetWeakSourceName(s.startScene); QListWidgetItem *item;
std::string sceneName2 = (s.usePreviousScene) item = new QListWidgetItem(ui->sceneSequenceSwitches);
? previous_scene_name ui->sceneSequenceSwitches->addItem(item);
: GetWeakSourceName(s.scene); SequenceWidget *sw = new SequenceWidget(&s);
std::string transitionName = GetWeakSourceName(s.transition); item->setSizeHint(sw->minimumSizeHint());
QString text = MakeSceneSequenceSwitchName( ui->sceneSequenceSwitches->setItemWidget(item, sw);
sceneName1.c_str(), sceneName2.c_str(),
transitionName.c_str(), s.delay);
QListWidgetItem *item =
new QListWidgetItem(text, ui->sceneSequences);
item->setData(Qt::UserRole, text);
if (s.delay < smallestDelay)
smallestDelay = s.delay;
} }
(smallestDelay * 1000 < switcher->interval)
? ui->intervalWarning->setVisible(true)
: ui->intervalWarning->setVisible(false);
ui->sceneSequenceDelayUnits->addItem("seconds"); if (switcher->sceneSequenceSwitches.size() == 0)
ui->sceneSequenceDelayUnits->addItem("minutes"); addPulse = PulseWidget(ui->sceneSequenceAdd, QColor(Qt::green));
ui->sceneSequenceDelayUnits->addItem("hours"); }
switch (switcher->sceneSequenceMultiplier) { bool SceneSequenceSwitch::initialized()
case 1: {
ui->sceneSequenceDelayUnits->setCurrentIndex(0); return SceneSwitcherEntry::initialized() && startScene;
}
bool SceneSequenceSwitch::valid()
{
return !initialized() ||
(SceneSwitcherEntry::valid() && WeakSourceValid(startScene));
}
void SceneSequenceSwitch::logSleep(int dur)
{
blog(LOG_INFO, "sequence sleep %d", dur);
}
void populateDelayUnits(QComboBox *list)
{
list->addItem("seconds");
list->addItem("minutes");
list->addItem("hours");
}
SequenceWidget::SequenceWidget(SceneSequenceSwitch *s) : SwitchWidget(s)
{
delay = new QDoubleSpinBox();
delayUnits = new QComboBox();
startScenes = new QComboBox();
whenLabel = new QLabel("When");
switchLabel = new QLabel("is active switch to");
afterLabel = new QLabel("after");
usingLabel = new QLabel("using");
QWidget::connect(delay, SIGNAL(valueChanged(double)), this,
SLOT(DelayChanged(double)));
QWidget::connect(delayUnits, SIGNAL(currentIndexChanged(int)), this,
SLOT(DelayUnitsChanged(int)));
QWidget::connect(startScenes,
SIGNAL(currentTextChanged(const QString &)), this,
SLOT(StartSceneChanged(const QString &)));
delay->setMaximum(99999.000000);
AdvSceneSwitcher::populateSceneSelection(startScenes, false);
populateDelayUnits(delayUnits);
if (s) {
switch (s->delayMultiplier) {
case 1:
delayUnits->setCurrentIndex(0);
break;
case 60:
delayUnits->setCurrentIndex(1);
break;
case 3600:
delayUnits->setCurrentIndex(2);
break;
default:
delayUnits->setCurrentIndex(0);
}
startScenes->setCurrentText(
GetWeakSourceName(s->startScene).c_str());
}
setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(whenLabel);
mainLayout->addWidget(startScenes);
mainLayout->addWidget(switchLabel);
mainLayout->addWidget(scenes);
mainLayout->addWidget(afterLabel);
mainLayout->addWidget(delay);
mainLayout->addWidget(delayUnits);
mainLayout->addWidget(usingLabel);
mainLayout->addWidget(transitions);
mainLayout->addStretch();
setLayout(mainLayout);
switchData = s;
loading = false;
UpdateDelay();
}
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::UpdateDelay()
{
if (switchData)
delay->setValue(switchData->delay /
switchData->delayMultiplier);
}
void SequenceWidget::DelayChanged(double delay)
{
if (loading || !switchData)
return;
switchData->delay = delay * switchData->delayMultiplier;
}
void SequenceWidget::DelayUnitsChanged(int idx)
{
if (loading || !switchData)
return;
delay_units unit = (delay_units)idx;
switch (unit) {
case SECONDS:
switchData->delayMultiplier = 1;
break; break;
case 60: case MINUTES:
ui->sceneSequenceDelayUnits->setCurrentIndex(1); switchData->delayMultiplier = 60;
break; break;
case 3600: case HOURS:
ui->sceneSequenceDelayUnits->setCurrentIndex(2); switchData->delayMultiplier = 60 * 60;
break; break;
default: default:
break; break;
} }
UpdateDelay();
} }
static inline QString MakeSceneSequenceSwitchName(const QString &scene1, void SequenceWidget::StartSceneChanged(const QString &text)
const QString &scene2,
const QString &transition,
double delay)
{ {
return scene1 + QStringLiteral(" -> wait for ") + if (loading || !switchData)
QString::number(delay) + QStringLiteral(" seconds -> ") + return;
scene2 + QStringLiteral(" (using ") + transition + std::lock_guard<std::mutex> lock(switcher->m);
QStringLiteral(" transition)"); switchData->startScene = GetWeakSourceByQString(text);
} }

View File

@@ -1,173 +1,75 @@
#include "headers/advanced-scene-switcher.hpp" #include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp"
static std::vector<std::pair<std::string, timeTrigger>> triggerTable = { static QMetaObject::Connection addPulse;
{"On any day", timeTrigger::ANY_DAY},
{"Mondays", timeTrigger::MONDAY},
{"Tuesdays", timeTrigger::TUSEDAY},
{"Wednesdays", timeTrigger::WEDNESDAY},
{"Thursdays", timeTrigger::THURSDAY},
{"Fridays", timeTrigger::FRIDAY},
{"Saturdays", timeTrigger::SATURDAY},
{"Sundays", timeTrigger::SUNDAY},
{"Atfer streaming/recording start", timeTrigger::LIVE}};
void SceneSwitcher::on_timeSwitches_currentRowChanged(int idx) void AdvSceneSwitcher::on_timeAdd_clicked()
{ {
if (loading) ui->timeAdd->disconnect(addPulse);
return;
if (idx == -1)
return;
QListWidgetItem *item = ui->timeSwitches->item(idx);
QString timeScenestr = item->data(Qt::UserRole).toString();
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->timeSwitches) { switcher->timeSwitches.emplace_back();
if (timeScenestr.compare(s.timeSwitchStr.c_str()) == 0) {
QString sceneName = GetWeakSourceName(s.scene).c_str(); QListWidgetItem *item;
QString transitionName = item = new QListWidgetItem(ui->timeSwitches);
GetWeakSourceName(s.transition).c_str(); ui->timeSwitches->addItem(item);
ui->timeScenes->setCurrentText(sceneName); TimeSwitchWidget *sw =
ui->timeTrigger->setCurrentIndex(s.trigger); new TimeSwitchWidget(&switcher->timeSwitches.back());
ui->timeEdit->setTime(s.time); item->setSizeHint(sw->minimumSizeHint());
ui->timeTransitions->setCurrentText(transitionName); ui->timeSwitches->setItemWidget(item, sw);
break;
}
}
} }
int SceneSwitcher::timeFindByData(const timeTrigger &trigger, const QTime &time) void AdvSceneSwitcher::on_timeRemove_clicked()
{
QRegExp rx(MakeTimeSwitchName(QStringLiteral(".*"),
QStringLiteral(".*"), trigger, time));
int count = ui->timeSwitches->count();
for (int i = 0; i < count; i++) {
QListWidgetItem *item = ui->timeSwitches->item(i);
QString str = item->data(Qt::UserRole).toString();
if (rx.exactMatch(str))
return i;
}
return -1;
}
void SceneSwitcher::on_timeAdd_clicked()
{
QString sceneName = ui->timeScenes->currentText();
QString transitionName = ui->timeTransitions->currentText();
QTime time = ui->timeEdit->time();
if (sceneName.isEmpty())
return;
OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
std::string triggerStr = ui->timeTrigger->currentText().toStdString();
auto it = std::find_if(
triggerTable.begin(), triggerTable.end(),
[&triggerStr](
const std::pair<std::string, timeTrigger> &element) {
return element.first == triggerStr;
});
timeTrigger trigger = it->second;
QString text =
MakeTimeSwitchName(sceneName, transitionName, trigger, time);
QVariant v = QVariant::fromValue(text);
int idx = timeFindByData(trigger, time);
if (idx == -1) {
std::lock_guard<std::mutex> lock(switcher->m);
switcher->timeSwitches.emplace_back(
source, transition, trigger, time,
(sceneName == QString(previous_scene_name)),
text.toUtf8().constData());
QListWidgetItem *item =
new QListWidgetItem(text, ui->timeSwitches);
item->setData(Qt::UserRole, v);
} else {
QListWidgetItem *item = ui->timeSwitches->item(idx);
item->setText(text);
item->setData(Qt::UserRole, v);
{
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->timeSwitches) {
if (s.trigger == trigger && s.time == time) {
s.scene = source;
s.transition = transition;
s.usePreviousScene =
(sceneName ==
QString(previous_scene_name));
s.timeSwitchStr =
text.toUtf8().constData();
break;
}
}
}
}
}
void SceneSwitcher::on_timeRemove_clicked()
{ {
QListWidgetItem *item = ui->timeSwitches->currentItem(); QListWidgetItem *item = ui->timeSwitches->currentItem();
if (!item) if (!item)
return; return;
std::string text =
item->data(Qt::UserRole).toString().toUtf8().constData();
{ {
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
int idx = ui->timeSwitches->currentRow();
auto &switches = switcher->timeSwitches; auto &switches = switcher->timeSwitches;
switches.erase(switches.begin() + idx);
for (auto it = switches.begin(); it != switches.end(); ++it) {
auto &s = *it;
if (s.timeSwitchStr == text) {
switches.erase(it);
break;
}
}
} }
delete item; delete item;
} }
void SceneSwitcher::on_timeUp_clicked() void AdvSceneSwitcher::on_timeUp_clicked()
{ {
int index = ui->timeSwitches->currentRow(); int index = ui->timeSwitches->currentRow();
if (index != -1 && index != 0) { if (!listMoveUp(ui->timeSwitches))
ui->timeSwitches->insertItem(index - 1, return;
ui->timeSwitches->takeItem(index));
ui->timeSwitches->setCurrentRow(index - 1);
std::lock_guard<std::mutex> lock(switcher->m); TimeSwitchWidget *s1 = (TimeSwitchWidget *)ui->timeSwitches->itemWidget(
ui->timeSwitches->item(index));
TimeSwitchWidget *s2 = (TimeSwitchWidget *)ui->timeSwitches->itemWidget(
ui->timeSwitches->item(index - 1));
TimeSwitchWidget::swapSwitchData(s1, s2);
iter_swap(switcher->timeSwitches.begin() + index, std::lock_guard<std::mutex> lock(switcher->m);
switcher->timeSwitches.begin() + index - 1);
} std::swap(switcher->timeSwitches[index],
switcher->timeSwitches[index - 1]);
} }
void SceneSwitcher::on_timeDown_clicked() void AdvSceneSwitcher::on_timeDown_clicked()
{ {
int index = ui->timeSwitches->currentRow(); int index = ui->timeSwitches->currentRow();
if (index != -1 && index != ui->timeSwitches->count() - 1) {
ui->timeSwitches->insertItem(index + 1,
ui->timeSwitches->takeItem(index));
ui->timeSwitches->setCurrentRow(index + 1);
std::lock_guard<std::mutex> lock(switcher->m); if (!listMoveDown(ui->timeSwitches))
return;
iter_swap(switcher->timeSwitches.begin() + index, TimeSwitchWidget *s1 = (TimeSwitchWidget *)ui->timeSwitches->itemWidget(
switcher->timeSwitches.begin() + index + 1); ui->timeSwitches->item(index));
} TimeSwitchWidget *s2 = (TimeSwitchWidget *)ui->timeSwitches->itemWidget(
ui->timeSwitches->item(index + 1));
TimeSwitchWidget::swapSwitchData(s1, s2);
std::lock_guard<std::mutex> lock(switcher->m);
std::swap(switcher->timeSwitches[index],
switcher->timeSwitches[index + 1]);
} }
bool timesAreInInterval(QTime &time1, QTime &time2, int &interval) bool timesAreInInterval(QTime &time1, QTime &time2, int &interval)
@@ -212,6 +114,9 @@ void SwitcherData::checkTimeSwitch(bool &match, OBSWeakSource &scene,
return; return;
for (TimeSwitch &s : timeSwitches) { for (TimeSwitch &s : timeSwitches) {
if (!s.initialized())
continue;
if (s.trigger == LIVE) if (s.trigger == LIVE)
match = checkLiveTime(s, liveTime, interval); match = checkLiveTime(s, liveTime, interval);
else else
@@ -282,91 +187,123 @@ void SwitcherData::loadTimeSwitches(obs_data_t *obj)
QTime time = QTime::fromString( QTime time = QTime::fromString(
obs_data_get_string(array_obj, "time")); obs_data_get_string(array_obj, "time"));
std::string timeSwitchStr =
MakeTimeSwitchName(scene, transition, trigger, time)
.toUtf8()
.constData();
switcher->timeSwitches.emplace_back( switcher->timeSwitches.emplace_back(
GetWeakSourceByName(scene), GetWeakSourceByName(scene),
GetWeakTransitionByName(transition), trigger, time, GetWeakTransitionByName(transition), trigger, time,
(strcmp(scene, previous_scene_name) == 0), (strcmp(scene, previous_scene_name) == 0));
timeSwitchStr);
obs_data_release(array_obj); obs_data_release(array_obj);
} }
obs_data_array_release(timeArray); obs_data_array_release(timeArray);
} }
void SceneSwitcher::setupTimeTab() void AdvSceneSwitcher::setupTimeTab()
{ {
populateSceneSelection(ui->timeScenes, true); for (auto &s : switcher->timeSwitches) {
populateTransitionSelection(ui->timeTransitions); QListWidgetItem *item;
item = new QListWidgetItem(ui->timeSwitches);
for (auto t : triggerTable) { ui->timeSwitches->addItem(item);
ui->timeTrigger->addItem(t.first.c_str()); TimeSwitchWidget *sw = new TimeSwitchWidget(&s);
item->setSizeHint(sw->minimumSizeHint());
ui->timeSwitches->setItemWidget(item, sw);
} }
// assuming the streaming / recording entry is always last if (switcher->timeSwitches.size() == 0)
ui->timeTrigger->setItemData( addPulse = PulseWidget(ui->timeAdd, QColor(Qt::green));
(int)triggerTable.size() - 1, }
void populateTriggers(QComboBox *list)
{
list->addItem("On any day");
list->addItem("Mondays");
list->addItem("Tuesdays");
list->addItem("Wednesdays");
list->addItem("Thursdays");
list->addItem("Fridays");
list->addItem("Saturdays");
list->addItem("Sundays");
list->addItem("Atfer streaming/recording start");
list->setItemData(
8,
"The time relative to the start of streaming / recording will be used", "The time relative to the start of streaming / recording will be used",
Qt::ToolTipRole); Qt::ToolTipRole);
for (auto &s : switcher->timeSwitches) {
std::string sceneName = (s.usePreviousScene)
? previous_scene_name
: GetWeakSourceName(s.scene);
std::string transitionName = GetWeakSourceName(s.transition);
QString listText = MakeTimeSwitchName(sceneName.c_str(),
transitionName.c_str(),
s.trigger, s.time);
QListWidgetItem *item =
new QListWidgetItem(listText, ui->timeSwitches);
item->setData(Qt::UserRole, listText);
}
} }
static inline QString MakeTimeSwitchName(const QString &scene, TimeSwitchWidget::TimeSwitchWidget(TimeSwitch *s) : SwitchWidget(s)
const QString &transition,
const timeTrigger &trigger,
const QTime &time)
{ {
QString switchName; triggers = new QComboBox();
time = new QTimeEdit();
switch (trigger) { atLabel = new QLabel("at");
case ANY_DAY: switchLabel = new QLabel("switch to");
switchName = QStringLiteral("On any weekday"); usingLabel = new QLabel("using");
break;
case MONDAY: QWidget::connect(triggers, SIGNAL(currentIndexChanged(int)), this,
switchName = QStringLiteral("Mondays"); SLOT(TriggerChanged(int)));
break; QWidget::connect(time, SIGNAL(timeChanged(const QTime &)), this,
case TUSEDAY: SLOT(TimeChanged(const QTime &)));
switchName = QStringLiteral("Tusedays");
break; populateTriggers(triggers);
case WEDNESDAY: time->setDisplayFormat("HH:mm:ss");
switchName = QStringLiteral("Wednesdays");
break; if (s) {
case THURSDAY: triggers->setCurrentIndex(s->trigger);
switchName = QStringLiteral("Thursdays"); time->setTime(s->time);
break;
case FRIDAY:
switchName = QStringLiteral("Fridays");
break;
case SATURDAY:
switchName = QStringLiteral("Saturdays");
break;
case SUNDAY:
switchName = QStringLiteral("Sundays");
break;
case LIVE:
switchName = QStringLiteral(
"Relative to starting streaming / recording");
break;
} }
switchName += QStringLiteral(" at ") + time.toString() +
QStringLiteral(" switch to ") + scene + setStyleSheet("* { background-color: transparent; }");
QStringLiteral(" using ") + transition;
return switchName; QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(triggers);
mainLayout->addWidget(atLabel);
mainLayout->addWidget(time);
mainLayout->addWidget(switchLabel);
mainLayout->addWidget(scenes);
mainLayout->addWidget(usingLabel);
mainLayout->addWidget(transitions);
mainLayout->addStretch();
setLayout(mainLayout);
switchData = s;
loading = false;
}
TimeSwitch *TimeSwitchWidget::getSwitchData()
{
return switchData;
}
void TimeSwitchWidget::setSwitchData(TimeSwitch *s)
{
switchData = s;
}
void TimeSwitchWidget::swapSwitchData(TimeSwitchWidget *s1,
TimeSwitchWidget *s2)
{
SwitchWidget::swapSwitchData(s1, s2);
TimeSwitch *t = s1->getSwitchData();
s1->setSwitchData(s2->getSwitchData());
s2->setSwitchData(t);
}
void TimeSwitchWidget::TriggerChanged(int index)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->trigger = (timeTrigger)index;
}
void TimeSwitchWidget::TimeChanged(const QTime &time)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->time = time;
} }

View File

@@ -1,161 +1,161 @@
#include "headers/advanced-scene-switcher.hpp" #include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp"
void SceneSwitcher::on_transitionsAdd_clicked() void AdvSceneSwitcher::on_transitionsAdd_clicked()
{ {
QString scene1Name = ui->transitionsScene1->currentText(); std::lock_guard<std::mutex> lock(switcher->m);
QString scene2Name = ui->transitionsScene2->currentText(); switcher->sceneTransitions.emplace_back();
QString transitionName = ui->transitionsTransitions->currentText();
if (scene1Name.isEmpty() || scene2Name.isEmpty()) QListWidgetItem *item;
return; item = new QListWidgetItem(ui->sceneTransitions);
ui->sceneTransitions->addItem(item);
if (scene1Name == scene2Name) TransitionSwitchWidget *sw =
return; new TransitionSwitchWidget(&switcher->sceneTransitions.back());
item->setSizeHint(sw->minimumSizeHint());
OBSWeakSource source1 = GetWeakSourceByQString(scene1Name); ui->sceneTransitions->setItemWidget(item, sw);
OBSWeakSource source2 = GetWeakSourceByQString(scene2Name);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QString text =
MakeSceneTransitionName(scene1Name, scene2Name, transitionName);
QVariant v = QVariant::fromValue(text);
int idx = SceneTransitionsFindByData(scene1Name, scene2Name);
if (idx == -1) {
QListWidgetItem *item =
new QListWidgetItem(text, ui->sceneTransitions);
item->setData(Qt::UserRole, v);
std::lock_guard<std::mutex> lock(switcher->m);
switcher->sceneTransitions.emplace_back(
source1, source2, transition,
text.toUtf8().constData());
} else {
QListWidgetItem *item = ui->sceneTransitions->item(idx);
item->setText(text);
{
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->sceneTransitions) {
if (s.scene == source1 && s.scene2 == source2) {
s.transition = transition;
s.sceneTransitionStr =
text.toUtf8().constData();
break;
}
}
}
ui->sceneTransitions->sortItems();
}
} }
void SceneSwitcher::on_transitionsRemove_clicked() void AdvSceneSwitcher::on_transitionsRemove_clicked()
{ {
QListWidgetItem *item = ui->sceneTransitions->currentItem(); QListWidgetItem *item = ui->sceneTransitions->currentItem();
if (!item) if (!item)
return; return;
std::string text =
item->data(Qt::UserRole).toString().toUtf8().constData();
{ {
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
int idx = ui->sceneTransitions->currentRow();
auto &switches = switcher->sceneTransitions; auto &switches = switcher->sceneTransitions;
switches.erase(switches.begin() + idx);
for (auto it = switches.begin(); it != switches.end(); ++it) {
auto &s = *it;
if (s.sceneTransitionStr == text) {
switches.erase(it);
break;
}
}
} }
delete item; delete item;
} }
void SceneSwitcher::on_defaultTransitionsAdd_clicked() void AdvSceneSwitcher::on_transitionsUp_clicked()
{ {
QString sceneName = ui->defaultTransitionsScene->currentText(); int index = ui->sceneTransitions->currentRow();
QString transitionName = if (!listMoveUp(ui->sceneTransitions))
ui->defaultTransitionsTransitions->currentText();
if (sceneName.isEmpty() || transitionName.isEmpty())
return; return;
OBSWeakSource source = GetWeakSourceByQString(sceneName); TransitionSwitchWidget *s1 =
OBSWeakSource transition = GetWeakTransitionByQString(transitionName); (TransitionSwitchWidget *)ui->sceneTransitions->itemWidget(
ui->sceneTransitions->item(index));
TransitionSwitchWidget *s2 =
(TransitionSwitchWidget *)ui->sceneTransitions->itemWidget(
ui->sceneTransitions->item(index - 1));
TransitionSwitchWidget::swapSwitchData(s1, s2);
QString text = std::lock_guard<std::mutex> lock(switcher->m);
MakeDefaultSceneTransitionName(sceneName, transitionName);
QVariant v = QVariant::fromValue(text);
int idx = DefaultTransitionsFindByData(sceneName); std::swap(switcher->sceneTransitions[index],
switcher->sceneTransitions[index - 1]);
if (idx == -1) {
QListWidgetItem *item =
new QListWidgetItem(text, ui->defaultTransitions);
item->setData(Qt::UserRole, v);
std::lock_guard<std::mutex> lock(switcher->m);
switcher->defaultSceneTransitions.emplace_back(
source, transition, text.toUtf8().constData());
} else {
QListWidgetItem *item = ui->defaultTransitions->item(idx);
item->setText(text);
{
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->defaultSceneTransitions) {
if (s.scene == source) {
s.transition = transition;
s.sceneTransitionStr =
text.toUtf8().constData();
break;
}
}
}
ui->defaultTransitions->sortItems();
}
} }
void SceneSwitcher::on_defaultTransitionsRemove_clicked() void AdvSceneSwitcher::on_transitionsDown_clicked()
{
int index = ui->sceneTransitions->currentRow();
if (!listMoveDown(ui->sceneTransitions))
return;
TransitionSwitchWidget *s1 =
(TransitionSwitchWidget *)ui->sceneTransitions->itemWidget(
ui->sceneTransitions->item(index));
TransitionSwitchWidget *s2 =
(TransitionSwitchWidget *)ui->sceneTransitions->itemWidget(
ui->sceneTransitions->item(index + 1));
TransitionSwitchWidget::swapSwitchData(s1, s2);
std::lock_guard<std::mutex> lock(switcher->m);
std::swap(switcher->sceneTransitions[index],
switcher->sceneTransitions[index + 1]);
}
void AdvSceneSwitcher::on_defaultTransitionsAdd_clicked()
{
std::lock_guard<std::mutex> lock(switcher->m);
switcher->defaultSceneTransitions.emplace_back();
QListWidgetItem *item;
item = new QListWidgetItem(ui->defaultTransitions);
ui->defaultTransitions->addItem(item);
DefTransitionSwitchWidget *sw = new DefTransitionSwitchWidget(
&switcher->defaultSceneTransitions.back());
item->setSizeHint(sw->minimumSizeHint());
ui->defaultTransitions->setItemWidget(item, sw);
}
void AdvSceneSwitcher::on_defaultTransitionsRemove_clicked()
{ {
QListWidgetItem *item = ui->defaultTransitions->currentItem(); QListWidgetItem *item = ui->defaultTransitions->currentItem();
if (!item) if (!item)
return; return;
std::string text =
item->data(Qt::UserRole).toString().toUtf8().constData();
{ {
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
int idx = ui->defaultTransitions->currentRow();
auto &switches = switcher->defaultSceneTransitions; auto &switches = switcher->defaultSceneTransitions;
switches.erase(switches.begin() + idx);
for (auto it = switches.begin(); it != switches.end(); ++it) {
auto &s = *it;
if (s.sceneTransitionStr == text) {
switches.erase(it);
break;
}
}
} }
delete item; delete item;
} }
void AdvSceneSwitcher::on_defaultTransitionsUp_clicked()
{
int index = ui->defaultTransitions->currentRow();
if (!listMoveUp(ui->defaultTransitions))
return;
TransitionSwitchWidget *s1 =
(TransitionSwitchWidget *)ui->defaultTransitions->itemWidget(
ui->defaultTransitions->item(index));
TransitionSwitchWidget *s2 =
(TransitionSwitchWidget *)ui->defaultTransitions->itemWidget(
ui->defaultTransitions->item(index - 1));
TransitionSwitchWidget::swapSwitchData(s1, s2);
std::lock_guard<std::mutex> lock(switcher->m);
std::swap(switcher->defaultSceneTransitions[index],
switcher->defaultSceneTransitions[index - 1]);
}
void AdvSceneSwitcher::on_defaultTransitionsDown_clicked()
{
int index = ui->defaultTransitions->currentRow();
if (!listMoveDown(ui->defaultTransitions))
return;
DefTransitionSwitchWidget *s1 =
(DefTransitionSwitchWidget *)ui->defaultTransitions->itemWidget(
ui->defaultTransitions->item(index));
DefTransitionSwitchWidget *s2 =
(DefTransitionSwitchWidget *)ui->defaultTransitions->itemWidget(
ui->defaultTransitions->item(index + 1));
DefTransitionSwitchWidget::swapSwitchData(s1, s2);
std::lock_guard<std::mutex> lock(switcher->m);
std::swap(switcher->defaultSceneTransitions[index],
switcher->defaultSceneTransitions[index + 1]);
}
void SwitcherData::setDefaultSceneTransitions() void SwitcherData::setDefaultSceneTransitions()
{ {
if (changedDefTransitionRecently)
return;
obs_source_t *currentSource = obs_frontend_get_current_scene(); obs_source_t *currentSource = obs_frontend_get_current_scene();
obs_weak_source_t *ws = obs_source_get_weak_source(currentSource); obs_weak_source_t *ws = obs_source_get_weak_source(currentSource);
for (DefaultSceneTransition &s : defaultSceneTransitions) { for (DefaultSceneTransition &s : defaultSceneTransitions) {
if (s.scene == ws) { if (s.scene == ws) {
if (!s.initialized())
continue;
obs_source_t *transition = obs_source_t *transition =
obs_weak_source_get_source(s.transition); obs_weak_source_get_source(s.transition);
//This might cancel the current transition //This might cancel the current transition
@@ -163,8 +163,7 @@ void SwitcherData::setDefaultSceneTransitions()
obs_frontend_set_current_transition(transition); obs_frontend_set_current_transition(transition);
if (verbose) if (verbose)
if (verbose) s.logMatch();
s.logMatch();
obs_source_release(transition); obs_source_release(transition);
break; break;
@@ -172,103 +171,10 @@ void SwitcherData::setDefaultSceneTransitions()
} }
obs_source_release(currentSource); obs_source_release(currentSource);
obs_weak_source_release(ws); obs_weak_source_release(ws);
changedDefTransitionRecently = true;
} }
int SceneSwitcher::SceneTransitionsFindByData(const QString &scene1, void AdvSceneSwitcher::on_transitionOverridecheckBox_stateChanged(int state)
const QString &scene2)
{
QRegExp rx(scene1 + " --- .* --> " + scene2);
int count = ui->sceneTransitions->count();
int idx = -1;
for (int i = 0; i < count; i++) {
QListWidgetItem *item = ui->sceneTransitions->item(i);
QString itemString = item->data(Qt::UserRole).toString();
if (rx.exactMatch(itemString)) {
idx = i;
break;
}
}
return idx;
}
int SceneSwitcher::DefaultTransitionsFindByData(const QString &scene)
{
QRegExp rx(scene + " --> .*");
int count = ui->defaultTransitions->count();
int idx = -1;
for (int i = 0; i < count; i++) {
QListWidgetItem *item = ui->defaultTransitions->item(i);
QString itemString = item->data(Qt::UserRole).toString();
if (rx.exactMatch(itemString)) {
idx = i;
break;
}
}
return idx;
}
void SceneSwitcher::on_sceneTransitions_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem *item = ui->sceneTransitions->item(idx);
QString sceneTransition = item->data(Qt::UserRole).toString();
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->sceneTransitions) {
if (sceneTransition.compare(s.sceneTransitionStr.c_str()) ==
0) {
std::string scene1 = GetWeakSourceName(s.scene);
std::string scene2 = GetWeakSourceName(s.scene2);
std::string transitionName =
GetWeakSourceName(s.transition);
ui->transitionsScene1->setCurrentText(scene1.c_str());
ui->transitionsScene2->setCurrentText(scene2.c_str());
ui->transitionsTransitions->setCurrentText(
transitionName.c_str());
break;
}
}
}
void SceneSwitcher::on_defaultTransitions_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem *item = ui->defaultTransitions->item(idx);
QString sceneTransition = item->data(Qt::UserRole).toString();
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->defaultSceneTransitions) {
if (sceneTransition.compare(s.sceneTransitionStr.c_str()) ==
0) {
std::string scene = GetWeakSourceName(s.scene);
std::string transitionName =
GetWeakSourceName(s.transition);
ui->defaultTransitionsScene->setCurrentText(
scene.c_str());
ui->defaultTransitionsTransitions->setCurrentText(
transitionName.c_str());
break;
}
}
}
void SceneSwitcher::on_transitionOverridecheckBox_stateChanged(int state)
{ {
if (loading) if (loading)
return; return;
@@ -287,8 +193,13 @@ obs_weak_source_t *getNextTransition(obs_weak_source_t *scene1,
obs_weak_source_t *ws = nullptr; obs_weak_source_t *ws = nullptr;
if (scene1 && scene2) { if (scene1 && scene2) {
for (SceneTransition &t : switcher->sceneTransitions) { for (SceneTransition &t : switcher->sceneTransitions) {
if (t.scene == scene1 && t.scene2 == scene2) if (!t.initialized())
continue;
if (t.scene == scene1 && t.scene2 == scene2) {
ws = t.transition; ws = t.transition;
break;
}
} }
obs_weak_source_addref(ws); obs_weak_source_addref(ws);
} }
@@ -373,11 +284,10 @@ void SwitcherData::saveSceneTransitions(obs_data_t *obj)
transitionName); transitionName);
obs_data_array_push_back(sceneTransitionsArray, obs_data_array_push_back(sceneTransitionsArray,
array_obj); array_obj);
obs_source_release(source1);
obs_source_release(source2);
obs_source_release(transition);
} }
obs_source_release(source1);
obs_source_release(source2);
obs_source_release(transition);
obs_data_release(array_obj); obs_data_release(array_obj);
} }
obs_data_set_array(obj, "sceneTransitions", sceneTransitionsArray); obs_data_set_array(obj, "sceneTransitions", sceneTransitionsArray);
@@ -399,10 +309,9 @@ void SwitcherData::saveSceneTransitions(obs_data_t *obj)
transitionName); transitionName);
obs_data_array_push_back(defaultTransitionsArray, obs_data_array_push_back(defaultTransitionsArray,
array_obj); array_obj);
obs_source_release(source);
obs_source_release(transition);
} }
obs_source_release(source);
obs_source_release(transition);
obs_data_release(array_obj); obs_data_release(array_obj);
} }
obs_data_set_array(obj, "defaultTransitions", defaultTransitionsArray); obs_data_set_array(obj, "defaultTransitions", defaultTransitionsArray);
@@ -429,16 +338,10 @@ void SwitcherData::loadSceneTransitions(obs_data_t *obj)
const char *transition = const char *transition =
obs_data_get_string(array_obj, "transition"); obs_data_get_string(array_obj, "transition");
std::string sceneTransitionsStr =
MakeSceneTransitionName(scene1, scene2, transition)
.toUtf8()
.constData();
switcher->sceneTransitions.emplace_back( switcher->sceneTransitions.emplace_back(
GetWeakSourceByName(scene1), GetWeakSourceByName(scene1),
GetWeakSourceByName(scene2), GetWeakSourceByName(scene2),
GetWeakTransitionByName(transition), GetWeakTransitionByName(transition));
sceneTransitionsStr);
obs_data_release(array_obj); obs_data_release(array_obj);
} }
@@ -458,15 +361,9 @@ void SwitcherData::loadSceneTransitions(obs_data_t *obj)
const char *transition = const char *transition =
obs_data_get_string(array_obj, "transition"); obs_data_get_string(array_obj, "transition");
std::string sceneTransitionsStr =
MakeDefaultSceneTransitionName(scene, transition)
.toUtf8()
.constData();
switcher->defaultSceneTransitions.emplace_back( switcher->defaultSceneTransitions.emplace_back(
GetWeakSourceByName(scene), GetWeakSourceByName(scene),
GetWeakTransitionByName(transition), GetWeakTransitionByName(transition));
sceneTransitionsStr);
obs_data_release(array_obj); obs_data_release(array_obj);
} }
@@ -476,52 +373,147 @@ void SwitcherData::loadSceneTransitions(obs_data_t *obj)
obs_data_get_bool(obj, "tansitionOverrideOverride"); obs_data_get_bool(obj, "tansitionOverrideOverride");
} }
void SceneSwitcher::setupTransitionsTab() void AdvSceneSwitcher::setupTransitionsTab()
{ {
populateSceneSelection(ui->transitionsScene1, false);
populateSceneSelection(ui->transitionsScene2, false);
populateSceneSelection(ui->defaultTransitionsScene, false);
populateTransitionSelection(ui->transitionsTransitions);
populateTransitionSelection(ui->defaultTransitionsTransitions);
for (auto &s : switcher->sceneTransitions) { for (auto &s : switcher->sceneTransitions) {
std::string sceneName1 = GetWeakSourceName(s.scene); QListWidgetItem *item;
std::string sceneName2 = GetWeakSourceName(s.scene2); item = new QListWidgetItem(ui->sceneTransitions);
std::string transitionName = GetWeakSourceName(s.transition); ui->sceneTransitions->addItem(item);
QString text = MakeSceneTransitionName(sceneName1.c_str(), TransitionSwitchWidget *sw = new TransitionSwitchWidget(&s);
sceneName2.c_str(), item->setSizeHint(sw->minimumSizeHint());
transitionName.c_str()); ui->sceneTransitions->setItemWidget(item, sw);
QListWidgetItem *item =
new QListWidgetItem(text, ui->sceneTransitions);
item->setData(Qt::UserRole, text);
} }
for (auto &s : switcher->defaultSceneTransitions) { for (auto &s : switcher->defaultSceneTransitions) {
std::string sceneName = GetWeakSourceName(s.scene); QListWidgetItem *item;
std::string transitionName = GetWeakSourceName(s.transition); item = new QListWidgetItem(ui->defaultTransitions);
QString text = MakeDefaultSceneTransitionName( ui->defaultTransitions->addItem(item);
sceneName.c_str(), transitionName.c_str()); DefTransitionSwitchWidget *sw =
new DefTransitionSwitchWidget(&s);
QListWidgetItem *item = item->setSizeHint(sw->minimumSizeHint());
new QListWidgetItem(text, ui->defaultTransitions); ui->defaultTransitions->setItemWidget(item, sw);
item->setData(Qt::UserRole, text);
} }
ui->transitionOverridecheckBox->setChecked( ui->transitionOverridecheckBox->setChecked(
switcher->tansitionOverrideOverride); switcher->tansitionOverrideOverride);
} }
static inline QString MakeSceneTransitionName(const QString &scene1, bool SceneTransition::initialized()
const QString &scene2,
const QString &transition)
{ {
return scene1 + QStringLiteral(" --- ") + transition + return SceneSwitcherEntry::initialized() && scene2;
QStringLiteral(" --> ") + scene2;
} }
static inline QString MakeDefaultSceneTransitionName(const QString &scene, bool SceneTransition::valid()
const QString &transition)
{ {
return scene + QStringLiteral(" --> ") + transition; return !initialized() ||
(SceneSwitcherEntry::valid() && WeakSourceValid(scene2));
}
TransitionSwitchWidget::TransitionSwitchWidget(SceneTransition *s)
: SwitchWidget(s, false)
{
scenes2 = new QComboBox();
switchLabel = new QLabel("Switch from scene");
toLabel = new QLabel("to scene");
usingLabel = new QLabel("using transition");
QWidget::connect(scenes2, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(Scene2Changed(const QString &)));
AdvSceneSwitcher::populateSceneSelection(scenes2, false);
if (s) {
scenes2->setCurrentText(GetWeakSourceName(s->scene2).c_str());
}
setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(switchLabel);
mainLayout->addWidget(scenes);
mainLayout->addWidget(toLabel);
mainLayout->addWidget(scenes2);
mainLayout->addWidget(usingLabel);
mainLayout->addWidget(transitions);
mainLayout->addStretch();
setLayout(mainLayout);
switchData = s;
loading = false;
}
SceneTransition *TransitionSwitchWidget::getSwitchData()
{
return switchData;
}
void TransitionSwitchWidget::setSwitchData(SceneTransition *s)
{
switchData = s;
}
void TransitionSwitchWidget::swapSwitchData(TransitionSwitchWidget *s1,
TransitionSwitchWidget *s2)
{
SwitchWidget::swapSwitchData(s1, s2);
SceneTransition *t = s1->getSwitchData();
s1->setSwitchData(s2->getSwitchData());
s2->setSwitchData(t);
}
void TransitionSwitchWidget::Scene2Changed(const QString &text)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->scene2 = GetWeakSourceByQString(text);
}
DefTransitionSwitchWidget::DefTransitionSwitchWidget(DefaultSceneTransition *s)
: SwitchWidget(s, false)
{
whenLabel = new QLabel("When scene");
switchLabel =
new QLabel("is active change default scene transition to ");
setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(whenLabel);
mainLayout->addWidget(scenes);
mainLayout->addWidget(switchLabel);
mainLayout->addWidget(transitions);
mainLayout->addStretch();
setLayout(mainLayout);
switchData = s;
loading = false;
}
DefaultSceneTransition *DefTransitionSwitchWidget::getSwitchData()
{
return switchData;
}
void DefTransitionSwitchWidget::setSwitchData(DefaultSceneTransition *s)
{
switchData = s;
}
void DefTransitionSwitchWidget::swapSwitchData(DefTransitionSwitchWidget *s1,
DefTransitionSwitchWidget *s2)
{
SwitchWidget::swapSwitchData(s1, s2);
DefaultSceneTransition *t = s1->getSwitchData();
s1->setSwitchData(s2->getSwitchData());
s2->setSwitchData(t);
} }

View File

@@ -1,4 +1,166 @@
#include "headers/advanced-scene-switcher.hpp" #include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp"
static QMetaObject::Connection addPulse;
void AdvSceneSwitcher::on_windowAdd_clicked()
{
ui->windowAdd->disconnect(addPulse);
std::lock_guard<std::mutex> lock(switcher->m);
switcher->windowSwitches.emplace_back();
QListWidgetItem *item;
item = new QListWidgetItem(ui->windowSwitches);
ui->windowSwitches->addItem(item);
WindowSwitchWidget *sw =
new WindowSwitchWidget(&switcher->windowSwitches.back());
item->setSizeHint(sw->minimumSizeHint());
ui->windowSwitches->setItemWidget(item, sw);
}
void AdvSceneSwitcher::on_windowRemove_clicked()
{
QListWidgetItem *item = ui->windowSwitches->currentItem();
if (!item)
return;
{
std::lock_guard<std::mutex> lock(switcher->m);
int idx = ui->windowSwitches->currentRow();
auto &switches = switcher->windowSwitches;
switches.erase(switches.begin() + idx);
}
delete item;
}
void AdvSceneSwitcher::on_windowUp_clicked()
{
int index = ui->windowSwitches->currentRow();
if (!listMoveUp(ui->windowSwitches))
return;
WindowSwitchWidget *s1 =
(WindowSwitchWidget *)ui->windowSwitches->itemWidget(
ui->windowSwitches->item(index));
WindowSwitchWidget *s2 =
(WindowSwitchWidget *)ui->windowSwitches->itemWidget(
ui->windowSwitches->item(index - 1));
WindowSwitchWidget::swapSwitchData(s1, s2);
std::lock_guard<std::mutex> lock(switcher->m);
std::swap(switcher->windowSwitches[index],
switcher->windowSwitches[index - 1]);
}
void AdvSceneSwitcher::on_windowDown_clicked()
{
int index = ui->windowSwitches->currentRow();
if (!listMoveDown(ui->windowSwitches))
return;
WindowSwitchWidget *s1 =
(WindowSwitchWidget *)ui->windowSwitches->itemWidget(
ui->windowSwitches->item(index));
WindowSwitchWidget *s2 =
(WindowSwitchWidget *)ui->windowSwitches->itemWidget(
ui->windowSwitches->item(index + 1));
WindowSwitchWidget::swapSwitchData(s1, s2);
std::lock_guard<std::mutex> lock(switcher->m);
std::swap(switcher->windowSwitches[index],
switcher->windowSwitches[index + 1]);
}
void AdvSceneSwitcher::on_ignoreWindowsAdd_clicked()
{
QString windowName = ui->ignoreWindowsWindows->currentText();
if (windowName.isEmpty())
return;
QVariant v = QVariant::fromValue(windowName);
QList<QListWidgetItem *> items =
ui->ignoreWindows->findItems(windowName, Qt::MatchExactly);
if (items.size() == 0) {
QListWidgetItem *item =
new QListWidgetItem(windowName, ui->ignoreWindows);
item->setData(Qt::UserRole, v);
std::lock_guard<std::mutex> lock(switcher->m);
switcher->ignoreWindowsSwitches.emplace_back(
windowName.toUtf8().constData());
}
}
void AdvSceneSwitcher::on_ignoreWindowsRemove_clicked()
{
QListWidgetItem *item = ui->ignoreWindows->currentItem();
if (!item)
return;
QString windowName = item->data(Qt::UserRole).toString();
{
std::lock_guard<std::mutex> lock(switcher->m);
auto &switches = switcher->ignoreWindowsSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it) {
auto &s = *it;
if (s == windowName.toUtf8().constData()) {
switches.erase(it);
break;
}
}
}
delete item;
}
int AdvSceneSwitcher::IgnoreWindowsFindByData(const QString &window)
{
int count = ui->ignoreWindows->count();
int idx = -1;
for (int i = 0; i < count; i++) {
QListWidgetItem *item = ui->ignoreWindows->item(i);
QString itemRegion = item->data(Qt::UserRole).toString();
if (itemRegion == window) {
idx = i;
break;
}
}
return idx;
}
void AdvSceneSwitcher::on_ignoreWindows_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem *item = ui->ignoreWindows->item(idx);
QString window = item->data(Qt::UserRole).toString();
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->ignoreWindowsSwitches) {
if (window.compare(s.c_str()) == 0) {
ui->ignoreWindowsWindows->setCurrentText(s.c_str());
break;
}
}
}
bool isRunning(std::string &title) bool isRunning(std::string &title)
{ {
@@ -28,246 +190,6 @@ bool isFocused(std::string &title)
return (equals || matches); return (equals || matches);
} }
void SceneSwitcher::on_up_clicked()
{
int index = ui->switches->currentRow();
if (index != -1 && index != 0) {
ui->switches->insertItem(index - 1,
ui->switches->takeItem(index));
ui->switches->setCurrentRow(index - 1);
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(switcher->windowSwitches.begin() + index,
switcher->windowSwitches.begin() + index - 1);
}
}
void SceneSwitcher::on_down_clicked()
{
int index = ui->switches->currentRow();
if (index != -1 && index != ui->switches->count() - 1) {
ui->switches->insertItem(index + 1,
ui->switches->takeItem(index));
ui->switches->setCurrentRow(index + 1);
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(switcher->windowSwitches.begin() + index,
switcher->windowSwitches.begin() + index + 1);
}
}
void SceneSwitcher::on_add_clicked()
{
QString sceneName = ui->scenes->currentText();
QString windowName = ui->windows->currentText();
QString transitionName = ui->transitions->currentText();
bool fullscreen = ui->fullscreenCheckBox->isChecked();
bool maximized = ui->maximizedCheckBox->isChecked();
bool focus = ui->focusCheckBox->isChecked();
if (windowName.isEmpty() || sceneName.isEmpty())
return;
OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QVariant v = QVariant::fromValue(windowName);
QString text = MakeWindowSwitchName(sceneName, windowName,
transitionName, fullscreen,
maximized, focus);
int idx = FindByData(windowName);
if (idx == -1) {
std::lock_guard<std::mutex> lock(switcher->m);
switcher->windowSwitches.emplace_back(
source, windowName.toUtf8().constData(), transition,
fullscreen, maximized, focus);
QListWidgetItem *item = new QListWidgetItem(text, ui->switches);
item->setData(Qt::UserRole, v);
} else {
QListWidgetItem *item = ui->switches->item(idx);
item->setText(text);
std::string window = windowName.toUtf8().constData();
{
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->windowSwitches) {
if (s.window == window) {
s.scene = source;
s.transition = transition;
s.fullscreen = fullscreen;
s.maximized = maximized;
s.focus = focus;
break;
}
}
}
}
}
void SceneSwitcher::on_remove_clicked()
{
QListWidgetItem *item = ui->switches->currentItem();
if (!item)
return;
std::string window =
item->data(Qt::UserRole).toString().toUtf8().constData();
{
std::lock_guard<std::mutex> lock(switcher->m);
auto &switches = switcher->windowSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it) {
auto &s = *it;
if (s.window == window) {
switches.erase(it);
break;
}
}
}
delete item;
}
void SceneSwitcher::on_ignoreWindowsAdd_clicked()
{
QString windowName = ui->ignoreWindowsWindows->currentText();
if (windowName.isEmpty())
return;
QVariant v = QVariant::fromValue(windowName);
QList<QListWidgetItem *> items =
ui->ignoreWindows->findItems(windowName, Qt::MatchExactly);
if (items.size() == 0) {
QListWidgetItem *item =
new QListWidgetItem(windowName, ui->ignoreWindows);
item->setData(Qt::UserRole, v);
std::lock_guard<std::mutex> lock(switcher->m);
switcher->ignoreWindowsSwitches.emplace_back(
windowName.toUtf8().constData());
}
}
void SceneSwitcher::on_ignoreWindowsRemove_clicked()
{
QListWidgetItem *item = ui->ignoreWindows->currentItem();
if (!item)
return;
QString windowName = item->data(Qt::UserRole).toString();
{
std::lock_guard<std::mutex> lock(switcher->m);
auto &switches = switcher->ignoreWindowsSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it) {
auto &s = *it;
if (s == windowName.toUtf8().constData()) {
switches.erase(it);
break;
}
}
}
delete item;
}
int SceneSwitcher::FindByData(const QString &window)
{
int count = ui->switches->count();
int idx = -1;
for (int i = 0; i < count; i++) {
QListWidgetItem *item = ui->switches->item(i);
QString itemWindow = item->data(Qt::UserRole).toString();
if (itemWindow == window) {
idx = i;
break;
}
}
return idx;
}
int SceneSwitcher::IgnoreWindowsFindByData(const QString &window)
{
int count = ui->ignoreWindows->count();
int idx = -1;
for (int i = 0; i < count; i++) {
QListWidgetItem *item = ui->ignoreWindows->item(i);
QString itemRegion = item->data(Qt::UserRole).toString();
if (itemRegion == window) {
idx = i;
break;
}
}
return idx;
}
void SceneSwitcher::on_switches_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem *item = ui->switches->item(idx);
QString window = item->data(Qt::UserRole).toString();
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->windowSwitches) {
if (window.compare(s.window.c_str()) == 0) {
std::string name = GetWeakSourceName(s.scene);
std::string transitionName =
GetWeakSourceName(s.transition);
ui->scenes->setCurrentText(name.c_str());
ui->windows->setCurrentText(window);
ui->transitions->setCurrentText(transitionName.c_str());
ui->fullscreenCheckBox->setChecked(s.fullscreen);
ui->maximizedCheckBox->setChecked(s.maximized);
ui->focusCheckBox->setChecked(s.focus);
break;
}
}
}
void SceneSwitcher::on_ignoreWindows_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem *item = ui->ignoreWindows->item(idx);
QString window = item->data(Qt::UserRole).toString();
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->ignoreWindowsSwitches) {
if (window.compare(s.c_str()) == 0) {
ui->ignoreWindowsWindows->setCurrentText(s.c_str());
break;
}
}
}
void SwitcherData::checkWindowTitleSwitch(bool &match, OBSWeakSource &scene, void SwitcherData::checkWindowTitleSwitch(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition) OBSWeakSource &transition)
{ {
@@ -293,7 +215,10 @@ void SwitcherData::checkWindowTitleSwitch(bool &match, OBSWeakSource &scene,
lastTitle = title; lastTitle = title;
// Check for match // Check for match
for (WindowSceneSwitch &s : windowSwitches) { for (WindowSwitch &s : windowSwitches) {
if (!s.initialized())
continue;
// True if fullscreen is disabled OR current window is fullscreen // True if fullscreen is disabled OR current window is fullscreen
bool fullscreen = (!s.fullscreen || isFullscreen(s.window)); bool fullscreen = (!s.fullscreen || isFullscreen(s.window));
// True if maximized is disabled OR current window is maximized // True if maximized is disabled OR current window is maximized
@@ -324,7 +249,7 @@ void SwitcherData::checkWindowTitleSwitch(bool &match, OBSWeakSource &scene,
void SwitcherData::saveWindowTitleSwitches(obs_data_t *obj) void SwitcherData::saveWindowTitleSwitches(obs_data_t *obj)
{ {
obs_data_array_t *windowTitleArray = obs_data_array_create(); obs_data_array_t *windowTitleArray = obs_data_array_create();
for (WindowSceneSwitch &s : switcher->windowSwitches) { for (WindowSwitch &s : switcher->windowSwitches) {
obs_data_t *array_obj = obs_data_create(); obs_data_t *array_obj = obs_data_create();
obs_source_t *source = obs_weak_source_get_source(s.scene); obs_source_t *source = obs_weak_source_get_source(s.scene);
@@ -344,9 +269,9 @@ void SwitcherData::saveWindowTitleSwitches(obs_data_t *obj)
obs_data_set_bool(array_obj, "maximized", s.maximized); obs_data_set_bool(array_obj, "maximized", s.maximized);
obs_data_set_bool(array_obj, "focus", s.focus); obs_data_set_bool(array_obj, "focus", s.focus);
obs_data_array_push_back(windowTitleArray, array_obj); obs_data_array_push_back(windowTitleArray, array_obj);
obs_source_release(source);
obs_source_release(transition);
} }
obs_source_release(source);
obs_source_release(transition);
obs_data_release(array_obj); obs_data_release(array_obj);
} }
obs_data_set_array(obj, "switches", windowTitleArray); obs_data_set_array(obj, "switches", windowTitleArray);
@@ -420,26 +345,22 @@ void SwitcherData::loadWindowTitleSwitches(obs_data_t *obj)
obs_data_array_release(ignoreWindowsArray); obs_data_array_release(ignoreWindowsArray);
} }
void SceneSwitcher::setupTitleTab() void AdvSceneSwitcher::setupTitleTab()
{ {
populateSceneSelection(ui->scenes, false);
populateTransitionSelection(ui->transitions);
populateWindowSelection(ui->windows);
populateWindowSelection(ui->ignoreWindowsWindows);
for (auto &s : switcher->windowSwitches) { for (auto &s : switcher->windowSwitches) {
std::string sceneName = GetWeakSourceName(s.scene); QListWidgetItem *item;
std::string transitionName = GetWeakSourceName(s.transition); item = new QListWidgetItem(ui->windowSwitches);
QString text = MakeWindowSwitchName(sceneName.c_str(), ui->windowSwitches->addItem(item);
s.window.c_str(), WindowSwitchWidget *sw = new WindowSwitchWidget(&s);
transitionName.c_str(), item->setSizeHint(sw->minimumSizeHint());
s.fullscreen, s.maximized, ui->windowSwitches->setItemWidget(item, sw);
s.focus);
QListWidgetItem *item = new QListWidgetItem(text, ui->switches);
item->setData(Qt::UserRole, s.window.c_str());
} }
if (switcher->windowSwitches.size() == 0)
addPulse = PulseWidget(ui->windowAdd, QColor(Qt::green));
populateWindowSelection(ui->ignoreWindowsWindows);
for (auto &window : switcher->ignoreWindowsSwitches) { for (auto &window : switcher->ignoreWindowsSwitches) {
QString text = QString::fromStdString(window); QString text = QString::fromStdString(window);
@@ -447,36 +368,110 @@ void SceneSwitcher::setupTitleTab()
new QListWidgetItem(text, ui->ignoreWindows); new QListWidgetItem(text, ui->ignoreWindows);
item->setData(Qt::UserRole, text); item->setData(Qt::UserRole, text);
} }
}
WindowSwitchWidget::WindowSwitchWidget(WindowSwitch *s) : SwitchWidget(s, false)
{
windows = new QComboBox();
fullscreen = new QCheckBox("if fullscreen");
maximized = new QCheckBox("if maximized");
focused = new QCheckBox("if focused");
QWidget::connect(windows, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(WindowChanged(const QString &)));
QWidget::connect(fullscreen, SIGNAL(stateChanged(int)), this,
SLOT(FullscreenChanged(int)));
QWidget::connect(maximized, SIGNAL(stateChanged(int)), this,
SLOT(MaximizedChanged(int)));
QWidget::connect(focused, SIGNAL(stateChanged(int)), this,
SLOT(FocusChanged(int)));
AdvSceneSwitcher::populateWindowSelection(windows);
windows->setEditable(true);
windows->setMaxVisibleItems(20);
#if __APPLE__ #if __APPLE__
// TODO: // TODO:
// not implemented on MacOS as I cannot test it // not implemented on MacOS as I cannot test it
ui->maximizedCheckBox->setDisabled(true); maximized->setDisabled(true);
ui->maximizedCheckBox->setVisible(false); maximized->setVisible(false);
#endif #endif
}
static inline QString MakeWindowSwitchName(const QString &scene, if (s) {
const QString &value, windows->setCurrentText(s->window.c_str());
const QString &transition, fullscreen->setChecked(s->fullscreen);
bool fullscreen, bool maximized, maximized->setChecked(s->maximized);
bool focus) focused->setChecked(s->focus);
{
QString name = QStringLiteral("[") + scene + QStringLiteral(", ") +
transition + QStringLiteral("]: ") + value;
if (fullscreen || maximized || focus) {
name += QStringLiteral(" (only if");
if (fullscreen)
name += QStringLiteral(" fullscreen ");
if (maximized)
name += QStringLiteral(" maximized ");
if (focus)
name += QStringLiteral(" focused");
name += QStringLiteral(")");
} }
return name; setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(windows);
mainLayout->addWidget(scenes);
mainLayout->addWidget(transitions);
mainLayout->addWidget(scenes);
mainLayout->addWidget(fullscreen);
mainLayout->addWidget(maximized);
mainLayout->addWidget(focused);
mainLayout->addStretch();
setLayout(mainLayout);
switchData = s;
loading = false;
}
WindowSwitch *WindowSwitchWidget::getSwitchData()
{
return switchData;
}
void WindowSwitchWidget::setSwitchData(WindowSwitch *s)
{
switchData = s;
}
void WindowSwitchWidget::swapSwitchData(WindowSwitchWidget *s1,
WindowSwitchWidget *s2)
{
SwitchWidget::swapSwitchData(s1, s2);
WindowSwitch *t = s1->getSwitchData();
s1->setSwitchData(s2->getSwitchData());
s2->setSwitchData(t);
}
void WindowSwitchWidget::WindowChanged(const QString &text)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->window = text.toStdString();
}
void WindowSwitchWidget::FullscreenChanged(int state)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->fullscreen = state;
}
void WindowSwitchWidget::MaximizedChanged(int state)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->maximized = state;
}
void WindowSwitchWidget::FocusChanged(int state)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->focus = state;
} }

View File

@@ -4,7 +4,7 @@
void SwitcherData::Prune() void SwitcherData::Prune()
{ {
for (size_t i = 0; i < windowSwitches.size(); i++) { for (size_t i = 0; i < windowSwitches.size(); i++) {
WindowSceneSwitch &s = windowSwitches[i]; WindowSwitch &s = windowSwitches[i];
if (!s.valid()) if (!s.valid())
windowSwitches.erase(windowSwitches.begin() + i--); windowSwitches.erase(windowSwitches.begin() + i--);
} }
@@ -60,7 +60,7 @@ void SwitcherData::Prune()
} }
for (size_t i = 0; i < executableSwitches.size(); i++) { for (size_t i = 0; i < executableSwitches.size(); i++) {
ExecutableSceneSwitch &s = executableSwitches[i]; ExecutableSwitch &s = executableSwitches[i];
if (!s.valid()) if (!s.valid())
executableSwitches.erase(executableSwitches.begin() + executableSwitches.erase(executableSwitches.begin() +
i--); i--);

View File

@@ -3,13 +3,16 @@
#include "../headers/advanced-scene-switcher.hpp" #include "../headers/advanced-scene-switcher.hpp"
#include <TlHelp32.h> #include <TlHelp32.h>
#include <Psapi.h> #include <Psapi.h>
#include <locale>
#include <codecvt>
#include <string>
using namespace std; #define MAX_SEARCH 1000
static bool GetWindowTitle(HWND window, string &title) static bool GetWindowTitle(HWND window, std::string &title)
{ {
size_t len = (size_t)GetWindowTextLengthW(window); size_t len = (size_t)GetWindowTextLengthW(window);
wstring wtitle; std::wstring wtitle;
wtitle.resize(len); wtitle.resize(len);
if (!GetWindowTextW(window, &wtitle[0], (int)len + 1)) if (!GetWindowTextW(window, &wtitle[0], (int)len + 1))
@@ -40,36 +43,55 @@ static bool WindowValid(HWND window)
return true; return true;
} }
void GetWindowList(vector<string> &windows) BOOL CALLBACK GetTitleCB(HWND hwnd, LPARAM lParam)
{ {
windows.resize(0); if (!WindowValid(hwnd)) {
return TRUE;
}
HWND window = GetWindow(GetDesktopWindow(), GW_CHILD); std::string title;
GetWindowTitle(hwnd, title);
if (title.empty())
return TRUE;
while (window) { std::vector<std::string> &titles =
string title; *reinterpret_cast<std::vector<std::string> *>(lParam);
if (WindowValid(window) && GetWindowTitle(window, title)) titles.push_back(title);
windows.emplace_back(title);
window = GetNextWindow(window, GW_HWNDNEXT); return TRUE;
}
VOID EnumWindowsWithMetro(__in WNDENUMPROC lpEnumFunc, __in LPARAM lParam)
{
HWND childWindow = NULL;
int i = 0;
while (i < MAX_SEARCH &&
(childWindow = FindWindowEx(NULL, childWindow, NULL, NULL))) {
if (!lpEnumFunc(childWindow, lParam))
return;
i++;
} }
} }
// Overloaded void GetWindowList(std::vector<std::string> &windows)
{
windows.resize(0);
EnumWindowsWithMetro(GetTitleCB, reinterpret_cast<LPARAM>(&windows));
}
void GetWindowList(QStringList &windows) void GetWindowList(QStringList &windows)
{ {
windows.clear(); windows.clear();
HWND window = GetWindow(GetDesktopWindow(), GW_CHILD); std::vector<std::string> w;
GetWindowList(w);
while (window) { for (auto window : w) {
string title; windows << QString::fromStdString(window);
if (WindowValid(window) && GetWindowTitle(window, title))
windows << QString::fromStdString(title);
window = GetNextWindow(window, GW_HWNDNEXT);
} }
} }
void GetCurrentWindowTitle(string &title) void GetCurrentWindowTitle(std::string &title)
{ {
HWND window = GetForegroundWindow(); HWND window = GetForegroundWindow();
DWORD pid; DWORD pid;
@@ -97,22 +119,26 @@ std::pair<int, int> getCursorPos()
return pos; return pos;
} }
HWND getHWNDfromTitle(std::string title)
{
HWND hwnd = NULL;
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
std::wstring wTitle = converter.from_bytes(title);
hwnd = FindWindowEx(NULL, NULL, NULL, wTitle.c_str());
return hwnd;
}
bool isMaximized(std::string &title) bool isMaximized(std::string &title)
{ {
RECT appBounds; RECT appBounds;
MONITORINFO monitorInfo = {0}; MONITORINFO monitorInfo = {0};
HWND hwnd = NULL;
HWND hwnd = GetWindow(GetDesktopWindow(), GW_CHILD); hwnd = getHWNDfromTitle(title);
while (hwnd) { if (!hwnd)
string wtitle; return false;
if (WindowValid(hwnd) && GetWindowTitle(hwnd, wtitle) &&
(wtitle == title ||
QString::fromStdString(wtitle).contains(QRegularExpression(
QString::fromStdString(title)))))
break;
hwnd = GetNextWindow(hwnd, GW_HWNDNEXT);
}
monitorInfo.cbSize = sizeof(MONITORINFO); monitorInfo.cbSize = sizeof(MONITORINFO);
GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST), GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST),
@@ -138,17 +164,11 @@ bool isFullscreen(std::string &title)
RECT appBounds; RECT appBounds;
MONITORINFO monitorInfo = {0}; MONITORINFO monitorInfo = {0};
HWND hwnd = GetWindow(GetDesktopWindow(), GW_CHILD); HWND hwnd = NULL;
while (hwnd) { hwnd = getHWNDfromTitle(title);
string wtitle;
if (WindowValid(hwnd) && GetWindowTitle(hwnd, wtitle) &&
(wtitle == title ||
QString::fromStdString(wtitle).contains(QRegularExpression(
QString::fromStdString(title)))))
break;
hwnd = GetNextWindow(hwnd, GW_HWNDNEXT); if (!hwnd)
} return false;
monitorInfo.cbSize = sizeof(MONITORINFO); monitorInfo.cbSize = sizeof(MONITORINFO);
GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST), GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST),