diff --git a/advanced-scene-switcher-module.c b/advanced-scene-switcher-module.c index 4443d2cd..8835c04d 100644 --- a/advanced-scene-switcher-module.c +++ b/advanced-scene-switcher-module.c @@ -1,17 +1,17 @@ -#include - -OBS_DECLARE_MODULE() - -void InitSceneSwitcher(); -void FreeSceneSwitcher(); - -bool obs_module_load(void) -{ - InitSceneSwitcher(); - return true; -} - -void obs_module_unload(void) -{ - FreeSceneSwitcher(); -} +#include + +OBS_DECLARE_MODULE() + +void InitSceneSwitcher(); +void FreeSceneSwitcher(); + +bool obs_module_load(void) +{ + InitSceneSwitcher(); + return true; +} + +void obs_module_unload(void) +{ + FreeSceneSwitcher(); +} diff --git a/advanced-scene-switcher-win.cpp b/advanced-scene-switcher-win.cpp index 89f836de..576b54ee 100644 --- a/advanced-scene-switcher-win.cpp +++ b/advanced-scene-switcher-win.cpp @@ -1,172 +1,168 @@ -#include -#include -#include "advanced-scene-switcher.hpp" -#include -#include - -using namespace std; - -static bool GetWindowTitle(HWND window, string& title) -{ - size_t len = (size_t)GetWindowTextLengthW(window); - wstring wtitle; - - wtitle.resize(len); - if (!GetWindowTextW(window, &wtitle[0], (int)len + 1)) - return false; - - len = os_wcs_to_utf8(wtitle.c_str(), 0, nullptr, 0); - title.resize(len); - os_wcs_to_utf8(wtitle.c_str(), 0, &title[0], len + 1); - return true; -} - -static bool WindowValid(HWND window) -{ - LONG_PTR styles, ex_styles; - RECT rect; - DWORD id; - - if (!IsWindowVisible(window)) - return false; - GetWindowThreadProcessId(window, &id); - if (id == GetCurrentProcessId()) - return false; - - GetClientRect(window, &rect); - styles = GetWindowLongPtr(window, GWL_STYLE); - ex_styles = GetWindowLongPtr(window, GWL_EXSTYLE); - - if (ex_styles & WS_EX_TOOLWINDOW) - return false; - if (styles & WS_CHILD) - return false; - - return true; -} - -void GetWindowList(vector& windows) -{ - HWND window = GetWindow(GetDesktopWindow(), GW_CHILD); - - while (window) - { - string title; - if (WindowValid(window) && GetWindowTitle(window, title)) - windows.emplace_back(title); - window = GetNextWindow(window, GW_HWNDNEXT); - } -} - -void GetCurrentWindowTitle(string& title) -{ - HWND window = GetForegroundWindow(); - DWORD pid; - DWORD thid; - thid = GetWindowThreadProcessId(window, &pid); - /*GetWindowText will freeze if the control it is reading was created in another thread. - It does not directly read the control.Instead, - it waits for the thread that created the control to process a WM_GETTEXT message. - So if that thread is frozen in a WaitFor... call you have a deadlock.*/ - DWORD this_thid = GetCurrentThreadId(); - //wstring message = L"\nUI id " + to_wstring(thid) + L", this_th_id " + to_wstring(this_thid) + L"\n"; - //OutputDebugString(message.c_str()); - //if (this_thid == thid) { - if (GetCurrentProcessId() == pid) { - title = "OBS"; - return; - } - GetWindowTitle(window, title); -} - -pair getCursorPos() -{ - pair pos(0, 0); - POINT cursorPos; - if (GetPhysicalCursorPos(&cursorPos)) - { - pos.first = cursorPos.x; - pos.second = cursorPos.y; - } - return pos; -} - -bool isFullscreen() -{ - RECT appBounds; - RECT rc; - GetWindowRect(GetDesktopWindow(), &rc); - HWND hwnd = GetForegroundWindow(); - if (hwnd != GetDesktopWindow() && hwnd != GetShellWindow()) - { - GetWindowRect(hwnd, &appBounds); - if (rc.bottom == appBounds.bottom && rc.top == appBounds.top && rc.left == appBounds.left - && rc.right == appBounds.right) - { - return true; - } - } - return false; -} - -void GetProcessList(QStringList &processes) { - - HANDLE procSnapshot; - PROCESSENTRY32 procEntry; - - procSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - if (procSnapshot == INVALID_HANDLE_VALUE) return; - - procEntry.dwSize = sizeof(PROCESSENTRY32); - - if (!Process32First(procSnapshot, &procEntry)) { - CloseHandle(procSnapshot); - return; - } - - do { - QString tempexe = QString::fromWCharArray(procEntry.szExeFile); - if (tempexe == "System") continue; - if (tempexe == "[System Process]") continue; - if (processes.contains(tempexe)) continue; - processes.append(tempexe); - } while (Process32Next(procSnapshot, &procEntry)); - - CloseHandle(procSnapshot); -} - -bool isInFocus(const QString &exeToCheck) { - // only checks if the current foreground window is from the same executable, - // may return true for incorrent not meant windows from a program - HWND foregroundWindow = GetForegroundWindow(); - DWORD processId = 0; - GetWindowThreadProcessId(foregroundWindow, &processId); - - HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId); - if (process == NULL) return false; - - WCHAR executablePath[600]; - GetModuleFileNameEx(process, 0, executablePath, 600); - CloseHandle(process); - - return exeToCheck == QString::fromWCharArray(executablePath).split(QRegExp("(/|\\\\)")).back(); -} - -int getLastInputTime() -{ - LASTINPUTINFO lastInputInfo; - lastInputInfo.cbSize = sizeof(LASTINPUTINFO); - if (GetLastInputInfo(&lastInputInfo)) - return lastInputInfo.dwTime; - return 0; -} - -int getTime() -{ - return GetTickCount(); -} - -int secondsSinceLastInput() -{ - return (getTime() - getLastInputTime()) / 1000; -} +#include +#include +#include "advanced-scene-switcher.hpp" +#include +#include + +using namespace std; + +static bool GetWindowTitle(HWND window, string& title) +{ + size_t len = (size_t)GetWindowTextLengthW(window); + wstring wtitle; + + wtitle.resize(len); + if (!GetWindowTextW(window, &wtitle[0], (int)len + 1)) + return false; + + len = os_wcs_to_utf8(wtitle.c_str(), 0, nullptr, 0); + title.resize(len); + os_wcs_to_utf8(wtitle.c_str(), 0, &title[0], len + 1); + return true; +} + +static bool WindowValid(HWND window) +{ + LONG_PTR styles, ex_styles; + RECT rect; + DWORD id; + + if (!IsWindowVisible(window)) + return false; + GetWindowThreadProcessId(window, &id); + if (id == GetCurrentProcessId()) + return false; + + GetClientRect(window, &rect); + styles = GetWindowLongPtr(window, GWL_STYLE); + ex_styles = GetWindowLongPtr(window, GWL_EXSTYLE); + + if (ex_styles & WS_EX_TOOLWINDOW) + return false; + if (styles & WS_CHILD) + return false; + + return true; +} + +void GetWindowList(vector& windows) +{ + HWND window = GetWindow(GetDesktopWindow(), GW_CHILD); + + while (window) + { + string title; + if (WindowValid(window) && GetWindowTitle(window, title)) + windows.emplace_back(title); + window = GetNextWindow(window, GW_HWNDNEXT); + } +} + +void GetCurrentWindowTitle(string& title) +{ + HWND window = GetForegroundWindow(); + DWORD pid; + DWORD thid; + thid = GetWindowThreadProcessId(window, &pid); + /*GetWindowText will freeze if the control it is reading was created in another thread. + It does not directly read the control.Instead, + it waits for the thread that created the control to process a WM_GETTEXT message. + So if that thread is frozen in a WaitFor... call you have a deadlock.*/ + if (GetCurrentProcessId() == pid) { + title = "OBS"; + return; + } + GetWindowTitle(window, title); +} + +pair getCursorPos() +{ + pair pos(0, 0); + POINT cursorPos; + if (GetPhysicalCursorPos(&cursorPos)) + { + pos.first = cursorPos.x; + pos.second = cursorPos.y; + } + return pos; +} + +bool isFullscreen() +{ + RECT appBounds; + RECT rc; + GetWindowRect(GetDesktopWindow(), &rc); + HWND hwnd = GetForegroundWindow(); + if (hwnd != GetDesktopWindow() && hwnd != GetShellWindow()) + { + GetWindowRect(hwnd, &appBounds); + if (rc.bottom == appBounds.bottom && rc.top == appBounds.top && rc.left == appBounds.left + && rc.right == appBounds.right) + { + return true; + } + } + return false; +} + +void GetProcessList(QStringList &processes) { + + HANDLE procSnapshot; + PROCESSENTRY32 procEntry; + + procSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (procSnapshot == INVALID_HANDLE_VALUE) return; + + procEntry.dwSize = sizeof(PROCESSENTRY32); + + if (!Process32First(procSnapshot, &procEntry)) { + CloseHandle(procSnapshot); + return; + } + + do { + QString tempexe = QString::fromWCharArray(procEntry.szExeFile); + if (tempexe == "System") continue; + if (tempexe == "[System Process]") continue; + if (processes.contains(tempexe)) continue; + processes.append(tempexe); + } while (Process32Next(procSnapshot, &procEntry)); + + CloseHandle(procSnapshot); +} + +bool isInFocus(const QString &exeToCheck) { + // only checks if the current foreground window is from the same executable, + // may return true for incorrent not meant windows from a program + HWND foregroundWindow = GetForegroundWindow(); + DWORD processId = 0; + GetWindowThreadProcessId(foregroundWindow, &processId); + + HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId); + if (process == NULL) return false; + + WCHAR executablePath[600]; + GetModuleFileNameEx(process, 0, executablePath, 600); + CloseHandle(process); + + return exeToCheck == QString::fromWCharArray(executablePath).split(QRegExp("(/|\\\\)")).back(); +} + +int getLastInputTime() +{ + LASTINPUTINFO lastInputInfo; + lastInputInfo.cbSize = sizeof(LASTINPUTINFO); + if (GetLastInputInfo(&lastInputInfo)) + return lastInputInfo.dwTime; + return 0; +} + +int getTime() +{ + return GetTickCount(); +} + +int secondsSinceLastInput() +{ + return (getTime() - getLastInputTime()) / 1000; +} diff --git a/advanced-scene-switcher.cpp b/advanced-scene-switcher.cpp index 9b005052..b05d42cf 100644 --- a/advanced-scene-switcher.cpp +++ b/advanced-scene-switcher.cpp @@ -1,1186 +1,1194 @@ -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "switcher-data-structs.hpp" -#include "utility.hpp" -#include "advanced-scene-switcher.hpp" - - -SwitcherData* switcher = nullptr; - -SceneSwitcher::SceneSwitcher(QWidget* parent) - : QDialog(parent) - , ui(new Ui_SceneSwitcher) -{ - ui->setupUi(this); - - lock_guard lock(switcher->m); - - switcher->Prune(); - - BPtr scenes = obs_frontend_get_scene_names(); - char** temp = scenes; - while (*temp) - { - const char* name = *temp; - ui->scenes->addItem(name); - ui->noMatchSwitchScene->addItem(name); - ui->screenRegionScenes->addItem(name); - ui->pauseScenesScenes->addItem(name); - ui->sceneRoundTripScenes1->addItem(name); - ui->sceneRoundTripScenes2->addItem(name); - ui->autoStopScenes->addItem(name); - ui->transitionsScene1->addItem(name); - ui->transitionsScene2->addItem(name); - ui->defaultTransitionsScene->addItem(name); - ui->executableScenes->addItem(name); - ui->idleScenes->addItem(name); - ui->randomScenes->addItem(name); - ui->fileScenes->addItem(name); - temp++; - } - - obs_frontend_source_list* transitions = new obs_frontend_source_list(); - obs_frontend_get_transitions(transitions); - - for (size_t i = 0; i < transitions->sources.num; i++) - { - const char* name = obs_source_get_name(transitions->sources.array[i]); - ui->transitions->addItem(name); - ui->screenRegionsTransitions->addItem(name); - ui->sceneRoundTripTransitions->addItem(name); - ui->transitionsTransitions->addItem(name); - ui->defaultTransitionsTransitions->addItem(name); - ui->executableTransitions->addItem(name); - ui->idleTransitions->addItem(name); - ui->randomTransitions->addItem(name); - ui->fileTransitions->addItem(name); - } - - obs_frontend_source_list_free(transitions); - - - - if (switcher->switchIfNotMatching == SWITCH) - { - ui->noMatchSwitch->setChecked(true); - ui->noMatchSwitchScene->setEnabled(true); - } - else if (switcher->switchIfNotMatching == NO_SWITCH) - { - ui->noMatchDontSwitch->setChecked(true); - ui->noMatchSwitchScene->setEnabled(false); - } - else - { - ui->noMatchRandomSwitch->setChecked(true); - ui->noMatchSwitchScene->setEnabled(false); - } - ui->noMatchSwitchScene->setCurrentText(GetWeakSourceName(switcher->nonMatchingScene).c_str()); - ui->checkInterval->setValue(switcher->interval); - - vector windows; - GetWindowList(windows); - - for (string& window : windows) - { - ui->windows->addItem(window.c_str()); - ui->ignoreWindowsWindows->addItem(window.c_str()); - ui->pauseWindowsWindows->addItem(window.c_str()); - ui->ignoreIdleWindowsWindows->addItem(window.c_str()); - } - - QStringList processes; - GetProcessList(processes); - for (QString& process : processes) - ui->executable->addItem(process); - - for (auto& s : switcher->executableSwitches) - { - string sceneName = GetWeakSourceName(s.mScene); - string transitionName = GetWeakSourceName(s.mTransition); - QString text = MakeSwitchNameExecutable( - sceneName.c_str(), s.mExe, transitionName.c_str(), s.mInFocus); - - QListWidgetItem* item = new QListWidgetItem(text, ui->executables); - item->setData(Qt::UserRole, s.mExe); - } - - for (auto& s : switcher->switches) - { - string sceneName = GetWeakSourceName(s.scene); - string transitionName = GetWeakSourceName(s.transition); - QString text = MakeSwitchName( - sceneName.c_str(), s.window.c_str(), transitionName.c_str(), s.fullscreen); - - QListWidgetItem* item = new QListWidgetItem(text, ui->switches); - item->setData(Qt::UserRole, s.window.c_str()); - } - - for (auto& s : switcher->screenRegionSwitches) - { - string sceneName = GetWeakSourceName(s.scene); - string transitionName = GetWeakSourceName(s.transition); - QString text = MakeScreenRegionSwitchName( - sceneName.c_str(), transitionName.c_str(), s.minX, s.minY, s.maxX, s.maxY); - - QListWidgetItem* item = new QListWidgetItem(text, ui->screenRegions); - item->setData(Qt::UserRole, s.regionStr.c_str()); - } - - ui->autoStopSceneCheckBox->setChecked(switcher->autoStopEnable); - ui->autoStopScenes->setCurrentText(GetWeakSourceName(switcher->autoStopScene).c_str()); - - if (ui->autoStopSceneCheckBox->checkState()) - { - ui->autoStopScenes->setDisabled(false); - } - else - { - ui->autoStopScenes->setDisabled(true); - } - - for (auto& scene : switcher->pauseScenesSwitches) - { - string sceneName = GetWeakSourceName(scene); - QString text = QString::fromStdString(sceneName); - - QListWidgetItem* item = new QListWidgetItem(text, ui->pauseScenes); - item->setData(Qt::UserRole, text); - } - - for (auto& window : switcher->pauseWindowsSwitches) - { - QString text = QString::fromStdString(window); - - QListWidgetItem* item = new QListWidgetItem(text, ui->pauseWindows); - item->setData(Qt::UserRole, text); - } - - for (auto& window : switcher->ignoreWindowsSwitches) - { - QString text = QString::fromStdString(window); - - QListWidgetItem* item = new QListWidgetItem(text, ui->ignoreWindows); - item->setData(Qt::UserRole, text); - } - - int smallestDelay = switcher->interval; - for (auto& s : switcher->sceneRoundTripSwitches) - { - string sceneName1 = GetWeakSourceName(s.scene1); - string sceneName2 = GetWeakSourceName(s.scene2); - string transitionName = GetWeakSourceName(s.transition); - QString text = MakeSceneRoundTripSwitchName( - sceneName1.c_str(), sceneName2.c_str(), transitionName.c_str(), (double)s.delay / 1000); - - QListWidgetItem* item = new QListWidgetItem(text, ui->sceneRoundTrips); - item->setData(Qt::UserRole, text); - - if (s.delay < smallestDelay) - smallestDelay = s.delay; - } - (smallestDelay < switcher->interval) ? ui->intervalWarning->setVisible(true) : ui->intervalWarning->setVisible(false); - - for (auto& s : switcher->sceneTransitions) - { - string sceneName1 = GetWeakSourceName(s.scene1); - string sceneName2 = GetWeakSourceName(s.scene2); - string transitionName = GetWeakSourceName(s.transition); - QString text = MakeSceneTransitionName( - sceneName1.c_str(), sceneName2.c_str(), transitionName.c_str()); - - QListWidgetItem* item = 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) - { - string sceneName = GetWeakSourceName(s.scene); - string transitionName = GetWeakSourceName(s.transition); - QString text = MakeDefaultSceneTransitionName( - sceneName.c_str(), transitionName.c_str()); - - QListWidgetItem* item = new QListWidgetItem(text, ui->defaultTransitions); - item->setData(Qt::UserRole, text); - } - - for (auto& window : switcher->ignoreIdleWindows) - { - QString text = QString::fromStdString(window); - - QListWidgetItem* item = new QListWidgetItem(text, ui->ignoreIdleWindows); - item->setData(Qt::UserRole, text); - } - - for (auto& s : switcher->randomSwitches) - { - string sceneName = GetWeakSourceName(s.scene); - string transitionName = GetWeakSourceName(s.transition); - QString text = MakeRandomSwitchName( - sceneName.c_str(), transitionName.c_str(), s.delay); - - QListWidgetItem* item = new QListWidgetItem(text, ui->randomScenesList); - item->setData(Qt::UserRole, text); - } - - for (auto& s : switcher->fileSwitches) - { - string sceneName = GetWeakSourceName(s.scene); - string transitionName = GetWeakSourceName(s.transition); - QString listText = MakeFileSwitchName( - sceneName.c_str(), transitionName.c_str(), s.file.c_str(), s.text.c_str(), s.useRegex, s.useTime); - - QListWidgetItem* item = new QListWidgetItem(listText, ui->fileScenesList); - item->setData(Qt::UserRole, listText); - } - - ui->idleCheckBox->setChecked(switcher->idleData.idleEnable); - ui->idleScenes->setCurrentText(GetWeakSourceName(switcher->idleData.scene).c_str()); - ui->idleTransitions->setCurrentText(GetWeakSourceName(switcher->idleData.transition).c_str()); - ui->idleSpinBox->setValue(switcher->idleData.time); - - if (ui->idleCheckBox->checkState()) - { - ui->idleScenes->setDisabled(false); - ui->idleSpinBox->setDisabled(false); - ui->idleTransitions->setDisabled(false); - } - else - { - ui->idleScenes->setDisabled(true); - ui->idleSpinBox->setDisabled(true); - ui->idleTransitions->setDisabled(true); - } - - ui->readPathLineEdit->setText(QString::fromStdString(switcher->fileIO.readPath.c_str())); - ui->readFileCheckBox->setChecked(switcher->fileIO.readEnabled); - ui->writePathLineEdit->setText(QString::fromStdString(switcher->fileIO.writePath.c_str())); - - if (ui->readFileCheckBox->checkState()) - { - ui->browseButton_2->setDisabled(false); - ui->readPathLineEdit->setDisabled(false); - } - else - { - ui->browseButton_2->setDisabled(true); - ui->readPathLineEdit->setDisabled(true); - } - - if (switcher->th.joinable()) - SetStarted(); - else - SetStopped(); - - loading = false; - - // screen region cursor position - QTimer* screenRegionTimer = new QTimer(this); - connect(screenRegionTimer, SIGNAL(timeout()), this, SLOT(updateScreenRegionCursorPos())); - screenRegionTimer->start(1000); - - for (int p : switcher->functionNamesByPriority) - { - string s = ""; - switch (p) { - case READ_FILE_FUNC: - s = "File Content"; - break; - case ROUND_TRIP_FUNC: - s = "Scene Sequence"; - break; - case IDLE_FUNC: - s = "Idle Detection"; - break; - case EXE_FUNC: - s = "Executable"; - break; - case SCREEN_REGION_FUNC: - s = "Screen Region"; - break; - case WINDOW_TITLE_FUNC: - s = "Window Title"; - } - QString text(s.c_str()); - QListWidgetItem* item = new QListWidgetItem(text, ui->priorityList); - item->setData(Qt::UserRole, text); - } - -} - - - -static void SaveSceneSwitcher(obs_data_t* save_data, bool saving, void*) -{ - if (saving) - { - lock_guard lock(switcher->m); - obs_data_t* obj = obs_data_create(); - obs_data_array_t* array = obs_data_array_create(); - obs_data_array_t* screenRegionArray = obs_data_array_create(); - obs_data_array_t* pauseScenesArray = obs_data_array_create(); - obs_data_array_t* pauseWindowsArray = obs_data_array_create(); - obs_data_array_t* ignoreWindowsArray = obs_data_array_create(); - obs_data_array_t* sceneRoundTripArray = obs_data_array_create(); - obs_data_array_t* sceneTransitionsArray = obs_data_array_create(); - obs_data_array_t* defaultTransitionsArray = obs_data_array_create(); - obs_data_array_t* ignoreIdleWindowsArray = obs_data_array_create(); - obs_data_array_t* executableArray = obs_data_array_create(); - obs_data_array_t* randomArray = obs_data_array_create(); - obs_data_array_t* fileArray = obs_data_array_create(); - - switcher->Prune(); - - for (SceneSwitch& s : switcher->switches) - { - obs_data_t* array_obj = obs_data_create(); - - obs_source_t* source = obs_weak_source_get_source(s.scene); - obs_source_t* transition = obs_weak_source_get_source(s.transition); - if (source && transition) - { - const char* sceneName = obs_source_get_name(source); - const char* transitionName = obs_source_get_name(transition); - obs_data_set_string(array_obj, "scene", sceneName); - obs_data_set_string(array_obj, "transition", transitionName); - obs_data_set_string(array_obj, "window_title", s.window.c_str()); - obs_data_set_bool(array_obj, "fullscreen", s.fullscreen); - obs_data_array_push_back(array, array_obj); - obs_source_release(source); - obs_source_release(transition); - } - - obs_data_release(array_obj); - } - - for (ScreenRegionSwitch& s : switcher->screenRegionSwitches) - { - obs_data_t* array_obj = obs_data_create(); - - obs_source_t* source = obs_weak_source_get_source(s.scene); - obs_source_t* transition = obs_weak_source_get_source(s.transition); - if (source && transition) - { - const char* sceneName = obs_source_get_name(source); - const char* transitionName = obs_source_get_name(transition); - obs_data_set_string(array_obj, "screenRegionScene", sceneName); - obs_data_set_string(array_obj, "transition", transitionName); - obs_data_set_int(array_obj, "minX", s.minX); - 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); - } - - obs_data_release(array_obj); - } - - for (OBSWeakSource& scene : switcher->pauseScenesSwitches) - { - obs_data_t* array_obj = obs_data_create(); - - obs_source_t* source = obs_weak_source_get_source(scene); - if (source) - { - const char* n = obs_source_get_name(source); - obs_data_set_string(array_obj, "pauseScene", n); - obs_data_array_push_back(pauseScenesArray, array_obj); - obs_source_release(source); - } - - obs_data_release(array_obj); - } - - for (string& window : switcher->pauseWindowsSwitches) - { - obs_data_t* array_obj = obs_data_create(); - obs_data_set_string(array_obj, "pauseWindow", window.c_str()); - obs_data_array_push_back(pauseWindowsArray, array_obj); - obs_data_release(array_obj); - } - - for (string& window : switcher->ignoreWindowsSwitches) - { - obs_data_t* array_obj = obs_data_create(); - obs_data_set_string(array_obj, "ignoreWindow", window.c_str()); - obs_data_array_push_back(ignoreWindowsArray, array_obj); - obs_data_release(array_obj); - } - - for (SceneRoundTripSwitch& s : switcher->sceneRoundTripSwitches) - { - 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* transition = obs_weak_source_get_source(s.transition); - if (source1 && source2 && transition) - { - const char* sceneName1 = obs_source_get_name(source1); - const char* sceneName2 = obs_source_get_name(source2); - const char* transitionName = obs_source_get_name(transition); - obs_data_set_string(array_obj, "sceneRoundTripScene1", sceneName1); - obs_data_set_string(array_obj, "sceneRoundTripScene2", sceneName2); - obs_data_set_string(array_obj, "transition", transitionName); - obs_data_set_int(array_obj, "sceneRoundTripDelay", s.delay / 1000); - obs_data_set_int(array_obj, "sceneRoundTripDelayMs", s.delay % 1000); //extra value for ms to not destroy settings of old versions - obs_data_set_string(array_obj, "sceneRoundTripStr", s.sceneRoundTripStr.c_str()); - obs_data_array_push_back(sceneRoundTripArray, array_obj); - obs_source_release(source1); - obs_source_release(source2); - obs_source_release(transition); - } - - obs_data_release(array_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* source2 = obs_weak_source_get_source(s.scene2); - obs_source_t* transition = obs_weak_source_get_source(s.transition); - if (source1 && source2 && transition) - { - const char* sceneName1 = obs_source_get_name(source1); - const char* sceneName2 = obs_source_get_name(source2); - const char* transitionName = obs_source_get_name(transition); - obs_data_set_string(array_obj, "Scene1", sceneName1); - 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); - obs_source_release(source2); - obs_source_release(transition); - } - - obs_data_release(array_obj); - } - - for (DefaultSceneTransition& s : switcher->defaultSceneTransitions) - { - obs_data_t* array_obj = obs_data_create(); - - obs_source_t* source = obs_weak_source_get_source(s.scene); - obs_source_t* transition = obs_weak_source_get_source(s.transition); - if (source && transition) - { - const char* sceneName = obs_source_get_name(source); - const char* transitionName = obs_source_get_name(transition); - obs_data_set_string(array_obj, "Scene", sceneName); - obs_data_set_string(array_obj, "transition", transitionName); - obs_data_set_string(array_obj, "Str", s.sceneTransitionStr.c_str()); - obs_data_array_push_back(defaultTransitionsArray, array_obj); - obs_source_release(source); - obs_source_release(transition); - } - - obs_data_release(array_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* transition = obs_weak_source_get_source(s.mTransition); - - if (source && transition) - { - const char* sceneName = obs_source_get_name(source); - const char* transitionName = obs_source_get_name(transition); - obs_data_set_string(array_obj, "scene", sceneName); - obs_data_set_string(array_obj, "transition", transitionName); - obs_data_set_string(array_obj, "exefile", s.mExe.toUtf8()); - obs_data_set_bool(array_obj, "infocus", s.mInFocus); - obs_data_array_push_back(executableArray, array_obj); - obs_source_release(source); - obs_source_release(transition); - } - - obs_data_release(array_obj); - } - - for (RandomSwitch& s : switcher->randomSwitches) - { - obs_data_t* array_obj = obs_data_create(); - - obs_source_t* source = obs_weak_source_get_source(s.scene); - obs_source_t* transition = obs_weak_source_get_source(s.transition); - - if (source && transition) - { - const char* sceneName = obs_source_get_name(source); - const char* transitionName = obs_source_get_name(transition); - obs_data_set_string(array_obj, "scene", sceneName); - obs_data_set_string(array_obj, "transition", transitionName); - obs_data_set_double(array_obj, "delay", s.delay); - obs_data_set_string(array_obj, "str", s.randomSwitchStr.c_str()); - obs_data_array_push_back(randomArray, array_obj); - obs_source_release(source); - obs_source_release(transition); - } - - obs_data_release(array_obj); - } - - for (string& window : switcher->ignoreIdleWindows) - { - obs_data_t* array_obj = obs_data_create(); - obs_data_set_string(array_obj, "window", window.c_str()); - obs_data_array_push_back(ignoreIdleWindowsArray, array_obj); - obs_data_release(array_obj); - } - - for (FileSwitch& s : switcher->fileSwitches) - { - obs_data_t* array_obj = obs_data_create(); - - obs_source_t* source = obs_weak_source_get_source(s.scene); - obs_source_t* transition = obs_weak_source_get_source(s.transition); - - if (source && transition) - { - const char* sceneName = obs_source_get_name(source); - const char* transitionName = obs_source_get_name(transition); - obs_data_set_string(array_obj, "scene", sceneName); - obs_data_set_string(array_obj, "transition", transitionName); - obs_data_set_string(array_obj, "file", s.file.c_str()); - obs_data_set_string(array_obj, "text", s.text.c_str()); - obs_data_set_bool(array_obj, "useRegex", s.useRegex); - obs_data_set_bool(array_obj, "useTime", s.useTime); - obs_data_array_push_back(fileArray, array_obj); - obs_source_release(source); - obs_source_release(transition); - } - - obs_data_release(array_obj); - } - - string nonMatchingSceneName = GetWeakSourceName(switcher->nonMatchingScene); - - obs_data_set_int(obj, "interval", switcher->interval); - obs_data_set_string(obj, "non_matching_scene", nonMatchingSceneName.c_str()); - obs_data_set_int(obj, "switch_if_not_matching", switcher->switchIfNotMatching); - obs_data_set_bool(obj, "active", !switcher->stop); - - obs_data_set_array(obj, "switches", array); - obs_data_set_array(obj, "screenRegion", screenRegionArray); - obs_data_set_array(obj, "pauseScenes", pauseScenesArray); - obs_data_set_array(obj, "pauseWindows", pauseWindowsArray); - obs_data_set_array(obj, "ignoreWindows", ignoreWindowsArray); - obs_data_set_array(obj, "sceneRoundTrip", sceneRoundTripArray); - obs_data_set_array(obj, "sceneTransitions", sceneTransitionsArray); - obs_data_set_array(obj, "defaultTransitions", defaultTransitionsArray); - obs_data_set_array(obj, "executableSwitches", executableArray); - obs_data_set_array(obj, "ignoreIdleWindows", ignoreIdleWindowsArray); - obs_data_set_array(obj, "randomSwitches", randomArray); - obs_data_set_array(obj, "fileSwitches", fileArray); - - - string autoStopSceneName = GetWeakSourceName(switcher->autoStopScene); - obs_data_set_bool(obj, "autoStopEnable", switcher->autoStopEnable); - obs_data_set_string(obj, "autoStopSceneName", autoStopSceneName.c_str()); - - string idleSceneName = GetWeakSourceName(switcher->idleData.scene); - string idleTransitionName = GetWeakSourceName(switcher->idleData.transition); - obs_data_set_bool(obj, "idleEnable", switcher->idleData.idleEnable); - obs_data_set_string(obj, "idleSceneName", idleSceneName.c_str()); - obs_data_set_string(obj, "idleTransitionName", idleTransitionName.c_str()); - obs_data_set_int(obj, "idleTime", switcher->idleData.time); - - obs_data_set_bool(obj, "readEnabled", switcher->fileIO.readEnabled); - obs_data_set_string(obj, "readPath", switcher->fileIO.readPath.c_str()); - obs_data_set_bool(obj, "writeEnabled", switcher->fileIO.writeEnabled); - obs_data_set_string(obj, "writePath", switcher->fileIO.writePath.c_str()); - - obs_data_set_int(obj, "priority0", switcher->functionNamesByPriority[0]); - obs_data_set_int(obj, "priority1", switcher->functionNamesByPriority[1]); - obs_data_set_int(obj, "priority2", switcher->functionNamesByPriority[2]); - obs_data_set_int(obj, "priority3", switcher->functionNamesByPriority[3]); - obs_data_set_int(obj, "priority4", switcher->functionNamesByPriority[4]); - obs_data_set_int(obj, "priority5", switcher->functionNamesByPriority[5]); - - obs_data_set_obj(save_data, "advanced-scene-switcher", obj); - - obs_data_array_release(array); - obs_data_array_release(screenRegionArray); - obs_data_array_release(pauseScenesArray); - obs_data_array_release(pauseWindowsArray); - obs_data_array_release(ignoreWindowsArray); - obs_data_array_release(sceneRoundTripArray); - obs_data_array_release(sceneTransitionsArray); - obs_data_array_release(defaultTransitionsArray); - obs_data_array_release(executableArray); - obs_data_array_release(ignoreIdleWindowsArray); - obs_data_array_release(randomArray); - obs_data_array_release(fileArray); - - obs_data_release(obj); - } - else - { - switcher->m.lock(); - - obs_data_t* obj = obs_data_get_obj(save_data, "advanced-scene-switcher"); - obs_data_array_t* array = obs_data_get_array(obj, "switches"); - obs_data_array_t* screenRegionArray = obs_data_get_array(obj, "screenRegion"); - obs_data_array_t* pauseScenesArray = obs_data_get_array(obj, "pauseScenes"); - obs_data_array_t* pauseWindowsArray = obs_data_get_array(obj, "pauseWindows"); - obs_data_array_t* ignoreWindowsArray = obs_data_get_array(obj, "ignoreWindows"); - obs_data_array_t* sceneRoundTripArray = obs_data_get_array(obj, "sceneRoundTrip"); - obs_data_array_t* sceneTransitionsArray = obs_data_get_array(obj, "sceneTransitions"); - obs_data_array_t* defaultTransitionsArray = obs_data_get_array(obj, "defaultTransitions"); - obs_data_array_t* executableArray = obs_data_get_array(obj, "executableSwitches"); - obs_data_array_t* ignoreIdleWindowsArray = obs_data_get_array(obj, "ignoreIdleWindows"); - obs_data_array_t* randomArray = obs_data_get_array(obj, "randomSwitches"); - obs_data_array_t* fileArray = obs_data_get_array(obj, "fileSwitches"); - - if (!obj) - obj = obs_data_create(); - - obs_data_set_default_int(obj, "interval", DEFAULT_INTERVAL); - - switcher->interval = obs_data_get_int(obj, "interval"); - obs_data_set_default_int(obj, "switch_if_not_matching", NO_SWITCH); - switcher->switchIfNotMatching = (NoMatch)obs_data_get_int(obj, "switch_if_not_matching"); - string nonMatchingScene = obs_data_get_string(obj, "non_matching_scene"); - bool active = obs_data_get_bool(obj, "active"); - - switcher->nonMatchingScene = GetWeakSourceByName(nonMatchingScene.c_str()); - - switcher->switches.clear(); - size_t count = obs_data_array_count(array); - - for (size_t i = 0; i < count; i++) - { - obs_data_t* array_obj = obs_data_array_item(array, i); - - const char* scene = obs_data_get_string(array_obj, "scene"); - const char* transition = obs_data_get_string(array_obj, "transition"); - const char* window = obs_data_get_string(array_obj, "window_title"); - bool fullscreen = obs_data_get_bool(array_obj, "fullscreen"); - - switcher->switches.emplace_back(GetWeakSourceByName(scene), window, - GetWeakTransitionByName(transition), fullscreen); - - obs_data_release(array_obj); - } - - switcher->screenRegionSwitches.clear(); - count = obs_data_array_count(screenRegionArray); - - for (size_t i = 0; i < count; i++) - { - obs_data_t* array_obj = obs_data_array_item(screenRegionArray, i); - - const char* scene = obs_data_get_string(array_obj, "screenRegionScene"); - const char* transition = obs_data_get_string(array_obj, "transition"); - int minX = obs_data_get_int(array_obj, "minX"); - 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"); - string regionStr = obs_data_get_string(array_obj, "screenRegionStr"); - - switcher->screenRegionSwitches.emplace_back(GetWeakSourceByName(scene), - GetWeakTransitionByName(transition), minX, minY, maxX, maxY, regionStr); - - obs_data_release(array_obj); - } - - switcher->pauseScenesSwitches.clear(); - count = obs_data_array_count(pauseScenesArray); - - for (size_t i = 0; i < count; i++) - { - obs_data_t* array_obj = obs_data_array_item(pauseScenesArray, i); - - const char* scene = obs_data_get_string(array_obj, "pauseScene"); - - switcher->pauseScenesSwitches.emplace_back(GetWeakSourceByName(scene)); - - obs_data_release(array_obj); - } - - switcher->pauseWindowsSwitches.clear(); - count = obs_data_array_count(pauseWindowsArray); - - for (size_t i = 0; i < count; i++) - { - obs_data_t* array_obj = obs_data_array_item(pauseWindowsArray, i); - - const char* window = obs_data_get_string(array_obj, "pauseWindow"); - - switcher->pauseWindowsSwitches.emplace_back(window); - - obs_data_release(array_obj); - } - - obs_data_array_release(pauseWindowsArray); - - switcher->ignoreWindowsSwitches.clear(); - count = obs_data_array_count(ignoreWindowsArray); - - for (size_t i = 0; i < count; i++) - { - obs_data_t* array_obj = obs_data_array_item(ignoreWindowsArray, i); - - const char* window = obs_data_get_string(array_obj, "ignoreWindow"); - - switcher->ignoreWindowsSwitches.emplace_back(window); - - obs_data_release(array_obj); - } - - switcher->sceneRoundTripSwitches.clear(); - count = obs_data_array_count(sceneRoundTripArray); - - for (size_t i = 0; i < count; i++) - { - obs_data_t* array_obj = obs_data_array_item(sceneRoundTripArray, i); - - const char* scene1 = obs_data_get_string(array_obj, "sceneRoundTripScene1"); - const char* scene2 = obs_data_get_string(array_obj, "sceneRoundTripScene2"); - const char* transition = obs_data_get_string(array_obj, "transition"); - int delay = obs_data_get_int(array_obj, "sceneRoundTripDelay"); - delay = delay * 1000 + obs_data_get_int(array_obj, "sceneRoundTripDelayMs"); //extra value for ms to not destroy settings of old versions - string str = MakeSceneRoundTripSwitchName(scene1, scene2, transition, ((double)delay)/1000.0).toUtf8().constData(); //aaaand i broke it - const char* sceneRoundTripStr = str.c_str(); - - switcher->sceneRoundTripSwitches.emplace_back(GetWeakSourceByName(scene1), - GetWeakSourceByName(scene2), GetWeakTransitionByName(transition), delay, - sceneRoundTripStr); - - obs_data_release(array_obj); - } - - switcher->sceneTransitions.clear(); - count = obs_data_array_count(sceneTransitionsArray); - - for (size_t i = 0; i < count; i++) - { - obs_data_t* array_obj = obs_data_array_item(sceneTransitionsArray, i); - - const char* scene1 = obs_data_get_string(array_obj, "Scene1"); - 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"); - - switcher->sceneTransitions.emplace_back(GetWeakSourceByName(scene1), - GetWeakSourceByName(scene2), GetWeakTransitionByName(transition), - sceneTransitionsStr); - - obs_data_release(array_obj); - } - - switcher->defaultSceneTransitions.clear(); - count = obs_data_array_count(defaultTransitionsArray); - - for (size_t i = 0; i < count; i++) - { - obs_data_t* array_obj = obs_data_array_item(defaultTransitionsArray, i); - - 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"); - - switcher->defaultSceneTransitions.emplace_back(GetWeakSourceByName(scene), - GetWeakTransitionByName(transition), - sceneTransitionsStr); - - obs_data_release(array_obj); - } - - switcher->executableSwitches.clear(); - count = obs_data_array_count(executableArray); - - for (size_t i = 0; i < count; i++) - { - obs_data_t* array_obj = obs_data_array_item(executableArray, i); - - const char* scene = obs_data_get_string(array_obj, "scene"); - const char* transition = obs_data_get_string(array_obj, "transition"); - const char* exe = obs_data_get_string(array_obj, "exefile"); - bool infocus = obs_data_get_bool(array_obj, "infocus"); - - switcher->executableSwitches.emplace_back( - GetWeakSourceByName(scene), GetWeakTransitionByName(transition), exe, infocus); - - obs_data_release(array_obj); - } - - switcher->ignoreIdleWindows.clear(); - count = obs_data_array_count(ignoreIdleWindowsArray); - - for (size_t i = 0; i < count; i++) - { - obs_data_t* array_obj = obs_data_array_item(ignoreIdleWindowsArray, i); - - const char* window = obs_data_get_string(array_obj, "window"); - - switcher->ignoreIdleWindows.emplace_back(window); - - obs_data_release(array_obj); - } - - switcher->randomSwitches.clear(); - count = obs_data_array_count(randomArray); - - for (size_t i = 0; i < count; i++) - { - obs_data_t* array_obj = obs_data_array_item(randomArray, i); - - const char* scene = obs_data_get_string(array_obj, "scene"); - const char* transition = obs_data_get_string(array_obj, "transition"); - double delay = obs_data_get_double(array_obj, "delay"); - const char* str = obs_data_get_string(array_obj, "str"); - - switcher->randomSwitches.emplace_back( - GetWeakSourceByName(scene), GetWeakTransitionByName(transition), delay, str); - - obs_data_release(array_obj); - } - - switcher->fileSwitches.clear(); - count = obs_data_array_count(fileArray); - - for (size_t i = 0; i < count; i++) - { - obs_data_t* array_obj = obs_data_array_item(fileArray, i); - - const char* scene = obs_data_get_string(array_obj, "scene"); - const char* transition = obs_data_get_string(array_obj, "transition"); - const char* file = obs_data_get_string(array_obj, "file"); - const char* text = obs_data_get_string(array_obj, "text"); - bool useRegex = obs_data_get_bool(array_obj, "useRegex"); - bool useTime = obs_data_get_bool(array_obj, "useTime"); - - switcher->fileSwitches.emplace_back( - GetWeakSourceByName(scene), GetWeakTransitionByName(transition), file, text, useRegex, useTime); - - obs_data_release(array_obj); - } - - string autoStopScene = obs_data_get_string(obj, "autoStopSceneName"); - switcher->autoStopEnable = obs_data_get_bool(obj, "autoStopEnable"); - switcher->autoStopScene = GetWeakSourceByName(autoStopScene.c_str()); - - string idleSceneName = obs_data_get_string(obj, "idleSceneName"); - string idleTransitionName = obs_data_get_string(obj, "idleTransitionName"); - switcher->idleData.scene = GetWeakSourceByName(idleSceneName.c_str()); - switcher->idleData.transition = GetWeakTransitionByName(idleTransitionName.c_str()); - obs_data_set_default_bool(obj, "idleEnable", false); - switcher->idleData.idleEnable = obs_data_get_bool(obj, "idleEnable"); - obs_data_set_default_int(obj, "idleTime", DEFAULT_IDLE_TIME); - switcher->idleData.time = obs_data_get_int(obj, "idleTime"); - - obs_data_set_default_bool(obj, "readEnabled", false); - switcher->fileIO.readEnabled = obs_data_get_bool(obj, "readEnabled"); - switcher->fileIO.readPath = obs_data_get_string(obj, "readPath"); - obs_data_set_default_bool(obj, "writeEnabled", false); - switcher->fileIO.writeEnabled = obs_data_get_bool(obj, "writeEnabled"); - switcher->fileIO.writePath = obs_data_get_string(obj, "writePath"); - - obs_data_set_default_int(obj, "priority0", DEFAULT_PRIORITY_0); - obs_data_set_default_int(obj, "priority1", DEFAULT_PRIORITY_1); - obs_data_set_default_int(obj, "priority2", DEFAULT_PRIORITY_2); - obs_data_set_default_int(obj, "priority3", DEFAULT_PRIORITY_3); - obs_data_set_default_int(obj, "priority4", DEFAULT_PRIORITY_4); - obs_data_set_default_int(obj, "priority5", DEFAULT_PRIORITY_5); - - switcher->functionNamesByPriority[0] = (obs_data_get_int(obj, "priority0")); - switcher->functionNamesByPriority[1] = (obs_data_get_int(obj, "priority1")); - switcher->functionNamesByPriority[2] = (obs_data_get_int(obj, "priority2")); - switcher->functionNamesByPriority[3] = (obs_data_get_int(obj, "priority3")); - switcher->functionNamesByPriority[4] = (obs_data_get_int(obj, "priority4")); - switcher->functionNamesByPriority[5] = (obs_data_get_int(obj, "priority5")); - if (!switcher->prioFuncsValid()) - { - switcher->functionNamesByPriority[0] = (DEFAULT_PRIORITY_0); - switcher->functionNamesByPriority[1] = (DEFAULT_PRIORITY_1); - switcher->functionNamesByPriority[2] = (DEFAULT_PRIORITY_2); - switcher->functionNamesByPriority[3] = (DEFAULT_PRIORITY_3); - switcher->functionNamesByPriority[4] = (DEFAULT_PRIORITY_4); - switcher->functionNamesByPriority[5] = (DEFAULT_PRIORITY_5); - } - - obs_data_array_release(array); - obs_data_array_release(screenRegionArray); - obs_data_array_release(pauseScenesArray); - obs_data_array_release(ignoreWindowsArray); - obs_data_array_release(sceneRoundTripArray); - obs_data_array_release(sceneTransitionsArray); - obs_data_array_release(defaultTransitionsArray); - obs_data_array_release(executableArray); - obs_data_array_release(ignoreIdleWindowsArray); - obs_data_array_release(randomArray); - obs_data_array_release(fileArray); - - obs_data_release(obj); - - switcher->m.unlock(); - - if (active) - switcher->Start(); - else - switcher->Stop(); - } -} - -bool SwitcherData::sceneChangedDuringWait(){ - bool r = false; - obs_source_t* currentSource = obs_frontend_get_current_scene(); - if (!currentSource) - return true; - string curName = (obs_source_get_name(currentSource)); - obs_source_release(currentSource); - if (!waitSceneName.empty() && curName != waitSceneName) - r = true; - waitSceneName = ""; - return r; -} - -obs_weak_source_t* getNextTransition(obs_weak_source_t* scene1, obs_weak_source_t* scene2); - -void switchScene(OBSWeakSource scene, OBSWeakSource transition) -{ - obs_source_t* source = obs_weak_source_get_source(scene); - obs_source_t* currentSource = obs_frontend_get_current_scene(); - - if (source && source != currentSource) - { - obs_weak_source_t* currentScene = obs_source_get_weak_source(currentSource); - obs_weak_source_t* nextTransitionWs = getNextTransition(currentScene, scene); - obs_weak_source_release(currentScene); - - if (nextTransitionWs) - { - obs_source_t* nextTransition = obs_weak_source_get_source(nextTransitionWs); - //lock.unlock(); - //transitionCv.wait(transitionLock, transitionActiveCheck); - //lock.lock(); - obs_frontend_set_current_transition(nextTransition); - obs_source_release(nextTransition); - } - else if (transition) - { - obs_source_t* nextTransition = obs_weak_source_get_source(transition); - //lock.unlock(); - //transitionCv.wait(transitionLock, transitionActiveCheck); - //lock.lock(); - obs_frontend_set_current_transition(nextTransition); - obs_source_release(nextTransition); - } - obs_frontend_set_current_scene(source); - obs_weak_source_release(nextTransitionWs); - } - obs_source_release(currentSource); - obs_source_release(source); -} - -void SwitcherData::Thread() -{ - - //to avoid scene duplication when rapidly switching scene collection - this_thread::sleep_for(chrono::seconds(2)); - - int sleep = 0; - - while (true) - { - startLoop: - unique_lock lock(m); - bool match = false; - OBSWeakSource scene; - OBSWeakSource transition; - chrono::milliseconds duration; - if (sleep > interval) - duration = chrono::milliseconds(sleep); - else - duration = chrono::milliseconds(interval); - sleep = 0; - switcher->Prune(); - writeSceneInfoToFile(); - //sleep for a bit - cv.wait_for(lock, duration); - if (switcher->stop) - { - break; - } - setDefaultSceneTransitions(lock); - if (autoStopEnable) - { - autoStopStreamAndRecording(); - } - if (checkPause()) - { - continue; - } - - for (int switchFuncName : functionNamesByPriority) - { - switch (switchFuncName) { - case READ_FILE_FUNC: - checkSwitchInfoFromFile(match, scene, transition); - checkFileContent(match, scene, transition); - break; - case IDLE_FUNC: - checkIdleSwitch(match, scene, transition); - break; - case EXE_FUNC: - checkExeSwitch(match, scene, transition); - break; - - case SCREEN_REGION_FUNC: - checkScreenRegionSwitch(match, scene, transition); - break; - case WINDOW_TITLE_FUNC: - checkWindowTitleSwitch(match, scene, transition); - break; - case ROUND_TRIP_FUNC: - checkSceneRoundTrip(match, scene, transition, lock); - if (sceneChangedDuringWait()) //scene might have changed during the sleep - { - goto startLoop; - } - } - if (switcher->stop) - { - goto endLoop; - } - if (match) - { - break; - } - } - - if (!match && switchIfNotMatching == SWITCH && nonMatchingScene) - { - match = true; - scene = nonMatchingScene; - transition = nullptr; - } - if (!match && switchIfNotMatching == RANDOM_SWITCH) - { - checkRandom(match, scene, transition, sleep); - } - if (match) - { - switchScene(scene, transition); - } - } -endLoop: - ; -} - -void SwitcherData::Start() -{ - if (!th.joinable()) - { - stop = false; - switcher->th = thread([]() - { - switcher->Thread(); - }); - } -} - -void SwitcherData::Stop() -{ - if (th.joinable()) - { - switcher->stop = true; - transitionCv.notify_one(); - cv.notify_one(); - th.join(); - } -} - -extern "C" void FreeSceneSwitcher() -{ - delete switcher; - switcher = nullptr; -} - -static void OBSEvent(enum obs_frontend_event event, void* switcher) -{ - switch (event){ - case OBS_FRONTEND_EVENT_EXIT: - FreeSceneSwitcher(); - break; - - case OBS_FRONTEND_EVENT_SCENE_CHANGED: - { - SwitcherData* s = (SwitcherData*)switcher; - //wakeup if waiting on timer if scene already changed - lock_guard lock(s->m); - if (s->sceneChangedDuringWait()) - s->cv.notify_one(); - break; - } - default: - break; - } -} - -void startStopHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotkey, bool pressed); -void loadKeybinding(obs_hotkey_id hotkeyId); - -extern "C" void InitSceneSwitcher() -{ - QAction* action - = (QAction*)obs_frontend_add_tools_menu_qaction("Advanced Scene Switcher"); - - switcher = new SwitcherData; - - auto cb = []() - { - QMainWindow* window = (QMainWindow*)obs_frontend_get_main_window(); - - SceneSwitcher ss(window); - ss.exec(); - }; - - obs_frontend_add_save_callback(SaveSceneSwitcher, nullptr); - obs_frontend_add_event_callback(OBSEvent, switcher); - - action->connect(action, &QAction::triggered, cb); - - char* path = obs_module_config_path(""); - QDir dir(path); - if (!dir.exists()) - { - dir.mkpath("."); - } - bfree(path); - - obs_hotkey_id pauseHotkeyId = obs_hotkey_register_frontend("startStopSwitcherHotkey", - "Toggle Start/Stop for the Advanced Scene Switcher", startStopHotkeyFunc, NULL); - loadKeybinding(pauseHotkeyId); -} +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "switcher-data-structs.hpp" +#include "utility.hpp" +#include "advanced-scene-switcher.hpp" + + +SwitcherData* switcher = nullptr; + + +/******************************************************************************** + * Create the Advanced Scene Switcher settings window + ********************************************************************************/ +SceneSwitcher::SceneSwitcher(QWidget* parent) + : QDialog(parent) + , ui(new Ui_SceneSwitcher) +{ + ui->setupUi(this); + + lock_guard lock(switcher->m); + + switcher->Prune(); + + BPtr scenes = obs_frontend_get_scene_names(); + char** temp = scenes; + while (*temp) + { + const char* name = *temp; + ui->scenes->addItem(name); + ui->noMatchSwitchScene->addItem(name); + ui->screenRegionScenes->addItem(name); + ui->pauseScenesScenes->addItem(name); + ui->sceneRoundTripScenes1->addItem(name); + ui->sceneRoundTripScenes2->addItem(name); + ui->autoStopScenes->addItem(name); + ui->transitionsScene1->addItem(name); + ui->transitionsScene2->addItem(name); + ui->defaultTransitionsScene->addItem(name); + ui->executableScenes->addItem(name); + ui->idleScenes->addItem(name); + ui->randomScenes->addItem(name); + ui->fileScenes->addItem(name); + temp++; + } + + obs_frontend_source_list* transitions = new obs_frontend_source_list(); + obs_frontend_get_transitions(transitions); + + for (size_t i = 0; i < transitions->sources.num; i++) + { + const char* name = obs_source_get_name(transitions->sources.array[i]); + ui->transitions->addItem(name); + ui->screenRegionsTransitions->addItem(name); + ui->sceneRoundTripTransitions->addItem(name); + ui->transitionsTransitions->addItem(name); + ui->defaultTransitionsTransitions->addItem(name); + ui->executableTransitions->addItem(name); + ui->idleTransitions->addItem(name); + ui->randomTransitions->addItem(name); + ui->fileTransitions->addItem(name); + } + + obs_frontend_source_list_free(transitions); + + + + if (switcher->switchIfNotMatching == SWITCH) + { + ui->noMatchSwitch->setChecked(true); + ui->noMatchSwitchScene->setEnabled(true); + } + else if (switcher->switchIfNotMatching == NO_SWITCH) + { + ui->noMatchDontSwitch->setChecked(true); + ui->noMatchSwitchScene->setEnabled(false); + } + else + { + ui->noMatchRandomSwitch->setChecked(true); + ui->noMatchSwitchScene->setEnabled(false); + } + ui->noMatchSwitchScene->setCurrentText(GetWeakSourceName(switcher->nonMatchingScene).c_str()); + ui->checkInterval->setValue(switcher->interval); + + vector windows; + GetWindowList(windows); + + for (string& window : windows) + { + ui->windows->addItem(window.c_str()); + ui->ignoreWindowsWindows->addItem(window.c_str()); + ui->pauseWindowsWindows->addItem(window.c_str()); + ui->ignoreIdleWindowsWindows->addItem(window.c_str()); + } + + QStringList processes; + GetProcessList(processes); + for (QString& process : processes) + ui->executable->addItem(process); + + for (auto& s : switcher->executableSwitches) + { + string sceneName = GetWeakSourceName(s.mScene); + string transitionName = GetWeakSourceName(s.mTransition); + QString text = MakeSwitchNameExecutable( + sceneName.c_str(), s.mExe, transitionName.c_str(), s.mInFocus); + + QListWidgetItem* item = new QListWidgetItem(text, ui->executables); + item->setData(Qt::UserRole, s.mExe); + } + + for (auto& s : switcher->windowSwitches) + { + string sceneName = GetWeakSourceName(s.scene); + string transitionName = GetWeakSourceName(s.transition); + QString text = MakeSwitchName( + sceneName.c_str(), s.window.c_str(), transitionName.c_str(), s.fullscreen); + + QListWidgetItem* item = new QListWidgetItem(text, ui->switches); + item->setData(Qt::UserRole, s.window.c_str()); + } + + for (auto& s : switcher->screenRegionSwitches) + { + string sceneName = GetWeakSourceName(s.scene); + string transitionName = GetWeakSourceName(s.transition); + QString text = MakeScreenRegionSwitchName( + sceneName.c_str(), transitionName.c_str(), s.minX, s.minY, s.maxX, s.maxY); + + QListWidgetItem* item = new QListWidgetItem(text, ui->screenRegions); + item->setData(Qt::UserRole, s.regionStr.c_str()); + } + + ui->autoStopSceneCheckBox->setChecked(switcher->autoStopEnable); + ui->autoStopScenes->setCurrentText(GetWeakSourceName(switcher->autoStopScene).c_str()); + + if (ui->autoStopSceneCheckBox->checkState()) + { + ui->autoStopScenes->setDisabled(false); + } + else + { + ui->autoStopScenes->setDisabled(true); + } + + for (auto& scene : switcher->pauseScenesSwitches) + { + string sceneName = GetWeakSourceName(scene); + QString text = QString::fromStdString(sceneName); + + QListWidgetItem* item = new QListWidgetItem(text, ui->pauseScenes); + item->setData(Qt::UserRole, text); + } + + for (auto& window : switcher->pauseWindowsSwitches) + { + QString text = QString::fromStdString(window); + + QListWidgetItem* item = new QListWidgetItem(text, ui->pauseWindows); + item->setData(Qt::UserRole, text); + } + + for (auto& window : switcher->ignoreWindowsSwitches) + { + QString text = QString::fromStdString(window); + + QListWidgetItem* item = new QListWidgetItem(text, ui->ignoreWindows); + item->setData(Qt::UserRole, text); + } + + int smallestDelay = switcher->interval; + for (auto& s : switcher->sceneRoundTripSwitches) + { + string sceneName1 = GetWeakSourceName(s.scene1); + string sceneName2 = GetWeakSourceName(s.scene2); + string transitionName = GetWeakSourceName(s.transition); + QString text = MakeSceneRoundTripSwitchName( + sceneName1.c_str(), sceneName2.c_str(), transitionName.c_str(), (double)s.delay / 1000); + + QListWidgetItem* item = new QListWidgetItem(text, ui->sceneRoundTrips); + item->setData(Qt::UserRole, text); + + if (s.delay < smallestDelay) + smallestDelay = s.delay; + } + (smallestDelay < switcher->interval) ? ui->intervalWarning->setVisible(true) : ui->intervalWarning->setVisible(false); + + for (auto& s : switcher->sceneTransitions) + { + string sceneName1 = GetWeakSourceName(s.scene1); + string sceneName2 = GetWeakSourceName(s.scene2); + string transitionName = GetWeakSourceName(s.transition); + QString text = MakeSceneTransitionName( + sceneName1.c_str(), sceneName2.c_str(), transitionName.c_str()); + + QListWidgetItem* item = 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) + { + string sceneName = GetWeakSourceName(s.scene); + string transitionName = GetWeakSourceName(s.transition); + QString text = MakeDefaultSceneTransitionName( + sceneName.c_str(), transitionName.c_str()); + + QListWidgetItem* item = new QListWidgetItem(text, ui->defaultTransitions); + item->setData(Qt::UserRole, text); + } + + for (auto& window : switcher->ignoreIdleWindows) + { + QString text = QString::fromStdString(window); + + QListWidgetItem* item = new QListWidgetItem(text, ui->ignoreIdleWindows); + item->setData(Qt::UserRole, text); + } + + for (auto& s : switcher->randomSwitches) + { + string sceneName = GetWeakSourceName(s.scene); + string transitionName = GetWeakSourceName(s.transition); + QString text = MakeRandomSwitchName( + sceneName.c_str(), transitionName.c_str(), s.delay); + + QListWidgetItem* item = new QListWidgetItem(text, ui->randomScenesList); + item->setData(Qt::UserRole, text); + } + + for (auto& s : switcher->fileSwitches) + { + string sceneName = GetWeakSourceName(s.scene); + string transitionName = GetWeakSourceName(s.transition); + QString listText = MakeFileSwitchName( + sceneName.c_str(), transitionName.c_str(), s.file.c_str(), s.text.c_str(), s.useRegex, s.useTime); + + QListWidgetItem* item = new QListWidgetItem(listText, ui->fileScenesList); + item->setData(Qt::UserRole, listText); + } + + ui->idleCheckBox->setChecked(switcher->idleData.idleEnable); + ui->idleScenes->setCurrentText(GetWeakSourceName(switcher->idleData.scene).c_str()); + ui->idleTransitions->setCurrentText(GetWeakSourceName(switcher->idleData.transition).c_str()); + ui->idleSpinBox->setValue(switcher->idleData.time); + + if (ui->idleCheckBox->checkState()) + { + ui->idleScenes->setDisabled(false); + ui->idleSpinBox->setDisabled(false); + ui->idleTransitions->setDisabled(false); + } + else + { + ui->idleScenes->setDisabled(true); + ui->idleSpinBox->setDisabled(true); + ui->idleTransitions->setDisabled(true); + } + + ui->readPathLineEdit->setText(QString::fromStdString(switcher->fileIO.readPath.c_str())); + ui->readFileCheckBox->setChecked(switcher->fileIO.readEnabled); + ui->writePathLineEdit->setText(QString::fromStdString(switcher->fileIO.writePath.c_str())); + + if (ui->readFileCheckBox->checkState()) + { + ui->browseButton_2->setDisabled(false); + ui->readPathLineEdit->setDisabled(false); + } + else + { + ui->browseButton_2->setDisabled(true); + ui->readPathLineEdit->setDisabled(true); + } + + if (switcher->th.joinable()) + SetStarted(); + else + SetStopped(); + + loading = false; + + // screen region cursor position + QTimer* screenRegionTimer = new QTimer(this); + connect(screenRegionTimer, SIGNAL(timeout()), this, SLOT(updateScreenRegionCursorPos())); + screenRegionTimer->start(1000); + + for (int p : switcher->functionNamesByPriority) + { + string s = ""; + switch (p) { + case READ_FILE_FUNC: + s = "File Content"; + break; + case ROUND_TRIP_FUNC: + s = "Scene Sequence"; + break; + case IDLE_FUNC: + s = "Idle Detection"; + break; + case EXE_FUNC: + s = "Executable"; + break; + case SCREEN_REGION_FUNC: + s = "Screen Region"; + break; + case WINDOW_TITLE_FUNC: + s = "Window Title"; + } + QString text(s.c_str()); + QListWidgetItem* item = new QListWidgetItem(text, ui->priorityList); + item->setData(Qt::UserRole, text); + } + +} + + +/******************************************************************************** + * Saving and loading + ********************************************************************************/ +static void SaveSceneSwitcher(obs_data_t* save_data, bool saving, void*) +{ + if (saving) + { + lock_guard lock(switcher->m); + obs_data_t* obj = obs_data_create(); + obs_data_array_t* array = obs_data_array_create(); + obs_data_array_t* screenRegionArray = obs_data_array_create(); + obs_data_array_t* pauseScenesArray = obs_data_array_create(); + obs_data_array_t* pauseWindowsArray = obs_data_array_create(); + obs_data_array_t* ignoreWindowsArray = obs_data_array_create(); + obs_data_array_t* sceneRoundTripArray = obs_data_array_create(); + obs_data_array_t* sceneTransitionsArray = obs_data_array_create(); + obs_data_array_t* defaultTransitionsArray = obs_data_array_create(); + obs_data_array_t* ignoreIdleWindowsArray = obs_data_array_create(); + obs_data_array_t* executableArray = obs_data_array_create(); + obs_data_array_t* randomArray = obs_data_array_create(); + obs_data_array_t* fileArray = obs_data_array_create(); + + switcher->Prune(); + + for (WindowSceneSwitch& s : switcher->windowSwitches) + { + obs_data_t* array_obj = obs_data_create(); + + obs_source_t* source = obs_weak_source_get_source(s.scene); + obs_source_t* transition = obs_weak_source_get_source(s.transition); + if (source && transition) + { + const char* sceneName = obs_source_get_name(source); + const char* transitionName = obs_source_get_name(transition); + obs_data_set_string(array_obj, "scene", sceneName); + obs_data_set_string(array_obj, "transition", transitionName); + obs_data_set_string(array_obj, "window_title", s.window.c_str()); + obs_data_set_bool(array_obj, "fullscreen", s.fullscreen); + obs_data_array_push_back(array, array_obj); + obs_source_release(source); + obs_source_release(transition); + } + + obs_data_release(array_obj); + } + + for (ScreenRegionSwitch& s : switcher->screenRegionSwitches) + { + obs_data_t* array_obj = obs_data_create(); + + obs_source_t* source = obs_weak_source_get_source(s.scene); + obs_source_t* transition = obs_weak_source_get_source(s.transition); + if (source && transition) + { + const char* sceneName = obs_source_get_name(source); + const char* transitionName = obs_source_get_name(transition); + obs_data_set_string(array_obj, "screenRegionScene", sceneName); + obs_data_set_string(array_obj, "transition", transitionName); + obs_data_set_int(array_obj, "minX", s.minX); + 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); + } + + obs_data_release(array_obj); + } + + for (OBSWeakSource& scene : switcher->pauseScenesSwitches) + { + obs_data_t* array_obj = obs_data_create(); + + obs_source_t* source = obs_weak_source_get_source(scene); + if (source) + { + const char* n = obs_source_get_name(source); + obs_data_set_string(array_obj, "pauseScene", n); + obs_data_array_push_back(pauseScenesArray, array_obj); + obs_source_release(source); + } + + obs_data_release(array_obj); + } + + for (string& window : switcher->pauseWindowsSwitches) + { + obs_data_t* array_obj = obs_data_create(); + obs_data_set_string(array_obj, "pauseWindow", window.c_str()); + obs_data_array_push_back(pauseWindowsArray, array_obj); + obs_data_release(array_obj); + } + + for (string& window : switcher->ignoreWindowsSwitches) + { + obs_data_t* array_obj = obs_data_create(); + obs_data_set_string(array_obj, "ignoreWindow", window.c_str()); + obs_data_array_push_back(ignoreWindowsArray, array_obj); + obs_data_release(array_obj); + } + + for (SceneRoundTripSwitch& s : switcher->sceneRoundTripSwitches) + { + 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* transition = obs_weak_source_get_source(s.transition); + if (source1 && source2 && transition) + { + const char* sceneName1 = obs_source_get_name(source1); + const char* sceneName2 = obs_source_get_name(source2); + const char* transitionName = obs_source_get_name(transition); + obs_data_set_string(array_obj, "sceneRoundTripScene1", sceneName1); + obs_data_set_string(array_obj, "sceneRoundTripScene2", sceneName2); + obs_data_set_string(array_obj, "transition", transitionName); + obs_data_set_int(array_obj, "sceneRoundTripDelay", s.delay / 1000); //delay stored in two separate values + obs_data_set_int(array_obj, "sceneRoundTripDelayMs", s.delay % 1000); //to be compatible with older versions + obs_data_set_string(array_obj, "sceneRoundTripStr", s.sceneRoundTripStr.c_str()); + obs_data_array_push_back(sceneRoundTripArray, array_obj); + obs_source_release(source1); + obs_source_release(source2); + obs_source_release(transition); + } + + obs_data_release(array_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* source2 = obs_weak_source_get_source(s.scene2); + obs_source_t* transition = obs_weak_source_get_source(s.transition); + if (source1 && source2 && transition) + { + const char* sceneName1 = obs_source_get_name(source1); + const char* sceneName2 = obs_source_get_name(source2); + const char* transitionName = obs_source_get_name(transition); + obs_data_set_string(array_obj, "Scene1", sceneName1); + 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); + obs_source_release(source2); + obs_source_release(transition); + } + + obs_data_release(array_obj); + } + + for (DefaultSceneTransition& s : switcher->defaultSceneTransitions) + { + obs_data_t* array_obj = obs_data_create(); + + obs_source_t* source = obs_weak_source_get_source(s.scene); + obs_source_t* transition = obs_weak_source_get_source(s.transition); + if (source && transition) + { + const char* sceneName = obs_source_get_name(source); + const char* transitionName = obs_source_get_name(transition); + obs_data_set_string(array_obj, "Scene", sceneName); + obs_data_set_string(array_obj, "transition", transitionName); + obs_data_set_string(array_obj, "Str", s.sceneTransitionStr.c_str()); + obs_data_array_push_back(defaultTransitionsArray, array_obj); + obs_source_release(source); + obs_source_release(transition); + } + + obs_data_release(array_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* transition = obs_weak_source_get_source(s.mTransition); + + if (source && transition) + { + const char* sceneName = obs_source_get_name(source); + const char* transitionName = obs_source_get_name(transition); + obs_data_set_string(array_obj, "scene", sceneName); + obs_data_set_string(array_obj, "transition", transitionName); + obs_data_set_string(array_obj, "exefile", s.mExe.toUtf8()); + obs_data_set_bool(array_obj, "infocus", s.mInFocus); + obs_data_array_push_back(executableArray, array_obj); + obs_source_release(source); + obs_source_release(transition); + } + + obs_data_release(array_obj); + } + + for (RandomSwitch& s : switcher->randomSwitches) + { + obs_data_t* array_obj = obs_data_create(); + + obs_source_t* source = obs_weak_source_get_source(s.scene); + obs_source_t* transition = obs_weak_source_get_source(s.transition); + + if (source && transition) + { + const char* sceneName = obs_source_get_name(source); + const char* transitionName = obs_source_get_name(transition); + obs_data_set_string(array_obj, "scene", sceneName); + obs_data_set_string(array_obj, "transition", transitionName); + obs_data_set_double(array_obj, "delay", s.delay); + obs_data_set_string(array_obj, "str", s.randomSwitchStr.c_str()); + obs_data_array_push_back(randomArray, array_obj); + obs_source_release(source); + obs_source_release(transition); + } + + obs_data_release(array_obj); + } + + for (string& window : switcher->ignoreIdleWindows) + { + obs_data_t* array_obj = obs_data_create(); + obs_data_set_string(array_obj, "window", window.c_str()); + obs_data_array_push_back(ignoreIdleWindowsArray, array_obj); + obs_data_release(array_obj); + } + + for (FileSwitch& s : switcher->fileSwitches) + { + obs_data_t* array_obj = obs_data_create(); + + obs_source_t* source = obs_weak_source_get_source(s.scene); + obs_source_t* transition = obs_weak_source_get_source(s.transition); + + if (source && transition) + { + const char* sceneName = obs_source_get_name(source); + const char* transitionName = obs_source_get_name(transition); + obs_data_set_string(array_obj, "scene", sceneName); + obs_data_set_string(array_obj, "transition", transitionName); + obs_data_set_string(array_obj, "file", s.file.c_str()); + obs_data_set_string(array_obj, "text", s.text.c_str()); + obs_data_set_bool(array_obj, "useRegex", s.useRegex); + obs_data_set_bool(array_obj, "useTime", s.useTime); + obs_data_array_push_back(fileArray, array_obj); + obs_source_release(source); + obs_source_release(transition); + } + + obs_data_release(array_obj); + } + + string nonMatchingSceneName = GetWeakSourceName(switcher->nonMatchingScene); + + obs_data_set_int(obj, "interval", switcher->interval); + obs_data_set_string(obj, "non_matching_scene", nonMatchingSceneName.c_str()); + obs_data_set_int(obj, "switch_if_not_matching", switcher->switchIfNotMatching); + obs_data_set_bool(obj, "active", !switcher->stop); + + obs_data_set_array(obj, "switches", array); + obs_data_set_array(obj, "screenRegion", screenRegionArray); + obs_data_set_array(obj, "pauseScenes", pauseScenesArray); + obs_data_set_array(obj, "pauseWindows", pauseWindowsArray); + obs_data_set_array(obj, "ignoreWindows", ignoreWindowsArray); + obs_data_set_array(obj, "sceneRoundTrip", sceneRoundTripArray); + obs_data_set_array(obj, "sceneTransitions", sceneTransitionsArray); + obs_data_set_array(obj, "defaultTransitions", defaultTransitionsArray); + obs_data_set_array(obj, "executableSwitches", executableArray); + obs_data_set_array(obj, "ignoreIdleWindows", ignoreIdleWindowsArray); + obs_data_set_array(obj, "randomSwitches", randomArray); + obs_data_set_array(obj, "fileSwitches", fileArray); + + + string autoStopSceneName = GetWeakSourceName(switcher->autoStopScene); + obs_data_set_bool(obj, "autoStopEnable", switcher->autoStopEnable); + obs_data_set_string(obj, "autoStopSceneName", autoStopSceneName.c_str()); + + string idleSceneName = GetWeakSourceName(switcher->idleData.scene); + string idleTransitionName = GetWeakSourceName(switcher->idleData.transition); + obs_data_set_bool(obj, "idleEnable", switcher->idleData.idleEnable); + obs_data_set_string(obj, "idleSceneName", idleSceneName.c_str()); + obs_data_set_string(obj, "idleTransitionName", idleTransitionName.c_str()); + obs_data_set_int(obj, "idleTime", switcher->idleData.time); + + obs_data_set_bool(obj, "readEnabled", switcher->fileIO.readEnabled); + obs_data_set_string(obj, "readPath", switcher->fileIO.readPath.c_str()); + obs_data_set_bool(obj, "writeEnabled", switcher->fileIO.writeEnabled); + obs_data_set_string(obj, "writePath", switcher->fileIO.writePath.c_str()); + + obs_data_set_int(obj, "priority0", switcher->functionNamesByPriority[0]); + obs_data_set_int(obj, "priority1", switcher->functionNamesByPriority[1]); + obs_data_set_int(obj, "priority2", switcher->functionNamesByPriority[2]); + obs_data_set_int(obj, "priority3", switcher->functionNamesByPriority[3]); + obs_data_set_int(obj, "priority4", switcher->functionNamesByPriority[4]); + obs_data_set_int(obj, "priority5", switcher->functionNamesByPriority[5]); + + obs_data_set_obj(save_data, "advanced-scene-switcher", obj); + + obs_data_array_release(array); + obs_data_array_release(screenRegionArray); + obs_data_array_release(pauseScenesArray); + obs_data_array_release(pauseWindowsArray); + obs_data_array_release(ignoreWindowsArray); + obs_data_array_release(sceneRoundTripArray); + obs_data_array_release(sceneTransitionsArray); + obs_data_array_release(defaultTransitionsArray); + obs_data_array_release(executableArray); + obs_data_array_release(ignoreIdleWindowsArray); + obs_data_array_release(randomArray); + obs_data_array_release(fileArray); + + obs_data_release(obj); + } + else + { + switcher->m.lock(); + + obs_data_t* obj = obs_data_get_obj(save_data, "advanced-scene-switcher"); + obs_data_array_t* array = obs_data_get_array(obj, "switches"); + obs_data_array_t* screenRegionArray = obs_data_get_array(obj, "screenRegion"); + obs_data_array_t* pauseScenesArray = obs_data_get_array(obj, "pauseScenes"); + obs_data_array_t* pauseWindowsArray = obs_data_get_array(obj, "pauseWindows"); + obs_data_array_t* ignoreWindowsArray = obs_data_get_array(obj, "ignoreWindows"); + obs_data_array_t* sceneRoundTripArray = obs_data_get_array(obj, "sceneRoundTrip"); + obs_data_array_t* sceneTransitionsArray = obs_data_get_array(obj, "sceneTransitions"); + obs_data_array_t* defaultTransitionsArray = obs_data_get_array(obj, "defaultTransitions"); + obs_data_array_t* executableArray = obs_data_get_array(obj, "executableSwitches"); + obs_data_array_t* ignoreIdleWindowsArray = obs_data_get_array(obj, "ignoreIdleWindows"); + obs_data_array_t* randomArray = obs_data_get_array(obj, "randomSwitches"); + obs_data_array_t* fileArray = obs_data_get_array(obj, "fileSwitches"); + + if (!obj) + obj = obs_data_create(); + + obs_data_set_default_int(obj, "interval", DEFAULT_INTERVAL); + + switcher->interval = obs_data_get_int(obj, "interval"); + obs_data_set_default_int(obj, "switch_if_not_matching", NO_SWITCH); + switcher->switchIfNotMatching = (NoMatch)obs_data_get_int(obj, "switch_if_not_matching"); + string nonMatchingScene = obs_data_get_string(obj, "non_matching_scene"); + bool active = obs_data_get_bool(obj, "active"); + + switcher->nonMatchingScene = GetWeakSourceByName(nonMatchingScene.c_str()); + + switcher->windowSwitches.clear(); + size_t count = obs_data_array_count(array); + + for (size_t i = 0; i < count; i++) + { + obs_data_t* array_obj = obs_data_array_item(array, i); + + const char* scene = obs_data_get_string(array_obj, "scene"); + const char* transition = obs_data_get_string(array_obj, "transition"); + const char* window = obs_data_get_string(array_obj, "window_title"); + bool fullscreen = obs_data_get_bool(array_obj, "fullscreen"); + + switcher->windowSwitches.emplace_back(GetWeakSourceByName(scene), window, + GetWeakTransitionByName(transition), fullscreen); + + obs_data_release(array_obj); + } + + switcher->screenRegionSwitches.clear(); + count = obs_data_array_count(screenRegionArray); + + for (size_t i = 0; i < count; i++) + { + obs_data_t* array_obj = obs_data_array_item(screenRegionArray, i); + + const char* scene = obs_data_get_string(array_obj, "screenRegionScene"); + const char* transition = obs_data_get_string(array_obj, "transition"); + int minX = obs_data_get_int(array_obj, "minX"); + 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"); + string regionStr = obs_data_get_string(array_obj, "screenRegionStr"); + + switcher->screenRegionSwitches.emplace_back(GetWeakSourceByName(scene), + GetWeakTransitionByName(transition), minX, minY, maxX, maxY, regionStr); + + obs_data_release(array_obj); + } + + switcher->pauseScenesSwitches.clear(); + count = obs_data_array_count(pauseScenesArray); + + for (size_t i = 0; i < count; i++) + { + obs_data_t* array_obj = obs_data_array_item(pauseScenesArray, i); + + const char* scene = obs_data_get_string(array_obj, "pauseScene"); + + switcher->pauseScenesSwitches.emplace_back(GetWeakSourceByName(scene)); + + obs_data_release(array_obj); + } + + switcher->pauseWindowsSwitches.clear(); + count = obs_data_array_count(pauseWindowsArray); + + for (size_t i = 0; i < count; i++) + { + obs_data_t* array_obj = obs_data_array_item(pauseWindowsArray, i); + + const char* window = obs_data_get_string(array_obj, "pauseWindow"); + + switcher->pauseWindowsSwitches.emplace_back(window); + + obs_data_release(array_obj); + } + + obs_data_array_release(pauseWindowsArray); + + switcher->ignoreWindowsSwitches.clear(); + count = obs_data_array_count(ignoreWindowsArray); + + for (size_t i = 0; i < count; i++) + { + obs_data_t* array_obj = obs_data_array_item(ignoreWindowsArray, i); + + const char* window = obs_data_get_string(array_obj, "ignoreWindow"); + + switcher->ignoreWindowsSwitches.emplace_back(window); + + obs_data_release(array_obj); + } + + switcher->sceneRoundTripSwitches.clear(); + count = obs_data_array_count(sceneRoundTripArray); + + for (size_t i = 0; i < count; i++) + { + obs_data_t* array_obj = obs_data_array_item(sceneRoundTripArray, i); + + const char* scene1 = obs_data_get_string(array_obj, "sceneRoundTripScene1"); + const char* scene2 = obs_data_get_string(array_obj, "sceneRoundTripScene2"); + const char* transition = obs_data_get_string(array_obj, "transition"); + int delay = obs_data_get_int(array_obj, "sceneRoundTripDelay"); //delay stored in two separate values + delay = delay * 1000 + obs_data_get_int(array_obj, "sceneRoundTripDelayMs"); //to be compatible with older versions + string str = MakeSceneRoundTripSwitchName(scene1, scene2, transition, ((double)delay)/1000.0).toUtf8().constData(); + const char* sceneRoundTripStr = str.c_str(); + + switcher->sceneRoundTripSwitches.emplace_back(GetWeakSourceByName(scene1), + GetWeakSourceByName(scene2), GetWeakTransitionByName(transition), delay, + sceneRoundTripStr); + + obs_data_release(array_obj); + } + + switcher->sceneTransitions.clear(); + count = obs_data_array_count(sceneTransitionsArray); + + for (size_t i = 0; i < count; i++) + { + obs_data_t* array_obj = obs_data_array_item(sceneTransitionsArray, i); + + const char* scene1 = obs_data_get_string(array_obj, "Scene1"); + 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"); + + switcher->sceneTransitions.emplace_back(GetWeakSourceByName(scene1), + GetWeakSourceByName(scene2), GetWeakTransitionByName(transition), + sceneTransitionsStr); + + obs_data_release(array_obj); + } + + switcher->defaultSceneTransitions.clear(); + count = obs_data_array_count(defaultTransitionsArray); + + for (size_t i = 0; i < count; i++) + { + obs_data_t* array_obj = obs_data_array_item(defaultTransitionsArray, i); + + 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"); + + switcher->defaultSceneTransitions.emplace_back(GetWeakSourceByName(scene), + GetWeakTransitionByName(transition), + sceneTransitionsStr); + + obs_data_release(array_obj); + } + + switcher->executableSwitches.clear(); + count = obs_data_array_count(executableArray); + + for (size_t i = 0; i < count; i++) + { + obs_data_t* array_obj = obs_data_array_item(executableArray, i); + + const char* scene = obs_data_get_string(array_obj, "scene"); + const char* transition = obs_data_get_string(array_obj, "transition"); + const char* exe = obs_data_get_string(array_obj, "exefile"); + bool infocus = obs_data_get_bool(array_obj, "infocus"); + + switcher->executableSwitches.emplace_back( + GetWeakSourceByName(scene), GetWeakTransitionByName(transition), exe, infocus); + + obs_data_release(array_obj); + } + + switcher->ignoreIdleWindows.clear(); + count = obs_data_array_count(ignoreIdleWindowsArray); + + for (size_t i = 0; i < count; i++) + { + obs_data_t* array_obj = obs_data_array_item(ignoreIdleWindowsArray, i); + + const char* window = obs_data_get_string(array_obj, "window"); + + switcher->ignoreIdleWindows.emplace_back(window); + + obs_data_release(array_obj); + } + + switcher->randomSwitches.clear(); + count = obs_data_array_count(randomArray); + + for (size_t i = 0; i < count; i++) + { + obs_data_t* array_obj = obs_data_array_item(randomArray, i); + + const char* scene = obs_data_get_string(array_obj, "scene"); + const char* transition = obs_data_get_string(array_obj, "transition"); + double delay = obs_data_get_double(array_obj, "delay"); + const char* str = obs_data_get_string(array_obj, "str"); + + switcher->randomSwitches.emplace_back( + GetWeakSourceByName(scene), GetWeakTransitionByName(transition), delay, str); + + obs_data_release(array_obj); + } + + switcher->fileSwitches.clear(); + count = obs_data_array_count(fileArray); + + for (size_t i = 0; i < count; i++) + { + obs_data_t* array_obj = obs_data_array_item(fileArray, i); + + const char* scene = obs_data_get_string(array_obj, "scene"); + const char* transition = obs_data_get_string(array_obj, "transition"); + const char* file = obs_data_get_string(array_obj, "file"); + const char* text = obs_data_get_string(array_obj, "text"); + bool useRegex = obs_data_get_bool(array_obj, "useRegex"); + bool useTime = obs_data_get_bool(array_obj, "useTime"); + + switcher->fileSwitches.emplace_back( + GetWeakSourceByName(scene), GetWeakTransitionByName(transition), file, text, useRegex, useTime); + + obs_data_release(array_obj); + } + + string autoStopScene = obs_data_get_string(obj, "autoStopSceneName"); + switcher->autoStopEnable = obs_data_get_bool(obj, "autoStopEnable"); + switcher->autoStopScene = GetWeakSourceByName(autoStopScene.c_str()); + + string idleSceneName = obs_data_get_string(obj, "idleSceneName"); + string idleTransitionName = obs_data_get_string(obj, "idleTransitionName"); + switcher->idleData.scene = GetWeakSourceByName(idleSceneName.c_str()); + switcher->idleData.transition = GetWeakTransitionByName(idleTransitionName.c_str()); + obs_data_set_default_bool(obj, "idleEnable", false); + switcher->idleData.idleEnable = obs_data_get_bool(obj, "idleEnable"); + obs_data_set_default_int(obj, "idleTime", DEFAULT_IDLE_TIME); + switcher->idleData.time = obs_data_get_int(obj, "idleTime"); + + obs_data_set_default_bool(obj, "readEnabled", false); + switcher->fileIO.readEnabled = obs_data_get_bool(obj, "readEnabled"); + switcher->fileIO.readPath = obs_data_get_string(obj, "readPath"); + obs_data_set_default_bool(obj, "writeEnabled", false); + switcher->fileIO.writeEnabled = obs_data_get_bool(obj, "writeEnabled"); + switcher->fileIO.writePath = obs_data_get_string(obj, "writePath"); + + obs_data_set_default_int(obj, "priority0", DEFAULT_PRIORITY_0); + obs_data_set_default_int(obj, "priority1", DEFAULT_PRIORITY_1); + obs_data_set_default_int(obj, "priority2", DEFAULT_PRIORITY_2); + obs_data_set_default_int(obj, "priority3", DEFAULT_PRIORITY_3); + obs_data_set_default_int(obj, "priority4", DEFAULT_PRIORITY_4); + obs_data_set_default_int(obj, "priority5", DEFAULT_PRIORITY_5); + + switcher->functionNamesByPriority[0] = (obs_data_get_int(obj, "priority0")); + switcher->functionNamesByPriority[1] = (obs_data_get_int(obj, "priority1")); + switcher->functionNamesByPriority[2] = (obs_data_get_int(obj, "priority2")); + switcher->functionNamesByPriority[3] = (obs_data_get_int(obj, "priority3")); + switcher->functionNamesByPriority[4] = (obs_data_get_int(obj, "priority4")); + switcher->functionNamesByPriority[5] = (obs_data_get_int(obj, "priority5")); + if (!switcher->prioFuncsValid()) + { + switcher->functionNamesByPriority[0] = (DEFAULT_PRIORITY_0); + switcher->functionNamesByPriority[1] = (DEFAULT_PRIORITY_1); + switcher->functionNamesByPriority[2] = (DEFAULT_PRIORITY_2); + switcher->functionNamesByPriority[3] = (DEFAULT_PRIORITY_3); + switcher->functionNamesByPriority[4] = (DEFAULT_PRIORITY_4); + switcher->functionNamesByPriority[5] = (DEFAULT_PRIORITY_5); + } + + obs_data_array_release(array); + obs_data_array_release(screenRegionArray); + obs_data_array_release(pauseScenesArray); + obs_data_array_release(ignoreWindowsArray); + obs_data_array_release(sceneRoundTripArray); + obs_data_array_release(sceneTransitionsArray); + obs_data_array_release(defaultTransitionsArray); + obs_data_array_release(executableArray); + obs_data_array_release(ignoreIdleWindowsArray); + obs_data_array_release(randomArray); + obs_data_array_release(fileArray); + + obs_data_release(obj); + + switcher->m.unlock(); + + if (active) + switcher->Start(); + else + switcher->Stop(); + } +} + + +/******************************************************************************** + * Main switcher thread + ********************************************************************************/ +void SwitcherData::Thread() +{ + + //to avoid scene duplication when rapidly switching scene collection + this_thread::sleep_for(chrono::seconds(2)); + + int sleep = 0; + + while (true) + { + startLoop: + unique_lock lock(m); + bool match = false; + OBSWeakSource scene; + OBSWeakSource transition; + chrono::milliseconds duration; + if (sleep > interval) + duration = chrono::milliseconds(sleep); + else + duration = chrono::milliseconds(interval); + sleep = 0; + switcher->Prune(); + writeSceneInfoToFile(); + //sleep for a bit + cv.wait_for(lock, duration); + if (switcher->stop) + { + break; + } + setDefaultSceneTransitions(lock); + if (autoStopEnable) + { + autoStopStreamAndRecording(); + } + if (checkPause()) + { + continue; + } + + for (int switchFuncName : functionNamesByPriority) + { + switch (switchFuncName) { + case READ_FILE_FUNC: + checkSwitchInfoFromFile(match, scene, transition); + checkFileContent(match, scene, transition); + break; + case IDLE_FUNC: + checkIdleSwitch(match, scene, transition); + break; + case EXE_FUNC: + checkExeSwitch(match, scene, transition); + break; + + case SCREEN_REGION_FUNC: + checkScreenRegionSwitch(match, scene, transition); + break; + case WINDOW_TITLE_FUNC: + checkWindowTitleSwitch(match, scene, transition); + break; + case ROUND_TRIP_FUNC: + checkSceneRoundTrip(match, scene, transition, lock); + if (sceneChangedDuringWait()) //scene might have changed during the sleep + { + goto startLoop; + } + } + if (switcher->stop) + { + goto endLoop; + } + if (match) + { + break; + } + } + + if (!match && switchIfNotMatching == SWITCH && nonMatchingScene) + { + match = true; + scene = nonMatchingScene; + transition = nullptr; + } + if (!match && switchIfNotMatching == RANDOM_SWITCH) + { + checkRandom(match, scene, transition, sleep); + } + if (match) + { + switchScene(scene, transition); + } + } +endLoop: + ; +} + +void switchScene(OBSWeakSource scene, OBSWeakSource transition) +{ + obs_source_t* source = obs_weak_source_get_source(scene); + obs_source_t* currentSource = obs_frontend_get_current_scene(); + + if (source && source != currentSource) + { + obs_weak_source_t* currentScene = obs_source_get_weak_source(currentSource); + obs_weak_source_t* nextTransitionWs = getNextTransition(currentScene, scene); + obs_weak_source_release(currentScene); + + if (nextTransitionWs) + { + obs_source_t* nextTransition = obs_weak_source_get_source(nextTransitionWs); + //lock.unlock(); + //transitionCv.wait(transitionLock, transitionActiveCheck); + //lock.lock(); + obs_frontend_set_current_transition(nextTransition); + obs_source_release(nextTransition); + } + else if (transition) + { + obs_source_t* nextTransition = obs_weak_source_get_source(transition); + //lock.unlock(); + //transitionCv.wait(transitionLock, transitionActiveCheck); + //lock.lock(); + obs_frontend_set_current_transition(nextTransition); + obs_source_release(nextTransition); + } + obs_frontend_set_current_scene(source); + obs_weak_source_release(nextTransitionWs); + } + obs_source_release(currentSource); + obs_source_release(source); +} + +bool SwitcherData::sceneChangedDuringWait() { + bool r = false; + obs_source_t* currentSource = obs_frontend_get_current_scene(); + if (!currentSource) + return true; + obs_source_release(currentSource); + if (waitScene && currentSource != waitScene) + r = true; + waitScene = NULL; + return r; +} + +void SwitcherData::Start() +{ + if (!th.joinable()) + { + stop = false; + switcher->th = thread([]() + { + switcher->Thread(); + }); + } +} + +void SwitcherData::Stop() +{ + if (th.joinable()) + { + switcher->stop = true; + transitionCv.notify_one(); + cv.notify_one(); + th.join(); + } +} + + +/******************************************************************************** + * OBS module setup + ********************************************************************************/ +extern "C" void FreeSceneSwitcher() +{ + delete switcher; + switcher = nullptr; +} + +static void OBSEvent(enum obs_frontend_event event, void* switcher) +{ + switch (event){ + case OBS_FRONTEND_EVENT_EXIT: + FreeSceneSwitcher(); + break; + + case OBS_FRONTEND_EVENT_SCENE_CHANGED: + { + SwitcherData* s = (SwitcherData*)switcher; + //stop waiting if scene was manually changed + lock_guard lock(s->m); + if (s->sceneChangedDuringWait()) + s->cv.notify_one(); + break; + } + default: + break; + } +} + +extern "C" void InitSceneSwitcher() +{ + QAction* action + = (QAction*)obs_frontend_add_tools_menu_qaction("Advanced Scene Switcher"); + + switcher = new SwitcherData; + + auto cb = []() + { + QMainWindow* window = (QMainWindow*)obs_frontend_get_main_window(); + + SceneSwitcher ss(window); + ss.exec(); + }; + + obs_frontend_add_save_callback(SaveSceneSwitcher, nullptr); + obs_frontend_add_event_callback(OBSEvent, switcher); + + action->connect(action, &QAction::triggered, cb); + + char* path = obs_module_config_path(""); + QDir dir(path); + if (!dir.exists()) + { + dir.mkpath("."); + } + bfree(path); + + obs_hotkey_id pauseHotkeyId = obs_hotkey_register_frontend("startStopSwitcherHotkey", + "Toggle Start/Stop for the Advanced Scene Switcher", startStopHotkeyFunc, NULL); + loadKeybinding(pauseHotkeyId); +} diff --git a/advanced-scene-switcher.hpp b/advanced-scene-switcher.hpp index 3e1382f2..c926c351 100644 --- a/advanced-scene-switcher.hpp +++ b/advanced-scene-switcher.hpp @@ -1,134 +1,175 @@ -#pragma once - -#include -#include -#include -#include -#include "ui_advanced-scene-switcher.h" -#include "switcher-data-structs.hpp" - -struct obs_weak_source; -typedef struct obs_weak_source obs_weak_source_t; - -class QCloseEvent; - -class SceneSwitcher : public QDialog { - Q_OBJECT - -public: - std::unique_ptr ui; - bool loading = true; - - SceneSwitcher(QWidget *parent); - - void closeEvent(QCloseEvent *event) override; - - void SetStarted(); - void SetStopped(); - - int FindByData(const QString &window); - int ScreenRegionFindByData(const QString ®ion); - int PauseScenesFindByData(const QString &scene); - int PauseWindowsFindByData(const QString &window); - int IgnoreWindowsFindByData(const QString &window); - int SceneRoundTripFindByData(const QString &scene1); - int SceneTransitionsFindByData(const QString &scene1, const QString &scene2); - int DefaultTransitionsFindByData(const QString &scene); - int executableFindByData(const QString &exe); - int IgnoreIdleWindowsFindByData(const QString& window); - int randomFindByData(const QString& scene); - - void UpdateNonMatchingScene(const QString &name); - void UpdateAutoStopScene(const QString &name); - void UpdateIdleDataTransition(const QString& name); - void UpdateIdleDataScene(const QString& name); - -public slots: - void on_switches_currentRowChanged(int idx); - void on_add_clicked(); - void on_remove_clicked(); - void on_noMatchDontSwitch_clicked(); - void on_noMatchSwitch_clicked(); - void on_noMatchRandomSwitch_clicked(); - void on_startAtLaunch_toggled(bool value); - void on_noMatchSwitchScene_currentTextChanged(const QString &text); - void on_checkInterval_valueChanged(int value); - void on_toggleStartButton_clicked(); - - void on_screenRegions_currentRowChanged(int idx); - void on_screenRegionAdd_clicked(); - void on_screenRegionRemove_clicked(); - - void on_pauseScenes_currentRowChanged(int idx); - void on_pauseScenesAdd_clicked(); - void on_pauseScenesRemove_clicked(); - - void on_pauseWindows_currentRowChanged(int idx); - void on_pauseWindowsAdd_clicked(); - void on_pauseWindowsRemove_clicked(); - - void on_ignoreWindows_currentRowChanged(int idx); - 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_autoStopSceneCheckBox_stateChanged(int state); - void on_autoStopScenes_currentTextChanged(const QString &text); - - void on_sceneTransitions_currentRowChanged(int idx); - void on_transitionsAdd_clicked(); - void on_transitionsRemove_clicked(); - void on_defaultTransitions_currentRowChanged(int idx); - void on_defaultTransitionsAdd_clicked(); - void on_defaultTransitionsRemove_clicked(); - - void on_browseButton_clicked(); - void on_readFileCheckBox_stateChanged(int state); - void on_readPathLineEdit_textChanged(const QString & text); - void on_writePathLineEdit_textChanged(const QString & text); - void on_browseButton_2_clicked(); - - void on_executableAdd_clicked(); - void on_executableRemove_clicked(); - void on_executables_currentRowChanged(int idx); - - void on_idleCheckBox_stateChanged(int state); - void on_idleTransitions_currentTextChanged(const QString& text); - void on_idleScenes_currentTextChanged(const QString& text); - void on_idleSpinBox_valueChanged(int i); - void on_ignoreIdleWindows_currentRowChanged(int idx); - void on_ignoreIdleAdd_clicked(); - void on_ignoreIdleRemove_clicked(); - - void on_randomAdd_clicked(); - void on_randomRemove_clicked(); - void on_randomScenesList_currentRowChanged(int idx); - - void on_fileAdd_clicked(); - void on_fileRemove_clicked(); - void on_fileScenesList_currentRowChanged(int idx); - void on_browseButton_3_clicked(); - - void on_priorityUp_clicked(); - void on_priorityDown_clicked(); - - void updateScreenRegionCursorPos(); - - void on_close_clicked(); -}; - -void GetWindowList(std::vector &windows); -void GetCurrentWindowTitle(std::string &title); -pair getCursorPos(); -bool isFullscreen(); -int secondsSinceLastInput(); -bool isInFocus(const QString &exeToCheck); -void GetProcessList(QStringList &processes); - -struct SwitcherData; -extern SwitcherData* switcher; +#pragma once + +#include +#include +#include +#include +#include "ui_advanced-scene-switcher.h" +#include "switcher-data-structs.hpp" + +class QCloseEvent; + + +/******************************************************************************* + * Advanced Scene Switcher window + *******************************************************************************/ +class SceneSwitcher : public QDialog { + Q_OBJECT + +public: + std::unique_ptr ui; + bool loading = true; + + SceneSwitcher(QWidget *parent); + + void closeEvent(QCloseEvent *event) override; + + void SetStarted(); + void SetStopped(); + + int FindByData(const QString &window); + int ScreenRegionFindByData(const QString ®ion); + int PauseScenesFindByData(const QString &scene); + int PauseWindowsFindByData(const QString &window); + int IgnoreWindowsFindByData(const QString &window); + int SceneRoundTripFindByData(const QString &scene1); + int SceneTransitionsFindByData(const QString &scene1, const QString &scene2); + int DefaultTransitionsFindByData(const QString &scene); + int executableFindByData(const QString &exe); + int IgnoreIdleWindowsFindByData(const QString& window); + int randomFindByData(const QString& scene); + + void UpdateNonMatchingScene(const QString &name); + void UpdateAutoStopScene(const QString &name); + void UpdateIdleDataTransition(const QString& name); + void UpdateIdleDataScene(const QString& name); + +public slots: + void on_switches_currentRowChanged(int idx); + void on_add_clicked(); + void on_remove_clicked(); + void on_noMatchDontSwitch_clicked(); + void on_noMatchSwitch_clicked(); + void on_noMatchRandomSwitch_clicked(); + void on_startAtLaunch_toggled(bool value); + void on_noMatchSwitchScene_currentTextChanged(const QString &text); + void on_checkInterval_valueChanged(int value); + void on_toggleStartButton_clicked(); + + void on_screenRegions_currentRowChanged(int idx); + void on_screenRegionAdd_clicked(); + void on_screenRegionRemove_clicked(); + + void on_pauseScenes_currentRowChanged(int idx); + void on_pauseScenesAdd_clicked(); + void on_pauseScenesRemove_clicked(); + + void on_pauseWindows_currentRowChanged(int idx); + void on_pauseWindowsAdd_clicked(); + void on_pauseWindowsRemove_clicked(); + + void on_ignoreWindows_currentRowChanged(int idx); + 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_autoStopSceneCheckBox_stateChanged(int state); + void on_autoStopScenes_currentTextChanged(const QString &text); + + void on_sceneTransitions_currentRowChanged(int idx); + void on_transitionsAdd_clicked(); + void on_transitionsRemove_clicked(); + void on_defaultTransitions_currentRowChanged(int idx); + void on_defaultTransitionsAdd_clicked(); + void on_defaultTransitionsRemove_clicked(); + + void on_browseButton_clicked(); + void on_readFileCheckBox_stateChanged(int state); + void on_readPathLineEdit_textChanged(const QString & text); + void on_writePathLineEdit_textChanged(const QString & text); + void on_browseButton_2_clicked(); + + void on_executableAdd_clicked(); + void on_executableRemove_clicked(); + void on_executables_currentRowChanged(int idx); + + void on_idleCheckBox_stateChanged(int state); + void on_idleTransitions_currentTextChanged(const QString& text); + void on_idleScenes_currentTextChanged(const QString& text); + void on_idleSpinBox_valueChanged(int i); + void on_ignoreIdleWindows_currentRowChanged(int idx); + void on_ignoreIdleAdd_clicked(); + void on_ignoreIdleRemove_clicked(); + + void on_randomAdd_clicked(); + void on_randomRemove_clicked(); + void on_randomScenesList_currentRowChanged(int idx); + + void on_fileAdd_clicked(); + void on_fileRemove_clicked(); + void on_fileScenesList_currentRowChanged(int idx); + void on_browseButton_3_clicked(); + + void on_priorityUp_clicked(); + void on_priorityDown_clicked(); + + void updateScreenRegionCursorPos(); + + void on_close_clicked(); +}; + + +/******************************************************************************** + * Windowtitle helper + ********************************************************************************/ +void GetWindowList(std::vector &windows); +void GetCurrentWindowTitle(std::string &title); +bool isFullscreen(); + + +/******************************************************************************** + * Screenregion helper + ********************************************************************************/ +pair getCursorPos(); + + +/******************************************************************************** + * Idle detection helper + ********************************************************************************/ +int secondsSinceLastInput(); + + +/******************************************************************************** + * Executable helper + ********************************************************************************/ +void GetProcessList(QStringList &processes); +bool isInFocus(const QString &exeToCheck); + + +/******************************************************************************** + * Sceneswitch helper + ********************************************************************************/ +struct obs_weak_source; +typedef struct obs_weak_source obs_weak_source_t; + +obs_weak_source_t* getNextTransition(obs_weak_source_t* scene1, obs_weak_source_t* scene2); +void switchScene(OBSWeakSource scene, OBSWeakSource transition); + + +/******************************************************************************** + * Hotkey helper + ********************************************************************************/ +void startStopHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotkey, bool pressed); +void loadKeybinding(obs_hotkey_id hotkeyId); + + +/******************************************************************************** + * Main SwitcherData + ********************************************************************************/ +struct SwitcherData; +extern SwitcherData* switcher; diff --git a/executable-switch.cpp b/executable-switch.cpp index 20842fe0..efe5f292 100644 --- a/executable-switch.cpp +++ b/executable-switch.cpp @@ -1,140 +1,140 @@ -#include "advanced-scene-switcher.hpp" - -int SceneSwitcher::executableFindByData(const QString& exe) -{ - int count = ui->executables->count(); - - for (int i = 0; i < count; i++) - { - QListWidgetItem* item = ui->executables->item(i); - QString itemExe = item->data(Qt::UserRole).toString(); - - if (itemExe == exe) - return i; - } - - return -1; -} - - -void SceneSwitcher::on_executables_currentRowChanged(int idx) -{ - if (loading) - return; - if (idx == -1) - return; - - QListWidgetItem* item = ui->executables->item(idx); - - QString exec = item->data(Qt::UserRole).toString(); - - lock_guard lock(switcher->m); - for (auto& s : switcher->executableSwitches) - { - if (exec.compare(s.mExe) == 0) - { - QString sceneName = GetWeakSourceName(s.mScene).c_str(); - QString transitionName = GetWeakSourceName(s.mTransition).c_str(); - ui->executableScenes->setCurrentText(sceneName); - ui->executable->setCurrentText(exec); - ui->executableTransitions->setCurrentText(transitionName); - ui->requiresFocusCheckBox->setChecked(s.mInFocus); - break; - } - } -} - - -void SceneSwitcher::on_executableAdd_clicked() -{ - QString sceneName = ui->executableScenes->currentText(); - QString exeName = ui->executable->currentText(); - QString transitionName = ui->executableTransitions->currentText(); - bool inFocus = ui->requiresFocusCheckBox->isChecked(); - - if (exeName.isEmpty() || sceneName.isEmpty()) - return; - - OBSWeakSource source = GetWeakSourceByQString(sceneName); - OBSWeakSource transition = GetWeakTransitionByQString(transitionName); - QVariant v = QVariant::fromValue(exeName); - - QString text = MakeSwitchNameExecutable(sceneName, exeName, transitionName, inFocus); - - int idx = executableFindByData(exeName); - - if (idx == -1) - { - lock_guard lock(switcher->m); - switcher->executableSwitches.emplace_back( - source, transition, exeName.toUtf8().constData(), inFocus); - - QListWidgetItem* item = new QListWidgetItem(text, ui->executables); - item->setData(Qt::UserRole, v); - } - else - { - QListWidgetItem* item = ui->executables->item(idx); - item->setText(text); - - { - lock_guard lock(switcher->m); - for (auto& s : switcher->executableSwitches) - { - if (s.mExe == exeName) - { - s.mScene = source; - s.mTransition = transition; - s.mInFocus = inFocus; - break; - } - } - } - - ui->executables->sortItems(); - } -} - - -void SceneSwitcher::on_executableRemove_clicked() -{ - QListWidgetItem* item = ui->executables->currentItem(); - if (!item) - return; - - QString exe = item->data(Qt::UserRole).toString(); - - { - lock_guard lock(switcher->m); - auto& switches = switcher->executableSwitches; - - for (auto it = switches.begin(); it != switches.end(); ++it) - { - auto& s = *it; - - if (s.mExe == exe) - { - switches.erase(it); - break; - } - } - } - - delete item; -} - -void SwitcherData::checkExeSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition) -{ - QStringList runningProcesses; - GetProcessList(runningProcesses); - for (ExecutableSceneSwitch& s : executableSwitches) - { - if (runningProcesses.contains(s.mExe)) - { - scene = s.mScene; - transition = s.mTransition; - match = !s.mInFocus || (s.mInFocus && isInFocus(s.mExe)); - break; - } - } -} +#include "advanced-scene-switcher.hpp" + +int SceneSwitcher::executableFindByData(const QString& exe) +{ + int count = ui->executables->count(); + + for (int i = 0; i < count; i++) + { + QListWidgetItem* item = ui->executables->item(i); + QString itemExe = item->data(Qt::UserRole).toString(); + + if (itemExe == exe) + return i; + } + + return -1; +} + + +void SceneSwitcher::on_executables_currentRowChanged(int idx) +{ + if (loading) + return; + if (idx == -1) + return; + + QListWidgetItem* item = ui->executables->item(idx); + + QString exec = item->data(Qt::UserRole).toString(); + + lock_guard lock(switcher->m); + for (auto& s : switcher->executableSwitches) + { + if (exec.compare(s.mExe) == 0) + { + QString sceneName = GetWeakSourceName(s.mScene).c_str(); + QString transitionName = GetWeakSourceName(s.mTransition).c_str(); + ui->executableScenes->setCurrentText(sceneName); + ui->executable->setCurrentText(exec); + ui->executableTransitions->setCurrentText(transitionName); + ui->requiresFocusCheckBox->setChecked(s.mInFocus); + break; + } + } +} + + +void SceneSwitcher::on_executableAdd_clicked() +{ + QString sceneName = ui->executableScenes->currentText(); + QString exeName = ui->executable->currentText(); + QString transitionName = ui->executableTransitions->currentText(); + bool inFocus = ui->requiresFocusCheckBox->isChecked(); + + if (exeName.isEmpty() || sceneName.isEmpty()) + return; + + OBSWeakSource source = GetWeakSourceByQString(sceneName); + OBSWeakSource transition = GetWeakTransitionByQString(transitionName); + QVariant v = QVariant::fromValue(exeName); + + QString text = MakeSwitchNameExecutable(sceneName, exeName, transitionName, inFocus); + + int idx = executableFindByData(exeName); + + if (idx == -1) + { + lock_guard lock(switcher->m); + switcher->executableSwitches.emplace_back( + source, transition, exeName.toUtf8().constData(), inFocus); + + QListWidgetItem* item = new QListWidgetItem(text, ui->executables); + item->setData(Qt::UserRole, v); + } + else + { + QListWidgetItem* item = ui->executables->item(idx); + item->setText(text); + + { + lock_guard lock(switcher->m); + for (auto& s : switcher->executableSwitches) + { + if (s.mExe == exeName) + { + s.mScene = source; + s.mTransition = transition; + s.mInFocus = inFocus; + break; + } + } + } + + ui->executables->sortItems(); + } +} + + +void SceneSwitcher::on_executableRemove_clicked() +{ + QListWidgetItem* item = ui->executables->currentItem(); + if (!item) + return; + + QString exe = item->data(Qt::UserRole).toString(); + + { + lock_guard lock(switcher->m); + auto& switches = switcher->executableSwitches; + + for (auto it = switches.begin(); it != switches.end(); ++it) + { + auto& s = *it; + + if (s.mExe == exe) + { + switches.erase(it); + break; + } + } + } + + delete item; +} + +void SwitcherData::checkExeSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition) +{ + QStringList runningProcesses; + GetProcessList(runningProcesses); + for (ExecutableSceneSwitch& s : executableSwitches) + { + if (runningProcesses.contains(s.mExe)) + { + scene = s.mScene; + transition = s.mTransition; + match = !s.mInFocus || (s.mInFocus && isInFocus(s.mExe)); + break; + } + } +} diff --git a/file-switch.cpp b/file-switch.cpp index 83913625..a315d380 100644 --- a/file-switch.cpp +++ b/file-switch.cpp @@ -1,261 +1,254 @@ -#include -#include -#include -#include -#include "advanced-scene-switcher.hpp" - - - -void SceneSwitcher::on_browseButton_clicked() -{ - QString path = QFileDialog::getOpenFileName( - this, tr("Select a file to write to ..."), QDir::currentPath(), tr("Text files (*.txt)")); - if (!path.isEmpty()) - ui->writePathLineEdit->setText(path); -} - -void SceneSwitcher::on_readFileCheckBox_stateChanged(int state) -{ - if (loading) - return; - - lock_guard lock(switcher->m); - if (!state) - { - ui->browseButton_2->setDisabled(true); - ui->readPathLineEdit->setDisabled(true); - switcher->fileIO.readEnabled = false; - } - else - { - ui->browseButton_2->setDisabled(false); - ui->readPathLineEdit->setDisabled(false); - switcher->fileIO.readEnabled = true; - } -} - -void SceneSwitcher::on_readPathLineEdit_textChanged(const QString& text) -{ - if (loading) - return; - - lock_guard lock(switcher->m); - if (text.isEmpty()) - { - switcher->fileIO.readEnabled = false; - return; - } - switcher->fileIO.readEnabled = true; - switcher->fileIO.readPath = text.toUtf8().constData(); -} - -void SceneSwitcher::on_writePathLineEdit_textChanged(const QString& text) -{ - if (loading) - return; - - lock_guard lock(switcher->m); - if (text.isEmpty()) - { - switcher->fileIO.writeEnabled = false; - return; - } - switcher->fileIO.writeEnabled = true; - switcher->fileIO.writePath = text.toUtf8().constData(); -} - -void SceneSwitcher::on_browseButton_2_clicked() -{ - QString path = QFileDialog::getOpenFileName( - this, tr("Select a file to read from ..."), QDir::currentPath(), tr("Any files (*.*)")); - if (!path.isEmpty()) - ui->readPathLineEdit->setText(path); -} - -void SwitcherData::writeSceneInfoToFile() -{ - if (!fileIO.writeEnabled || fileIO.writePath.empty()) - return; - - obs_source_t* currentSource = obs_frontend_get_current_scene(); - - QFile file(QString::fromStdString(fileIO.writePath)); - if (file.open(QIODevice::WriteOnly)) - { - const char* msg = obs_source_get_name(currentSource); - file.write(msg, qstrlen(msg)); - file.close(); - } - obs_source_release(currentSource); -} - -obs_weak_source_t* getNextTransition(obs_weak_source_t* scene1, obs_weak_source_t* scene2); - -void SwitcherData::checkSwitchInfoFromFile(bool& match, OBSWeakSource& scene, OBSWeakSource& transition) -{ - if (!fileIO.readEnabled || fileIO.readPath.empty()) - return; - - QFile file(QString::fromStdString(fileIO.readPath)); - if (file.open(QIODevice::ReadOnly)) - { - QTextStream in(&file); - QString sceneStr = in.readLine(); - obs_source_t* sceneRead = obs_get_source_by_name(sceneStr.toUtf8().constData()); - if (sceneRead){ - obs_weak_source_t* sceneReadWs = obs_source_get_weak_source(sceneRead); - - match = true; - scene = sceneReadWs; - transition = nullptr; - - obs_weak_source_release(sceneReadWs); - obs_source_release(sceneRead); - } - file.close(); - } -} - -void SwitcherData::checkFileContent(bool& match, OBSWeakSource& scene, OBSWeakSource& transition) -{ - for (FileSwitch& s : fileSwitches) - { - bool equal = false; - QString t = QString::fromStdString(s.text); - QFile file(QString::fromStdString(s.file)); - if (!file.open(QIODevice::ReadOnly)) - continue; - - //check file mod date - if (s.useTime) - { - QDateTime newLastMod = QFileInfo(file).lastModified(); - if (s.lastMod == newLastMod) - continue; - s.lastMod = newLastMod; - } - - - if (s.useRegex) - { - QTextStream in(&file); - QRegExp rx(t); - equal = rx.exactMatch(in.readAll()); - } - else - { - /*Im using QTextStream here so the conversion between different lineendings is done by QT. - *QT itself uses only the linefeed internally so the input by the user is always using that, - *but the files selected by the user might use different line endings. - *If you are reading this and know of a cleaner way to do this, please let me know :) - */ - QTextStream in(&file); - QTextStream text(&t); - while (!in.atEnd() && !text.atEnd()) - { - QString fileLine = in.readLine(); - QString textLine = text.readLine(); - if (QString::compare(fileLine, textLine, Qt::CaseSensitive) != 0) - { - equal = false; - break; - } - else { - equal = true; - } - } - } - file.close(); - - if (equal) - { - scene = s.scene; - transition = s.transition; - match = true; - - break; - } - } -} - - -void SceneSwitcher::on_browseButton_3_clicked() -{ - QString path = QFileDialog::getOpenFileName( - this, tr("Select a file to read from ..."), QDir::currentPath(), tr("Any files (*.*)")); - if (!path.isEmpty()) - ui->filePathLineEdit->setText(path); -} - -void SceneSwitcher::on_fileAdd_clicked() -{ - QString sceneName = ui->fileScenes->currentText(); - QString transitionName = ui->fileTransitions->currentText(); - QString fileName = ui->filePathLineEdit->text(); - QString text = ui->fileTextEdit->toPlainText(); - bool useRegex = ui->fileContentRegExCheckBox->isChecked(); - bool useTime = ui->fileContentTimeCheckBox->isChecked(); - - if (sceneName.isEmpty() || transitionName.isEmpty() || fileName.isEmpty() || text.isEmpty()) - return; - - OBSWeakSource source = GetWeakSourceByQString(sceneName); - OBSWeakSource transition = GetWeakTransitionByQString(transitionName); - - QString switchText = MakeFileSwitchName(sceneName, transitionName, fileName, text, useRegex, useTime); - QVariant v = QVariant::fromValue(switchText); - - - QListWidgetItem* item = new QListWidgetItem(switchText, ui->fileScenesList); - item->setData(Qt::UserRole, v); - - lock_guard lock(switcher->m); - switcher->fileSwitches.emplace_back( - source, transition, fileName.toUtf8().constData(), text.toUtf8().constData(), useRegex, useTime); - -} - -void SceneSwitcher::on_fileRemove_clicked() -{ - QListWidgetItem* item = ui->fileScenesList->currentItem(); - if (!item) - return; - - int idx = ui->fileScenesList->currentRow(); - if (idx == -1) - return; - - { - lock_guard lock(switcher->m); - - auto& switches = switcher->fileSwitches; - switches.erase(switches.begin() + idx); - } - qDeleteAll(ui->fileScenesList->selectedItems()); - //delete item; -} - - -void SceneSwitcher::on_fileScenesList_currentRowChanged(int idx) -{ - if (loading) - return; - if (idx == -1) - return; - - lock_guard lock(switcher->m); - - if (switcher->fileSwitches.size() <= idx) - return; - FileSwitch s = switcher->fileSwitches[idx]; - - string sceneName = GetWeakSourceName(s.scene); - string transitionName = GetWeakSourceName(s.transition); - - ui->fileScenes->setCurrentText(sceneName.c_str()); - ui->fileTransitions->setCurrentText(transitionName.c_str()); - ui->fileTextEdit->setPlainText(s.text.c_str()); - ui->filePathLineEdit->setText(s.file.c_str()); - ui->fileContentRegExCheckBox->setChecked(s.useRegex); - ui->fileContentTimeCheckBox->setChecked(s.useTime); -} +#include +#include +#include +#include +#include "advanced-scene-switcher.hpp" + + + +void SceneSwitcher::on_browseButton_clicked() +{ + QString path = QFileDialog::getOpenFileName( + this, tr("Select a file to write to ..."), QDir::currentPath(), tr("Text files (*.txt)")); + if (!path.isEmpty()) + ui->writePathLineEdit->setText(path); +} + +void SceneSwitcher::on_readFileCheckBox_stateChanged(int state) +{ + if (loading) + return; + + lock_guard lock(switcher->m); + if (!state) + { + ui->browseButton_2->setDisabled(true); + ui->readPathLineEdit->setDisabled(true); + switcher->fileIO.readEnabled = false; + } + else + { + ui->browseButton_2->setDisabled(false); + ui->readPathLineEdit->setDisabled(false); + switcher->fileIO.readEnabled = true; + } +} + +void SceneSwitcher::on_readPathLineEdit_textChanged(const QString& text) +{ + if (loading) + return; + + lock_guard lock(switcher->m); + if (text.isEmpty()) + { + switcher->fileIO.readEnabled = false; + return; + } + switcher->fileIO.readEnabled = true; + switcher->fileIO.readPath = text.toUtf8().constData(); +} + +void SceneSwitcher::on_writePathLineEdit_textChanged(const QString& text) +{ + if (loading) + return; + + lock_guard lock(switcher->m); + if (text.isEmpty()) + { + switcher->fileIO.writeEnabled = false; + return; + } + switcher->fileIO.writeEnabled = true; + switcher->fileIO.writePath = text.toUtf8().constData(); +} + +void SceneSwitcher::on_browseButton_2_clicked() +{ + QString path = QFileDialog::getOpenFileName( + this, tr("Select a file to read from ..."), QDir::currentPath(), tr("Any files (*.*)")); + if (!path.isEmpty()) + ui->readPathLineEdit->setText(path); +} + +void SwitcherData::writeSceneInfoToFile() +{ + if (!fileIO.writeEnabled || fileIO.writePath.empty()) + return; + + obs_source_t* currentSource = obs_frontend_get_current_scene(); + + QFile file(QString::fromStdString(fileIO.writePath)); + if (file.open(QIODevice::WriteOnly)) + { + const char* msg = obs_source_get_name(currentSource); + file.write(msg, qstrlen(msg)); + file.close(); + } + obs_source_release(currentSource); +} + +void SwitcherData::checkSwitchInfoFromFile(bool& match, OBSWeakSource& scene, OBSWeakSource& transition) +{ + if (!fileIO.readEnabled || fileIO.readPath.empty()) + return; + + QFile file(QString::fromStdString(fileIO.readPath)); + if (file.open(QIODevice::ReadOnly)) + { + QTextStream in(&file); + QString sceneStr = in.readLine(); + obs_source_t* sceneRead = obs_get_source_by_name(sceneStr.toUtf8().constData()); + if (sceneRead){ + obs_weak_source_t* sceneReadWs = obs_source_get_weak_source(sceneRead); + + match = true; + scene = sceneReadWs; + transition = nullptr; + + obs_weak_source_release(sceneReadWs); + obs_source_release(sceneRead); + } + file.close(); + } +} + +void SwitcherData::checkFileContent(bool& match, OBSWeakSource& scene, OBSWeakSource& transition) +{ + for (FileSwitch& s : fileSwitches) + { + bool equal = false; + QString t = QString::fromStdString(s.text); + QFile file(QString::fromStdString(s.file)); + if (!file.open(QIODevice::ReadOnly)) + continue; + + if (s.useTime) + { + QDateTime newLastMod = QFileInfo(file).lastModified(); + if (s.lastMod == newLastMod) + continue; + s.lastMod = newLastMod; + } + + if (s.useRegex) + { + QTextStream in(&file); + QRegExp rx(t); + equal = rx.exactMatch(in.readAll()); + } + else + { + /*Im using QTextStream here so the conversion between different lineendings is done by QT. + *QT itself uses only the linefeed internally so the input by the user is always using that, + *but the files selected by the user might use different line endings. + *If you are reading this and know of a cleaner way to do this, please let me know :) + */ + QTextStream in(&file); + QTextStream text(&t); + while (!in.atEnd() && !text.atEnd()) + { + QString fileLine = in.readLine(); + QString textLine = text.readLine(); + if (QString::compare(fileLine, textLine, Qt::CaseSensitive) != 0) + { + equal = false; + break; + } + else { + equal = true; + } + } + } + file.close(); + + if (equal) + { + scene = s.scene; + transition = s.transition; + match = true; + + break; + } + } +} + +void SceneSwitcher::on_browseButton_3_clicked() +{ + QString path = QFileDialog::getOpenFileName( + this, tr("Select a file to read from ..."), QDir::currentPath(), tr("Any files (*.*)")); + if (!path.isEmpty()) + ui->filePathLineEdit->setText(path); +} + +void SceneSwitcher::on_fileAdd_clicked() +{ + QString sceneName = ui->fileScenes->currentText(); + QString transitionName = ui->fileTransitions->currentText(); + QString fileName = ui->filePathLineEdit->text(); + QString text = ui->fileTextEdit->toPlainText(); + bool useRegex = ui->fileContentRegExCheckBox->isChecked(); + bool useTime = ui->fileContentTimeCheckBox->isChecked(); + + if (sceneName.isEmpty() || transitionName.isEmpty() || fileName.isEmpty() || text.isEmpty()) + return; + + OBSWeakSource source = GetWeakSourceByQString(sceneName); + OBSWeakSource transition = GetWeakTransitionByQString(transitionName); + + QString switchText = MakeFileSwitchName(sceneName, transitionName, fileName, text, useRegex, useTime); + QVariant v = QVariant::fromValue(switchText); + + + QListWidgetItem* item = new QListWidgetItem(switchText, ui->fileScenesList); + item->setData(Qt::UserRole, v); + + lock_guard lock(switcher->m); + switcher->fileSwitches.emplace_back( + source, transition, fileName.toUtf8().constData(), text.toUtf8().constData(), useRegex, useTime); + +} + +void SceneSwitcher::on_fileRemove_clicked() +{ + QListWidgetItem* item = ui->fileScenesList->currentItem(); + if (!item) + return; + + int idx = ui->fileScenesList->currentRow(); + if (idx == -1) + return; + + { + lock_guard lock(switcher->m); + + auto& switches = switcher->fileSwitches; + switches.erase(switches.begin() + idx); + } + qDeleteAll(ui->fileScenesList->selectedItems()); +} + +void SceneSwitcher::on_fileScenesList_currentRowChanged(int idx) +{ + if (loading) + return; + if (idx == -1) + return; + + lock_guard lock(switcher->m); + + if (switcher->fileSwitches.size() <= idx) + return; + FileSwitch s = switcher->fileSwitches[idx]; + + string sceneName = GetWeakSourceName(s.scene); + string transitionName = GetWeakSourceName(s.transition); + + ui->fileScenes->setCurrentText(sceneName.c_str()); + ui->fileTransitions->setCurrentText(transitionName.c_str()); + ui->fileTextEdit->setPlainText(s.text.c_str()); + ui->filePathLineEdit->setText(s.file.c_str()); + ui->fileContentRegExCheckBox->setChecked(s.useRegex); + ui->fileContentTimeCheckBox->setChecked(s.useTime); +} diff --git a/general.cpp b/general.cpp index 37f3ff03..73aa2f17 100644 --- a/general.cpp +++ b/general.cpp @@ -1,107 +1,107 @@ -#include "advanced-scene-switcher.hpp" -#include - -void SceneSwitcher::on_close_clicked() -{ - done(0); -} - -void SceneSwitcher::on_startAtLaunch_toggled(bool value) -{ - if (loading) - return; - - lock_guard lock(switcher->m); - switcher->startAtLaunch = value; -} - -void SceneSwitcher::UpdateNonMatchingScene(const QString& name) -{ - obs_source_t* scene = obs_get_source_by_name(name.toUtf8().constData()); - obs_weak_source_t* ws = obs_source_get_weak_source(scene); - - switcher->nonMatchingScene = ws; - - obs_weak_source_release(ws); - obs_source_release(scene); -} - -void SceneSwitcher::on_noMatchDontSwitch_clicked() -{ - if (loading) - return; - - lock_guard lock(switcher->m); - switcher->switchIfNotMatching = NO_SWITCH; - ui->noMatchSwitchScene->setEnabled(false); -} - -void SceneSwitcher::on_noMatchSwitch_clicked() -{ - if (loading) - return; - - lock_guard lock(switcher->m); - switcher->switchIfNotMatching = SWITCH; - ui->noMatchSwitchScene->setEnabled(true); - UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText()); -} - -void SceneSwitcher::on_noMatchRandomSwitch_clicked() -{ - if (loading) - return; - - lock_guard lock(switcher->m); - switcher->switchIfNotMatching = RANDOM_SWITCH; - ui->noMatchSwitchScene->setEnabled(false); -} - -void SceneSwitcher::on_noMatchSwitchScene_currentTextChanged(const QString& text) -{ - if (loading) - return; - - lock_guard lock(switcher->m); - UpdateNonMatchingScene(text); -} - -void SceneSwitcher::on_checkInterval_valueChanged(int value) -{ - if (loading) - return; - - lock_guard lock(switcher->m); - switcher->interval = value; -} - -void SceneSwitcher::SetStarted() -{ - ui->toggleStartButton->setText("Stop"); - ui->pluginRunningText->setText("Active"); -} - -void SceneSwitcher::SetStopped() -{ - ui->toggleStartButton->setText("Start"); - ui->pluginRunningText->setText("Inactive"); -} - -void SceneSwitcher::on_toggleStartButton_clicked() -{ - if (switcher->th.joinable()) - { - switcher->Stop(); - SetStopped(); - } - else - { - switcher->Start(); - SetStarted(); - } -} - -void SceneSwitcher::closeEvent(QCloseEvent*) -{ - obs_frontend_save(); -} +#include "advanced-scene-switcher.hpp" +#include + +void SceneSwitcher::on_close_clicked() +{ + done(0); +} + +void SceneSwitcher::on_startAtLaunch_toggled(bool value) +{ + if (loading) + return; + + lock_guard lock(switcher->m); + switcher->startAtLaunch = value; +} + +void SceneSwitcher::UpdateNonMatchingScene(const QString& name) +{ + obs_source_t* scene = obs_get_source_by_name(name.toUtf8().constData()); + obs_weak_source_t* ws = obs_source_get_weak_source(scene); + + switcher->nonMatchingScene = ws; + + obs_weak_source_release(ws); + obs_source_release(scene); +} + +void SceneSwitcher::on_noMatchDontSwitch_clicked() +{ + if (loading) + return; + + lock_guard lock(switcher->m); + switcher->switchIfNotMatching = NO_SWITCH; + ui->noMatchSwitchScene->setEnabled(false); +} + +void SceneSwitcher::on_noMatchSwitch_clicked() +{ + if (loading) + return; + + lock_guard lock(switcher->m); + switcher->switchIfNotMatching = SWITCH; + ui->noMatchSwitchScene->setEnabled(true); + UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText()); +} + +void SceneSwitcher::on_noMatchRandomSwitch_clicked() +{ + if (loading) + return; + + lock_guard lock(switcher->m); + switcher->switchIfNotMatching = RANDOM_SWITCH; + ui->noMatchSwitchScene->setEnabled(false); +} + +void SceneSwitcher::on_noMatchSwitchScene_currentTextChanged(const QString& text) +{ + if (loading) + return; + + lock_guard lock(switcher->m); + UpdateNonMatchingScene(text); +} + +void SceneSwitcher::on_checkInterval_valueChanged(int value) +{ + if (loading) + return; + + lock_guard lock(switcher->m); + switcher->interval = value; +} + +void SceneSwitcher::SetStarted() +{ + ui->toggleStartButton->setText("Stop"); + ui->pluginRunningText->setText("Active"); +} + +void SceneSwitcher::SetStopped() +{ + ui->toggleStartButton->setText("Start"); + ui->pluginRunningText->setText("Inactive"); +} + +void SceneSwitcher::on_toggleStartButton_clicked() +{ + if (switcher->th.joinable()) + { + switcher->Stop(); + SetStopped(); + } + else + { + switcher->Start(); + SetStarted(); + } +} + +void SceneSwitcher::closeEvent(QCloseEvent*) +{ + obs_frontend_save(); +} diff --git a/hotkey.cpp b/hotkey.cpp index 569fa10d..dd998c26 100644 --- a/hotkey.cpp +++ b/hotkey.cpp @@ -1,72 +1,72 @@ -#include -#include "advanced-scene-switcher.hpp" - -void startStopHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotkey, bool pressed) -{ - UNUSED_PARAMETER(data); - UNUSED_PARAMETER(hotkey); - - if (pressed) - { - if (switcher->th.joinable()) - switcher->Stop(); - else - switcher->Start(); - } - - obs_data_array* hotkeyData = obs_hotkey_save(id); - - if (hotkeyData != NULL) - { - char* path = obs_module_config_path(""); - ofstream file; - file.open(string(path).append("hotkey.txt"), ofstream::trunc); - if (file.is_open()) - { - size_t num = obs_data_array_count(hotkeyData); - for (size_t i = 0; i < num; i++) - { - obs_data_t* data = obs_data_array_item(hotkeyData, i); - string temp = obs_data_get_json(data); - obs_data_release(data); - file << temp; - } - file.close(); - } - bfree(path); - } - obs_data_array_release(hotkeyData); -} - -string loadConfigFile(string filename) -{ - ifstream settingsFile; - char* path = obs_module_config_path(""); - string value; - - settingsFile.open(string(path).append(filename)); - if (settingsFile.is_open()) - { - settingsFile.seekg(0, ios::end); - value.reserve(settingsFile.tellg()); - settingsFile.seekg(0, ios::beg); - value.assign((istreambuf_iterator(settingsFile)), istreambuf_iterator()); - settingsFile.close(); - } - bfree(path); - return value; -} - -void loadKeybinding(obs_hotkey_id hotkeyId) -{ - string bindings = loadConfigFile("hotkey.txt"); - if (!bindings.empty()) - { - obs_data_array_t* hotkeyData = obs_data_array_create(); - obs_data_t* data = obs_data_create_from_json(bindings.c_str()); - obs_data_array_insert(hotkeyData, 0, data); - obs_data_release(data); - obs_hotkey_load(hotkeyId, hotkeyData); - obs_data_array_release(hotkeyData); - } -} +#include +#include "advanced-scene-switcher.hpp" + +void startStopHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotkey, bool pressed) +{ + UNUSED_PARAMETER(data); + UNUSED_PARAMETER(hotkey); + + if (pressed) + { + if (switcher->th.joinable()) + switcher->Stop(); + else + switcher->Start(); + } + + obs_data_array* hotkeyData = obs_hotkey_save(id); + + if (hotkeyData != NULL) + { + char* path = obs_module_config_path(""); + ofstream file; + file.open(string(path).append("hotkey.txt"), ofstream::trunc); + if (file.is_open()) + { + size_t num = obs_data_array_count(hotkeyData); + for (size_t i = 0; i < num; i++) + { + obs_data_t* data = obs_data_array_item(hotkeyData, i); + string temp = obs_data_get_json(data); + obs_data_release(data); + file << temp; + } + file.close(); + } + bfree(path); + } + obs_data_array_release(hotkeyData); +} + +string loadConfigFile(string filename) +{ + ifstream settingsFile; + char* path = obs_module_config_path(""); + string value; + + settingsFile.open(string(path).append(filename)); + if (settingsFile.is_open()) + { + settingsFile.seekg(0, ios::end); + value.reserve(settingsFile.tellg()); + settingsFile.seekg(0, ios::beg); + value.assign((istreambuf_iterator(settingsFile)), istreambuf_iterator()); + settingsFile.close(); + } + bfree(path); + return value; +} + +void loadKeybinding(obs_hotkey_id hotkeyId) +{ + string bindings = loadConfigFile("hotkey.txt"); + if (!bindings.empty()) + { + obs_data_array_t* hotkeyData = obs_data_array_create(); + obs_data_t* data = obs_data_create_from_json(bindings.c_str()); + obs_data_array_insert(hotkeyData, 0, data); + obs_data_release(data); + obs_hotkey_load(hotkeyId, hotkeyData); + obs_data_array_release(hotkeyData); + } +} diff --git a/idle-switch.cpp b/idle-switch.cpp index c12767d7..465a64d3 100644 --- a/idle-switch.cpp +++ b/idle-switch.cpp @@ -1,210 +1,210 @@ -#include "advanced-scene-switcher.hpp" - -void SwitcherData::checkIdleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition) -{ - if (!idleData.idleEnable) - return; - - string title; - bool ignoreIdle = false; - //lock.unlock(); - GetCurrentWindowTitle(title); - //lock.lock(); - - for (string& window : ignoreIdleWindows) - { - if (window == title) - { - ignoreIdle = true; - break; - } - } - - if (!ignoreIdle) - { - for (string& window : ignoreIdleWindows) - { - try - { - bool matches = regex_match(title, regex(window)); - if (matches) - { - ignoreIdle = true; - break; - } - } - catch (const regex_error&) - { - } - } - } - - if (!ignoreIdle && secondsSinceLastInput() > idleData.time) - { - scene = idleData.scene; - transition = idleData.transition; - match = true; - } -} - -void SceneSwitcher::on_idleCheckBox_stateChanged(int state) -{ - if (loading) - return; - - lock_guard lock(switcher->m); - if (!state) - { - ui->idleScenes->setDisabled(true); - ui->idleSpinBox->setDisabled(true); - ui->idleTransitions->setDisabled(true); - - switcher->idleData.idleEnable = false; - } - else - { - ui->idleScenes->setDisabled(false); - ui->idleSpinBox->setDisabled(false); - ui->idleTransitions->setDisabled(false); - - switcher->idleData.idleEnable = true; - - UpdateIdleDataTransition(ui->idleTransitions->currentText()); - UpdateIdleDataScene(ui->idleScenes->currentText()); - } -} - - -void SceneSwitcher::UpdateIdleDataTransition(const QString& name) -{ - obs_weak_source_t* transition = GetWeakTransitionByQString(name); - switcher->idleData.transition = transition; -} - -void SceneSwitcher::UpdateIdleDataScene(const QString& name) -{ - obs_source_t* scene = obs_get_source_by_name(name.toUtf8().constData()); - obs_weak_source_t* ws = obs_source_get_weak_source(scene); - - switcher->idleData.scene = ws; - - obs_weak_source_release(ws); - obs_source_release(scene); -} - -void SceneSwitcher::on_idleTransitions_currentTextChanged(const QString& text) -{ - if (loading) - return; - - lock_guard lock(switcher->m); - UpdateIdleDataTransition(text); -} - -void SceneSwitcher::on_idleScenes_currentTextChanged(const QString& text) -{ - if (loading) - return; - - lock_guard lock(switcher->m); - UpdateIdleDataScene(text); -} - -void SceneSwitcher::on_idleSpinBox_valueChanged(int i) -{ - if (loading) - return; - lock_guard lock(switcher->m); - switcher->idleData.time = i; -} - -void SceneSwitcher::on_ignoreIdleWindows_currentRowChanged(int idx) -{ - if (loading) - return; - if (idx == -1) - return; - - QListWidgetItem* item = ui->ignoreIdleWindows->item(idx); - - QString window = item->data(Qt::UserRole).toString(); - - lock_guard lock(switcher->m); - for (auto& w : switcher->ignoreIdleWindows) - { - if (window.compare(w.c_str()) == 0) - { - ui->ignoreIdleWindowsWindows->setCurrentText(w.c_str()); - break; - } - } -} - -void SceneSwitcher::on_ignoreIdleAdd_clicked() -{ - QString windowName = ui->ignoreIdleWindowsWindows->currentText(); - - if (windowName.isEmpty()) - return; - - QVariant v = QVariant::fromValue(windowName); - - QList items = ui->ignoreIdleWindows->findItems(windowName, Qt::MatchExactly); - - if (items.size() == 0) - { - QListWidgetItem* item = new QListWidgetItem(windowName, ui->ignoreIdleWindows); - item->setData(Qt::UserRole, v); - - lock_guard lock(switcher->m); - switcher->ignoreIdleWindows.emplace_back(windowName.toUtf8().constData()); - ui->ignoreIdleWindows->sortItems(); - } -} - -void SceneSwitcher::on_ignoreIdleRemove_clicked() -{ - QListWidgetItem* item = ui->ignoreIdleWindows->currentItem(); - if (!item) - return; - - QString windowName = item->data(Qt::UserRole).toString(); - - { - lock_guard lock(switcher->m); - auto& windows = switcher->ignoreIdleWindows; - - for (auto it = windows.begin(); it != windows.end(); ++it) - { - auto& s = *it; - - if (s == windowName.toUtf8().constData()) - { - windows.erase(it); - break; - } - } - } - - delete item; -} - -int SceneSwitcher::IgnoreIdleWindowsFindByData(const QString& window) -{ - int count = ui->ignoreIdleWindows->count(); - int idx = -1; - - for (int i = 0; i < count; i++) - { - QListWidgetItem* item = ui->ignoreIdleWindows->item(i); - QString itemRegion = item->data(Qt::UserRole).toString(); - - if (itemRegion == window) - { - idx = i; - break; - } - } - - return idx; -} +#include "advanced-scene-switcher.hpp" + +void SwitcherData::checkIdleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition) +{ + if (!idleData.idleEnable) + return; + + string title; + bool ignoreIdle = false; + //lock.unlock(); + GetCurrentWindowTitle(title); + //lock.lock(); + + for (string& window : ignoreIdleWindows) + { + if (window == title) + { + ignoreIdle = true; + break; + } + } + + if (!ignoreIdle) + { + for (string& window : ignoreIdleWindows) + { + try + { + bool matches = regex_match(title, regex(window)); + if (matches) + { + ignoreIdle = true; + break; + } + } + catch (const regex_error&) + { + } + } + } + + if (!ignoreIdle && secondsSinceLastInput() > idleData.time) + { + scene = idleData.scene; + transition = idleData.transition; + match = true; + } +} + +void SceneSwitcher::on_idleCheckBox_stateChanged(int state) +{ + if (loading) + return; + + lock_guard lock(switcher->m); + if (!state) + { + ui->idleScenes->setDisabled(true); + ui->idleSpinBox->setDisabled(true); + ui->idleTransitions->setDisabled(true); + + switcher->idleData.idleEnable = false; + } + else + { + ui->idleScenes->setDisabled(false); + ui->idleSpinBox->setDisabled(false); + ui->idleTransitions->setDisabled(false); + + switcher->idleData.idleEnable = true; + + UpdateIdleDataTransition(ui->idleTransitions->currentText()); + UpdateIdleDataScene(ui->idleScenes->currentText()); + } +} + + +void SceneSwitcher::UpdateIdleDataTransition(const QString& name) +{ + obs_weak_source_t* transition = GetWeakTransitionByQString(name); + switcher->idleData.transition = transition; +} + +void SceneSwitcher::UpdateIdleDataScene(const QString& name) +{ + obs_source_t* scene = obs_get_source_by_name(name.toUtf8().constData()); + obs_weak_source_t* ws = obs_source_get_weak_source(scene); + + switcher->idleData.scene = ws; + + obs_weak_source_release(ws); + obs_source_release(scene); +} + +void SceneSwitcher::on_idleTransitions_currentTextChanged(const QString& text) +{ + if (loading) + return; + + lock_guard lock(switcher->m); + UpdateIdleDataTransition(text); +} + +void SceneSwitcher::on_idleScenes_currentTextChanged(const QString& text) +{ + if (loading) + return; + + lock_guard lock(switcher->m); + UpdateIdleDataScene(text); +} + +void SceneSwitcher::on_idleSpinBox_valueChanged(int i) +{ + if (loading) + return; + lock_guard lock(switcher->m); + switcher->idleData.time = i; +} + +void SceneSwitcher::on_ignoreIdleWindows_currentRowChanged(int idx) +{ + if (loading) + return; + if (idx == -1) + return; + + QListWidgetItem* item = ui->ignoreIdleWindows->item(idx); + + QString window = item->data(Qt::UserRole).toString(); + + lock_guard lock(switcher->m); + for (auto& w : switcher->ignoreIdleWindows) + { + if (window.compare(w.c_str()) == 0) + { + ui->ignoreIdleWindowsWindows->setCurrentText(w.c_str()); + break; + } + } +} + +void SceneSwitcher::on_ignoreIdleAdd_clicked() +{ + QString windowName = ui->ignoreIdleWindowsWindows->currentText(); + + if (windowName.isEmpty()) + return; + + QVariant v = QVariant::fromValue(windowName); + + QList items = ui->ignoreIdleWindows->findItems(windowName, Qt::MatchExactly); + + if (items.size() == 0) + { + QListWidgetItem* item = new QListWidgetItem(windowName, ui->ignoreIdleWindows); + item->setData(Qt::UserRole, v); + + lock_guard lock(switcher->m); + switcher->ignoreIdleWindows.emplace_back(windowName.toUtf8().constData()); + ui->ignoreIdleWindows->sortItems(); + } +} + +void SceneSwitcher::on_ignoreIdleRemove_clicked() +{ + QListWidgetItem* item = ui->ignoreIdleWindows->currentItem(); + if (!item) + return; + + QString windowName = item->data(Qt::UserRole).toString(); + + { + lock_guard lock(switcher->m); + auto& windows = switcher->ignoreIdleWindows; + + for (auto it = windows.begin(); it != windows.end(); ++it) + { + auto& s = *it; + + if (s == windowName.toUtf8().constData()) + { + windows.erase(it); + break; + } + } + } + + delete item; +} + +int SceneSwitcher::IgnoreIdleWindowsFindByData(const QString& window) +{ + int count = ui->ignoreIdleWindows->count(); + int idx = -1; + + for (int i = 0; i < count; i++) + { + QListWidgetItem* item = ui->ignoreIdleWindows->item(i); + QString itemRegion = item->data(Qt::UserRole).toString(); + + if (itemRegion == window) + { + idx = i; + break; + } + } + + return idx; +} diff --git a/pause-switch.cpp b/pause-switch.cpp index c887b7e4..719a15e9 100644 --- a/pause-switch.cpp +++ b/pause-switch.cpp @@ -1,242 +1,242 @@ -#include "advanced-scene-switcher.hpp" - -void SceneSwitcher::on_pauseScenesAdd_clicked() -{ - QString sceneName = ui->pauseScenesScenes->currentText(); - - if (sceneName.isEmpty()) - return; - - OBSWeakSource source = GetWeakSourceByQString(sceneName); - QVariant v = QVariant::fromValue(sceneName); - - QList items = ui->pauseScenes->findItems(sceneName, Qt::MatchExactly); - - if (items.size() == 0) - { - QListWidgetItem* item = new QListWidgetItem(sceneName, ui->pauseScenes); - item->setData(Qt::UserRole, v); - - lock_guard lock(switcher->m); - switcher->pauseScenesSwitches.emplace_back(source); - ui->pauseScenes->sortItems(); - } -} - -void SceneSwitcher::on_pauseScenesRemove_clicked() -{ - QListWidgetItem* item = ui->pauseScenes->currentItem(); - if (!item) - return; - - QString pauseScene = item->data(Qt::UserRole).toString(); - - { - lock_guard lock(switcher->m); - auto& switches = switcher->pauseScenesSwitches; - - for (auto it = switches.begin(); it != switches.end(); ++it) - { - auto& s = *it; - - if (s == GetWeakSourceByQString(pauseScene)) - { - switches.erase(it); - break; - } - } - } - - delete item; -} - -void SceneSwitcher::on_pauseWindowsAdd_clicked() -{ - QString windowName = ui->pauseWindowsWindows->currentText(); - - if (windowName.isEmpty()) - return; - - QVariant v = QVariant::fromValue(windowName); - - QList items = ui->pauseWindows->findItems(windowName, Qt::MatchExactly); - - if (items.size() == 0) - { - QListWidgetItem* item = new QListWidgetItem(windowName, ui->pauseWindows); - item->setData(Qt::UserRole, v); - - lock_guard lock(switcher->m); - switcher->pauseWindowsSwitches.emplace_back(windowName.toUtf8().constData()); - ui->pauseWindows->sortItems(); - } -} - -void SceneSwitcher::on_pauseWindowsRemove_clicked() -{ - QListWidgetItem* item = ui->pauseWindows->currentItem(); - if (!item) - return; - - QString windowName = item->data(Qt::UserRole).toString(); - - { - lock_guard lock(switcher->m); - auto& switches = switcher->pauseWindowsSwitches; - - for (auto it = switches.begin(); it != switches.end(); ++it) - { - auto& s = *it; - - if (s == windowName.toUtf8().constData()) - { - switches.erase(it); - break; - } - } - } - - delete item; -} - -void SceneSwitcher::on_pauseScenes_currentRowChanged(int idx) -{ - if (loading) - return; - if (idx == -1) - return; - - QListWidgetItem* item = ui->pauseScenes->item(idx); - - QString scene = item->data(Qt::UserRole).toString(); - - lock_guard lock(switcher->m); - for (auto& s : switcher->pauseScenesSwitches) - { - string name = GetWeakSourceName(s); - if (scene.compare(name.c_str()) == 0) - { - ui->pauseScenesScenes->setCurrentText(name.c_str()); - break; - } - } -} - -void SceneSwitcher::on_pauseWindows_currentRowChanged(int idx) -{ - if (loading) - return; - if (idx == -1) - return; - - QListWidgetItem* item = ui->pauseWindows->item(idx); - - QString window = item->data(Qt::UserRole).toString(); - - lock_guard lock(switcher->m); - for (auto& s : switcher->pauseWindowsSwitches) - { - if (window.compare(s.c_str()) == 0) - { - ui->pauseWindowsWindows->setCurrentText(s.c_str()); - break; - } - } -} - -int SceneSwitcher::PauseScenesFindByData(const QString& scene) -{ - int count = ui->pauseScenes->count(); - int idx = -1; - - for (int i = 0; i < count; i++) - { - QListWidgetItem* item = ui->pauseScenes->item(i); - QString itemRegion = item->data(Qt::UserRole).toString(); - - if (itemRegion == scene) - { - idx = i; - break; - } - } - - return idx; -} - -int SceneSwitcher::PauseWindowsFindByData(const QString& window) -{ - int count = ui->pauseWindows->count(); - int idx = -1; - - for (int i = 0; i < count; i++) - { - QListWidgetItem* item = ui->pauseWindows->item(i); - QString itemRegion = item->data(Qt::UserRole).toString(); - - if (itemRegion == window) - { - idx = i; - break; - } - } - - return idx; -} - -bool SwitcherData::checkPause() -{ - bool pause = false; - obs_source_t* currentSource = obs_frontend_get_current_scene(); - obs_weak_source_t* ws = obs_source_get_weak_source(currentSource); - - for (OBSWeakSource& s : pauseScenesSwitches) - { - if (s == ws) - { - pause = true; - break; - } - } - obs_source_release(currentSource); - obs_weak_source_release(ws); - - string title; - if (!pause) - { - //lock.unlock(); - GetCurrentWindowTitle(title); - //lock.lock(); - for (string& window : pauseWindowsSwitches) - { - if (window == title) - { - pause = true; - break; - } - } - } - - if (!pause) - { - //lock.unlock(); - GetCurrentWindowTitle(title); - //lock.lock(); - for (string& window : pauseWindowsSwitches) - { - try - { - bool matches = regex_match(title, regex(window)); - if (matches) - { - pause = true; - break; - } - } - catch (const regex_error&) - { - } - } - } - return pause; -} +#include "advanced-scene-switcher.hpp" + +void SceneSwitcher::on_pauseScenesAdd_clicked() +{ + QString sceneName = ui->pauseScenesScenes->currentText(); + + if (sceneName.isEmpty()) + return; + + OBSWeakSource source = GetWeakSourceByQString(sceneName); + QVariant v = QVariant::fromValue(sceneName); + + QList items = ui->pauseScenes->findItems(sceneName, Qt::MatchExactly); + + if (items.size() == 0) + { + QListWidgetItem* item = new QListWidgetItem(sceneName, ui->pauseScenes); + item->setData(Qt::UserRole, v); + + lock_guard lock(switcher->m); + switcher->pauseScenesSwitches.emplace_back(source); + ui->pauseScenes->sortItems(); + } +} + +void SceneSwitcher::on_pauseScenesRemove_clicked() +{ + QListWidgetItem* item = ui->pauseScenes->currentItem(); + if (!item) + return; + + QString pauseScene = item->data(Qt::UserRole).toString(); + + { + lock_guard lock(switcher->m); + auto& switches = switcher->pauseScenesSwitches; + + for (auto it = switches.begin(); it != switches.end(); ++it) + { + auto& s = *it; + + if (s == GetWeakSourceByQString(pauseScene)) + { + switches.erase(it); + break; + } + } + } + + delete item; +} + +void SceneSwitcher::on_pauseWindowsAdd_clicked() +{ + QString windowName = ui->pauseWindowsWindows->currentText(); + + if (windowName.isEmpty()) + return; + + QVariant v = QVariant::fromValue(windowName); + + QList items = ui->pauseWindows->findItems(windowName, Qt::MatchExactly); + + if (items.size() == 0) + { + QListWidgetItem* item = new QListWidgetItem(windowName, ui->pauseWindows); + item->setData(Qt::UserRole, v); + + lock_guard lock(switcher->m); + switcher->pauseWindowsSwitches.emplace_back(windowName.toUtf8().constData()); + ui->pauseWindows->sortItems(); + } +} + +void SceneSwitcher::on_pauseWindowsRemove_clicked() +{ + QListWidgetItem* item = ui->pauseWindows->currentItem(); + if (!item) + return; + + QString windowName = item->data(Qt::UserRole).toString(); + + { + lock_guard lock(switcher->m); + auto& switches = switcher->pauseWindowsSwitches; + + for (auto it = switches.begin(); it != switches.end(); ++it) + { + auto& s = *it; + + if (s == windowName.toUtf8().constData()) + { + switches.erase(it); + break; + } + } + } + + delete item; +} + +void SceneSwitcher::on_pauseScenes_currentRowChanged(int idx) +{ + if (loading) + return; + if (idx == -1) + return; + + QListWidgetItem* item = ui->pauseScenes->item(idx); + + QString scene = item->data(Qt::UserRole).toString(); + + lock_guard lock(switcher->m); + for (auto& s : switcher->pauseScenesSwitches) + { + string name = GetWeakSourceName(s); + if (scene.compare(name.c_str()) == 0) + { + ui->pauseScenesScenes->setCurrentText(name.c_str()); + break; + } + } +} + +void SceneSwitcher::on_pauseWindows_currentRowChanged(int idx) +{ + if (loading) + return; + if (idx == -1) + return; + + QListWidgetItem* item = ui->pauseWindows->item(idx); + + QString window = item->data(Qt::UserRole).toString(); + + lock_guard lock(switcher->m); + for (auto& s : switcher->pauseWindowsSwitches) + { + if (window.compare(s.c_str()) == 0) + { + ui->pauseWindowsWindows->setCurrentText(s.c_str()); + break; + } + } +} + +int SceneSwitcher::PauseScenesFindByData(const QString& scene) +{ + int count = ui->pauseScenes->count(); + int idx = -1; + + for (int i = 0; i < count; i++) + { + QListWidgetItem* item = ui->pauseScenes->item(i); + QString itemRegion = item->data(Qt::UserRole).toString(); + + if (itemRegion == scene) + { + idx = i; + break; + } + } + + return idx; +} + +int SceneSwitcher::PauseWindowsFindByData(const QString& window) +{ + int count = ui->pauseWindows->count(); + int idx = -1; + + for (int i = 0; i < count; i++) + { + QListWidgetItem* item = ui->pauseWindows->item(i); + QString itemRegion = item->data(Qt::UserRole).toString(); + + if (itemRegion == window) + { + idx = i; + break; + } + } + + return idx; +} + +bool SwitcherData::checkPause() +{ + bool pause = false; + obs_source_t* currentSource = obs_frontend_get_current_scene(); + obs_weak_source_t* ws = obs_source_get_weak_source(currentSource); + + for (OBSWeakSource& s : pauseScenesSwitches) + { + if (s == ws) + { + pause = true; + break; + } + } + obs_source_release(currentSource); + obs_weak_source_release(ws); + + string title; + if (!pause) + { + //lock.unlock(); + GetCurrentWindowTitle(title); + //lock.lock(); + for (string& window : pauseWindowsSwitches) + { + if (window == title) + { + pause = true; + break; + } + } + } + + if (!pause) + { + //lock.unlock(); + GetCurrentWindowTitle(title); + //lock.lock(); + for (string& window : pauseWindowsSwitches) + { + try + { + bool matches = regex_match(title, regex(window)); + if (matches) + { + pause = true; + break; + } + } + catch (const regex_error&) + { + } + } + } + return pause; +} diff --git a/priority.cpp b/priority.cpp index e1eeedd3..791b3e06 100644 --- a/priority.cpp +++ b/priority.cpp @@ -1,45 +1,44 @@ -#include -#include "advanced-scene-switcher.hpp" - -void SceneSwitcher::on_priorityUp_clicked() -{ - int currentIndex = ui->priorityList->currentRow(); - if (currentIndex != -1 && currentIndex != 0) - { - ui->priorityList->insertItem(currentIndex - 1 ,ui->priorityList->takeItem(currentIndex)); - ui->priorityList->setCurrentRow(currentIndex -1); - lock_guard lock(switcher->m); - - iter_swap(switcher->functionNamesByPriority.begin() + currentIndex, switcher->functionNamesByPriority.begin() + currentIndex - 1); - } -} - -void SceneSwitcher::on_priorityDown_clicked() -{ - int currentIndex = ui->priorityList->currentRow(); - if (currentIndex != -1 && currentIndex != ui->priorityList->count() - 1) - { - ui->priorityList->insertItem(currentIndex + 1, ui->priorityList->takeItem(currentIndex)); - ui->priorityList->setCurrentRow(currentIndex + 1); - lock_guard lock(switcher->m); - - iter_swap(switcher->functionNamesByPriority.begin() + currentIndex, switcher->functionNamesByPriority.begin() + currentIndex + 1); - } -} - - -bool SwitcherData::prioFuncsValid() -{ - auto it = std::unique(functionNamesByPriority.begin(), functionNamesByPriority.end()); - bool wasUnique = (it == functionNamesByPriority.end()); - if (!wasUnique) - return false; - - for (int p : functionNamesByPriority) - { - if (p < 0 || p > 5) - return false; - } - return true; -} - +#include +#include "advanced-scene-switcher.hpp" + +void SceneSwitcher::on_priorityUp_clicked() +{ + int currentIndex = ui->priorityList->currentRow(); + if (currentIndex != -1 && currentIndex != 0) + { + ui->priorityList->insertItem(currentIndex - 1 ,ui->priorityList->takeItem(currentIndex)); + ui->priorityList->setCurrentRow(currentIndex -1); + lock_guard lock(switcher->m); + + iter_swap(switcher->functionNamesByPriority.begin() + currentIndex, switcher->functionNamesByPriority.begin() + currentIndex - 1); + } +} + +void SceneSwitcher::on_priorityDown_clicked() +{ + int currentIndex = ui->priorityList->currentRow(); + if (currentIndex != -1 && currentIndex != ui->priorityList->count() - 1) + { + ui->priorityList->insertItem(currentIndex + 1, ui->priorityList->takeItem(currentIndex)); + ui->priorityList->setCurrentRow(currentIndex + 1); + lock_guard lock(switcher->m); + + iter_swap(switcher->functionNamesByPriority.begin() + currentIndex, switcher->functionNamesByPriority.begin() + currentIndex + 1); + } +} + +bool SwitcherData::prioFuncsValid() +{ + auto it = std::unique(functionNamesByPriority.begin(), functionNamesByPriority.end()); + bool wasUnique = (it == functionNamesByPriority.end()); + if (!wasUnique) + return false; + + for (int p : functionNamesByPriority) + { + if (p < 0 || p > 5) + return false; + } + return true; +} + diff --git a/random.cpp b/random.cpp index 4b1c1a9d..d940ba6c 100644 --- a/random.cpp +++ b/random.cpp @@ -1,143 +1,141 @@ -#include "advanced-scene-switcher.hpp" - -void SceneSwitcher::on_randomScenesList_currentRowChanged(int idx) -{ - if (loading) - return; - if (idx == -1) - return; - - QListWidgetItem* item = ui->randomScenesList->item(idx); - - QString randomSceneStr = item->data(Qt::UserRole).toString(); - - lock_guard lock(switcher->m); - for (auto& s : switcher->randomSwitches) - { - if (randomSceneStr.compare(s.randomSwitchStr.c_str()) == 0) - { - QString sceneName = GetWeakSourceName(s.scene).c_str(); - QString transitionName = GetWeakSourceName(s.transition).c_str(); - ui->randomScenes->setCurrentText(sceneName); - ui->randomSpinBox->setValue(s.delay); - ui->randomTransitions->setCurrentText(transitionName); - break; - } - } -} - -int SceneSwitcher::randomFindByData(const QString& randomStr) -{ - int count = ui->randomScenesList->count(); - - for (int i = 0; i < count; i++) - { - QListWidgetItem* item = ui->randomScenesList->item(i); - QString str = item->data(Qt::UserRole).toString(); - - if (str == randomStr) - return i; - } - - return -1; -} - -void SceneSwitcher::on_randomAdd_clicked() -{ - QString sceneName = ui->randomScenes->currentText(); - QString transitionName = ui->randomTransitions->currentText(); - double delay = ui->randomSpinBox->value(); - - - if (sceneName.isEmpty()) - return; - - OBSWeakSource source = GetWeakSourceByQString(sceneName); - OBSWeakSource transition = GetWeakTransitionByQString(transitionName); - - - QString text = MakeRandomSwitchName(sceneName, transitionName, delay); - QVariant v = QVariant::fromValue(text); - - int idx = randomFindByData(text); - - if (idx == -1) - { - lock_guard lock(switcher->m); - switcher->randomSwitches.emplace_back( - source, transition, delay, text.toUtf8().constData()); - - QListWidgetItem* item = new QListWidgetItem(text, ui->randomScenesList); - item->setData(Qt::UserRole, v); - } - else - { - QListWidgetItem* item = ui->randomScenesList->item(idx); - item->setText(text); - - { - lock_guard lock(switcher->m); - for (auto& s : switcher->randomSwitches) - { - if (s.scene == source) - { - s.delay = delay; - s.transition = transition; - s.randomSwitchStr = text.toUtf8().constData();; - break; - } - } - } - - ui->randomScenesList->sortItems(); - } -} - - -void SceneSwitcher::on_randomRemove_clicked() -{ - QListWidgetItem* item = ui->randomScenesList->currentItem(); - if (!item) - return; - - string text = item->data(Qt::UserRole).toString().toUtf8().constData(); - - { - lock_guard lock(switcher->m); - auto& switches = switcher->randomSwitches; - - for (auto it = switches.begin(); it != switches.end(); ++it) - { - auto& s = *it; - - if (s.randomSwitchStr == text) - { - switches.erase(it); - break; - } - } - } - - delete item; -} - - -void SwitcherData::checkRandom(bool& match, OBSWeakSource& scene, OBSWeakSource& transition, int& delay) -{ - if (randomSwitches.size() == 0) - return; - - vector rs (randomSwitches); - std::random_shuffle(rs.begin(), rs.end()); - for (RandomSwitch& r : rs) - { - if (r.scene == lastRandomScene) - continue; - scene = r.scene; - transition = r.transition; - delay = (int)r.delay * 1000; - match = true; - lastRandomScene = r.scene; - break; - } -} +#include "advanced-scene-switcher.hpp" + +void SceneSwitcher::on_randomScenesList_currentRowChanged(int idx) +{ + if (loading) + return; + if (idx == -1) + return; + + QListWidgetItem* item = ui->randomScenesList->item(idx); + + QString randomSceneStr = item->data(Qt::UserRole).toString(); + + lock_guard lock(switcher->m); + for (auto& s : switcher->randomSwitches) + { + if (randomSceneStr.compare(s.randomSwitchStr.c_str()) == 0) + { + QString sceneName = GetWeakSourceName(s.scene).c_str(); + QString transitionName = GetWeakSourceName(s.transition).c_str(); + ui->randomScenes->setCurrentText(sceneName); + ui->randomSpinBox->setValue(s.delay); + ui->randomTransitions->setCurrentText(transitionName); + break; + } + } +} + +int SceneSwitcher::randomFindByData(const QString& randomStr) +{ + int count = ui->randomScenesList->count(); + + for (int i = 0; i < count; i++) + { + QListWidgetItem* item = ui->randomScenesList->item(i); + QString str = item->data(Qt::UserRole).toString(); + + if (str == randomStr) + return i; + } + + return -1; +} + +void SceneSwitcher::on_randomAdd_clicked() +{ + QString sceneName = ui->randomScenes->currentText(); + QString transitionName = ui->randomTransitions->currentText(); + double delay = ui->randomSpinBox->value(); + + + if (sceneName.isEmpty()) + return; + + OBSWeakSource source = GetWeakSourceByQString(sceneName); + OBSWeakSource transition = GetWeakTransitionByQString(transitionName); + + + QString text = MakeRandomSwitchName(sceneName, transitionName, delay); + QVariant v = QVariant::fromValue(text); + + int idx = randomFindByData(text); + + if (idx == -1) + { + lock_guard lock(switcher->m); + switcher->randomSwitches.emplace_back( + source, transition, delay, text.toUtf8().constData()); + + QListWidgetItem* item = new QListWidgetItem(text, ui->randomScenesList); + item->setData(Qt::UserRole, v); + } + else + { + QListWidgetItem* item = ui->randomScenesList->item(idx); + item->setText(text); + + { + lock_guard lock(switcher->m); + for (auto& s : switcher->randomSwitches) + { + if (s.scene == source) + { + s.delay = delay; + s.transition = transition; + s.randomSwitchStr = text.toUtf8().constData();; + break; + } + } + } + + ui->randomScenesList->sortItems(); + } +} + +void SceneSwitcher::on_randomRemove_clicked() +{ + QListWidgetItem* item = ui->randomScenesList->currentItem(); + if (!item) + return; + + string text = item->data(Qt::UserRole).toString().toUtf8().constData(); + + { + lock_guard lock(switcher->m); + auto& switches = switcher->randomSwitches; + + for (auto it = switches.begin(); it != switches.end(); ++it) + { + auto& s = *it; + + if (s.randomSwitchStr == text) + { + switches.erase(it); + break; + } + } + } + + delete item; +} + +void SwitcherData::checkRandom(bool& match, OBSWeakSource& scene, OBSWeakSource& transition, int& delay) +{ + if (randomSwitches.size() == 0) + return; + + vector rs (randomSwitches); + std::random_shuffle(rs.begin(), rs.end()); + for (RandomSwitch& r : rs) + { + if (r.scene == lastRandomScene) + continue; + scene = r.scene; + transition = r.transition; + delay = (int)r.delay * 1000; + match = true; + lastRandomScene = r.scene; + break; + } +} diff --git a/scene-round-trip.cpp b/scene-round-trip.cpp index f13c62b7..a79ea4da 100644 --- a/scene-round-trip.cpp +++ b/scene-round-trip.cpp @@ -1,309 +1,305 @@ -#include -#include -#include - -#include "advanced-scene-switcher.hpp" - -obs_weak_source_t* getNextTransition(obs_weak_source_t* scene1, obs_weak_source_t* scene2); - -void SceneSwitcher::on_sceneRoundTripAdd_clicked() -{ - QString scene1Name = ui->sceneRoundTripScenes1->currentText(); - QString scene2Name = ui->sceneRoundTripScenes2->currentText(); - QString transitionName = ui->sceneRoundTripTransitions->currentText(); - - if (scene1Name.isEmpty() || scene2Name.isEmpty()) - return; - - double delay = ui->sceneRoundTripSpinBox->value(); - - if (scene1Name == scene2Name) - return; - - OBSWeakSource source1 = GetWeakSourceByQString(scene1Name); - OBSWeakSource source2 = GetWeakSourceByQString(scene2Name); - OBSWeakSource transition = GetWeakTransitionByQString(transitionName); - - QString text = MakeSceneRoundTripSwitchName(scene1Name, scene2Name, transitionName, delay); - QVariant v = QVariant::fromValue(text); - - int idx = SceneRoundTripFindByData(scene1Name); - - if (idx == -1) - { - QListWidgetItem* item = new QListWidgetItem(text, ui->sceneRoundTrips); - item->setData(Qt::UserRole, v); - - lock_guard lock(switcher->m); - switcher->sceneRoundTripSwitches.emplace_back( - source1, source2, transition, int(delay * 1000), text.toUtf8().constData()); - } - else - { - QListWidgetItem* item = ui->sceneRoundTrips->item(idx); - item->setText(text); - - { - lock_guard lock(switcher->m); - for (auto& s : switcher->sceneRoundTripSwitches) - { - if (s.scene1 == source1) - { - s.scene2 = source2; - s.delay = int(delay * 1000); - s.transition = transition; - s.sceneRoundTripStr = text.toUtf8().constData(); - break; - } - } - } - - ui->sceneRoundTrips->sortItems(); - } -} - -void SceneSwitcher::on_sceneRoundTripRemove_clicked() -{ - QListWidgetItem* item = ui->sceneRoundTrips->currentItem(); - if (!item) - return; - - string text = item->data(Qt::UserRole).toString().toUtf8().constData(); - - { - lock_guard lock(switcher->m); - auto& switches = switcher->sceneRoundTripSwitches; - - for (auto it = switches.begin(); it != switches.end(); ++it) - { - auto& s = *it; - - if (s.sceneRoundTripStr == text) - { - switches.erase(it); - break; - } - } - } - - delete item; -} - -void SceneSwitcher::on_autoStopSceneCheckBox_stateChanged(int state) -{ - if (loading) - return; - - lock_guard lock(switcher->m); - if (!state) - { - ui->autoStopScenes->setDisabled(true); - switcher->autoStopEnable = false; - } - else - { - ui->autoStopScenes->setDisabled(false); - switcher->autoStopEnable = true; - } -} - -void SceneSwitcher::UpdateAutoStopScene(const QString& name) -{ - obs_source_t* scene = obs_get_source_by_name(name.toUtf8().constData()); - obs_weak_source_t* ws = obs_source_get_weak_source(scene); - - switcher->autoStopScene = ws; - - obs_weak_source_release(ws); - obs_source_release(scene); -} - -void SceneSwitcher::on_autoStopScenes_currentTextChanged(const QString& text) -{ - if (loading) - return; - - lock_guard lock(switcher->m); - UpdateAutoStopScene(text); -} - -void SceneSwitcher::on_sceneRoundTripSave_clicked() -{ - QString directory = QFileDialog::getSaveFileName( - this, tr("Save Scene Round Trip to file ..."), QDir::currentPath(), tr("Text files (*.txt)")); - if (!directory.isEmpty()) - { - QFile file(directory); - if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) - return; - QTextStream out(&file); - for (SceneRoundTripSwitch s : switcher->sceneRoundTripSwitches) - { - out << QString::fromStdString(GetWeakSourceName(s.scene1)) << "\n"; - out << QString::fromStdString(GetWeakSourceName(s.scene2)) << "\n"; - out << s.delay << "\n"; - out << QString::fromStdString(s.sceneRoundTripStr) << "\n"; - out << QString::fromStdString(GetWeakSourceName(s.transition)) << "\n"; - } - } -} - -void SceneSwitcher::on_sceneRoundTripLoad_clicked() -{ - lock_guard lock(switcher->m); - - QString directory = QFileDialog::getOpenFileName( - this, tr("Select a file to read Scene Round Trip from ..."), QDir::currentPath(), tr("Text files (*.txt)")); - if (!directory.isEmpty()) - { - QFile file(directory); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) - return; - - QTextStream in(&file); - vector lines; - - vector newSceneRoundTripSwitch; - - while (!in.atEnd()) - { - QString line = in.readLine(); - lines.push_back(line); - if (lines.size() == 5) - { - OBSWeakSource scene1 = GetWeakSourceByQString(lines[0]); - OBSWeakSource scene2 = GetWeakSourceByQString(lines[1]); - OBSWeakSource transition = GetWeakTransitionByQString(lines[4]); - - if (WeakSourceValid(scene1) && WeakSourceValid(scene2) - && WeakSourceValid(transition)) - { - newSceneRoundTripSwitch.emplace_back(SceneRoundTripSwitch( - GetWeakSourceByQString(lines[0]), - GetWeakSourceByQString(lines[1]), - GetWeakTransitionByQString(lines[4]), - lines[2].toInt(), - lines[3].toStdString())); - } - lines.clear(); - } - } - //unvalid amount of lines in file or nothing valid read - if (lines.size() != 0 || newSceneRoundTripSwitch.size() == 0) - return; - - switcher->sceneRoundTripSwitches.clear(); - ui->sceneRoundTrips->clear(); - switcher->sceneRoundTripSwitches = newSceneRoundTripSwitch; - for (SceneRoundTripSwitch s : switcher->sceneRoundTripSwitches) - { - QListWidgetItem* item = new QListWidgetItem(QString::fromStdString(s.sceneRoundTripStr), ui->sceneRoundTrips); - item->setData(Qt::UserRole, QString::fromStdString(s.sceneRoundTripStr)); - } - } -} - - -void SwitcherData::checkSceneRoundTrip(bool& match, OBSWeakSource& scene, OBSWeakSource& transition, 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; - int dur = s.delay - interval; - if (dur > 0) - { - string s = obs_source_get_name(currentSource); - waitSceneName = s; - cv.wait_for(lock, chrono::milliseconds(dur)); - } - obs_source_t* currentSource2 = obs_frontend_get_current_scene(); - - // only switch if user hasn't changed scene manually - if (currentSource == currentSource2) - { - match = true; - scene = s.scene2; - transition = s.transition; - } - obs_source_release(currentSource2); - break; - } - } - obs_source_release(currentSource); - obs_weak_source_release(ws); -} - -void SceneSwitcher::on_sceneRoundTrips_currentRowChanged(int idx) -{ - if (loading) - return; - if (idx == -1) - return; - - QListWidgetItem* item = ui->sceneRoundTrips->item(idx); - - QString sceneRoundTrip = item->text(); - - lock_guard lock(switcher->m); - for (auto& s : switcher->sceneRoundTripSwitches) - { - if (sceneRoundTrip.compare(s.sceneRoundTripStr.c_str()) == 0) - { - string scene1 = GetWeakSourceName(s.scene1); - string scene2 = GetWeakSourceName(s.scene2); - string transitionName = GetWeakSourceName(s.transition); - int delay = s.delay; - ui->sceneRoundTripScenes1->setCurrentText(scene1.c_str()); - ui->sceneRoundTripScenes2->setCurrentText(scene2.c_str()); - ui->sceneRoundTripTransitions->setCurrentText(transitionName.c_str()); - ui->sceneRoundTripSpinBox->setValue((double)delay/1000); - break; - } - } -} - - -int SceneSwitcher::SceneRoundTripFindByData(const QString& scene1) -{ - QRegExp rx(scene1 + " ->.*"); - int count = ui->sceneRoundTrips->count(); - int idx = -1; - - for (int i = 0; i < count; i++) - { - QListWidgetItem* item = ui->sceneRoundTrips->item(i); - QString itemString = item->data(Qt::UserRole).toString(); - - if (rx.exactMatch(itemString)) - { - idx = i; - break; - } - } - - return idx; -} - - -void SwitcherData::autoStopStreamAndRecording() -{ - obs_source_t* currentSource = obs_frontend_get_current_scene(); - obs_weak_source_t* ws = obs_source_get_weak_source(currentSource); - - if (ws && autoStopScene == ws) - { - if (obs_frontend_streaming_active()) - obs_frontend_streaming_stop(); - if (obs_frontend_recording_active()) - obs_frontend_recording_stop(); - } - obs_source_release(currentSource); - obs_weak_source_release(ws); -} - +#include +#include +#include + +#include "advanced-scene-switcher.hpp" + +void SceneSwitcher::on_sceneRoundTripAdd_clicked() +{ + QString scene1Name = ui->sceneRoundTripScenes1->currentText(); + QString scene2Name = ui->sceneRoundTripScenes2->currentText(); + QString transitionName = ui->sceneRoundTripTransitions->currentText(); + + if (scene1Name.isEmpty() || scene2Name.isEmpty()) + return; + + double delay = ui->sceneRoundTripSpinBox->value(); + + if (scene1Name == scene2Name) + return; + + OBSWeakSource source1 = GetWeakSourceByQString(scene1Name); + OBSWeakSource source2 = GetWeakSourceByQString(scene2Name); + OBSWeakSource transition = GetWeakTransitionByQString(transitionName); + + QString text = MakeSceneRoundTripSwitchName(scene1Name, scene2Name, transitionName, delay); + QVariant v = QVariant::fromValue(text); + + int idx = SceneRoundTripFindByData(scene1Name); + + if (idx == -1) + { + QListWidgetItem* item = new QListWidgetItem(text, ui->sceneRoundTrips); + item->setData(Qt::UserRole, v); + + lock_guard lock(switcher->m); + switcher->sceneRoundTripSwitches.emplace_back( + source1, source2, transition, int(delay * 1000), text.toUtf8().constData()); + } + else + { + QListWidgetItem* item = ui->sceneRoundTrips->item(idx); + item->setText(text); + + { + lock_guard lock(switcher->m); + for (auto& s : switcher->sceneRoundTripSwitches) + { + if (s.scene1 == source1) + { + s.scene2 = source2; + s.delay = int(delay * 1000); + s.transition = transition; + s.sceneRoundTripStr = text.toUtf8().constData(); + break; + } + } + } + + ui->sceneRoundTrips->sortItems(); + } +} + +void SceneSwitcher::on_sceneRoundTripRemove_clicked() +{ + QListWidgetItem* item = ui->sceneRoundTrips->currentItem(); + if (!item) + return; + + string text = item->data(Qt::UserRole).toString().toUtf8().constData(); + + { + lock_guard lock(switcher->m); + auto& switches = switcher->sceneRoundTripSwitches; + + for (auto it = switches.begin(); it != switches.end(); ++it) + { + auto& s = *it; + + if (s.sceneRoundTripStr == text) + { + switches.erase(it); + break; + } + } + } + + delete item; +} + +void SceneSwitcher::on_autoStopSceneCheckBox_stateChanged(int state) +{ + if (loading) + return; + + lock_guard lock(switcher->m); + if (!state) + { + ui->autoStopScenes->setDisabled(true); + switcher->autoStopEnable = false; + } + else + { + ui->autoStopScenes->setDisabled(false); + switcher->autoStopEnable = true; + } +} + +void SceneSwitcher::UpdateAutoStopScene(const QString& name) +{ + obs_source_t* scene = obs_get_source_by_name(name.toUtf8().constData()); + obs_weak_source_t* ws = obs_source_get_weak_source(scene); + + switcher->autoStopScene = ws; + + obs_weak_source_release(ws); + obs_source_release(scene); +} + +void SceneSwitcher::on_autoStopScenes_currentTextChanged(const QString& text) +{ + if (loading) + return; + + lock_guard lock(switcher->m); + UpdateAutoStopScene(text); +} + +void SceneSwitcher::on_sceneRoundTripSave_clicked() +{ + QString directory = QFileDialog::getSaveFileName( + this, tr("Save Scene Round Trip to file ..."), QDir::currentPath(), tr("Text files (*.txt)")); + if (!directory.isEmpty()) + { + QFile file(directory); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) + return; + QTextStream out(&file); + for (SceneRoundTripSwitch s : switcher->sceneRoundTripSwitches) + { + out << QString::fromStdString(GetWeakSourceName(s.scene1)) << "\n"; + out << QString::fromStdString(GetWeakSourceName(s.scene2)) << "\n"; + out << s.delay << "\n"; + out << QString::fromStdString(s.sceneRoundTripStr) << "\n"; + out << QString::fromStdString(GetWeakSourceName(s.transition)) << "\n"; + } + } +} + +void SceneSwitcher::on_sceneRoundTripLoad_clicked() +{ + lock_guard lock(switcher->m); + + QString directory = QFileDialog::getOpenFileName( + this, tr("Select a file to read Scene Round Trip from ..."), QDir::currentPath(), tr("Text files (*.txt)")); + if (!directory.isEmpty()) + { + QFile file(directory); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + return; + + QTextStream in(&file); + vector lines; + + vector newSceneRoundTripSwitch; + + while (!in.atEnd()) + { + QString line = in.readLine(); + lines.push_back(line); + if (lines.size() == 5) + { + OBSWeakSource scene1 = GetWeakSourceByQString(lines[0]); + OBSWeakSource scene2 = GetWeakSourceByQString(lines[1]); + OBSWeakSource transition = GetWeakTransitionByQString(lines[4]); + + if (WeakSourceValid(scene1) && WeakSourceValid(scene2) + && WeakSourceValid(transition)) + { + newSceneRoundTripSwitch.emplace_back(SceneRoundTripSwitch( + GetWeakSourceByQString(lines[0]), + GetWeakSourceByQString(lines[1]), + GetWeakTransitionByQString(lines[4]), + lines[2].toInt(), + lines[3].toStdString())); + } + lines.clear(); + } + } + + if (lines.size() != 0 || newSceneRoundTripSwitch.size() == 0) + return; + + switcher->sceneRoundTripSwitches.clear(); + ui->sceneRoundTrips->clear(); + switcher->sceneRoundTripSwitches = newSceneRoundTripSwitch; + for (SceneRoundTripSwitch s : switcher->sceneRoundTripSwitches) + { + QListWidgetItem* item = new QListWidgetItem(QString::fromStdString(s.sceneRoundTripStr), ui->sceneRoundTrips); + item->setData(Qt::UserRole, QString::fromStdString(s.sceneRoundTripStr)); + } + } +} + + +void SwitcherData::checkSceneRoundTrip(bool& match, OBSWeakSource& scene, OBSWeakSource& transition, 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; + int dur = s.delay - interval; + if (dur > 0) + { + waitScene = currentSource; + cv.wait_for(lock, chrono::milliseconds(dur)); + } + obs_source_t* currentSource2 = obs_frontend_get_current_scene(); + + // only switch if user hasn't changed scene manually + if (currentSource == currentSource2) + { + match = true; + scene = s.scene2; + transition = s.transition; + } + obs_source_release(currentSource2); + break; + } + } + obs_source_release(currentSource); + obs_weak_source_release(ws); +} + +void SceneSwitcher::on_sceneRoundTrips_currentRowChanged(int idx) +{ + if (loading) + return; + if (idx == -1) + return; + + QListWidgetItem* item = ui->sceneRoundTrips->item(idx); + + QString sceneRoundTrip = item->text(); + + lock_guard lock(switcher->m); + for (auto& s : switcher->sceneRoundTripSwitches) + { + if (sceneRoundTrip.compare(s.sceneRoundTripStr.c_str()) == 0) + { + string scene1 = GetWeakSourceName(s.scene1); + string scene2 = GetWeakSourceName(s.scene2); + string transitionName = GetWeakSourceName(s.transition); + int delay = s.delay; + ui->sceneRoundTripScenes1->setCurrentText(scene1.c_str()); + ui->sceneRoundTripScenes2->setCurrentText(scene2.c_str()); + ui->sceneRoundTripTransitions->setCurrentText(transitionName.c_str()); + ui->sceneRoundTripSpinBox->setValue((double)delay/1000); + break; + } + } +} + + +int SceneSwitcher::SceneRoundTripFindByData(const QString& scene1) +{ + QRegExp rx(scene1 + " ->.*"); + int count = ui->sceneRoundTrips->count(); + int idx = -1; + + for (int i = 0; i < count; i++) + { + QListWidgetItem* item = ui->sceneRoundTrips->item(i); + QString itemString = item->data(Qt::UserRole).toString(); + + if (rx.exactMatch(itemString)) + { + idx = i; + break; + } + } + + return idx; +} + + +void SwitcherData::autoStopStreamAndRecording() +{ + obs_source_t* currentSource = obs_frontend_get_current_scene(); + obs_weak_source_t* ws = obs_source_get_weak_source(currentSource); + + if (ws && autoStopScene == ws) + { + if (obs_frontend_streaming_active()) + obs_frontend_streaming_stop(); + if (obs_frontend_recording_active()) + obs_frontend_recording_stop(); + } + obs_source_release(currentSource); + obs_weak_source_release(ws); +} diff --git a/scene-transitions.cpp b/scene-transitions.cpp index 37fcb99b..b9dd4016 100644 --- a/scene-transitions.cpp +++ b/scene-transitions.cpp @@ -1,283 +1,284 @@ -#include "advanced-scene-switcher.hpp" - -void SceneSwitcher::on_transitionsAdd_clicked() -{ - QString scene1Name = ui->transitionsScene1->currentText(); - QString scene2Name = ui->transitionsScene2->currentText(); - QString transitionName = ui->transitionsTransitions->currentText(); - - if (scene1Name.isEmpty() || scene2Name.isEmpty()) - return; - - if (scene1Name == scene2Name) - return; - - OBSWeakSource source1 = GetWeakSourceByQString(scene1Name); - OBSWeakSource source2 = GetWeakSourceByQString(scene2Name); - OBSWeakSource transition = GetWeakTransitionByQString(transitionName); - - QString text = MakeSceneTransitionName(scene1Name, scene2Name, transitionName); - QVariant v = QVariant::fromValue(text); - - int idx = SceneTransitionsFindByData(scene1Name, scene2Name); - - if (idx == -1) - { - QListWidgetItem* item = new QListWidgetItem(text, ui->sceneTransitions); - item->setData(Qt::UserRole, v); - - lock_guard lock(switcher->m); - switcher->sceneTransitions.emplace_back( - source1, source2, transition, text.toUtf8().constData()); - } - else - { - QListWidgetItem* item = ui->sceneTransitions->item(idx); - item->setText(text); - - { - lock_guard lock(switcher->m); - for (auto& s : switcher->sceneTransitions) - { - if (s.scene1 == source1 && s.scene2 == source2) - { - s.transition = transition; - s.sceneTransitionStr = text.toUtf8().constData(); - break; - } - } - } - - ui->sceneTransitions->sortItems(); - } -} - -void SceneSwitcher::on_transitionsRemove_clicked() -{ - QListWidgetItem* item = ui->sceneTransitions->currentItem(); - if (!item) - return; - - string text = item->data(Qt::UserRole).toString().toUtf8().constData(); - - { - lock_guard lock(switcher->m); - auto& switches = switcher->sceneTransitions; - - for (auto it = switches.begin(); it != switches.end(); ++it) - { - auto& s = *it; - - if (s.sceneTransitionStr == text) - { - switches.erase(it); - break; - } - } - } - - delete item; -} - -void SceneSwitcher::on_defaultTransitionsAdd_clicked() -{ - QString sceneName = ui->defaultTransitionsScene->currentText(); - QString transitionName = ui->defaultTransitionsTransitions->currentText(); - - if (sceneName.isEmpty() || transitionName.isEmpty()) - return; - - OBSWeakSource source = GetWeakSourceByQString(sceneName); - OBSWeakSource transition = GetWeakTransitionByQString(transitionName); - - QString text = MakeDefaultSceneTransitionName(sceneName, transitionName); - QVariant v = QVariant::fromValue(text); - - int idx = DefaultTransitionsFindByData(sceneName); - - if (idx == -1) - { - QListWidgetItem* item = new QListWidgetItem(text, ui->defaultTransitions); - item->setData(Qt::UserRole, v); - - lock_guard lock(switcher->m); - switcher->defaultSceneTransitions.emplace_back( - source, transition, text.toUtf8().constData()); - } - else - { - QListWidgetItem* item = ui->defaultTransitions->item(idx); - item->setText(text); - - { - lock_guard lock(switcher->m); - for (auto& s : switcher->defaultSceneTransitions) - { - if (s.scene == source) - { - s.transition = transition; - s.sceneTransitionStr = text.toUtf8().constData(); - break; - } - } - } - - ui->defaultTransitions->sortItems(); - } -} - -void SceneSwitcher::on_defaultTransitionsRemove_clicked() -{ - QListWidgetItem* item = ui->defaultTransitions->currentItem(); - if (!item) - return; - - string text = item->data(Qt::UserRole).toString().toUtf8().constData(); - - { - lock_guard lock(switcher->m); - auto& switches = switcher->defaultSceneTransitions; - - for (auto it = switches.begin(); it != switches.end(); ++it) - { - auto& s = *it; - - if (s.sceneTransitionStr == text) - { - switches.erase(it); - break; - } - } - } - - delete item; -} - -void SwitcherData::setDefaultSceneTransitions(unique_lock& lock) -{ - obs_source_t* currentSource = obs_frontend_get_current_scene(); - obs_weak_source_t* ws = obs_source_get_weak_source(currentSource); - - for (DefaultSceneTransition& s : defaultSceneTransitions) - { - if (s.scene == ws) - { - obs_source_t* transition = obs_weak_source_get_source(s.transition); - //sleep planned but no fitting OBS event to measure transition time - obs_frontend_set_current_transition(transition); - obs_source_release(transition); - break; - } - } - obs_source_release(currentSource); - obs_weak_source_release(ws); -} - -int SceneSwitcher::SceneTransitionsFindByData(const QString& scene1, const QString& scene2) -{ - QRegExp rx(scene1 + " --- .* --> " + scene2); - int count = ui->sceneTransitions->count(); - int idx = -1; - - for (int i = 0; i < count; i++) - { - QListWidgetItem* item = ui->sceneTransitions->item(i); - QString itemString = item->data(Qt::UserRole).toString(); - - if (rx.exactMatch(itemString)) - { - idx = i; - break; - } - } - - return idx; -} - -int SceneSwitcher::DefaultTransitionsFindByData(const QString& scene) -{ - QRegExp rx(scene + " --> .*"); - int count = ui->defaultTransitions->count(); - int idx = -1; - - for (int i = 0; i < count; i++) - { - QListWidgetItem* item = ui->defaultTransitions->item(i); - QString itemString = item->data(Qt::UserRole).toString(); - - if (rx.exactMatch(itemString)) - { - idx = i; - break; - } - } - - return idx; -} - -void SceneSwitcher::on_sceneTransitions_currentRowChanged(int idx) -{ - if (loading) - return; - if (idx == -1) - return; - - QListWidgetItem* item = ui->sceneTransitions->item(idx); - - QString sceneTransition = item->data(Qt::UserRole).toString(); - - lock_guard lock(switcher->m); - for (auto& s : switcher->sceneTransitions) - { - if (sceneTransition.compare(s.sceneTransitionStr.c_str()) == 0) - { - string scene1 = GetWeakSourceName(s.scene1); - string scene2 = GetWeakSourceName(s.scene2); - string transitionName = GetWeakSourceName(s.transition); - ui->transitionsScene1->setCurrentText(scene1.c_str()); - ui->transitionsScene2->setCurrentText(scene2.c_str()); - ui->transitionsTransitions->setCurrentText(transitionName.c_str()); - break; - } - } -} - -void SceneSwitcher::on_defaultTransitions_currentRowChanged(int idx) -{ - if (loading) - return; - if (idx == -1) - return; - - QListWidgetItem* item = ui->defaultTransitions->item(idx); - - QString sceneTransition = item->data(Qt::UserRole).toString(); - - lock_guard lock(switcher->m); - for (auto& s : switcher->defaultSceneTransitions) - { - if (sceneTransition.compare(s.sceneTransitionStr.c_str()) == 0) - { - string scene = GetWeakSourceName(s.scene); - string transitionName = GetWeakSourceName(s.transition); - ui->defaultTransitionsScene->setCurrentText(scene.c_str()); - ui->defaultTransitionsTransitions->setCurrentText(transitionName.c_str()); - break; - } - } -} - -obs_weak_source_t* getNextTransition(obs_weak_source_t* scene1, obs_weak_source_t* scene2) -{ - obs_weak_source_t* ws = nullptr; - if (scene1 && scene2) - { - for (SceneTransition& t : switcher->sceneTransitions) - { - if (t.scene1 == scene1 && t.scene2 == scene2) - ws = t.transition; - } - obs_weak_source_addref(ws); - } - return ws; -} +#include "advanced-scene-switcher.hpp" + +void SceneSwitcher::on_transitionsAdd_clicked() +{ + QString scene1Name = ui->transitionsScene1->currentText(); + QString scene2Name = ui->transitionsScene2->currentText(); + QString transitionName = ui->transitionsTransitions->currentText(); + + if (scene1Name.isEmpty() || scene2Name.isEmpty()) + return; + + if (scene1Name == scene2Name) + return; + + OBSWeakSource source1 = GetWeakSourceByQString(scene1Name); + OBSWeakSource source2 = GetWeakSourceByQString(scene2Name); + OBSWeakSource transition = GetWeakTransitionByQString(transitionName); + + QString text = MakeSceneTransitionName(scene1Name, scene2Name, transitionName); + QVariant v = QVariant::fromValue(text); + + int idx = SceneTransitionsFindByData(scene1Name, scene2Name); + + if (idx == -1) + { + QListWidgetItem* item = new QListWidgetItem(text, ui->sceneTransitions); + item->setData(Qt::UserRole, v); + + lock_guard lock(switcher->m); + switcher->sceneTransitions.emplace_back( + source1, source2, transition, text.toUtf8().constData()); + } + else + { + QListWidgetItem* item = ui->sceneTransitions->item(idx); + item->setText(text); + + { + lock_guard lock(switcher->m); + for (auto& s : switcher->sceneTransitions) + { + if (s.scene1 == source1 && s.scene2 == source2) + { + s.transition = transition; + s.sceneTransitionStr = text.toUtf8().constData(); + break; + } + } + } + + ui->sceneTransitions->sortItems(); + } +} + +void SceneSwitcher::on_transitionsRemove_clicked() +{ + QListWidgetItem* item = ui->sceneTransitions->currentItem(); + if (!item) + return; + + string text = item->data(Qt::UserRole).toString().toUtf8().constData(); + + { + lock_guard lock(switcher->m); + auto& switches = switcher->sceneTransitions; + + for (auto it = switches.begin(); it != switches.end(); ++it) + { + auto& s = *it; + + if (s.sceneTransitionStr == text) + { + switches.erase(it); + break; + } + } + } + + delete item; +} + +void SceneSwitcher::on_defaultTransitionsAdd_clicked() +{ + QString sceneName = ui->defaultTransitionsScene->currentText(); + QString transitionName = ui->defaultTransitionsTransitions->currentText(); + + if (sceneName.isEmpty() || transitionName.isEmpty()) + return; + + OBSWeakSource source = GetWeakSourceByQString(sceneName); + OBSWeakSource transition = GetWeakTransitionByQString(transitionName); + + QString text = MakeDefaultSceneTransitionName(sceneName, transitionName); + QVariant v = QVariant::fromValue(text); + + int idx = DefaultTransitionsFindByData(sceneName); + + if (idx == -1) + { + QListWidgetItem* item = new QListWidgetItem(text, ui->defaultTransitions); + item->setData(Qt::UserRole, v); + + lock_guard lock(switcher->m); + switcher->defaultSceneTransitions.emplace_back( + source, transition, text.toUtf8().constData()); + } + else + { + QListWidgetItem* item = ui->defaultTransitions->item(idx); + item->setText(text); + + { + lock_guard lock(switcher->m); + for (auto& s : switcher->defaultSceneTransitions) + { + if (s.scene == source) + { + s.transition = transition; + s.sceneTransitionStr = text.toUtf8().constData(); + break; + } + } + } + + ui->defaultTransitions->sortItems(); + } +} + +void SceneSwitcher::on_defaultTransitionsRemove_clicked() +{ + QListWidgetItem* item = ui->defaultTransitions->currentItem(); + if (!item) + return; + + string text = item->data(Qt::UserRole).toString().toUtf8().constData(); + + { + lock_guard lock(switcher->m); + auto& switches = switcher->defaultSceneTransitions; + + for (auto it = switches.begin(); it != switches.end(); ++it) + { + auto& s = *it; + + if (s.sceneTransitionStr == text) + { + switches.erase(it); + break; + } + } + } + + delete item; +} + +void SwitcherData::setDefaultSceneTransitions(unique_lock& lock) +{ + obs_source_t* currentSource = obs_frontend_get_current_scene(); + obs_weak_source_t* ws = obs_source_get_weak_source(currentSource); + + for (DefaultSceneTransition& s : defaultSceneTransitions) + { + if (s.scene == ws) + { + obs_source_t* transition = obs_weak_source_get_source(s.transition); + //This might cancel the current transition + //There is no way to be sure when the previous transition finished + obs_frontend_set_current_transition(transition); + obs_source_release(transition); + break; + } + } + obs_source_release(currentSource); + obs_weak_source_release(ws); +} + +int SceneSwitcher::SceneTransitionsFindByData(const QString& scene1, const QString& scene2) +{ + QRegExp rx(scene1 + " --- .* --> " + scene2); + int count = ui->sceneTransitions->count(); + int idx = -1; + + for (int i = 0; i < count; i++) + { + QListWidgetItem* item = ui->sceneTransitions->item(i); + QString itemString = item->data(Qt::UserRole).toString(); + + if (rx.exactMatch(itemString)) + { + idx = i; + break; + } + } + + return idx; +} + +int SceneSwitcher::DefaultTransitionsFindByData(const QString& scene) +{ + QRegExp rx(scene + " --> .*"); + int count = ui->defaultTransitions->count(); + int idx = -1; + + for (int i = 0; i < count; i++) + { + QListWidgetItem* item = ui->defaultTransitions->item(i); + QString itemString = item->data(Qt::UserRole).toString(); + + if (rx.exactMatch(itemString)) + { + idx = i; + break; + } + } + + return idx; +} + +void SceneSwitcher::on_sceneTransitions_currentRowChanged(int idx) +{ + if (loading) + return; + if (idx == -1) + return; + + QListWidgetItem* item = ui->sceneTransitions->item(idx); + + QString sceneTransition = item->data(Qt::UserRole).toString(); + + lock_guard lock(switcher->m); + for (auto& s : switcher->sceneTransitions) + { + if (sceneTransition.compare(s.sceneTransitionStr.c_str()) == 0) + { + string scene1 = GetWeakSourceName(s.scene1); + string scene2 = GetWeakSourceName(s.scene2); + string transitionName = GetWeakSourceName(s.transition); + ui->transitionsScene1->setCurrentText(scene1.c_str()); + ui->transitionsScene2->setCurrentText(scene2.c_str()); + ui->transitionsTransitions->setCurrentText(transitionName.c_str()); + break; + } + } +} + +void SceneSwitcher::on_defaultTransitions_currentRowChanged(int idx) +{ + if (loading) + return; + if (idx == -1) + return; + + QListWidgetItem* item = ui->defaultTransitions->item(idx); + + QString sceneTransition = item->data(Qt::UserRole).toString(); + + lock_guard lock(switcher->m); + for (auto& s : switcher->defaultSceneTransitions) + { + if (sceneTransition.compare(s.sceneTransitionStr.c_str()) == 0) + { + string scene = GetWeakSourceName(s.scene); + string transitionName = GetWeakSourceName(s.transition); + ui->defaultTransitionsScene->setCurrentText(scene.c_str()); + ui->defaultTransitionsTransitions->setCurrentText(transitionName.c_str()); + break; + } + } +} + +obs_weak_source_t* getNextTransition(obs_weak_source_t* scene1, obs_weak_source_t* scene2) +{ + obs_weak_source_t* ws = nullptr; + if (scene1 && scene2) + { + for (SceneTransition& t : switcher->sceneTransitions) + { + if (t.scene1 == scene1 && t.scene2 == scene2) + ws = t.transition; + } + obs_weak_source_addref(ws); + } + return ws; +} diff --git a/screen-region-switch.cpp b/screen-region-switch.cpp index 4cff25cf..45d17765 100644 --- a/screen-region-switch.cpp +++ b/screen-region-switch.cpp @@ -1,165 +1,165 @@ -#include "advanced-scene-switcher.hpp" - -void SwitcherData::checkScreenRegionSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition) -{ - pair cursorPos = getCursorPos(); - int minRegionSize = 99999; - - for (auto& s : screenRegionSwitches) - { - if (cursorPos.first >= s.minX && cursorPos.second >= s.minY - && cursorPos.first <= s.maxX && cursorPos.second <= s.maxY) - { - int regionSize = (s.maxX - s.minX) + (s.maxY - s.minY); - if (regionSize < minRegionSize) - { - match = true; - scene = s.scene; - transition = s.transition; - minRegionSize = regionSize; - } - } - } -} - -void SceneSwitcher::updateScreenRegionCursorPos() -{ - pair position = getCursorPos(); - ui->cursorXPosition->setText(QString::number(position.first)); - ; - ui->cursorYPosition->setText(QString::number(position.second)); -} - -void SceneSwitcher::on_screenRegionAdd_clicked() -{ - QString sceneName = ui->screenRegionScenes->currentText(); - QString transitionName = ui->screenRegionsTransitions->currentText(); - - if (sceneName.isEmpty()) - return; - - int minX = ui->screenRegionMinX->value(); - int minY = ui->screenRegionMinY->value(); - int maxX = ui->screenRegionMaxX->value(); - int maxY = ui->screenRegionMaxY->value(); - - string regionStr = to_string(minX) + ", " + to_string(minY) + " x " + to_string(maxX) + ", " - + to_string(maxY); - QString region = QString::fromStdString(regionStr); - - OBSWeakSource source = GetWeakSourceByQString(sceneName); - OBSWeakSource transition = GetWeakTransitionByQString(transitionName); - QVariant v = QVariant::fromValue(region); - - QString text = MakeScreenRegionSwitchName(sceneName, transitionName, minX, minY, maxX, maxY); - - int idx = ScreenRegionFindByData(region); - - if (idx == -1) - { - QListWidgetItem* item = new QListWidgetItem(text, ui->screenRegions); - item->setData(Qt::UserRole, v); - - lock_guard lock(switcher->m); - switcher->screenRegionSwitches.emplace_back( - source, transition, minX, minY, maxX, maxY, regionStr); - } - else - { - QListWidgetItem* item = ui->screenRegions->item(idx); - item->setText(text); - - string curRegion = region.toUtf8().constData(); - - { - lock_guard lock(switcher->m); - for (auto& s : switcher->screenRegionSwitches) - { - if (s.regionStr == curRegion) - { - s.scene = source; - s.transition = transition; - break; - } - } - } - - ui->screenRegions->sortItems(); - } -} - -void SceneSwitcher::on_screenRegionRemove_clicked() -{ - QListWidgetItem* item = ui->screenRegions->currentItem(); - if (!item) - return; - - string region = item->data(Qt::UserRole).toString().toUtf8().constData(); - - { - lock_guard lock(switcher->m); - auto& switches = switcher->screenRegionSwitches; - - for (auto it = switches.begin(); it != switches.end(); ++it) - { - auto& s = *it; - - if (s.regionStr == region) - { - switches.erase(it); - break; - } - } - } - - delete item; -} - -void SceneSwitcher::on_screenRegions_currentRowChanged(int idx) -{ - if (loading) - return; - if (idx == -1) - return; - - QListWidgetItem* item = ui->screenRegions->item(idx); - - QString region = item->data(Qt::UserRole).toString(); - - lock_guard lock(switcher->m); - for (auto& s : switcher->screenRegionSwitches) - { - if (region.compare(s.regionStr.c_str()) == 0) - { - string name = GetWeakSourceName(s.scene); - string transitionName = GetWeakSourceName(s.transition); - ui->screenRegionScenes->setCurrentText(name.c_str()); - ui->screenRegionsTransitions->setCurrentText(transitionName.c_str()); - ui->screenRegionMinX->setValue(s.minX); - ui->screenRegionMinY->setValue(s.minY); - ui->screenRegionMaxX->setValue(s.maxX); - ui->screenRegionMaxY->setValue(s.maxY); - break; - } - } -} - -int SceneSwitcher::ScreenRegionFindByData(const QString& region) -{ - int count = ui->screenRegions->count(); - int idx = -1; - - for (int i = 0; i < count; i++) - { - QListWidgetItem* item = ui->screenRegions->item(i); - QString itemRegion = item->data(Qt::UserRole).toString(); - - if (itemRegion == region) - { - idx = i; - break; - } - } - - return idx; -} +#include "advanced-scene-switcher.hpp" + +void SwitcherData::checkScreenRegionSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition) +{ + pair cursorPos = getCursorPos(); + int minRegionSize = 99999; + + for (auto& s : screenRegionSwitches) + { + if (cursorPos.first >= s.minX && cursorPos.second >= s.minY + && cursorPos.first <= s.maxX && cursorPos.second <= s.maxY) + { + int regionSize = (s.maxX - s.minX) + (s.maxY - s.minY); + if (regionSize < minRegionSize) + { + match = true; + scene = s.scene; + transition = s.transition; + minRegionSize = regionSize; + } + } + } +} + +void SceneSwitcher::updateScreenRegionCursorPos() +{ + pair position = getCursorPos(); + ui->cursorXPosition->setText(QString::number(position.first)); + ; + ui->cursorYPosition->setText(QString::number(position.second)); +} + +void SceneSwitcher::on_screenRegionAdd_clicked() +{ + QString sceneName = ui->screenRegionScenes->currentText(); + QString transitionName = ui->screenRegionsTransitions->currentText(); + + if (sceneName.isEmpty()) + return; + + int minX = ui->screenRegionMinX->value(); + int minY = ui->screenRegionMinY->value(); + int maxX = ui->screenRegionMaxX->value(); + int maxY = ui->screenRegionMaxY->value(); + + string regionStr = to_string(minX) + ", " + to_string(minY) + " x " + to_string(maxX) + ", " + + to_string(maxY); + QString region = QString::fromStdString(regionStr); + + OBSWeakSource source = GetWeakSourceByQString(sceneName); + OBSWeakSource transition = GetWeakTransitionByQString(transitionName); + QVariant v = QVariant::fromValue(region); + + QString text = MakeScreenRegionSwitchName(sceneName, transitionName, minX, minY, maxX, maxY); + + int idx = ScreenRegionFindByData(region); + + if (idx == -1) + { + QListWidgetItem* item = new QListWidgetItem(text, ui->screenRegions); + item->setData(Qt::UserRole, v); + + lock_guard lock(switcher->m); + switcher->screenRegionSwitches.emplace_back( + source, transition, minX, minY, maxX, maxY, regionStr); + } + else + { + QListWidgetItem* item = ui->screenRegions->item(idx); + item->setText(text); + + string curRegion = region.toUtf8().constData(); + + { + lock_guard lock(switcher->m); + for (auto& s : switcher->screenRegionSwitches) + { + if (s.regionStr == curRegion) + { + s.scene = source; + s.transition = transition; + break; + } + } + } + + ui->screenRegions->sortItems(); + } +} + +void SceneSwitcher::on_screenRegionRemove_clicked() +{ + QListWidgetItem* item = ui->screenRegions->currentItem(); + if (!item) + return; + + string region = item->data(Qt::UserRole).toString().toUtf8().constData(); + + { + lock_guard lock(switcher->m); + auto& switches = switcher->screenRegionSwitches; + + for (auto it = switches.begin(); it != switches.end(); ++it) + { + auto& s = *it; + + if (s.regionStr == region) + { + switches.erase(it); + break; + } + } + } + + delete item; +} + +void SceneSwitcher::on_screenRegions_currentRowChanged(int idx) +{ + if (loading) + return; + if (idx == -1) + return; + + QListWidgetItem* item = ui->screenRegions->item(idx); + + QString region = item->data(Qt::UserRole).toString(); + + lock_guard lock(switcher->m); + for (auto& s : switcher->screenRegionSwitches) + { + if (region.compare(s.regionStr.c_str()) == 0) + { + string name = GetWeakSourceName(s.scene); + string transitionName = GetWeakSourceName(s.transition); + ui->screenRegionScenes->setCurrentText(name.c_str()); + ui->screenRegionsTransitions->setCurrentText(transitionName.c_str()); + ui->screenRegionMinX->setValue(s.minX); + ui->screenRegionMinY->setValue(s.minY); + ui->screenRegionMaxX->setValue(s.maxX); + ui->screenRegionMaxY->setValue(s.maxY); + break; + } + } +} + +int SceneSwitcher::ScreenRegionFindByData(const QString& region) +{ + int count = ui->screenRegions->count(); + int idx = -1; + + for (int i = 0; i < count; i++) + { + QListWidgetItem* item = ui->screenRegions->item(i); + QString itemRegion = item->data(Qt::UserRole).toString(); + + if (itemRegion == region) + { + idx = i; + break; + } + } + + return idx; +} diff --git a/switcher-data-structs.hpp b/switcher-data-structs.hpp index 58e4b39f..c3480db9 100644 --- a/switcher-data-structs.hpp +++ b/switcher-data-structs.hpp @@ -1,354 +1,372 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "utility.hpp" - -#define DEFAULT_INTERVAL 300 - -#define DEFAULT_IDLE_TIME 60 - -#define READ_FILE_FUNC 0 -#define ROUND_TRIP_FUNC 1 -#define IDLE_FUNC 2 -#define EXE_FUNC 3 -#define SCREEN_REGION_FUNC 4 -#define WINDOW_TITLE_FUNC 5 - -#define DEFAULT_PRIORITY_0 READ_FILE_FUNC -#define DEFAULT_PRIORITY_1 ROUND_TRIP_FUNC -#define DEFAULT_PRIORITY_2 IDLE_FUNC -#define DEFAULT_PRIORITY_3 EXE_FUNC -#define DEFAULT_PRIORITY_4 SCREEN_REGION_FUNC -#define DEFAULT_PRIORITY_5 WINDOW_TITLE_FUNC - -using namespace std; - -struct SceneSwitch -{ - OBSWeakSource scene; - string window; - OBSWeakSource transition; - bool fullscreen; - - inline SceneSwitch( - OBSWeakSource scene_, const char* window_, OBSWeakSource transition_, bool fullscreen_) - : scene(scene_) - , window(window_) - , transition(transition_) - , fullscreen(fullscreen_) - { - } -}; - -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; - string regionStr; - - inline ScreenRegionSwitch(OBSWeakSource scene_, OBSWeakSource transition_, int minX_, int minY_, - int maxX_, int maxY_, string regionStr_) - : scene(scene_) - , transition(transition_) - , minX(minX_) - , minY(minY_) - , maxX(maxX_) - , maxY(maxY_) - , regionStr(regionStr_) - { - } -}; - -struct SceneRoundTripSwitch -{ - OBSWeakSource scene1; - OBSWeakSource scene2; - OBSWeakSource transition; - int delay; - string sceneRoundTripStr; - - inline SceneRoundTripSwitch(OBSWeakSource scene1_, OBSWeakSource scene2_, - OBSWeakSource transition_, int delay_, string str) - : scene1(scene1_) - , scene2(scene2_) - , transition(transition_) - , delay(delay_) - , sceneRoundTripStr(str) - { - } -}; - -struct RandomSwitch -{ - OBSWeakSource scene; - OBSWeakSource transition; - double delay; - string randomSwitchStr; - - inline RandomSwitch(OBSWeakSource scene_, OBSWeakSource transition_ - , double delay_, string str) - : scene(scene_) - , transition(transition_) - , delay(delay_) - , randomSwitchStr(str) - { - } -}; - -struct SceneTransition -{ - OBSWeakSource scene1; - OBSWeakSource scene2; - OBSWeakSource transition; - string sceneTransitionStr; - - inline SceneTransition(OBSWeakSource scene1_, OBSWeakSource scene2_, OBSWeakSource transition_, - string sceneTransitionStr_) - : scene1(scene1_) - , scene2(scene2_) - , transition(transition_) - , sceneTransitionStr(sceneTransitionStr_) - { - } -}; - -struct DefaultSceneTransition -{ - OBSWeakSource scene; - OBSWeakSource transition; - string sceneTransitionStr; - - inline DefaultSceneTransition(OBSWeakSource scene_, OBSWeakSource transition_, - string sceneTransitionStr_) - : scene(scene_) - , transition(transition_) - , sceneTransitionStr(sceneTransitionStr_) - { - } -}; - -struct FileSwitch -{ - OBSWeakSource scene; - OBSWeakSource transition; - string file; - string text; - bool useRegex = false; - bool useTime = false; - QDateTime lastMod; - - inline FileSwitch( - OBSWeakSource scene_, OBSWeakSource transition_, const char* file_, const char* text_, bool useRegex_, bool useTime_) - : scene(scene_) - , transition(transition_) - , file(file_) - , text(text_) - , useRegex(useRegex_) - , useTime(useTime_) - , lastMod() - { - } -}; - -struct FileIOData -{ - bool readEnabled = false; - string readPath; - bool writeEnabled = false; - string writePath; -}; - -struct IdleData -{ - bool idleEnable = false; - int time = DEFAULT_IDLE_TIME; - OBSWeakSource scene; - OBSWeakSource transition; -}; - -typedef enum { - NO_SWITCH = 0, - SWITCH = 1, - RANDOM_SWITCH = 2 -} NoMatch; - - - -struct SwitcherData -{ - thread th; - condition_variable cv; - mutex m; - bool transitionActive = false; - bool waitForTransition = false; - condition_variable transitionCv; - bool stop = false; - - vector switches; - string lastTitle; - OBSWeakSource nonMatchingScene; - OBSWeakSource lastRandomScene; - int interval = DEFAULT_INTERVAL; - NoMatch switchIfNotMatching = NO_SWITCH; - bool startAtLaunch = false; - vector screenRegionSwitches; - vector pauseScenesSwitches; - vector pauseWindowsSwitches; - vector ignoreWindowsSwitches; - vector sceneRoundTripSwitches; - vector randomSwitches; - vector fileSwitches; - bool autoStopEnable = false; - OBSWeakSource autoStopScene; - string waitSceneName; //indicates which scene was active when we startet waiting on something - vector sceneTransitions; - vector defaultSceneTransitions; - vector executableSwitches; - FileIOData fileIO; - IdleData idleData; - vector ignoreIdleWindows; - vector functionNamesByPriority = vector{ - DEFAULT_PRIORITY_0, - DEFAULT_PRIORITY_1, - DEFAULT_PRIORITY_2, - DEFAULT_PRIORITY_3, - DEFAULT_PRIORITY_4, - DEFAULT_PRIORITY_5, - }; - - void Thread(); - void Start(); - void Stop(); - - bool sceneChangedDuringWait(); - bool prioFuncsValid(); - void writeSceneInfoToFile(); - void setDefaultSceneTransitions(unique_lock& lock); - void autoStopStreamAndRecording(); - bool checkPause(); - void checkSceneRoundTrip(bool& match, OBSWeakSource& scene, OBSWeakSource& transition, unique_lock& lock); - void checkIdleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition); - void checkWindowTitleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition); - void checkExeSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition); - void checkScreenRegionSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition); - void checkSwitchInfoFromFile(bool& match, OBSWeakSource& scene, OBSWeakSource& transition); - void checkFileContent(bool& match, OBSWeakSource& scene, OBSWeakSource& transition); - void checkRandom(bool& match, OBSWeakSource& scene, OBSWeakSource& transition, int& delay); - - - - void Prune() - { - for (size_t i = 0; i < switches.size(); i++) - { - SceneSwitch& s = switches[i]; - if (!WeakSourceValid(s.scene) || !WeakSourceValid(s.transition)) - switches.erase(switches.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) || !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--); - } - - if (!WeakSourceValid(idleData.scene) || !WeakSourceValid(idleData.transition)) - { - idleData.idleEnable = false; - } - } - inline ~SwitcherData() - { - Stop(); - } -}; - +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "utility.hpp" + +#define DEFAULT_INTERVAL 300 + +#define DEFAULT_IDLE_TIME 60 + +#define READ_FILE_FUNC 0 +#define ROUND_TRIP_FUNC 1 +#define IDLE_FUNC 2 +#define EXE_FUNC 3 +#define SCREEN_REGION_FUNC 4 +#define WINDOW_TITLE_FUNC 5 + +#define DEFAULT_PRIORITY_0 READ_FILE_FUNC +#define DEFAULT_PRIORITY_1 ROUND_TRIP_FUNC +#define DEFAULT_PRIORITY_2 IDLE_FUNC +#define DEFAULT_PRIORITY_3 EXE_FUNC +#define DEFAULT_PRIORITY_4 SCREEN_REGION_FUNC +#define DEFAULT_PRIORITY_5 WINDOW_TITLE_FUNC + +using namespace std; + + +/******************************************************************************** + * Data structs for each scene switching method + ********************************************************************************/ +struct WindowSceneSwitch +{ + OBSWeakSource scene; + string window; + OBSWeakSource transition; + bool fullscreen; + + inline WindowSceneSwitch( + OBSWeakSource scene_, const char* window_, OBSWeakSource transition_, bool fullscreen_) + : scene(scene_) + , window(window_) + , transition(transition_) + , fullscreen(fullscreen_) + { + } +}; + +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; + string regionStr; + + inline ScreenRegionSwitch(OBSWeakSource scene_, OBSWeakSource transition_, int minX_, int minY_, + int maxX_, int maxY_, string regionStr_) + : scene(scene_) + , transition(transition_) + , minX(minX_) + , minY(minY_) + , maxX(maxX_) + , maxY(maxY_) + , regionStr(regionStr_) + { + } +}; + +struct SceneRoundTripSwitch +{ + OBSWeakSource scene1; + OBSWeakSource scene2; + OBSWeakSource transition; + int delay; + string sceneRoundTripStr; + + inline SceneRoundTripSwitch(OBSWeakSource scene1_, OBSWeakSource scene2_, + OBSWeakSource transition_, int delay_, string str) + : scene1(scene1_) + , scene2(scene2_) + , transition(transition_) + , delay(delay_) + , sceneRoundTripStr(str) + { + } +}; + +struct RandomSwitch +{ + OBSWeakSource scene; + OBSWeakSource transition; + double delay; + string randomSwitchStr; + + inline RandomSwitch(OBSWeakSource scene_, OBSWeakSource transition_ + , double delay_, string str) + : scene(scene_) + , transition(transition_) + , delay(delay_) + , randomSwitchStr(str) + { + } +}; + +struct SceneTransition +{ + OBSWeakSource scene1; + OBSWeakSource scene2; + OBSWeakSource transition; + string sceneTransitionStr; + + inline SceneTransition(OBSWeakSource scene1_, OBSWeakSource scene2_, OBSWeakSource transition_, + string sceneTransitionStr_) + : scene1(scene1_) + , scene2(scene2_) + , transition(transition_) + , sceneTransitionStr(sceneTransitionStr_) + { + } +}; + +struct DefaultSceneTransition +{ + OBSWeakSource scene; + OBSWeakSource transition; + string sceneTransitionStr; + + inline DefaultSceneTransition(OBSWeakSource scene_, OBSWeakSource transition_, + string sceneTransitionStr_) + : scene(scene_) + , transition(transition_) + , sceneTransitionStr(sceneTransitionStr_) + { + } +}; + +struct FileSwitch +{ + OBSWeakSource scene; + OBSWeakSource transition; + string file; + string text; + bool useRegex = false; + bool useTime = false; + QDateTime lastMod; + + inline FileSwitch( + OBSWeakSource scene_, OBSWeakSource transition_, const char* file_, const char* text_, bool useRegex_, bool useTime_) + : scene(scene_) + , transition(transition_) + , file(file_) + , text(text_) + , useRegex(useRegex_) + , useTime(useTime_) + , lastMod() + { + } +}; + +struct FileIOData +{ + bool readEnabled = false; + string readPath; + bool writeEnabled = false; + string writePath; +}; + +struct IdleData +{ + bool idleEnable = false; + int time = DEFAULT_IDLE_TIME; + OBSWeakSource scene; + OBSWeakSource transition; +}; + +typedef enum { + NO_SWITCH = 0, + SWITCH = 1, + RANDOM_SWITCH = 2 +} NoMatch; + + +/******************************************************************************** + * SwitcherData + ********************************************************************************/ +struct SwitcherData +{ + thread th; + condition_variable cv; + mutex m; + bool transitionActive = false; + bool waitForTransition = false; + condition_variable transitionCv; + bool startAtLaunch = false; + bool stop = false; + obs_source_t* waitScene = NULL; //scene during which wait started + + int interval = DEFAULT_INTERVAL; + + OBSWeakSource nonMatchingScene; + + OBSWeakSource lastRandomScene; + + NoMatch switchIfNotMatching = NO_SWITCH; + + vector windowSwitches; + vector ignoreIdleWindows; + string lastTitle; + + vector screenRegionSwitches; + + vector pauseScenesSwitches; + + vector pauseWindowsSwitches; + + vector ignoreWindowsSwitches; + + vector sceneRoundTripSwitches; + + vector randomSwitches; + + FileIOData fileIO; + IdleData idleData; + vector fileSwitches; + + vector executableSwitches; + + bool autoStopEnable = false; + OBSWeakSource autoStopScene; + + vector sceneTransitions; + vector defaultSceneTransitions; + + vector functionNamesByPriority = vector{ + DEFAULT_PRIORITY_0, + DEFAULT_PRIORITY_1, + DEFAULT_PRIORITY_2, + DEFAULT_PRIORITY_3, + DEFAULT_PRIORITY_4, + DEFAULT_PRIORITY_5, + }; + + void Thread(); + void Start(); + void Stop(); + + bool sceneChangedDuringWait(); + bool prioFuncsValid(); + void writeSceneInfoToFile(); + void setDefaultSceneTransitions(unique_lock& lock); + void autoStopStreamAndRecording(); + bool checkPause(); + void checkSceneRoundTrip(bool& match, OBSWeakSource& scene, OBSWeakSource& transition, unique_lock& lock); + void checkIdleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition); + void checkWindowTitleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition); + void checkExeSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition); + void checkScreenRegionSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition); + void checkSwitchInfoFromFile(bool& match, OBSWeakSource& scene, OBSWeakSource& transition); + void checkFileContent(bool& match, OBSWeakSource& scene, OBSWeakSource& transition); + void checkRandom(bool& match, OBSWeakSource& scene, OBSWeakSource& transition, int& delay); + + 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) || !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--); + } + + if (!WeakSourceValid(idleData.scene) || !WeakSourceValid(idleData.transition)) + { + idleData.idleEnable = false; + } + } + inline ~SwitcherData() + { + Stop(); + } +}; diff --git a/utility.hpp b/utility.hpp index cff394f2..cdc3985e 100644 --- a/utility.hpp +++ b/utility.hpp @@ -1,167 +1,166 @@ -#pragma once -#include -#include -#include -#include "switcher-data-structs.hpp" -using namespace std; - -static inline bool WeakSourceValid(obs_weak_source_t* ws) -{ - obs_source_t* source = obs_weak_source_get_source(ws); - if (source) - obs_source_release(source); - return !!source; -} - -static inline QString MakeSwitchName( - const QString& scene, const QString& value, const QString& transition, bool fullscreen) -{ - if (!fullscreen) - return QStringLiteral("[") + scene + QStringLiteral(", ") + transition - + QStringLiteral("]: ") + value; - return QStringLiteral("[") + scene + QStringLiteral(", ") + transition + QStringLiteral("]: ") - + value + QStringLiteral(" (only if window is fullscreen)"); -} - -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 window is 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; -} - -static inline string GetWeakSourceName(obs_weak_source_t* weak_source) -{ - string name; - - obs_source_t* source = obs_weak_source_get_source(weak_source); - if (source) - { - name = obs_source_get_name(source); - obs_source_release(source); - } - - return name; -} - -static inline OBSWeakSource GetWeakSourceByName(const char* name) -{ - OBSWeakSource weak; - obs_source_t* source = obs_get_source_by_name(name); - if (source) - { - weak = obs_source_get_weak_source(source); - obs_weak_source_release(weak); - obs_source_release(source); - } - - return weak; -} - -static inline OBSWeakSource GetWeakSourceByQString(const QString& name) -{ - return GetWeakSourceByName(name.toUtf8().constData()); -} - -static inline OBSWeakSource GetWeakTransitionByName(const char* transitionName) -{ - OBSWeakSource weak; - obs_source_t* source = nullptr; - - if (strcmp(transitionName, "Default") == 0) - { - source = obs_frontend_get_current_transition(); - weak = obs_source_get_weak_source(source); - obs_source_release(source); - obs_weak_source_release(weak); - return weak; - } - - obs_frontend_source_list* transitions = new obs_frontend_source_list(); - obs_frontend_get_transitions(transitions); - bool match = false; - - for (size_t i = 0; i < transitions->sources.num; i++) - { - const char* name = obs_source_get_name(transitions->sources.array[i]); - if (strcmp(transitionName, name) == 0) - { - match = true; - source = transitions->sources.array[i]; - break; - } - } - - if (match){ - weak = obs_source_get_weak_source(source); - obs_weak_source_release(weak); - } - obs_frontend_source_list_free(transitions); - - return weak; -} - -static inline OBSWeakSource GetWeakTransitionByQString(const QString& name) -{ - return GetWeakTransitionByName(name.toUtf8().constData()); -} - +#pragma once +#include +#include +#include +#include "switcher-data-structs.hpp" +using namespace std; + +static inline bool WeakSourceValid(obs_weak_source_t* ws) +{ + obs_source_t* source = obs_weak_source_get_source(ws); + if (source) + obs_source_release(source); + return !!source; +} + +static inline QString MakeSwitchName( + const QString& scene, const QString& value, const QString& transition, bool fullscreen) +{ + if (!fullscreen) + return QStringLiteral("[") + scene + QStringLiteral(", ") + transition + + QStringLiteral("]: ") + value; + return QStringLiteral("[") + scene + QStringLiteral(", ") + transition + QStringLiteral("]: ") + + value + QStringLiteral(" (only if window is fullscreen)"); +} + +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 window is 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; +} + +static inline string GetWeakSourceName(obs_weak_source_t* weak_source) +{ + string name; + + obs_source_t* source = obs_weak_source_get_source(weak_source); + if (source) + { + name = obs_source_get_name(source); + obs_source_release(source); + } + + return name; +} + +static inline OBSWeakSource GetWeakSourceByName(const char* name) +{ + OBSWeakSource weak; + obs_source_t* source = obs_get_source_by_name(name); + if (source) + { + weak = obs_source_get_weak_source(source); + obs_weak_source_release(weak); + obs_source_release(source); + } + + return weak; +} + +static inline OBSWeakSource GetWeakSourceByQString(const QString& name) +{ + return GetWeakSourceByName(name.toUtf8().constData()); +} + +static inline OBSWeakSource GetWeakTransitionByName(const char* transitionName) +{ + OBSWeakSource weak; + obs_source_t* source = nullptr; + + if (strcmp(transitionName, "Default") == 0) + { + source = obs_frontend_get_current_transition(); + weak = obs_source_get_weak_source(source); + obs_source_release(source); + obs_weak_source_release(weak); + return weak; + } + + obs_frontend_source_list* transitions = new obs_frontend_source_list(); + obs_frontend_get_transitions(transitions); + bool match = false; + + for (size_t i = 0; i < transitions->sources.num; i++) + { + const char* name = obs_source_get_name(transitions->sources.array[i]); + if (strcmp(transitionName, name) == 0) + { + match = true; + source = transitions->sources.array[i]; + break; + } + } + + if (match){ + weak = obs_source_get_weak_source(source); + obs_weak_source_release(weak); + } + obs_frontend_source_list_free(transitions); + + return weak; +} + +static inline OBSWeakSource GetWeakTransitionByQString(const QString& name) +{ + return GetWeakTransitionByName(name.toUtf8().constData()); +} diff --git a/window-title-switch.cpp b/window-title-switch.cpp index ed7961b6..9dd37746 100644 --- a/window-title-switch.cpp +++ b/window-title-switch.cpp @@ -1,283 +1,280 @@ -#include -#include "advanced-scene-switcher.hpp" - -void SceneSwitcher::on_add_clicked() -{ - QString sceneName = ui->scenes->currentText(); - QString windowName = ui->windows->currentText(); - QString transitionName = ui->transitions->currentText(); - bool fullscreen = ui->fullscreenCheckBox->isChecked(); - - if (windowName.isEmpty() || sceneName.isEmpty()) - return; - - OBSWeakSource source = GetWeakSourceByQString(sceneName); - OBSWeakSource transition = GetWeakTransitionByQString(transitionName); - QVariant v = QVariant::fromValue(windowName); - - QString text = MakeSwitchName(sceneName, windowName, transitionName, fullscreen); - - int idx = FindByData(windowName); - - if (idx == -1) - { - lock_guard lock(switcher->m); - switcher->switches.emplace_back( - source, windowName.toUtf8().constData(), transition, fullscreen); - - QListWidgetItem* item = new QListWidgetItem(text, ui->switches); - item->setData(Qt::UserRole, v); - } - else - { - QListWidgetItem* item = ui->switches->item(idx); - item->setText(text); - - string window = windowName.toUtf8().constData(); - - { - lock_guard lock(switcher->m); - for (auto& s : switcher->switches) - { - if (s.window == window) - { - s.scene = source; - s.transition = transition; - s.fullscreen = fullscreen; - break; - } - } - } - - ui->switches->sortItems(); - } -} - -void SceneSwitcher::on_remove_clicked() -{ - QListWidgetItem* item = ui->switches->currentItem(); - if (!item) - return; - - string window = item->data(Qt::UserRole).toString().toUtf8().constData(); - - { - lock_guard lock(switcher->m); - auto& switches = switcher->switches; - - for (auto it = switches.begin(); it != switches.end(); ++it) - { - auto& s = *it; - - if (s.window == window) - { - switches.erase(it); - break; - } - } - } - - delete item; -} - - - - -void SceneSwitcher::on_ignoreWindowsAdd_clicked() -{ - QString windowName = ui->ignoreWindowsWindows->currentText(); - - if (windowName.isEmpty()) - return; - - QVariant v = QVariant::fromValue(windowName); - - QList items = ui->ignoreWindows->findItems(windowName, Qt::MatchExactly); - - if (items.size() == 0) - { - QListWidgetItem* item = new QListWidgetItem(windowName, ui->ignoreWindows); - item->setData(Qt::UserRole, v); - - lock_guard lock(switcher->m); - switcher->ignoreWindowsSwitches.emplace_back(windowName.toUtf8().constData()); - ui->ignoreWindows->sortItems(); - } -} - -void SceneSwitcher::on_ignoreWindowsRemove_clicked() -{ - QListWidgetItem* item = ui->ignoreWindows->currentItem(); - if (!item) - return; - - QString windowName = item->data(Qt::UserRole).toString(); - - { - lock_guard lock(switcher->m); - auto& switches = switcher->ignoreWindowsSwitches; - - for (auto it = switches.begin(); it != switches.end(); ++it) - { - auto& s = *it; - - if (s == windowName.toUtf8().constData()) - { - switches.erase(it); - break; - } - } - } - - delete item; -} - -int SceneSwitcher::FindByData(const QString& window) -{ - int count = ui->switches->count(); - int idx = -1; - - for (int i = 0; i < count; i++) - { - QListWidgetItem* item = ui->switches->item(i); - QString itemWindow = item->data(Qt::UserRole).toString(); - - if (itemWindow == window) - { - idx = i; - break; - } - } - - return idx; -} - - - - -int SceneSwitcher::IgnoreWindowsFindByData(const QString& window) -{ - int count = ui->ignoreWindows->count(); - int idx = -1; - - for (int i = 0; i < count; i++) - { - QListWidgetItem* item = ui->ignoreWindows->item(i); - QString itemRegion = item->data(Qt::UserRole).toString(); - - if (itemRegion == window) - { - idx = i; - break; - } - } - - return idx; -} - - -void SceneSwitcher::on_switches_currentRowChanged(int idx) -{ - if (loading) - return; - if (idx == -1) - return; - - QListWidgetItem* item = ui->switches->item(idx); - - QString window = item->data(Qt::UserRole).toString(); - - lock_guard lock(switcher->m); - for (auto& s : switcher->switches) - { - if (window.compare(s.window.c_str()) == 0) - { - string name = GetWeakSourceName(s.scene); - string transitionName = GetWeakSourceName(s.transition); - ui->scenes->setCurrentText(name.c_str()); - ui->windows->setCurrentText(window); - ui->transitions->setCurrentText(transitionName.c_str()); - ui->fullscreenCheckBox->setChecked(s.fullscreen); - break; - } - } -} - - - - -void SceneSwitcher::on_ignoreWindows_currentRowChanged(int idx) -{ - if (loading) - return; - if (idx == -1) - return; - - QListWidgetItem* item = ui->ignoreWindows->item(idx); - - QString window = item->data(Qt::UserRole).toString(); - - lock_guard lock(switcher->m); - for (auto& s : switcher->ignoreWindowsSwitches) - { - if (window.compare(s.c_str()) == 0) - { - ui->ignoreWindowsWindows->setCurrentText(s.c_str()); - break; - } - } -} - -void SwitcherData::checkWindowTitleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition) -{ - //check if title should be ignored - string title; - GetCurrentWindowTitle(title); - for (auto& window : ignoreWindowsSwitches) - { - try - { - bool matches = regex_match(title, regex(window)); - if (matches) - { - title = lastTitle; - break; - } - } - catch (const regex_error&) - { - } - } - lastTitle = title; - - //direct match - for (SceneSwitch& s : switches) - { - if (s.window == title) - { - match = !s.fullscreen || (s.fullscreen && isFullscreen()); - scene = s.scene; - transition = s.transition; - return; - } - } - //regex match - for (SceneSwitch& s : switches) - { - try - { - bool matches = regex_match(title, regex(s.window)); - if (matches) - { - match = !s.fullscreen || (s.fullscreen && isFullscreen()); - scene = s.scene; - transition = s.transition; - } - } - catch (const regex_error&) - { - } - } - -} - +#include +#include "advanced-scene-switcher.hpp" + +void SceneSwitcher::on_add_clicked() +{ + QString sceneName = ui->scenes->currentText(); + QString windowName = ui->windows->currentText(); + QString transitionName = ui->transitions->currentText(); + bool fullscreen = ui->fullscreenCheckBox->isChecked(); + + if (windowName.isEmpty() || sceneName.isEmpty()) + return; + + OBSWeakSource source = GetWeakSourceByQString(sceneName); + OBSWeakSource transition = GetWeakTransitionByQString(transitionName); + QVariant v = QVariant::fromValue(windowName); + + QString text = MakeSwitchName(sceneName, windowName, transitionName, fullscreen); + + int idx = FindByData(windowName); + + if (idx == -1) + { + lock_guard lock(switcher->m); + switcher->windowSwitches.emplace_back( + source, windowName.toUtf8().constData(), transition, fullscreen); + + QListWidgetItem* item = new QListWidgetItem(text, ui->switches); + item->setData(Qt::UserRole, v); + } + else + { + QListWidgetItem* item = ui->switches->item(idx); + item->setText(text); + + string window = windowName.toUtf8().constData(); + + { + lock_guard lock(switcher->m); + for (auto& s : switcher->windowSwitches) + { + if (s.window == window) + { + s.scene = source; + s.transition = transition; + s.fullscreen = fullscreen; + break; + } + } + } + + ui->switches->sortItems(); + } +} + +void SceneSwitcher::on_remove_clicked() +{ + QListWidgetItem* item = ui->switches->currentItem(); + if (!item) + return; + + string window = item->data(Qt::UserRole).toString().toUtf8().constData(); + + { + lock_guard lock(switcher->m); + auto& switches = switcher->windowSwitches; + + for (auto it = switches.begin(); it != switches.end(); ++it) + { + auto& s = *it; + + if (s.window == window) + { + switches.erase(it); + break; + } + } + } + + delete item; +} + + + + +void SceneSwitcher::on_ignoreWindowsAdd_clicked() +{ + QString windowName = ui->ignoreWindowsWindows->currentText(); + + if (windowName.isEmpty()) + return; + + QVariant v = QVariant::fromValue(windowName); + + QList items = ui->ignoreWindows->findItems(windowName, Qt::MatchExactly); + + if (items.size() == 0) + { + QListWidgetItem* item = new QListWidgetItem(windowName, ui->ignoreWindows); + item->setData(Qt::UserRole, v); + + lock_guard lock(switcher->m); + switcher->ignoreWindowsSwitches.emplace_back(windowName.toUtf8().constData()); + ui->ignoreWindows->sortItems(); + } +} + +void SceneSwitcher::on_ignoreWindowsRemove_clicked() +{ + QListWidgetItem* item = ui->ignoreWindows->currentItem(); + if (!item) + return; + + QString windowName = item->data(Qt::UserRole).toString(); + + { + lock_guard lock(switcher->m); + auto& switches = switcher->ignoreWindowsSwitches; + + for (auto it = switches.begin(); it != switches.end(); ++it) + { + auto& s = *it; + + if (s == windowName.toUtf8().constData()) + { + switches.erase(it); + break; + } + } + } + + delete item; +} + +int SceneSwitcher::FindByData(const QString& window) +{ + int count = ui->switches->count(); + int idx = -1; + + for (int i = 0; i < count; i++) + { + QListWidgetItem* item = ui->switches->item(i); + QString itemWindow = item->data(Qt::UserRole).toString(); + + if (itemWindow == window) + { + idx = i; + break; + } + } + + return idx; +} + + + + +int SceneSwitcher::IgnoreWindowsFindByData(const QString& window) +{ + int count = ui->ignoreWindows->count(); + int idx = -1; + + for (int i = 0; i < count; i++) + { + QListWidgetItem* item = ui->ignoreWindows->item(i); + QString itemRegion = item->data(Qt::UserRole).toString(); + + if (itemRegion == window) + { + idx = i; + break; + } + } + + return idx; +} + + +void SceneSwitcher::on_switches_currentRowChanged(int idx) +{ + if (loading) + return; + if (idx == -1) + return; + + QListWidgetItem* item = ui->switches->item(idx); + + QString window = item->data(Qt::UserRole).toString(); + + lock_guard lock(switcher->m); + for (auto& s : switcher->windowSwitches) + { + if (window.compare(s.window.c_str()) == 0) + { + string name = GetWeakSourceName(s.scene); + string transitionName = GetWeakSourceName(s.transition); + ui->scenes->setCurrentText(name.c_str()); + ui->windows->setCurrentText(window); + ui->transitions->setCurrentText(transitionName.c_str()); + ui->fullscreenCheckBox->setChecked(s.fullscreen); + break; + } + } +} + + +void SceneSwitcher::on_ignoreWindows_currentRowChanged(int idx) +{ + if (loading) + return; + if (idx == -1) + return; + + QListWidgetItem* item = ui->ignoreWindows->item(idx); + + QString window = item->data(Qt::UserRole).toString(); + + lock_guard lock(switcher->m); + for (auto& s : switcher->ignoreWindowsSwitches) + { + if (window.compare(s.c_str()) == 0) + { + ui->ignoreWindowsWindows->setCurrentText(s.c_str()); + break; + } + } +} + +void SwitcherData::checkWindowTitleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition) +{ + //check if title should be ignored + string title; + GetCurrentWindowTitle(title); + for (auto& window : ignoreWindowsSwitches) + { + try + { + bool matches = regex_match(title, regex(window)); + if (matches) + { + title = lastTitle; + break; + } + } + catch (const regex_error&) + { + } + } + lastTitle = title; + + //direct match + for (WindowSceneSwitch& s : windowSwitches) + { + if (s.window == title) + { + match = !s.fullscreen || (s.fullscreen && isFullscreen()); + scene = s.scene; + transition = s.transition; + return; + } + } + //regex match + for (WindowSceneSwitch& s : windowSwitches) + { + try + { + bool matches = regex_match(title, regex(s.window)); + if (matches) + { + match = !s.fullscreen || (s.fullscreen && isFullscreen()); + scene = s.scene; + transition = s.transition; + } + } + catch (const regex_error&) + { + } + } + +}