diff --git a/CMakeLists.txt b/CMakeLists.txt index 6ac49323..34c17860 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,26 +36,40 @@ if(BUILD_OUT_OF_TREE) src/headers/switcher-data-structs.hpp src/headers/utility.hpp src/headers/curl-helper.hpp + src/headers/switch-audio.hpp + src/headers/switch-executable.hpp + src/headers/switch-file.hpp + src/headers/switch-idle.hpp + src/headers/switch-media.hpp + src/headers/switch-random.hpp + src/headers/switch-screen-region.hpp + src/headers/switch-time.hpp + src/headers/switch-transitions.hpp + src/headers/switch-window.hpp + src/headers/swtich-sequence.hpp + src/headers/switch-generic.hpp ) set(advanced-scene-switcher_SOURCES ${advanced-scene-switcher_SOURCES} src/advanced-scene-switcher.cpp src/advanced-scene-switcher-module.c - src/scene-transitions.cpp - src/screen-region-switch.cpp - src/priority.cpp - src/executable-switch.cpp - src/idle-switch.cpp - src/scene-round-trip.cpp - src/file-switch.cpp - src/window-title-switch.cpp - src/media-switch.cpp + src/switcher-data-structs.cpp + src/switch-transitions.cpp + src/switch-screen-region.cpp + src/switch-priority.cpp + src/switch-executable.cpp + src/switch-idle.cpp + src/switch-sequence.cpp + src/switch-file.cpp + src/switch-window.cpp + src/switch-media.cpp src/hotkey.cpp src/general.cpp - src/pause-switch.cpp - src/random.cpp - src/time-switch.cpp + src/switch-pause.cpp + src/switch-random.cpp + src/switch-time.cpp + src/switch-audio.cpp src/curl-helper.cpp ) @@ -170,27 +184,40 @@ else () src/headers/utility.hpp src/headers/curl-helper.hpp src/headers/volume-control.hpp + src/headers/switch-audio.hpp + src/headers/switch-executable.hpp + src/headers/switch-file.hpp + src/headers/switch-idle.hpp + src/headers/switch-media.hpp + src/headers/switch-random.hpp + src/headers/switch-screen-region.hpp + src/headers/switch-time.hpp + src/headers/switch-transitions.hpp + src/headers/switch-window.hpp + src/headers/swtich-sequence.hpp + src/headers/switch-generic.hpp ) set(advanced-scene-switcher_SOURCES ${advanced-scene-switcher_SOURCES} src/advanced-scene-switcher.cpp src/advanced-scene-switcher-module.c - src/scene-transitions.cpp - src/screen-region-switch.cpp - src/priority.cpp - src/executable-switch.cpp - src/idle-switch.cpp - src/scene-round-trip.cpp - src/file-switch.cpp - src/window-title-switch.cpp - src/media-switch.cpp + src/switcher-data-structs.cpp + src/switch-transitions.cpp + src/switch-screen-region.cpp + src/switch-priority.cpp + src/switch-executable.cpp + src/switch-idle.cpp + src/switch-sequence.cpp + src/switch-file.cpp + src/switch-window.cpp + src/switch-media.cpp src/hotkey.cpp src/general.cpp - src/pause-switch.cpp - src/random.cpp - src/time-switch.cpp - src/audio-switch.cpp + src/switch-pause.cpp + src/switch-random.cpp + src/switch-time.cpp + src/switch-audio.cpp src/curl-helper.cpp src/volume-control.cpp ) diff --git a/forms/advanced-scene-switcher.ui b/forms/advanced-scene-switcher.ui index 102544ad..ea4f2908 100644 --- a/forms/advanced-scene-switcher.ui +++ b/forms/advanced-scene-switcher.ui @@ -1246,14 +1246,21 @@ - only if fullscreen + if fullscreen + + + + + + + if maximized - only if focused + if focused @@ -3359,7 +3366,7 @@ - + Sequence @@ -3374,7 +3381,7 @@ - + 0 @@ -3397,7 +3404,7 @@ - + 0 @@ -3420,7 +3427,7 @@ - + @@ -3430,7 +3437,7 @@ - + @@ -3440,7 +3447,7 @@ - + @@ -3465,7 +3472,7 @@ - + 0 @@ -3480,7 +3487,7 @@ - + 22 @@ -3496,7 +3503,7 @@ - + 22 @@ -3551,7 +3558,7 @@ - + 22 @@ -3574,7 +3581,7 @@ - + 22 @@ -3627,14 +3634,14 @@ - + Save Round Trips to file - + Load Round Trips from file diff --git a/src/advanced-scene-switcher.cpp b/src/advanced-scene-switcher.cpp index 404ae893..b246eef6 100644 --- a/src/advanced-scene-switcher.cpp +++ b/src/advanced-scene-switcher.cpp @@ -112,7 +112,7 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *) switcher->saveWindowTitleSwitches(obj); switcher->saveScreenRegionSwitches(obj); switcher->savePauseSwitches(obj); - switcher->saveSceneRoundTripSwitches(obj); + switcher->saveSceneSequenceSwitches(obj); switcher->saveSceneTransitions(obj); switcher->saveIdleSwitches(obj); switcher->saveExecutableSwitches(obj); @@ -138,7 +138,7 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *) switcher->loadWindowTitleSwitches(obj); switcher->loadScreenRegionSwitches(obj); switcher->loadPauseSwitches(obj); - switcher->loadSceneRoundTripSwitches(obj); + switcher->loadSceneSequenceSwitches(obj); switcher->loadSceneTransitions(obj); switcher->loadIdleSwitches(obj); switcher->loadExecutableSwitches(obj); @@ -153,9 +153,11 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *) switcher->m.unlock(); - if (switcher->stop) - switcher->Stop(); - else + // stop the scene switcher at least once + // to avoid issues with scene collection changes + bool start = !switcher->stop; + switcher->Stop(); + if (start) switcher->Start(); } } @@ -166,9 +168,6 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *) void SwitcherData::Thread() { blog(LOG_INFO, "Advanced Scene Switcher started"); - //to avoid scene duplication when rapidly switching scene collection - std::this_thread::sleep_for(std::chrono::seconds(2)); - int sleep = 0; while (true) { @@ -237,7 +236,7 @@ void SwitcherData::Thread() transition); break; case round_trip_func: - checkSceneRoundTrip(match, scene, transition, + checkSceneSequence(match, scene, transition, lock); if (sceneChangedDuringWait()) //scene might have changed during the sleep { diff --git a/src/curl-helper.cpp b/src/curl-helper.cpp index b6cfd527..4e54400f 100644 --- a/src/curl-helper.cpp +++ b/src/curl-helper.cpp @@ -15,7 +15,8 @@ QLibrary *loaded_curl_lib = nullptr; bool resolveCurl() { f_curl_init = (initFunction)loaded_curl_lib->resolve("curl_easy_init"); - f_curl_setopt = (setOptFunction)loaded_curl_lib->resolve("curl_easy_setopt"); + f_curl_setopt = + (setOptFunction)loaded_curl_lib->resolve("curl_easy_setopt"); f_curl_perform = (performFunction)loaded_curl_lib->resolve("curl_easy_perform"); f_curl_cleanup = @@ -43,7 +44,8 @@ bool loadCurl() for (QString path : locations) { blog(LOG_INFO, "trying '%s'", path.toUtf8().constData()); - QFileInfo libPath(QDir(path).absoluteFilePath(CURL_LIBRARY_NAME)); + QFileInfo libPath( + QDir(path).absoluteFilePath(curl_library_name)); if (libPath.exists() && libPath.isFile()) { QString libFilePath = libPath.absoluteFilePath(); diff --git a/src/general.cpp b/src/general.cpp index 76399740..6111a74c 100644 --- a/src/general.cpp +++ b/src/general.cpp @@ -257,7 +257,7 @@ void SceneSwitcher::on_exportSettings_clicked() switcher->saveWindowTitleSwitches(obj); switcher->saveScreenRegionSwitches(obj); switcher->savePauseSwitches(obj); - switcher->saveSceneRoundTripSwitches(obj); + switcher->saveSceneSequenceSwitches(obj); switcher->saveSceneTransitions(obj); switcher->saveIdleSwitches(obj); switcher->saveExecutableSwitches(obj); @@ -302,7 +302,7 @@ void SceneSwitcher::on_importSettings_clicked() switcher->loadWindowTitleSwitches(obj); switcher->loadScreenRegionSwitches(obj); switcher->loadPauseSwitches(obj); - switcher->loadSceneRoundTripSwitches(obj); + switcher->loadSceneSequenceSwitches(obj); switcher->loadSceneTransitions(obj); switcher->loadIdleSwitches(obj); switcher->loadExecutableSwitches(obj); @@ -674,7 +674,7 @@ void SceneSwitcher::setupGeneralTab() item->setData(Qt::UserRole, text); } - for (int i = 0; i < switcher->threadPriorities.size(); ++i) { + for (int i = 0; i < (int)switcher->threadPriorities.size(); ++i) { ui->threadPriority->addItem( switcher->threadPriorities[i].name.c_str()); ui->threadPriority->setItemData( diff --git a/src/headers/advanced-scene-switcher.hpp b/src/headers/advanced-scene-switcher.hpp index 0f5e04a4..8dc31914 100644 --- a/src/headers/advanced-scene-switcher.hpp +++ b/src/headers/advanced-scene-switcher.hpp @@ -37,7 +37,7 @@ public: int PauseScenesFindByData(const QString &scene); int PauseWindowsFindByData(const QString &window); int IgnoreWindowsFindByData(const QString &window); - int SceneRoundTripFindByData(const QString &scene1); + int SceneSequenceFindByData(const QString &scene1); int SceneTransitionsFindByData(const QString &scene1, const QString &scene2); int DefaultTransitionsFindByData(const QString &scene); @@ -106,14 +106,14 @@ public slots: void on_ignoreWindowsAdd_clicked(); void on_ignoreWindowsRemove_clicked(); - void on_sceneRoundTrips_currentRowChanged(int idx); - void on_sceneRoundTripAdd_clicked(); - void on_sceneRoundTripRemove_clicked(); - void on_sceneRoundTripSave_clicked(); - void on_sceneRoundTripLoad_clicked(); - void on_sceneRoundTripUp_clicked(); - void on_sceneRoundTripDown_clicked(); - void on_sceneRoundTripDelayUnits_currentIndexChanged(int index); + void on_sceneSequences_currentRowChanged(int idx); + void on_sceneSequenceAdd_clicked(); + void on_sceneSequenceRemove_clicked(); + void on_sceneSequenceSave_clicked(); + void on_sceneSequenceLoad_clicked(); + void on_sceneSequenceUp_clicked(); + void on_sceneSequenceDown_clicked(); + void on_sceneSequenceDelayUnits_currentIndexChanged(int index); void on_autoStopSceneCheckBox_stateChanged(int state); void on_autoStopScenes_currentTextChanged(const QString &text); @@ -205,6 +205,7 @@ void GetWindowList(std::vector &windows); void GetWindowList(QStringList &windows); // Overloaded void GetCurrentWindowTitle(std::string &title); bool isFullscreen(std::string &title); +bool isMaximized(std::string &title); /******************************************************************************** * Screenregion helper diff --git a/src/headers/curl-helper.hpp b/src/headers/curl-helper.hpp index 80a447e1..d8496cc0 100644 --- a/src/headers/curl-helper.hpp +++ b/src/headers/curl-helper.hpp @@ -3,11 +3,11 @@ #include #if defined(WIN32) -#define CURL_LIBRARY_NAME "libcurl.dll" +constexpr auto curl_library_name = "libcurl.dll"; #elif __APPLE__ -#define CURL_LIBRARY_NAME "libcurl.4.dylib" +#define curl_library_name "libcurl.4.dylib" #else -#define CURL_LIBRARY_NAME "libcurl.so.4" +#define curl_library_name "libcurl.so.4" #endif typedef CURL *(*initFunction)(void); diff --git a/src/headers/switch-audio.hpp b/src/headers/switch-audio.hpp new file mode 100644 index 00000000..d7627fb9 --- /dev/null +++ b/src/headers/switch-audio.hpp @@ -0,0 +1,115 @@ +#pragma once +#include +#include "utility.hpp" +#include "switch-generic.hpp" + +constexpr auto audio_func = 8; +constexpr auto default_priority_8 = audio_func; + +struct AudioSwitch : virtual SceneSwitcherEntry { + OBSWeakSource audioSource; + int volumeThreshold; + float peak; + std::string audioSwitchStr; + obs_volmeter_t *volmeter; + + const char *getType() { return "audio"; } + + static void setVolumeLevel(void *data, + const float magnitude[MAX_AUDIO_CHANNELS], + const float peak[MAX_AUDIO_CHANNELS], + const float inputPeak[MAX_AUDIO_CHANNELS]) + { + UNUSED_PARAMETER(magnitude); + UNUSED_PARAMETER(inputPeak); + AudioSwitch *s = static_cast(data); + + s->peak = peak[0]; + for (int i = 1; i < MAX_AUDIO_CHANNELS; i++) + if (peak[i] > s->peak) + s->peak = peak[i]; + } + + bool valid() + { + return (usePreviousScene || WeakSourceValid(scene)) && + WeakSourceValid(audioSource) && + WeakSourceValid(transition); + } + + inline AudioSwitch(OBSWeakSource scene_, OBSWeakSource transition_, + OBSWeakSource audioSource_, int volumeThreshold_, + bool usePreviousScene_, std::string audioSwitchStr_) + : SceneSwitcherEntry(scene_, transition_, usePreviousScene_), + audioSource(audioSource_), + volumeThreshold(volumeThreshold_), + audioSwitchStr(audioSwitchStr_) + { + volmeter = obs_volmeter_create(OBS_FADER_LOG); + obs_volmeter_add_callback(volmeter, setVolumeLevel, this); + obs_source_t *as = obs_weak_source_get_source(audioSource); + if (!obs_volmeter_attach_source(volmeter, as)) { + const char *name = obs_source_get_name(as); + blog(LOG_WARNING, + "failed to attach volmeter to source %s", name); + } + obs_source_release(as); + } + + AudioSwitch(const AudioSwitch &other) + : SceneSwitcherEntry(other.scene, other.transition, + other.usePreviousScene), + audioSource(other.audioSource), + volumeThreshold(other.volumeThreshold), + audioSwitchStr(other.audioSwitchStr) + { + volmeter = obs_volmeter_create(OBS_FADER_LOG); + obs_volmeter_add_callback(volmeter, setVolumeLevel, this); + obs_source_t *as = + obs_weak_source_get_source(other.audioSource); + if (!obs_volmeter_attach_source(volmeter, as)) { + const char *name = obs_source_get_name(as); + blog(LOG_WARNING, + "failed to attach volmeter to source %s", name); + } + obs_source_release(as); + } + + AudioSwitch(AudioSwitch &&other) + : SceneSwitcherEntry(other.scene, other.transition, + other.usePreviousScene), + audioSource(other.audioSource), + volumeThreshold(other.volumeThreshold), + audioSwitchStr(other.audioSwitchStr), + volmeter(other.volmeter) + { + other.volmeter = nullptr; + } + + inline ~AudioSwitch() + { + obs_volmeter_remove_callback(volmeter, setVolumeLevel, this); + obs_volmeter_destroy(volmeter); + } + + AudioSwitch &operator=(const AudioSwitch &other) + { + return *this = AudioSwitch(other); + } + + AudioSwitch &operator=(AudioSwitch &&other) noexcept + { + if (this == &other) { + return *this; + } + obs_volmeter_destroy(volmeter); + volmeter = other.volmeter; + other.volmeter = nullptr; + return *this; + } +}; + +static inline QString MakeAudioSwitchName(const QString &scene, + const QString &transition, + const QString &audioSrouce, + const int &volume); diff --git a/src/headers/switch-executable.hpp b/src/headers/switch-executable.hpp new file mode 100644 index 00000000..05400534 --- /dev/null +++ b/src/headers/switch-executable.hpp @@ -0,0 +1,28 @@ +#pragma once +#include +#include "utility.hpp" +#include "switch-generic.hpp" + +constexpr auto exe_func = 3; +constexpr auto default_priority_3 = exe_func; + +struct ExecutableSceneSwitch : SceneSwitcherEntry { + QString exe; + bool inFocus; + + const char *getType() { return "exec"; } + + inline ExecutableSceneSwitch(OBSWeakSource scene_, + OBSWeakSource transition_, + const QString &exe_, bool inFocus_) + : SceneSwitcherEntry(scene_, transition_), + exe(exe_), + inFocus(inFocus_) + { + } +}; + +static inline QString MakeSwitchNameExecutable(const QString &scene, + const QString &value, + const QString &transition, + bool inFocus); diff --git a/src/headers/switch-file.hpp b/src/headers/switch-file.hpp new file mode 100644 index 00000000..b2ff7f0e --- /dev/null +++ b/src/headers/switch-file.hpp @@ -0,0 +1,44 @@ +#pragma once +#include +#include "utility.hpp" +#include "switch-generic.hpp" + +constexpr auto read_file_func = 0; +constexpr auto default_priority_0 = read_file_func; + +struct FileSwitch : SceneSwitcherEntry { + std::string file; + std::string text; + bool remote = false; + bool useRegex = false; + bool useTime = false; + QDateTime lastMod; + + const char *getType() { return "file"; } + + inline FileSwitch(OBSWeakSource scene_, OBSWeakSource transition_, + const char *file_, const char *text_, bool remote_, + bool useRegex_, bool useTime_) + : SceneSwitcherEntry(scene_, transition_), + file(file_), + text(text_), + remote(remote_), + useRegex(useRegex_), + useTime(useTime_), + lastMod() + { + } +}; + +struct FileIOData { + bool readEnabled = false; + std::string readPath; + bool writeEnabled = false; + std::string writePath; +}; + +static inline QString MakeFileSwitchName(const QString &scene, + const QString &transition, + const QString &fileName, + const QString &text, bool useRegex, + bool useTime); diff --git a/src/headers/switch-generic.hpp b/src/headers/switch-generic.hpp new file mode 100644 index 00000000..6a932f4a --- /dev/null +++ b/src/headers/switch-generic.hpp @@ -0,0 +1,48 @@ +#pragma once +#include +#include + +struct SceneSwitcherEntry { + OBSWeakSource scene; + OBSWeakSource transition; + bool usePreviousScene; + + virtual bool valid() + { + return (usePreviousScene || WeakSourceValid(scene)) && + WeakSourceValid(transition); + } + + virtual const char *getType() = 0; + + // TODO + //virtual bool checkMatch() = 0; + + virtual void logMatch() + { + obs_source_t *s = obs_weak_source_get_source(scene); + const char *sceneName = obs_source_get_name(s); + obs_source_release(s); + blog(LOG_INFO, + "Advanced Scene Switcher match for '%s' - switch to scene '%s'", + getType(), sceneName); + } + + inline SceneSwitcherEntry() : usePreviousScene(false) {} + + inline SceneSwitcherEntry(OBSWeakSource scene_, + OBSWeakSource transition_, + bool usePreviousScene_) + : scene(scene_), + transition(transition_), + usePreviousScene(usePreviousScene_) + { + } + inline SceneSwitcherEntry(OBSWeakSource scene_, + OBSWeakSource transition_) + : scene(scene_), + transition(transition_), + usePreviousScene(false) + { + } +}; diff --git a/src/headers/switch-idle.hpp b/src/headers/switch-idle.hpp new file mode 100644 index 00000000..f7559ae6 --- /dev/null +++ b/src/headers/switch-idle.hpp @@ -0,0 +1,16 @@ +#pragma once +#include +#include "utility.hpp" +#include "switch-generic.hpp" + +constexpr auto default_idle_time = 60; +constexpr auto idle_func = 2; +constexpr auto default_priority_2 = idle_func; + +struct IdleData : SceneSwitcherEntry { + bool idleEnable = false; + int time = default_idle_time; + bool alreadySwitched = false; + + const char *getType() { return "idle"; } +}; diff --git a/src/headers/switch-media.hpp b/src/headers/switch-media.hpp new file mode 100644 index 00000000..8b9f1a2f --- /dev/null +++ b/src/headers/switch-media.hpp @@ -0,0 +1,50 @@ +#pragma once +#include +#include "utility.hpp" +#include "switch-generic.hpp" + +constexpr auto media_func = 6; +constexpr auto default_priority_6 = media_func; + +typedef enum { + TIME_RESTRICTION_NONE, + TIME_RESTRICTION_SHORTER, + TIME_RESTRICTION_LONGER, + TIME_RESTRICTION_REMAINING_SHORTER, + TIME_RESTRICTION_REMAINING_LONGER, +} time_restriction; + +struct MediaSwitch : SceneSwitcherEntry { + OBSWeakSource source; + obs_media_state state; + time_restriction restriction; + int64_t time; + bool matched; + std::string mediaSwitchStr; + + const char *getType() { return "meida"; } + + bool valid() + { + return (usePreviousScene || WeakSourceValid(scene)) && + WeakSourceValid(source) && WeakSourceValid(transition); + } + + inline MediaSwitch(OBSWeakSource scene_, OBSWeakSource source_, + OBSWeakSource transition_, obs_media_state state_, + time_restriction restriction_, uint64_t time_, + bool usePreviousScene_, std::string mediaSwitchStr_) + : SceneSwitcherEntry(scene_, transition_, usePreviousScene_), + source(source_), + state(state_), + restriction(restriction_), + time(time_), + mediaSwitchStr(mediaSwitchStr_) + { + } +}; + +static inline QString +MakeMediaSwitchName(const QString &source, const QString &scene, + const QString &transition, obs_media_state state, + time_restriction restriction, uint64_t time); diff --git a/src/headers/switch-random.hpp b/src/headers/switch-random.hpp new file mode 100644 index 00000000..7090aa56 --- /dev/null +++ b/src/headers/switch-random.hpp @@ -0,0 +1,23 @@ +#pragma once +#include +#include "utility.hpp" +#include "switch-generic.hpp" + +struct RandomSwitch : SceneSwitcherEntry { + double delay; + std::string randomSwitchStr; + + const char *getType() { return "random"; } + + inline RandomSwitch(OBSWeakSource scene_, OBSWeakSource transition_, + double delay_, std::string str) + : SceneSwitcherEntry(scene_, transition_), + delay(delay_), + randomSwitchStr(str) + { + } +}; + +static inline QString MakeRandomSwitchName(const QString &scene, + const QString &transition, + double &delay); diff --git a/src/headers/switch-screen-region.hpp b/src/headers/switch-screen-region.hpp new file mode 100644 index 00000000..717f2c58 --- /dev/null +++ b/src/headers/switch-screen-region.hpp @@ -0,0 +1,32 @@ +#pragma once +#include +#include "utility.hpp" +#include "switch-generic.hpp" + +constexpr auto screen_region_func = 4; +constexpr auto default_priority_4 = screen_region_func; + +struct ScreenRegionSwitch : SceneSwitcherEntry { + int minX, minY, maxX, maxY; + std::string regionStr; + + const char *getType() { return "region"; } + + inline ScreenRegionSwitch(OBSWeakSource scene_, + OBSWeakSource transition_, int minX_, + int minY_, int maxX_, int maxY_, + std::string regionStr_) + : SceneSwitcherEntry(scene_, transition_), + minX(minX_), + minY(minY_), + maxX(maxX_), + maxY(maxY_), + regionStr(regionStr_) + { + } +}; + +static inline QString MakeScreenRegionSwitchName(const QString &scene, + const QString &transition, + int minX, int minY, int maxX, + int maxY); diff --git a/src/headers/switch-time.hpp b/src/headers/switch-time.hpp new file mode 100644 index 00000000..98c2f867 --- /dev/null +++ b/src/headers/switch-time.hpp @@ -0,0 +1,43 @@ +#pragma once +#include +#include +#include "utility.hpp" +#include "switch-generic.hpp" + +constexpr auto time_func = 7; +constexpr auto default_priority_7 = time_func; + +typedef enum { + ANY_DAY = 0, + MONDAY = 1, + TUSEDAY = 2, + WEDNESDAY = 3, + THURSDAY = 4, + FRIDAY = 5, + SATURDAY = 6, + SUNDAY = 7, + LIVE = 8 +} timeTrigger; + +struct TimeSwitch : SceneSwitcherEntry { + timeTrigger trigger; + QTime time; + std::string timeSwitchStr; + + const char *getType() { return "time"; } + + inline TimeSwitch(OBSWeakSource scene_, OBSWeakSource transition_, + timeTrigger trigger_, QTime time_, + bool usePreviousScene_, std::string timeSwitchStr_) + : SceneSwitcherEntry(scene_, transition_, usePreviousScene_), + trigger(trigger_), + time(time_), + timeSwitchStr(timeSwitchStr_) + { + } +}; + +static inline QString MakeTimeSwitchName(const QString &scene, + const QString &transition, + const timeTrigger &trigger, + const QTime &time); diff --git a/src/headers/switch-transitions.hpp b/src/headers/switch-transitions.hpp new file mode 100644 index 00000000..12c9e038 --- /dev/null +++ b/src/headers/switch-transitions.hpp @@ -0,0 +1,47 @@ +#pragma once +#include +#include "utility.hpp" +#include "switch-generic.hpp" + +struct SceneTransition : SceneSwitcherEntry { + OBSWeakSource scene2; + std::string sceneTransitionStr; + + const char *getType() { return "transition"; } + + bool valid() + { + return (WeakSourceValid(scene) && WeakSourceValid(scene2)) && + WeakSourceValid(transition); + } + + inline SceneTransition(OBSWeakSource scene_, OBSWeakSource scene2_, + OBSWeakSource transition_, + std::string sceneTransitionStr_) + : SceneSwitcherEntry(scene_, transition_), + scene2(scene2_), + sceneTransitionStr(sceneTransitionStr_) + { + } +}; + +static inline QString MakeSceneTransitionName(const QString &scene1, + const QString &scene2, + const QString &transition); + +struct DefaultSceneTransition : SceneSwitcherEntry { + std::string sceneTransitionStr; + + const char *getType() { return "def_transition"; } + + inline DefaultSceneTransition(OBSWeakSource scene_, + OBSWeakSource transition_, + std::string sceneTransitionStr_) + : SceneSwitcherEntry(scene_, transition_), + sceneTransitionStr(sceneTransitionStr_) + { + } +}; + +static inline QString MakeDefaultSceneTransitionName(const QString &scene, + const QString &transition); diff --git a/src/headers/switch-window.hpp b/src/headers/switch-window.hpp new file mode 100644 index 00000000..16b91702 --- /dev/null +++ b/src/headers/switch-window.hpp @@ -0,0 +1,33 @@ +#pragma once +#include +#include "utility.hpp" +#include "switch-generic.hpp" + +constexpr auto window_title_func = 5; +constexpr auto default_priority_5 = window_title_func; + +struct WindowSceneSwitch : SceneSwitcherEntry { + std::string window; + bool fullscreen; + bool maximized; + bool focus; + + const char *getType() { return "window"; } + + inline WindowSceneSwitch(OBSWeakSource scene_, const char *window_, + OBSWeakSource transition_, bool fullscreen_, + bool maximized_, bool focus_) + : SceneSwitcherEntry(scene_, transition_), + window(window_), + fullscreen(fullscreen_), + maximized(maximized_), + focus(focus_) + { + } +}; + +static inline QString MakeWindowSwitchName(const QString &scene, + const QString &value, + const QString &transition, + bool fullscreen, bool maximized, + bool focus); diff --git a/src/headers/switcher-data-structs.hpp b/src/headers/switcher-data-structs.hpp index 3cca3761..b87b25e9 100644 --- a/src/headers/switcher-data-structs.hpp +++ b/src/headers/switcher-data-structs.hpp @@ -1,362 +1,27 @@ #pragma once #include -#include #include #include -#include #include -#include #include #include #include -#include "utility.hpp" + +#include "switch-audio.hpp" +#include "switch-executable.hpp" +#include "switch-file.hpp" +#include "switch-idle.hpp" +#include "switch-media.hpp" +#include "switch-random.hpp" +#include "switch-screen-region.hpp" +#include "switch-time.hpp" +#include "switch-transitions.hpp" +#include "switch-window.hpp" +#include "swtich-sequence.hpp" constexpr auto default_interval = 300; - -constexpr auto default_idle_time = 60; - constexpr auto previous_scene_name = "Previous Scene"; -constexpr auto read_file_func = 0; -constexpr auto round_trip_func = 1; -constexpr auto idle_func = 2; -constexpr auto exe_func = 3; -constexpr auto screen_region_func = 4; -constexpr auto window_title_func = 5; -constexpr auto media_func = 6; -constexpr auto time_func = 7; -constexpr auto audio_func = 8; - -constexpr auto default_priority_0 = read_file_func; -constexpr auto default_priority_1 = round_trip_func; -constexpr auto default_priority_2 = idle_func; -constexpr auto default_priority_3 = exe_func; -constexpr auto default_priority_4 = screen_region_func; -constexpr auto default_priority_5 = window_title_func; -constexpr auto default_priority_6 = media_func; -constexpr auto default_priority_7 = time_func; -constexpr auto default_priority_8 = audio_func; - -/******************************************************************************** - * Data structs for each scene switching method - ********************************************************************************/ -struct WindowSceneSwitch { - OBSWeakSource scene; - std::string window; - OBSWeakSource transition; - bool fullscreen; - bool focus; - - inline WindowSceneSwitch(OBSWeakSource scene_, const char *window_, - OBSWeakSource transition_, bool fullscreen_, - bool focus_) - : scene(scene_), - window(window_), - transition(transition_), - fullscreen(fullscreen_), - focus(focus_) - { - } -}; - -struct ExecutableSceneSwitch { - OBSWeakSource mScene; - OBSWeakSource mTransition; - QString mExe; - bool mInFocus; - - inline ExecutableSceneSwitch(OBSWeakSource scene, - OBSWeakSource transition, - const QString &exe, bool inFocus) - : mScene(scene), - mTransition(transition), - mExe(exe), - mInFocus(inFocus) - { - } -}; - -struct ScreenRegionSwitch { - OBSWeakSource scene; - OBSWeakSource transition; - int minX, minY, maxX, maxY; - std::string regionStr; - - inline ScreenRegionSwitch(OBSWeakSource scene_, - OBSWeakSource transition_, int minX_, - int minY_, int maxX_, int maxY_, - std::string regionStr_) - : scene(scene_), - transition(transition_), - minX(minX_), - minY(minY_), - maxX(maxX_), - maxY(maxY_), - regionStr(regionStr_) - { - } -}; - -struct SceneRoundTripSwitch { - OBSWeakSource scene1; - OBSWeakSource scene2; - OBSWeakSource transition; - double delay; - bool usePreviousScene; - std::string sceneRoundTripStr; - - inline SceneRoundTripSwitch(OBSWeakSource scene1_, - OBSWeakSource scene2_, - OBSWeakSource transition_, double delay_, - bool usePreviousScene_, std::string str) - : scene1(scene1_), - scene2(scene2_), - transition(transition_), - delay(delay_), - usePreviousScene(usePreviousScene_), - sceneRoundTripStr(str) - { - } -}; - -struct RandomSwitch { - OBSWeakSource scene; - OBSWeakSource transition; - double delay; - std::string randomSwitchStr; - - inline RandomSwitch(OBSWeakSource scene_, OBSWeakSource transition_, - double delay_, std::string str) - : scene(scene_), - transition(transition_), - delay(delay_), - randomSwitchStr(str) - { - } -}; - -struct SceneTransition { - OBSWeakSource scene1; - OBSWeakSource scene2; - OBSWeakSource transition; - std::string sceneTransitionStr; - - inline SceneTransition(OBSWeakSource scene1_, OBSWeakSource scene2_, - OBSWeakSource transition_, - std::string sceneTransitionStr_) - : scene1(scene1_), - scene2(scene2_), - transition(transition_), - sceneTransitionStr(sceneTransitionStr_) - { - } -}; - -struct DefaultSceneTransition { - OBSWeakSource scene; - OBSWeakSource transition; - std::string sceneTransitionStr; - - inline DefaultSceneTransition(OBSWeakSource scene_, - OBSWeakSource transition_, - std::string sceneTransitionStr_) - : scene(scene_), - transition(transition_), - sceneTransitionStr(sceneTransitionStr_) - { - } -}; - -struct FileSwitch { - OBSWeakSource scene; - OBSWeakSource transition; - std::string file; - std::string text; - bool remote = false; - bool useRegex = false; - bool useTime = false; - QDateTime lastMod; - - inline FileSwitch(OBSWeakSource scene_, OBSWeakSource transition_, - const char *file_, const char *text_, bool remote_, - bool useRegex_, bool useTime_) - : scene(scene_), - transition(transition_), - file(file_), - text(text_), - remote(remote_), - useRegex(useRegex_), - useTime(useTime_), - lastMod() - { - } -}; - -struct FileIOData { - bool readEnabled = false; - std::string readPath; - bool writeEnabled = false; - std::string writePath; -}; - -struct IdleData { - bool idleEnable = false; - int time = default_idle_time; - OBSWeakSource scene; - OBSWeakSource transition; - bool usePreviousScene; - bool alreadySwitched = false; -}; - -struct MediaSwitch { - OBSWeakSource scene; - OBSWeakSource source; - OBSWeakSource transition; - obs_media_state state; - int64_t time; - time_restriction restriction; - bool matched; - bool usePreviousScene; - std::string mediaSwitchStr; - - inline MediaSwitch(OBSWeakSource scene_, OBSWeakSource source_, - OBSWeakSource transition_, obs_media_state state_, - time_restriction restriction_, uint64_t time_, - bool usePreviousScene_, std::string mediaSwitchStr_) - : scene(scene_), - source(source_), - transition(transition_), - state(state_), - restriction(restriction_), - time(time_), - usePreviousScene(usePreviousScene_), - mediaSwitchStr(mediaSwitchStr_) - { - } -}; - -struct TimeSwitch { - OBSWeakSource scene; - OBSWeakSource transition; - timeTrigger trigger; - QTime time; - bool usePreviousScene; - std::string timeSwitchStr; - - inline TimeSwitch(OBSWeakSource scene_, OBSWeakSource transition_, - timeTrigger trigger_, QTime time_, - bool usePreviousScene_, std::string timeSwitchStr_) - : scene(scene_), - transition(transition_), - trigger(trigger_), - time(time_), - usePreviousScene(usePreviousScene_), - timeSwitchStr(timeSwitchStr_) - { - } -}; - -struct AudioSwitch { - OBSWeakSource scene; - OBSWeakSource audioSource; - OBSWeakSource transition; - int volumeThreshold; - float peak; - bool usePreviousScene; - obs_volmeter_t *volmeter; - std::string audioSwitchStr; - - static void setVolumeLevel(void *data, - const float magnitude[MAX_AUDIO_CHANNELS], - const float peak[MAX_AUDIO_CHANNELS], - const float inputPeak[MAX_AUDIO_CHANNELS]) - { - UNUSED_PARAMETER(magnitude); - UNUSED_PARAMETER(inputPeak); - AudioSwitch *s = static_cast(data); - - s->peak = peak[0]; - for (int i = 1; i < MAX_AUDIO_CHANNELS; i++) - if (peak[i] > s->peak) - s->peak = peak[i]; - } - - inline AudioSwitch(OBSWeakSource scene_, OBSWeakSource transition_, - OBSWeakSource audioSource_, int volumeThreshold_, - bool usePreviousScene_, std::string audioSwitchStr_) - : scene(scene_), - transition(transition_), - audioSource(audioSource_), - volumeThreshold(volumeThreshold_), - usePreviousScene(usePreviousScene_), - audioSwitchStr(audioSwitchStr_) - { - volmeter = obs_volmeter_create(OBS_FADER_LOG); - obs_volmeter_add_callback(volmeter, setVolumeLevel, this); - obs_source_t *as = obs_weak_source_get_source(audioSource); - if (!obs_volmeter_attach_source(volmeter, as)) { - const char *name = obs_source_get_name(as); - blog(LOG_WARNING, - "failed to attach volmeter to source %s", name); - } - obs_source_release(as); - } - - AudioSwitch(const AudioSwitch &other) - : scene(other.scene), - transition(other.transition), - audioSource(other.audioSource), - volumeThreshold(other.volumeThreshold), - usePreviousScene(other.usePreviousScene), - audioSwitchStr(other.audioSwitchStr) - { - volmeter = obs_volmeter_create(OBS_FADER_LOG); - obs_volmeter_add_callback(volmeter, setVolumeLevel, this); - obs_source_t *as = - obs_weak_source_get_source(other.audioSource); - if (!obs_volmeter_attach_source(volmeter, as)) { - const char *name = obs_source_get_name(as); - blog(LOG_WARNING, - "failed to attach volmeter to source %s", name); - } - obs_source_release(as); - } - - AudioSwitch(AudioSwitch &&other) - : scene(other.scene), - transition(other.transition), - audioSource(other.audioSource), - volumeThreshold(other.volumeThreshold), - usePreviousScene(other.usePreviousScene), - audioSwitchStr(other.audioSwitchStr), - volmeter(other.volmeter) - { - other.volmeter = nullptr; - } - - inline ~AudioSwitch() - { - obs_volmeter_remove_callback(volmeter, setVolumeLevel, this); - obs_volmeter_destroy(volmeter); - } - - AudioSwitch &operator=(const AudioSwitch &other) - { - return *this = AudioSwitch(other); - } - - AudioSwitch &operator=(AudioSwitch &&other) noexcept - { - if (this == &other) { - return *this; - } - obs_volmeter_destroy(volmeter); - volmeter = other.volmeter; - other.volmeter = nullptr; - return *this; - } -}; - typedef enum { NO_SWITCH = 0, SWITCH = 1, RANDOM_SWITCH = 2 } NoMatch; typedef enum { PERSIST = 0, START = 1, STOP = 2 } StartupBehavior; typedef enum { @@ -384,7 +49,7 @@ struct SwitcherData { int interval = default_interval; - obs_source_t *waitScene = NULL; //scene during which wait started + obs_source_t *waitScene = NULL; OBSWeakSource previousScene = NULL; OBSWeakSource PreviousScene2 = NULL; OBSWeakSource lastRandomScene; @@ -404,8 +69,8 @@ struct SwitcherData { std::vector ignoreWindowsSwitches; - std::vector sceneRoundTripSwitches; - int sceneRoundTripUnitMultiplier = 1; + std::vector sceneSequenceSwitches; + int sceneSequenceMultiplier = 1; std::vector randomSwitches; @@ -479,7 +144,7 @@ struct SwitcherData { void autoStopStreamAndRecording(); void autoStartStreamRecording(); bool checkPause(); - void checkSceneRoundTrip(bool &match, OBSWeakSource &scene, + void checkSceneSequence(bool &match, OBSWeakSource &scene, OBSWeakSource &transition, std::unique_lock &lock); void checkIdleSwitch(bool &match, OBSWeakSource &scene, @@ -506,7 +171,7 @@ struct SwitcherData { void saveWindowTitleSwitches(obs_data_t *obj); void saveScreenRegionSwitches(obs_data_t *obj); void savePauseSwitches(obs_data_t *obj); - void saveSceneRoundTripSwitches(obs_data_t *obj); + void saveSceneSequenceSwitches(obs_data_t *obj); void saveSceneTransitions(obs_data_t *obj); void saveIdleSwitches(obs_data_t *obj); void saveExecutableSwitches(obs_data_t *obj); @@ -520,7 +185,7 @@ struct SwitcherData { void loadWindowTitleSwitches(obs_data_t *obj); void loadScreenRegionSwitches(obs_data_t *obj); void loadPauseSwitches(obs_data_t *obj); - void loadSceneRoundTripSwitches(obs_data_t *obj); + void loadSceneSequenceSwitches(obs_data_t *obj); void loadSceneTransitions(obs_data_t *obj); void loadIdleSwitches(obs_data_t *obj); void loadExecutableSwitches(obs_data_t *obj); @@ -531,124 +196,7 @@ struct SwitcherData { void loadAudioSwitches(obs_data_t *obj); void loadGeneralSettings(obs_data_t *obj); - void Prune() - { - for (size_t i = 0; i < windowSwitches.size(); i++) { - WindowSceneSwitch &s = windowSwitches[i]; - if (!WeakSourceValid(s.scene) || - !WeakSourceValid(s.transition)) - windowSwitches.erase(windowSwitches.begin() + - i--); - } - - if (nonMatchingScene && !WeakSourceValid(nonMatchingScene)) { - 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]; - if (!WeakSourceValid(s.scene) || - !WeakSourceValid(s.transition)) - screenRegionSwitches.erase( - screenRegionSwitches.begin() + i--); - } - - for (size_t i = 0; i < pauseScenesSwitches.size(); i++) { - OBSWeakSource &scene = pauseScenesSwitches[i]; - if (!WeakSourceValid(scene)) - pauseScenesSwitches.erase( - pauseScenesSwitches.begin() + i--); - } - - for (size_t i = 0; i < sceneRoundTripSwitches.size(); i++) { - SceneRoundTripSwitch &s = sceneRoundTripSwitches[i]; - if (!WeakSourceValid(s.scene1) || - (!s.usePreviousScene && - !WeakSourceValid(s.scene2)) || - !WeakSourceValid(s.transition)) - sceneRoundTripSwitches.erase( - sceneRoundTripSwitches.begin() + i--); - } - - if (!WeakSourceValid(autoStopScene)) { - autoStopScene = nullptr; - autoStopEnable = false; - } - - for (size_t i = 0; i < sceneTransitions.size(); i++) { - SceneTransition &s = sceneTransitions[i]; - if (!WeakSourceValid(s.scene1) || - !WeakSourceValid(s.scene2) || - !WeakSourceValid(s.transition)) - sceneTransitions.erase( - sceneTransitions.begin() + i--); - } - - for (size_t i = 0; i < defaultSceneTransitions.size(); i++) { - DefaultSceneTransition &s = defaultSceneTransitions[i]; - if (!WeakSourceValid(s.scene) || - !WeakSourceValid(s.transition)) - defaultSceneTransitions.erase( - defaultSceneTransitions.begin() + i--); - } - - for (size_t i = 0; i < executableSwitches.size(); i++) { - ExecutableSceneSwitch &s = executableSwitches[i]; - if (!WeakSourceValid(s.mScene) || - !WeakSourceValid(s.mTransition)) - executableSwitches.erase( - executableSwitches.begin() + i--); - } - - for (size_t i = 0; i < fileSwitches.size(); i++) { - FileSwitch &s = fileSwitches[i]; - if (!WeakSourceValid(s.scene) || - !WeakSourceValid(s.transition)) - fileSwitches.erase(fileSwitches.begin() + i--); - } - - for (size_t i = 0; i < timeSwitches.size(); i++) { - TimeSwitch &s = timeSwitches[i]; - if ((!s.usePreviousScene && - !WeakSourceValid(s.scene)) || - !WeakSourceValid(s.transition)) - timeSwitches.erase(timeSwitches.begin() + i--); - } - - if (!idleData.usePreviousScene && - !WeakSourceValid(idleData.scene) || - !WeakSourceValid(idleData.transition)) { - idleData.idleEnable = false; - } - - for (size_t i = 0; i < mediaSwitches.size(); i++) { - MediaSwitch &s = mediaSwitches[i]; - if ((!s.usePreviousScene && - !WeakSourceValid(s.scene)) || - !WeakSourceValid(s.source) || - !WeakSourceValid(s.transition)) - mediaSwitches.erase(mediaSwitches.begin() + - i--); - } - - for (size_t i = 0; i < audioSwitches.size(); i++) { - AudioSwitch &s = audioSwitches[i]; - if ((!s.usePreviousScene && - !WeakSourceValid(s.scene)) || - !WeakSourceValid(s.transition)) - audioSwitches.erase(audioSwitches.begin() + - i--); - } - } + void Prune(); inline ~SwitcherData() { Stop(); } }; diff --git a/src/headers/swtich-sequence.hpp b/src/headers/swtich-sequence.hpp new file mode 100644 index 00000000..646ed8bb --- /dev/null +++ b/src/headers/swtich-sequence.hpp @@ -0,0 +1,44 @@ +#pragma once +#include +#include "utility.hpp" +#include "switch-generic.hpp" + +constexpr auto round_trip_func = 1; +constexpr auto default_priority_1 = round_trip_func; + +struct SceneSequenceSwitch : SceneSwitcherEntry { + OBSWeakSource startScene; + double delay; + std::string sceneSequenceStr; + + const char *getType() { return "sequence"; } + + bool valid() + { + return WeakSourceValid(startScene) && + (usePreviousScene || WeakSourceValid(scene)) && + WeakSourceValid(transition); + } + + void logSleep(int dur) + { + blog(LOG_INFO, "Advanced Scene Switcher sequence sleep %d", + dur); + } + + inline SceneSequenceSwitch(OBSWeakSource startScene_, + OBSWeakSource scene_, + OBSWeakSource transition_, double delay_, + bool usePreviousScene_, std::string str) + : SceneSwitcherEntry(scene_, transition_, usePreviousScene_), + startScene(startScene_), + delay(delay_), + sceneSequenceStr(str) + { + } +}; + +static inline QString MakeSceneSequenceSwitchName(const QString &scene1, + const QString &scene2, + const QString &transition, + double delay); diff --git a/src/headers/utility.hpp b/src/headers/utility.hpp index 6857fd07..6e8ff410 100644 --- a/src/headers/utility.hpp +++ b/src/headers/utility.hpp @@ -11,232 +11,6 @@ static inline bool WeakSourceValid(obs_weak_source_t *ws) return !!source; } -static inline QString MakeSwitchName(const QString &scene, const QString &value, - const QString &transition, bool fullscreen, - bool focus) -{ - QString name = QStringLiteral("[") + scene + QStringLiteral(", ") + - transition + QStringLiteral("]: ") + value; - - if (fullscreen || focus) { - name += QStringLiteral(" (only if"); - - if (fullscreen) - name += QStringLiteral(" fullscreen"); - if (fullscreen && focus) - name += QStringLiteral(" and"); - if (focus) - name += QStringLiteral(" focused"); - - name += QStringLiteral(")"); - } - - return name; -} - -static inline QString MakeSwitchNameExecutable(const QString &scene, - const QString &value, - const QString &transition, - bool inFocus) -{ - if (!inFocus) - return QStringLiteral("[") + scene + QStringLiteral(", ") + - transition + QStringLiteral("]: ") + value; - return QStringLiteral("[") + scene + QStringLiteral(", ") + transition + - QStringLiteral("]: ") + value + - QStringLiteral(" (only if focused)"); -} - -static inline QString MakeScreenRegionSwitchName(const QString &scene, - const QString &transition, - int minX, int minY, int maxX, - int maxY) -{ - return QStringLiteral("[") + scene + QStringLiteral(", ") + transition + - QStringLiteral("]: ") + QString::number(minX) + - QStringLiteral(", ") + QString::number(minY) + - QStringLiteral(" x ") + QString::number(maxX) + - QStringLiteral(", ") + QString::number(maxY); -} - -static inline QString MakeSceneRoundTripSwitchName(const QString &scene1, - const QString &scene2, - const QString &transition, - double delay) -{ - return scene1 + QStringLiteral(" -> wait for ") + - QString::number(delay) + QStringLiteral(" seconds -> ") + - scene2 + QStringLiteral(" (using ") + transition + - QStringLiteral(" transition)"); -} - -static inline QString MakeSceneTransitionName(const QString &scene1, - const QString &scene2, - const QString &transition) -{ - return scene1 + QStringLiteral(" --- ") + transition + - QStringLiteral(" --> ") + scene2; -} - -static inline QString MakeDefaultSceneTransitionName(const QString &scene, - const QString &transition) -{ - 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 QString MakeFileSwitchName(const QString &scene, - const QString &transition, - const QString &fileName, - const QString &text, bool useRegex, - bool useTime) -{ - QString switchName = QStringLiteral("Switch to ") + scene + - QStringLiteral(" using ") + transition + - QStringLiteral(" if ") + fileName; - if (useTime) - switchName += QStringLiteral(" was modified and"); - switchName += QStringLiteral(" contains"); - if (useRegex) - switchName += QStringLiteral(" (RegEx): \n\""); - else - switchName += QStringLiteral(": \n\""); - if (text.length() > 30) - switchName += text.left(27) + QStringLiteral("...\""); - else - switchName += text + QStringLiteral("\""); - - return switchName; -} - -typedef enum { - TIME_RESTRICTION_NONE, - TIME_RESTRICTION_SHORTER, - TIME_RESTRICTION_LONGER, - TIME_RESTRICTION_REMAINING_SHORTER, - TIME_RESTRICTION_REMAINING_LONGER, -} time_restriction; - -static inline QString -MakeMediaSwitchName(const QString &source, const QString &scene, - const QString &transition, obs_media_state state, - time_restriction restriction, uint64_t time) -{ - QString switchName = QStringLiteral("Switch to ") + scene + - QStringLiteral(" using ") + transition + - QStringLiteral(" if ") + source + - QStringLiteral(" state is "); - if (state == OBS_MEDIA_STATE_NONE) { - switchName += QStringLiteral("none"); - } else if (state == OBS_MEDIA_STATE_PLAYING) { - switchName += QStringLiteral("playing"); - } else if (state == OBS_MEDIA_STATE_OPENING) { - switchName += QStringLiteral("opening"); - } else if (state == OBS_MEDIA_STATE_BUFFERING) { - switchName += QStringLiteral("buffering"); - } else if (state == OBS_MEDIA_STATE_PAUSED) { - switchName += QStringLiteral("paused"); - } else if (state == OBS_MEDIA_STATE_STOPPED) { - switchName += QStringLiteral("stopped"); - } else if (state == OBS_MEDIA_STATE_ENDED) { - switchName += QStringLiteral("ended"); - } else if (state == OBS_MEDIA_STATE_ERROR) { - switchName += QStringLiteral("error"); - } - if (restriction == TIME_RESTRICTION_SHORTER) { - switchName += QStringLiteral(" and time shorter than "); - } else if (restriction == TIME_RESTRICTION_LONGER) { - switchName += QStringLiteral(" and time longer than "); - } else if (restriction == TIME_RESTRICTION_REMAINING_SHORTER) { - switchName += - QStringLiteral(" and time remaining shorter than "); - } else if (restriction == TIME_RESTRICTION_REMAINING_LONGER) { - switchName += - QStringLiteral(" and time remaining longer than "); - } - if (restriction != TIME_RESTRICTION_NONE) { - switchName += std::to_string(time).c_str(); - switchName += QStringLiteral(" ms"); - } - return switchName; -} - -typedef enum { - ANY_DAY = 0, - MONDAY = 1, - TUSEDAY = 2, - WEDNESDAY = 3, - THURSDAY = 4, - FRIDAY = 5, - SATURDAY = 6, - SUNDAY = 7, - LIVE = 8 -} timeTrigger; - -static inline QString MakeTimeSwitchName(const QString &scene, - const QString &transition, - const timeTrigger &trigger, - const QTime &time) -{ - QString switchName; - - switch (trigger) { - case ANY_DAY: - switchName = QStringLiteral("On any weekday"); - break; - case MONDAY: - switchName = QStringLiteral("Mondays"); - break; - case TUSEDAY: - switchName = QStringLiteral("Tusedays"); - break; - case WEDNESDAY: - switchName = QStringLiteral("Wednesdays"); - break; - case THURSDAY: - switchName = QStringLiteral("Thursdays"); - break; - case FRIDAY: - switchName = QStringLiteral("Fridays"); - break; - case SATURDAY: - switchName = QStringLiteral("Saturdays"); - break; - case SUNDAY: - switchName = QStringLiteral("Sundays"); - break; - case LIVE: - switchName = QStringLiteral( - "Relative to starting streaming / recording"); - break; - } - switchName += QStringLiteral(" at ") + time.toString() + - QStringLiteral(" switch to ") + scene + - QStringLiteral(" using ") + transition; - return switchName; -} - -static inline QString MakeAudioSwitchName(const QString &scene, - const QString &transition, - const QString &audioSrouce, - const int &volume) -{ - QString switchName = QStringLiteral("When volume of ") + audioSrouce + - QStringLiteral(" is above ") + - QString::number(volume) + - QStringLiteral("% switch to ") + scene + - QStringLiteral(" using ") + transition; - return switchName; -} - static inline std::string GetWeakSourceName(obs_weak_source_t *weak_source) { std::string name; diff --git a/src/hotkey.cpp b/src/hotkey.cpp index 4e4cae7a..8e9a599a 100644 --- a/src/hotkey.cpp +++ b/src/hotkey.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include "headers/advanced-scene-switcher.hpp" void startHotkeyFunc(void *data, obs_hotkey_id id, obs_hotkey_t *hotkey, diff --git a/src/linux/advanced-scene-switcher-nix.cpp b/src/linux/advanced-scene-switcher-nix.cpp index 253da9cd..16b63a25 100644 --- a/src/linux/advanced-scene-switcher-nix.cpp +++ b/src/linux/advanced-scene-switcher-nix.cpp @@ -247,6 +247,55 @@ std::pair getCursorPos() return pos; } +bool isMaximized(std::string &title) +{ + if (!ewmhIsSupported()) + return false; + + // Find switch in top level windows + std::vector windows = getTopLevelWindows(); + for (auto &window : windows) { + XTextProperty text; + int status = XGetTextProperty( + disp(), window, &text, + XInternAtom(disp(), "_NET_WM_NAME", true)); + if (status == 0) + status = XGetTextProperty(disp(), window, &text, + XInternAtom(disp(), "WM_NAME", + true)); + char *name = reinterpret_cast(text.value); + + if (status == 0 || name == nullptr) + continue; + + // True if switch equals window + bool equals = (title == name); + // True if switch matches window + bool matches = QString::fromStdString(name).contains( + QRegularExpression(QString::fromStdString(title))); + + // If found, check if switch is maximized + if (equals || matches) { + QStringList states = getStates(window); + + if (!states.isEmpty()) { + // True if window is maximized vertically + bool vertical = states.contains( + "_NET_WM_STATE_MAXIMIZED_VERT"); + // True if window is maximized horizontally + bool horizontal = states.contains( + "_NET_WM_STATE_MAXIMIZED_HORZ"); + + return (vertical && horizontal); + } + + break; + } + } + + return false; +} + bool isFullscreen(std::string &title) { if (!ewmhIsSupported()) @@ -282,14 +331,8 @@ bool isFullscreen(std::string &title) // True if window is fullscreen bool fullscreen = states.contains( "_NET_WM_STATE_FULLSCREEN"); - // True if window is maximized vertically - bool vertical = states.contains( - "_NET_WM_STATE_MAXIMIZED_VERT"); - // True if window is maximized horizontally - bool horizontal = states.contains( - "_NET_WM_STATE_MAXIMIZED_HORZ"); - return (fullscreen || (vertical && horizontal)); + return (fullscreen); } break; @@ -343,4 +386,4 @@ int secondsSinceLastInput() XCloseDisplay(display); return idle_time; -} +} \ No newline at end of file diff --git a/src/osx/advanced-scene-switcher-osx.mm b/src/osx/advanced-scene-switcher-osx.mm index 52daa364..ff990c40 100644 --- a/src/osx/advanced-scene-switcher-osx.mm +++ b/src/osx/advanced-scene-switcher-osx.mm @@ -126,6 +126,13 @@ std::pair getCursorPos() return pos; } +// TODO: +// not implemented on MacOS as I cannot test it +bool isMaximized(std::string &title) +{ + return false; +} + bool isFullscreen(std::string &title) { // Check for match diff --git a/src/audio-switch.cpp b/src/switch-audio.cpp similarity index 95% rename from src/audio-switch.cpp rename to src/switch-audio.cpp index 387a9b94..60812ddd 100644 --- a/src/audio-switch.cpp +++ b/src/switch-audio.cpp @@ -1,5 +1,4 @@ #include "headers/advanced-scene-switcher.hpp" - #include "headers/volume-control.hpp" void SceneSwitcher::on_audioSwitches_currentRowChanged(int idx) @@ -193,7 +192,6 @@ void SwitcherData::checkAudioSwitch(bool &match, OBSWeakSource &scene, for (AudioSwitch &s : audioSwitches) { obs_source_t *as = obs_weak_source_get_source(s.audioSource); - const char *name = obs_source_get_name(as); bool audioActive = obs_source_active(as); obs_source_release(as); @@ -207,10 +205,7 @@ void SwitcherData::checkAudioSwitch(bool &match, OBSWeakSource &scene, match = true; if (verbose) - blog(LOG_INFO, - "Advanced Scene Switcher audio match for %s", - name); - + s.logMatch(); break; } } @@ -325,3 +320,16 @@ void SceneSwitcher::setupAudioTab() item->setData(Qt::UserRole, listText); } } + +static inline QString MakeAudioSwitchName(const QString &scene, + const QString &transition, + const QString &audioSrouce, + const int &volume) +{ + QString switchName = QStringLiteral("When volume of ") + audioSrouce + + QStringLiteral(" is above ") + + QString::number(volume) + + QStringLiteral("% switch to ") + scene + + QStringLiteral(" using ") + transition; + return switchName; +} diff --git a/src/executable-switch.cpp b/src/switch-executable.cpp similarity index 82% rename from src/executable-switch.cpp rename to src/switch-executable.cpp index f50d511e..4445727c 100644 --- a/src/executable-switch.cpp +++ b/src/switch-executable.cpp @@ -28,15 +28,15 @@ void SceneSwitcher::on_executables_currentRowChanged(int idx) std::lock_guard lock(switcher->m); for (auto &s : switcher->executableSwitches) { - if (exec.compare(s.mExe) == 0) { - QString sceneName = GetWeakSourceName(s.mScene).c_str(); + if (exec.compare(s.exe) == 0) { + QString sceneName = GetWeakSourceName(s.scene).c_str(); QString transitionName = - GetWeakSourceName(s.mTransition).c_str(); + GetWeakSourceName(s.transition).c_str(); ui->executableScenes->setCurrentText(sceneName); ui->executable->setCurrentText(exec); ui->executableTransitions->setCurrentText( transitionName); - ui->requiresFocusCheckBox->setChecked(s.mInFocus); + ui->requiresFocusCheckBox->setChecked(s.inFocus); break; } } @@ -107,10 +107,10 @@ void SceneSwitcher::on_executableAdd_clicked() { std::lock_guard lock(switcher->m); for (auto &s : switcher->executableSwitches) { - if (s.mExe == exeName) { - s.mScene = source; - s.mTransition = transition; - s.mInFocus = inFocus; + if (s.exe == exeName) { + s.scene = source; + s.transition = transition; + s.inFocus = inFocus; break; } } @@ -133,7 +133,7 @@ void SceneSwitcher::on_executableRemove_clicked() for (auto it = switches.begin(); it != switches.end(); ++it) { auto &s = *it; - if (s.mExe == exe) { + if (s.exe == exe) { switches.erase(it); break; } @@ -172,27 +172,25 @@ void SwitcherData::checkExeSwitch(bool &match, OBSWeakSource &scene, GetProcessList(runningProcesses); for (ExecutableSceneSwitch &s : executableSwitches) { // True if executable switch is running (direct) - bool equals = runningProcesses.contains(s.mExe); + bool equals = runningProcesses.contains(s.exe); // True if executable switch is running (regex) bool matches = (runningProcesses.indexOf( - QRegularExpression(s.mExe)) != -1); + QRegularExpression(s.exe)) != -1); // True if focus is disabled OR switch is focused - bool focus = (!s.mInFocus || isInFocus(s.mExe)); + bool focus = (!s.inFocus || isInFocus(s.exe)); // True if current window is ignored AND switch equals OR matches last window bool ignore = - (ignored && (title == s.mExe.toStdString() || + (ignored && (title == s.exe.toStdString() || QString::fromStdString(title).contains( - QRegularExpression(s.mExe)))); + QRegularExpression(s.exe)))); if ((equals || matches) && (focus || ignore)) { match = true; - scene = s.mScene; - transition = s.mTransition; + scene = s.scene; + transition = s.transition; if (verbose) - blog(LOG_INFO, - "Advanced Scene Switcher exec match"); - + s.logMatch(); break; } } @@ -204,9 +202,9 @@ void SwitcherData::saveExecutableSwitches(obs_data_t *obj) for (ExecutableSceneSwitch &s : switcher->executableSwitches) { obs_data_t *array_obj = obs_data_create(); - obs_source_t *source = obs_weak_source_get_source(s.mScene); + obs_source_t *source = obs_weak_source_get_source(s.scene); obs_source_t *transition = - obs_weak_source_get_source(s.mTransition); + obs_weak_source_get_source(s.transition); if (source && transition) { const char *sceneName = obs_source_get_name(source); @@ -216,8 +214,8 @@ void SwitcherData::saveExecutableSwitches(obs_data_t *obj) obs_data_set_string(array_obj, "transition", transitionName); obs_data_set_string(array_obj, "exefile", - s.mExe.toUtf8()); - obs_data_set_bool(array_obj, "infocus", s.mInFocus); + s.exe.toUtf8()); + obs_data_set_bool(array_obj, "infocus", s.inFocus); obs_data_array_push_back(executableArray, array_obj); obs_source_release(source); obs_source_release(transition); @@ -266,15 +264,28 @@ void SceneSwitcher::setupExecutableTab() ui->executable->addItem(process); for (auto &s : switcher->executableSwitches) { - std::string sceneName = GetWeakSourceName(s.mScene); - std::string transitionName = GetWeakSourceName(s.mTransition); + std::string sceneName = GetWeakSourceName(s.scene); + std::string transitionName = GetWeakSourceName(s.transition); QString text = MakeSwitchNameExecutable(sceneName.c_str(), - s.mExe, + s.exe, transitionName.c_str(), - s.mInFocus); + s.inFocus); QListWidgetItem *item = new QListWidgetItem(text, ui->executables); - item->setData(Qt::UserRole, s.mExe); + item->setData(Qt::UserRole, s.exe); } } + +static inline QString MakeSwitchNameExecutable(const QString &scene, + const QString &value, + const QString &transition, + bool inFocus) +{ + if (!inFocus) + return QStringLiteral("[") + scene + QStringLiteral(", ") + + transition + QStringLiteral("]: ") + value; + return QStringLiteral("[") + scene + QStringLiteral(", ") + transition + + QStringLiteral("]: ") + value + + QStringLiteral(" (only if focused)"); +} diff --git a/src/file-switch.cpp b/src/switch-file.cpp similarity index 93% rename from src/file-switch.cpp rename to src/switch-file.cpp index 1bf9345f..6f089e6a 100644 --- a/src/file-switch.cpp +++ b/src/switch-file.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include "headers/advanced-scene-switcher.hpp" @@ -129,7 +128,8 @@ std::string getRemoteData(std::string &url) if (switcher->curl && f_curl_setopt && f_curl_perform) { f_curl_setopt(switcher->curl, CURLOPT_URL, url.c_str()); - f_curl_setopt(switcher->curl, CURLOPT_WRITEFUNCTION, WriteCallback); + f_curl_setopt(switcher->curl, CURLOPT_WRITEFUNCTION, + WriteCallback); f_curl_setopt(switcher->curl, CURLOPT_WRITEDATA, &readBuffer); f_curl_perform(switcher->curl); } @@ -217,9 +217,7 @@ void SwitcherData::checkFileContent(bool &match, OBSWeakSource &scene, match = true; if (verbose) - blog(LOG_INFO, - "Advanced Scene Switcher file match"); - + s.logMatch(); break; } } @@ -310,7 +308,7 @@ void SceneSwitcher::on_fileScenesList_currentRowChanged(int idx) std::lock_guard lock(switcher->m); - if (switcher->fileSwitches.size() <= idx) + if ((int)switcher->fileSwitches.size() <= idx) return; FileSwitch s = switcher->fileSwitches[idx]; @@ -473,3 +471,27 @@ void SceneSwitcher::setupFileTab() ui->readPathLineEdit->setDisabled(true); } } + +static inline QString MakeFileSwitchName(const QString &scene, + const QString &transition, + const QString &fileName, + const QString &text, bool useRegex, + bool useTime) +{ + QString switchName = QStringLiteral("Switch to ") + scene + + QStringLiteral(" using ") + transition + + QStringLiteral(" if ") + fileName; + if (useTime) + switchName += QStringLiteral(" was modified and"); + switchName += QStringLiteral(" contains"); + if (useRegex) + switchName += QStringLiteral(" (RegEx): \n\""); + else + switchName += QStringLiteral(": \n\""); + if (text.length() > 30) + switchName += text.left(27) + QStringLiteral("...\""); + else + switchName += text + QStringLiteral("\""); + + return switchName; +} diff --git a/src/idle-switch.cpp b/src/switch-idle.cpp similarity index 99% rename from src/idle-switch.cpp rename to src/switch-idle.cpp index 5dee86c4..df681f77 100644 --- a/src/idle-switch.cpp +++ b/src/switch-idle.cpp @@ -1,3 +1,5 @@ +#include + #include "headers/advanced-scene-switcher.hpp" void SwitcherData::checkIdleSwitch(bool &match, OBSWeakSource &scene, @@ -43,7 +45,7 @@ void SwitcherData::checkIdleSwitch(bool &match, OBSWeakSource &scene, idleData.alreadySwitched = true; if (verbose) - blog(LOG_INFO, "Advanced Scene Switcher idle match"); + idleData.logMatch(); } else idleData.alreadySwitched = false; } diff --git a/src/media-switch.cpp b/src/switch-media.cpp similarity index 83% rename from src/media-switch.cpp rename to src/switch-media.cpp index 8de9cd54..9cbd9b3d 100644 --- a/src/media-switch.cpp +++ b/src/switch-media.cpp @@ -1,4 +1,3 @@ -#include #include "headers/advanced-scene-switcher.hpp" void SceneSwitcher::on_mediaSwitches_currentRowChanged(int idx) @@ -167,8 +166,7 @@ void SwitcherData::checkMediaSwitch(bool &match, OBSWeakSource &scene, transition = mediaSwitch.transition; if (verbose) - blog(LOG_INFO, - "Advanced Scene Switcher meida match"); + mediaSwitch.logMatch(); } mediaSwitch.matched = matched; obs_source_release(source); @@ -299,3 +297,47 @@ void SceneSwitcher::setupMediaTab() item->setData(Qt::UserRole, listText); } } + +static inline QString +MakeMediaSwitchName(const QString &source, const QString &scene, + const QString &transition, obs_media_state state, + time_restriction restriction, uint64_t time) +{ + QString switchName = QStringLiteral("Switch to ") + scene + + QStringLiteral(" using ") + transition + + QStringLiteral(" if ") + source + + QStringLiteral(" state is "); + if (state == OBS_MEDIA_STATE_NONE) { + switchName += QStringLiteral("none"); + } else if (state == OBS_MEDIA_STATE_PLAYING) { + switchName += QStringLiteral("playing"); + } else if (state == OBS_MEDIA_STATE_OPENING) { + switchName += QStringLiteral("opening"); + } else if (state == OBS_MEDIA_STATE_BUFFERING) { + switchName += QStringLiteral("buffering"); + } else if (state == OBS_MEDIA_STATE_PAUSED) { + switchName += QStringLiteral("paused"); + } else if (state == OBS_MEDIA_STATE_STOPPED) { + switchName += QStringLiteral("stopped"); + } else if (state == OBS_MEDIA_STATE_ENDED) { + switchName += QStringLiteral("ended"); + } else if (state == OBS_MEDIA_STATE_ERROR) { + switchName += QStringLiteral("error"); + } + if (restriction == TIME_RESTRICTION_SHORTER) { + switchName += QStringLiteral(" and time shorter than "); + } else if (restriction == TIME_RESTRICTION_LONGER) { + switchName += QStringLiteral(" and time longer than "); + } else if (restriction == TIME_RESTRICTION_REMAINING_SHORTER) { + switchName += + QStringLiteral(" and time remaining shorter than "); + } else if (restriction == TIME_RESTRICTION_REMAINING_LONGER) { + switchName += + QStringLiteral(" and time remaining longer than "); + } + if (restriction != TIME_RESTRICTION_NONE) { + switchName += std::to_string(time).c_str(); + switchName += QStringLiteral(" ms"); + } + return switchName; +} diff --git a/src/pause-switch.cpp b/src/switch-pause.cpp similarity index 99% rename from src/pause-switch.cpp rename to src/switch-pause.cpp index f762423b..9dd84892 100644 --- a/src/pause-switch.cpp +++ b/src/switch-pause.cpp @@ -1,3 +1,5 @@ +#include + #include "headers/advanced-scene-switcher.hpp" void SceneSwitcher::on_pauseScenesAdd_clicked() diff --git a/src/priority.cpp b/src/switch-priority.cpp similarity index 94% rename from src/priority.cpp rename to src/switch-priority.cpp index f4619975..7eef9d2a 100644 --- a/src/priority.cpp +++ b/src/switch-priority.cpp @@ -1,10 +1,11 @@ #include + #include "headers/advanced-scene-switcher.hpp" void SceneSwitcher::on_threadPriority_currentTextChanged(const QString &text) { - if (loading || - ui->threadPriority->count() != switcher->threadPriorities.size()) + if (loading || ui->threadPriority->count() != + (int)switcher->threadPriorities.size()) return; std::lock_guard lock(switcher->m); diff --git a/src/random.cpp b/src/switch-random.cpp similarity index 91% rename from src/random.cpp rename to src/switch-random.cpp index 558a631e..fe71c156 100644 --- a/src/random.cpp +++ b/src/switch-random.cpp @@ -1,6 +1,7 @@ -#include "headers/advanced-scene-switcher.hpp" #include +#include "headers/advanced-scene-switcher.hpp" + void SceneSwitcher::on_randomScenesList_currentRowChanged(int idx) { if (loading) @@ -134,8 +135,7 @@ void SwitcherData::checkRandom(bool &match, OBSWeakSource &scene, lastRandomScene = r.scene; if (verbose) - blog(LOG_INFO, "Advanced Scene Switcher random match"); - + r.logMatch(); break; } } @@ -158,8 +158,6 @@ void SwitcherData::saveRandomSwitches(obs_data_t *obj) 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); @@ -186,11 +184,16 @@ void SwitcherData::loadRandomSwitches(obs_data_t *obj) const char *transition = obs_data_get_string(array_obj, "transition"); double delay = obs_data_get_double(array_obj, "delay"); - const char *str = obs_data_get_string(array_obj, "str"); + + std::string randomSwitchStr = + MakeRandomSwitchName(scene, transition, delay) + .toUtf8() + .constData(); switcher->randomSwitches.emplace_back( GetWeakSourceByName(scene), - GetWeakTransitionByName(transition), delay, str); + GetWeakTransitionByName(transition), delay, + randomSwitchStr); obs_data_release(array_obj); } @@ -213,3 +216,12 @@ void SceneSwitcher::setupRandomTab() item->setData(Qt::UserRole, text); } } + +static inline QString MakeRandomSwitchName(const QString &scene, + const QString &transition, + double &delay) +{ + return QStringLiteral("[") + scene + QStringLiteral(", ") + transition + + QStringLiteral("]: ") + QString::number(delay) + + QStringLiteral(" seconds"); +} diff --git a/src/screen-region-switch.cpp b/src/switch-screen-region.cpp similarity index 93% rename from src/screen-region-switch.cpp rename to src/switch-screen-region.cpp index a74984e0..558675e6 100644 --- a/src/screen-region-switch.cpp +++ b/src/switch-screen-region.cpp @@ -19,9 +19,7 @@ void SwitcherData::checkScreenRegionSwitch(bool &match, OBSWeakSource &scene, minRegionSize = regionSize; if (verbose) - blog(LOG_INFO, - "Advanced Scene Switcher region match"); - + s.logMatch(); break; } } @@ -213,8 +211,6 @@ void SwitcherData::saveScreenRegionSwitches(obs_data_t *obj) obs_data_set_int(array_obj, "minY", s.minY); obs_data_set_int(array_obj, "maxX", s.maxX); obs_data_set_int(array_obj, "maxY", s.maxY); - obs_data_set_string(array_obj, "screenRegionStr", - s.regionStr.c_str()); obs_data_array_push_back(screenRegionArray, array_obj); obs_source_release(source); obs_source_release(transition); @@ -246,8 +242,12 @@ void SwitcherData::loadScreenRegionSwitches(obs_data_t *obj) int minY = obs_data_get_int(array_obj, "minY"); int maxX = obs_data_get_int(array_obj, "maxX"); int maxY = obs_data_get_int(array_obj, "maxY"); + std::string regionStr = - obs_data_get_string(array_obj, "screenRegionStr"); + MakeScreenRegionSwitchName(scene, transition, minX, + minY, maxX, maxY) + .toUtf8() + .constData(); switcher->screenRegionSwitches.emplace_back( GetWeakSourceByName(scene), @@ -282,3 +282,15 @@ void SceneSwitcher::setupRegionTab() SLOT(updateScreenRegionCursorPos())); screenRegionTimer->start(1000); } + +static inline QString MakeScreenRegionSwitchName(const QString &scene, + const QString &transition, + int minX, int minY, int maxX, + int maxY) +{ + return QStringLiteral("[") + scene + QStringLiteral(", ") + transition + + QStringLiteral("]: ") + QString::number(minX) + + QStringLiteral(", ") + QString::number(minY) + + QStringLiteral(" x ") + QString::number(maxX) + + QStringLiteral(", ") + QString::number(maxY); +} diff --git a/src/scene-round-trip.cpp b/src/switch-sequence.cpp similarity index 58% rename from src/scene-round-trip.cpp rename to src/switch-sequence.cpp index 22a144fc..b6e46734 100644 --- a/src/scene-round-trip.cpp +++ b/src/switch-sequence.cpp @@ -1,24 +1,23 @@ #include #include #include -#include #include "headers/advanced-scene-switcher.hpp" -#define SECONDS_INDEX 0 -#define MINUTES_INDEX 1 -#define HOURS_INDEX 2 +constexpr auto seconds_index = 0; +constexpr auto minutes_index = 1; +constexpr auto hours_index = 2; -void SceneSwitcher::on_sceneRoundTripDelayUnits_currentIndexChanged(int index) +void SceneSwitcher::on_sceneSequenceDelayUnits_currentIndexChanged(int index) { if (loading) return; std::lock_guard lock(switcher->m); - double val = ui->sceneRoundTripSpinBox->value(); + double val = ui->sceneSequenceSpinBox->value(); - switch (switcher->sceneRoundTripUnitMultiplier) { + switch (switcher->sceneSequenceMultiplier) { case 1: val /= pow(60, index); break; @@ -30,32 +29,32 @@ void SceneSwitcher::on_sceneRoundTripDelayUnits_currentIndexChanged(int index) break; } - ui->sceneRoundTripSpinBox->setValue(val); + ui->sceneSequenceSpinBox->setValue(val); switch (index) { - case SECONDS_INDEX: - switcher->sceneRoundTripUnitMultiplier = 1; + case seconds_index: + switcher->sceneSequenceMultiplier = 1; break; - case MINUTES_INDEX: - switcher->sceneRoundTripUnitMultiplier = 60; + case minutes_index: + switcher->sceneSequenceMultiplier = 60; break; - case HOURS_INDEX: - switcher->sceneRoundTripUnitMultiplier = 3600; + case hours_index: + switcher->sceneSequenceMultiplier = 3600; break; } } -void SceneSwitcher::on_sceneRoundTripAdd_clicked() +void SceneSwitcher::on_sceneSequenceAdd_clicked() { - QString scene1Name = ui->sceneRoundTripScenes1->currentText(); - QString scene2Name = ui->sceneRoundTripScenes2->currentText(); - QString transitionName = ui->sceneRoundTripTransitions->currentText(); + QString scene1Name = ui->sceneSequenceScenes1->currentText(); + QString scene2Name = ui->sceneSequenceScenes2->currentText(); + QString transitionName = ui->sceneSequenceTransitions->currentText(); if (scene1Name.isEmpty() || scene2Name.isEmpty()) return; - double delay = ui->sceneRoundTripSpinBox->value() * - switcher->sceneRoundTripUnitMultiplier; + double delay = ui->sceneSequenceSpinBox->value() * + switcher->sceneSequenceMultiplier; if (scene1Name == scene2Name) return; @@ -64,37 +63,37 @@ void SceneSwitcher::on_sceneRoundTripAdd_clicked() OBSWeakSource source2 = GetWeakSourceByQString(scene2Name); OBSWeakSource transition = GetWeakTransitionByQString(transitionName); - QString text = MakeSceneRoundTripSwitchName(scene1Name, scene2Name, + QString text = MakeSceneSequenceSwitchName(scene1Name, scene2Name, transitionName, delay); QVariant v = QVariant::fromValue(text); - int idx = SceneRoundTripFindByData(scene1Name); + int idx = SceneSequenceFindByData(scene1Name); if (idx == -1) { QListWidgetItem *item = - new QListWidgetItem(text, ui->sceneRoundTrips); + new QListWidgetItem(text, ui->sceneSequences); item->setData(Qt::UserRole, v); std::lock_guard lock(switcher->m); - switcher->sceneRoundTripSwitches.emplace_back( + switcher->sceneSequenceSwitches.emplace_back( source1, source2, transition, delay, (scene2Name == QString(previous_scene_name)), text.toUtf8().constData()); } else { - QListWidgetItem *item = ui->sceneRoundTrips->item(idx); + QListWidgetItem *item = ui->sceneSequences->item(idx); item->setText(text); { std::lock_guard lock(switcher->m); - for (auto &s : switcher->sceneRoundTripSwitches) { - if (s.scene1 == source1) { - s.scene2 = source2; + for (auto &s : switcher->sceneSequenceSwitches) { + if (s.startScene == source1) { + s.scene = source2; s.delay = delay; s.transition = transition; s.usePreviousScene = (scene2Name == QString(previous_scene_name)); - s.sceneRoundTripStr = + s.sceneSequenceStr = text.toUtf8().constData(); break; } @@ -103,9 +102,9 @@ void SceneSwitcher::on_sceneRoundTripAdd_clicked() } } -void SceneSwitcher::on_sceneRoundTripRemove_clicked() +void SceneSwitcher::on_sceneSequenceRemove_clicked() { - QListWidgetItem *item = ui->sceneRoundTrips->currentItem(); + QListWidgetItem *item = ui->sceneSequences->currentItem(); if (!item) return; @@ -114,12 +113,12 @@ void SceneSwitcher::on_sceneRoundTripRemove_clicked() { std::lock_guard lock(switcher->m); - auto &switches = switcher->sceneRoundTripSwitches; + auto &switches = switcher->sceneSequenceSwitches; for (auto it = switches.begin(); it != switches.end(); ++it) { auto &s = *it; - if (s.sceneRoundTripStr == text) { + if (s.sceneSequenceStr == text) { switches.erase(it); break; } @@ -129,10 +128,10 @@ void SceneSwitcher::on_sceneRoundTripRemove_clicked() delete item; } -void SceneSwitcher::on_sceneRoundTripSave_clicked() +void SceneSwitcher::on_sceneSequenceSave_clicked() { QString directory = QFileDialog::getSaveFileName( - this, tr("Save Scene Round Trip to file ..."), + this, tr("Save Scene Sequence to file ..."), QDir::currentPath(), tr("Text files (*.txt)")); if (directory.isEmpty()) return; @@ -141,7 +140,7 @@ void SceneSwitcher::on_sceneRoundTripSave_clicked() return; obs_data_t *obj = obs_data_create(); - switcher->saveSceneRoundTripSwitches(obj); + switcher->saveSceneSequenceSwitches(obj); obs_data_save_json(obj, file.fileName().toUtf8().constData()); obs_data_release(obj); } @@ -152,7 +151,7 @@ bool oldSceneRoundTripLoad(QFile *file) QTextStream in(file); std::vector lines; - std::vector newSceneRoundTripSwitch; + std::vector newSceneRoundTripSwitch; while (!in.atEnd()) { QString line = in.readLine(); @@ -168,7 +167,7 @@ bool oldSceneRoundTripLoad(QFile *file) (WeakSourceValid(scene2))) && WeakSourceValid(transition)) { newSceneRoundTripSwitch.emplace_back( - SceneRoundTripSwitch( + SceneSequenceSwitch( GetWeakSourceByQString(lines[0]), GetWeakSourceByQString(lines[1]), GetWeakTransitionByQString( @@ -185,17 +184,17 @@ bool oldSceneRoundTripLoad(QFile *file) if (lines.size() != 0 || newSceneRoundTripSwitch.size() == 0) return false; - switcher->sceneRoundTripSwitches.clear(); - switcher->sceneRoundTripSwitches = newSceneRoundTripSwitch; + switcher->sceneSequenceSwitches.clear(); + switcher->sceneSequenceSwitches = newSceneRoundTripSwitch; return true; } -void SceneSwitcher::on_sceneRoundTripLoad_clicked() +void SceneSwitcher::on_sceneSequenceLoad_clicked() { std::lock_guard lock(switcher->m); QString directory = QFileDialog::getOpenFileName( - this, tr("Select a file to read Scene Round Trip from ..."), + this, tr("Select a file to read Scene Sequence from ..."), QDir::currentPath(), tr("Text files (*.txt)")); if (directory.isEmpty()) return; @@ -228,7 +227,7 @@ void SceneSwitcher::on_sceneRoundTripLoad_clicked() } return; } - switcher->loadSceneRoundTripSwitches(obj); + switcher->loadSceneSequenceSwitches(obj); obs_data_release(obj); QMessageBox Msgbox; @@ -238,25 +237,21 @@ void SceneSwitcher::on_sceneRoundTripLoad_clicked() close(); } -void SwitcherData::checkSceneRoundTrip(bool &match, OBSWeakSource &scene, +void SwitcherData::checkSceneSequence(bool &match, OBSWeakSource &scene, OBSWeakSource &transition, std::unique_lock &lock) { - bool sceneRoundTripActive = false; obs_source_t *currentSource = obs_frontend_get_current_scene(); obs_weak_source_t *ws = obs_source_get_weak_source(currentSource); - for (SceneRoundTripSwitch &s : sceneRoundTripSwitches) { - if (s.scene1 == ws) { - sceneRoundTripActive = true; + for (SceneSequenceSwitch &s : sceneSequenceSwitches) { + if (s.startScene == ws) { int dur = s.delay * 1000 - interval; if (dur > 0) { waitScene = currentSource; if (verbose) - blog(LOG_INFO, - "Advanced Scene Switcher sequence sleep %d", - dur); + s.logSleep(dur); cv.wait_for(lock, std::chrono::milliseconds(dur)); @@ -269,8 +264,10 @@ void SwitcherData::checkSceneRoundTrip(bool &match, OBSWeakSource &scene, if (currentSource == currentSource2) { match = true; scene = (s.usePreviousScene) ? previousScene - : s.scene2; + : s.scene; transition = s.transition; + if (verbose) + s.logMatch(); } obs_source_release(currentSource2); break; @@ -280,46 +277,46 @@ void SwitcherData::checkSceneRoundTrip(bool &match, OBSWeakSource &scene, obs_weak_source_release(ws); } -void SceneSwitcher::on_sceneRoundTrips_currentRowChanged(int idx) +void SceneSwitcher::on_sceneSequences_currentRowChanged(int idx) { if (loading) return; if (idx == -1) return; - QListWidgetItem *item = ui->sceneRoundTrips->item(idx); + QListWidgetItem *item = ui->sceneSequences->item(idx); - QString sceneRoundTrip = item->text(); + QString sceneSequence = item->text(); std::lock_guard lock(switcher->m); - for (auto &s : switcher->sceneRoundTripSwitches) { - if (sceneRoundTrip.compare(s.sceneRoundTripStr.c_str()) == 0) { - std::string scene1 = GetWeakSourceName(s.scene1); - std::string scene2 = GetWeakSourceName(s.scene2); + for (auto &s : switcher->sceneSequenceSwitches) { + if (sceneSequence.compare(s.sceneSequenceStr.c_str()) == 0) { + std::string scene1 = GetWeakSourceName(s.startScene); + std::string scene2 = GetWeakSourceName(s.scene); std::string transitionName = GetWeakSourceName(s.transition); double delay = s.delay / - switcher->sceneRoundTripUnitMultiplier; - ui->sceneRoundTripScenes1->setCurrentText( + switcher->sceneSequenceMultiplier; + ui->sceneSequenceScenes1->setCurrentText( scene1.c_str()); - ui->sceneRoundTripScenes2->setCurrentText( + ui->sceneSequenceScenes2->setCurrentText( scene2.c_str()); - ui->sceneRoundTripTransitions->setCurrentText( + ui->sceneSequenceTransitions->setCurrentText( transitionName.c_str()); - ui->sceneRoundTripSpinBox->setValue(delay); + ui->sceneSequenceSpinBox->setValue(delay); break; } } } -int SceneSwitcher::SceneRoundTripFindByData(const QString &scene1) +int SceneSwitcher::SceneSequenceFindByData(const QString &scene1) { QRegExp rx(scene1 + " ->.*"); - int count = ui->sceneRoundTrips->count(); + int count = ui->sceneSequences->count(); int idx = -1; for (int i = 0; i < count; i++) { - QListWidgetItem *item = ui->sceneRoundTrips->item(i); + QListWidgetItem *item = ui->sceneSequences->item(i); QString itemString = item->data(Qt::UserRole).toString(); if (rx.exactMatch(itemString)) { @@ -331,44 +328,45 @@ int SceneSwitcher::SceneRoundTripFindByData(const QString &scene1) return idx; } -void SceneSwitcher::on_sceneRoundTripUp_clicked() +void SceneSwitcher::on_sceneSequenceUp_clicked() { - int index = ui->sceneRoundTrips->currentRow(); + int index = ui->sceneSequences->currentRow(); if (index != -1 && index != 0) { - ui->sceneRoundTrips->insertItem( - index - 1, ui->sceneRoundTrips->takeItem(index)); - ui->sceneRoundTrips->setCurrentRow(index - 1); + ui->sceneSequences->insertItem( + index - 1, ui->sceneSequences->takeItem(index)); + ui->sceneSequences->setCurrentRow(index - 1); std::lock_guard lock(switcher->m); - iter_swap(switcher->sceneRoundTripSwitches.begin() + index, - switcher->sceneRoundTripSwitches.begin() + index - 1); + iter_swap(switcher->sceneSequenceSwitches.begin() + index, + switcher->sceneSequenceSwitches.begin() + index - 1); } } -void SceneSwitcher::on_sceneRoundTripDown_clicked() +void SceneSwitcher::on_sceneSequenceDown_clicked() { - int index = ui->sceneRoundTrips->currentRow(); - if (index != -1 && index != ui->sceneRoundTrips->count() - 1) { - ui->sceneRoundTrips->insertItem( - index + 1, ui->sceneRoundTrips->takeItem(index)); - ui->sceneRoundTrips->setCurrentRow(index + 1); + int index = ui->sceneSequences->currentRow(); + if (index != -1 && index != ui->sceneSequences->count() - 1) { + ui->sceneSequences->insertItem( + index + 1, ui->sceneSequences->takeItem(index)); + ui->sceneSequences->setCurrentRow(index + 1); std::lock_guard lock(switcher->m); - iter_swap(switcher->sceneRoundTripSwitches.begin() + index, - switcher->sceneRoundTripSwitches.begin() + index + 1); + iter_swap(switcher->sceneSequenceSwitches.begin() + index, + switcher->sceneSequenceSwitches.begin() + index + 1); } } -void SwitcherData::saveSceneRoundTripSwitches(obs_data_t *obj) +void SwitcherData::saveSceneSequenceSwitches(obs_data_t *obj) { - obs_data_array_t *sceneRoundTripArray = obs_data_array_create(); - for (SceneRoundTripSwitch &s : switcher->sceneRoundTripSwitches) { + obs_data_array_t *sceneSequenceArray = obs_data_array_create(); + for (SceneSequenceSwitch &s : switcher->sceneSequenceSwitches) { obs_data_t *array_obj = obs_data_create(); - obs_source_t *source1 = obs_weak_source_get_source(s.scene1); - obs_source_t *source2 = obs_weak_source_get_source(s.scene2); + obs_source_t *source1 = + obs_weak_source_get_source(s.startScene); + obs_source_t *source2 = obs_weak_source_get_source(s.scene); obs_source_t *transition = obs_weak_source_get_source(s.transition); if (source1 && (s.usePreviousScene || source2) && transition) { @@ -385,9 +383,7 @@ void SwitcherData::saveSceneRoundTripSwitches(obs_data_t *obj) obs_data_set_string(array_obj, "transition", transitionName); obs_data_set_double(array_obj, "delay", s.delay); - obs_data_set_string(array_obj, "sceneRoundTripStr", - s.sceneRoundTripStr.c_str()); - obs_data_array_push_back(sceneRoundTripArray, + obs_data_array_push_back(sceneSequenceArray, array_obj); obs_source_release(source1); obs_source_release(source2); @@ -396,21 +392,21 @@ void SwitcherData::saveSceneRoundTripSwitches(obs_data_t *obj) obs_data_release(array_obj); } - obs_data_set_array(obj, "sceneRoundTrip", sceneRoundTripArray); - obs_data_array_release(sceneRoundTripArray); + obs_data_set_array(obj, "sceneRoundTrip", sceneSequenceArray); + obs_data_array_release(sceneSequenceArray); } -void SwitcherData::loadSceneRoundTripSwitches(obs_data_t *obj) +void SwitcherData::loadSceneSequenceSwitches(obs_data_t *obj) { - switcher->sceneRoundTripSwitches.clear(); + switcher->sceneSequenceSwitches.clear(); - obs_data_array_t *sceneRoundTripArray = + obs_data_array_t *sceneSequenceArray = obs_data_get_array(obj, "sceneRoundTrip"); - size_t count = obs_data_array_count(sceneRoundTripArray); + size_t count = obs_data_array_count(sceneSequenceArray); for (size_t i = 0; i < count; i++) { obs_data_t *array_obj = - obs_data_array_item(sceneRoundTripArray, i); + obs_data_array_item(sceneSequenceArray, i); const char *scene1 = obs_data_get_string(array_obj, "sceneRoundTripScene1"); @@ -434,43 +430,43 @@ void SwitcherData::loadSceneRoundTripSwitches(obs_data_t *obj) delay = obs_data_get_double(array_obj, "delay"); } - std::string str = MakeSceneRoundTripSwitchName( + std::string str = MakeSceneSequenceSwitchName( scene1, scene2, transition, delay) .toUtf8() .constData(); - const char *sceneRoundTripStr = str.c_str(); + const char *sceneSequenceStr = str.c_str(); - switcher->sceneRoundTripSwitches.emplace_back( + switcher->sceneSequenceSwitches.emplace_back( GetWeakSourceByName(scene1), GetWeakSourceByName(scene2), GetWeakTransitionByName(transition), delay, (strcmp(scene2, previous_scene_name) == 0), - sceneRoundTripStr); + sceneSequenceStr); obs_data_release(array_obj); } - obs_data_array_release(sceneRoundTripArray); + obs_data_array_release(sceneSequenceArray); } void SceneSwitcher::setupSequenceTab() { - populateSceneSelection(ui->sceneRoundTripScenes1, false); - populateSceneSelection(ui->sceneRoundTripScenes2, true); - populateTransitionSelection(ui->sceneRoundTripTransitions); + populateSceneSelection(ui->sceneSequenceScenes1, false); + populateSceneSelection(ui->sceneSequenceScenes2, true); + populateTransitionSelection(ui->sceneSequenceTransitions); double smallestDelay = double(switcher->interval) / 1000; - for (auto &s : switcher->sceneRoundTripSwitches) { - std::string sceneName1 = GetWeakSourceName(s.scene1); + for (auto &s : switcher->sceneSequenceSwitches) { + std::string sceneName1 = GetWeakSourceName(s.startScene); std::string sceneName2 = (s.usePreviousScene) ? previous_scene_name - : GetWeakSourceName(s.scene2); + : GetWeakSourceName(s.scene); std::string transitionName = GetWeakSourceName(s.transition); - QString text = MakeSceneRoundTripSwitchName( + QString text = MakeSceneSequenceSwitchName( sceneName1.c_str(), sceneName2.c_str(), transitionName.c_str(), s.delay); QListWidgetItem *item = - new QListWidgetItem(text, ui->sceneRoundTrips); + new QListWidgetItem(text, ui->sceneSequences); item->setData(Qt::UserRole, text); if (s.delay < smallestDelay) @@ -480,21 +476,32 @@ void SceneSwitcher::setupSequenceTab() ? ui->intervalWarning->setVisible(true) : ui->intervalWarning->setVisible(false); - ui->sceneRoundTripDelayUnits->addItem("seconds"); - ui->sceneRoundTripDelayUnits->addItem("minutes"); - ui->sceneRoundTripDelayUnits->addItem("hours"); + ui->sceneSequenceDelayUnits->addItem("seconds"); + ui->sceneSequenceDelayUnits->addItem("minutes"); + ui->sceneSequenceDelayUnits->addItem("hours"); - switch (switcher->sceneRoundTripUnitMultiplier) { + switch (switcher->sceneSequenceMultiplier) { case 1: - ui->sceneRoundTripDelayUnits->setCurrentIndex(0); + ui->sceneSequenceDelayUnits->setCurrentIndex(0); break; case 60: - ui->sceneRoundTripDelayUnits->setCurrentIndex(1); + ui->sceneSequenceDelayUnits->setCurrentIndex(1); break; case 3600: - ui->sceneRoundTripDelayUnits->setCurrentIndex(2); + ui->sceneSequenceDelayUnits->setCurrentIndex(2); break; default: break; } } + +static inline QString MakeSceneSequenceSwitchName(const QString &scene1, + const QString &scene2, + const QString &transition, + double delay) +{ + return scene1 + QStringLiteral(" -> wait for ") + + QString::number(delay) + QStringLiteral(" seconds -> ") + + scene2 + QStringLiteral(" (using ") + transition + + QStringLiteral(" transition)"); +} diff --git a/src/time-switch.cpp b/src/switch-time.cpp similarity index 89% rename from src/time-switch.cpp rename to src/switch-time.cpp index 356d9078..c8723815 100644 --- a/src/time-switch.cpp +++ b/src/switch-time.cpp @@ -223,9 +223,7 @@ void SwitcherData::checkTimeSwitch(bool &match, OBSWeakSource &scene, match = true; if (verbose) - blog(LOG_INFO, - "Advanced Scene Switcher time match"); - + s.logMatch(); break; } } @@ -329,3 +327,46 @@ void SceneSwitcher::setupTimeTab() item->setData(Qt::UserRole, listText); } } + +static inline QString MakeTimeSwitchName(const QString &scene, + const QString &transition, + const timeTrigger &trigger, + const QTime &time) +{ + QString switchName; + + switch (trigger) { + case ANY_DAY: + switchName = QStringLiteral("On any weekday"); + break; + case MONDAY: + switchName = QStringLiteral("Mondays"); + break; + case TUSEDAY: + switchName = QStringLiteral("Tusedays"); + break; + case WEDNESDAY: + switchName = QStringLiteral("Wednesdays"); + break; + case THURSDAY: + switchName = QStringLiteral("Thursdays"); + break; + case FRIDAY: + switchName = QStringLiteral("Fridays"); + break; + case SATURDAY: + switchName = QStringLiteral("Saturdays"); + break; + case SUNDAY: + switchName = QStringLiteral("Sundays"); + break; + case LIVE: + switchName = QStringLiteral( + "Relative to starting streaming / recording"); + break; + } + switchName += QStringLiteral(" at ") + time.toString() + + QStringLiteral(" switch to ") + scene + + QStringLiteral(" using ") + transition; + return switchName; +} diff --git a/src/scene-transitions.cpp b/src/switch-transitions.cpp similarity index 93% rename from src/scene-transitions.cpp rename to src/switch-transitions.cpp index 52d6439d..610db78a 100644 --- a/src/scene-transitions.cpp +++ b/src/switch-transitions.cpp @@ -38,8 +38,7 @@ void SceneSwitcher::on_transitionsAdd_clicked() { std::lock_guard lock(switcher->m); for (auto &s : switcher->sceneTransitions) { - if (s.scene1 == source1 && - s.scene2 == source2) { + if (s.scene == source1 && s.scene2 == source2) { s.transition = transition; s.sceneTransitionStr = text.toUtf8().constData(); @@ -164,8 +163,8 @@ void SwitcherData::setDefaultSceneTransitions() obs_frontend_set_current_transition(transition); if (verbose) - blog(LOG_INFO, - "Advanced Scene Switcher default transition set"); + if (verbose) + s.logMatch(); obs_source_release(transition); break; @@ -229,7 +228,7 @@ void SceneSwitcher::on_sceneTransitions_currentRowChanged(int idx) for (auto &s : switcher->sceneTransitions) { if (sceneTransition.compare(s.sceneTransitionStr.c_str()) == 0) { - std::string scene1 = GetWeakSourceName(s.scene1); + std::string scene1 = GetWeakSourceName(s.scene); std::string scene2 = GetWeakSourceName(s.scene2); std::string transitionName = GetWeakSourceName(s.transition); @@ -288,7 +287,7 @@ obs_weak_source_t *getNextTransition(obs_weak_source_t *scene1, obs_weak_source_t *ws = nullptr; if (scene1 && scene2) { for (SceneTransition &t : switcher->sceneTransitions) { - if (t.scene1 == scene1 && t.scene2 == scene2) + if (t.scene == scene1 && t.scene2 == scene2) ws = t.transition; } obs_weak_source_addref(ws); @@ -359,7 +358,7 @@ void SwitcherData::saveSceneTransitions(obs_data_t *obj) for (SceneTransition &s : switcher->sceneTransitions) { obs_data_t *array_obj = obs_data_create(); - obs_source_t *source1 = obs_weak_source_get_source(s.scene1); + obs_source_t *source1 = obs_weak_source_get_source(s.scene); obs_source_t *source2 = obs_weak_source_get_source(s.scene2); obs_source_t *transition = obs_weak_source_get_source(s.transition); @@ -372,8 +371,6 @@ void SwitcherData::saveSceneTransitions(obs_data_t *obj) obs_data_set_string(array_obj, "Scene2", sceneName2); obs_data_set_string(array_obj, "transition", transitionName); - obs_data_set_string(array_obj, "Str", - s.sceneTransitionStr.c_str()); obs_data_array_push_back(sceneTransitionsArray, array_obj); obs_source_release(source1); @@ -400,8 +397,6 @@ void SwitcherData::saveSceneTransitions(obs_data_t *obj) obs_data_set_string(array_obj, "Scene", sceneName); obs_data_set_string(array_obj, "transition", transitionName); - obs_data_set_string(array_obj, "Str", - s.sceneTransitionStr.c_str()); obs_data_array_push_back(defaultTransitionsArray, array_obj); obs_source_release(source); @@ -433,8 +428,11 @@ void SwitcherData::loadSceneTransitions(obs_data_t *obj) const char *scene2 = obs_data_get_string(array_obj, "Scene2"); const char *transition = obs_data_get_string(array_obj, "transition"); - const char *sceneTransitionsStr = - obs_data_get_string(array_obj, "Str"); + + std::string sceneTransitionsStr = + MakeSceneTransitionName(scene1, scene2, transition) + .toUtf8() + .constData(); switcher->sceneTransitions.emplace_back( GetWeakSourceByName(scene1), @@ -459,8 +457,11 @@ void SwitcherData::loadSceneTransitions(obs_data_t *obj) const char *scene = obs_data_get_string(array_obj, "Scene"); const char *transition = obs_data_get_string(array_obj, "transition"); - const char *sceneTransitionsStr = - obs_data_get_string(array_obj, "Str"); + + std::string sceneTransitionsStr = + MakeDefaultSceneTransitionName(scene, transition) + .toUtf8() + .constData(); switcher->defaultSceneTransitions.emplace_back( GetWeakSourceByName(scene), @@ -484,7 +485,7 @@ void SceneSwitcher::setupTransitionsTab() populateTransitionSelection(ui->defaultTransitionsTransitions); for (auto &s : switcher->sceneTransitions) { - std::string sceneName1 = GetWeakSourceName(s.scene1); + std::string sceneName1 = GetWeakSourceName(s.scene); std::string sceneName2 = GetWeakSourceName(s.scene2); std::string transitionName = GetWeakSourceName(s.transition); QString text = MakeSceneTransitionName(sceneName1.c_str(), @@ -495,9 +496,6 @@ void SceneSwitcher::setupTransitionsTab() new QListWidgetItem(text, ui->sceneTransitions); item->setData(Qt::UserRole, text); } - //(transitionDurationLongerThanInterval(switcher->interval)) - // ? ui->transitionWarning->setVisible(true) - // : ui->transitionWarning->setVisible(false); for (auto &s : switcher->defaultSceneTransitions) { std::string sceneName = GetWeakSourceName(s.scene); @@ -513,3 +511,17 @@ void SceneSwitcher::setupTransitionsTab() ui->transitionOverridecheckBox->setChecked( switcher->tansitionOverrideOverride); } + +static inline QString MakeSceneTransitionName(const QString &scene1, + const QString &scene2, + const QString &transition) +{ + return scene1 + QStringLiteral(" --- ") + transition + + QStringLiteral(" --> ") + scene2; +} + +static inline QString MakeDefaultSceneTransitionName(const QString &scene, + const QString &transition) +{ + return scene + QStringLiteral(" --> ") + transition; +} diff --git a/src/window-title-switch.cpp b/src/switch-window.cpp similarity index 86% rename from src/window-title-switch.cpp rename to src/switch-window.cpp index 6dc9faaf..476ef8cd 100644 --- a/src/window-title-switch.cpp +++ b/src/switch-window.cpp @@ -1,4 +1,3 @@ -#include #include "headers/advanced-scene-switcher.hpp" bool isRunning(std::string &title) @@ -65,6 +64,7 @@ void SceneSwitcher::on_add_clicked() QString windowName = ui->windows->currentText(); QString transitionName = ui->transitions->currentText(); bool fullscreen = ui->fullscreenCheckBox->isChecked(); + bool maximized = ui->maximizedCheckBox->isChecked(); bool focus = ui->focusCheckBox->isChecked(); if (windowName.isEmpty() || sceneName.isEmpty()) @@ -74,8 +74,9 @@ void SceneSwitcher::on_add_clicked() OBSWeakSource transition = GetWeakTransitionByQString(transitionName); QVariant v = QVariant::fromValue(windowName); - QString text = MakeSwitchName(sceneName, windowName, transitionName, - fullscreen, focus); + QString text = MakeWindowSwitchName(sceneName, windowName, + transitionName, fullscreen, + maximized, focus); int idx = FindByData(windowName); @@ -83,7 +84,7 @@ void SceneSwitcher::on_add_clicked() std::lock_guard lock(switcher->m); switcher->windowSwitches.emplace_back( source, windowName.toUtf8().constData(), transition, - fullscreen, focus); + fullscreen, maximized, focus); QListWidgetItem *item = new QListWidgetItem(text, ui->switches); item->setData(Qt::UserRole, v); @@ -100,6 +101,7 @@ void SceneSwitcher::on_add_clicked() s.scene = source; s.transition = transition; s.fullscreen = fullscreen; + s.maximized = maximized; s.focus = focus; break; } @@ -239,6 +241,7 @@ void SceneSwitcher::on_switches_currentRowChanged(int idx) ui->windows->setCurrentText(window); ui->transitions->setCurrentText(transitionName.c_str()); ui->fullscreenCheckBox->setChecked(s.fullscreen); + ui->maximizedCheckBox->setChecked(s.maximized); ui->focusCheckBox->setChecked(s.focus); break; } @@ -293,6 +296,8 @@ void SwitcherData::checkWindowTitleSwitch(bool &match, OBSWeakSource &scene, for (WindowSceneSwitch &s : windowSwitches) { // True if fullscreen is disabled OR current window is fullscreen bool fullscreen = (!s.fullscreen || isFullscreen(s.window)); + // True if maximized is disabled OR current window is maximized + bool max = (!s.maximized || isMaximized(s.window)); // True if focus is disabled OR switch is focused bool focus = (!s.focus || isFocused(s.window)); // True if current window is ignored AND switch equals OR matches last window @@ -303,11 +308,14 @@ void SwitcherData::checkWindowTitleSwitch(bool &match, OBSWeakSource &scene, QRegularExpression( QString::fromStdString(s.window))))); - if (isRunning(s.window) && (fullscreen && (focus || ignore))) { + if (isRunning(s.window) && + (fullscreen && (max && (focus || ignore)))) { match = true; scene = s.scene; transition = s.transition; + if (verbose) + s.logMatch(); break; } } @@ -333,6 +341,7 @@ void SwitcherData::saveWindowTitleSwitches(obs_data_t *obj) s.window.c_str()); obs_data_set_bool(array_obj, "fullscreen", s.fullscreen); + obs_data_set_bool(array_obj, "maximized", s.maximized); obs_data_set_bool(array_obj, "focus", s.focus); obs_data_array_push_back(windowTitleArray, array_obj); obs_source_release(source); @@ -372,12 +381,20 @@ void SwitcherData::loadWindowTitleSwitches(obs_data_t *obj) const char *window = obs_data_get_string(array_obj, "window_title"); bool fullscreen = obs_data_get_bool(array_obj, "fullscreen"); +#if __APPLE__ + // TODO: + // not implemented on MacOS as I cannot test it + bool maximized = false; +#else + bool maximized = obs_data_get_bool(array_obj, "maximized"); +#endif bool focus = obs_data_get_bool(array_obj, "focus") || !obs_data_has_user_value(array_obj, "focus"); switcher->windowSwitches.emplace_back( GetWeakSourceByName(scene), window, - GetWeakTransitionByName(transition), fullscreen, focus); + GetWeakTransitionByName(transition), fullscreen, + maximized, focus); obs_data_release(array_obj); } @@ -413,10 +430,11 @@ void SceneSwitcher::setupTitleTab() for (auto &s : switcher->windowSwitches) { std::string sceneName = GetWeakSourceName(s.scene); std::string transitionName = GetWeakSourceName(s.transition); - QString text = MakeSwitchName(sceneName.c_str(), - s.window.c_str(), - transitionName.c_str(), - s.fullscreen, s.focus); + QString text = MakeWindowSwitchName(sceneName.c_str(), + s.window.c_str(), + transitionName.c_str(), + s.fullscreen, s.maximized, + s.focus); QListWidgetItem *item = new QListWidgetItem(text, ui->switches); item->setData(Qt::UserRole, s.window.c_str()); @@ -429,4 +447,36 @@ void SceneSwitcher::setupTitleTab() new QListWidgetItem(text, ui->ignoreWindows); item->setData(Qt::UserRole, text); } + +#if __APPLE__ + // TODO: + // not implemented on MacOS as I cannot test it + ui->maximizedCheckBox->setDisabled(true); + ui->maximizedCheckBox->setVisible(false); +#endif +} + +static inline QString MakeWindowSwitchName(const QString &scene, + const QString &value, + const QString &transition, + bool fullscreen, bool maximized, + bool focus) +{ + QString name = QStringLiteral("[") + scene + QStringLiteral(", ") + + transition + QStringLiteral("]: ") + value; + + if (fullscreen || maximized || focus) { + name += QStringLiteral(" (only if"); + + if (fullscreen) + name += QStringLiteral(" fullscreen "); + if (maximized) + name += QStringLiteral(" maximized "); + if (focus) + name += QStringLiteral(" focused"); + + name += QStringLiteral(")"); + } + + return name; } diff --git a/src/switcher-data-structs.cpp b/src/switcher-data-structs.cpp new file mode 100644 index 00000000..83217636 --- /dev/null +++ b/src/switcher-data-structs.cpp @@ -0,0 +1,96 @@ +#include "headers/switcher-data-structs.hpp" +#include "headers/utility.hpp" + +void SwitcherData::Prune() +{ + for (size_t i = 0; i < windowSwitches.size(); i++) { + WindowSceneSwitch &s = windowSwitches[i]; + if (!s.valid()) + windowSwitches.erase(windowSwitches.begin() + i--); + } + + if (nonMatchingScene && !WeakSourceValid(nonMatchingScene)) { + switchIfNotMatching = NO_SWITCH; + nonMatchingScene = nullptr; + } + + for (size_t i = 0; i < randomSwitches.size(); i++) { + RandomSwitch &s = randomSwitches[i]; + if (!s.valid()) + randomSwitches.erase(randomSwitches.begin() + i--); + } + + for (size_t i = 0; i < screenRegionSwitches.size(); i++) { + ScreenRegionSwitch &s = screenRegionSwitches[i]; + if (!s.valid()) + screenRegionSwitches.erase( + screenRegionSwitches.begin() + i--); + } + + for (size_t i = 0; i < pauseScenesSwitches.size(); i++) { + OBSWeakSource &scene = pauseScenesSwitches[i]; + if (!WeakSourceValid(scene)) + pauseScenesSwitches.erase(pauseScenesSwitches.begin() + + i--); + } + + for (size_t i = 0; i < sceneSequenceSwitches.size(); i++) { + SceneSequenceSwitch &s = sceneSequenceSwitches[i]; + if (!s.valid()) + sceneSequenceSwitches.erase( + sceneSequenceSwitches.begin() + i--); + } + + if (!WeakSourceValid(autoStopScene)) { + autoStopScene = nullptr; + autoStopEnable = false; + } + + for (size_t i = 0; i < sceneTransitions.size(); i++) { + SceneTransition &s = sceneTransitions[i]; + if (!s.valid()) + sceneTransitions.erase(sceneTransitions.begin() + i--); + } + + for (size_t i = 0; i < defaultSceneTransitions.size(); i++) { + DefaultSceneTransition &s = defaultSceneTransitions[i]; + if (!s.valid()) + defaultSceneTransitions.erase( + defaultSceneTransitions.begin() + i--); + } + + for (size_t i = 0; i < executableSwitches.size(); i++) { + ExecutableSceneSwitch &s = executableSwitches[i]; + if (!s.valid()) + executableSwitches.erase(executableSwitches.begin() + + i--); + } + + for (size_t i = 0; i < fileSwitches.size(); i++) { + FileSwitch &s = fileSwitches[i]; + if (!s.valid()) + fileSwitches.erase(fileSwitches.begin() + i--); + } + + for (size_t i = 0; i < timeSwitches.size(); i++) { + TimeSwitch &s = timeSwitches[i]; + if (!s.valid()) + timeSwitches.erase(timeSwitches.begin() + i--); + } + + if (!idleData.valid()) { + idleData.idleEnable = false; + } + + for (size_t i = 0; i < mediaSwitches.size(); i++) { + MediaSwitch &s = mediaSwitches[i]; + if (!s.valid()) + mediaSwitches.erase(mediaSwitches.begin() + i--); + } + + for (size_t i = 0; i < audioSwitches.size(); i++) { + AudioSwitch &s = audioSwitches[i]; + if (!s.valid()) + audioSwitches.erase(audioSwitches.begin() + i--); + } +} diff --git a/src/volume-control.cpp b/src/volume-control.cpp index 8ec51e64..842bbb74 100644 --- a/src/volume-control.cpp +++ b/src/volume-control.cpp @@ -20,7 +20,7 @@ QWeakPointer VolumeMeter::updateTimer; void VolControl::OBSVolumeChanged(void *data, float db) { Q_UNUSED(db); - VolControl *volControl = static_cast(data); + Q_UNUSED(data); } void VolControl::OBSVolumeLevel(void *data, @@ -35,6 +35,7 @@ void VolControl::OBSVolumeLevel(void *data, void VolControl::SliderChanged(int vol) { + Q_UNUSED(vol); updateText(); } diff --git a/src/win/advanced-scene-switcher-win.cpp b/src/win/advanced-scene-switcher-win.cpp index 4cca33a2..bd37e3a8 100644 --- a/src/win/advanced-scene-switcher-win.cpp +++ b/src/win/advanced-scene-switcher-win.cpp @@ -102,7 +102,7 @@ std::pair getCursorPos() return pos; } -bool isFullscreen(std::string &title) +bool isMaximized(std::string &title) { RECT appBounds; MONITORINFO monitorInfo = {0}; @@ -135,6 +135,39 @@ bool isFullscreen(std::string &title) return true; } } + return false; +} + +bool isFullscreen(std::string &title) +{ + RECT appBounds; + MONITORINFO monitorInfo = {0}; + + HWND hwnd = GetWindow(GetDesktopWindow(), GW_CHILD); + while (hwnd) { + string wtitle; + if (WindowValid(hwnd) && GetWindowTitle(hwnd, wtitle) && + (wtitle == title || + QString::fromStdString(wtitle).contains(QRegularExpression( + QString::fromStdString(title))))) + break; + + hwnd = GetNextWindow(hwnd, GW_HWNDNEXT); + } + + monitorInfo.cbSize = sizeof(MONITORINFO); + GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST), + &monitorInfo); + + if (hwnd && hwnd != GetDesktopWindow() && hwnd != GetShellWindow()) { + GetWindowRect(hwnd, &appBounds); + if (monitorInfo.rcMonitor.bottom == appBounds.bottom && + monitorInfo.rcMonitor.top == appBounds.top && + monitorInfo.rcMonitor.left == appBounds.left && + monitorInfo.rcMonitor.right == appBounds.right) { + return true; + } + } return false; }