option to switch to random scene if no no match

added random tab:
scenes listed here can be switched to at random for a set duration if no switch condition is met (and this setting is selected on the general tab)
This commit is contained in:
WarmUpTill
2018-02-19 19:32:09 +01:00
committed by GitHub
parent dd2d70bb9c
commit c934b5c7ff
8 changed files with 444 additions and 14 deletions

View File

@@ -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}

View File

@@ -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);

View File

@@ -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();

View File

@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>981</width>
<height>405</height>
<height>428</height>
</rect>
</property>
<property name="windowTitle">
@@ -205,6 +205,13 @@
</item>
</layout>
</item>
<item>
<widget class="QRadioButton" name="noMatchRandomSwitch">
<property name="text">
<string>Switch to any Scene on Random Tab</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
@@ -1912,6 +1919,149 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="randomTab">
<attribute name="title">
<string>Random</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_8">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_42">
<property name="text">
<string>If no switch condition is met switch to </string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="randomScenes">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_43">
<property name="text">
<string>using the</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="randomTransitions"/>
</item>
<item>
<widget class="QLabel" name="label_41">
<property name="text">
<string>transition for a duration of</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="randomSpinBox">
<property name="suffix">
<string>s</string>
</property>
<property name="maximum">
<double>999999999.990000009536743</double>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_14">
<property name="text">
<string>or any of the options below:</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_36">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QListWidget" name="randomScenesList">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QPushButton" name="randomAdd">
<property name="maximumSize">
<size>
<width>22</width>
<height>22</height>
</size>
</property>
<property name="flat">
<bool>true</bool>
</property>
<property name="themeID" stdset="0">
<string notr="true">addIconSmall</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="randomRemove">
<property name="maximumSize">
<size>
<width>22</width>
<height>22</height>
</size>
</property>
<property name="flat">
<bool>true</bool>
</property>
<property name="themeID" stdset="0">
<string notr="true">removeIconSmall</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_37">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="fileTab">
<attribute name="title">
<string> Write To File / Read From File </string>

View File

@@ -32,7 +32,8 @@ void SceneSwitcher::on_noMatchDontSwitch_clicked()
return;
lock_guard<mutex> 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<mutex> 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<mutex> lock(switcher->m);
switcher->switchIfNotMatching = RANDOM_SWITCH;
ui->noMatchSwitchScene->setEnabled(false);
}
void SceneSwitcher::on_noMatchSwitchScene_currentTextChanged(const QString& text)
{
if (loading)

144
random.cpp Normal file
View File

@@ -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<mutex> 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<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);
{
lock_guard<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)
return;
string text = item->data(Qt::UserRole).toString().toUtf8().constData();
{
lock_guard<mutex> 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<RandomSwitch> 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;
}
}

View File

@@ -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<SceneSwitch> switches;
string lastTitle;
OBSWeakSource nonMatchingScene;
OBSWeakSource lastRandomScene;
int interval = DEFAULT_INTERVAL;
bool switchIfNotMatching = false;
NoMatch switchIfNotMatching;
bool startAtLaunch = false;
vector<ScreenRegionSwitch> screenRegionSwitches;
vector<OBSWeakSource> pauseScenesSwitches;
vector<string> pauseWindowsSwitches;
vector<string> ignoreWindowsSwitches;
vector<SceneRoundTripSwitch> sceneRoundTripSwitches;
vector<RandomSwitch> 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];

View File

@@ -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;