diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6753351e..17386077 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -32,6 +32,7 @@ set(advanced-scene-switcher_SOURCES
hotkey.cpp
general.cpp
pause-switch.cpp
+ random.cpp
)
set(advanced-scene-switcher_UI
${advanced-scene-switcher_UI}
diff --git a/advanced-scene-switcher.cpp b/advanced-scene-switcher.cpp
index 2dcc8d71..c1286dd8 100644
--- a/advanced-scene-switcher.cpp
+++ b/advanced-scene-switcher.cpp
@@ -54,6 +54,7 @@ SceneSwitcher::SceneSwitcher(QWidget* parent)
ui->defaultTransitionsScene->addItem(name);
ui->executableScenes->addItem(name);
ui->idleScenes->addItem(name);
+ ui->randomScenes->addItem(name);
temp++;
}
@@ -70,17 +71,28 @@ SceneSwitcher::SceneSwitcher(QWidget* parent)
ui->defaultTransitionsTransitions->addItem(name);
ui->executableTransitions->addItem(name);
ui->idleTransitions->addItem(name);
+ ui->randomTransitions->addItem(name);
}
obs_frontend_source_list_free(transitions);
- if (switcher->switchIfNotMatching)
+ if (switcher->switchIfNotMatching == SWITCH)
+ {
ui->noMatchSwitch->setChecked(true);
- else
+ ui->noMatchSwitchScene->setEnabled(true);
+ }
+ else if (switcher->switchIfNotMatching == NO_SWITCH)
+ {
ui->noMatchDontSwitch->setChecked(true);
-
+ ui->noMatchSwitchScene->setEnabled(false);
+ }
+ else
+ {
+ ui->noMatchRandomSwitch->setChecked(true);
+ ui->noMatchSwitchScene->setEnabled(false);
+ }
ui->noMatchSwitchScene->setCurrentText(GetWeakSourceName(switcher->nonMatchingScene).c_str());
ui->checkInterval->setValue(switcher->interval);
@@ -219,6 +231,17 @@ SceneSwitcher::SceneSwitcher(QWidget* parent)
item->setData(Qt::UserRole, text);
}
+ for (auto& s : switcher->randomSwitches)
+ {
+ string sceneName = GetWeakSourceName(s.scene);
+ string transitionName = GetWeakSourceName(s.transition);
+ QString text = MakeRandomSwitchName(
+ sceneName.c_str(), transitionName.c_str(), s.delay);
+
+ QListWidgetItem* item = new QListWidgetItem(text, ui->randomScenesList);
+ item->setData(Qt::UserRole, text);
+ }
+
ui->idleCheckBox->setChecked(switcher->idleData.idleEnable);
ui->idleScenes->setCurrentText(GetWeakSourceName(switcher->idleData.scene).c_str());
ui->idleTransitions->setCurrentText(GetWeakSourceName(switcher->idleData.transition).c_str());
@@ -290,6 +313,8 @@ static void SaveSceneSwitcher(obs_data_t* save_data, bool saving, void*)
obs_data_array_t* sceneTransitionsArray = obs_data_array_create();
obs_data_array_t* defaultTransitionsArray = obs_data_array_create();
obs_data_array_t* ignoreIdleWindowsArray = obs_data_array_create();
+ obs_data_array_t* executableArray = obs_data_array_create();
+ obs_data_array_t* randomArray = obs_data_array_create();
switcher->Prune();
@@ -445,8 +470,6 @@ static void SaveSceneSwitcher(obs_data_t* save_data, bool saving, void*)
obs_data_release(array_obj);
}
- obs_data_array_t* executableArray = obs_data_array_create();
-
for (ExecutableSceneSwitch& s : switcher->executableSwitches)
{
obs_data_t* array_obj = obs_data_create();
@@ -470,6 +493,29 @@ static void SaveSceneSwitcher(obs_data_t* save_data, bool saving, void*)
obs_data_release(array_obj);
}
+ for (RandomSwitch& s : switcher->randomSwitches)
+ {
+ obs_data_t* array_obj = obs_data_create();
+
+ obs_source_t* source = obs_weak_source_get_source(s.scene);
+ obs_source_t* transition = obs_weak_source_get_source(s.transition);
+
+ if (source && transition)
+ {
+ const char* sceneName = obs_source_get_name(source);
+ const char* transitionName = obs_source_get_name(transition);
+ obs_data_set_string(array_obj, "scene", sceneName);
+ obs_data_set_string(array_obj, "transition", transitionName);
+ obs_data_set_double(array_obj, "delay", s.delay);
+ obs_data_set_string(array_obj, "str", s.randomSwitchStr.c_str());
+ obs_data_array_push_back(randomArray, array_obj);
+ obs_source_release(source);
+ obs_source_release(transition);
+ }
+
+ obs_data_release(array_obj);
+ }
+
for (string& window : switcher->ignoreIdleWindows)
{
obs_data_t* array_obj = obs_data_create();
@@ -482,7 +528,7 @@ static void SaveSceneSwitcher(obs_data_t* save_data, bool saving, void*)
obs_data_set_int(obj, "interval", switcher->interval);
obs_data_set_string(obj, "non_matching_scene", nonMatchingSceneName.c_str());
- obs_data_set_bool(obj, "switch_if_not_matching", switcher->switchIfNotMatching);
+ obs_data_set_int(obj, "switch_if_not_matching", switcher->switchIfNotMatching);
obs_data_set_bool(obj, "active", !switcher->stop);
obs_data_set_array(obj, "switches", array);
@@ -495,6 +541,7 @@ static void SaveSceneSwitcher(obs_data_t* save_data, bool saving, void*)
obs_data_set_array(obj, "defaultTransitions", defaultTransitionsArray);
obs_data_set_array(obj, "executableSwitches", executableArray);
obs_data_set_array(obj, "ignoreIdleWindows", ignoreIdleWindowsArray);
+ obs_data_set_array(obj, "randomSwitches", randomArray);
string autoStopSceneName = GetWeakSourceName(switcher->autoStopScene);
@@ -532,6 +579,7 @@ static void SaveSceneSwitcher(obs_data_t* save_data, bool saving, void*)
obs_data_array_release(defaultTransitionsArray);
obs_data_array_release(executableArray);
obs_data_array_release(ignoreIdleWindowsArray);
+ obs_data_array_release(randomArray);
obs_data_release(obj);
}
@@ -550,6 +598,7 @@ static void SaveSceneSwitcher(obs_data_t* save_data, bool saving, void*)
obs_data_array_t* defaultTransitionsArray = obs_data_get_array(obj, "defaultTransitions");
obs_data_array_t* executableArray = obs_data_get_array(obj, "executableSwitches");
obs_data_array_t* ignoreIdleWindowsArray = obs_data_get_array(obj, "ignoreIdleWindows");
+ obs_data_array_t* randomArray = obs_data_get_array(obj, "randomSwitches");
if (!obj)
obj = obs_data_create();
@@ -557,7 +606,7 @@ static void SaveSceneSwitcher(obs_data_t* save_data, bool saving, void*)
obs_data_set_default_int(obj, "interval", DEFAULT_INTERVAL);
switcher->interval = obs_data_get_int(obj, "interval");
- switcher->switchIfNotMatching = obs_data_get_bool(obj, "switch_if_not_matching");
+ switcher->switchIfNotMatching = (NoMatch)obs_data_get_int(obj, "switch_if_not_matching");
string nonMatchingScene = obs_data_get_string(obj, "non_matching_scene");
bool active = obs_data_get_bool(obj, "active");
@@ -737,6 +786,23 @@ static void SaveSceneSwitcher(obs_data_t* save_data, bool saving, void*)
obs_data_release(array_obj);
}
+ count = obs_data_array_count(randomArray);
+
+ for (size_t i = 0; i < count; i++)
+ {
+ obs_data_t* array_obj = obs_data_array_item(randomArray, i);
+
+ const char* scene = obs_data_get_string(array_obj, "scene");
+ const char* transition = obs_data_get_string(array_obj, "transition");
+ double delay = obs_data_get_double(array_obj, "delay");
+ string str = obs_data_get_string(array_obj, "str");
+
+ switcher->randomSwitches.emplace_back(
+ GetWeakSourceByName(scene), GetWeakTransitionByName(transition), delay, str);
+
+ obs_data_release(array_obj);
+ }
+
string autoStopScene = obs_data_get_string(obj, "autoStopSceneName");
switcher->autoStopEnable = obs_data_get_bool(obj, "autoStopEnable");
switcher->autoStopScene = GetWeakSourceByName(autoStopScene.c_str());
@@ -785,6 +851,7 @@ static void SaveSceneSwitcher(obs_data_t* save_data, bool saving, void*)
obs_data_array_release(defaultTransitionsArray);
obs_data_array_release(executableArray);
obs_data_array_release(ignoreIdleWindowsArray);
+ obs_data_array_release(randomArray);
obs_data_release(obj);
@@ -854,6 +921,8 @@ void SwitcherData::Thread()
//to avoid scene duplication when rapidly switching scene collection
this_thread::sleep_for(chrono::seconds(2));
+ int extraSleep = 0;
+
while (true)
{
startLoop:
@@ -861,7 +930,12 @@ void SwitcherData::Thread()
bool match = false;
OBSWeakSource scene;
OBSWeakSource transition;
- chrono::milliseconds duration(interval);
+ chrono::milliseconds duration;
+ if (extraSleep > interval)
+ duration = chrono::milliseconds(extraSleep);
+ else
+ duration = chrono::milliseconds(interval);
+ extraSleep = 0;
switcher->Prune();
//sleep for a bit
cv.wait_for(lock, duration);
@@ -919,12 +993,16 @@ void SwitcherData::Thread()
}
}
- if (!match && switchIfNotMatching && nonMatchingScene)
+ if (!match && switchIfNotMatching == SWITCH && nonMatchingScene)
{
match = true;
scene = nonMatchingScene;
transition = nullptr;
}
+ if (!match && switchIfNotMatching == RANDOM_SWITCH)
+ {
+ checkRandom(match, scene, transition, extraSleep);
+ }
if (match)
{
switchScene(scene, transition);
diff --git a/advanced-scene-switcher.hpp b/advanced-scene-switcher.hpp
index d6959fb6..8d09d942 100644
--- a/advanced-scene-switcher.hpp
+++ b/advanced-scene-switcher.hpp
@@ -36,6 +36,7 @@ public:
int DefaultTransitionsFindByData(const QString &scene);
int executableFindByData(const QString &exe);
int IgnoreIdleWindowsFindByData(const QString& window);
+ int randomFindByData(const QString& scene);
void UpdateNonMatchingScene(const QString &name);
void UpdateAutoStopScene(const QString &name);
@@ -48,6 +49,7 @@ public slots:
void on_remove_clicked();
void on_noMatchDontSwitch_clicked();
void on_noMatchSwitch_clicked();
+ void on_noMatchRandomSwitch_clicked();
void on_startAtLaunch_toggled(bool value);
void on_noMatchSwitchScene_currentTextChanged(const QString &text);
void on_checkInterval_valueChanged(int value);
@@ -103,6 +105,10 @@ public slots:
void on_ignoreIdleAdd_clicked();
void on_ignoreIdleRemove_clicked();
+ void on_randomAdd_clicked();
+ void on_randomRemove_clicked();
+ void on_randomScenesList_currentRowChanged(int idx);
+
void on_priorityUp_clicked();
void on_priorityDown_clicked();
diff --git a/forms/advanced-scene-switcher.ui b/forms/advanced-scene-switcher.ui
index 9cc63926..6cb36495 100644
--- a/forms/advanced-scene-switcher.ui
+++ b/forms/advanced-scene-switcher.ui
@@ -7,7 +7,7 @@
0
0
981
- 405
+ 428
@@ -205,6 +205,13 @@
+ -
+
+
+ Switch to any Scene on Random Tab
+
+
+
-
@@ -1912,6 +1919,149 @@
+
+
+ Random
+
+
+ -
+
+
-
+
+
+ If no switch condition is met switch to
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 100
+ 0
+
+
+
+
+ -
+
+
+ using the
+
+
+
+ -
+
+
+ -
+
+
+ transition for a duration of
+
+
+
+ -
+
+
+ s
+
+
+ 999999999.990000009536743
+
+
+
+ -
+
+
+ or any of the options below:
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ true
+
+
+
+ -
+
+
-
+
+
+
+ 22
+ 22
+
+
+
+ true
+
+
+ addIconSmall
+
+
+
+ -
+
+
+
+ 22
+ 22
+
+
+
+ true
+
+
+ removeIconSmall
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
Write To File / Read From File
diff --git a/general.cpp b/general.cpp
index 30cf3fca..37f3ff03 100644
--- a/general.cpp
+++ b/general.cpp
@@ -32,7 +32,8 @@ void SceneSwitcher::on_noMatchDontSwitch_clicked()
return;
lock_guard lock(switcher->m);
- switcher->switchIfNotMatching = false;
+ switcher->switchIfNotMatching = NO_SWITCH;
+ ui->noMatchSwitchScene->setEnabled(false);
}
void SceneSwitcher::on_noMatchSwitch_clicked()
@@ -41,10 +42,21 @@ void SceneSwitcher::on_noMatchSwitch_clicked()
return;
lock_guard lock(switcher->m);
- switcher->switchIfNotMatching = true;
+ switcher->switchIfNotMatching = SWITCH;
+ ui->noMatchSwitchScene->setEnabled(true);
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
}
+void SceneSwitcher::on_noMatchRandomSwitch_clicked()
+{
+ if (loading)
+ return;
+
+ lock_guard lock(switcher->m);
+ switcher->switchIfNotMatching = RANDOM_SWITCH;
+ ui->noMatchSwitchScene->setEnabled(false);
+}
+
void SceneSwitcher::on_noMatchSwitchScene_currentTextChanged(const QString& text)
{
if (loading)
diff --git a/random.cpp b/random.cpp
new file mode 100644
index 00000000..650effe2
--- /dev/null
+++ b/random.cpp
@@ -0,0 +1,144 @@
+#include "advanced-scene-switcher.hpp"
+
+void SceneSwitcher::on_randomScenesList_currentRowChanged(int idx)
+{
+ if (loading)
+ return;
+ if (idx == -1)
+ return;
+
+ QListWidgetItem* item = ui->randomScenesList->item(idx);
+
+ QString randomSceneStr = item->data(Qt::UserRole).toString();
+
+ lock_guard lock(switcher->m);
+ for (auto& s : switcher->randomSwitches)
+ {
+ if (randomSceneStr.compare(s.randomSwitchStr.c_str()) == 0)
+ {
+ QString sceneName = GetWeakSourceName(s.scene).c_str();
+ QString transitionName = GetWeakSourceName(s.transition).c_str();
+ ui->randomScenes->setCurrentText(sceneName);
+ ui->randomSpinBox->setValue(s.delay);
+ ui->randomTransitions->setCurrentText(transitionName);
+ break;
+ }
+ }
+}
+
+int SceneSwitcher::randomFindByData(const QString& randomStr)
+{
+ int count = ui->randomScenesList->count();
+
+ 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)
+ {
+ lock_guard 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);
+
+ {
+ lock_guard 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)
+ return;
+
+ string text = item->data(Qt::UserRole).toString().toUtf8().constData();
+
+ {
+ lock_guard lock(switcher->m);
+ auto& switches = switcher->randomSwitches;
+
+ for (auto it = switches.begin(); it != switches.end(); ++it)
+ {
+ auto& s = *it;
+
+ if (s.randomSwitchStr == text)
+ {
+ switches.erase(it);
+ break;
+ }
+ }
+ }
+
+ delete item;
+}
+
+
+void SwitcherData::checkRandom(bool& match, OBSWeakSource& scene, OBSWeakSource& transition, int& delay)
+{
+ int size = randomSwitches.size();
+ if (randomSwitches.size() == 0)
+ return;
+
+ vector rs = randomSwitches;
+ std::random_shuffle(rs.begin(), rs.end());
+ for (RandomSwitch& r : rs)
+ {
+ if (r.scene == lastRandomScene)
+ continue;
+ scene = r.scene;
+ transition = r.transition;
+ delay = (int)r.delay * 1000;
+ match = true;
+ lastRandomScene = r.scene;
+ break;
+ }
+}
diff --git a/switcher-data-structs.hpp b/switcher-data-structs.hpp
index 4ed1f037..41b15efc 100644
--- a/switcher-data-structs.hpp
+++ b/switcher-data-structs.hpp
@@ -100,6 +100,23 @@ struct SceneRoundTripSwitch
}
};
+struct RandomSwitch
+{
+ OBSWeakSource scene;
+ OBSWeakSource transition;
+ double delay;
+ string randomSwitchStr;
+
+ inline RandomSwitch(OBSWeakSource scene_, OBSWeakSource transition_
+ , double delay_, string str)
+ : scene(scene_)
+ , transition(transition_)
+ , delay(delay_)
+ , randomSwitchStr(str)
+ {
+ }
+};
+
struct SceneTransition
{
OBSWeakSource scene1;
@@ -148,6 +165,11 @@ struct IdleData
OBSWeakSource transition;
};
+typedef enum {
+ NO_SWITCH = 0,
+ SWITCH = 1,
+ RANDOM_SWITCH = 2
+} NoMatch;
@@ -164,14 +186,16 @@ struct SwitcherData
vector switches;
string lastTitle;
OBSWeakSource nonMatchingScene;
+ OBSWeakSource lastRandomScene;
int interval = DEFAULT_INTERVAL;
- bool switchIfNotMatching = false;
+ NoMatch switchIfNotMatching;
bool startAtLaunch = false;
vector screenRegionSwitches;
vector pauseScenesSwitches;
vector pauseWindowsSwitches;
vector ignoreWindowsSwitches;
vector sceneRoundTripSwitches;
+ vector randomSwitches;
bool autoStopEnable = false;
OBSWeakSource autoStopScene;
string waitSceneName; //indicates which scene was active when we startet waiting on something
@@ -206,6 +230,7 @@ struct SwitcherData
void checkExeSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition);
void checkScreenRegionSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition);
void checkSwitchInfoFromFile(bool& match, OBSWeakSource& scene, OBSWeakSource& transition);
+ void checkRandom(bool& match, OBSWeakSource& scene, OBSWeakSource& transition, int& delay);
@@ -220,10 +245,17 @@ struct SwitcherData
if (nonMatchingScene && !WeakSourceValid(nonMatchingScene))
{
- switchIfNotMatching = false;
+ switchIfNotMatching = NO_SWITCH;
nonMatchingScene = nullptr;
}
+ for (size_t i = 0; i < randomSwitches.size(); i++)
+ {
+ RandomSwitch& s = randomSwitches[i];
+ if (!WeakSourceValid(s.scene) || !WeakSourceValid(s.transition))
+ randomSwitches.erase(randomSwitches.begin() + i--);
+ }
+
for (size_t i = 0; i < screenRegionSwitches.size(); i++)
{
ScreenRegionSwitch& s = screenRegionSwitches[i];
diff --git a/utility.hpp b/utility.hpp
index 2fec2530..59e47f44 100644
--- a/utility.hpp
+++ b/utility.hpp
@@ -62,6 +62,13 @@ static inline QString MakeDefaultSceneTransitionName(
return scene + QStringLiteral(" --> ") + transition;
}
+static inline QString MakeRandomSwitchName(
+ const QString& scene, const QString& transition, double& delay)
+{
+ return QStringLiteral("[") + scene + QStringLiteral(", ") + transition + QStringLiteral("]: ")
+ + QString::number(delay) + QStringLiteral(" seconds");
+}
+
static inline string GetWeakSourceName(obs_weak_source_t* weak_source)
{
string name;