mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-09-07 00:56:00 -05:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
33667a1f23 | ||
|
|
7947ad2608 | ||
|
|
920c188213 | ||
|
|
28fbff1adc | ||
|
|
326617aad7 | ||
|
|
499ba7dd21 | ||
|
|
f4902933ab | ||
|
|
9aa0b31bff | ||
|
|
6d5086b971 | ||
|
|
f32f47db4b | ||
|
|
74c0cd1736 | ||
|
|
a74a952b1d | ||
|
|
5bbfef81e0 | ||
|
|
c31d1cd975 | ||
|
|
81d91a9139 |
1
.github/workflows/build.yml
vendored
1
.github/workflows/build.yml
vendored
@@ -161,6 +161,7 @@ jobs:
|
|||||||
pkg-config \
|
pkg-config \
|
||||||
python3-dev \
|
python3-dev \
|
||||||
qtbase5-dev \
|
qtbase5-dev \
|
||||||
|
qtbase5-private-dev \
|
||||||
libqt5svg5-dev \
|
libqt5svg5-dev \
|
||||||
swig \
|
swig \
|
||||||
libxss-dev
|
libxss-dev
|
||||||
|
|||||||
@@ -7,6 +7,13 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
|
|||||||
include(GetGitRevisionDescription)
|
include(GetGitRevisionDescription)
|
||||||
get_git_head_revision(GIT_REFSPEC GIT_SHA1)
|
get_git_head_revision(GIT_REFSPEC GIT_SHA1)
|
||||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/src/version.cpp" @ONLY)
|
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/src/version.cpp" @ONLY)
|
||||||
|
if(WIN32)
|
||||||
|
get_filename_component(ISS_PLUGIN_FILES_DIR "${CMAKE_BINARY_DIR}\\..\\package" ABSOLUTE)
|
||||||
|
file(TO_NATIVE_PATH "${ISS_PLUGIN_FILES_DIR}" ISS_PLUGIN_FILES_DIR)
|
||||||
|
get_filename_component(ISS_MSVC_REDIST_HELPER_DIR "${CMAKE_PACKAGE_PREFIX}\\.." ABSOLUTE)
|
||||||
|
file(TO_NATIVE_PATH "${ISS_MSVC_REDIST_HELPER_DIR}" ISS_MSVC_REDIST_HELPER_DIR)
|
||||||
|
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/CI/windows/setup.iss.in" "${CMAKE_CURRENT_BINARY_DIR}/CI/windows/setup.iss" @ONLY)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
get_filename_component(ISS_PLUGIN_FILES_DIR "${CMAKE_BINARY_DIR}\\..\\package" ABSOLUTE)
|
get_filename_component(ISS_PLUGIN_FILES_DIR "${CMAKE_BINARY_DIR}\\..\\package" ABSOLUTE)
|
||||||
|
|||||||
@@ -232,7 +232,10 @@ AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopStreaming="Streamen stop
|
|||||||
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startStreaming="Streamen starten"
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startStreaming="Streamen starten"
|
||||||
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startReplayBuffer="Replay Buffer starten"
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startReplayBuffer="Replay Buffer starten"
|
||||||
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopReplayBuffer="Replay Buffer stoppen"
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopReplayBuffer="Replay Buffer stoppen"
|
||||||
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.muteSource="Quelle stumm schalten"
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.muteSource="Audio Quelle stumm schalten"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.unmuteSource="Audio Quelle aktiv schalten"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startSwitcher="Szenenwechsler starten"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopSwitcher="Szenenwechsler stoppen"
|
||||||
AdvSceneSwitcher.sceneTriggerTab.entry="Wenn {{scenes}} {{triggers}} {{actions}} {{audioSources}} nach {{duration}} "
|
AdvSceneSwitcher.sceneTriggerTab.entry="Wenn {{scenes}} {{triggers}} {{actions}} {{audioSources}} nach {{duration}} "
|
||||||
AdvSceneSwitcher.sceneTriggerTab.help="Dieser Tab ermöglicht es automatisiert Handlungen, wie etwa das Stoppen von einer Aufnahme oder des Streamens, bei einem Szenenwechsel auszuführen."
|
AdvSceneSwitcher.sceneTriggerTab.help="Dieser Tab ermöglicht es automatisiert Handlungen, wie etwa das Stoppen von einer Aufnahme oder des Streamens, bei einem Szenenwechsel auszuführen."
|
||||||
|
|
||||||
@@ -249,6 +252,7 @@ AdvSceneSwitcher.browse="Öffnen"
|
|||||||
|
|
||||||
AdvSceneSwitcher.selectScene="--Szene auswählen--"
|
AdvSceneSwitcher.selectScene="--Szene auswählen--"
|
||||||
AdvSceneSwitcher.selectPreviousScene="Vorhergehende Szene"
|
AdvSceneSwitcher.selectPreviousScene="Vorhergehende Szene"
|
||||||
|
AdvSceneSwitcher.currentTransition="Aktueller Szenenübergang"
|
||||||
AdvSceneSwitcher.selectTransition="--Szenenübergang auswählen--"
|
AdvSceneSwitcher.selectTransition="--Szenenübergang auswählen--"
|
||||||
AdvSceneSwitcher.selectWindow="--Fenster auswählen--"
|
AdvSceneSwitcher.selectWindow="--Fenster auswählen--"
|
||||||
AdvSceneSwitcher.selectAudioSource="--Audio Quelle auswählen--"
|
AdvSceneSwitcher.selectAudioSource="--Audio Quelle auswählen--"
|
||||||
|
|||||||
@@ -186,6 +186,8 @@ AdvSceneSwitcher.sceneSequenceTab.fileType="Text files (*.txt)"
|
|||||||
AdvSceneSwitcher.sceneSequenceTab.interruptible="interruptible"
|
AdvSceneSwitcher.sceneSequenceTab.interruptible="interruptible"
|
||||||
AdvSceneSwitcher.sceneSequenceTab.interruptibleHint="Other switching methods are allowed to interrupt this scene sequence"
|
AdvSceneSwitcher.sceneSequenceTab.interruptibleHint="Other switching methods are allowed to interrupt this scene sequence"
|
||||||
AdvSceneSwitcher.sceneSequenceTab.entry="When {{startScenes}} is active switch to {{scenes}} after {{delay}} {{delayUnits}} using {{transitions}} {{interruptible}}"
|
AdvSceneSwitcher.sceneSequenceTab.entry="When {{startScenes}} is active switch to {{scenes}} after {{delay}} {{delayUnits}} using {{transitions}} {{interruptible}}"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.extendEdit="Extend Sequence"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.extendEntry="After {{delay}} {{delayUnits}} switch to {{scenes}} using {{transitions}}"
|
||||||
AdvSceneSwitcher.sceneSequenceTab.help="This tab will allow you to automatically switch to a different scene if a scene was active for a configured period of time.\nFor example, you could automatically cycle back and forth between two scenes automatically.\n\nClick on the highlighted plus symbol to continue."
|
AdvSceneSwitcher.sceneSequenceTab.help="This tab will allow you to automatically switch to a different scene if a scene was active for a configured period of time.\nFor example, you could automatically cycle back and forth between two scenes automatically.\n\nClick on the highlighted plus symbol to continue."
|
||||||
|
|
||||||
; Audio Tab
|
; Audio Tab
|
||||||
@@ -233,6 +235,9 @@ AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startStreaming="start stream
|
|||||||
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startReplayBuffer="start replay buffer"
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startReplayBuffer="start replay buffer"
|
||||||
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopReplayBuffer="stop replay buffer"
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopReplayBuffer="stop replay buffer"
|
||||||
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.muteSource="mute source"
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.muteSource="mute source"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.unmuteSource="unmute source"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startSwitcher="start the scene switcher"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopSwitcher="stop the scene switcher"
|
||||||
AdvSceneSwitcher.sceneTriggerTab.entry="When {{scenes}} {{triggers}} {{actions}} {{audioSources}} after {{duration}}"
|
AdvSceneSwitcher.sceneTriggerTab.entry="When {{scenes}} {{triggers}} {{actions}} {{audioSources}} after {{duration}}"
|
||||||
AdvSceneSwitcher.sceneTriggerTab.help="This tab allows you to trigger actions on scene changes, like stopping recording or streaming."
|
AdvSceneSwitcher.sceneTriggerTab.help="This tab allows you to trigger actions on scene changes, like stopping recording or streaming."
|
||||||
|
|
||||||
@@ -248,6 +253,7 @@ AdvSceneSwitcher.browse="Browse"
|
|||||||
|
|
||||||
AdvSceneSwitcher.selectScene="--select scene--"
|
AdvSceneSwitcher.selectScene="--select scene--"
|
||||||
AdvSceneSwitcher.selectPreviousScene="Previous Scene"
|
AdvSceneSwitcher.selectPreviousScene="Previous Scene"
|
||||||
|
AdvSceneSwitcher.currentTransition="Current Transition"
|
||||||
AdvSceneSwitcher.selectTransition="--select transition--"
|
AdvSceneSwitcher.selectTransition="--select transition--"
|
||||||
AdvSceneSwitcher.selectWindow="--select window--"
|
AdvSceneSwitcher.selectWindow="--select window--"
|
||||||
AdvSceneSwitcher.selectAudioSource="--select audio source--"
|
AdvSceneSwitcher.selectAudioSource="--select audio source--"
|
||||||
|
|||||||
@@ -2824,6 +2824,20 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="sequenceEdit">
|
||||||
|
<property name="text">
|
||||||
|
<string>AdvSceneSwitcher.sceneSequenceTab.extendEdit</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer_8">
|
<spacer name="horizontalSpacer_8">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
|
|||||||
@@ -92,8 +92,9 @@ bool AdvSceneSwitcher::DisplayMessage(QString msg, bool question)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addSelectionEntry(QComboBox *sel, const char *description,
|
void AdvSceneSwitcher::addSelectionEntry(QComboBox *sel,
|
||||||
const char *tooltip = "")
|
const char *description,
|
||||||
|
bool selectable, const char *tooltip)
|
||||||
{
|
{
|
||||||
sel->addItem(description);
|
sel->addItem(description);
|
||||||
|
|
||||||
@@ -106,14 +107,17 @@ void addSelectionEntry(QComboBox *sel, const char *description,
|
|||||||
QModelIndex firstIndex =
|
QModelIndex firstIndex =
|
||||||
model->index(0, sel->modelColumn(), sel->rootModelIndex());
|
model->index(0, sel->modelColumn(), sel->rootModelIndex());
|
||||||
QStandardItem *firstItem = model->itemFromIndex(firstIndex);
|
QStandardItem *firstItem = model->itemFromIndex(firstIndex);
|
||||||
firstItem->setSelectable(false);
|
if (!selectable) {
|
||||||
firstItem->setEnabled(false);
|
firstItem->setSelectable(false);
|
||||||
|
firstItem->setEnabled(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::populateSceneSelection(QComboBox *sel, bool addPrevious,
|
void AdvSceneSwitcher::populateSceneSelection(QComboBox *sel, bool addPrevious,
|
||||||
bool addSceneGroup,
|
bool addSceneGroup,
|
||||||
bool addSelect,
|
bool addSelect,
|
||||||
std::string selectText)
|
std::string selectText,
|
||||||
|
bool selectable)
|
||||||
{
|
{
|
||||||
sel->clear();
|
sel->clear();
|
||||||
|
|
||||||
@@ -122,10 +126,11 @@ void AdvSceneSwitcher::populateSceneSelection(QComboBox *sel, bool addPrevious,
|
|||||||
addSelectionEntry(
|
addSelectionEntry(
|
||||||
sel,
|
sel,
|
||||||
obs_module_text("AdvSceneSwitcher.selectScene"),
|
obs_module_text("AdvSceneSwitcher.selectScene"),
|
||||||
|
selectable,
|
||||||
obs_module_text(
|
obs_module_text(
|
||||||
"AdvSceneSwitcher.invaildEntriesWillNotBeSaved"));
|
"AdvSceneSwitcher.invaildEntriesWillNotBeSaved"));
|
||||||
} else {
|
} else {
|
||||||
addSelectionEntry(sel, selectText.c_str());
|
addSelectionEntry(sel, selectText.c_str(), selectable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,12 +155,20 @@ void AdvSceneSwitcher::populateSceneSelection(QComboBox *sel, bool addPrevious,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::populateTransitionSelection(QComboBox *sel,
|
void AdvSceneSwitcher::populateTransitionSelection(QComboBox *sel,
|
||||||
bool addSelect)
|
bool addCurrent,
|
||||||
|
bool addSelect,
|
||||||
|
bool selectable)
|
||||||
{
|
{
|
||||||
if (addSelect) {
|
if (addSelect) {
|
||||||
addSelectionEntry(
|
addSelectionEntry(
|
||||||
sel,
|
sel,
|
||||||
obs_module_text("AdvSceneSwitcher.selectTransition"));
|
obs_module_text("AdvSceneSwitcher.selectTransition"),
|
||||||
|
selectable);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addCurrent) {
|
||||||
|
sel->addItem(
|
||||||
|
obs_module_text("AdvSceneSwitcher.currentTransition"));
|
||||||
}
|
}
|
||||||
|
|
||||||
obs_frontend_source_list *transitions = new obs_frontend_source_list();
|
obs_frontend_source_list *transitions = new obs_frontend_source_list();
|
||||||
@@ -197,6 +210,7 @@ void AdvSceneSwitcher::populateAudioSelection(QComboBox *sel, bool addSelect)
|
|||||||
addSelectionEntry(
|
addSelectionEntry(
|
||||||
sel,
|
sel,
|
||||||
obs_module_text("AdvSceneSwitcher.selectAudioSource"),
|
obs_module_text("AdvSceneSwitcher.selectAudioSource"),
|
||||||
|
false,
|
||||||
obs_module_text(
|
obs_module_text(
|
||||||
"AdvSceneSwitcher.invaildEntriesWillNotBeSaved"));
|
"AdvSceneSwitcher.invaildEntriesWillNotBeSaved"));
|
||||||
}
|
}
|
||||||
@@ -227,6 +241,7 @@ void AdvSceneSwitcher::populateMediaSelection(QComboBox *sel, bool addSelect)
|
|||||||
addSelectionEntry(
|
addSelectionEntry(
|
||||||
sel,
|
sel,
|
||||||
obs_module_text("AdvSceneSwitcher.selectMediaSource"),
|
obs_module_text("AdvSceneSwitcher.selectMediaSource"),
|
||||||
|
false,
|
||||||
obs_module_text(
|
obs_module_text(
|
||||||
"AdvSceneSwitcher.invaildEntriesWillNotBeSaved"));
|
"AdvSceneSwitcher.invaildEntriesWillNotBeSaved"));
|
||||||
}
|
}
|
||||||
@@ -428,9 +443,6 @@ void SwitcherData::Thread()
|
|||||||
OBSWeakSource scene;
|
OBSWeakSource scene;
|
||||||
OBSWeakSource transition;
|
OBSWeakSource transition;
|
||||||
|
|
||||||
bool defTransitionMatch = false;
|
|
||||||
OBSWeakSource defTransition;
|
|
||||||
|
|
||||||
endTime = std::chrono::high_resolution_clock::now();
|
endTime = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
auto runTime =
|
auto runTime =
|
||||||
@@ -449,7 +461,7 @@ void SwitcherData::Thread()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vblog(LOG_INFO, "sleep for %ld", duration.count());
|
vblog(LOG_INFO, "try to sleep for %ld", duration.count());
|
||||||
cv.wait_for(lock, duration);
|
cv.wait_for(lock, duration);
|
||||||
|
|
||||||
startTime = std::chrono::high_resolution_clock::now();
|
startTime = std::chrono::high_resolution_clock::now();
|
||||||
@@ -457,63 +469,17 @@ void SwitcherData::Thread()
|
|||||||
linger = 0;
|
linger = 0;
|
||||||
|
|
||||||
switcher->Prune();
|
switcher->Prune();
|
||||||
|
|
||||||
if (switcher->stop) {
|
if (switcher->stop) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checkPause()) {
|
if (checkPause()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
match = checkForMatch(scene, transition, linger);
|
||||||
checkDefaultSceneTransitions(defTransitionMatch, defTransition);
|
if (switcher->stop) {
|
||||||
|
break;
|
||||||
for (int switchFuncName : functionNamesByPriority) {
|
|
||||||
switch (switchFuncName) {
|
|
||||||
case read_file_func:
|
|
||||||
checkSwitchInfoFromFile(match, scene,
|
|
||||||
transition);
|
|
||||||
checkFileContent(match, scene, transition);
|
|
||||||
break;
|
|
||||||
case idle_func:
|
|
||||||
checkIdleSwitch(match, scene, transition);
|
|
||||||
break;
|
|
||||||
case exe_func:
|
|
||||||
checkExeSwitch(match, scene, transition);
|
|
||||||
break;
|
|
||||||
case screen_region_func:
|
|
||||||
checkScreenRegionSwitch(match, scene,
|
|
||||||
transition);
|
|
||||||
break;
|
|
||||||
case window_title_func:
|
|
||||||
checkWindowTitleSwitch(match, scene,
|
|
||||||
transition);
|
|
||||||
break;
|
|
||||||
case round_trip_func:
|
|
||||||
checkSceneSequence(match, scene, transition,
|
|
||||||
linger);
|
|
||||||
break;
|
|
||||||
case media_func:
|
|
||||||
checkMediaSwitch(match, scene, transition);
|
|
||||||
break;
|
|
||||||
case time_func:
|
|
||||||
checkTimeSwitch(match, scene, transition);
|
|
||||||
break;
|
|
||||||
case audio_func:
|
|
||||||
checkAudioSwitch(match, scene, transition);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (switcher->stop) {
|
|
||||||
goto endLoop;
|
|
||||||
}
|
|
||||||
if (match) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
checkNoMatchSwitch(match, scene, transition, sleep);
|
checkNoMatchSwitch(match, scene, transition, sleep);
|
||||||
|
|
||||||
checkSwitchCooldown(match);
|
checkSwitchCooldown(match);
|
||||||
|
|
||||||
if (linger) {
|
if (linger) {
|
||||||
@@ -544,10 +510,6 @@ void SwitcherData::Thread()
|
|||||||
// leading to a deadlock, so we have to unlock()
|
// leading to a deadlock, so we have to unlock()
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
|
||||||
if (!match && defTransitionMatch) {
|
|
||||||
setCurrentDefTransition(defTransition);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (match) {
|
if (match) {
|
||||||
switchScene(scene, transition,
|
switchScene(scene, transition,
|
||||||
tansitionOverrideOverride);
|
tansitionOverrideOverride);
|
||||||
@@ -555,10 +517,64 @@ void SwitcherData::Thread()
|
|||||||
|
|
||||||
writeSceneInfoToFile();
|
writeSceneInfoToFile();
|
||||||
}
|
}
|
||||||
endLoop:
|
|
||||||
blog(LOG_INFO, "stopped");
|
blog(LOG_INFO, "stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SwitcherData::checkForMatch(OBSWeakSource &scene,
|
||||||
|
OBSWeakSource &transition, int &linger)
|
||||||
|
{
|
||||||
|
bool match = false;
|
||||||
|
|
||||||
|
if (uninterruptibleSceneSequenceActive) {
|
||||||
|
checkSceneSequence(match, scene, transition, linger);
|
||||||
|
if (match) {
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int switchFuncName : functionNamesByPriority) {
|
||||||
|
switch (switchFuncName) {
|
||||||
|
case read_file_func:
|
||||||
|
checkSwitchInfoFromFile(match, scene, transition);
|
||||||
|
checkFileContent(match, scene, transition);
|
||||||
|
break;
|
||||||
|
case idle_func:
|
||||||
|
checkIdleSwitch(match, scene, transition);
|
||||||
|
break;
|
||||||
|
case exe_func:
|
||||||
|
checkExeSwitch(match, scene, transition);
|
||||||
|
break;
|
||||||
|
case screen_region_func:
|
||||||
|
checkScreenRegionSwitch(match, scene, transition);
|
||||||
|
break;
|
||||||
|
case window_title_func:
|
||||||
|
checkWindowTitleSwitch(match, scene, transition);
|
||||||
|
break;
|
||||||
|
case round_trip_func:
|
||||||
|
checkSceneSequence(match, scene, transition, linger);
|
||||||
|
break;
|
||||||
|
case media_func:
|
||||||
|
checkMediaSwitch(match, scene, transition);
|
||||||
|
break;
|
||||||
|
case time_func:
|
||||||
|
checkTimeSwitch(match, scene, transition);
|
||||||
|
break;
|
||||||
|
case audio_func:
|
||||||
|
checkAudioSwitch(match, scene, transition);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (switcher->stop) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (match) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
void switchScene(OBSWeakSource &scene, OBSWeakSource &transition,
|
void switchScene(OBSWeakSource &scene, OBSWeakSource &transition,
|
||||||
bool &transitionOverrideOverride)
|
bool &transitionOverrideOverride)
|
||||||
{
|
{
|
||||||
@@ -643,7 +659,7 @@ extern "C" void FreeSceneSwitcher()
|
|||||||
|
|
||||||
void handleSceneChange(SwitcherData *s)
|
void handleSceneChange(SwitcherData *s)
|
||||||
{
|
{
|
||||||
// Stop waiting if scene was manually changed
|
// Stop waiting if scene was changed
|
||||||
if (s->sceneChangedDuringWait()) {
|
if (s->sceneChangedDuringWait()) {
|
||||||
s->cv.notify_one();
|
s->cv.notify_one();
|
||||||
}
|
}
|
||||||
@@ -658,12 +674,8 @@ void handleSceneChange(SwitcherData *s)
|
|||||||
s->previousSceneHelper = ws;
|
s->previousSceneHelper = ws;
|
||||||
}
|
}
|
||||||
|
|
||||||
switcher->checkTriggers();
|
s->checkTriggers();
|
||||||
}
|
s->checkDefaultSceneTransitions();
|
||||||
|
|
||||||
void handleTransitionStop(SwitcherData *s)
|
|
||||||
{
|
|
||||||
s->checkedDefTransition = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setLiveTime(SwitcherData *s)
|
void setLiveTime(SwitcherData *s)
|
||||||
@@ -702,9 +714,6 @@ static void OBSEvent(enum obs_frontend_event event, void *switcher)
|
|||||||
case OBS_FRONTEND_EVENT_SCENE_CHANGED:
|
case OBS_FRONTEND_EVENT_SCENE_CHANGED:
|
||||||
handleSceneChange((SwitcherData *)switcher);
|
handleSceneChange((SwitcherData *)switcher);
|
||||||
break;
|
break;
|
||||||
case OBS_FRONTEND_EVENT_TRANSITION_STOPPED:
|
|
||||||
handleTransitionStop((SwitcherData *)switcher);
|
|
||||||
break;
|
|
||||||
case OBS_FRONTEND_EVENT_RECORDING_STARTED:
|
case OBS_FRONTEND_EVENT_RECORDING_STARTED:
|
||||||
setLiveTime((SwitcherData *)switcher);
|
setLiveTime((SwitcherData *)switcher);
|
||||||
checkAutoStartRecording((SwitcherData *)switcher);
|
checkAutoStartRecording((SwitcherData *)switcher);
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ void AdvSceneSwitcher::SetStarted()
|
|||||||
ui->pluginRunningText->setText(
|
ui->pluginRunningText->setText(
|
||||||
obs_module_text("AdvSceneSwitcher.status.active"));
|
obs_module_text("AdvSceneSwitcher.status.active"));
|
||||||
ui->pluginRunningText->disconnect(inactivePluse);
|
ui->pluginRunningText->disconnect(inactivePluse);
|
||||||
|
currentStatusActive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::SetStopped()
|
void AdvSceneSwitcher::SetStopped()
|
||||||
@@ -139,6 +140,7 @@ void AdvSceneSwitcher::SetStopped()
|
|||||||
obs_module_text("AdvSceneSwitcher.status.inactive"));
|
obs_module_text("AdvSceneSwitcher.status.inactive"));
|
||||||
inactivePluse = PulseWidget(ui->pluginRunningText, QColor(Qt::red),
|
inactivePluse = PulseWidget(ui->pluginRunningText, QColor(Qt::red),
|
||||||
QColor(0, 0, 0, 0), "QLabel ");
|
QColor(0, 0, 0, 0), "QLabel ");
|
||||||
|
currentStatusActive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_toggleStartButton_clicked()
|
void AdvSceneSwitcher::on_toggleStartButton_clicked()
|
||||||
@@ -681,6 +683,21 @@ void populateAutoStartEventSelection(QComboBox *cb)
|
|||||||
"AdvSceneSwitcher.generalTab.status.autoStart.recordingAndStreaming"));
|
"AdvSceneSwitcher.generalTab.status.autoStart.recordingAndStreaming"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::updateStatus()
|
||||||
|
{
|
||||||
|
if (switcher->th && switcher->th->isRunning()) {
|
||||||
|
if (currentStatusActive) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SetStarted();
|
||||||
|
} else {
|
||||||
|
if (!currentStatusActive) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SetStopped();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::setupGeneralTab()
|
void AdvSceneSwitcher::setupGeneralTab()
|
||||||
{
|
{
|
||||||
populateSceneSelection(ui->noMatchSwitchScene, false);
|
populateSceneSelection(ui->noMatchSwitchScene, false);
|
||||||
@@ -780,4 +797,10 @@ void AdvSceneSwitcher::setupGeneralTab()
|
|||||||
} else {
|
} else {
|
||||||
SetStopped();
|
SetStopped();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Updates the UI status element if the status changed externally
|
||||||
|
// (e.g. via hotkeys)
|
||||||
|
QTimer *statusTimer = new QTimer(this);
|
||||||
|
connect(statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus()));
|
||||||
|
statusTimer->start(1000);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,9 @@
|
|||||||
#include "switcher-data-structs.hpp"
|
#include "switcher-data-structs.hpp"
|
||||||
|
|
||||||
#define blog(level, msg, ...) blog(level, "[adv-ss] " msg, ##__VA_ARGS__)
|
#define blog(level, msg, ...) blog(level, "[adv-ss] " msg, ##__VA_ARGS__)
|
||||||
#define vblog(level, msg, ...) \
|
#define vblog(level, msg, ...) \
|
||||||
if (verbose) { \
|
if (verbose) { \
|
||||||
blog(level, "[adv-ss] " msg, ##__VA_ARGS__); \
|
blog(level, msg, ##__VA_ARGS__); \
|
||||||
}
|
}
|
||||||
|
|
||||||
class QCloseEvent;
|
class QCloseEvent;
|
||||||
@@ -23,6 +23,7 @@ class AdvSceneSwitcher : public QDialog {
|
|||||||
public:
|
public:
|
||||||
std::unique_ptr<Ui_AdvSceneSwitcher> ui;
|
std::unique_ptr<Ui_AdvSceneSwitcher> ui;
|
||||||
bool loading = true;
|
bool loading = true;
|
||||||
|
bool currentStatusActive = false;
|
||||||
|
|
||||||
AdvSceneSwitcher(QWidget *parent);
|
AdvSceneSwitcher(QWidget *parent);
|
||||||
|
|
||||||
@@ -39,6 +40,7 @@ public:
|
|||||||
int IgnoreIdleWindowsFindByData(const QString &window);
|
int IgnoreIdleWindowsFindByData(const QString &window);
|
||||||
|
|
||||||
void UpdateNonMatchingScene(const QString &name);
|
void UpdateNonMatchingScene(const QString &name);
|
||||||
|
void OpenSequenceExtendEdit(SequenceWidget *sw);
|
||||||
void SetEditSceneGroup(SceneGroup &sg);
|
void SetEditSceneGroup(SceneGroup &sg);
|
||||||
|
|
||||||
void loadUI();
|
void loadUI();
|
||||||
@@ -62,14 +64,20 @@ public:
|
|||||||
static bool DisplayMessage(QString msg, bool question = false);
|
static bool DisplayMessage(QString msg, bool question = false);
|
||||||
static void AskBackup(obs_data_t *obj);
|
static void AskBackup(obs_data_t *obj);
|
||||||
|
|
||||||
|
static void addSelectionEntry(QComboBox *sel, const char *description,
|
||||||
|
bool selectable = false,
|
||||||
|
const char *tooltip = "");
|
||||||
static void populateSceneSelection(QComboBox *sel,
|
static void populateSceneSelection(QComboBox *sel,
|
||||||
bool addPrevious = false,
|
bool addPrevious = false,
|
||||||
bool addSceneGroup = false,
|
bool addSceneGroup = false,
|
||||||
bool addSelect = true,
|
bool addSelect = true,
|
||||||
std::string selectText = "");
|
std::string selectText = "",
|
||||||
|
bool selectable = false);
|
||||||
|
|
||||||
static void populateTransitionSelection(QComboBox *sel,
|
static void populateTransitionSelection(QComboBox *sel,
|
||||||
bool addSelect = true);
|
bool addCurrent = true,
|
||||||
|
bool addSelect = true,
|
||||||
|
bool selectable = false);
|
||||||
static void populateWindowSelection(QComboBox *sel,
|
static void populateWindowSelection(QComboBox *sel,
|
||||||
bool addSelect = true);
|
bool addSelect = true);
|
||||||
static void populateAudioSelection(QComboBox *sel,
|
static void populateAudioSelection(QComboBox *sel,
|
||||||
@@ -129,10 +137,12 @@ public slots:
|
|||||||
|
|
||||||
void on_sceneSequenceAdd_clicked();
|
void on_sceneSequenceAdd_clicked();
|
||||||
void on_sceneSequenceRemove_clicked();
|
void on_sceneSequenceRemove_clicked();
|
||||||
void on_sceneSequenceSave_clicked();
|
|
||||||
void on_sceneSequenceLoad_clicked();
|
|
||||||
void on_sceneSequenceUp_clicked();
|
void on_sceneSequenceUp_clicked();
|
||||||
void on_sceneSequenceDown_clicked();
|
void on_sceneSequenceDown_clicked();
|
||||||
|
void on_sceneSequenceSave_clicked();
|
||||||
|
void on_sceneSequenceLoad_clicked();
|
||||||
|
void on_sequenceEdit_clicked();
|
||||||
|
void on_sceneSequenceSwitches_itemDoubleClicked(QListWidgetItem *item);
|
||||||
|
|
||||||
void on_verboseLogging_stateChanged(int state);
|
void on_verboseLogging_stateChanged(int state);
|
||||||
void on_uiHintsDisable_stateChanged(int state);
|
void on_uiHintsDisable_stateChanged(int state);
|
||||||
@@ -213,6 +223,7 @@ public slots:
|
|||||||
void on_threadPriority_currentTextChanged(const QString &text);
|
void on_threadPriority_currentTextChanged(const QString &text);
|
||||||
|
|
||||||
void updateScreenRegionCursorPos();
|
void updateScreenRegionCursorPos();
|
||||||
|
void updateStatus();
|
||||||
|
|
||||||
void on_close_clicked();
|
void on_close_clicked();
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ struct SceneGroup {
|
|||||||
|
|
||||||
int currentCount = -1;
|
int currentCount = -1;
|
||||||
std::chrono::high_resolution_clock::time_point lastAdvTime;
|
std::chrono::high_resolution_clock::time_point lastAdvTime;
|
||||||
OBSWeakSource lastRandomScene = nullptr;
|
int lastRandomScene = -1;
|
||||||
|
|
||||||
inline SceneGroup(){};
|
inline SceneGroup(){};
|
||||||
inline SceneGroup(std::string name_) : name(name_){};
|
inline SceneGroup(std::string name_) : name(name_){};
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ enum class sceneTriggerAction {
|
|||||||
STOP_REPLAY_BUFFER,
|
STOP_REPLAY_BUFFER,
|
||||||
|
|
||||||
MUTE_SOURCE,
|
MUTE_SOURCE,
|
||||||
|
UNMUTE_SOURCE,
|
||||||
|
|
||||||
|
START_SWITCHER,
|
||||||
|
STOP_SWITCHER,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SceneTrigger : SceneSwitcherEntry {
|
struct SceneTrigger : SceneSwitcherEntry {
|
||||||
@@ -36,7 +40,8 @@ struct SceneTrigger : SceneSwitcherEntry {
|
|||||||
void save(obs_data_t *obj);
|
void save(obs_data_t *obj);
|
||||||
void load(obs_data_t *obj);
|
void load(obs_data_t *obj);
|
||||||
|
|
||||||
bool checkMatch(OBSWeakSource previousScene);
|
bool checkMatch(OBSWeakSource currentScene,
|
||||||
|
OBSWeakSource previousScene);
|
||||||
void performAction();
|
void performAction();
|
||||||
void logMatch();
|
void logMatch();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ struct SceneSwitcherEntry {
|
|||||||
OBSWeakSource scene = nullptr;
|
OBSWeakSource scene = nullptr;
|
||||||
OBSWeakSource transition = nullptr;
|
OBSWeakSource transition = nullptr;
|
||||||
bool usePreviousScene = false;
|
bool usePreviousScene = false;
|
||||||
|
bool useCurrentTransition = false;
|
||||||
|
|
||||||
virtual const char *getType() = 0;
|
virtual const char *getType() = 0;
|
||||||
virtual bool initialized();
|
virtual bool initialized();
|
||||||
@@ -64,14 +65,15 @@ class SwitchWidget : public QWidget {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
SwitchWidget(QWidget *parent, SceneSwitcherEntry *s,
|
SwitchWidget(QWidget *parent, SceneSwitcherEntry *s,
|
||||||
bool usePreviousScene = true, bool addSceneGroup = false);
|
bool usePreviousScene = true, bool addSceneGroup = false,
|
||||||
|
bool addCurrentTransition = true);
|
||||||
virtual SceneSwitcherEntry *getSwitchData();
|
virtual SceneSwitcherEntry *getSwitchData();
|
||||||
virtual void setSwitchData(SceneSwitcherEntry *s);
|
virtual void setSwitchData(SceneSwitcherEntry *s);
|
||||||
void showSwitchData();
|
void showSwitchData();
|
||||||
|
|
||||||
static void swapSwitchData(SwitchWidget *s1, SwitchWidget *s2);
|
static void swapSwitchData(SwitchWidget *s1, SwitchWidget *s2);
|
||||||
|
|
||||||
private slots:
|
protected slots:
|
||||||
void SceneChanged(const QString &text);
|
void SceneChanged(const QString &text);
|
||||||
void TransitionChanged(const QString &text);
|
void TransitionChanged(const QString &text);
|
||||||
void SceneGroupAdd(const QString &name);
|
void SceneGroupAdd(const QString &name);
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
#include "switch-generic.hpp"
|
#include "switch-generic.hpp"
|
||||||
|
|
||||||
constexpr auto round_trip_func = 1;
|
constexpr auto round_trip_func = 1;
|
||||||
@@ -12,42 +14,77 @@ typedef enum {
|
|||||||
|
|
||||||
struct SceneSequenceSwitch : SceneSwitcherEntry {
|
struct SceneSequenceSwitch : SceneSwitcherEntry {
|
||||||
static bool pause;
|
static bool pause;
|
||||||
|
SwitchTargetType startTargetType = SwitchTargetType::Scene;
|
||||||
OBSWeakSource startScene = nullptr;
|
OBSWeakSource startScene = nullptr;
|
||||||
double delay = 0;
|
double delay = 0;
|
||||||
int delayMultiplier = 1;
|
int delayMultiplier = 1;
|
||||||
bool interruptible = false;
|
bool interruptible = false;
|
||||||
unsigned int matchCount = 0;
|
unsigned int matchCount = 0;
|
||||||
|
|
||||||
|
// nullptr marks start point and reaching end of extended sequence
|
||||||
|
SceneSequenceSwitch *activeSequence = nullptr;
|
||||||
|
|
||||||
|
std::unique_ptr<SceneSequenceSwitch> extendedSequence = nullptr;
|
||||||
|
|
||||||
const char *getType() { return "sequence"; }
|
const char *getType() { return "sequence"; }
|
||||||
bool initialized();
|
bool initialized();
|
||||||
bool valid();
|
bool valid();
|
||||||
void save(obs_data_t *obj);
|
void save(obs_data_t *obj, bool saveExt = true);
|
||||||
void load(obs_data_t *obj);
|
void load(obs_data_t *obj, bool saveExt = true);
|
||||||
|
|
||||||
|
bool reduce();
|
||||||
|
SceneSequenceSwitch *extend();
|
||||||
|
|
||||||
|
bool checkMatch(OBSWeakSource currentScene, int &linger,
|
||||||
|
SceneSequenceSwitch *root = nullptr);
|
||||||
|
bool checkDurationMatchInterruptible();
|
||||||
|
void prepareUninterruptibleMatch(OBSWeakSource currentScene,
|
||||||
|
int &linger);
|
||||||
|
void advanceActiveSequence();
|
||||||
|
void logAdvanceSequence();
|
||||||
|
void logSequenceCanceled();
|
||||||
};
|
};
|
||||||
|
|
||||||
class SequenceWidget : public SwitchWidget {
|
class SequenceWidget : public SwitchWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SequenceWidget(QWidget *parent, SceneSequenceSwitch *s);
|
SequenceWidget(QWidget *parent, SceneSequenceSwitch *s,
|
||||||
|
bool extendSequence = false,
|
||||||
|
bool editExtendMode = false);
|
||||||
SceneSequenceSwitch *getSwitchData();
|
SceneSequenceSwitch *getSwitchData();
|
||||||
void setSwitchData(SceneSequenceSwitch *s);
|
void setSwitchData(SceneSequenceSwitch *s);
|
||||||
|
|
||||||
static void swapSwitchData(SequenceWidget *s1, SequenceWidget *s2);
|
static void swapSwitchData(SequenceWidget *s1, SequenceWidget *s2);
|
||||||
|
|
||||||
void UpdateDelay();
|
void UpdateDelay();
|
||||||
|
void UpdateExtendText();
|
||||||
|
void setExtendedSequenceStartScene();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
void SceneChanged(const QString &text);
|
||||||
void DelayChanged(double delay);
|
void DelayChanged(double delay);
|
||||||
void DelayUnitsChanged(int idx);
|
void DelayUnitsChanged(int idx);
|
||||||
void StartSceneChanged(const QString &text);
|
void StartSceneChanged(const QString &text);
|
||||||
void InterruptibleChanged(int state);
|
void InterruptibleChanged(int state);
|
||||||
|
void ExtendClicked();
|
||||||
|
void ReduceClicked();
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
QDoubleSpinBox *delay;
|
QDoubleSpinBox *delay;
|
||||||
QComboBox *delayUnits;
|
QComboBox *delayUnits;
|
||||||
QComboBox *startScenes;
|
QComboBox *startScenes;
|
||||||
QCheckBox *interruptible;
|
QCheckBox *interruptible;
|
||||||
|
QVBoxLayout *extendSequenceLayout;
|
||||||
|
QPushButton *extend;
|
||||||
|
QPushButton *reduce;
|
||||||
|
|
||||||
|
// I would prefer having a list of only widgets of type editExtendMode
|
||||||
|
// but I am not sure how to best implement that using a QListWidget.
|
||||||
|
//
|
||||||
|
// So use edit button to bring up edit widget and
|
||||||
|
// add a label to disaplay current extended sequence state.
|
||||||
|
QLabel *extendText;
|
||||||
|
|
||||||
SceneSequenceSwitch *switchData;
|
SceneSequenceSwitch *switchData;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ struct DefaultSceneTransition : SceneSwitcherEntry {
|
|||||||
static bool pause;
|
static bool pause;
|
||||||
|
|
||||||
const char *getType() { return "def_transition"; }
|
const char *getType() { return "def_transition"; }
|
||||||
|
bool checkMatch(OBSWeakSource currentScene);
|
||||||
|
void setTransition();
|
||||||
|
|
||||||
inline DefaultSceneTransition(){};
|
inline DefaultSceneTransition(){};
|
||||||
inline DefaultSceneTransition(OBSWeakSource scene_,
|
inline DefaultSceneTransition(OBSWeakSource scene_,
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
constexpr auto default_interval = 300;
|
constexpr auto default_interval = 300;
|
||||||
constexpr auto previous_scene_name = "Previous Scene";
|
constexpr auto previous_scene_name = "Previous Scene";
|
||||||
|
constexpr auto current_transition_name = "Current Transition";
|
||||||
|
|
||||||
typedef enum { NO_SWITCH = 0, SWITCH = 1, RANDOM_SWITCH = 2 } NoMatch;
|
typedef enum { NO_SWITCH = 0, SWITCH = 1, RANDOM_SWITCH = 2 } NoMatch;
|
||||||
typedef enum { PERSIST = 0, START = 1, STOP = 2 } StartupBehavior;
|
typedef enum { PERSIST = 0, START = 1, STOP = 2 } StartupBehavior;
|
||||||
@@ -84,6 +85,7 @@ struct SwitcherData {
|
|||||||
|
|
||||||
std::vector<std::string> ignoreWindowsSwitches;
|
std::vector<std::string> ignoreWindowsSwitches;
|
||||||
|
|
||||||
|
bool uninterruptibleSceneSequenceActive = false;
|
||||||
std::deque<SceneSequenceSwitch> sceneSequenceSwitches;
|
std::deque<SceneSequenceSwitch> sceneSequenceSwitches;
|
||||||
|
|
||||||
std::deque<RandomSwitch> randomSwitches;
|
std::deque<RandomSwitch> randomSwitches;
|
||||||
@@ -100,7 +102,6 @@ struct SwitcherData {
|
|||||||
|
|
||||||
std::deque<SceneTransition> sceneTransitions;
|
std::deque<SceneTransition> sceneTransitions;
|
||||||
std::deque<DefaultSceneTransition> defaultSceneTransitions;
|
std::deque<DefaultSceneTransition> defaultSceneTransitions;
|
||||||
bool checkedDefTransition = false;
|
|
||||||
|
|
||||||
std::deque<MediaSwitch> mediaSwitches;
|
std::deque<MediaSwitch> mediaSwitches;
|
||||||
|
|
||||||
@@ -160,13 +161,14 @@ struct SwitcherData {
|
|||||||
void Stop();
|
void Stop();
|
||||||
|
|
||||||
bool sceneChangedDuringWait();
|
bool sceneChangedDuringWait();
|
||||||
|
|
||||||
bool prioFuncsValid();
|
bool prioFuncsValid();
|
||||||
|
|
||||||
void writeSceneInfoToFile();
|
void writeSceneInfoToFile();
|
||||||
void writeToStatusFile(QString status);
|
void writeToStatusFile(QString status);
|
||||||
bool checkPause();
|
|
||||||
void checkDefaultSceneTransitions(bool &match,
|
bool checkForMatch(OBSWeakSource &scene, OBSWeakSource &transition,
|
||||||
OBSWeakSource &transition);
|
int &linger);
|
||||||
void setCurrentDefTransition(OBSWeakSource &transition);
|
|
||||||
void checkSceneSequence(bool &match, OBSWeakSource &scene,
|
void checkSceneSequence(bool &match, OBSWeakSource &scene,
|
||||||
OBSWeakSource &transition, int &linger);
|
OBSWeakSource &transition, int &linger);
|
||||||
void checkIdleSwitch(bool &match, OBSWeakSource &scene,
|
void checkIdleSwitch(bool &match, OBSWeakSource &scene,
|
||||||
@@ -195,6 +197,8 @@ struct SwitcherData {
|
|||||||
OBSWeakSource &transition, int &sleep);
|
OBSWeakSource &transition, int &sleep);
|
||||||
void checkSwitchCooldown(bool &match);
|
void checkSwitchCooldown(bool &match);
|
||||||
void checkTriggers();
|
void checkTriggers();
|
||||||
|
bool checkPause();
|
||||||
|
void checkDefaultSceneTransitions();
|
||||||
|
|
||||||
void saveSettings(obs_data_t *obj);
|
void saveSettings(obs_data_t *obj);
|
||||||
void saveWindowTitleSwitches(obs_data_t *obj);
|
void saveWindowTitleSwitches(obs_data_t *obj);
|
||||||
|
|||||||
@@ -51,27 +51,26 @@ OBSWeakSource SceneGroup::getNextSceneTime()
|
|||||||
OBSWeakSource SceneGroup::getNextSceneRandom()
|
OBSWeakSource SceneGroup::getNextSceneRandom()
|
||||||
{
|
{
|
||||||
if (scenes.size() == 1) {
|
if (scenes.size() == 1) {
|
||||||
return *scenes.begin();
|
currentIdx = 0;
|
||||||
|
return scenes[currentIdx];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<OBSWeakSource> rs(scenes);
|
int rIdx = lastRandomScene;
|
||||||
std::random_device rng;
|
do {
|
||||||
std::mt19937 urng(rng());
|
rIdx = rand() % scenes.size();
|
||||||
std::shuffle(rs.begin(), rs.end(), urng);
|
} while (rIdx == lastRandomScene);
|
||||||
for (OBSWeakSource &s : rs) {
|
|
||||||
if (s == lastRandomScene) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
lastRandomScene = s;
|
lastRandomScene = rIdx;
|
||||||
|
currentIdx = rIdx;
|
||||||
|
|
||||||
return s;
|
return scenes[currentIdx];
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OBSWeakSource SceneGroup::getCurrentScene()
|
OBSWeakSource SceneGroup::getCurrentScene()
|
||||||
{
|
{
|
||||||
|
if (scenes.size() < currentIdx + 1) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
return scenes[currentIdx];
|
return scenes[currentIdx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -133,6 +133,15 @@ void SceneTrigger::logMatch()
|
|||||||
case sceneTriggerAction::MUTE_SOURCE:
|
case sceneTriggerAction::MUTE_SOURCE:
|
||||||
actionName = "MUTE (" + GetWeakSourceName(audioSource) + ")";
|
actionName = "MUTE (" + GetWeakSourceName(audioSource) + ")";
|
||||||
break;
|
break;
|
||||||
|
case sceneTriggerAction::UNMUTE_SOURCE:
|
||||||
|
actionName = "UNMUTE (" + GetWeakSourceName(audioSource) + ")";
|
||||||
|
break;
|
||||||
|
case sceneTriggerAction::START_SWITCHER:
|
||||||
|
actionName = "START SCENE SWITCHER";
|
||||||
|
break;
|
||||||
|
case sceneTriggerAction::STOP_SWITCHER:
|
||||||
|
actionName = "STOP SCENE SWITCHER";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
actionName = "UNKOWN";
|
actionName = "UNKOWN";
|
||||||
break;
|
break;
|
||||||
@@ -176,24 +185,35 @@ void frontEndActionThread(sceneTriggerAction action, double delay)
|
|||||||
case sceneTriggerAction::STOP_REPLAY_BUFFER:
|
case sceneTriggerAction::STOP_REPLAY_BUFFER:
|
||||||
obs_frontend_replay_buffer_stop();
|
obs_frontend_replay_buffer_stop();
|
||||||
break;
|
break;
|
||||||
case sceneTriggerAction::MUTE_SOURCE:
|
|
||||||
obs_frontend_replay_buffer_stop();
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
|
blog(LOG_WARNING, "ignoring unexpected frontend action '%d'",
|
||||||
|
action);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void muteThread(OBSWeakSource source, double delay)
|
void muteThread(OBSWeakSource source, double delay, bool mute)
|
||||||
{
|
{
|
||||||
long long mil = delay * 1000;
|
long long mil = delay * 1000;
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(mil));
|
std::this_thread::sleep_for(std::chrono::milliseconds(mil));
|
||||||
|
|
||||||
auto s = obs_weak_source_get_source(source);
|
auto s = obs_weak_source_get_source(source);
|
||||||
obs_source_set_muted(s, true);
|
obs_source_set_muted(s, mute);
|
||||||
obs_source_release(s);
|
obs_source_release(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void statusThread(double delay, bool stop)
|
||||||
|
{
|
||||||
|
long long mil = delay * 1000;
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(mil));
|
||||||
|
|
||||||
|
if (stop) {
|
||||||
|
switcher->Stop();
|
||||||
|
} else {
|
||||||
|
switcher->Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool isFrontendAction(sceneTriggerAction triggerAction)
|
bool isFrontendAction(sceneTriggerAction triggerAction)
|
||||||
{
|
{
|
||||||
return triggerAction == sceneTriggerAction::START_RECORDING ||
|
return triggerAction == sceneTriggerAction::START_RECORDING ||
|
||||||
@@ -206,6 +226,18 @@ bool isFrontendAction(sceneTriggerAction triggerAction)
|
|||||||
triggerAction == sceneTriggerAction::STOP_REPLAY_BUFFER;
|
triggerAction == sceneTriggerAction::STOP_REPLAY_BUFFER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isAudioAction(sceneTriggerAction t)
|
||||||
|
{
|
||||||
|
return t == sceneTriggerAction::MUTE_SOURCE ||
|
||||||
|
t == sceneTriggerAction::UNMUTE_SOURCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isSwitcherStatusAction(sceneTriggerAction t)
|
||||||
|
{
|
||||||
|
return t == sceneTriggerAction::START_SWITCHER ||
|
||||||
|
t == sceneTriggerAction::STOP_SWITCHER;
|
||||||
|
}
|
||||||
|
|
||||||
void SceneTrigger::performAction()
|
void SceneTrigger::performAction()
|
||||||
{
|
{
|
||||||
if (triggerAction == sceneTriggerAction::NONE) {
|
if (triggerAction == sceneTriggerAction::NONE) {
|
||||||
@@ -216,20 +248,22 @@ void SceneTrigger::performAction()
|
|||||||
|
|
||||||
if (isFrontendAction(triggerAction)) {
|
if (isFrontendAction(triggerAction)) {
|
||||||
t = std::thread(frontEndActionThread, triggerAction, duration);
|
t = std::thread(frontEndActionThread, triggerAction, duration);
|
||||||
|
} else if (isAudioAction(triggerAction)) {
|
||||||
|
bool mute = triggerAction == sceneTriggerAction::MUTE_SOURCE;
|
||||||
|
t = std::thread(muteThread, audioSource, duration, mute);
|
||||||
|
} else if (isSwitcherStatusAction(triggerAction)) {
|
||||||
|
bool stop = triggerAction == sceneTriggerAction::STOP_SWITCHER;
|
||||||
|
t = std::thread(statusThread, duration, stop);
|
||||||
} else {
|
} else {
|
||||||
t = std::thread(muteThread, audioSource, duration);
|
blog(LOG_WARNING, "ignoring unkown action '%d'", triggerAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
t.detach();
|
t.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SceneTrigger::checkMatch(OBSWeakSource previousScene)
|
bool SceneTrigger::checkMatch(OBSWeakSource currentScene,
|
||||||
|
OBSWeakSource previousScene)
|
||||||
{
|
{
|
||||||
OBSSource source = obs_frontend_get_current_scene();
|
|
||||||
OBSWeakSource currentScene = obs_source_get_weak_source(source);
|
|
||||||
obs_source_release(source);
|
|
||||||
obs_weak_source_release(currentScene);
|
|
||||||
|
|
||||||
switch (triggerType) {
|
switch (triggerType) {
|
||||||
case sceneTriggerType::NONE:
|
case sceneTriggerType::NONE:
|
||||||
return false;
|
return false;
|
||||||
@@ -245,16 +279,26 @@ bool SceneTrigger::checkMatch(OBSWeakSource previousScene)
|
|||||||
|
|
||||||
void SwitcherData::checkTriggers()
|
void SwitcherData::checkTriggers()
|
||||||
{
|
{
|
||||||
if (SceneTrigger::pause || stop) {
|
if (SceneTrigger::pause) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OBSSource source = obs_frontend_get_current_scene();
|
||||||
|
OBSWeakSource currentScene = obs_source_get_weak_source(source);
|
||||||
|
|
||||||
for (auto &t : sceneTriggers) {
|
for (auto &t : sceneTriggers) {
|
||||||
if (t.checkMatch(previousScene)) {
|
if (stop && !isSwitcherStatusAction(t.triggerAction)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t.checkMatch(currentScene, previousScene)) {
|
||||||
t.logMatch();
|
t.logMatch();
|
||||||
t.performAction();
|
t.performAction();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
obs_source_release(source);
|
||||||
|
obs_weak_source_release(currentScene);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitcherData::saveSceneTriggers(obs_data_t *obj)
|
void SwitcherData::saveSceneTriggers(obs_data_t *obj)
|
||||||
@@ -425,10 +469,13 @@ void SceneTrigger::load(obs_data_t *obj)
|
|||||||
audioSource = GetWeakSourceByName(audioSourceName);
|
audioSource = GetWeakSourceByName(audioSourceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void populateTriggers(QComboBox *list)
|
static inline void populateTriggers(QComboBox *list)
|
||||||
{
|
{
|
||||||
list->addItem(obs_module_text(
|
AdvSceneSwitcher::addSelectionEntry(
|
||||||
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.none"));
|
list,
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.none"));
|
||||||
|
|
||||||
list->addItem(obs_module_text(
|
list->addItem(obs_module_text(
|
||||||
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.sceneActive"));
|
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.sceneActive"));
|
||||||
list->addItem(obs_module_text(
|
list->addItem(obs_module_text(
|
||||||
@@ -439,8 +486,11 @@ inline void populateTriggers(QComboBox *list)
|
|||||||
|
|
||||||
inline void populateActions(QComboBox *list)
|
inline void populateActions(QComboBox *list)
|
||||||
{
|
{
|
||||||
list->addItem(obs_module_text(
|
AdvSceneSwitcher::addSelectionEntry(
|
||||||
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.none"));
|
list,
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.none"));
|
||||||
|
|
||||||
list->addItem(obs_module_text(
|
list->addItem(obs_module_text(
|
||||||
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startRecording"));
|
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startRecording"));
|
||||||
list->addItem(obs_module_text(
|
list->addItem(obs_module_text(
|
||||||
@@ -459,6 +509,12 @@ inline void populateActions(QComboBox *list)
|
|||||||
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopReplayBuffer"));
|
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopReplayBuffer"));
|
||||||
list->addItem(obs_module_text(
|
list->addItem(obs_module_text(
|
||||||
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.muteSource"));
|
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.muteSource"));
|
||||||
|
list->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.unmuteSource"));
|
||||||
|
list->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startSwitcher"));
|
||||||
|
list->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopSwitcher"));
|
||||||
}
|
}
|
||||||
|
|
||||||
SceneTriggerWidget::SceneTriggerWidget(QWidget *parent, SceneTrigger *s)
|
SceneTriggerWidget::SceneTriggerWidget(QWidget *parent, SceneTrigger *s)
|
||||||
@@ -495,7 +551,7 @@ SceneTriggerWidget::SceneTriggerWidget(QWidget *parent, SceneTrigger *s)
|
|||||||
audioSources->setCurrentText(
|
audioSources->setCurrentText(
|
||||||
GetWeakSourceName(s->audioSource).c_str());
|
GetWeakSourceName(s->audioSource).c_str());
|
||||||
|
|
||||||
if (s->triggerAction == sceneTriggerAction::MUTE_SOURCE) {
|
if (isAudioAction(s->triggerAction)) {
|
||||||
audioSources->show();
|
audioSources->show();
|
||||||
} else {
|
} else {
|
||||||
audioSources->hide();
|
audioSources->hide();
|
||||||
@@ -560,7 +616,7 @@ void SceneTriggerWidget::TriggerActionChanged(int index)
|
|||||||
static_cast<sceneTriggerAction>(index);
|
static_cast<sceneTriggerAction>(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switchData->triggerAction == sceneTriggerAction::MUTE_SOURCE) {
|
if (isAudioAction(switchData->triggerAction)) {
|
||||||
audioSources->show();
|
audioSources->show();
|
||||||
} else {
|
} else {
|
||||||
audioSources->hide();
|
audioSources->hide();
|
||||||
|
|||||||
@@ -118,29 +118,37 @@ void SwitcherData::writeToStatusFile(QString msg)
|
|||||||
void SwitcherData::checkSwitchInfoFromFile(bool &match, OBSWeakSource &scene,
|
void SwitcherData::checkSwitchInfoFromFile(bool &match, OBSWeakSource &scene,
|
||||||
OBSWeakSource &transition)
|
OBSWeakSource &transition)
|
||||||
{
|
{
|
||||||
if (!fileIO.readEnabled || fileIO.readPath.empty()) {
|
if (!fileIO.readEnabled || fileIO.readPath.empty() ||
|
||||||
|
FileSwitch::pause) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QFile file(QString::fromStdString(fileIO.readPath));
|
QFile file(QString::fromStdString(fileIO.readPath));
|
||||||
if (file.open(QIODevice::ReadOnly)) {
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
QTextStream in(&file);
|
return;
|
||||||
QString sceneStr = in.readLine();
|
|
||||||
obs_source_t *sceneRead =
|
|
||||||
obs_get_source_by_name(sceneStr.toUtf8().constData());
|
|
||||||
if (sceneRead) {
|
|
||||||
obs_weak_source_t *sceneReadWs =
|
|
||||||
obs_source_get_weak_source(sceneRead);
|
|
||||||
|
|
||||||
match = true;
|
|
||||||
scene = sceneReadWs;
|
|
||||||
transition = nullptr;
|
|
||||||
|
|
||||||
obs_weak_source_release(sceneReadWs);
|
|
||||||
obs_source_release(sceneRead);
|
|
||||||
}
|
|
||||||
file.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QTextStream in(&file);
|
||||||
|
|
||||||
|
QString sceneStr = in.readLine();
|
||||||
|
OBSWeakSource sceneRead = GetWeakSourceByQString(sceneStr);
|
||||||
|
|
||||||
|
QString transitionStr = in.readLine();
|
||||||
|
OBSWeakSource transitionRead =
|
||||||
|
GetWeakTransitionByQString(transitionStr);
|
||||||
|
|
||||||
|
if (sceneRead) {
|
||||||
|
match = true;
|
||||||
|
scene = sceneRead;
|
||||||
|
transition = transitionRead;
|
||||||
|
|
||||||
|
vblog(LOG_INFO,
|
||||||
|
"match for 'file' - read scene '%s' and transition '%s' from file '%s'",
|
||||||
|
sceneStr.toUtf8().constData(),
|
||||||
|
transitionStr.toUtf8().constData(),
|
||||||
|
fileIO.readPath.c_str());
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t WriteCallback(void *contents, size_t size, size_t nmemb,
|
static size_t WriteCallback(void *contents, size_t size, size_t nmemb,
|
||||||
|
|||||||
@@ -5,14 +5,15 @@ bool SceneSwitcherEntry::initialized()
|
|||||||
{
|
{
|
||||||
return (usePreviousScene || WeakSourceValid(scene) ||
|
return (usePreviousScene || WeakSourceValid(scene) ||
|
||||||
SceneGroupValid(group)) &&
|
SceneGroupValid(group)) &&
|
||||||
transition;
|
(useCurrentTransition || transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SceneSwitcherEntry::valid()
|
bool SceneSwitcherEntry::valid()
|
||||||
{
|
{
|
||||||
return !initialized() || ((usePreviousScene || WeakSourceValid(scene) ||
|
return !initialized() ||
|
||||||
SceneGroupValid(group)) &&
|
((usePreviousScene || WeakSourceValid(scene) ||
|
||||||
WeakSourceValid(transition));
|
SceneGroupValid(group)) &&
|
||||||
|
(useCurrentTransition || WeakSourceValid(transition)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcherEntry::logMatchScene()
|
void SceneSwitcherEntry::logMatchScene()
|
||||||
@@ -82,8 +83,11 @@ void SceneSwitcherEntry::save(obs_data_t *obj, const char *targetTypeSaveName,
|
|||||||
|
|
||||||
obs_data_set_string(obj, targetSaveName, targetName.c_str());
|
obs_data_set_string(obj, targetSaveName, targetName.c_str());
|
||||||
|
|
||||||
obs_data_set_string(obj, transitionSaveName,
|
std::string transitionName = current_transition_name;
|
||||||
GetWeakSourceName(transition).c_str());
|
if (!useCurrentTransition) {
|
||||||
|
transitionName = GetWeakSourceName(transition);
|
||||||
|
}
|
||||||
|
obs_data_set_string(obj, transitionSaveName, transitionName.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcherEntry::load(obs_data_t *obj, const char *targetTypeLoadName,
|
void SceneSwitcherEntry::load(obs_data_t *obj, const char *targetTypeLoadName,
|
||||||
@@ -104,11 +108,14 @@ void SceneSwitcherEntry::load(obs_data_t *obj, const char *targetTypeLoadName,
|
|||||||
group = GetSceneGroupByName(targetName);
|
group = GetSceneGroupByName(targetName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
usePreviousScene = strcmp(targetName, previous_scene_name) == 0;
|
||||||
|
|
||||||
const char *transitionName =
|
const char *transitionName =
|
||||||
obs_data_get_string(obj, transitionLoadName);
|
obs_data_get_string(obj, transitionLoadName);
|
||||||
transition = GetWeakTransitionByName(transitionName);
|
transition = GetWeakTransitionByName(transitionName);
|
||||||
|
|
||||||
usePreviousScene = strcmp(targetName, previous_scene_name) == 0;
|
useCurrentTransition =
|
||||||
|
strcmp(transitionName, current_transition_name) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitchWidget::SceneGroupAdd(const QString &name)
|
void SwitchWidget::SceneGroupAdd(const QString &name)
|
||||||
@@ -166,7 +173,8 @@ void SwitchWidget::SceneGroupRename(const QString &oldName,
|
|||||||
}
|
}
|
||||||
|
|
||||||
SwitchWidget::SwitchWidget(QWidget *parent, SceneSwitcherEntry *s,
|
SwitchWidget::SwitchWidget(QWidget *parent, SceneSwitcherEntry *s,
|
||||||
bool usePreviousScene, bool addSceneGroup)
|
bool usePreviousScene, bool addSceneGroup,
|
||||||
|
bool addCurrentTransition)
|
||||||
{
|
{
|
||||||
scenes = new QComboBox();
|
scenes = new QComboBox();
|
||||||
transitions = new QComboBox();
|
transitions = new QComboBox();
|
||||||
@@ -194,7 +202,8 @@ SwitchWidget::SwitchWidget(QWidget *parent, SceneSwitcherEntry *s,
|
|||||||
|
|
||||||
AdvSceneSwitcher::populateSceneSelection(scenes, usePreviousScene,
|
AdvSceneSwitcher::populateSceneSelection(scenes, usePreviousScene,
|
||||||
addSceneGroup);
|
addSceneGroup);
|
||||||
AdvSceneSwitcher::populateTransitionSelection(transitions);
|
AdvSceneSwitcher::populateTransitionSelection(transitions,
|
||||||
|
addCurrentTransition);
|
||||||
|
|
||||||
switchData = s;
|
switchData = s;
|
||||||
showSwitchData();
|
showSwitchData();
|
||||||
@@ -218,6 +227,10 @@ void SwitchWidget::showSwitchData()
|
|||||||
|
|
||||||
transitions->setCurrentText(
|
transitions->setCurrentText(
|
||||||
GetWeakSourceName(switchData->transition).c_str());
|
GetWeakSourceName(switchData->transition).c_str());
|
||||||
|
if (switchData->useCurrentTransition) {
|
||||||
|
transitions->setCurrentText(
|
||||||
|
obs_module_text("AdvSceneSwitcher.currentTransition"));
|
||||||
|
}
|
||||||
|
|
||||||
if (switchData->usePreviousScene) {
|
if (switchData->usePreviousScene) {
|
||||||
scenes->setCurrentText(obs_module_text(
|
scenes->setCurrentText(obs_module_text(
|
||||||
@@ -278,4 +291,5 @@ void SwitchWidget::TransitionChanged(const QString &text)
|
|||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switchData->transition = GetWeakTransitionByQString(text);
|
switchData->transition = GetWeakTransitionByQString(text);
|
||||||
|
switchData->useCurrentTransition = switchData->transition == nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -353,7 +353,8 @@ ScreenRegionWidget::ScreenRegionWidget(QWidget *parent, ScreenRegionSwitch *s)
|
|||||||
AdvSceneSwitcher::populateSceneSelection(
|
AdvSceneSwitcher::populateSceneSelection(
|
||||||
excludeScenes, false, false, true,
|
excludeScenes, false, false, true,
|
||||||
obs_module_text(
|
obs_module_text(
|
||||||
"AdvSceneSwitcher.screenRegionTab.excludeScenes.None"));
|
"AdvSceneSwitcher.screenRegionTab.excludeScenes.None"),
|
||||||
|
true);
|
||||||
|
|
||||||
if (s) {
|
if (s) {
|
||||||
excludeScenes->setCurrentText(
|
excludeScenes->setCurrentText(
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
|
constexpr auto max_extend_text_size = 150;
|
||||||
|
|
||||||
bool SceneSequenceSwitch::pause = false;
|
bool SceneSequenceSwitch::pause = false;
|
||||||
static QMetaObject::Connection addPulse;
|
static QMetaObject::Connection addPulse;
|
||||||
|
|
||||||
@@ -159,30 +161,41 @@ void AdvSceneSwitcher::on_sceneSequenceLoad_clicked()
|
|||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool matchInterruptible(SwitcherData *switcher, SceneSequenceSwitch &s)
|
void AdvSceneSwitcher::OpenSequenceExtendEdit(SequenceWidget *sw)
|
||||||
{
|
{
|
||||||
bool durationReached = s.matchCount * (switcher->interval / 1000.0) >=
|
QDialog edit;
|
||||||
s.delay;
|
SequenceWidget editWidget(this, sw->getSwitchData(), false, true);
|
||||||
|
QHBoxLayout layout;
|
||||||
|
layout.setSizeConstraint(QLayout::SetFixedSize);
|
||||||
|
layout.addWidget(&editWidget);
|
||||||
|
edit.setLayout(&layout);
|
||||||
|
edit.setWindowTitle(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.sceneSequenceTab.extendEdit"));
|
||||||
|
edit.exec();
|
||||||
|
|
||||||
s.matchCount++;
|
sw->UpdateExtendText();
|
||||||
|
|
||||||
if (durationReached) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool matchUninterruptible(SwitcherData *switcher, SceneSequenceSwitch &s,
|
void AdvSceneSwitcher::on_sequenceEdit_clicked()
|
||||||
obs_source_t *currentSource, int &linger)
|
|
||||||
{
|
{
|
||||||
// scene was already active for the previous cycle so remove this time
|
int index = ui->sceneSequenceSwitches->currentRow();
|
||||||
int dur = s.delay * 1000 - switcher->interval;
|
if (index == -1) {
|
||||||
if (dur > 0) {
|
return;
|
||||||
switcher->waitScene = currentSource;
|
|
||||||
linger = dur;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
SequenceWidget *currentWidget =
|
||||||
|
(SequenceWidget *)ui->sceneSequenceSwitches->itemWidget(
|
||||||
|
ui->sceneSequenceSwitches->item(index));
|
||||||
|
|
||||||
|
OpenSequenceExtendEdit(currentWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_sceneSequenceSwitches_itemDoubleClicked(
|
||||||
|
QListWidgetItem *item)
|
||||||
|
{
|
||||||
|
SequenceWidget *currentWidget =
|
||||||
|
(SequenceWidget *)ui->sceneSequenceSwitches->itemWidget(item);
|
||||||
|
OpenSequenceExtendEdit(currentWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitcherData::checkSceneSequence(bool &match, OBSWeakSource &scene,
|
void SwitcherData::checkSceneSequence(bool &match, OBSWeakSource &scene,
|
||||||
@@ -192,38 +205,53 @@ void SwitcherData::checkSceneSequence(bool &match, OBSWeakSource &scene,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
obs_source_t *currentSource = obs_frontend_get_current_scene();
|
obs_source_t *currentSceneSource = obs_frontend_get_current_scene();
|
||||||
obs_weak_source_t *ws = obs_source_get_weak_source(currentSource);
|
obs_weak_source_t *currentScene =
|
||||||
|
obs_source_get_weak_source(currentSceneSource);
|
||||||
|
|
||||||
for (SceneSequenceSwitch &s : sceneSequenceSwitches) {
|
for (SceneSequenceSwitch &s : sceneSequenceSwitches) {
|
||||||
if (!s.initialized()) {
|
// Continue the active uninterruptible sequence and skip others
|
||||||
|
if (uninterruptibleSceneSequenceActive &&
|
||||||
|
s.activeSequence == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s.startScene == ws) {
|
bool matched = s.checkMatch(currentScene, linger);
|
||||||
if (!match) {
|
|
||||||
if (s.interruptible) {
|
|
||||||
match = matchInterruptible(switcher, s);
|
|
||||||
} else {
|
|
||||||
match = matchUninterruptible(
|
|
||||||
switcher, s, currentSource,
|
|
||||||
linger);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (match) {
|
if (!match && matched) {
|
||||||
scene = s.getScene();
|
match = matched;
|
||||||
transition = s.transition;
|
|
||||||
if (switcher->verbose) {
|
if (s.activeSequence) {
|
||||||
s.logMatch();
|
scene = s.activeSequence->getScene();
|
||||||
}
|
transition = s.activeSequence->transition;
|
||||||
|
} else {
|
||||||
|
scene = s.getScene();
|
||||||
|
transition = s.transition;
|
||||||
|
if (verbose) {
|
||||||
|
s.logMatch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
s.matchCount = 0;
|
s.advanceActiveSequence();
|
||||||
|
if (verbose) {
|
||||||
|
s.logAdvanceSequence();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore other switching methods if sequence is not
|
||||||
|
// interruptible and has not reached its end
|
||||||
|
if (s.activeSequence) {
|
||||||
|
uninterruptibleSceneSequenceActive =
|
||||||
|
!s.interruptible;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
obs_source_release(currentSource);
|
|
||||||
obs_weak_source_release(ws);
|
if (!match) {
|
||||||
|
uninterruptibleSceneSequenceActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_source_release(currentSceneSource);
|
||||||
|
obs_weak_source_release(currentScene);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitcherData::saveSceneSequenceSwitches(obs_data_t *obj)
|
void SwitcherData::saveSceneSequenceSwitches(obs_data_t *obj)
|
||||||
@@ -291,18 +319,32 @@ bool SceneSequenceSwitch::valid()
|
|||||||
(SceneSwitcherEntry::valid() && WeakSourceValid(startScene));
|
(SceneSwitcherEntry::valid() && WeakSourceValid(startScene));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSequenceSwitch::save(obs_data_t *obj)
|
void SceneSequenceSwitch::save(obs_data_t *obj, bool saveExt)
|
||||||
{
|
{
|
||||||
SceneSwitcherEntry::save(obj);
|
SceneSwitcherEntry::save(obj);
|
||||||
|
|
||||||
|
obs_data_set_int(obj, "startTargetType",
|
||||||
|
static_cast<int>(startTargetType));
|
||||||
obs_data_set_string(obj, "startScene",
|
obs_data_set_string(obj, "startScene",
|
||||||
GetWeakSourceName(startScene).c_str());
|
GetWeakSourceName(startScene).c_str());
|
||||||
|
|
||||||
obs_data_set_double(obj, "delay", delay);
|
obs_data_set_double(obj, "delay", delay);
|
||||||
|
|
||||||
obs_data_set_int(obj, "delayMultiplier", delayMultiplier);
|
obs_data_set_int(obj, "delayMultiplier", delayMultiplier);
|
||||||
|
|
||||||
obs_data_set_bool(obj, "interruptible", interruptible);
|
obs_data_set_bool(obj, "interruptible", interruptible);
|
||||||
|
|
||||||
|
if (saveExt) {
|
||||||
|
auto cur = extendedSequence.get();
|
||||||
|
|
||||||
|
obs_data_array_t *extendScenes = obs_data_array_create();
|
||||||
|
while (cur) {
|
||||||
|
obs_data_t *array_obj = obs_data_create();
|
||||||
|
cur->save(array_obj, false);
|
||||||
|
obs_data_array_push_back(extendScenes, array_obj);
|
||||||
|
obs_data_release(array_obj);
|
||||||
|
cur = cur->extendedSequence.get();
|
||||||
|
}
|
||||||
|
obs_data_set_array(obj, "extendScenes", extendScenes);
|
||||||
|
obs_data_array_release(extendScenes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// To be removed in future version
|
// To be removed in future version
|
||||||
@@ -341,14 +383,15 @@ bool loadOldScequence(obs_data_t *obj, SceneSequenceSwitch *s)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSequenceSwitch::load(obs_data_t *obj)
|
void SceneSequenceSwitch::load(obs_data_t *obj, bool saveExt)
|
||||||
{
|
{
|
||||||
if (loadOldScequence(obj, this)) {
|
if (loadOldScequence(obj, this)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SceneSwitcherEntry::load(obj);
|
SceneSwitcherEntry::load(obj);
|
||||||
|
startTargetType = static_cast<SwitchTargetType>(
|
||||||
|
obs_data_get_int(obj, "startTargetType"));
|
||||||
const char *scene = obs_data_get_string(obj, "startScene");
|
const char *scene = obs_data_get_string(obj, "startScene");
|
||||||
startScene = GetWeakSourceByName(scene);
|
startScene = GetWeakSourceByName(scene);
|
||||||
|
|
||||||
@@ -360,6 +403,174 @@ void SceneSequenceSwitch::load(obs_data_t *obj)
|
|||||||
delayMultiplier = 1;
|
delayMultiplier = 1;
|
||||||
|
|
||||||
interruptible = obs_data_get_bool(obj, "interruptible");
|
interruptible = obs_data_get_bool(obj, "interruptible");
|
||||||
|
|
||||||
|
if (saveExt) {
|
||||||
|
auto cur = this;
|
||||||
|
|
||||||
|
obs_data_array_t *extendScenes =
|
||||||
|
obs_data_get_array(obj, "extendScenes");
|
||||||
|
size_t count = obs_data_array_count(extendScenes);
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
obs_data_t *array_obj =
|
||||||
|
obs_data_array_item(extendScenes, i);
|
||||||
|
|
||||||
|
cur->extendedSequence =
|
||||||
|
std::make_unique<SceneSequenceSwitch>();
|
||||||
|
|
||||||
|
cur->extendedSequence->load(array_obj, false);
|
||||||
|
|
||||||
|
cur = cur->extendedSequence.get();
|
||||||
|
obs_data_release(array_obj);
|
||||||
|
}
|
||||||
|
obs_data_array_release(extendScenes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SceneSequenceSwitch::reduce()
|
||||||
|
{
|
||||||
|
// Reset activeSequence just in case it was one of the deleted entries
|
||||||
|
activeSequence = nullptr;
|
||||||
|
|
||||||
|
if (!extendedSequence) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (extendedSequence->reduce()) {
|
||||||
|
extendedSequence.reset(nullptr);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneSequenceSwitch *SceneSequenceSwitch::extend()
|
||||||
|
{
|
||||||
|
if (extendedSequence) {
|
||||||
|
return extendedSequence->extend();
|
||||||
|
}
|
||||||
|
extendedSequence = std::make_unique<SceneSequenceSwitch>();
|
||||||
|
extendedSequence->startScene = scene;
|
||||||
|
return extendedSequence.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SceneSequenceSwitch::checkMatch(OBSWeakSource currentScene, int &linger,
|
||||||
|
SceneSequenceSwitch *root)
|
||||||
|
{
|
||||||
|
if (!initialized()) {
|
||||||
|
if (root) {
|
||||||
|
root->activeSequence = nullptr;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool match = false;
|
||||||
|
|
||||||
|
if (activeSequence) {
|
||||||
|
return activeSequence->checkMatch(currentScene, linger, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startScene == currentScene) {
|
||||||
|
if (interruptible) {
|
||||||
|
match = checkDurationMatchInterruptible();
|
||||||
|
} else {
|
||||||
|
match = true;
|
||||||
|
prepareUninterruptibleMatch(currentScene, linger);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
matchCount = 0;
|
||||||
|
|
||||||
|
if (root) {
|
||||||
|
root->activeSequence = nullptr;
|
||||||
|
logSequenceCanceled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SceneSequenceSwitch::checkDurationMatchInterruptible()
|
||||||
|
{
|
||||||
|
bool durationReached = matchCount * (switcher->interval / 1000.0) >=
|
||||||
|
delay;
|
||||||
|
matchCount++;
|
||||||
|
if (durationReached) {
|
||||||
|
matchCount = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneSequenceSwitch::prepareUninterruptibleMatch(
|
||||||
|
OBSWeakSource currentScene, int &linger)
|
||||||
|
{
|
||||||
|
int dur = delay * 1000;
|
||||||
|
if (dur > 0) {
|
||||||
|
switcher->waitScene = obs_weak_source_get_source(currentScene);
|
||||||
|
obs_source_release(switcher->waitScene);
|
||||||
|
linger = dur;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneSequenceSwitch::advanceActiveSequence()
|
||||||
|
{
|
||||||
|
// Set start Scene
|
||||||
|
OBSWeakSource currentSceneGroupScene = nullptr;
|
||||||
|
if (targetType == SwitchTargetType::SceneGroup && group) {
|
||||||
|
currentSceneGroupScene = group->getCurrentScene();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeSequence) {
|
||||||
|
activeSequence = activeSequence->extendedSequence.get();
|
||||||
|
} else {
|
||||||
|
activeSequence = extendedSequence.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeSequence) {
|
||||||
|
if (activeSequence->startTargetType ==
|
||||||
|
SwitchTargetType::SceneGroup) {
|
||||||
|
activeSequence->startScene = currentSceneGroupScene;
|
||||||
|
}
|
||||||
|
if (activeSequence->targetType == SwitchTargetType::Scene &&
|
||||||
|
!activeSequence->scene) {
|
||||||
|
blog(LOG_WARNING,
|
||||||
|
"cannot advance sequence - null scene set");
|
||||||
|
activeSequence = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (activeSequence->targetType ==
|
||||||
|
SwitchTargetType::SceneGroup &&
|
||||||
|
activeSequence->group &&
|
||||||
|
activeSequence->group->scenes.empty()) {
|
||||||
|
blog(LOG_WARNING,
|
||||||
|
"cannot advance sequence - no scenes specified in '%s'",
|
||||||
|
activeSequence->group->name.c_str());
|
||||||
|
activeSequence = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reinit old matchCount value in case it was previously set
|
||||||
|
activeSequence->matchCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneSequenceSwitch::logAdvanceSequence()
|
||||||
|
{
|
||||||
|
if (activeSequence) {
|
||||||
|
std::string targetName =
|
||||||
|
GetWeakSourceName(activeSequence->scene);
|
||||||
|
|
||||||
|
if (activeSequence->targetType ==
|
||||||
|
SwitchTargetType::SceneGroup &&
|
||||||
|
activeSequence->group) {
|
||||||
|
targetName = activeSequence->group->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
blog(LOG_INFO, "continuing sequence with '%s' -> '%s'",
|
||||||
|
GetWeakSourceName(activeSequence->startScene).c_str(),
|
||||||
|
targetName.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneSequenceSwitch::logSequenceCanceled()
|
||||||
|
{
|
||||||
|
blog(LOG_INFO, "unexpected scene change - cancel sequence");
|
||||||
}
|
}
|
||||||
|
|
||||||
void populateDelayUnits(QComboBox *list)
|
void populateDelayUnits(QComboBox *list)
|
||||||
@@ -369,14 +580,82 @@ void populateDelayUnits(QComboBox *list)
|
|||||||
list->addItem(obs_module_text("AdvSceneSwitcher.unit.hours"));
|
list->addItem(obs_module_text("AdvSceneSwitcher.unit.hours"));
|
||||||
}
|
}
|
||||||
|
|
||||||
SequenceWidget::SequenceWidget(QWidget *parent, SceneSequenceSwitch *s)
|
QString makeExtendText(SceneSequenceSwitch *s, int curLen = 0)
|
||||||
: SwitchWidget(parent, s, true, true)
|
|
||||||
{
|
{
|
||||||
|
if (!s) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ext = "";
|
||||||
|
|
||||||
|
ext = QString::number(s->delay / s->delayMultiplier) + " ";
|
||||||
|
|
||||||
|
switch (s->delayMultiplier) {
|
||||||
|
case 1:
|
||||||
|
ext += obs_module_text("AdvSceneSwitcher.unit.secends");
|
||||||
|
break;
|
||||||
|
case 60:
|
||||||
|
ext += obs_module_text("AdvSceneSwitcher.unit.minutes");
|
||||||
|
break;
|
||||||
|
case 60 * 60:
|
||||||
|
ext += obs_module_text("AdvSceneSwitcher.unit.hours");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ext += obs_module_text("?????");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString sceneName = GetWeakSourceName(s->scene).c_str();
|
||||||
|
if (s->targetType == SwitchTargetType::SceneGroup && s->group) {
|
||||||
|
sceneName = QString::fromStdString(s->group->name);
|
||||||
|
}
|
||||||
|
if (sceneName.isEmpty()) {
|
||||||
|
sceneName = obs_module_text("AdvSceneSwitcher.selectScene");
|
||||||
|
}
|
||||||
|
ext += " -> [" + sceneName + "]";
|
||||||
|
|
||||||
|
if (ext.length() + curLen > max_extend_text_size) {
|
||||||
|
return "...";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->extendedSequence.get()) {
|
||||||
|
return ext +=
|
||||||
|
" | " + makeExtendText(s->extendedSequence.get(),
|
||||||
|
curLen + ext.length());
|
||||||
|
} else {
|
||||||
|
return ext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SequenceWidget::SequenceWidget(QWidget *parent, SceneSequenceSwitch *s,
|
||||||
|
bool extendSequence, bool editExtendMode)
|
||||||
|
: SwitchWidget(parent, s, !extendSequence, true)
|
||||||
|
{
|
||||||
|
this->setParent(parent);
|
||||||
|
|
||||||
delay = new QDoubleSpinBox();
|
delay = new QDoubleSpinBox();
|
||||||
delayUnits = new QComboBox();
|
delayUnits = new QComboBox();
|
||||||
startScenes = new QComboBox();
|
startScenes = new QComboBox();
|
||||||
interruptible = new QCheckBox(obs_module_text(
|
interruptible = new QCheckBox(obs_module_text(
|
||||||
"AdvSceneSwitcher.sceneSequenceTab.interruptible"));
|
"AdvSceneSwitcher.sceneSequenceTab.interruptible"));
|
||||||
|
extendText = new QLabel();
|
||||||
|
extend = new QPushButton();
|
||||||
|
reduce = new QPushButton();
|
||||||
|
|
||||||
|
extend->setProperty("themeID",
|
||||||
|
QVariant(QStringLiteral("addIconSmall")));
|
||||||
|
reduce->setProperty("themeID",
|
||||||
|
QVariant(QStringLiteral("removeIconSmall")));
|
||||||
|
|
||||||
|
extend->setMaximumSize(22, 22);
|
||||||
|
reduce->setMaximumSize(22, 22);
|
||||||
|
|
||||||
|
// We need to extend the generic SwitchWidget::SceneChanged()
|
||||||
|
// with our own SequenceWidget::SceneChanged()
|
||||||
|
// so the old singal / slot needs to be disconnected
|
||||||
|
scenes->disconnect();
|
||||||
|
QWidget::connect(scenes, SIGNAL(currentTextChanged(const QString &)),
|
||||||
|
this, SLOT(SceneChanged(const QString &)));
|
||||||
|
|
||||||
QWidget::connect(delay, SIGNAL(valueChanged(double)), this,
|
QWidget::connect(delay, SIGNAL(valueChanged(double)), this,
|
||||||
SLOT(DelayChanged(double)));
|
SLOT(DelayChanged(double)));
|
||||||
@@ -388,6 +667,11 @@ SequenceWidget::SequenceWidget(QWidget *parent, SceneSequenceSwitch *s)
|
|||||||
QWidget::connect(interruptible, SIGNAL(stateChanged(int)), this,
|
QWidget::connect(interruptible, SIGNAL(stateChanged(int)), this,
|
||||||
SLOT(InterruptibleChanged(int)));
|
SLOT(InterruptibleChanged(int)));
|
||||||
|
|
||||||
|
QWidget::connect(extend, SIGNAL(clicked()), this,
|
||||||
|
SLOT(ExtendClicked()));
|
||||||
|
QWidget::connect(reduce, SIGNAL(clicked()), this,
|
||||||
|
SLOT(ReduceClicked()));
|
||||||
|
|
||||||
delay->setMaximum(99999.000000);
|
delay->setMaximum(99999.000000);
|
||||||
AdvSceneSwitcher::populateSceneSelection(startScenes, false);
|
AdvSceneSwitcher::populateSceneSelection(startScenes, false);
|
||||||
populateDelayUnits(delayUnits);
|
populateDelayUnits(delayUnits);
|
||||||
@@ -413,17 +697,62 @@ SequenceWidget::SequenceWidget(QWidget *parent, SceneSequenceSwitch *s)
|
|||||||
interruptible->setChecked(s->interruptible);
|
interruptible->setChecked(s->interruptible);
|
||||||
}
|
}
|
||||||
|
|
||||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
if (extendSequence) {
|
||||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
{"{{startScenes}}", startScenes},
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
{"{{scenes}}", scenes},
|
{"{{scenes}}", scenes},
|
||||||
{"{{delay}}", delay},
|
{"{{delay}}", delay},
|
||||||
{"{{delayUnits}}", delayUnits},
|
{"{{delayUnits}}", delayUnits},
|
||||||
{"{{transitions}}", transitions},
|
{"{{transitions}}", transitions}};
|
||||||
{"{{interruptible}}", interruptible}};
|
placeWidgets(
|
||||||
placeWidgets(obs_module_text("AdvSceneSwitcher.sceneSequenceTab.entry"),
|
obs_module_text(
|
||||||
mainLayout, widgetPlaceholders);
|
"AdvSceneSwitcher.sceneSequenceTab.extendEntry"),
|
||||||
setLayout(mainLayout);
|
mainLayout, widgetPlaceholders);
|
||||||
|
setLayout(mainLayout);
|
||||||
|
} else {
|
||||||
|
QHBoxLayout *startSequence = new QHBoxLayout;
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
|
{"{{startScenes}}", startScenes},
|
||||||
|
{"{{scenes}}", scenes},
|
||||||
|
{"{{delay}}", delay},
|
||||||
|
{"{{delayUnits}}", delayUnits},
|
||||||
|
{"{{transitions}}", transitions},
|
||||||
|
{"{{interruptible}}", interruptible}};
|
||||||
|
placeWidgets(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.sceneSequenceTab.entry"),
|
||||||
|
startSequence, widgetPlaceholders);
|
||||||
|
|
||||||
|
//exetend widgets placed here
|
||||||
|
extendSequenceLayout = new QVBoxLayout;
|
||||||
|
if (s) {
|
||||||
|
if (!editExtendMode) {
|
||||||
|
extendText->setText(makeExtendText(
|
||||||
|
s->extendedSequence.get()));
|
||||||
|
} else {
|
||||||
|
auto cur = s->extendedSequence.get();
|
||||||
|
while (cur != nullptr) {
|
||||||
|
extendSequenceLayout->addWidget(
|
||||||
|
new SequenceWidget(parent, cur,
|
||||||
|
true, true));
|
||||||
|
cur = cur->extendedSequence.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QHBoxLayout *extendSequenceControlsLayout = new QHBoxLayout;
|
||||||
|
if (editExtendMode) {
|
||||||
|
extendSequenceControlsLayout->addWidget(extend);
|
||||||
|
extendSequenceControlsLayout->addWidget(reduce);
|
||||||
|
}
|
||||||
|
extendSequenceControlsLayout->addStretch();
|
||||||
|
|
||||||
|
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||||
|
mainLayout->addLayout(startSequence);
|
||||||
|
mainLayout->addLayout(extendSequenceLayout);
|
||||||
|
mainLayout->addWidget(extendText);
|
||||||
|
mainLayout->addLayout(extendSequenceControlsLayout);
|
||||||
|
setLayout(mainLayout);
|
||||||
|
}
|
||||||
|
|
||||||
switchData = s;
|
switchData = s;
|
||||||
|
|
||||||
@@ -493,6 +822,32 @@ void SequenceWidget::DelayUnitsChanged(int idx)
|
|||||||
UpdateDelay();
|
UpdateDelay();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SequenceWidget::setExtendedSequenceStartScene()
|
||||||
|
{
|
||||||
|
switchData->extendedSequence->startScene = switchData->scene;
|
||||||
|
switchData->extendedSequence->startTargetType = SwitchTargetType::Scene;
|
||||||
|
|
||||||
|
if (switchData->targetType == SwitchTargetType::SceneGroup) {
|
||||||
|
switchData->extendedSequence->startScene = nullptr;
|
||||||
|
switchData->extendedSequence->startTargetType =
|
||||||
|
SwitchTargetType::SceneGroup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SequenceWidget::SceneChanged(const QString &text)
|
||||||
|
{
|
||||||
|
if (loading || !switchData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SwitchWidget::SceneChanged(text);
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
|
||||||
|
if (switchData->extendedSequence) {
|
||||||
|
setExtendedSequenceStartScene();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SequenceWidget::StartSceneChanged(const QString &text)
|
void SequenceWidget::StartSceneChanged(const QString &text)
|
||||||
{
|
{
|
||||||
if (loading || !switchData) {
|
if (loading || !switchData) {
|
||||||
@@ -511,4 +866,45 @@ void SequenceWidget::InterruptibleChanged(int state)
|
|||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switchData->interruptible = state;
|
switchData->interruptible = state;
|
||||||
|
|
||||||
|
auto cur = switchData->extendedSequence.get();
|
||||||
|
while (cur != nullptr) {
|
||||||
|
cur->interruptible = state;
|
||||||
|
cur = cur->extendedSequence.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SequenceWidget::UpdateExtendText()
|
||||||
|
{
|
||||||
|
extendText->setText(makeExtendText(switchData->extendedSequence.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SequenceWidget::ExtendClicked()
|
||||||
|
{
|
||||||
|
if (loading || !switchData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
auto es = switchData->extend();
|
||||||
|
|
||||||
|
SequenceWidget *ew = new SequenceWidget(this->parentWidget(), es, true);
|
||||||
|
extendSequenceLayout->addWidget(ew);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SequenceWidget::ReduceClicked()
|
||||||
|
{
|
||||||
|
if (loading || !switchData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->reduce();
|
||||||
|
|
||||||
|
int count = extendSequenceLayout->count();
|
||||||
|
auto item = extendSequenceLayout->takeAt(count - 1);
|
||||||
|
if (item) {
|
||||||
|
item->widget()->setVisible(false);
|
||||||
|
delete item;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -241,7 +241,7 @@ void TimeSwitch::load(obs_data_t *obj)
|
|||||||
time = QTime::fromString(obs_data_get_string(obj, "time"));
|
time = QTime::fromString(obs_data_get_string(obj, "time"));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void populateTriggers(QComboBox *list)
|
static inline void populateTriggers(QComboBox *list)
|
||||||
{
|
{
|
||||||
list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.anyDay"));
|
list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.anyDay"));
|
||||||
list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.mondays"));
|
list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.mondays"));
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#include <thread>
|
||||||
|
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
@@ -148,42 +150,28 @@ void AdvSceneSwitcher::on_defaultTransitionsDown_clicked()
|
|||||||
switcher->defaultSceneTransitions[index + 1]);
|
switcher->defaultSceneTransitions[index + 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitcherData::checkDefaultSceneTransitions(bool &match,
|
void SwitcherData::checkDefaultSceneTransitions()
|
||||||
OBSWeakSource &transition)
|
|
||||||
{
|
{
|
||||||
if (checkedDefTransition || DefaultSceneTransition::pause) {
|
if (DefaultSceneTransition::pause || stop) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
obs_source_t *currentSource = obs_frontend_get_current_scene();
|
obs_source_t *currentSceneSource = obs_frontend_get_current_scene();
|
||||||
obs_weak_source_t *ws = obs_source_get_weak_source(currentSource);
|
obs_weak_source_t *currentScene =
|
||||||
|
obs_source_get_weak_source(currentSceneSource);
|
||||||
for (DefaultSceneTransition &s : defaultSceneTransitions) {
|
|
||||||
if (s.scene == ws) {
|
|
||||||
if (!s.initialized()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
match = true;
|
|
||||||
transition = s.transition;
|
|
||||||
|
|
||||||
|
for (auto &t : defaultSceneTransitions) {
|
||||||
|
if (t.checkMatch(currentScene)) {
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
s.logMatch();
|
t.logMatch();
|
||||||
}
|
}
|
||||||
|
t.setTransition();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
obs_source_release(currentSource);
|
|
||||||
obs_weak_source_release(ws);
|
|
||||||
|
|
||||||
checkedDefTransition = true;
|
obs_weak_source_release(currentScene);
|
||||||
}
|
obs_source_release(currentSceneSource);
|
||||||
|
|
||||||
void SwitcherData::setCurrentDefTransition(OBSWeakSource &transition)
|
|
||||||
{
|
|
||||||
obs_source_t *transitionSource = obs_weak_source_get_source(transition);
|
|
||||||
obs_frontend_set_current_transition(transitionSource);
|
|
||||||
obs_source_release(transitionSource);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_transitionOverridecheckBox_stateChanged(int state)
|
void AdvSceneSwitcher::on_transitionOverridecheckBox_stateChanged(int state)
|
||||||
@@ -439,7 +427,7 @@ bool SceneTransition::valid()
|
|||||||
|
|
||||||
TransitionSwitchWidget::TransitionSwitchWidget(QWidget *parent,
|
TransitionSwitchWidget::TransitionSwitchWidget(QWidget *parent,
|
||||||
SceneTransition *s)
|
SceneTransition *s)
|
||||||
: SwitchWidget(parent, s, false)
|
: SwitchWidget(parent, s, false, false, false)
|
||||||
{
|
{
|
||||||
scenes2 = new QComboBox();
|
scenes2 = new QComboBox();
|
||||||
|
|
||||||
@@ -498,7 +486,7 @@ void TransitionSwitchWidget::Scene2Changed(const QString &text)
|
|||||||
|
|
||||||
DefTransitionSwitchWidget::DefTransitionSwitchWidget(QWidget *parent,
|
DefTransitionSwitchWidget::DefTransitionSwitchWidget(QWidget *parent,
|
||||||
DefaultSceneTransition *s)
|
DefaultSceneTransition *s)
|
||||||
: SwitchWidget(parent, s, false)
|
: SwitchWidget(parent, s, false, false, false)
|
||||||
{
|
{
|
||||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
@@ -533,3 +521,37 @@ void DefTransitionSwitchWidget::swapSwitchData(DefTransitionSwitchWidget *s1,
|
|||||||
s1->setSwitchData(s2->getSwitchData());
|
s1->setSwitchData(s2->getSwitchData());
|
||||||
s2->setSwitchData(t);
|
s2->setSwitchData(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DefaultSceneTransition::checkMatch(OBSWeakSource currentScene)
|
||||||
|
{
|
||||||
|
return scene == currentScene;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTransitionDelayed(OBSWeakSource transition)
|
||||||
|
{
|
||||||
|
// A hardcoded delay of 50 ms before switching transition type is
|
||||||
|
// necessary due to OBS_FRONTEND_EVENT_SCENE_CHANGED seemingly firing a
|
||||||
|
// bit too early and thus leading to canceled transitions.
|
||||||
|
//
|
||||||
|
// The same is to be the case for OBS_FRONTEND_EVENT_TRANSITION_STOPPED.
|
||||||
|
//
|
||||||
|
// 50 ms was chosen as it seems to avoid the problem mentioned above and
|
||||||
|
// becuase that is the minimum value which can be chosen for the scene
|
||||||
|
// switcher's check interval.
|
||||||
|
// Thus it can be made sure that the delayed setting of the transition
|
||||||
|
// does not interfere with any new scene changes triggered by the scene
|
||||||
|
// switcher
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||||
|
|
||||||
|
obs_source_t *transitionSource = obs_weak_source_get_source(transition);
|
||||||
|
obs_frontend_set_current_transition(transitionSource);
|
||||||
|
obs_source_release(transitionSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefaultSceneTransition::setTransition()
|
||||||
|
{
|
||||||
|
std::thread t;
|
||||||
|
t = std::thread(setTransitionDelayed, transition);
|
||||||
|
t.detach();
|
||||||
|
}
|
||||||
|
|||||||
@@ -43,6 +43,16 @@ void SwitcherData::Prune()
|
|||||||
sceneSequenceSwitches.erase(
|
sceneSequenceSwitches.erase(
|
||||||
sceneSequenceSwitches.begin() + i--);
|
sceneSequenceSwitches.begin() + i--);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto cur = &s;
|
||||||
|
while (cur != nullptr) {
|
||||||
|
if (cur->extendedSequence &&
|
||||||
|
!cur->extendedSequence->valid()) {
|
||||||
|
cur->extendedSequence.reset(nullptr);
|
||||||
|
s.activeSequence = nullptr;
|
||||||
|
}
|
||||||
|
cur = cur->extendedSequence.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < sceneTransitions.size(); i++) {
|
for (size_t i = 0; i < sceneTransitions.size(); i++) {
|
||||||
|
|||||||
Reference in New Issue
Block a user