mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-08-29 12:45:28 -05:00
Compare commits
112 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
214821b69f | ||
|
|
7edb6eb6c1 | ||
|
|
46916dc5d3 | ||
|
|
8aed15f3a8 | ||
|
|
1e6a022787 | ||
|
|
fb1eac5268 | ||
|
|
787b664d29 | ||
|
|
dd63ff846c | ||
|
|
1559d437ec | ||
|
|
8d023ee385 | ||
|
|
3fd3801e56 | ||
|
|
3ec1e99f4b | ||
|
|
21a788b48b | ||
|
|
a5c8d776f3 | ||
|
|
95261ce9bb | ||
|
|
255d10e603 | ||
|
|
ab3e93ab84 | ||
|
|
3b5f88c14f | ||
|
|
2f33b6bdc3 | ||
|
|
3c1e240722 | ||
|
|
91831a1075 | ||
|
|
ccc824abc1 | ||
|
|
6f39d4648b | ||
|
|
74cb400426 | ||
|
|
910b1dde99 | ||
|
|
e462d7f420 | ||
|
|
0cdd8bf1d0 | ||
|
|
f8ad8c31be | ||
|
|
93c889c215 | ||
|
|
f8b505fa4e | ||
|
|
1516263d2a | ||
|
|
79f5ec340d | ||
|
|
cd54cc17c0 | ||
|
|
098159dc0f | ||
|
|
a4418996f4 | ||
|
|
340cb559ee | ||
|
|
eeefd8279f | ||
|
|
e62dc91cd7 | ||
|
|
536041abd2 | ||
|
|
d3ab9e01c5 | ||
|
|
2113025877 | ||
|
|
6aaffeb5a4 | ||
|
|
2a92df4f3c | ||
|
|
560044bbbf | ||
|
|
4bd8cdf5a0 | ||
|
|
c17cbb66d9 | ||
|
|
8d23dd46b0 | ||
|
|
bf70bd7c60 | ||
|
|
1a144d84f5 | ||
|
|
6810ba71e8 | ||
|
|
bbe6a30506 | ||
|
|
08c668f90a | ||
|
|
3151a7542f | ||
|
|
7bfde0a39b | ||
|
|
7347be370e | ||
|
|
66d847c047 | ||
|
|
c9f1f9624b | ||
|
|
8e4a8b7e9d | ||
|
|
e693794549 | ||
|
|
7a924438bc | ||
|
|
7458e9f2d5 | ||
|
|
da2e11e35e | ||
|
|
9f7ca3e4c7 | ||
|
|
2f77d99161 | ||
|
|
acd2e2863a | ||
|
|
513fe0728c | ||
|
|
cba39633aa | ||
|
|
c6a26d862f | ||
|
|
9386109168 | ||
|
|
4b86849356 | ||
|
|
8fd263f44a | ||
|
|
5590e97f4f | ||
|
|
98c3131017 | ||
|
|
f03fca85aa | ||
|
|
7fef29dafb | ||
|
|
9f03264672 | ||
|
|
5082f5944e | ||
|
|
b981a446b6 | ||
|
|
5ab8199e03 | ||
|
|
e6a3f98ab7 | ||
|
|
5e60cefd1c | ||
|
|
fabb7406bd | ||
|
|
cfb0a44b1f | ||
|
|
78ed7415f5 | ||
|
|
d6380b865e | ||
|
|
55d8303ecf | ||
|
|
23201100fa | ||
|
|
3959e41e88 | ||
|
|
f0cf5a5c19 | ||
|
|
87da123c19 | ||
|
|
2a0e9e9d9a | ||
|
|
a7a8adb91b | ||
|
|
e61905d02f | ||
|
|
f00c244bfa | ||
|
|
463b54f1fb | ||
|
|
70894f9302 | ||
|
|
de5b6f8eb4 | ||
|
|
be83232caa | ||
|
|
e4b640903d | ||
|
|
a4de8c0c59 | ||
|
|
ac051a42a8 | ||
|
|
e33e93fd18 | ||
|
|
d5052c94ca | ||
|
|
f0aa76517a | ||
|
|
a2543f1b85 | ||
|
|
5f87a61177 | ||
|
|
451bb6518c | ||
|
|
318502d8d0 | ||
|
|
e9b1ef58ba | ||
|
|
26c24d4d53 | ||
|
|
3654f39247 | ||
|
|
b45b38cf6a |
107
.clang-format
Normal file
107
.clang-format
Normal file
@@ -0,0 +1,107 @@
|
||||
# please use clang-format version 8 or later
|
||||
|
||||
Standard: Cpp11
|
||||
AccessModifierOffset: -8
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
#AllowAllArgumentsOnNextLine: false # requires clang-format 9
|
||||
#AllowAllConstructorInitializersOnNextLine: false # requires clang-format 9
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
#AllowShortLambdasOnASingleLine: Inline # requires clang-format 9
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: false
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakStringLiterals: false # apparently unpredictable
|
||||
ColumnLimit: 80
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 8
|
||||
ContinuationIndentWidth: 8
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
FixNamespaceComments: false
|
||||
ForEachMacros:
|
||||
- 'json_object_foreach'
|
||||
- 'json_object_foreach_safe'
|
||||
- 'json_array_foreach'
|
||||
IncludeBlocks: Preserve
|
||||
IndentCaseLabels: false
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 8
|
||||
IndentWrappedFunctionNames: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
#ObjCBinPackProtocolList: Auto # requires clang-format 7
|
||||
ObjCBlockIndentWidth: 8
|
||||
ObjCSpaceAfterProperty: true
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
|
||||
PenaltyBreakAssignment: 10
|
||||
PenaltyBreakBeforeFirstCallParameter: 30
|
||||
PenaltyBreakComment: 10
|
||||
PenaltyBreakFirstLessLess: 0
|
||||
PenaltyBreakString: 10
|
||||
PenaltyExcessCharacter: 100
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
|
||||
PointerAlignment: Right
|
||||
ReflowComments: false
|
||||
SortIncludes: false
|
||||
SortUsingDeclarations: false
|
||||
SpaceAfterCStyleCast: false
|
||||
#SpaceAfterLogicalNot: false # requires clang-format 9
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
#SpaceBeforeCtorInitializerColon: true # requires clang-format 7
|
||||
#SpaceBeforeInheritanceColon: true # requires clang-format 7
|
||||
SpaceBeforeParens: ControlStatements
|
||||
#SpaceBeforeRangeBasedForLoopColon: true # requires clang-format 7
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
#StatementMacros: # requires clang-format 8
|
||||
# - 'Q_OBJECT'
|
||||
TabWidth: 8
|
||||
#TypenameMacros: # requires clang-format 9
|
||||
# - 'DARRAY'
|
||||
UseTab: ForContinuationAndIndentation
|
||||
---
|
||||
Language: ObjC
|
||||
25
.github/workflows/build.yml
vendored
25
.github/workflows/build.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
runs-on: [macos-latest]
|
||||
env:
|
||||
QT_VERSION: 5.14.1
|
||||
OSX_DEPS_VERSION: '2020-04-07'
|
||||
MACOS_DEPS_VERSION: '2020-08-30'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
@@ -35,20 +35,31 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
cd UI/frontend-plugins/${{ env.PLUGIN_NAME }}/CI/macos
|
||||
brew untap local/openssl
|
||||
brew untap local/python2
|
||||
brew update
|
||||
brew bundle
|
||||
cd -
|
||||
- name: 'Install prerequisite: Pre-built dependencies'
|
||||
if: steps.deps-cache.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
curl -L -O https://github.com/obsproject/obs-deps/releases/download/${{ env.OSX_DEPS_VERSION }}/osx-deps-${{ env.OSX_DEPS_VERSION }}.tar.gz
|
||||
tar -xf ./osx-deps-${{ env.OSX_DEPS_VERSION }}.tar.gz -C "/tmp"
|
||||
curl -L -O https://github.com/obsproject/obs-deps/releases/download/${{ env.MACOS_DEPS_VERSION }}/macos-deps-${{ env.MACOS_DEPS_VERSION }}.tar.gz
|
||||
tar -xf ./macos-deps-${{ env.MACOS_DEPS_VERSION }}.tar.gz -C "/tmp"
|
||||
- name: 'Install prerequisite: Pre-built dependency Qt'
|
||||
if: steps.deps-qt-cache.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
curl -L -O https://github.com/obsproject/obs-deps/releases/download/${{ env.MACOS_DEPS_VERSION }}/macos-qt-${{ env.QT_VERSION }}-${{ env.MACOS_DEPS_VERSION }}.tar.gz
|
||||
tar -xf ./macos-qt-${{ env.QT_VERSION }}-${{ env.MACOS_DEPS_VERSION }}.tar.gz -C "/tmp"
|
||||
xattr -r -d com.apple.quarantine /tmp/obsdeps
|
||||
- name: Configure
|
||||
shell: bash
|
||||
run: |
|
||||
echo "add_subdirectory(${{ env.PLUGIN_NAME }})" >> UI/frontend-plugins/CMakeLists.txt
|
||||
mkdir ./build
|
||||
cd ./build
|
||||
cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.11 -DDepsPath="/tmp/obsdeps" -DQTDIR="/usr/local/Cellar/qt/${{ env.QT_VERSION }}" ..
|
||||
cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.11 -DDISABLE_PYTHON=ON -DDepsPath="/tmp/obsdeps" -DQTDIR="/tmp/obsdeps" ..
|
||||
cd -
|
||||
- name: Build
|
||||
shell: bash
|
||||
@@ -70,9 +81,9 @@ jobs:
|
||||
cd UI/frontend-plugins/${{ env.PLUGIN_NAME }}
|
||||
install_name_tool -change @rpath/libobs-frontend-api.dylib @executable_path/../Frameworks/libobs-frontend-api.dylib ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
|
||||
install_name_tool -change @rpath/libobs.0.dylib @executable_path/../Frameworks/libobs.0.dylib ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
|
||||
install_name_tool -change /usr/local/opt/qt5/lib/QtWidgets.framework/Versions/5/QtWidgets @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
|
||||
install_name_tool -change /usr/local/opt/qt5/lib/QtGui.framework/Versions/5/QtGui @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
|
||||
install_name_tool -change /usr/local/opt/qt5/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
|
||||
install_name_tool -change /tmp/obsdeps/lib/QtWidgets.framework/Versions/5/QtWidgets @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
|
||||
install_name_tool -change /tmp/obsdeps/lib/QtGui.framework/Versions/5/QtGui @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
|
||||
install_name_tool -change /tmp/obsdeps/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
|
||||
FILE_DATE=$(date +%Y-%m-%d)
|
||||
FILE_NAME=${{ env.PLUGIN_NAME }}-$FILE_DATE-${{ github.sha }}-macos.pkg
|
||||
echo "::set-env name=FILE_NAME::${FILE_NAME}"
|
||||
|
||||
@@ -2,5 +2,4 @@ brew "jack"
|
||||
brew "speexdsp"
|
||||
brew "cmake"
|
||||
brew "freetype"
|
||||
brew "fdk-aac"
|
||||
brew "https://gist.githubusercontent.com/DDRBoxman/9c7a2b08933166f4b61ed9a44b242609/raw/ef4de6c587c6bd7f50210eccd5bd51ff08e6de13/qt.rb"
|
||||
brew "fdk-aac"
|
||||
@@ -13,6 +13,7 @@ if(BUILD_OUT_OF_TREE)
|
||||
find_package(LibObs REQUIRED)
|
||||
find_package(Qt5Core REQUIRED)
|
||||
find_package(Qt5Widgets REQUIRED)
|
||||
find_package(Libcurl REQUIRED)
|
||||
find_path(LIBOBS_FRONTEND_INCLUDE_DIR HINTS ${LIBOBS_INCLUDE_DIRS})
|
||||
find_file(LIBOBS_FRONTEND_API_LIB NAMES libobs-frontend-api.* HINTS ${LIBOBS_LIB} )
|
||||
|
||||
@@ -34,26 +35,44 @@ if(BUILD_OUT_OF_TREE)
|
||||
src/headers/advanced-scene-switcher.hpp
|
||||
src/headers/switcher-data-structs.hpp
|
||||
src/headers/utility.hpp
|
||||
src/headers/curl-helper.hpp
|
||||
src/headers/switch-audio.hpp
|
||||
src/headers/switch-executable.hpp
|
||||
src/headers/switch-file.hpp
|
||||
src/headers/switch-idle.hpp
|
||||
src/headers/switch-media.hpp
|
||||
src/headers/switch-random.hpp
|
||||
src/headers/switch-screen-region.hpp
|
||||
src/headers/switch-time.hpp
|
||||
src/headers/switch-transitions.hpp
|
||||
src/headers/switch-window.hpp
|
||||
src/headers/switch-sequence.hpp
|
||||
src/headers/switch-generic.hpp
|
||||
)
|
||||
|
||||
set(advanced-scene-switcher_SOURCES
|
||||
${advanced-scene-switcher_SOURCES}
|
||||
src/advanced-scene-switcher.cpp
|
||||
src/advanced-scene-switcher-module.c
|
||||
src/scene-transitions.cpp
|
||||
src/screen-region-switch.cpp
|
||||
src/priority.cpp
|
||||
src/executable-switch.cpp
|
||||
src/idle-switch.cpp
|
||||
src/scene-round-trip.cpp
|
||||
src/file-switch.cpp
|
||||
src/window-title-switch.cpp
|
||||
src/media-switch.cpp
|
||||
src/switcher-data-structs.cpp
|
||||
src/switch-transitions.cpp
|
||||
src/switch-screen-region.cpp
|
||||
src/switch-priority.cpp
|
||||
src/switch-executable.cpp
|
||||
src/switch-idle.cpp
|
||||
src/switch-sequence.cpp
|
||||
src/switch-file.cpp
|
||||
src/switch-window.cpp
|
||||
src/switch-media.cpp
|
||||
src/hotkey.cpp
|
||||
src/general.cpp
|
||||
src/pause-switch.cpp
|
||||
src/random.cpp
|
||||
src/time-switch.cpp
|
||||
src/switch-pause.cpp
|
||||
src/switch-random.cpp
|
||||
src/switch-time.cpp
|
||||
src/switch-audio.cpp
|
||||
src/switch-generic.cpp
|
||||
src/curl-helper.cpp
|
||||
src/volume-control.cpp
|
||||
)
|
||||
|
||||
set(advanced-scene-switcher_UI
|
||||
@@ -96,7 +115,8 @@ if(BUILD_OUT_OF_TREE)
|
||||
"${LIBOBS_INCLUDE_DIRS}"
|
||||
"${LIBOBS_FRONTEND_INCLUDE_DIR}"
|
||||
${Qt5Core_INCLUDES}
|
||||
${Qt5Widgets_INCLUDES})
|
||||
${Qt5Widgets_INCLUDES}
|
||||
${LIBCURL_INCLUDE_DIRS})
|
||||
|
||||
target_link_libraries(advanced-scene-switcher
|
||||
${advanced-scene-switcher_PLATFORM_LIBS}
|
||||
@@ -164,26 +184,45 @@ else ()
|
||||
src/headers/advanced-scene-switcher.hpp
|
||||
src/headers/switcher-data-structs.hpp
|
||||
src/headers/utility.hpp
|
||||
src/headers/curl-helper.hpp
|
||||
src/headers/volume-control.hpp
|
||||
src/headers/switch-audio.hpp
|
||||
src/headers/switch-executable.hpp
|
||||
src/headers/switch-file.hpp
|
||||
src/headers/switch-idle.hpp
|
||||
src/headers/switch-media.hpp
|
||||
src/headers/switch-random.hpp
|
||||
src/headers/switch-screen-region.hpp
|
||||
src/headers/switch-time.hpp
|
||||
src/headers/switch-transitions.hpp
|
||||
src/headers/switch-window.hpp
|
||||
src/headers/switch-sequence.hpp
|
||||
src/headers/switch-generic.hpp
|
||||
)
|
||||
|
||||
set(advanced-scene-switcher_SOURCES
|
||||
${advanced-scene-switcher_SOURCES}
|
||||
src/advanced-scene-switcher.cpp
|
||||
src/advanced-scene-switcher-module.c
|
||||
src/scene-transitions.cpp
|
||||
src/screen-region-switch.cpp
|
||||
src/priority.cpp
|
||||
src/executable-switch.cpp
|
||||
src/idle-switch.cpp
|
||||
src/scene-round-trip.cpp
|
||||
src/file-switch.cpp
|
||||
src/window-title-switch.cpp
|
||||
src/media-switch.cpp
|
||||
src/switcher-data-structs.cpp
|
||||
src/switch-transitions.cpp
|
||||
src/switch-screen-region.cpp
|
||||
src/switch-priority.cpp
|
||||
src/switch-executable.cpp
|
||||
src/switch-idle.cpp
|
||||
src/switch-sequence.cpp
|
||||
src/switch-file.cpp
|
||||
src/switch-window.cpp
|
||||
src/switch-media.cpp
|
||||
src/hotkey.cpp
|
||||
src/general.cpp
|
||||
src/pause-switch.cpp
|
||||
src/random.cpp
|
||||
src/time-switch.cpp
|
||||
src/switch-pause.cpp
|
||||
src/switch-random.cpp
|
||||
src/switch-time.cpp
|
||||
src/switch-audio.cpp
|
||||
src/switch-generic.cpp
|
||||
src/curl-helper.cpp
|
||||
src/volume-control.cpp
|
||||
)
|
||||
|
||||
set(advanced-scene-switcher_UI
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
67
src/curl-helper.cpp
Normal file
67
src/curl-helper.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <curl/curl.h>
|
||||
#include <obs.hpp>
|
||||
|
||||
#include "headers/curl-helper.hpp"
|
||||
|
||||
initFunction f_curl_init = nullptr;
|
||||
setOptFunction f_curl_setopt = nullptr;
|
||||
performFunction f_curl_perform = nullptr;
|
||||
cleanupFunction f_curl_cleanup = nullptr;
|
||||
|
||||
QLibrary *loaded_curl_lib = nullptr;
|
||||
|
||||
bool resolveCurl()
|
||||
{
|
||||
f_curl_init = (initFunction)loaded_curl_lib->resolve("curl_easy_init");
|
||||
f_curl_setopt =
|
||||
(setOptFunction)loaded_curl_lib->resolve("curl_easy_setopt");
|
||||
f_curl_perform =
|
||||
(performFunction)loaded_curl_lib->resolve("curl_easy_perform");
|
||||
f_curl_cleanup =
|
||||
(cleanupFunction)loaded_curl_lib->resolve("curl_easy_cleanup");
|
||||
|
||||
if (f_curl_init && f_curl_setopt && f_curl_perform && f_curl_cleanup) {
|
||||
blog(LOG_INFO, "[adv-ss] curl loaded successfully");
|
||||
return true;
|
||||
}
|
||||
|
||||
blog(LOG_INFO, "[adv-ss] curl symbols not resolved");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool loadCurl()
|
||||
{
|
||||
QStringList locations;
|
||||
locations << QDir::currentPath();
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
locations << "/usr/lib";
|
||||
locations << "/usr/local/lib";
|
||||
locations << "/usr/lib/x86_64-linux-gnu";
|
||||
locations << "/usr/local/opt/curl/lib";
|
||||
#endif
|
||||
|
||||
for (QString path : locations) {
|
||||
blog(LOG_INFO, "[adv-ss] trying '%s'", path.toUtf8().constData());
|
||||
QFileInfo libPath(
|
||||
QDir(path).absoluteFilePath(curl_library_name));
|
||||
|
||||
if (libPath.exists() && libPath.isFile()) {
|
||||
QString libFilePath = libPath.absoluteFilePath();
|
||||
blog(LOG_INFO, "[adv-ss] found curl library at '%s'",
|
||||
libFilePath.toUtf8().constData());
|
||||
|
||||
loaded_curl_lib = new QLibrary(libFilePath, nullptr);
|
||||
if (resolveCurl())
|
||||
return true;
|
||||
else {
|
||||
delete loaded_curl_lib;
|
||||
loaded_curl_lib = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
blog(LOG_WARNING, "[adv-ss] can't find the curl library");
|
||||
return false;
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
#include "headers/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<mutex> 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<mutex> 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<mutex> 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<mutex> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,254 +0,0 @@
|
||||
#include <QFileDialog>
|
||||
#include <QTextStream>
|
||||
#include <QDateTime>
|
||||
#include <obs.hpp>
|
||||
#include "headers/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<mutex> 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<mutex> 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<mutex> 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<mutex> 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<mutex> 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<mutex> 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);
|
||||
}
|
||||
680
src/general.cpp
680
src/general.cpp
@@ -1,24 +1,20 @@
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
#include <obs-module.h>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
void SceneSwitcher::on_close_clicked()
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
#include "headers/utility.hpp"
|
||||
|
||||
QMetaObject::Connection inactivePluse;
|
||||
|
||||
void AdvSceneSwitcher::on_close_clicked()
|
||||
{
|
||||
done(0);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_startAtLaunch_toggled(bool value)
|
||||
void AdvSceneSwitcher::UpdateNonMatchingScene(const QString &name)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> 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);
|
||||
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;
|
||||
|
||||
@@ -26,82 +22,698 @@ void SceneSwitcher::UpdateNonMatchingScene(const QString& name)
|
||||
obs_source_release(scene);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_noMatchDontSwitch_clicked()
|
||||
void AdvSceneSwitcher::on_noMatchDontSwitch_clicked()
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->switchIfNotMatching = NO_SWITCH;
|
||||
ui->noMatchSwitchScene->setEnabled(false);
|
||||
ui->randomDisabledWarning->setVisible(true);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_noMatchSwitch_clicked()
|
||||
void AdvSceneSwitcher::on_noMatchSwitch_clicked()
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->switchIfNotMatching = SWITCH;
|
||||
ui->noMatchSwitchScene->setEnabled(true);
|
||||
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
|
||||
ui->randomDisabledWarning->setVisible(true);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_noMatchRandomSwitch_clicked()
|
||||
void AdvSceneSwitcher::on_noMatchRandomSwitch_clicked()
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->switchIfNotMatching = RANDOM_SWITCH;
|
||||
ui->noMatchSwitchScene->setEnabled(false);
|
||||
ui->randomDisabledWarning->setVisible(false);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_noMatchSwitchScene_currentTextChanged(const QString& text)
|
||||
void AdvSceneSwitcher::on_startupBehavior_currentIndexChanged(int index)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->startupBehavior = (StartupBehavior)index;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_noMatchSwitchScene_currentTextChanged(
|
||||
const QString &text)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
UpdateNonMatchingScene(text);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_checkInterval_valueChanged(int value)
|
||||
void AdvSceneSwitcher::on_checkInterval_valueChanged(int value)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->interval = value;
|
||||
}
|
||||
|
||||
void SceneSwitcher::SetStarted()
|
||||
void AdvSceneSwitcher::SetStarted()
|
||||
{
|
||||
ui->toggleStartButton->setText("Stop");
|
||||
ui->pluginRunningText->setText("Active");
|
||||
ui->pluginRunningText->disconnect(inactivePluse);
|
||||
}
|
||||
|
||||
void SceneSwitcher::SetStopped()
|
||||
void AdvSceneSwitcher::SetStopped()
|
||||
{
|
||||
ui->toggleStartButton->setText("Start");
|
||||
ui->pluginRunningText->setText("Inactive");
|
||||
inactivePluse = PulseWidget(ui->pluginRunningText, QColor(Qt::red),
|
||||
QColor(0, 0, 0, 0), "QLabel ");
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_toggleStartButton_clicked()
|
||||
void AdvSceneSwitcher::on_toggleStartButton_clicked()
|
||||
{
|
||||
if (switcher->th.joinable())
|
||||
{
|
||||
if (switcher->th && switcher->th->isRunning()) {
|
||||
switcher->Stop();
|
||||
SetStopped();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
switcher->Start();
|
||||
SetStarted();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::closeEvent(QCloseEvent*)
|
||||
void AdvSceneSwitcher::closeEvent(QCloseEvent *)
|
||||
{
|
||||
obs_frontend_save();
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_autoStopScenes_currentTextChanged(const QString &text)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
UpdateAutoStopScene(text);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_autoStopSceneCheckBox_stateChanged(int state)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
if (!state) {
|
||||
ui->autoStopScenes->setDisabled(true);
|
||||
switcher->autoStopEnable = false;
|
||||
} else {
|
||||
ui->autoStopScenes->setDisabled(false);
|
||||
switcher->autoStopEnable = true;
|
||||
if (!switcher->autoStopScene)
|
||||
UpdateAutoStopScene(ui->autoStopScenes->currentText());
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::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 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);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_autoStartType_currentIndexChanged(int index)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->autoStartType = (AutoStartType)index;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_autoStartScenes_currentTextChanged(const QString &text)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
UpdateAutoStartScene(text);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_autoStartSceneCheckBox_stateChanged(int state)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
if (!state) {
|
||||
ui->autoStartScenes->setDisabled(true);
|
||||
ui->autoStartType->setDisabled(true);
|
||||
switcher->autoStartEnable = false;
|
||||
} else {
|
||||
ui->autoStartScenes->setDisabled(false);
|
||||
ui->autoStartType->setDisabled(false);
|
||||
switcher->autoStartEnable = true;
|
||||
if (!switcher->autoStartScene)
|
||||
UpdateAutoStartScene(
|
||||
ui->autoStartScenes->currentText());
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::UpdateAutoStartScene(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->autoStartScene = ws;
|
||||
|
||||
obs_weak_source_release(ws);
|
||||
obs_source_release(scene);
|
||||
}
|
||||
|
||||
void SwitcherData::autoStartStreamRecording()
|
||||
{
|
||||
if (autoStartedRecently)
|
||||
return;
|
||||
|
||||
obs_source_t *currentSource = obs_frontend_get_current_scene();
|
||||
obs_weak_source_t *ws = obs_source_get_weak_source(currentSource);
|
||||
|
||||
if (ws && autoStartScene == ws) {
|
||||
if ((switcher->autoStartType == STREAMING ||
|
||||
switcher->autoStartType == RECORINDGSTREAMING) &&
|
||||
!obs_frontend_streaming_active())
|
||||
obs_frontend_streaming_start();
|
||||
if ((switcher->autoStartType == RECORDING ||
|
||||
switcher->autoStartType == RECORINDGSTREAMING) &&
|
||||
!obs_frontend_recording_active())
|
||||
obs_frontend_recording_start();
|
||||
}
|
||||
obs_source_release(currentSource);
|
||||
obs_weak_source_release(ws);
|
||||
|
||||
autoStartedRecently = true;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_verboseLogging_stateChanged(int state)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
switcher->verbose = state;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_uiHintsDisable_stateChanged(int state)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
switcher->disableHints = state;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_exportSettings_clicked()
|
||||
{
|
||||
QString directory = QFileDialog::getSaveFileName(
|
||||
this, tr("Export Advanced Scene Switcher settings to file ..."),
|
||||
QDir::currentPath(), tr("Text files (*.txt)"));
|
||||
if (directory.isEmpty())
|
||||
return;
|
||||
|
||||
QFile file(directory);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
|
||||
return;
|
||||
|
||||
obs_data_t *obj = obs_data_create();
|
||||
|
||||
switcher->saveWindowTitleSwitches(obj);
|
||||
switcher->saveScreenRegionSwitches(obj);
|
||||
switcher->savePauseSwitches(obj);
|
||||
switcher->saveSceneSequenceSwitches(obj);
|
||||
switcher->saveSceneTransitions(obj);
|
||||
switcher->saveIdleSwitches(obj);
|
||||
switcher->saveExecutableSwitches(obj);
|
||||
switcher->saveRandomSwitches(obj);
|
||||
switcher->saveFileSwitches(obj);
|
||||
switcher->saveMediaSwitches(obj);
|
||||
switcher->saveTimeSwitches(obj);
|
||||
switcher->saveAudioSwitches(obj);
|
||||
switcher->saveGeneralSettings(obj);
|
||||
switcher->saveHotkeys(obj);
|
||||
|
||||
obs_data_save_json(obj, file.fileName().toUtf8().constData());
|
||||
|
||||
obs_data_release(obj);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_importSettings_clicked()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
QString directory = QFileDialog::getOpenFileName(
|
||||
this,
|
||||
tr("Import Advanced Scene Switcher settings from file ..."),
|
||||
QDir::currentPath(), tr("Text files (*.txt)"));
|
||||
if (directory.isEmpty())
|
||||
return;
|
||||
|
||||
QFile file(directory);
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
return;
|
||||
|
||||
obs_data_t *obj = obs_data_create_from_json_file(
|
||||
file.fileName().toUtf8().constData());
|
||||
|
||||
if (!obj) {
|
||||
QMessageBox Msgbox;
|
||||
Msgbox.setText(
|
||||
"Advanced Scene Switcher failed to import settings");
|
||||
Msgbox.exec();
|
||||
return;
|
||||
}
|
||||
|
||||
switcher->loadWindowTitleSwitches(obj);
|
||||
switcher->loadScreenRegionSwitches(obj);
|
||||
switcher->loadPauseSwitches(obj);
|
||||
switcher->loadSceneSequenceSwitches(obj);
|
||||
switcher->loadSceneTransitions(obj);
|
||||
switcher->loadIdleSwitches(obj);
|
||||
switcher->loadExecutableSwitches(obj);
|
||||
switcher->loadRandomSwitches(obj);
|
||||
switcher->loadFileSwitches(obj);
|
||||
switcher->loadMediaSwitches(obj);
|
||||
switcher->loadTimeSwitches(obj);
|
||||
switcher->loadAudioSwitches(obj);
|
||||
switcher->loadGeneralSettings(obj);
|
||||
switcher->loadHotkeys(obj);
|
||||
|
||||
obs_data_release(obj);
|
||||
|
||||
QMessageBox Msgbox;
|
||||
Msgbox.setText(
|
||||
"Advanced Scene Switcher settings imported successfully");
|
||||
Msgbox.exec();
|
||||
close();
|
||||
}
|
||||
|
||||
int findTabIndex(QTabBar *bar, int pos)
|
||||
{
|
||||
int at = -1;
|
||||
|
||||
QString tabName = "";
|
||||
switch (pos) {
|
||||
case 0:
|
||||
tabName = "General";
|
||||
break;
|
||||
case 1:
|
||||
tabName = "Transition";
|
||||
break;
|
||||
case 2:
|
||||
tabName = "Pause";
|
||||
break;
|
||||
case 3:
|
||||
tabName = "Title";
|
||||
break;
|
||||
case 4:
|
||||
tabName = "Executable";
|
||||
break;
|
||||
case 5:
|
||||
tabName = "Region";
|
||||
break;
|
||||
case 6:
|
||||
tabName = "Media";
|
||||
break;
|
||||
case 7:
|
||||
tabName = "File";
|
||||
break;
|
||||
case 8:
|
||||
tabName = "Random";
|
||||
break;
|
||||
case 9:
|
||||
tabName = "Time";
|
||||
break;
|
||||
case 10:
|
||||
tabName = "Idle";
|
||||
break;
|
||||
case 11:
|
||||
tabName = "Sequence";
|
||||
break;
|
||||
case 12:
|
||||
tabName = "Audio";
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < bar->count(); ++i) {
|
||||
if (bar->tabText(i).compare(tabName) == 0) {
|
||||
at = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (at == -1)
|
||||
blog(LOG_INFO, "failed to find tab %s",
|
||||
tabName.toUtf8().constData());
|
||||
|
||||
return at;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setTabOrder()
|
||||
{
|
||||
QTabBar *bar = ui->tabWidget->tabBar();
|
||||
for (int i = 0; i < bar->count(); ++i) {
|
||||
int curPos = findTabIndex(bar, switcher->tabOrder[i]);
|
||||
|
||||
if (i != curPos && curPos != -1)
|
||||
bar->moveTab(curPos, i);
|
||||
}
|
||||
|
||||
connect(bar, &QTabBar::tabMoved, this, &AdvSceneSwitcher::on_tabMoved);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_tabMoved(int from, int to)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
std::swap(switcher->tabOrder[from], switcher->tabOrder[to]);
|
||||
}
|
||||
|
||||
void SwitcherData::saveGeneralSettings(obs_data_t *obj)
|
||||
{
|
||||
obs_data_set_int(obj, "interval", switcher->interval);
|
||||
|
||||
std::string nonMatchingSceneName =
|
||||
GetWeakSourceName(switcher->nonMatchingScene);
|
||||
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_int(obj, "startup_behavior", switcher->startupBehavior);
|
||||
|
||||
std::string autoStopSceneName =
|
||||
GetWeakSourceName(switcher->autoStopScene);
|
||||
obs_data_set_bool(obj, "autoStopEnable", switcher->autoStopEnable);
|
||||
obs_data_set_string(obj, "autoStopSceneName",
|
||||
autoStopSceneName.c_str());
|
||||
|
||||
std::string autoStartSceneName =
|
||||
GetWeakSourceName(switcher->autoStartScene);
|
||||
obs_data_set_bool(obj, "autoStartEnable", switcher->autoStartEnable);
|
||||
obs_data_set_int(obj, "autoStartType", switcher->autoStartType);
|
||||
obs_data_set_string(obj, "autoStartSceneName",
|
||||
autoStartSceneName.c_str());
|
||||
|
||||
obs_data_set_bool(obj, "verbose", switcher->verbose);
|
||||
obs_data_set_bool(obj, "disableHints", switcher->disableHints);
|
||||
|
||||
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_int(obj, "priority6",
|
||||
switcher->functionNamesByPriority[6]);
|
||||
obs_data_set_int(obj, "priority7",
|
||||
switcher->functionNamesByPriority[7]);
|
||||
obs_data_set_int(obj, "priority8",
|
||||
switcher->functionNamesByPriority[8]);
|
||||
|
||||
obs_data_set_int(obj, "threadPriority", switcher->threadPriority);
|
||||
|
||||
obs_data_set_int(obj, "generalTabPos", switcher->tabOrder[0]);
|
||||
obs_data_set_int(obj, "transitionTabPos", switcher->tabOrder[1]);
|
||||
obs_data_set_int(obj, "pauseTabPos", switcher->tabOrder[2]);
|
||||
obs_data_set_int(obj, "titleTabPos", switcher->tabOrder[3]);
|
||||
obs_data_set_int(obj, "exeTabPos", switcher->tabOrder[4]);
|
||||
obs_data_set_int(obj, "regionTabPos", switcher->tabOrder[5]);
|
||||
obs_data_set_int(obj, "mediaTabPos", switcher->tabOrder[6]);
|
||||
obs_data_set_int(obj, "fileTabPos", switcher->tabOrder[7]);
|
||||
obs_data_set_int(obj, "randomTabPos", switcher->tabOrder[8]);
|
||||
obs_data_set_int(obj, "timeTabPos", switcher->tabOrder[9]);
|
||||
obs_data_set_int(obj, "idleTabPos", switcher->tabOrder[10]);
|
||||
obs_data_set_int(obj, "sequenceTabPos", switcher->tabOrder[11]);
|
||||
obs_data_set_int(obj, "audioTabPos", switcher->tabOrder[12]);
|
||||
}
|
||||
|
||||
void SwitcherData::loadGeneralSettings(obs_data_t *obj)
|
||||
{
|
||||
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");
|
||||
std::string nonMatchingScene =
|
||||
obs_data_get_string(obj, "non_matching_scene");
|
||||
switcher->nonMatchingScene =
|
||||
GetWeakSourceByName(nonMatchingScene.c_str());
|
||||
|
||||
switcher->stop = !obs_data_get_bool(obj, "active");
|
||||
switcher->startupBehavior =
|
||||
(StartupBehavior)obs_data_get_int(obj, "startup_behavior");
|
||||
if (switcher->startupBehavior == START)
|
||||
switcher->stop = false;
|
||||
if (switcher->startupBehavior == STOP)
|
||||
switcher->stop = true;
|
||||
|
||||
std::string autoStopScene =
|
||||
obs_data_get_string(obj, "autoStopSceneName");
|
||||
switcher->autoStopEnable = obs_data_get_bool(obj, "autoStopEnable");
|
||||
switcher->autoStopScene = GetWeakSourceByName(autoStopScene.c_str());
|
||||
|
||||
std::string autoStartScene =
|
||||
obs_data_get_string(obj, "autoStartSceneName");
|
||||
switcher->autoStartEnable = obs_data_get_bool(obj, "autoStartEnable");
|
||||
switcher->autoStartType =
|
||||
(AutoStartType)obs_data_get_int(obj, "autoStartType");
|
||||
switcher->autoStartScene = GetWeakSourceByName(autoStartScene.c_str());
|
||||
|
||||
switcher->verbose = obs_data_get_bool(obj, "verbose");
|
||||
switcher->disableHints = obs_data_get_bool(obj, "disableHints");
|
||||
|
||||
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);
|
||||
obs_data_set_default_int(obj, "priority6", default_priority_6);
|
||||
obs_data_set_default_int(obj, "priority7", default_priority_7);
|
||||
obs_data_set_default_int(obj, "priority8", default_priority_8);
|
||||
|
||||
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"));
|
||||
switcher->functionNamesByPriority[6] =
|
||||
(obs_data_get_int(obj, "priority6"));
|
||||
switcher->functionNamesByPriority[7] =
|
||||
(obs_data_get_int(obj, "priority7"));
|
||||
switcher->functionNamesByPriority[8] =
|
||||
(obs_data_get_int(obj, "priority8"));
|
||||
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);
|
||||
switcher->functionNamesByPriority[6] = (default_priority_6);
|
||||
switcher->functionNamesByPriority[7] = (default_priority_7);
|
||||
switcher->functionNamesByPriority[8] = (default_priority_8);
|
||||
}
|
||||
|
||||
obs_data_set_default_int(obj, "threadPriority",
|
||||
QThread::NormalPriority);
|
||||
switcher->threadPriority = obs_data_get_int(obj, "threadPriority");
|
||||
|
||||
obs_data_set_default_int(obj, "generalTabPos", 0);
|
||||
obs_data_set_default_int(obj, "transitionTabPos", 1);
|
||||
obs_data_set_default_int(obj, "pauseTabPos", 2);
|
||||
obs_data_set_default_int(obj, "titleTabPos", 3);
|
||||
obs_data_set_default_int(obj, "exeTabPos", 4);
|
||||
obs_data_set_default_int(obj, "regionTabPos", 5);
|
||||
obs_data_set_default_int(obj, "mediaTabPos", 6);
|
||||
obs_data_set_default_int(obj, "fileTabPos", 7);
|
||||
obs_data_set_default_int(obj, "randomTabPos", 8);
|
||||
obs_data_set_default_int(obj, "timeTabPos", 9);
|
||||
obs_data_set_default_int(obj, "idleTabPos", 10);
|
||||
obs_data_set_default_int(obj, "sequenceTabPos", 11);
|
||||
obs_data_set_default_int(obj, "audioTabPos", 12);
|
||||
|
||||
switcher->tabOrder.emplace_back(
|
||||
(int)(obs_data_get_int(obj, "generalTabPos")));
|
||||
switcher->tabOrder.emplace_back(
|
||||
(int)(obs_data_get_int(obj, "transitionTabPos")));
|
||||
switcher->tabOrder.emplace_back(
|
||||
(int)(obs_data_get_int(obj, "pauseTabPos")));
|
||||
switcher->tabOrder.emplace_back(
|
||||
(int)(obs_data_get_int(obj, "titleTabPos")));
|
||||
switcher->tabOrder.emplace_back(
|
||||
(int)(obs_data_get_int(obj, "exeTabPos")));
|
||||
switcher->tabOrder.emplace_back(
|
||||
(int)(obs_data_get_int(obj, "regionTabPos")));
|
||||
switcher->tabOrder.emplace_back(
|
||||
(int)(obs_data_get_int(obj, "mediaTabPos")));
|
||||
switcher->tabOrder.emplace_back(
|
||||
(int)(obs_data_get_int(obj, "fileTabPos")));
|
||||
switcher->tabOrder.emplace_back(
|
||||
(int)(obs_data_get_int(obj, "randomTabPos")));
|
||||
switcher->tabOrder.emplace_back(
|
||||
(int)(obs_data_get_int(obj, "timeTabPos")));
|
||||
switcher->tabOrder.emplace_back(
|
||||
(int)(obs_data_get_int(obj, "idleTabPos")));
|
||||
switcher->tabOrder.emplace_back(
|
||||
(int)(obs_data_get_int(obj, "sequenceTabPos")));
|
||||
switcher->tabOrder.emplace_back(
|
||||
(int)(obs_data_get_int(obj, "audioTabPos")));
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupGeneralTab()
|
||||
{
|
||||
populateSceneSelection(ui->noMatchSwitchScene, false);
|
||||
populateSceneSelection(ui->autoStopScenes, false);
|
||||
populateSceneSelection(ui->autoStartScenes, false);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
ui->autoStartType->addItem("Recording");
|
||||
ui->autoStartType->addItem("Streaming");
|
||||
ui->autoStartType->addItem("Recording and Streaming");
|
||||
|
||||
ui->autoStartSceneCheckBox->setChecked(switcher->autoStartEnable);
|
||||
ui->autoStartScenes->setCurrentText(
|
||||
GetWeakSourceName(switcher->autoStartScene).c_str());
|
||||
ui->autoStartType->setCurrentIndex(switcher->autoStartType);
|
||||
|
||||
if (ui->autoStartSceneCheckBox->checkState()) {
|
||||
ui->autoStartScenes->setDisabled(false);
|
||||
ui->autoStartType->setDisabled(false);
|
||||
} else {
|
||||
ui->autoStartScenes->setDisabled(true);
|
||||
ui->autoStartType->setDisabled(true);
|
||||
}
|
||||
|
||||
ui->verboseLogging->setChecked(switcher->verbose);
|
||||
ui->uiHintsDisable->setChecked(switcher->disableHints);
|
||||
|
||||
for (int p : switcher->functionNamesByPriority) {
|
||||
std::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";
|
||||
break;
|
||||
case media_func:
|
||||
s = "Media";
|
||||
break;
|
||||
case time_func:
|
||||
s = "Time";
|
||||
break;
|
||||
case audio_func:
|
||||
s = "Audio";
|
||||
break;
|
||||
}
|
||||
QString text(s.c_str());
|
||||
QListWidgetItem *item =
|
||||
new QListWidgetItem(text, ui->priorityList);
|
||||
item->setData(Qt::UserRole, text);
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)switcher->threadPriorities.size(); ++i) {
|
||||
ui->threadPriority->addItem(
|
||||
switcher->threadPriorities[i].name.c_str());
|
||||
ui->threadPriority->setItemData(
|
||||
i, switcher->threadPriorities[i].description.c_str(),
|
||||
Qt::ToolTipRole);
|
||||
if (switcher->threadPriority ==
|
||||
switcher->threadPriorities[i].value) {
|
||||
ui->threadPriority->setCurrentText(
|
||||
switcher->threadPriorities[i].name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
ui->startupBehavior->addItem(
|
||||
"Start the scene switcher if it was running");
|
||||
ui->startupBehavior->addItem("Always start the scene switcher");
|
||||
ui->startupBehavior->addItem("Do not start the scene switcher");
|
||||
|
||||
ui->startupBehavior->setCurrentIndex(switcher->startupBehavior);
|
||||
|
||||
if (switcher->th && switcher->th->isRunning())
|
||||
SetStarted();
|
||||
else
|
||||
SetStopped();
|
||||
}
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#ifdef BUILD_OUT_OF_TREE
|
||||
#include "../../forms/ui_advanced-scene-switcher.h"
|
||||
#else
|
||||
@@ -11,59 +6,94 @@
|
||||
#endif
|
||||
#include "switcher-data-structs.hpp"
|
||||
|
||||
#define blog(level, msg, ...) blog(level, "[adv-ss] " msg, ##__VA_ARGS__)
|
||||
|
||||
class QCloseEvent;
|
||||
|
||||
/*******************************************************************************
|
||||
* Advanced Scene Switcher window
|
||||
*******************************************************************************/
|
||||
class SceneSwitcher : public QDialog {
|
||||
class AdvSceneSwitcher : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
std::unique_ptr<Ui_SceneSwitcher> ui;
|
||||
std::unique_ptr<Ui_AdvSceneSwitcher> ui;
|
||||
bool loading = true;
|
||||
|
||||
SceneSwitcher(QWidget *parent);
|
||||
AdvSceneSwitcher(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);
|
||||
int timeFindByData(const QString &timeStr);
|
||||
|
||||
void UpdateNonMatchingScene(const QString &name);
|
||||
void UpdateAutoStopScene(const QString &name);
|
||||
void UpdateAutoStartScene(const QString &name);
|
||||
void UpdateIdleDataTransition(const QString &name);
|
||||
void UpdateIdleDataScene(const QString &name);
|
||||
|
||||
void loadUI();
|
||||
void setupGeneralTab();
|
||||
void setupTitleTab();
|
||||
void setupExecutableTab();
|
||||
void setupRegionTab();
|
||||
void setupPauseTab();
|
||||
void setupSequenceTab();
|
||||
void setupTransitionsTab();
|
||||
void setupIdleTab();
|
||||
void setupRandomTab();
|
||||
void setupMediaTab();
|
||||
void setupFileTab();
|
||||
void setupTimeTab();
|
||||
void setupAudioTab();
|
||||
void setTabOrder();
|
||||
|
||||
static void populateSceneSelection(QComboBox *sel,
|
||||
bool addPrevious = false,
|
||||
bool addSelect = true);
|
||||
static void populateTransitionSelection(QComboBox *sel,
|
||||
bool addSelect = true);
|
||||
static void populateWindowSelection(QComboBox *sel,
|
||||
bool addSelect = true);
|
||||
static void populateAudioSelection(QComboBox *sel,
|
||||
bool addSelect = true);
|
||||
static void populateMediaSelection(QComboBox *sel,
|
||||
bool addSelect = true);
|
||||
static void populateProcessSelection(QComboBox *sel,
|
||||
bool addSelect = true);
|
||||
QMetaObject::Connection PulseWidget(QWidget *widget, QColor endColor,
|
||||
QColor = QColor(0, 0, 0, 0),
|
||||
QString specifier = "QLabel ");
|
||||
|
||||
bool listMoveUp(QListWidget *list);
|
||||
bool listMoveDown(QListWidget *list);
|
||||
|
||||
public slots:
|
||||
void on_switches_currentRowChanged(int idx);
|
||||
void on_add_clicked();
|
||||
void on_remove_clicked();
|
||||
void on_windowUp_clicked();
|
||||
void on_windowDown_clicked();
|
||||
void on_windowAdd_clicked();
|
||||
void on_windowRemove_clicked();
|
||||
void on_noMatchDontSwitch_clicked();
|
||||
void on_noMatchSwitch_clicked();
|
||||
void on_noMatchRandomSwitch_clicked();
|
||||
void on_startAtLaunch_toggled(bool value);
|
||||
void on_startupBehavior_currentIndexChanged(int index);
|
||||
void on_noMatchSwitchScene_currentTextChanged(const QString &text);
|
||||
void on_checkInterval_valueChanged(int value);
|
||||
void on_toggleStartButton_clicked();
|
||||
void on_tabMoved(int from, int to);
|
||||
|
||||
void on_screenRegions_currentRowChanged(int idx);
|
||||
void on_screenRegionSwitches_currentRowChanged(int idx);
|
||||
void on_showFrame_clicked();
|
||||
void on_screenRegionAdd_clicked();
|
||||
void on_screenRegionRemove_clicked();
|
||||
void on_screenRegionUp_clicked();
|
||||
void on_screenRegionDown_clicked();
|
||||
|
||||
void on_pauseScenes_currentRowChanged(int idx);
|
||||
void on_pauseScenesAdd_clicked();
|
||||
@@ -77,31 +107,47 @@ public slots:
|
||||
void on_ignoreWindowsAdd_clicked();
|
||||
void on_ignoreWindowsRemove_clicked();
|
||||
|
||||
void on_sceneRoundTrips_currentRowChanged(int idx);
|
||||
void on_sceneRoundTripAdd_clicked();
|
||||
void on_sceneRoundTripRemove_clicked();
|
||||
void on_sceneRoundTripSave_clicked();
|
||||
void on_sceneRoundTripLoad_clicked();
|
||||
void on_sceneSequenceAdd_clicked();
|
||||
void on_sceneSequenceRemove_clicked();
|
||||
void on_sceneSequenceSave_clicked();
|
||||
void on_sceneSequenceLoad_clicked();
|
||||
void on_sceneSequenceUp_clicked();
|
||||
void on_sceneSequenceDown_clicked();
|
||||
|
||||
void on_autoStopSceneCheckBox_stateChanged(int state);
|
||||
void on_autoStopScenes_currentTextChanged(const QString &text);
|
||||
|
||||
void on_sceneTransitions_currentRowChanged(int idx);
|
||||
void on_autoStartSceneCheckBox_stateChanged(int state);
|
||||
void on_autoStartType_currentIndexChanged(int index);
|
||||
void on_autoStartScenes_currentTextChanged(const QString &text);
|
||||
|
||||
void on_verboseLogging_stateChanged(int state);
|
||||
void on_uiHintsDisable_stateChanged(int state);
|
||||
|
||||
void on_exportSettings_clicked();
|
||||
void on_importSettings_clicked();
|
||||
|
||||
void on_transitionsAdd_clicked();
|
||||
void on_transitionsRemove_clicked();
|
||||
void on_defaultTransitions_currentRowChanged(int idx);
|
||||
void on_transitionsUp_clicked();
|
||||
void on_transitionsDown_clicked();
|
||||
void on_defaultTransitionsAdd_clicked();
|
||||
void on_defaultTransitionsRemove_clicked();
|
||||
void on_defaultTransitionsUp_clicked();
|
||||
void on_defaultTransitionsDown_clicked();
|
||||
void on_transitionOverridecheckBox_stateChanged(int state);
|
||||
|
||||
void on_browseButton_clicked();
|
||||
void on_readFileCheckBox_stateChanged(int state);
|
||||
void on_fileType_currentIndexChanged(int idx);
|
||||
void on_readPathLineEdit_textChanged(const QString &text);
|
||||
void on_writePathLineEdit_textChanged(const QString &text);
|
||||
void on_browseButton_2_clicked();
|
||||
|
||||
void on_executableUp_clicked();
|
||||
void on_executableDown_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);
|
||||
@@ -113,39 +159,53 @@ public slots:
|
||||
|
||||
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_fileUp_clicked();
|
||||
void on_fileDown_clicked();
|
||||
|
||||
void on_mediaAdd_clicked();
|
||||
void on_mediaRemove_clicked();
|
||||
void on_mediaUp_clicked();
|
||||
void on_mediaDown_clicked();
|
||||
|
||||
void on_timeSwitches_currentRowChanged(int idx);
|
||||
void on_timeAdd_clicked();
|
||||
void on_timeRemove_clicked();
|
||||
void on_timeUp_clicked();
|
||||
void on_timeDown_clicked();
|
||||
|
||||
void on_audioAdd_clicked();
|
||||
void on_audioRemove_clicked();
|
||||
void on_audioUp_clicked();
|
||||
void on_audioDown_clicked();
|
||||
|
||||
void on_priorityUp_clicked();
|
||||
void on_priorityDown_clicked();
|
||||
void on_threadPriority_currentTextChanged(const QString &text);
|
||||
|
||||
void updateScreenRegionCursorPos();
|
||||
|
||||
void on_close_clicked();
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
/********************************************************************************
|
||||
* Windowtitle helper
|
||||
********************************************************************************/
|
||||
void GetWindowList(std::vector<std::string> &windows);
|
||||
void GetWindowList(QStringList &windows); // Overloaded
|
||||
void GetCurrentWindowTitle(std::string &title);
|
||||
bool isFullscreen();
|
||||
bool isFullscreen(std::string &title);
|
||||
bool isMaximized(std::string &title);
|
||||
|
||||
/********************************************************************************
|
||||
* Screenregion helper
|
||||
********************************************************************************/
|
||||
pair<int, int> getCursorPos();
|
||||
std::pair<int, int> getCursorPos();
|
||||
|
||||
/********************************************************************************
|
||||
* Idle detection helper
|
||||
@@ -156,34 +216,22 @@ int secondsSinceLastInput();
|
||||
* Executable helper
|
||||
********************************************************************************/
|
||||
void GetProcessList(QStringList &processes);
|
||||
bool isInFocus(const QString &exeToCheck);
|
||||
bool isInFocus(const QString &executable);
|
||||
|
||||
/********************************************************************************
|
||||
* 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 setNextTransition(OBSWeakSource &targetScene, obs_source_t *currentSource,
|
||||
OBSWeakSource &transition,
|
||||
bool &transitionOverrideOverride, transitionData &td);
|
||||
void overwriteTransitionOverride(obs_weak_source_t *sceneWs,
|
||||
obs_source_t *transition, transitionData &td);
|
||||
void restoreTransitionOverride(obs_source_t *scene, transitionData td);
|
||||
|
||||
void switchScene(OBSWeakSource &scene, OBSWeakSource &transition,
|
||||
unique_lock<mutex> &lock);
|
||||
|
||||
/********************************************************************************
|
||||
* Hotkey helper
|
||||
********************************************************************************/
|
||||
|
||||
#define TOGGLE_HOTKEY_PATH "hotkey_toggle.txt"
|
||||
#define STOP_HOTKEY_PATH "hotkey_stop.txt"
|
||||
#define START_HOTKEY_PATH "hotkey_start.txt"
|
||||
|
||||
void stopHotkeyFunc(void *data, obs_hotkey_id id, obs_hotkey_t *hotkey,
|
||||
bool pressed);
|
||||
void startHotkeyFunc(void *data, obs_hotkey_id id, obs_hotkey_t *hotkey,
|
||||
bool pressed);
|
||||
void startStopToggleHotkeyFunc(void *data, obs_hotkey_id id,
|
||||
obs_hotkey_t *hotkey, bool pressed);
|
||||
void loadKeybinding(obs_hotkey_id hotkeyId, string path);
|
||||
bool &transitionOverrideOverride,
|
||||
std::unique_lock<std::mutex> &lock);
|
||||
|
||||
/********************************************************************************
|
||||
* Main SwitcherData
|
||||
|
||||
26
src/headers/curl-helper.hpp
Normal file
26
src/headers/curl-helper.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#include <curl/curl.h>
|
||||
#include <QLibrary>
|
||||
|
||||
#if defined(WIN32)
|
||||
constexpr auto curl_library_name = "libcurl.dll";
|
||||
#elif __APPLE__
|
||||
#define curl_library_name "libcurl.4.dylib"
|
||||
#else
|
||||
#define curl_library_name "libcurl.so.4"
|
||||
#endif
|
||||
|
||||
typedef CURL *(*initFunction)(void);
|
||||
typedef CURLcode (*setOptFunction)(CURL *, CURLoption, ...);
|
||||
typedef CURLcode (*performFunction)(CURL *);
|
||||
typedef void (*cleanupFunction)(CURL *);
|
||||
|
||||
extern initFunction f_curl_init;
|
||||
extern setOptFunction f_curl_setopt;
|
||||
extern performFunction f_curl_perform;
|
||||
extern cleanupFunction f_curl_cleanup;
|
||||
|
||||
extern QLibrary *loaded_curl_lib;
|
||||
|
||||
bool resolveCurl();
|
||||
bool loadCurl();
|
||||
65
src/headers/switch-audio.hpp
Normal file
65
src/headers/switch-audio.hpp
Normal file
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
#include <QSpinBox>
|
||||
|
||||
#include "switch-generic.hpp"
|
||||
#include "volume-control.hpp"
|
||||
|
||||
constexpr auto audio_func = 8;
|
||||
constexpr auto default_priority_8 = audio_func;
|
||||
|
||||
struct AudioSwitch : virtual SceneSwitcherEntry {
|
||||
OBSWeakSource audioSource = nullptr;
|
||||
int volumeThreshold = 0;
|
||||
float peak = -1;
|
||||
obs_volmeter_t *volmeter = nullptr;
|
||||
|
||||
const char *getType() { return "audio"; }
|
||||
bool initialized();
|
||||
bool valid();
|
||||
static void setVolumeLevel(void *data,
|
||||
const float magnitude[MAX_AUDIO_CHANNELS],
|
||||
const float peak[MAX_AUDIO_CHANNELS],
|
||||
const float inputPeak[MAX_AUDIO_CHANNELS]);
|
||||
void resetVolmeter();
|
||||
|
||||
AudioSwitch(){};
|
||||
AudioSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
||||
OBSWeakSource audioSource_, int volumeThreshold_,
|
||||
bool usePreviousScene_);
|
||||
AudioSwitch(const AudioSwitch &other);
|
||||
AudioSwitch(AudioSwitch &&other);
|
||||
~AudioSwitch();
|
||||
AudioSwitch &operator=(const AudioSwitch &other);
|
||||
AudioSwitch &operator=(AudioSwitch &&other) noexcept;
|
||||
friend void swap(AudioSwitch &first, AudioSwitch &second);
|
||||
};
|
||||
|
||||
class AudioSwitchWidget : public SwitchWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AudioSwitchWidget(AudioSwitch *s);
|
||||
void UpdateVolmeterSource();
|
||||
AudioSwitch *getSwitchData();
|
||||
void setSwitchData(AudioSwitch *s);
|
||||
|
||||
static void swapSwitchData(AudioSwitchWidget *as1,
|
||||
AudioSwitchWidget *as2);
|
||||
|
||||
private slots:
|
||||
void SourceChanged(const QString &text);
|
||||
void VolumeThresholdChanged(int vol);
|
||||
|
||||
private:
|
||||
QComboBox *audioSources;
|
||||
QSpinBox *audioVolumeThreshold;
|
||||
|
||||
VolControl *volMeter;
|
||||
|
||||
QLabel *whenLabel;
|
||||
QLabel *aboveLabel;
|
||||
QLabel *switchLabel;
|
||||
QLabel *usingLabel;
|
||||
|
||||
AudioSwitch *switchData;
|
||||
};
|
||||
48
src/headers/switch-executable.hpp
Normal file
48
src/headers/switch-executable.hpp
Normal file
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
#include <QCheckBox>
|
||||
#include "switch-generic.hpp"
|
||||
|
||||
constexpr auto exe_func = 3;
|
||||
constexpr auto default_priority_3 = exe_func;
|
||||
|
||||
struct ExecutableSwitch : SceneSwitcherEntry {
|
||||
QString exe = "";
|
||||
bool inFocus = false;
|
||||
|
||||
const char *getType() { return "exec"; }
|
||||
|
||||
inline ExecutableSwitch(){};
|
||||
inline ExecutableSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
||||
const QString &exe_, bool inFocus_)
|
||||
: SceneSwitcherEntry(scene_, transition_),
|
||||
exe(exe_),
|
||||
inFocus(inFocus_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class ExecutableSwitchWidget : public SwitchWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ExecutableSwitchWidget(ExecutableSwitch *s);
|
||||
ExecutableSwitch *getSwitchData();
|
||||
void setSwitchData(ExecutableSwitch *s);
|
||||
|
||||
static void swapSwitchData(ExecutableSwitchWidget *s1,
|
||||
ExecutableSwitchWidget *s2);
|
||||
|
||||
private slots:
|
||||
void ProcessChanged(const QString &text);
|
||||
void FocusChanged(int state);
|
||||
|
||||
private:
|
||||
QComboBox *processes;
|
||||
QCheckBox *requiresFocus;
|
||||
|
||||
QLabel *whenLabel;
|
||||
QLabel *switchLabel;
|
||||
QLabel *usingLabel;
|
||||
|
||||
ExecutableSwitch *switchData;
|
||||
};
|
||||
42
src/headers/switch-file.hpp
Normal file
42
src/headers/switch-file.hpp
Normal file
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
#include "switch-generic.hpp"
|
||||
|
||||
constexpr auto read_file_func = 0;
|
||||
constexpr auto default_priority_0 = read_file_func;
|
||||
|
||||
struct FileSwitch : SceneSwitcherEntry {
|
||||
std::string file;
|
||||
std::string text;
|
||||
bool remote = false;
|
||||
bool useRegex = false;
|
||||
bool useTime = false;
|
||||
QDateTime lastMod;
|
||||
|
||||
const char *getType() { return "file"; }
|
||||
|
||||
inline FileSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
||||
const char *file_, const char *text_, bool remote_,
|
||||
bool useRegex_, bool useTime_)
|
||||
: SceneSwitcherEntry(scene_, transition_),
|
||||
file(file_),
|
||||
text(text_),
|
||||
remote(remote_),
|
||||
useRegex(useRegex_),
|
||||
useTime(useTime_),
|
||||
lastMod()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct FileIOData {
|
||||
bool readEnabled = false;
|
||||
std::string readPath;
|
||||
bool writeEnabled = false;
|
||||
std::string writePath;
|
||||
};
|
||||
|
||||
static inline QString MakeFileSwitchName(const QString &scene,
|
||||
const QString &transition,
|
||||
const QString &fileName,
|
||||
const QString &text, bool useRegex,
|
||||
bool useTime);
|
||||
50
src/headers/switch-generic.hpp
Normal file
50
src/headers/switch-generic.hpp
Normal file
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
#include <obs.hpp>
|
||||
#include <QComboBox>
|
||||
|
||||
struct SceneSwitcherEntry {
|
||||
OBSWeakSource scene = nullptr;
|
||||
OBSWeakSource transition = nullptr;
|
||||
bool usePreviousScene = false;
|
||||
|
||||
virtual const char *getType() = 0;
|
||||
virtual bool initialized();
|
||||
virtual bool valid();
|
||||
virtual void logMatch();
|
||||
|
||||
inline SceneSwitcherEntry() {}
|
||||
|
||||
inline SceneSwitcherEntry(OBSWeakSource scene_,
|
||||
OBSWeakSource transition_,
|
||||
bool usePreviousScene_ = false)
|
||||
: scene(scene_),
|
||||
transition(transition_),
|
||||
usePreviousScene(usePreviousScene_)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~SceneSwitcherEntry() {}
|
||||
};
|
||||
|
||||
class SwitchWidget : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SwitchWidget(SceneSwitcherEntry *s, bool usePreviousScene = true);
|
||||
virtual SceneSwitcherEntry *getSwitchData();
|
||||
virtual void setSwitchData(SceneSwitcherEntry *s);
|
||||
|
||||
static void swapSwitchData(SwitchWidget *s1, SwitchWidget *s2);
|
||||
|
||||
private slots:
|
||||
void SceneChanged(const QString &text);
|
||||
void TransitionChanged(const QString &text);
|
||||
|
||||
protected:
|
||||
bool loading = true;
|
||||
|
||||
QComboBox *scenes;
|
||||
QComboBox *transitions;
|
||||
|
||||
SceneSwitcherEntry *switchData;
|
||||
};
|
||||
14
src/headers/switch-idle.hpp
Normal file
14
src/headers/switch-idle.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include "switch-generic.hpp"
|
||||
|
||||
constexpr auto default_idle_time = 60;
|
||||
constexpr auto idle_func = 2;
|
||||
constexpr auto default_priority_2 = idle_func;
|
||||
|
||||
struct IdleData : SceneSwitcherEntry {
|
||||
bool idleEnable = false;
|
||||
int time = default_idle_time;
|
||||
bool alreadySwitched = false;
|
||||
|
||||
const char *getType() { return "idle"; }
|
||||
};
|
||||
79
src/headers/switch-media.hpp
Normal file
79
src/headers/switch-media.hpp
Normal file
@@ -0,0 +1,79 @@
|
||||
#pragma once
|
||||
#include "switch-generic.hpp"
|
||||
|
||||
constexpr auto media_func = 6;
|
||||
constexpr auto default_priority_6 = media_func;
|
||||
|
||||
typedef enum {
|
||||
TIME_RESTRICTION_NONE,
|
||||
TIME_RESTRICTION_SHORTER,
|
||||
TIME_RESTRICTION_LONGER,
|
||||
TIME_RESTRICTION_REMAINING_SHORTER,
|
||||
TIME_RESTRICTION_REMAINING_LONGER,
|
||||
} time_restriction;
|
||||
|
||||
struct MediaSwitch : SceneSwitcherEntry {
|
||||
OBSWeakSource source = nullptr;
|
||||
obs_media_state state = OBS_MEDIA_STATE_NONE;
|
||||
bool anyState = false;
|
||||
time_restriction restriction = TIME_RESTRICTION_NONE;
|
||||
int64_t time = 0;
|
||||
std::atomic<bool> stopped = false;
|
||||
std::atomic<bool> ended = false;
|
||||
|
||||
// workaround to enable use of "ended" to specify end of VLC playlist
|
||||
bool previousStateEnded = false;
|
||||
|
||||
const char *getType() { return "media"; }
|
||||
bool initialized();
|
||||
bool valid();
|
||||
|
||||
void clearSignalHandler();
|
||||
void resetSignalHandler();
|
||||
static void MediaStopped(void *data, calldata_t *);
|
||||
static void MediaEnded(void *data, calldata_t *);
|
||||
|
||||
inline MediaSwitch(){};
|
||||
inline MediaSwitch(OBSWeakSource scene_, OBSWeakSource source_,
|
||||
OBSWeakSource transition_, obs_media_state state_,
|
||||
time_restriction restriction_, uint64_t time_,
|
||||
bool usePreviousScene_);
|
||||
MediaSwitch(const MediaSwitch &other);
|
||||
MediaSwitch(MediaSwitch &&other);
|
||||
~MediaSwitch();
|
||||
MediaSwitch &operator=(const MediaSwitch &other);
|
||||
MediaSwitch &operator=(MediaSwitch &&other) noexcept;
|
||||
friend void swap(MediaSwitch &first, MediaSwitch &second);
|
||||
};
|
||||
|
||||
class MediaSwitchWidget : public SwitchWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MediaSwitchWidget(MediaSwitch *s);
|
||||
MediaSwitch *getSwitchData();
|
||||
void setSwitchData(MediaSwitch *s);
|
||||
|
||||
static void swapSwitchData(MediaSwitchWidget *s1,
|
||||
MediaSwitchWidget *s2);
|
||||
|
||||
private slots:
|
||||
void SourceChanged(const QString &text);
|
||||
void StateChanged(int index);
|
||||
void TimeRestrictionChanged(int index);
|
||||
void TimeChanged(int time);
|
||||
|
||||
private:
|
||||
QComboBox *meidaSources;
|
||||
QComboBox *states;
|
||||
QComboBox *timeRestrictions;
|
||||
QSpinBox *time;
|
||||
|
||||
QLabel *whenLabel;
|
||||
QLabel *stateLabel;
|
||||
QLabel *andLabel;
|
||||
QLabel *switchLabel;
|
||||
QLabel *usingLabel;
|
||||
|
||||
MediaSwitch *switchData;
|
||||
};
|
||||
39
src/headers/switch-random.hpp
Normal file
39
src/headers/switch-random.hpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
#include "switch-generic.hpp"
|
||||
|
||||
struct RandomSwitch : SceneSwitcherEntry {
|
||||
double delay = 0.0;
|
||||
|
||||
const char *getType() { return "random"; }
|
||||
|
||||
inline RandomSwitch() {}
|
||||
inline RandomSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
||||
double delay_)
|
||||
: SceneSwitcherEntry(scene_, transition_), delay(delay_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class RandomSwitchWidget : public SwitchWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
RandomSwitchWidget(RandomSwitch *s);
|
||||
RandomSwitch *getSwitchData();
|
||||
void setSwitchData(RandomSwitch *s);
|
||||
|
||||
static void swapSwitchData(RandomSwitchWidget *s1,
|
||||
RandomSwitchWidget *s2);
|
||||
|
||||
private slots:
|
||||
void DelayChanged(double d);
|
||||
|
||||
private:
|
||||
QDoubleSpinBox *delay;
|
||||
|
||||
QLabel *switchLabel;
|
||||
QLabel *usingLabel;
|
||||
QLabel *forLabel;
|
||||
|
||||
RandomSwitch *switchData;
|
||||
};
|
||||
62
src/headers/switch-screen-region.hpp
Normal file
62
src/headers/switch-screen-region.hpp
Normal file
@@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
#include <QSpinBox>
|
||||
#include "switch-generic.hpp"
|
||||
|
||||
constexpr auto screen_region_func = 4;
|
||||
constexpr auto default_priority_4 = screen_region_func;
|
||||
|
||||
struct ScreenRegionSwitch : SceneSwitcherEntry {
|
||||
int minX = 0, minY = 0, maxX = 0, maxY = 0;
|
||||
|
||||
const char *getType() { return "region"; }
|
||||
|
||||
inline ScreenRegionSwitch(){};
|
||||
inline ScreenRegionSwitch(OBSWeakSource scene_,
|
||||
OBSWeakSource transition_, int minX_,
|
||||
int minY_, int maxX_, int maxY_)
|
||||
: SceneSwitcherEntry(scene_, transition_),
|
||||
minX(minX_),
|
||||
minY(minY_),
|
||||
maxX(maxX_),
|
||||
maxY(maxY_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class ScreenRegionWidget : public SwitchWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ScreenRegionWidget(ScreenRegionSwitch *s);
|
||||
ScreenRegionSwitch *getSwitchData();
|
||||
void setSwitchData(ScreenRegionSwitch *s);
|
||||
|
||||
static void swapSwitchData(ScreenRegionWidget *s1,
|
||||
ScreenRegionWidget *s2);
|
||||
|
||||
void showFrame();
|
||||
void hideFrame();
|
||||
|
||||
private slots:
|
||||
void MinXChanged(int pos);
|
||||
void MinYChanged(int pos);
|
||||
void MaxXChanged(int pos);
|
||||
void MaxYChanged(int pos);
|
||||
|
||||
private:
|
||||
QSpinBox *minX;
|
||||
QSpinBox *minY;
|
||||
QSpinBox *maxX;
|
||||
QSpinBox *maxY;
|
||||
|
||||
QFrame helperFrame;
|
||||
|
||||
QLabel *cursorLabel;
|
||||
QLabel *xLabel;
|
||||
QLabel *switchLabel;
|
||||
QLabel *usingLabel;
|
||||
|
||||
ScreenRegionSwitch *switchData;
|
||||
|
||||
void drawFrame();
|
||||
};
|
||||
64
src/headers/switch-sequence.hpp
Normal file
64
src/headers/switch-sequence.hpp
Normal file
@@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
#include "switch-generic.hpp"
|
||||
|
||||
constexpr auto round_trip_func = 1;
|
||||
constexpr auto default_priority_1 = round_trip_func;
|
||||
|
||||
typedef enum {
|
||||
SECONDS,
|
||||
MINUTES,
|
||||
HOURS,
|
||||
} delay_units;
|
||||
|
||||
struct SceneSequenceSwitch : SceneSwitcherEntry {
|
||||
OBSWeakSource startScene = nullptr;
|
||||
double delay = 0;
|
||||
int delayMultiplier = 1;
|
||||
|
||||
const char *getType() { return "sequence"; }
|
||||
bool initialized();
|
||||
bool valid();
|
||||
void logSleep(int dur);
|
||||
|
||||
inline SceneSequenceSwitch(){};
|
||||
inline SceneSequenceSwitch(OBSWeakSource startScene_,
|
||||
OBSWeakSource scene_,
|
||||
OBSWeakSource transition_, double delay_,
|
||||
int delayMultiplier_, bool usePreviousScene_)
|
||||
: SceneSwitcherEntry(scene_, transition_, usePreviousScene_),
|
||||
startScene(startScene_),
|
||||
delay(delay_),
|
||||
delayMultiplier(delayMultiplier_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class SequenceWidget : public SwitchWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SequenceWidget(SceneSequenceSwitch *s);
|
||||
SceneSequenceSwitch *getSwitchData();
|
||||
void setSwitchData(SceneSequenceSwitch *s);
|
||||
|
||||
static void swapSwitchData(SequenceWidget *s1, SequenceWidget *s2);
|
||||
|
||||
void UpdateDelay();
|
||||
|
||||
private slots:
|
||||
void DelayChanged(double delay);
|
||||
void DelayUnitsChanged(int idx);
|
||||
void StartSceneChanged(const QString &text);
|
||||
|
||||
private:
|
||||
QDoubleSpinBox *delay;
|
||||
QComboBox *delayUnits;
|
||||
QComboBox *startScenes;
|
||||
|
||||
QLabel *whenLabel;
|
||||
QLabel *switchLabel;
|
||||
QLabel *afterLabel;
|
||||
QLabel *usingLabel;
|
||||
|
||||
SceneSequenceSwitch *switchData;
|
||||
};
|
||||
61
src/headers/switch-time.hpp
Normal file
61
src/headers/switch-time.hpp
Normal file
@@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
#include <QTimeEdit>
|
||||
|
||||
#include "switch-generic.hpp"
|
||||
|
||||
constexpr auto time_func = 7;
|
||||
constexpr auto default_priority_7 = time_func;
|
||||
|
||||
typedef enum {
|
||||
ANY_DAY = 0,
|
||||
MONDAY = 1,
|
||||
TUSEDAY = 2,
|
||||
WEDNESDAY = 3,
|
||||
THURSDAY = 4,
|
||||
FRIDAY = 5,
|
||||
SATURDAY = 6,
|
||||
SUNDAY = 7,
|
||||
LIVE = 8
|
||||
} timeTrigger;
|
||||
|
||||
struct TimeSwitch : SceneSwitcherEntry {
|
||||
timeTrigger trigger = ANY_DAY;
|
||||
QTime time = QTime();
|
||||
|
||||
const char *getType() { return "time"; }
|
||||
|
||||
inline TimeSwitch(){};
|
||||
inline TimeSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
||||
timeTrigger trigger_, QTime time_,
|
||||
bool usePreviousScene_)
|
||||
: SceneSwitcherEntry(scene_, transition_, usePreviousScene_),
|
||||
trigger(trigger_),
|
||||
time(time_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class TimeSwitchWidget : public SwitchWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TimeSwitchWidget(TimeSwitch *s);
|
||||
TimeSwitch *getSwitchData();
|
||||
void setSwitchData(TimeSwitch *s);
|
||||
|
||||
static void swapSwitchData(TimeSwitchWidget *s1, TimeSwitchWidget *s2);
|
||||
|
||||
private slots:
|
||||
void TriggerChanged(int index);
|
||||
void TimeChanged(const QTime &time);
|
||||
|
||||
private:
|
||||
QComboBox *triggers;
|
||||
QTimeEdit *time;
|
||||
|
||||
QLabel *atLabel;
|
||||
QLabel *switchLabel;
|
||||
QLabel *usingLabel;
|
||||
|
||||
TimeSwitch *switchData;
|
||||
};
|
||||
71
src/headers/switch-transitions.hpp
Normal file
71
src/headers/switch-transitions.hpp
Normal file
@@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
#include "switch-generic.hpp"
|
||||
|
||||
struct SceneTransition : SceneSwitcherEntry {
|
||||
OBSWeakSource scene2 = nullptr;
|
||||
|
||||
const char *getType() { return "transition"; }
|
||||
bool initialized();
|
||||
bool valid();
|
||||
|
||||
inline SceneTransition(){};
|
||||
inline SceneTransition(OBSWeakSource scene_, OBSWeakSource scene2_,
|
||||
OBSWeakSource transition_)
|
||||
: SceneSwitcherEntry(scene_, transition_), scene2(scene2_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct DefaultSceneTransition : SceneSwitcherEntry {
|
||||
|
||||
const char *getType() { return "def_transition"; }
|
||||
|
||||
inline DefaultSceneTransition(){};
|
||||
inline DefaultSceneTransition(OBSWeakSource scene_,
|
||||
OBSWeakSource transition_)
|
||||
: SceneSwitcherEntry(scene_, transition_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class TransitionSwitchWidget : public SwitchWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TransitionSwitchWidget(SceneTransition *s);
|
||||
SceneTransition *getSwitchData();
|
||||
void setSwitchData(SceneTransition *s);
|
||||
|
||||
static void swapSwitchData(TransitionSwitchWidget *s1,
|
||||
TransitionSwitchWidget *s2);
|
||||
|
||||
private slots:
|
||||
void Scene2Changed(const QString &text);
|
||||
|
||||
private:
|
||||
QComboBox *scenes2;
|
||||
|
||||
QLabel *switchLabel;
|
||||
QLabel *toLabel;
|
||||
QLabel *usingLabel;
|
||||
|
||||
SceneTransition *switchData;
|
||||
};
|
||||
|
||||
class DefTransitionSwitchWidget : public SwitchWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DefTransitionSwitchWidget(DefaultSceneTransition *s);
|
||||
DefaultSceneTransition *getSwitchData();
|
||||
void setSwitchData(DefaultSceneTransition *s);
|
||||
|
||||
static void swapSwitchData(DefTransitionSwitchWidget *s1,
|
||||
DefTransitionSwitchWidget *s2);
|
||||
|
||||
private:
|
||||
QLabel *whenLabel;
|
||||
QLabel *switchLabel;
|
||||
|
||||
DefaultSceneTransition *switchData;
|
||||
};
|
||||
52
src/headers/switch-window.hpp
Normal file
52
src/headers/switch-window.hpp
Normal file
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
#include "switch-generic.hpp"
|
||||
|
||||
constexpr auto window_title_func = 5;
|
||||
constexpr auto default_priority_5 = window_title_func;
|
||||
|
||||
struct WindowSwitch : SceneSwitcherEntry {
|
||||
std::string window = "";
|
||||
bool fullscreen = false;
|
||||
bool maximized = false;
|
||||
bool focus = true;
|
||||
|
||||
const char *getType() { return "window"; }
|
||||
|
||||
inline WindowSwitch() {}
|
||||
inline WindowSwitch(OBSWeakSource scene_, const char *window_,
|
||||
OBSWeakSource transition_, bool fullscreen_,
|
||||
bool maximized_, bool focus_)
|
||||
: SceneSwitcherEntry(scene_, transition_),
|
||||
window(window_),
|
||||
fullscreen(fullscreen_),
|
||||
maximized(maximized_),
|
||||
focus(focus_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class WindowSwitchWidget : public SwitchWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
WindowSwitchWidget(WindowSwitch *s);
|
||||
WindowSwitch *getSwitchData();
|
||||
void setSwitchData(WindowSwitch *s);
|
||||
|
||||
static void swapSwitchData(WindowSwitchWidget *s1,
|
||||
WindowSwitchWidget *s2);
|
||||
|
||||
private slots:
|
||||
void WindowChanged(const QString &text);
|
||||
void FullscreenChanged(int state);
|
||||
void MaximizedChanged(int state);
|
||||
void FocusChanged(int state);
|
||||
|
||||
private:
|
||||
QComboBox *windows;
|
||||
QCheckBox *fullscreen;
|
||||
QCheckBox *maximized;
|
||||
QCheckBox *focused;
|
||||
|
||||
WindowSwitch *switchData;
|
||||
};
|
||||
@@ -1,326 +1,152 @@
|
||||
#pragma once
|
||||
#include <condition_variable>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <regex>
|
||||
#include <deque>
|
||||
#include <mutex>
|
||||
#include <fstream>
|
||||
#include <QDateTime>
|
||||
#include <QThread>
|
||||
#include "utility.hpp"
|
||||
#include <curl/curl.h>
|
||||
|
||||
#define DEFAULT_INTERVAL 300
|
||||
#include "switch-audio.hpp"
|
||||
#include "switch-executable.hpp"
|
||||
#include "switch-file.hpp"
|
||||
#include "switch-idle.hpp"
|
||||
#include "switch-media.hpp"
|
||||
#include "switch-random.hpp"
|
||||
#include "switch-screen-region.hpp"
|
||||
#include "switch-time.hpp"
|
||||
#include "switch-transitions.hpp"
|
||||
#include "switch-window.hpp"
|
||||
#include "switch-sequence.hpp"
|
||||
|
||||
#define DEFAULT_IDLE_TIME 60
|
||||
|
||||
#define PREVIOUS_SCENE_NAME "Previous Scene"
|
||||
|
||||
#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 MEDIA_FUNC 6
|
||||
#define TIME_FUNC 7
|
||||
|
||||
#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
|
||||
#define DEFAULT_PRIORITY_6 MEDIA_FUNC
|
||||
#define DEFAULT_PRIORITY_7 TIME_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;
|
||||
bool usePreviousScene;
|
||||
string sceneRoundTripStr;
|
||||
|
||||
inline SceneRoundTripSwitch(OBSWeakSource scene1_,
|
||||
OBSWeakSource scene2_,
|
||||
OBSWeakSource transition_, int delay_,
|
||||
bool usePreviousScene_, string str)
|
||||
: scene1(scene1_),
|
||||
scene2(scene2_),
|
||||
transition(transition_),
|
||||
delay(delay_),
|
||||
usePreviousScene(usePreviousScene_),
|
||||
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;
|
||||
bool usePreviousScene;
|
||||
bool alreadySwitched = false;
|
||||
};
|
||||
|
||||
struct MediaSwitch {
|
||||
OBSWeakSource scene;
|
||||
OBSWeakSource source;
|
||||
OBSWeakSource transition;
|
||||
obs_media_state state;
|
||||
uint64_t time;
|
||||
time_restriction restriction;
|
||||
bool matched;
|
||||
bool usePreviousScene;
|
||||
|
||||
inline MediaSwitch(OBSWeakSource scene_, OBSWeakSource source_,
|
||||
OBSWeakSource transition_, obs_media_state state_,
|
||||
time_restriction restriction_, uint64_t time_,
|
||||
bool usePreviousScene_)
|
||||
: scene(scene_),
|
||||
source(source_),
|
||||
transition(transition_),
|
||||
state(state_),
|
||||
restriction(restriction_),
|
||||
time(time_),
|
||||
usePreviousScene(usePreviousScene_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct TimeSwitch {
|
||||
OBSWeakSource scene;
|
||||
OBSWeakSource transition;
|
||||
QTime time;
|
||||
bool matched;
|
||||
bool usePreviousScene;
|
||||
string timeSwitchStr;
|
||||
|
||||
inline TimeSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
||||
QTime time_, bool usePreviousScene_,
|
||||
string timeSwitchStr_)
|
||||
: scene(scene_),
|
||||
transition(transition_),
|
||||
time(time_),
|
||||
usePreviousScene(usePreviousScene_),
|
||||
timeSwitchStr(timeSwitchStr_)
|
||||
{
|
||||
}
|
||||
};
|
||||
constexpr auto default_interval = 300;
|
||||
constexpr auto previous_scene_name = "Previous Scene";
|
||||
|
||||
typedef enum { NO_SWITCH = 0, SWITCH = 1, RANDOM_SWITCH = 2 } NoMatch;
|
||||
typedef enum { PERSIST = 0, START = 1, STOP = 2 } StartupBehavior;
|
||||
typedef enum {
|
||||
RECORDING = 0,
|
||||
STREAMING = 1,
|
||||
RECORINDGSTREAMING = 2
|
||||
} AutoStartType;
|
||||
|
||||
typedef struct transitionData {
|
||||
std::string name = "";
|
||||
int duration = 0;
|
||||
|
||||
} transitionData;
|
||||
|
||||
class SwitcherThread;
|
||||
|
||||
/********************************************************************************
|
||||
* SwitcherData
|
||||
* SwitcherData
|
||||
********************************************************************************/
|
||||
struct SwitcherData {
|
||||
thread th;
|
||||
condition_variable cv;
|
||||
mutex m;
|
||||
SwitcherThread *th = nullptr;
|
||||
|
||||
std::condition_variable cv;
|
||||
std::mutex m;
|
||||
bool transitionActive = false;
|
||||
bool waitForTransition = false;
|
||||
condition_variable transitionCv;
|
||||
bool startAtLaunch = false;
|
||||
std::condition_variable transitionCv;
|
||||
bool stop = false;
|
||||
bool verbose = false;
|
||||
bool disableHints = false;
|
||||
bool showFrame = false;
|
||||
bool tansitionOverrideOverride = false;
|
||||
|
||||
int interval = DEFAULT_INTERVAL;
|
||||
int interval = default_interval;
|
||||
|
||||
obs_source_t *waitScene = NULL; //scene during which wait started
|
||||
obs_source_t *waitScene = NULL;
|
||||
OBSWeakSource previousScene = NULL;
|
||||
OBSWeakSource PreviousScene2 = NULL;
|
||||
OBSWeakSource lastRandomScene;
|
||||
OBSWeakSource nonMatchingScene;
|
||||
NoMatch switchIfNotMatching = NO_SWITCH;
|
||||
StartupBehavior startupBehavior = PERSIST;
|
||||
|
||||
vector<WindowSceneSwitch> windowSwitches;
|
||||
vector<string> ignoreIdleWindows;
|
||||
string lastTitle;
|
||||
std::deque<WindowSwitch> windowSwitches;
|
||||
std::vector<std::string> ignoreIdleWindows;
|
||||
std::string lastTitle;
|
||||
|
||||
vector<ScreenRegionSwitch> screenRegionSwitches;
|
||||
std::deque<ScreenRegionSwitch> screenRegionSwitches;
|
||||
|
||||
vector<OBSWeakSource> pauseScenesSwitches;
|
||||
std::vector<OBSWeakSource> pauseScenesSwitches;
|
||||
|
||||
vector<string> pauseWindowsSwitches;
|
||||
std::vector<std::string> pauseWindowsSwitches;
|
||||
|
||||
vector<string> ignoreWindowsSwitches;
|
||||
std::vector<std::string> ignoreWindowsSwitches;
|
||||
|
||||
vector<SceneRoundTripSwitch> sceneRoundTripSwitches;
|
||||
std::deque<SceneSequenceSwitch> sceneSequenceSwitches;
|
||||
|
||||
vector<RandomSwitch> randomSwitches;
|
||||
std::deque<RandomSwitch> randomSwitches;
|
||||
|
||||
IdleData idleData;
|
||||
|
||||
FileIOData fileIO;
|
||||
IdleData idleData;
|
||||
vector<FileSwitch> fileSwitches;
|
||||
std::vector<FileSwitch> fileSwitches;
|
||||
CURL *curl = nullptr;
|
||||
|
||||
vector<ExecutableSceneSwitch> executableSwitches;
|
||||
std::deque<ExecutableSwitch> executableSwitches;
|
||||
|
||||
bool autoStopEnable = false;
|
||||
OBSWeakSource autoStopScene;
|
||||
|
||||
vector<SceneTransition> sceneTransitions;
|
||||
vector<DefaultSceneTransition> defaultSceneTransitions;
|
||||
bool autoStartEnable = false;
|
||||
AutoStartType autoStartType = RECORDING;
|
||||
OBSWeakSource autoStartScene;
|
||||
bool autoStartedRecently = false;
|
||||
|
||||
vector<MediaSwitch> mediaSwitches;
|
||||
std::deque<SceneTransition> sceneTransitions;
|
||||
std::deque<DefaultSceneTransition> defaultSceneTransitions;
|
||||
bool changedDefTransitionRecently = false;
|
||||
|
||||
vector<TimeSwitch> timeSwitches;
|
||||
std::deque<MediaSwitch> mediaSwitches;
|
||||
|
||||
vector<int> functionNamesByPriority = vector<int>{
|
||||
DEFAULT_PRIORITY_0, DEFAULT_PRIORITY_1, DEFAULT_PRIORITY_2,
|
||||
DEFAULT_PRIORITY_3, DEFAULT_PRIORITY_4, DEFAULT_PRIORITY_5,
|
||||
DEFAULT_PRIORITY_6, DEFAULT_PRIORITY_7};
|
||||
std::deque<TimeSwitch> timeSwitches;
|
||||
QDateTime liveTime;
|
||||
|
||||
std::vector<std::string> threadPrioritiesNamesOrderdByPrio{
|
||||
"Lowest", "Low", "Normal", "High", "Highest", "Time critical",
|
||||
std::deque<AudioSwitch> audioSwitches;
|
||||
|
||||
std::vector<int> functionNamesByPriority = std::vector<int>{
|
||||
default_priority_0, default_priority_1, default_priority_2,
|
||||
default_priority_3, default_priority_4, default_priority_5,
|
||||
default_priority_6, default_priority_7, default_priority_8};
|
||||
|
||||
struct ThreadPrio {
|
||||
std::string name;
|
||||
std::string description;
|
||||
uint32_t value;
|
||||
};
|
||||
std::map<std::string, int> threadPriorities = {
|
||||
{"Lowest", QThread::LowestPriority},
|
||||
{"Low", QThread::LowPriority},
|
||||
{"Normal", QThread::NormalPriority},
|
||||
{"High", QThread::HighPriority},
|
||||
{"Highest", QThread::HighestPriority},
|
||||
{"Time critical", QThread::TimeCriticalPriority},
|
||||
|
||||
std::vector<ThreadPrio> threadPriorities{
|
||||
{"Idle",
|
||||
"scheduled only when no other threads are running (lowest CPU load)",
|
||||
QThread::IdlePriority},
|
||||
{"Lowest", "scheduled less often than LowPriority",
|
||||
QThread::LowestPriority},
|
||||
{"Low", "scheduled less often than NormalPriority",
|
||||
QThread::LowPriority},
|
||||
{"Normal", "the default priority of the operating system",
|
||||
QThread::NormalPriority},
|
||||
{"High", "scheduled more often than NormalPriority",
|
||||
QThread::HighPriority},
|
||||
{"Highest", "scheduled more often than HighPriority",
|
||||
QThread::HighestPriority},
|
||||
{"Time critical",
|
||||
"scheduled as often as possible (highest CPU load)",
|
||||
QThread::TimeCriticalPriority},
|
||||
};
|
||||
|
||||
uint32_t threadPriority = QThread::NormalPriority;
|
||||
|
||||
std::vector<int> tabOrder;
|
||||
|
||||
bool hotkeysRegistered = false;
|
||||
obs_hotkey_id startHotkey;
|
||||
obs_hotkey_id stopHotkey;
|
||||
obs_hotkey_id toggleHotkey;
|
||||
|
||||
void Thread();
|
||||
void Start();
|
||||
void Stop();
|
||||
@@ -330,10 +156,11 @@ struct SwitcherData {
|
||||
void writeSceneInfoToFile();
|
||||
void setDefaultSceneTransitions();
|
||||
void autoStopStreamAndRecording();
|
||||
void autoStartStreamRecording();
|
||||
bool checkPause();
|
||||
void checkSceneRoundTrip(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition,
|
||||
unique_lock<mutex> &lock);
|
||||
void checkSceneSequence(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition,
|
||||
std::unique_lock<std::mutex> &lock);
|
||||
void checkIdleSwitch(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition);
|
||||
void checkWindowTitleSwitch(bool &match, OBSWeakSource &scene,
|
||||
@@ -352,104 +179,46 @@ struct SwitcherData {
|
||||
OBSWeakSource &transition);
|
||||
void checkTimeSwitch(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition);
|
||||
void checkAudioSwitch(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition);
|
||||
|
||||
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--);
|
||||
}
|
||||
void saveWindowTitleSwitches(obs_data_t *obj);
|
||||
void saveScreenRegionSwitches(obs_data_t *obj);
|
||||
void savePauseSwitches(obs_data_t *obj);
|
||||
void saveSceneSequenceSwitches(obs_data_t *obj);
|
||||
void saveSceneTransitions(obs_data_t *obj);
|
||||
void saveIdleSwitches(obs_data_t *obj);
|
||||
void saveExecutableSwitches(obs_data_t *obj);
|
||||
void saveRandomSwitches(obs_data_t *obj);
|
||||
void saveFileSwitches(obs_data_t *obj);
|
||||
void saveMediaSwitches(obs_data_t *obj);
|
||||
void saveTimeSwitches(obs_data_t *obj);
|
||||
void saveAudioSwitches(obs_data_t *obj);
|
||||
void saveGeneralSettings(obs_data_t *obj);
|
||||
void saveHotkeys(obs_data_t *obj);
|
||||
|
||||
if (nonMatchingScene && !WeakSourceValid(nonMatchingScene)) {
|
||||
switchIfNotMatching = NO_SWITCH;
|
||||
nonMatchingScene = nullptr;
|
||||
}
|
||||
void loadWindowTitleSwitches(obs_data_t *obj);
|
||||
void loadScreenRegionSwitches(obs_data_t *obj);
|
||||
void loadPauseSwitches(obs_data_t *obj);
|
||||
void loadSceneSequenceSwitches(obs_data_t *obj);
|
||||
void loadSceneTransitions(obs_data_t *obj);
|
||||
void loadIdleSwitches(obs_data_t *obj);
|
||||
void loadExecutableSwitches(obs_data_t *obj);
|
||||
void loadRandomSwitches(obs_data_t *obj);
|
||||
void loadFileSwitches(obs_data_t *obj);
|
||||
void loadMediaSwitches(obs_data_t *obj);
|
||||
void loadTimeSwitches(obs_data_t *obj);
|
||||
void loadAudioSwitches(obs_data_t *obj);
|
||||
void loadGeneralSettings(obs_data_t *obj);
|
||||
void loadHotkeys(obs_data_t *obj);
|
||||
|
||||
for (size_t i = 0; i < randomSwitches.size(); i++) {
|
||||
RandomSwitch &s = randomSwitches[i];
|
||||
if (!WeakSourceValid(s.scene) ||
|
||||
!WeakSourceValid(s.transition))
|
||||
randomSwitches.erase(randomSwitches.begin() +
|
||||
i--);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < screenRegionSwitches.size(); i++) {
|
||||
ScreenRegionSwitch &s = screenRegionSwitches[i];
|
||||
if (!WeakSourceValid(s.scene) ||
|
||||
!WeakSourceValid(s.transition))
|
||||
screenRegionSwitches.erase(
|
||||
screenRegionSwitches.begin() + i--);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < pauseScenesSwitches.size(); i++) {
|
||||
OBSWeakSource &scene = pauseScenesSwitches[i];
|
||||
if (!WeakSourceValid(scene))
|
||||
pauseScenesSwitches.erase(
|
||||
pauseScenesSwitches.begin() + i--);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < sceneRoundTripSwitches.size(); i++) {
|
||||
SceneRoundTripSwitch &s = sceneRoundTripSwitches[i];
|
||||
if (!WeakSourceValid(s.scene1) ||
|
||||
(!s.usePreviousScene &&
|
||||
!WeakSourceValid(s.scene2)) ||
|
||||
!WeakSourceValid(s.transition))
|
||||
sceneRoundTripSwitches.erase(
|
||||
sceneRoundTripSwitches.begin() + i--);
|
||||
}
|
||||
|
||||
if (!WeakSourceValid(autoStopScene)) {
|
||||
autoStopScene = nullptr;
|
||||
autoStopEnable = false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < sceneTransitions.size(); i++) {
|
||||
SceneTransition &s = sceneTransitions[i];
|
||||
if (!WeakSourceValid(s.scene1) ||
|
||||
!WeakSourceValid(s.scene2) ||
|
||||
!WeakSourceValid(s.transition))
|
||||
sceneTransitions.erase(
|
||||
sceneTransitions.begin() + i--);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < defaultSceneTransitions.size(); i++) {
|
||||
DefaultSceneTransition &s = defaultSceneTransitions[i];
|
||||
if (!WeakSourceValid(s.scene) ||
|
||||
!WeakSourceValid(s.transition))
|
||||
defaultSceneTransitions.erase(
|
||||
defaultSceneTransitions.begin() + i--);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < executableSwitches.size(); i++) {
|
||||
ExecutableSceneSwitch &s = executableSwitches[i];
|
||||
if (!WeakSourceValid(s.mScene) ||
|
||||
!WeakSourceValid(s.mTransition))
|
||||
executableSwitches.erase(
|
||||
executableSwitches.begin() + i--);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < fileSwitches.size(); i++) {
|
||||
FileSwitch &s = fileSwitches[i];
|
||||
if (!WeakSourceValid(s.scene) ||
|
||||
!WeakSourceValid(s.transition))
|
||||
fileSwitches.erase(fileSwitches.begin() + i--);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < timeSwitches.size(); i++) {
|
||||
TimeSwitch &s = timeSwitches[i];
|
||||
if (!WeakSourceValid(s.scene) ||
|
||||
!WeakSourceValid(s.transition))
|
||||
timeSwitches.erase(timeSwitches.begin() + i--);
|
||||
}
|
||||
|
||||
if (!idleData.usePreviousScene &&
|
||||
!WeakSourceValid(idleData.scene) ||
|
||||
!WeakSourceValid(idleData.transition)) {
|
||||
idleData.idleEnable = false;
|
||||
}
|
||||
}
|
||||
void Prune();
|
||||
inline ~SwitcherData() { Stop(); }
|
||||
};
|
||||
|
||||
extern SwitcherData *switcher;
|
||||
class SwitcherThread : public QThread {
|
||||
public:
|
||||
explicit SwitcherThread(){};
|
||||
void run() { switcher->Thread(); };
|
||||
};
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
#include <obs.hpp>
|
||||
#include <QString>
|
||||
#include <obs-frontend-api.h>
|
||||
#include "switcher-data-structs.hpp"
|
||||
using namespace std;
|
||||
|
||||
static inline bool WeakSourceValid(obs_weak_source_t *ws)
|
||||
{
|
||||
@@ -13,164 +11,9 @@ static inline bool WeakSourceValid(obs_weak_source_t *ws)
|
||||
return !!source;
|
||||
}
|
||||
|
||||
static inline QString MakeSwitchName(const QString &scene, const QString &value,
|
||||
const QString &transition, bool fullscreen)
|
||||
static inline std::string GetWeakSourceName(obs_weak_source_t *weak_source)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
TIME_RESTRICTION_NONE,
|
||||
TIME_RESTRICTION_SHORTER,
|
||||
TIME_RESTRICTION_LONGER,
|
||||
TIME_RESTRICTION_REMAINING_SHORTER,
|
||||
TIME_RESTRICTION_REMAINING_LONGER,
|
||||
} time_restriction;
|
||||
|
||||
static inline QString
|
||||
MakeMediaSwitchName(const QString &source, const QString &scene,
|
||||
const QString &transition, obs_media_state state,
|
||||
time_restriction restriction, uint64_t time)
|
||||
{
|
||||
QString switchName = QStringLiteral("Switch to ") + scene +
|
||||
QStringLiteral(" using ") + transition +
|
||||
QStringLiteral(" if ") + source +
|
||||
QStringLiteral(" state is ");
|
||||
if (state == OBS_MEDIA_STATE_NONE) {
|
||||
switchName += QStringLiteral("none");
|
||||
} else if (state == OBS_MEDIA_STATE_PLAYING) {
|
||||
switchName += QStringLiteral("playing");
|
||||
} else if (state == OBS_MEDIA_STATE_OPENING) {
|
||||
switchName += QStringLiteral("opening");
|
||||
} else if (state == OBS_MEDIA_STATE_BUFFERING) {
|
||||
switchName += QStringLiteral("buffering");
|
||||
} else if (state == OBS_MEDIA_STATE_PAUSED) {
|
||||
switchName += QStringLiteral("paused");
|
||||
} else if (state == OBS_MEDIA_STATE_STOPPED) {
|
||||
switchName += QStringLiteral("stopped");
|
||||
} else if (state == OBS_MEDIA_STATE_ENDED) {
|
||||
switchName += QStringLiteral("ended");
|
||||
} else if (state == OBS_MEDIA_STATE_ERROR) {
|
||||
switchName += QStringLiteral("error");
|
||||
}
|
||||
if (restriction == TIME_RESTRICTION_SHORTER) {
|
||||
switchName += QStringLiteral(" and time shorter than ");
|
||||
} else if (restriction == TIME_RESTRICTION_LONGER) {
|
||||
switchName += QStringLiteral(" and time longer than ");
|
||||
} else if (restriction == TIME_RESTRICTION_REMAINING_SHORTER) {
|
||||
switchName +=
|
||||
QStringLiteral(" and time remaining shorter than ");
|
||||
} else if (restriction == TIME_RESTRICTION_REMAINING_LONGER) {
|
||||
switchName +=
|
||||
QStringLiteral(" and time remaining longer than ");
|
||||
}
|
||||
if (restriction != TIME_RESTRICTION_NONE) {
|
||||
switchName += std::to_string(time).c_str();
|
||||
switchName += QStringLiteral(" ms");
|
||||
}
|
||||
return switchName;
|
||||
}
|
||||
|
||||
static inline QString MakeTimeSwitchName(const QString &scene,
|
||||
const QString &transition, QTime &time)
|
||||
{
|
||||
QString switchName = QStringLiteral("At ") + time.toString() +
|
||||
QStringLiteral(" switch to ") + scene +
|
||||
QStringLiteral(" using ") + transition;
|
||||
return switchName;
|
||||
}
|
||||
|
||||
static inline string GetWeakSourceName(obs_weak_source_t *weak_source)
|
||||
{
|
||||
string name;
|
||||
std::string name;
|
||||
|
||||
obs_source_t *source = obs_weak_source_get_source(weak_source);
|
||||
if (source) {
|
||||
|
||||
245
src/headers/volume-control.hpp
Normal file
245
src/headers/volume-control.hpp
Normal file
@@ -0,0 +1,245 @@
|
||||
#pragma once
|
||||
|
||||
#include <obs.hpp>
|
||||
#include <QWidget>
|
||||
#include <QPaintEvent>
|
||||
#include <QSharedPointer>
|
||||
#include <QTimer>
|
||||
#include <QMutex>
|
||||
#include <QList>
|
||||
|
||||
class QPushButton;
|
||||
class VolumeMeterTimer;
|
||||
|
||||
class VolumeMeter : public QWidget {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QColor backgroundNominalColor READ getBackgroundNominalColor
|
||||
WRITE setBackgroundNominalColor DESIGNABLE true)
|
||||
Q_PROPERTY(QColor backgroundWarningColor READ getBackgroundWarningColor
|
||||
WRITE setBackgroundWarningColor DESIGNABLE true)
|
||||
Q_PROPERTY(QColor backgroundErrorColor READ getBackgroundErrorColor
|
||||
WRITE setBackgroundErrorColor DESIGNABLE true)
|
||||
Q_PROPERTY(QColor foregroundNominalColor READ getForegroundNominalColor
|
||||
WRITE setForegroundNominalColor DESIGNABLE true)
|
||||
Q_PROPERTY(QColor foregroundWarningColor READ getForegroundWarningColor
|
||||
WRITE setForegroundWarningColor DESIGNABLE true)
|
||||
Q_PROPERTY(QColor foregroundErrorColor READ getForegroundErrorColor
|
||||
WRITE setForegroundErrorColor DESIGNABLE true)
|
||||
Q_PROPERTY(QColor clipColor READ getClipColor WRITE setClipColor
|
||||
DESIGNABLE true)
|
||||
Q_PROPERTY(QColor magnitudeColor READ getMagnitudeColor WRITE
|
||||
setMagnitudeColor DESIGNABLE true)
|
||||
Q_PROPERTY(QColor majorTickColor READ getMajorTickColor WRITE
|
||||
setMajorTickColor DESIGNABLE true)
|
||||
Q_PROPERTY(QColor minorTickColor READ getMinorTickColor WRITE
|
||||
setMinorTickColor DESIGNABLE true)
|
||||
|
||||
// Levels are denoted in dBFS.
|
||||
Q_PROPERTY(qreal minimumLevel READ getMinimumLevel WRITE setMinimumLevel
|
||||
DESIGNABLE true)
|
||||
Q_PROPERTY(qreal warningLevel READ getWarningLevel WRITE setWarningLevel
|
||||
DESIGNABLE true)
|
||||
Q_PROPERTY(qreal errorLevel READ getErrorLevel WRITE setErrorLevel
|
||||
DESIGNABLE true)
|
||||
Q_PROPERTY(qreal clipLevel READ getClipLevel WRITE setClipLevel
|
||||
DESIGNABLE true)
|
||||
Q_PROPERTY(qreal minimumInputLevel READ getMinimumInputLevel WRITE
|
||||
setMinimumInputLevel DESIGNABLE true)
|
||||
|
||||
// Rates are denoted in dB/second.
|
||||
Q_PROPERTY(qreal peakDecayRate READ getPeakDecayRate WRITE
|
||||
setPeakDecayRate DESIGNABLE true)
|
||||
|
||||
// Time in seconds for the VU meter to integrate over.
|
||||
Q_PROPERTY(
|
||||
qreal magnitudeIntegrationTime READ getMagnitudeIntegrationTime
|
||||
WRITE setMagnitudeIntegrationTime DESIGNABLE true)
|
||||
|
||||
// Duration is denoted in seconds.
|
||||
Q_PROPERTY(qreal peakHoldDuration READ getPeakHoldDuration WRITE
|
||||
setPeakHoldDuration DESIGNABLE true)
|
||||
Q_PROPERTY(qreal inputPeakHoldDuration READ getInputPeakHoldDuration
|
||||
WRITE setInputPeakHoldDuration DESIGNABLE true)
|
||||
|
||||
private slots:
|
||||
void ClipEnding();
|
||||
|
||||
private:
|
||||
obs_volmeter_t *obs_volmeter;
|
||||
static QWeakPointer<VolumeMeterTimer> updateTimer;
|
||||
QSharedPointer<VolumeMeterTimer> updateTimerRef;
|
||||
|
||||
inline void resetLevels();
|
||||
inline void handleChannelCofigurationChange();
|
||||
inline bool detectIdle(uint64_t ts);
|
||||
inline void calculateBallistics(uint64_t ts,
|
||||
qreal timeSinceLastRedraw = 0.0);
|
||||
inline void calculateBallisticsForChannel(int channelNr, uint64_t ts,
|
||||
qreal timeSinceLastRedraw);
|
||||
|
||||
void paintInputMeter(QPainter &painter, int x, int y, int width,
|
||||
int height, float peakHold);
|
||||
void paintHMeter(QPainter &painter, int x, int y, int width, int height,
|
||||
float magnitude, float peak, float peakHold);
|
||||
void paintHTicks(QPainter &painter, int x, int y, int width,
|
||||
int height);
|
||||
void paintVMeter(QPainter &painter, int x, int y, int width, int height,
|
||||
float magnitude, float peak, float peakHold);
|
||||
void paintVTicks(QPainter &painter, int x, int y, int height);
|
||||
|
||||
QMutex dataMutex;
|
||||
|
||||
uint64_t currentLastUpdateTime = 0;
|
||||
float currentMagnitude[MAX_AUDIO_CHANNELS];
|
||||
float currentPeak[MAX_AUDIO_CHANNELS];
|
||||
float currentInputPeak[MAX_AUDIO_CHANNELS];
|
||||
|
||||
QPixmap *tickPaintCache = nullptr;
|
||||
int displayNrAudioChannels = 0;
|
||||
float displayMagnitude[MAX_AUDIO_CHANNELS];
|
||||
float displayPeak[MAX_AUDIO_CHANNELS];
|
||||
float displayPeakHold[MAX_AUDIO_CHANNELS];
|
||||
uint64_t displayPeakHoldLastUpdateTime[MAX_AUDIO_CHANNELS];
|
||||
float displayInputPeakHold[MAX_AUDIO_CHANNELS];
|
||||
uint64_t displayInputPeakHoldLastUpdateTime[MAX_AUDIO_CHANNELS];
|
||||
|
||||
QFont tickFont;
|
||||
QColor backgroundNominalColor;
|
||||
QColor backgroundWarningColor;
|
||||
QColor backgroundErrorColor;
|
||||
QColor foregroundNominalColor;
|
||||
QColor foregroundWarningColor;
|
||||
QColor foregroundErrorColor;
|
||||
QColor clipColor;
|
||||
QColor magnitudeColor;
|
||||
QColor majorTickColor;
|
||||
QColor minorTickColor;
|
||||
qreal minimumLevel;
|
||||
qreal warningLevel;
|
||||
qreal errorLevel;
|
||||
qreal clipLevel;
|
||||
qreal minimumInputLevel;
|
||||
qreal peakDecayRate;
|
||||
qreal magnitudeIntegrationTime;
|
||||
qreal peakHoldDuration;
|
||||
qreal inputPeakHoldDuration;
|
||||
|
||||
uint64_t lastRedrawTime = 0;
|
||||
int channels = 0;
|
||||
bool clipping = false;
|
||||
bool vertical;
|
||||
|
||||
public:
|
||||
explicit VolumeMeter(QWidget *parent = nullptr,
|
||||
obs_volmeter_t *obs_volmeter = nullptr,
|
||||
bool vertical = false);
|
||||
~VolumeMeter();
|
||||
|
||||
void setLevels(const float magnitude[MAX_AUDIO_CHANNELS],
|
||||
const float peak[MAX_AUDIO_CHANNELS],
|
||||
const float inputPeak[MAX_AUDIO_CHANNELS]);
|
||||
|
||||
QColor getBackgroundNominalColor() const;
|
||||
void setBackgroundNominalColor(QColor c);
|
||||
QColor getBackgroundWarningColor() const;
|
||||
void setBackgroundWarningColor(QColor c);
|
||||
QColor getBackgroundErrorColor() const;
|
||||
void setBackgroundErrorColor(QColor c);
|
||||
QColor getForegroundNominalColor() const;
|
||||
void setForegroundNominalColor(QColor c);
|
||||
QColor getForegroundWarningColor() const;
|
||||
void setForegroundWarningColor(QColor c);
|
||||
QColor getForegroundErrorColor() const;
|
||||
void setForegroundErrorColor(QColor c);
|
||||
QColor getClipColor() const;
|
||||
void setClipColor(QColor c);
|
||||
QColor getMagnitudeColor() const;
|
||||
void setMagnitudeColor(QColor c);
|
||||
QColor getMajorTickColor() const;
|
||||
void setMajorTickColor(QColor c);
|
||||
QColor getMinorTickColor() const;
|
||||
void setMinorTickColor(QColor c);
|
||||
qreal getMinimumLevel() const;
|
||||
void setMinimumLevel(qreal v);
|
||||
qreal getWarningLevel() const;
|
||||
void setWarningLevel(qreal v);
|
||||
qreal getErrorLevel() const;
|
||||
void setErrorLevel(qreal v);
|
||||
qreal getClipLevel() const;
|
||||
void setClipLevel(qreal v);
|
||||
qreal getMinimumInputLevel() const;
|
||||
void setMinimumInputLevel(qreal v);
|
||||
qreal getPeakDecayRate() const;
|
||||
void setPeakDecayRate(qreal v);
|
||||
qreal getMagnitudeIntegrationTime() const;
|
||||
void setMagnitudeIntegrationTime(qreal v);
|
||||
qreal getPeakHoldDuration() const;
|
||||
void setPeakHoldDuration(qreal v);
|
||||
qreal getInputPeakHoldDuration() const;
|
||||
void setInputPeakHoldDuration(qreal v);
|
||||
void setPeakMeterType(enum obs_peak_meter_type peakMeterType);
|
||||
virtual void mousePressEvent(QMouseEvent *event) override;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
};
|
||||
|
||||
class VolumeMeterTimer : public QTimer {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
inline VolumeMeterTimer() : QTimer() {}
|
||||
|
||||
void AddVolControl(VolumeMeter *meter);
|
||||
void RemoveVolControl(VolumeMeter *meter);
|
||||
|
||||
protected:
|
||||
void timerEvent(QTimerEvent *event) override;
|
||||
QList<VolumeMeter *> volumeMeters;
|
||||
};
|
||||
|
||||
class QLabel;
|
||||
class QSlider;
|
||||
class MuteCheckBox;
|
||||
|
||||
class VolControl : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
OBSSource source;
|
||||
QLabel *nameLabel;
|
||||
QLabel *volLabel;
|
||||
VolumeMeter *volMeter;
|
||||
QSlider *slider;
|
||||
float levelTotal;
|
||||
float levelCount;
|
||||
obs_fader_t *obs_fader;
|
||||
obs_volmeter_t *obs_volmeter;
|
||||
bool vertical;
|
||||
|
||||
static void OBSVolumeChanged(void *param, float db);
|
||||
static void OBSVolumeLevel(void *data,
|
||||
const float magnitude[MAX_AUDIO_CHANNELS],
|
||||
const float peak[MAX_AUDIO_CHANNELS],
|
||||
const float inputPeak[MAX_AUDIO_CHANNELS]);
|
||||
|
||||
private slots:
|
||||
void SliderChanged(int vol);
|
||||
void updateText();
|
||||
|
||||
public:
|
||||
explicit VolControl(OBSSource source, bool vertical = false);
|
||||
~VolControl();
|
||||
|
||||
inline obs_source_t *GetSource() const { return source; }
|
||||
|
||||
QString GetName() const;
|
||||
void SetName(const QString &newName);
|
||||
|
||||
void SetMeterDecayRate(qreal q);
|
||||
void setPeakMeterType(enum obs_peak_meter_type peakMeterType);
|
||||
|
||||
void EnableSlider(bool enable);
|
||||
|
||||
QSlider *GetSlider() const;
|
||||
};
|
||||
173
src/hotkey.cpp
173
src/hotkey.cpp
@@ -1,142 +1,101 @@
|
||||
#include <obs-module.h>
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
|
||||
void startHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotkey, bool pressed)
|
||||
void startHotkeyFunc(void *data, obs_hotkey_id id, obs_hotkey_t *hotkey,
|
||||
bool pressed)
|
||||
{
|
||||
UNUSED_PARAMETER(id);
|
||||
UNUSED_PARAMETER(data);
|
||||
UNUSED_PARAMETER(hotkey);
|
||||
|
||||
if (pressed)
|
||||
{
|
||||
if (!switcher->th.joinable())
|
||||
if (pressed) {
|
||||
if (!(switcher->th && switcher->th->isRunning()))
|
||||
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(START_HOTKEY_PATH), 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);
|
||||
}
|
||||
|
||||
void stopHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotkey, bool pressed)
|
||||
void stopHotkeyFunc(void *data, obs_hotkey_id id, obs_hotkey_t *hotkey,
|
||||
bool pressed)
|
||||
{
|
||||
UNUSED_PARAMETER(id);
|
||||
UNUSED_PARAMETER(data);
|
||||
UNUSED_PARAMETER(hotkey);
|
||||
|
||||
if (pressed)
|
||||
{
|
||||
if (switcher->th.joinable())
|
||||
if (pressed) {
|
||||
if (switcher->th && switcher->th->isRunning())
|
||||
switcher->Stop();
|
||||
}
|
||||
|
||||
obs_data_array* hotkeyData = obs_hotkey_save(id);
|
||||
|
||||
if (hotkeyData != NULL)
|
||||
{
|
||||
char* path = obs_module_config_path("");
|
||||
ofstream file;
|
||||
file.open(string(path).append(STOP_HOTKEY_PATH), 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);
|
||||
}
|
||||
|
||||
void startStopToggleHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotkey, bool pressed)
|
||||
void startStopToggleHotkeyFunc(void *data, obs_hotkey_id id,
|
||||
obs_hotkey_t *hotkey, bool pressed)
|
||||
{
|
||||
UNUSED_PARAMETER(id);
|
||||
UNUSED_PARAMETER(data);
|
||||
UNUSED_PARAMETER(hotkey);
|
||||
|
||||
if (pressed)
|
||||
{
|
||||
if (switcher->th.joinable())
|
||||
if (pressed) {
|
||||
if (switcher->th && switcher->th->isRunning())
|
||||
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(TOGGLE_HOTKEY_PATH), 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)
|
||||
void registerHotkeys()
|
||||
{
|
||||
ifstream settingsFile;
|
||||
char* path = obs_module_config_path("");
|
||||
string value;
|
||||
switcher->startHotkey = obs_hotkey_register_frontend(
|
||||
"startSwitcherHotkey", "Start the Advanced Scene Switcher",
|
||||
startHotkeyFunc, NULL);
|
||||
switcher->stopHotkey = obs_hotkey_register_frontend(
|
||||
"stopSwitcherHotkey", "Stop the Advanced Scene Switcher",
|
||||
stopHotkeyFunc, NULL);
|
||||
switcher->toggleHotkey = obs_hotkey_register_frontend(
|
||||
"startStopToggleSwitcherHotkey",
|
||||
"Toggle Start/Stop for the Advanced Scene Switcher",
|
||||
startStopToggleHotkeyFunc, NULL);
|
||||
|
||||
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<char>(settingsFile)), istreambuf_iterator<char>());
|
||||
settingsFile.close();
|
||||
}
|
||||
bfree(path);
|
||||
return value;
|
||||
switcher->hotkeysRegistered = true;
|
||||
}
|
||||
|
||||
void loadKeybinding(obs_hotkey_id hotkeyId, string path)
|
||||
void SwitcherData::saveHotkeys(obs_data_t *obj)
|
||||
{
|
||||
string bindings = loadConfigFile(path);
|
||||
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);
|
||||
}
|
||||
obs_data_array_t *startHotkeyArrray =
|
||||
obs_hotkey_save(switcher->startHotkey);
|
||||
obs_data_set_array(obj, "startHotkey", startHotkeyArrray);
|
||||
obs_data_array_release(startHotkeyArrray);
|
||||
|
||||
obs_data_array_t *stopHotkeyArrray =
|
||||
obs_hotkey_save(switcher->stopHotkey);
|
||||
|
||||
obs_data_set_array(obj, "stopHotkey", stopHotkeyArrray);
|
||||
obs_data_array_release(stopHotkeyArrray);
|
||||
|
||||
obs_data_array_t *toggleHotkeyArrray =
|
||||
obs_hotkey_save(switcher->toggleHotkey);
|
||||
obs_data_set_array(obj, "toggleHotkey", toggleHotkeyArrray);
|
||||
obs_data_array_release(toggleHotkeyArrray);
|
||||
}
|
||||
|
||||
void SwitcherData::loadHotkeys(obs_data_t *obj)
|
||||
{
|
||||
if (!switcher->hotkeysRegistered)
|
||||
registerHotkeys();
|
||||
|
||||
obs_data_array_t *startHotkeyArrray =
|
||||
obs_data_get_array(obj, "startHotkey");
|
||||
obs_hotkey_load(switcher->startHotkey, startHotkeyArrray);
|
||||
obs_data_array_release(startHotkeyArrray);
|
||||
|
||||
obs_data_array_t *stopHotkeyArrray =
|
||||
obs_data_get_array(obj, "stopHotkey");
|
||||
obs_hotkey_load(switcher->stopHotkey, stopHotkeyArrray);
|
||||
obs_data_array_release(stopHotkeyArrray);
|
||||
|
||||
obs_data_array_t *toggleHotkeyArrray =
|
||||
obs_data_get_array(obj, "toggleHotkey");
|
||||
obs_hotkey_load(switcher->toggleHotkey, toggleHotkeyArrray);
|
||||
obs_data_array_release(toggleHotkeyArrray);
|
||||
}
|
||||
|
||||
@@ -1,216 +0,0 @@
|
||||
#include "headers/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)
|
||||
{
|
||||
if (idleData.alreadySwitched)
|
||||
return;
|
||||
scene = (idleData.usePreviousScene) ? previousScene : idleData.scene;
|
||||
transition = idleData.transition;
|
||||
match = true;
|
||||
idleData.alreadySwitched = true;
|
||||
}
|
||||
else
|
||||
idleData.alreadySwitched = false;
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_idleCheckBox_stateChanged(int state)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> 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)
|
||||
{
|
||||
switcher->idleData.usePreviousScene = (name == PREVIOUS_SCENE_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<mutex> lock(switcher->m);
|
||||
UpdateIdleDataTransition(text);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_idleScenes_currentTextChanged(const QString& text)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
UpdateIdleDataScene(text);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_idleSpinBox_valueChanged(int i)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
lock_guard<mutex> 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<mutex> 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<QListWidgetItem*> 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<mutex> 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<mutex> 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;
|
||||
}
|
||||
@@ -16,9 +16,7 @@
|
||||
#include <util/platform.h>
|
||||
#include "../headers/advanced-scene-switcher.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static Display* xdisplay = 0;
|
||||
static Display *xdisplay = 0;
|
||||
|
||||
Display *disp()
|
||||
{
|
||||
@@ -40,31 +38,22 @@ void cleanupDisplay()
|
||||
static bool ewmhIsSupported()
|
||||
{
|
||||
Display *display = disp();
|
||||
Atom netSupportingWmCheck = XInternAtom(display,
|
||||
"_NET_SUPPORTING_WM_CHECK", true);
|
||||
Atom netSupportingWmCheck =
|
||||
XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", true);
|
||||
Atom actualType;
|
||||
int format = 0;
|
||||
unsigned long num = 0, bytes = 0;
|
||||
unsigned char *data = NULL;
|
||||
Window ewmh_window = 0;
|
||||
|
||||
int status = XGetWindowProperty(
|
||||
display,
|
||||
DefaultRootWindow(display),
|
||||
netSupportingWmCheck,
|
||||
0L,
|
||||
1L,
|
||||
false,
|
||||
XA_WINDOW,
|
||||
&actualType,
|
||||
&format,
|
||||
&num,
|
||||
&bytes,
|
||||
&data);
|
||||
int status = XGetWindowProperty(display, DefaultRootWindow(display),
|
||||
netSupportingWmCheck, 0L, 1L, false,
|
||||
XA_WINDOW, &actualType, &format, &num,
|
||||
&bytes, &data);
|
||||
|
||||
if (status == Success) {
|
||||
if (num > 0) {
|
||||
ewmh_window = ((Window*)data)[0];
|
||||
ewmh_window = ((Window *)data)[0];
|
||||
}
|
||||
if (data) {
|
||||
XFree(data);
|
||||
@@ -73,21 +62,12 @@ static bool ewmhIsSupported()
|
||||
}
|
||||
|
||||
if (ewmh_window) {
|
||||
status = XGetWindowProperty(
|
||||
display,
|
||||
ewmh_window,
|
||||
netSupportingWmCheck,
|
||||
0L,
|
||||
1L,
|
||||
false,
|
||||
XA_WINDOW,
|
||||
&actualType,
|
||||
&format,
|
||||
&num,
|
||||
&bytes,
|
||||
&data);
|
||||
status = XGetWindowProperty(display, ewmh_window,
|
||||
netSupportingWmCheck, 0L, 1L, false,
|
||||
XA_WINDOW, &actualType, &format,
|
||||
&num, &bytes, &data);
|
||||
if (status != Success || num == 0 ||
|
||||
ewmh_window != ((Window*)data)[0]) {
|
||||
ewmh_window != ((Window *)data)[0]) {
|
||||
ewmh_window = 0;
|
||||
}
|
||||
if (status == Success && data) {
|
||||
@@ -98,6 +78,30 @@ static bool ewmhIsSupported()
|
||||
return ewmh_window != 0;
|
||||
}
|
||||
|
||||
static QStringList getStates(Window window)
|
||||
{
|
||||
QStringList states;
|
||||
|
||||
if (!ewmhIsSupported())
|
||||
return states;
|
||||
|
||||
Atom wmState = XInternAtom(disp(), "_NET_WM_STATE", true), type;
|
||||
int format;
|
||||
unsigned long num, bytes;
|
||||
unsigned char *data;
|
||||
|
||||
int status = XGetWindowProperty(disp(), window, wmState, 0, ~0L, false,
|
||||
AnyPropertyType, &type, &format, &num,
|
||||
&bytes, &data);
|
||||
|
||||
if (status == Success)
|
||||
for (unsigned long i = 0; i < num; i++)
|
||||
states.append(QString(
|
||||
XGetAtomName(disp(), ((Atom *)data)[i])));
|
||||
|
||||
return states;
|
||||
}
|
||||
|
||||
static std::vector<Window> getTopLevelWindows()
|
||||
{
|
||||
std::vector<Window> res;
|
||||
@@ -112,24 +116,15 @@ static std::vector<Window> getTopLevelWindows()
|
||||
Atom actualType;
|
||||
int format;
|
||||
unsigned long num, bytes;
|
||||
Window* data = 0;
|
||||
Window *data = 0;
|
||||
|
||||
for (int i = 0; i < ScreenCount(disp()); ++i) {
|
||||
Window rootWin = RootWindow(disp(), i);
|
||||
|
||||
int status = XGetWindowProperty(
|
||||
disp(),
|
||||
rootWin,
|
||||
netClList,
|
||||
0L,
|
||||
~0L,
|
||||
false,
|
||||
AnyPropertyType,
|
||||
&actualType,
|
||||
&format,
|
||||
&num,
|
||||
&bytes,
|
||||
(uint8_t**)&data);
|
||||
int status = XGetWindowProperty(disp(), rootWin, netClList, 0L,
|
||||
~0L, false, AnyPropertyType,
|
||||
&actualType, &format, &num,
|
||||
&bytes, (uint8_t **)&data);
|
||||
|
||||
if (status != Success) {
|
||||
continue;
|
||||
@@ -148,33 +143,47 @@ static std::string GetWindowTitle(size_t i)
|
||||
{
|
||||
Window w = getTopLevelWindows().at(i);
|
||||
std::string windowTitle;
|
||||
char* name;
|
||||
char *name;
|
||||
|
||||
XTextProperty text;
|
||||
int status = XGetWMName(disp(), w, &text);
|
||||
name = reinterpret_cast<char*>(text.value);
|
||||
if (status >= Success && name != nullptr)
|
||||
{
|
||||
int status = XGetTextProperty(
|
||||
disp(), w, &text, XInternAtom(disp(), "_NET_WM_NAME", true));
|
||||
if (status == 0)
|
||||
status = XGetTextProperty(disp(), w, &text,
|
||||
XInternAtom(disp(), "WM_NAME", true));
|
||||
name = reinterpret_cast<char *>(text.value);
|
||||
|
||||
if (status != 0 && name != nullptr) {
|
||||
std::string str(name);
|
||||
windowTitle = str;
|
||||
XFree(name);
|
||||
}
|
||||
|
||||
XFree(name);
|
||||
|
||||
return windowTitle;
|
||||
}
|
||||
|
||||
void GetWindowList(vector<string> &windows)
|
||||
void GetWindowList(std::vector<std::string> &windows)
|
||||
{
|
||||
windows.resize(0);
|
||||
|
||||
for (size_t i = 0; i < getTopLevelWindows().size(); ++i){
|
||||
for (size_t i = 0; i < getTopLevelWindows().size(); ++i) {
|
||||
if (GetWindowTitle(i) != "")
|
||||
windows.emplace_back(GetWindowTitle(i));
|
||||
}
|
||||
}
|
||||
|
||||
void GetCurrentWindowTitle(string &title)
|
||||
// Overloaded
|
||||
void GetWindowList(QStringList &windows)
|
||||
{
|
||||
windows.clear();
|
||||
|
||||
for (size_t i = 0; i < getTopLevelWindows().size(); ++i) {
|
||||
if (GetWindowTitle(i) != "")
|
||||
windows << QString::fromStdString(GetWindowTitle(i));
|
||||
}
|
||||
}
|
||||
|
||||
void GetCurrentWindowTitle(std::string &title)
|
||||
{
|
||||
if (!ewmhIsSupported()) {
|
||||
return;
|
||||
@@ -184,40 +193,39 @@ void GetCurrentWindowTitle(string &title)
|
||||
Atom actualType;
|
||||
int format;
|
||||
unsigned long num, bytes;
|
||||
Window* data = 0;
|
||||
char* name;
|
||||
Window *data = 0;
|
||||
char *name;
|
||||
|
||||
Window rootWin = RootWindow(disp(), 0);
|
||||
|
||||
XGetWindowProperty(
|
||||
disp(),
|
||||
rootWin,
|
||||
active,
|
||||
0L,
|
||||
~0L,
|
||||
false,
|
||||
AnyPropertyType,
|
||||
&actualType,
|
||||
&format,
|
||||
&num,
|
||||
&bytes,
|
||||
(uint8_t**)&data);
|
||||
int xstatus = XGetWindowProperty(disp(), rootWin, active, 0L, ~0L,
|
||||
false, AnyPropertyType, &actualType,
|
||||
&format, &num, &bytes,
|
||||
(uint8_t **)&data);
|
||||
|
||||
int status = 0;
|
||||
XTextProperty text;
|
||||
int status = XGetWMName(disp(), data[0], &text);
|
||||
name = reinterpret_cast<char*>(text.value);
|
||||
if (xstatus == Success) {
|
||||
status = XGetTextProperty(disp(), data[0], &text,
|
||||
XInternAtom(disp(), "_NET_WM_NAME",
|
||||
true));
|
||||
if (status == 0)
|
||||
status = XGetTextProperty(disp(), data[0], &text,
|
||||
XInternAtom(disp(), "WM_NAME",
|
||||
true));
|
||||
}
|
||||
name = reinterpret_cast<char *>(text.value);
|
||||
|
||||
if (status >= Success && name != nullptr) {
|
||||
if (status != 0 && name != nullptr) {
|
||||
std::string str(name);
|
||||
title = str;
|
||||
XFree(name);
|
||||
}
|
||||
|
||||
XFree(name);
|
||||
}
|
||||
|
||||
pair<int, int> getCursorPos()
|
||||
std::pair<int, int> getCursorPos()
|
||||
{
|
||||
pair<int, int> pos(0, 0);
|
||||
std::pair<int, int> pos(0, 0);
|
||||
Display *dpy;
|
||||
Window root;
|
||||
Window ret_root;
|
||||
@@ -231,95 +239,151 @@ pair<int, int> getCursorPos()
|
||||
dpy = XOpenDisplay(NULL);
|
||||
root = XDefaultRootWindow(dpy);
|
||||
|
||||
if(XQueryPointer(dpy, root, &ret_root, &ret_child, &root_x, &root_y,
|
||||
&win_x, &win_y, &mask))
|
||||
{
|
||||
pos = pair<int, int> (root_x,root_y);
|
||||
if (XQueryPointer(dpy, root, &ret_root, &ret_child, &root_x, &root_y,
|
||||
&win_x, &win_y, &mask)) {
|
||||
pos = std::pair<int, int>(root_x, root_y);
|
||||
}
|
||||
XCloseDisplay(dpy);
|
||||
return pos;
|
||||
}
|
||||
|
||||
bool isFullscreen()
|
||||
bool isMaximized(std::string &title)
|
||||
{
|
||||
if (!ewmhIsSupported()) {
|
||||
if (!ewmhIsSupported())
|
||||
return false;
|
||||
|
||||
// Find switch in top level windows
|
||||
std::vector<Window> windows = getTopLevelWindows();
|
||||
for (auto &window : windows) {
|
||||
XTextProperty text;
|
||||
int status = XGetTextProperty(
|
||||
disp(), window, &text,
|
||||
XInternAtom(disp(), "_NET_WM_NAME", true));
|
||||
if (status == 0)
|
||||
status = XGetTextProperty(disp(), window, &text,
|
||||
XInternAtom(disp(), "WM_NAME",
|
||||
true));
|
||||
char *name = reinterpret_cast<char *>(text.value);
|
||||
|
||||
if (status == 0 || name == nullptr)
|
||||
continue;
|
||||
|
||||
// True if switch equals window
|
||||
bool equals = (title == name);
|
||||
// True if switch matches window
|
||||
bool matches = QString::fromStdString(name).contains(
|
||||
QRegularExpression(QString::fromStdString(title)));
|
||||
|
||||
// If found, check if switch is maximized
|
||||
if (equals || matches) {
|
||||
QStringList states = getStates(window);
|
||||
|
||||
if (!states.isEmpty()) {
|
||||
// True if window is maximized vertically
|
||||
bool vertical = states.contains(
|
||||
"_NET_WM_STATE_MAXIMIZED_VERT");
|
||||
// True if window is maximized horizontally
|
||||
bool horizontal = states.contains(
|
||||
"_NET_WM_STATE_MAXIMIZED_HORZ");
|
||||
|
||||
return (vertical && horizontal);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Atom active = XInternAtom(disp(), "_NET_ACTIVE_WINDOW", true);
|
||||
Atom actualType;
|
||||
int format;
|
||||
unsigned long num, bytes;
|
||||
Window* data = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
Window rootWin = RootWindow(disp(), 0);
|
||||
XGetWindowProperty(
|
||||
disp(),
|
||||
rootWin,
|
||||
active,
|
||||
0L,
|
||||
~0L,
|
||||
false,
|
||||
AnyPropertyType,
|
||||
&actualType,
|
||||
&format,
|
||||
&num,
|
||||
&bytes,
|
||||
(uint8_t**)&data);
|
||||
bool isFullscreen(std::string &title)
|
||||
{
|
||||
if (!ewmhIsSupported())
|
||||
return false;
|
||||
|
||||
// Find switch in top level windows
|
||||
std::vector<Window> windows = getTopLevelWindows();
|
||||
for (auto &window : windows) {
|
||||
XTextProperty text;
|
||||
int status = XGetTextProperty(
|
||||
disp(), window, &text,
|
||||
XInternAtom(disp(), "_NET_WM_NAME", true));
|
||||
if (status == 0)
|
||||
status = XGetTextProperty(disp(), window, &text,
|
||||
XInternAtom(disp(), "WM_NAME",
|
||||
true));
|
||||
char *name = reinterpret_cast<char *>(text.value);
|
||||
|
||||
XWindowAttributes window_attributes_return;
|
||||
XWindowAttributes screen_attributes_return;
|
||||
if (status == 0 || name == nullptr)
|
||||
continue;
|
||||
|
||||
XGetWindowAttributes(disp(), rootWin, &screen_attributes_return);
|
||||
XGetWindowAttributes(disp(), data[0], &window_attributes_return);
|
||||
// True if switch equals window
|
||||
bool equals = (title == name);
|
||||
// True if switch matches window
|
||||
bool matches = QString::fromStdString(name).contains(
|
||||
QRegularExpression(QString::fromStdString(title)));
|
||||
|
||||
//menu bar is always 24 pixels in height
|
||||
return (window_attributes_return.width >= screen_attributes_return.width &&
|
||||
window_attributes_return.height + 24 >= screen_attributes_return.height) ? true : false;
|
||||
// If found, check if switch is fullscreen
|
||||
if (equals || matches) {
|
||||
QStringList states = getStates(window);
|
||||
|
||||
if (!states.isEmpty()) {
|
||||
// True if window is fullscreen
|
||||
bool fullscreen = states.contains(
|
||||
"_NET_WM_STATE_FULLSCREEN");
|
||||
|
||||
return (fullscreen);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//exe switch is not quite what is expected but it works for now
|
||||
void GetProcessList(QStringList &processes)
|
||||
{
|
||||
processes.clear();
|
||||
for (size_t i = 0; i < getTopLevelWindows().size(); ++i){
|
||||
string s = GetWindowTitle(i);
|
||||
for (size_t i = 0; i < getTopLevelWindows().size(); ++i) {
|
||||
std::string s = GetWindowTitle(i);
|
||||
if (s != "")
|
||||
processes << QString::fromStdString(s);
|
||||
}
|
||||
}
|
||||
|
||||
bool isInFocus(const QString &exeToCheck)
|
||||
bool isInFocus(const QString &executable)
|
||||
{
|
||||
string curWindow;
|
||||
GetCurrentWindowTitle(curWindow);
|
||||
std::string current;
|
||||
GetCurrentWindowTitle(current);
|
||||
|
||||
return (QString::compare(
|
||||
QString::fromStdString(curWindow),
|
||||
exeToCheck,
|
||||
Qt::CaseInsensitive) == 0) ? true : false;
|
||||
// True if executable switch equals current window
|
||||
bool equals = (executable.toStdString() == current);
|
||||
// True if executable switch matches current window
|
||||
bool matches = QString::fromStdString(current).contains(
|
||||
QRegularExpression(executable));
|
||||
|
||||
return (equals || matches);
|
||||
}
|
||||
|
||||
|
||||
int secondsSinceLastInput()
|
||||
{
|
||||
time_t idle_time;
|
||||
static XScreenSaverInfo *mit_info;
|
||||
Display *display;
|
||||
int screen;
|
||||
time_t idle_time;
|
||||
static XScreenSaverInfo *mit_info;
|
||||
Display *display;
|
||||
int screen;
|
||||
|
||||
mit_info = XScreenSaverAllocInfo();
|
||||
mit_info = XScreenSaverAllocInfo();
|
||||
|
||||
if((display=XOpenDisplay(NULL)) == NULL)
|
||||
{
|
||||
return(-1);
|
||||
if ((display = XOpenDisplay(NULL)) == NULL) {
|
||||
return (-1);
|
||||
}
|
||||
screen = DefaultScreen(display);
|
||||
XScreenSaverQueryInfo(display, RootWindow(display,screen), mit_info);
|
||||
idle_time = (mit_info->idle) / 1000;
|
||||
XFree(mit_info);
|
||||
XCloseDisplay(display);
|
||||
screen = DefaultScreen(display);
|
||||
XScreenSaverQueryInfo(display, RootWindow(display, screen), mit_info);
|
||||
idle_time = (mit_info->idle) / 1000;
|
||||
XFree(mit_info);
|
||||
XCloseDisplay(display);
|
||||
|
||||
return idle_time;
|
||||
}
|
||||
return idle_time;
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
#include <obs-module.h>
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
|
||||
void SceneSwitcher::on_mediaAdd_clicked()
|
||||
{
|
||||
QString sourceName = ui->mediaSources->currentText();
|
||||
QString sceneName = ui->mediaScenes->currentText();
|
||||
QString transitionName = ui->mediaTransitions->currentText();
|
||||
obs_media_state state =
|
||||
(obs_media_state)ui->mediaStates->currentIndex();
|
||||
time_restriction restriction =
|
||||
(time_restriction)ui->mediaTimeRestrictions->currentIndex();
|
||||
uint64_t time = ui->mediaTime->value();
|
||||
|
||||
if (sceneName.isEmpty() || transitionName.isEmpty() ||
|
||||
sourceName.isEmpty())
|
||||
return;
|
||||
|
||||
OBSWeakSource source = GetWeakSourceByQString(sourceName);
|
||||
OBSWeakSource scene = GetWeakSourceByQString(sceneName);
|
||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
||||
|
||||
QString switchText = MakeMediaSwitchName(sourceName, sceneName,
|
||||
transitionName, state,
|
||||
restriction, time);
|
||||
QVariant v = QVariant::fromValue(switchText);
|
||||
|
||||
QListWidgetItem *item =
|
||||
new QListWidgetItem(switchText, ui->mediaSwitches);
|
||||
item->setData(Qt::UserRole, v);
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->mediaSwitches.emplace_back(
|
||||
scene, source, transition, state, restriction, time,
|
||||
(sceneName == QString(PREVIOUS_SCENE_NAME)));
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_mediaRemove_clicked()
|
||||
{
|
||||
QListWidgetItem *item = ui->mediaSwitches->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
int idx = ui->mediaSwitches->currentRow();
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
|
||||
auto &switches = switcher->mediaSwitches;
|
||||
switches.erase(switches.begin() + idx);
|
||||
}
|
||||
qDeleteAll(ui->mediaSwitches->selectedItems());
|
||||
}
|
||||
|
||||
void SwitcherData::checkMediaSwitch(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition)
|
||||
{
|
||||
for (MediaSwitch &mediaSwitch : mediaSwitches) {
|
||||
obs_source_t *source =
|
||||
obs_weak_source_get_source(mediaSwitch.source);
|
||||
auto duration = obs_source_media_get_duration(source);
|
||||
auto time = obs_source_media_get_time(source);
|
||||
obs_media_state state = obs_source_media_get_state(source);
|
||||
bool matched =
|
||||
state == mediaSwitch.state &&
|
||||
(mediaSwitch.restriction == TIME_RESTRICTION_NONE ||
|
||||
(mediaSwitch.restriction == TIME_RESTRICTION_LONGER &&
|
||||
time > mediaSwitch.time) ||
|
||||
(mediaSwitch.restriction == TIME_RESTRICTION_SHORTER &&
|
||||
time < mediaSwitch.time) ||
|
||||
(mediaSwitch.restriction ==
|
||||
TIME_RESTRICTION_REMAINING_SHORTER &&
|
||||
duration > time &&
|
||||
duration - time < mediaSwitch.time) ||
|
||||
(mediaSwitch.restriction ==
|
||||
TIME_RESTRICTION_REMAINING_LONGER &&
|
||||
duration > time &&
|
||||
duration - time > mediaSwitch.time));
|
||||
if (matched && !mediaSwitch.matched) {
|
||||
match = true;
|
||||
scene = (mediaSwitch.usePreviousScene)
|
||||
? previousScene
|
||||
: mediaSwitch.scene;
|
||||
transition = mediaSwitch.transition;
|
||||
}
|
||||
mediaSwitch.matched = matched;
|
||||
}
|
||||
}
|
||||
@@ -6,141 +6,239 @@
|
||||
#include <util/platform.h>
|
||||
#include "../headers/advanced-scene-switcher.hpp"
|
||||
|
||||
|
||||
void GetWindowList(vector<string> &windows)
|
||||
void GetWindowList(std::vector<std::string> &windows)
|
||||
{
|
||||
windows.resize(0);
|
||||
windows.resize(0);
|
||||
|
||||
@autoreleasepool {
|
||||
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
|
||||
NSArray *array = [ws runningApplications];
|
||||
for (NSRunningApplication *app in array) {
|
||||
NSString *name = app.localizedName;
|
||||
if (!name)
|
||||
continue;
|
||||
@autoreleasepool {
|
||||
NSMutableArray *apps =
|
||||
(__bridge NSMutableArray *)CGWindowListCopyWindowInfo(
|
||||
kCGWindowListOptionAll, kCGNullWindowID);
|
||||
for (NSDictionary *app in apps) {
|
||||
// Construct string from NSString accounting for nil
|
||||
std::string name([[app objectForKey:@"kCGWindowName"]
|
||||
UTF8String],
|
||||
[[app objectForKey:@"kCGWindowName"]
|
||||
lengthOfBytesUsingEncoding:
|
||||
NSUTF8StringEncoding]);
|
||||
std::string owner([[app objectForKey:@"kCGWindowOwnerName"]
|
||||
UTF8String],
|
||||
[[app objectForKey:@"kCGWindowOwnerName"]
|
||||
lengthOfBytesUsingEncoding:
|
||||
NSUTF8StringEncoding]);
|
||||
|
||||
const char *str = name.UTF8String;
|
||||
if (str && *str)
|
||||
windows.emplace_back(str);
|
||||
}
|
||||
}
|
||||
// Check if name exists
|
||||
if (!name.empty() &&
|
||||
find(windows.begin(), windows.end(), name) ==
|
||||
windows.end())
|
||||
windows.emplace_back(name);
|
||||
// Check if owner exists
|
||||
else if (!owner.empty() &&
|
||||
find(windows.begin(), windows.end(), owner) ==
|
||||
windows.end())
|
||||
windows.emplace_back(owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GetCurrentWindowTitle(string &title)
|
||||
// Overloaded
|
||||
void GetWindowList(QStringList &windows)
|
||||
{
|
||||
title.resize(0);
|
||||
windows.clear();
|
||||
|
||||
@autoreleasepool {
|
||||
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
|
||||
NSRunningApplication *app = [ws frontmostApplication];
|
||||
if (app) {
|
||||
NSString *name = app.localizedName;
|
||||
if (!name)
|
||||
return;
|
||||
@autoreleasepool {
|
||||
NSMutableArray *apps =
|
||||
(__bridge NSMutableArray *)CGWindowListCopyWindowInfo(
|
||||
kCGWindowListOptionAll, kCGNullWindowID);
|
||||
for (NSDictionary *app in apps) {
|
||||
// Construct string from NSString accounting for nil
|
||||
std::string name([[app objectForKey:@"kCGWindowName"]
|
||||
UTF8String],
|
||||
[[app objectForKey:@"kCGWindowName"]
|
||||
lengthOfBytesUsingEncoding:
|
||||
NSUTF8StringEncoding]);
|
||||
std::string owner([[app objectForKey:@"kCGWindowOwnerName"]
|
||||
UTF8String],
|
||||
[[app objectForKey:@"kCGWindowOwnerName"]
|
||||
lengthOfBytesUsingEncoding:
|
||||
NSUTF8StringEncoding]);
|
||||
|
||||
const char *str = name.UTF8String;
|
||||
if (str && *str)
|
||||
title = str;
|
||||
}
|
||||
}
|
||||
// Check if name exists
|
||||
if (!name.empty() &&
|
||||
!windows.contains(QString::fromStdString(name)))
|
||||
windows << QString::fromStdString(name);
|
||||
// Check if owner exists
|
||||
else if (!owner.empty() &&
|
||||
!windows.contains(
|
||||
QString::fromStdString(name)))
|
||||
windows << QString::fromStdString(owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pair<int, int> getCursorPos() {
|
||||
pair<int, int> pos(0, 0);
|
||||
CGEventRef event = CGEventCreate(NULL);
|
||||
CGPoint cursorPos = CGEventGetLocation(event);
|
||||
CFRelease(event);
|
||||
pos.first = cursorPos.x;
|
||||
pos.second = cursorPos.y;
|
||||
return pos;
|
||||
}
|
||||
void GetCurrentWindowTitle(std::string &title)
|
||||
{
|
||||
title.resize(0);
|
||||
|
||||
bool isFullscreen() {
|
||||
@autoreleasepool {
|
||||
AXValueRef temp;
|
||||
CGSize windowSize;
|
||||
CGPoint windowPosition;
|
||||
AXUIElementRef frontMostApp;
|
||||
AXUIElementRef frontMostWindow;
|
||||
@autoreleasepool {
|
||||
NSMutableArray *apps =
|
||||
(__bridge NSMutableArray *)CGWindowListCopyWindowInfo(
|
||||
kCGWindowListOptionOnScreenOnly,
|
||||
kCGNullWindowID);
|
||||
for (NSDictionary *app in apps) {
|
||||
int layer =
|
||||
[[app objectForKey:@"kCGWindowLayer"] intValue];
|
||||
// True if window is frontmost
|
||||
if (layer == 0) {
|
||||
// Construct string from NSString accounting for nil
|
||||
std::string name(
|
||||
[[app objectForKey:@"kCGWindowName"]
|
||||
UTF8String],
|
||||
[[app objectForKey:@"kCGWindowName"]
|
||||
lengthOfBytesUsingEncoding:
|
||||
NSUTF8StringEncoding]);
|
||||
std::string owner(
|
||||
[[app objectForKey:@"kCGWindowOwnerName"]
|
||||
UTF8String],
|
||||
[[app objectForKey:@"kCGWindowOwnerName"]
|
||||
lengthOfBytesUsingEncoding:
|
||||
NSUTF8StringEncoding]);
|
||||
|
||||
pid_t pid;
|
||||
ProcessSerialNumber psn;
|
||||
@try {
|
||||
GetFrontProcess(&psn);
|
||||
GetProcessPID(&psn, &pid);
|
||||
frontMostApp = AXUIElementCreateApplication(pid);
|
||||
if (!name.empty())
|
||||
title = name;
|
||||
else if (!owner.empty())
|
||||
title = owner;
|
||||
|
||||
AXUIElementCopyAttributeValue(
|
||||
frontMostApp, kAXFocusedWindowAttribute, (CFTypeRef *)&frontMostWindow);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the window size and position
|
||||
AXUIElementCopyAttributeValue(
|
||||
frontMostWindow, kAXSizeAttribute, (CFTypeRef *)&temp);
|
||||
AXValueGetValue(temp, kAXValueTypeCGSize, &windowSize);
|
||||
CFRelease(temp);
|
||||
std::pair<int, int> getCursorPos()
|
||||
{
|
||||
std::pair<int, int> pos(0, 0);
|
||||
CGEventRef event = CGEventCreate(NULL);
|
||||
CGPoint cursorPos = CGEventGetLocation(event);
|
||||
CFRelease(event);
|
||||
pos.first = cursorPos.x;
|
||||
pos.second = cursorPos.y;
|
||||
return pos;
|
||||
}
|
||||
|
||||
AXUIElementCopyAttributeValue(
|
||||
frontMostWindow, kAXPositionAttribute, (CFTypeRef *)&temp);
|
||||
AXValueGetValue(temp, kAXValueTypeCGPoint, &windowPosition);
|
||||
CFRelease(temp);
|
||||
// TODO:
|
||||
// not implemented on MacOS as I cannot test it
|
||||
bool isMaximized(std::string &title)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CGRect screenBound = CGDisplayBounds(CGMainDisplayID());
|
||||
CGSize screenSize = screenBound.size;
|
||||
bool isFullscreen(std::string &title)
|
||||
{
|
||||
// Check for match
|
||||
@autoreleasepool {
|
||||
NSArray *screens = [NSScreen screens];
|
||||
NSMutableArray *apps =
|
||||
(__bridge NSMutableArray *)CGWindowListCopyWindowInfo(
|
||||
kCGWindowListOptionAll, kCGNullWindowID);
|
||||
for (NSDictionary *app in apps) {
|
||||
// Construct string from NSString accounting for nil
|
||||
std::string name([[app objectForKey:@"kCGWindowName"]
|
||||
UTF8String],
|
||||
[[app objectForKey:@"kCGWindowName"]
|
||||
lengthOfBytesUsingEncoding:
|
||||
NSUTF8StringEncoding]);
|
||||
std::string owner([[app objectForKey:@"kCGWindowOwnerName"]
|
||||
UTF8String],
|
||||
[[app objectForKey:@"kCGWindowOwnerName"]
|
||||
lengthOfBytesUsingEncoding:
|
||||
NSUTF8StringEncoding]);
|
||||
|
||||
if((windowSize.width == screenSize.width) && (windowSize.height == screenSize.height) &&
|
||||
(windowPosition.x == 0) && (windowPosition.y == 0))
|
||||
return true;
|
||||
}
|
||||
@catch (...) {
|
||||
// deal with the exception
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
// deal with the exception
|
||||
}
|
||||
// True if switch equals app
|
||||
bool equals = (title == name || title == owner);
|
||||
// True if switch matches app
|
||||
bool matches = (QString::fromStdString(name).contains(
|
||||
QRegularExpression(
|
||||
QString::fromStdString(
|
||||
title))) ||
|
||||
QString::fromStdString(owner).contains(
|
||||
QRegularExpression(
|
||||
QString::fromStdString(
|
||||
title))));
|
||||
|
||||
}
|
||||
return false;
|
||||
// If found, check if fullscreen
|
||||
if (equals || matches) {
|
||||
// Get window bounds
|
||||
NSRect bounds;
|
||||
CGRectMakeWithDictionaryRepresentation(
|
||||
(CFDictionaryRef)[app
|
||||
objectForKey:@"kCGWindowBounds"],
|
||||
&bounds);
|
||||
|
||||
// Compare to screen bounds
|
||||
for (NSScreen *screen in screens) {
|
||||
NSRect frame = [screen visibleFrame];
|
||||
|
||||
// True if flipped window origin equals screen origin
|
||||
bool origin =
|
||||
(bounds.origin.x ==
|
||||
frame.origin.x &&
|
||||
([screens[0] visibleFrame]
|
||||
.size.height -
|
||||
frame.size.height -
|
||||
bounds.origin.y ==
|
||||
frame.origin.y));
|
||||
// True if window size equals screen size
|
||||
bool size = NSEqualSizes(bounds.size,
|
||||
frame.size);
|
||||
|
||||
if (origin && size)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int secondsSinceLastInput()
|
||||
{
|
||||
double time = CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateCombinedSessionState, kCGAnyInputEventType) + 0.5;
|
||||
return (int) time;
|
||||
double time = CGEventSourceSecondsSinceLastEventType(
|
||||
kCGEventSourceStateCombinedSessionState,
|
||||
kCGAnyInputEventType) +
|
||||
0.5;
|
||||
return (int)time;
|
||||
}
|
||||
|
||||
void GetProcessList(QStringList& list)
|
||||
void GetProcessList(QStringList &list)
|
||||
{
|
||||
list.clear();
|
||||
@autoreleasepool {
|
||||
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
|
||||
NSArray *array = [ws runningApplications];
|
||||
for (NSRunningApplication *app in array) {
|
||||
NSString *name = app.localizedName;
|
||||
if (!name)
|
||||
continue;
|
||||
|
||||
const char *str = name.UTF8String;
|
||||
if (str && *str)
|
||||
list << (str);
|
||||
}
|
||||
}
|
||||
list.clear();
|
||||
@autoreleasepool {
|
||||
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
|
||||
NSArray *array = [ws runningApplications];
|
||||
for (NSRunningApplication *app in array) {
|
||||
NSString *name = app.localizedName;
|
||||
if (!name)
|
||||
continue;
|
||||
|
||||
const char *str = name.UTF8String;
|
||||
if (str && *str)
|
||||
list << (str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool isInFocus(QString const& appQName)
|
||||
bool isInFocus(const QString &executable)
|
||||
{
|
||||
QByteArray ba = appQName.toLocal8Bit();
|
||||
const char * appName = ba.data();
|
||||
@autoreleasepool {
|
||||
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
|
||||
NSRunningApplication *app = [ws frontmostApplication];
|
||||
if (app) {
|
||||
NSString *name = app.localizedName;
|
||||
if (!name)
|
||||
return false;
|
||||
|
||||
const char *str = name.UTF8String;
|
||||
return (str && *str && strcmp(appName,str) == 0 )? true : false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
std::string current;
|
||||
GetCurrentWindowTitle(current);
|
||||
|
||||
// True if executable switch equals current window
|
||||
bool equals = (executable.toStdString() == current);
|
||||
// True if executable switch matches current window
|
||||
bool matches = QString::fromStdString(current).contains(
|
||||
QRegularExpression(executable));
|
||||
|
||||
return (equals || matches);
|
||||
}
|
||||
|
||||
@@ -1,242 +0,0 @@
|
||||
#include "headers/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<QListWidgetItem*> 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<mutex> 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<mutex> 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<QListWidgetItem*> 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<mutex> 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<mutex> 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<mutex> 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<mutex> 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;
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
#include <algorithm>
|
||||
#include "headers/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<mutex> 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<mutex> 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 > 7)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
144
src/random.cpp
144
src/random.cpp
@@ -1,144 +0,0 @@
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
#include <random>
|
||||
|
||||
void SceneSwitcher::on_randomScenesList_currentRowChanged(int idx)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
QListWidgetItem* item = ui->randomScenesList->item(idx);
|
||||
|
||||
QString randomSceneStr = item->data(Qt::UserRole).toString();
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->randomSwitches)
|
||||
{
|
||||
if (randomSceneStr.compare(s.randomSwitchStr.c_str()) == 0)
|
||||
{
|
||||
QString sceneName = GetWeakSourceName(s.scene).c_str();
|
||||
QString transitionName = GetWeakSourceName(s.transition).c_str();
|
||||
ui->randomScenes->setCurrentText(sceneName);
|
||||
ui->randomSpinBox->setValue(s.delay);
|
||||
ui->randomTransitions->setCurrentText(transitionName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int SceneSwitcher::randomFindByData(const QString& randomStr)
|
||||
{
|
||||
int count = ui->randomScenesList->count();
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
QListWidgetItem* item = ui->randomScenesList->item(i);
|
||||
QString str = item->data(Qt::UserRole).toString();
|
||||
|
||||
if (str == randomStr)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_randomAdd_clicked()
|
||||
{
|
||||
QString sceneName = ui->randomScenes->currentText();
|
||||
QString transitionName = ui->randomTransitions->currentText();
|
||||
double delay = ui->randomSpinBox->value();
|
||||
|
||||
|
||||
if (sceneName.isEmpty())
|
||||
return;
|
||||
|
||||
OBSWeakSource source = GetWeakSourceByQString(sceneName);
|
||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
||||
|
||||
|
||||
QString text = MakeRandomSwitchName(sceneName, transitionName, delay);
|
||||
QVariant v = QVariant::fromValue(text);
|
||||
|
||||
int idx = randomFindByData(text);
|
||||
|
||||
if (idx == -1)
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->randomSwitches.emplace_back(
|
||||
source, transition, delay, text.toUtf8().constData());
|
||||
|
||||
QListWidgetItem* item = new QListWidgetItem(text, ui->randomScenesList);
|
||||
item->setData(Qt::UserRole, v);
|
||||
}
|
||||
else
|
||||
{
|
||||
QListWidgetItem* item = ui->randomScenesList->item(idx);
|
||||
item->setText(text);
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->randomSwitches)
|
||||
{
|
||||
if (s.scene == source)
|
||||
{
|
||||
s.delay = delay;
|
||||
s.transition = transition;
|
||||
s.randomSwitchStr = text.toUtf8().constData();;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui->randomScenesList->sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_randomRemove_clicked()
|
||||
{
|
||||
QListWidgetItem* item = ui->randomScenesList->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
string text = item->data(Qt::UserRole).toString().toUtf8().constData();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
auto& switches = switcher->randomSwitches;
|
||||
|
||||
for (auto it = switches.begin(); it != switches.end(); ++it)
|
||||
{
|
||||
auto& s = *it;
|
||||
|
||||
if (s.randomSwitchStr == text)
|
||||
{
|
||||
switches.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void SwitcherData::checkRandom(bool& match, OBSWeakSource& scene, OBSWeakSource& transition, int& delay)
|
||||
{
|
||||
if (randomSwitches.size() == 0)
|
||||
return;
|
||||
|
||||
vector<RandomSwitch> rs (randomSwitches);
|
||||
std::random_device rng;
|
||||
std::mt19937 urng(rng());
|
||||
std::shuffle(rs.begin(), rs.end(), urng);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,312 +0,0 @@
|
||||
#include <QFileDialog>
|
||||
#include <QTextStream>
|
||||
#include <obs.hpp>
|
||||
|
||||
#include "headers/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<mutex> lock(switcher->m);
|
||||
switcher->sceneRoundTripSwitches.emplace_back(
|
||||
source1, source2, transition, int(delay * 1000),
|
||||
(scene2Name == QString(PREVIOUS_SCENE_NAME)),
|
||||
text.toUtf8().constData());
|
||||
}
|
||||
else
|
||||
{
|
||||
QListWidgetItem* item = ui->sceneRoundTrips->item(idx);
|
||||
item->setText(text);
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->sceneRoundTripSwitches)
|
||||
{
|
||||
if (s.scene1 == source1)
|
||||
{
|
||||
s.scene2 = source2;
|
||||
s.delay = int(delay * 1000);
|
||||
s.transition = transition;
|
||||
s.usePreviousScene = (scene2Name == QString(PREVIOUS_SCENE_NAME));
|
||||
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<mutex> 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<mutex> 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<mutex> 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";
|
||||
if (s.usePreviousScene)
|
||||
out << (PREVIOUS_SCENE_NAME) << "\n";
|
||||
else
|
||||
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<mutex> 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<QString> lines;
|
||||
|
||||
vector<SceneRoundTripSwitch> 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) && ((lines[1] == QString(PREVIOUS_SCENE_NAME)) || (WeakSourceValid(scene2)))
|
||||
&& WeakSourceValid(transition))
|
||||
{
|
||||
newSceneRoundTripSwitch.emplace_back(SceneRoundTripSwitch(
|
||||
GetWeakSourceByQString(lines[0]),
|
||||
GetWeakSourceByQString(lines[1]),
|
||||
GetWeakTransitionByQString(lines[4]),
|
||||
lines[2].toInt(),
|
||||
(lines[1] == QString(PREVIOUS_SCENE_NAME)),
|
||||
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<mutex>& 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.usePreviousScene) ? previousScene : 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<mutex> 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);
|
||||
}
|
||||
@@ -1,284 +0,0 @@
|
||||
#include "headers/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<mutex> 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<mutex> 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<mutex> 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<mutex> lock(switcher->m);
|
||||
switcher->defaultSceneTransitions.emplace_back(
|
||||
source, transition, text.toUtf8().constData());
|
||||
}
|
||||
else
|
||||
{
|
||||
QListWidgetItem* item = ui->defaultTransitions->item(idx);
|
||||
item->setText(text);
|
||||
|
||||
{
|
||||
lock_guard<mutex> 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<mutex> 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()
|
||||
{
|
||||
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<mutex> 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<mutex> 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;
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
|
||||
void SwitcherData::checkScreenRegionSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
|
||||
{
|
||||
pair<int, int> 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<int, int> 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<mutex> 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<mutex> 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<mutex> 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<mutex> 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;
|
||||
}
|
||||
442
src/switch-audio.cpp
Normal file
442
src/switch-audio.cpp
Normal file
@@ -0,0 +1,442 @@
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
#include "headers/volume-control.hpp"
|
||||
#include "headers/utility.hpp"
|
||||
|
||||
static QMetaObject::Connection addPulse;
|
||||
|
||||
void AdvSceneSwitcher::on_audioAdd_clicked()
|
||||
{
|
||||
ui->audioAdd->disconnect(addPulse);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->audioSwitches.emplace_back();
|
||||
|
||||
QListWidgetItem *item;
|
||||
item = new QListWidgetItem(ui->audioSwitches);
|
||||
ui->audioSwitches->addItem(item);
|
||||
AudioSwitchWidget *sw =
|
||||
new AudioSwitchWidget(&switcher->audioSwitches.back());
|
||||
item->setSizeHint(sw->minimumSizeHint());
|
||||
ui->audioSwitches->setItemWidget(item, sw);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_audioRemove_clicked()
|
||||
{
|
||||
QListWidgetItem *item = ui->audioSwitches->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
int idx = ui->audioSwitches->currentRow();
|
||||
auto &switches = switcher->audioSwitches;
|
||||
switches.erase(switches.begin() + idx);
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_audioUp_clicked()
|
||||
{
|
||||
int index = ui->audioSwitches->currentRow();
|
||||
if (!listMoveUp(ui->audioSwitches))
|
||||
return;
|
||||
|
||||
AudioSwitchWidget *s1 =
|
||||
(AudioSwitchWidget *)ui->audioSwitches->itemWidget(
|
||||
ui->audioSwitches->item(index));
|
||||
AudioSwitchWidget *s2 =
|
||||
(AudioSwitchWidget *)ui->audioSwitches->itemWidget(
|
||||
ui->audioSwitches->item(index - 1));
|
||||
AudioSwitchWidget::swapSwitchData(s1, s2);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
std::swap(switcher->audioSwitches[index],
|
||||
switcher->audioSwitches[index - 1]);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_audioDown_clicked()
|
||||
{
|
||||
int index = ui->audioSwitches->currentRow();
|
||||
|
||||
if (!listMoveDown(ui->audioSwitches))
|
||||
return;
|
||||
|
||||
AudioSwitchWidget *s1 =
|
||||
(AudioSwitchWidget *)ui->audioSwitches->itemWidget(
|
||||
ui->audioSwitches->item(index));
|
||||
AudioSwitchWidget *s2 =
|
||||
(AudioSwitchWidget *)ui->audioSwitches->itemWidget(
|
||||
ui->audioSwitches->item(index + 1));
|
||||
AudioSwitchWidget::swapSwitchData(s1, s2);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
std::swap(switcher->audioSwitches[index],
|
||||
switcher->audioSwitches[index + 1]);
|
||||
}
|
||||
|
||||
void SwitcherData::checkAudioSwitch(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition)
|
||||
{
|
||||
if (audioSwitches.size() == 0)
|
||||
return;
|
||||
|
||||
for (AudioSwitch &s : audioSwitches) {
|
||||
if (!s.initialized())
|
||||
continue;
|
||||
|
||||
obs_source_t *as = obs_weak_source_get_source(s.audioSource);
|
||||
bool audioActive = obs_source_active(as);
|
||||
obs_source_release(as);
|
||||
|
||||
// peak will have a value from -60 db to 0 db
|
||||
bool volumeThresholdreached = ((double)s.peak + 60) * 1.7 >
|
||||
s.volumeThreshold;
|
||||
|
||||
if (volumeThresholdreached && audioActive) {
|
||||
scene = (s.usePreviousScene) ? previousScene : s.scene;
|
||||
transition = s.transition;
|
||||
match = true;
|
||||
|
||||
if (verbose)
|
||||
s.logMatch();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SwitcherData::saveAudioSwitches(obs_data_t *obj)
|
||||
{
|
||||
obs_data_array_t *audioArray = obs_data_array_create();
|
||||
for (AudioSwitch &s : switcher->audioSwitches) {
|
||||
obs_data_t *array_obj = obs_data_create();
|
||||
|
||||
obs_source_t *sceneSource = obs_weak_source_get_source(s.scene);
|
||||
obs_source_t *transition =
|
||||
obs_weak_source_get_source(s.transition);
|
||||
obs_source_t *audioSrouce =
|
||||
obs_weak_source_get_source(s.audioSource);
|
||||
if ((s.usePreviousScene || sceneSource) && transition &&
|
||||
audioSrouce) {
|
||||
const char *sceneName =
|
||||
obs_source_get_name(sceneSource);
|
||||
const char *transitionName =
|
||||
obs_source_get_name(transition);
|
||||
const char *audioSourceName =
|
||||
obs_source_get_name(audioSrouce);
|
||||
obs_data_set_string(array_obj, "scene",
|
||||
s.usePreviousScene
|
||||
? previous_scene_name
|
||||
: sceneName);
|
||||
obs_data_set_string(array_obj, "transition",
|
||||
transitionName);
|
||||
obs_data_set_string(array_obj, "audioSource",
|
||||
audioSourceName);
|
||||
obs_data_set_int(array_obj, "volume",
|
||||
s.volumeThreshold);
|
||||
obs_data_array_push_back(audioArray, array_obj);
|
||||
}
|
||||
obs_source_release(sceneSource);
|
||||
obs_source_release(transition);
|
||||
obs_source_release(audioSrouce);
|
||||
|
||||
obs_data_release(array_obj);
|
||||
}
|
||||
obs_data_set_array(obj, "audioSwitches", audioArray);
|
||||
obs_data_array_release(audioArray);
|
||||
}
|
||||
|
||||
void SwitcherData::loadAudioSwitches(obs_data_t *obj)
|
||||
{
|
||||
switcher->audioSwitches.clear();
|
||||
|
||||
obs_data_array_t *audioArray = obs_data_get_array(obj, "audioSwitches");
|
||||
size_t count = obs_data_array_count(audioArray);
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
obs_data_t *array_obj = obs_data_array_item(audioArray, i);
|
||||
|
||||
const char *scene = obs_data_get_string(array_obj, "scene");
|
||||
const char *transition =
|
||||
obs_data_get_string(array_obj, "transition");
|
||||
const char *audioSource =
|
||||
obs_data_get_string(array_obj, "audioSource");
|
||||
int vol = obs_data_get_int(array_obj, "volume");
|
||||
|
||||
switcher->audioSwitches.emplace_back(
|
||||
GetWeakSourceByName(scene),
|
||||
GetWeakTransitionByName(transition),
|
||||
GetWeakSourceByName(audioSource), vol,
|
||||
(strcmp(scene, previous_scene_name) == 0));
|
||||
|
||||
obs_data_release(array_obj);
|
||||
}
|
||||
obs_data_array_release(audioArray);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupAudioTab()
|
||||
{
|
||||
for (auto &s : switcher->audioSwitches) {
|
||||
QListWidgetItem *item;
|
||||
item = new QListWidgetItem(ui->audioSwitches);
|
||||
ui->audioSwitches->addItem(item);
|
||||
AudioSwitchWidget *sw = new AudioSwitchWidget(&s);
|
||||
item->setSizeHint(sw->minimumSizeHint());
|
||||
ui->audioSwitches->setItemWidget(item, sw);
|
||||
}
|
||||
|
||||
if (switcher->audioSwitches.size() == 0)
|
||||
addPulse = PulseWidget(ui->audioAdd, QColor(Qt::green));
|
||||
}
|
||||
|
||||
void AudioSwitch::setVolumeLevel(void *data,
|
||||
const float magnitude[MAX_AUDIO_CHANNELS],
|
||||
const float peak[MAX_AUDIO_CHANNELS],
|
||||
const float inputPeak[MAX_AUDIO_CHANNELS])
|
||||
{
|
||||
UNUSED_PARAMETER(magnitude);
|
||||
UNUSED_PARAMETER(inputPeak);
|
||||
AudioSwitch *s = static_cast<AudioSwitch *>(data);
|
||||
|
||||
s->peak = peak[0];
|
||||
for (int i = 1; i < MAX_AUDIO_CHANNELS; i++)
|
||||
if (peak[i] > s->peak)
|
||||
s->peak = peak[i];
|
||||
}
|
||||
|
||||
void AudioSwitch::resetVolmeter()
|
||||
{
|
||||
obs_volmeter_remove_callback(volmeter, setVolumeLevel, this);
|
||||
obs_volmeter_destroy(volmeter);
|
||||
|
||||
volmeter = obs_volmeter_create(OBS_FADER_LOG);
|
||||
obs_volmeter_add_callback(volmeter, setVolumeLevel, this);
|
||||
obs_source_t *as = obs_weak_source_get_source(audioSource);
|
||||
if (!obs_volmeter_attach_source(volmeter, as)) {
|
||||
const char *name = obs_source_get_name(as);
|
||||
blog(LOG_WARNING, "failed to attach volmeter to source %s",
|
||||
name);
|
||||
}
|
||||
obs_source_release(as);
|
||||
}
|
||||
|
||||
bool AudioSwitch::initialized()
|
||||
{
|
||||
return SceneSwitcherEntry::initialized() && audioSource;
|
||||
}
|
||||
|
||||
bool AudioSwitch::valid()
|
||||
{
|
||||
return !initialized() ||
|
||||
(SceneSwitcherEntry::valid() && WeakSourceValid(audioSource));
|
||||
}
|
||||
|
||||
AudioSwitch::AudioSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
||||
OBSWeakSource audioSource_, int volumeThreshold_,
|
||||
bool usePreviousScene_)
|
||||
: SceneSwitcherEntry(scene_, transition_, usePreviousScene_),
|
||||
audioSource(audioSource_),
|
||||
volumeThreshold(volumeThreshold_)
|
||||
{
|
||||
volmeter = obs_volmeter_create(OBS_FADER_LOG);
|
||||
obs_volmeter_add_callback(volmeter, setVolumeLevel, this);
|
||||
obs_source_t *as = obs_weak_source_get_source(audioSource);
|
||||
if (!obs_volmeter_attach_source(volmeter, as)) {
|
||||
const char *name = obs_source_get_name(as);
|
||||
blog(LOG_WARNING, "failed to attach volmeter to source %s",
|
||||
name);
|
||||
}
|
||||
obs_source_release(as);
|
||||
}
|
||||
|
||||
AudioSwitch::AudioSwitch(const AudioSwitch &other)
|
||||
: SceneSwitcherEntry(other.scene, other.transition,
|
||||
other.usePreviousScene),
|
||||
audioSource(other.audioSource),
|
||||
volumeThreshold(other.volumeThreshold)
|
||||
{
|
||||
volmeter = obs_volmeter_create(OBS_FADER_LOG);
|
||||
obs_volmeter_add_callback(volmeter, setVolumeLevel, this);
|
||||
obs_source_t *as = obs_weak_source_get_source(other.audioSource);
|
||||
if (!obs_volmeter_attach_source(volmeter, as)) {
|
||||
const char *name = obs_source_get_name(as);
|
||||
blog(LOG_WARNING, "failed to attach volmeter to source %s",
|
||||
name);
|
||||
}
|
||||
obs_source_release(as);
|
||||
}
|
||||
|
||||
AudioSwitch::AudioSwitch(AudioSwitch &&other)
|
||||
: SceneSwitcherEntry(other.scene, other.transition,
|
||||
other.usePreviousScene),
|
||||
audioSource(other.audioSource),
|
||||
volumeThreshold(other.volumeThreshold),
|
||||
volmeter(other.volmeter)
|
||||
{
|
||||
other.volmeter = nullptr;
|
||||
}
|
||||
|
||||
AudioSwitch::~AudioSwitch()
|
||||
{
|
||||
obs_volmeter_remove_callback(volmeter, setVolumeLevel, this);
|
||||
obs_volmeter_destroy(volmeter);
|
||||
}
|
||||
|
||||
AudioSwitch &AudioSwitch::operator=(const AudioSwitch &other)
|
||||
{
|
||||
AudioSwitch t(other);
|
||||
swap(*this, t);
|
||||
return *this = AudioSwitch(other);
|
||||
}
|
||||
|
||||
AudioSwitch &AudioSwitch::operator=(AudioSwitch &&other) noexcept
|
||||
{
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
swap(*this, other);
|
||||
|
||||
obs_volmeter_remove_callback(other.volmeter, setVolumeLevel, this);
|
||||
obs_volmeter_destroy(other.volmeter);
|
||||
other.volmeter = nullptr;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(AudioSwitch &first, AudioSwitch &second)
|
||||
{
|
||||
std::swap(first.scene, second.scene);
|
||||
std::swap(first.transition, second.transition);
|
||||
std::swap(first.usePreviousScene, second.usePreviousScene);
|
||||
std::swap(first.audioSource, second.audioSource);
|
||||
std::swap(first.volumeThreshold, second.volumeThreshold);
|
||||
std::swap(first.peak, second.peak);
|
||||
std::swap(first.volmeter, second.volmeter);
|
||||
first.resetVolmeter();
|
||||
second.resetVolmeter();
|
||||
}
|
||||
|
||||
AudioSwitchWidget::AudioSwitchWidget(AudioSwitch *s) : SwitchWidget(s)
|
||||
{
|
||||
audioSources = new QComboBox();
|
||||
audioVolumeThreshold = new QSpinBox();
|
||||
|
||||
obs_source_t *soruce = nullptr;
|
||||
if (s)
|
||||
soruce = obs_weak_source_get_source(s->audioSource);
|
||||
volMeter = new VolControl(soruce);
|
||||
obs_source_release(soruce);
|
||||
|
||||
whenLabel = new QLabel("When the volume of");
|
||||
aboveLabel = new QLabel("is above");
|
||||
switchLabel = new QLabel("switch to");
|
||||
usingLabel = new QLabel("using");
|
||||
|
||||
audioVolumeThreshold->setSuffix("%");
|
||||
audioVolumeThreshold->setMaximum(100);
|
||||
audioVolumeThreshold->setMinimum(0);
|
||||
|
||||
QWidget::connect(volMeter->GetSlider(), SIGNAL(valueChanged(int)),
|
||||
audioVolumeThreshold, SLOT(setValue(int)));
|
||||
QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)),
|
||||
volMeter->GetSlider(), SLOT(setValue(int)));
|
||||
QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)), this,
|
||||
SLOT(VolumeThresholdChanged(int)));
|
||||
QWidget::connect(audioSources,
|
||||
SIGNAL(currentTextChanged(const QString &)), this,
|
||||
SLOT(SourceChanged(const QString &)));
|
||||
|
||||
AdvSceneSwitcher::populateAudioSelection(audioSources);
|
||||
|
||||
if (s) {
|
||||
audioSources->setCurrentText(
|
||||
GetWeakSourceName(s->audioSource).c_str());
|
||||
audioVolumeThreshold->setValue(s->volumeThreshold);
|
||||
}
|
||||
|
||||
setStyleSheet("* { background-color: transparent; }");
|
||||
|
||||
QHBoxLayout *switchLayout = new QHBoxLayout;
|
||||
|
||||
switchLayout->addWidget(whenLabel);
|
||||
switchLayout->addWidget(audioSources);
|
||||
switchLayout->addWidget(aboveLabel);
|
||||
switchLayout->addWidget(audioVolumeThreshold);
|
||||
switchLayout->addWidget(switchLabel);
|
||||
switchLayout->addWidget(scenes);
|
||||
switchLayout->addWidget(usingLabel);
|
||||
switchLayout->addWidget(transitions);
|
||||
switchLayout->addStretch();
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
|
||||
mainLayout->addLayout(switchLayout);
|
||||
mainLayout->addWidget(volMeter);
|
||||
|
||||
setLayout(mainLayout);
|
||||
|
||||
switchData = s;
|
||||
|
||||
loading = false;
|
||||
}
|
||||
|
||||
AudioSwitch *AudioSwitchWidget::getSwitchData()
|
||||
{
|
||||
return switchData;
|
||||
}
|
||||
|
||||
void AudioSwitchWidget::setSwitchData(AudioSwitch *s)
|
||||
{
|
||||
switchData = s;
|
||||
}
|
||||
|
||||
void AudioSwitchWidget::swapSwitchData(AudioSwitchWidget *s1,
|
||||
AudioSwitchWidget *s2)
|
||||
{
|
||||
SwitchWidget::swapSwitchData(s1, s2);
|
||||
|
||||
AudioSwitch *t = s1->getSwitchData();
|
||||
s1->setSwitchData(s2->getSwitchData());
|
||||
s2->setSwitchData(t);
|
||||
}
|
||||
|
||||
void AudioSwitchWidget::UpdateVolmeterSource()
|
||||
{
|
||||
delete volMeter;
|
||||
obs_source_t *soruce =
|
||||
obs_weak_source_get_source(switchData->audioSource);
|
||||
volMeter = new VolControl(soruce);
|
||||
obs_source_release(soruce);
|
||||
|
||||
QLayout *layout = this->layout();
|
||||
layout->addWidget(volMeter);
|
||||
|
||||
QWidget::connect(volMeter->GetSlider(), SIGNAL(valueChanged(int)),
|
||||
audioVolumeThreshold, SLOT(setValue(int)));
|
||||
QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)),
|
||||
volMeter->GetSlider(), SLOT(setValue(int)));
|
||||
|
||||
// Slider will default to 0 so set it manually once
|
||||
volMeter->GetSlider()->setValue(switchData->volumeThreshold);
|
||||
}
|
||||
|
||||
void AudioSwitchWidget::SourceChanged(const QString &text)
|
||||
{
|
||||
if (loading || !switchData)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->audioSource = GetWeakSourceByQString(text);
|
||||
switchData->resetVolmeter();
|
||||
UpdateVolmeterSource();
|
||||
}
|
||||
|
||||
void AudioSwitchWidget::VolumeThresholdChanged(int vol)
|
||||
{
|
||||
if (loading || !switchData)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->volumeThreshold = vol;
|
||||
}
|
||||
284
src/switch-executable.cpp
Normal file
284
src/switch-executable.cpp
Normal file
@@ -0,0 +1,284 @@
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
#include "headers/utility.hpp"
|
||||
|
||||
static QMetaObject::Connection addPulse;
|
||||
|
||||
void AdvSceneSwitcher::on_executableAdd_clicked()
|
||||
{
|
||||
ui->executableAdd->disconnect(addPulse);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->executableSwitches.emplace_back();
|
||||
|
||||
QListWidgetItem *item;
|
||||
item = new QListWidgetItem(ui->executables);
|
||||
ui->executables->addItem(item);
|
||||
ExecutableSwitchWidget *sw = new ExecutableSwitchWidget(
|
||||
&switcher->executableSwitches.back());
|
||||
item->setSizeHint(sw->minimumSizeHint());
|
||||
ui->executables->setItemWidget(item, sw);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_executableRemove_clicked()
|
||||
{
|
||||
QListWidgetItem *item = ui->executables->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
int idx = ui->executables->currentRow();
|
||||
auto &switches = switcher->executableSwitches;
|
||||
switches.erase(switches.begin() + idx);
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_executableUp_clicked()
|
||||
{
|
||||
int index = ui->executables->currentRow();
|
||||
if (!listMoveUp(ui->executables))
|
||||
return;
|
||||
|
||||
ExecutableSwitchWidget *s1 =
|
||||
(ExecutableSwitchWidget *)ui->executables->itemWidget(
|
||||
ui->executables->item(index));
|
||||
ExecutableSwitchWidget *s2 =
|
||||
(ExecutableSwitchWidget *)ui->executables->itemWidget(
|
||||
ui->executables->item(index - 1));
|
||||
ExecutableSwitchWidget::swapSwitchData(s1, s2);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
std::swap(switcher->executableSwitches[index],
|
||||
switcher->executableSwitches[index - 1]);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_executableDown_clicked()
|
||||
{
|
||||
int index = ui->executables->currentRow();
|
||||
|
||||
if (!listMoveDown(ui->executables))
|
||||
return;
|
||||
|
||||
ExecutableSwitchWidget *s1 =
|
||||
(ExecutableSwitchWidget *)ui->executables->itemWidget(
|
||||
ui->executables->item(index));
|
||||
ExecutableSwitchWidget *s2 =
|
||||
(ExecutableSwitchWidget *)ui->executables->itemWidget(
|
||||
ui->executables->item(index + 1));
|
||||
ExecutableSwitchWidget::swapSwitchData(s1, s2);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
std::swap(switcher->executableSwitches[index],
|
||||
switcher->executableSwitches[index + 1]);
|
||||
}
|
||||
|
||||
void SwitcherData::checkExeSwitch(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition)
|
||||
{
|
||||
std::string title;
|
||||
QStringList runningProcesses;
|
||||
bool ignored = false;
|
||||
|
||||
// Check if current window is ignored
|
||||
GetCurrentWindowTitle(title);
|
||||
for (auto &window : ignoreWindowsSwitches) {
|
||||
// True if ignored switch equals title
|
||||
bool equals = (title == window);
|
||||
// True if ignored switch matches title
|
||||
bool matches = QString::fromStdString(title).contains(
|
||||
QRegularExpression(QString::fromStdString(window)));
|
||||
|
||||
if (equals || matches) {
|
||||
ignored = true;
|
||||
title = lastTitle;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
lastTitle = title;
|
||||
|
||||
// Check for match
|
||||
GetProcessList(runningProcesses);
|
||||
for (ExecutableSwitch &s : executableSwitches) {
|
||||
if (!s.initialized())
|
||||
continue;
|
||||
// True if executable switch is running (direct)
|
||||
bool equals = runningProcesses.contains(s.exe);
|
||||
// True if executable switch is running (regex)
|
||||
bool matches = (runningProcesses.indexOf(
|
||||
QRegularExpression(s.exe)) != -1);
|
||||
// True if focus is disabled OR switch is focused
|
||||
bool focus = (!s.inFocus || isInFocus(s.exe));
|
||||
// True if current window is ignored AND switch equals OR matches last window
|
||||
bool ignore =
|
||||
(ignored && (title == s.exe.toStdString() ||
|
||||
QString::fromStdString(title).contains(
|
||||
QRegularExpression(s.exe))));
|
||||
|
||||
if ((equals || matches) && (focus || ignore)) {
|
||||
match = true;
|
||||
scene = s.scene;
|
||||
transition = s.transition;
|
||||
|
||||
if (verbose)
|
||||
s.logMatch();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SwitcherData::saveExecutableSwitches(obs_data_t *obj)
|
||||
{
|
||||
obs_data_array_t *executableArray = obs_data_array_create();
|
||||
for (ExecutableSwitch &s : switcher->executableSwitches) {
|
||||
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, "exefile",
|
||||
s.exe.toUtf8());
|
||||
obs_data_set_bool(array_obj, "infocus", s.inFocus);
|
||||
obs_data_array_push_back(executableArray, array_obj);
|
||||
}
|
||||
obs_source_release(source);
|
||||
obs_source_release(transition);
|
||||
obs_data_release(array_obj);
|
||||
}
|
||||
obs_data_set_array(obj, "executableSwitches", executableArray);
|
||||
obs_data_array_release(executableArray);
|
||||
}
|
||||
|
||||
void SwitcherData::loadExecutableSwitches(obs_data_t *obj)
|
||||
{
|
||||
switcher->executableSwitches.clear();
|
||||
|
||||
obs_data_array_t *executableArray =
|
||||
obs_data_get_array(obj, "executableSwitches");
|
||||
size_t 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);
|
||||
}
|
||||
obs_data_array_release(executableArray);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupExecutableTab()
|
||||
{
|
||||
for (auto &s : switcher->executableSwitches) {
|
||||
QListWidgetItem *item;
|
||||
item = new QListWidgetItem(ui->executables);
|
||||
ui->executables->addItem(item);
|
||||
ExecutableSwitchWidget *sw = new ExecutableSwitchWidget(&s);
|
||||
item->setSizeHint(sw->minimumSizeHint());
|
||||
ui->executables->setItemWidget(item, sw);
|
||||
}
|
||||
|
||||
if (switcher->executableSwitches.size() == 0)
|
||||
addPulse = PulseWidget(ui->executableAdd, QColor(Qt::green));
|
||||
}
|
||||
|
||||
ExecutableSwitchWidget::ExecutableSwitchWidget(ExecutableSwitch *s)
|
||||
: SwitchWidget(s, false)
|
||||
{
|
||||
processes = new QComboBox();
|
||||
requiresFocus = new QCheckBox("only if focused");
|
||||
|
||||
whenLabel = new QLabel("When");
|
||||
switchLabel = new QLabel("is running switch to");
|
||||
usingLabel = new QLabel("using");
|
||||
|
||||
QWidget::connect(processes, SIGNAL(currentTextChanged(const QString &)),
|
||||
this, SLOT(ProcessChanged(const QString &)));
|
||||
QWidget::connect(requiresFocus, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(FocusChanged(int)));
|
||||
|
||||
AdvSceneSwitcher::populateProcessSelection(processes);
|
||||
|
||||
processes->setEditable(true);
|
||||
processes->setMaxVisibleItems(20);
|
||||
|
||||
if (s) {
|
||||
processes->setCurrentText(s->exe);
|
||||
requiresFocus->setChecked(s->inFocus);
|
||||
}
|
||||
|
||||
setStyleSheet("* { background-color: transparent; }");
|
||||
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||
|
||||
mainLayout->addWidget(whenLabel);
|
||||
mainLayout->addWidget(processes);
|
||||
mainLayout->addWidget(switchLabel);
|
||||
mainLayout->addWidget(scenes);
|
||||
mainLayout->addWidget(usingLabel);
|
||||
mainLayout->addWidget(transitions);
|
||||
mainLayout->addWidget(requiresFocus);
|
||||
mainLayout->addStretch();
|
||||
|
||||
setLayout(mainLayout);
|
||||
|
||||
switchData = s;
|
||||
|
||||
loading = false;
|
||||
}
|
||||
|
||||
ExecutableSwitch *ExecutableSwitchWidget::getSwitchData()
|
||||
{
|
||||
return switchData;
|
||||
}
|
||||
|
||||
void ExecutableSwitchWidget::setSwitchData(ExecutableSwitch *s)
|
||||
{
|
||||
switchData = s;
|
||||
}
|
||||
|
||||
void ExecutableSwitchWidget::swapSwitchData(ExecutableSwitchWidget *s1,
|
||||
ExecutableSwitchWidget *s2)
|
||||
{
|
||||
SwitchWidget::swapSwitchData(s1, s2);
|
||||
|
||||
ExecutableSwitch *t = s1->getSwitchData();
|
||||
s1->setSwitchData(s2->getSwitchData());
|
||||
s2->setSwitchData(t);
|
||||
}
|
||||
|
||||
void ExecutableSwitchWidget::ProcessChanged(const QString &text)
|
||||
{
|
||||
if (loading || !switchData)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->exe = text;
|
||||
}
|
||||
|
||||
void ExecutableSwitchWidget::FocusChanged(int state)
|
||||
{
|
||||
if (loading || !switchData)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->inFocus = state;
|
||||
}
|
||||
497
src/switch-file.cpp
Normal file
497
src/switch-file.cpp
Normal file
@@ -0,0 +1,497 @@
|
||||
#include <QFileDialog>
|
||||
#include <QTextStream>
|
||||
#include <QDateTime>
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
#include "headers/curl-helper.hpp"
|
||||
#include "headers/utility.hpp"
|
||||
|
||||
#define LOCAL_FILE_IDX 0
|
||||
#define REMOTE_FILE_IDX 1
|
||||
|
||||
void AdvSceneSwitcher::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 AdvSceneSwitcher::on_readFileCheckBox_stateChanged(int state)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> 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 AdvSceneSwitcher::on_readPathLineEdit_textChanged(const QString &text)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
if (text.isEmpty()) {
|
||||
switcher->fileIO.readEnabled = false;
|
||||
return;
|
||||
}
|
||||
switcher->fileIO.readEnabled = true;
|
||||
switcher->fileIO.readPath = text.toUtf8().constData();
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_writePathLineEdit_textChanged(const QString &text)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
if (text.isEmpty()) {
|
||||
switcher->fileIO.writeEnabled = false;
|
||||
return;
|
||||
}
|
||||
switcher->fileIO.writeEnabled = true;
|
||||
switcher->fileIO.writePath = text.toUtf8().constData();
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::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();
|
||||
}
|
||||
}
|
||||
|
||||
static size_t WriteCallback(void *contents, size_t size, size_t nmemb,
|
||||
void *userp)
|
||||
{
|
||||
((std::string *)userp)->append((char *)contents, size * nmemb);
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
std::string getRemoteData(std::string &url)
|
||||
{
|
||||
std::string readBuffer;
|
||||
|
||||
if (switcher->curl && f_curl_setopt && f_curl_perform) {
|
||||
f_curl_setopt(switcher->curl, CURLOPT_URL, url.c_str());
|
||||
f_curl_setopt(switcher->curl, CURLOPT_WRITEFUNCTION,
|
||||
WriteCallback);
|
||||
f_curl_setopt(switcher->curl, CURLOPT_WRITEDATA, &readBuffer);
|
||||
f_curl_perform(switcher->curl);
|
||||
}
|
||||
return readBuffer;
|
||||
}
|
||||
|
||||
bool compareIgnoringLineEnding(QString &s1, QString &s2)
|
||||
{
|
||||
/*
|
||||
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 s1stream(&s1);
|
||||
QTextStream s2stream(&s2);
|
||||
|
||||
while (!s1stream.atEnd() && !s2stream.atEnd()) {
|
||||
QString s1s = s1stream.readLine();
|
||||
QString s2s = s2stream.readLine();
|
||||
if (QString::compare(s1s, s2s, Qt::CaseSensitive) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool checkRemoteFileContent(FileSwitch &s)
|
||||
{
|
||||
std::string data = getRemoteData(s.file);
|
||||
bool ret = false;
|
||||
if (s.useRegex) {
|
||||
ret = QString::fromStdString(data).contains(
|
||||
QRegularExpression(QString::fromStdString(s.text)));
|
||||
return ret;
|
||||
}
|
||||
QString t = QString::fromStdString(s.text);
|
||||
QString d = QString::fromStdString(data);
|
||||
|
||||
return compareIgnoringLineEnding(t, d);
|
||||
}
|
||||
|
||||
bool checkLocalFileContent(FileSwitch &s)
|
||||
{
|
||||
bool equal = false;
|
||||
QString t = QString::fromStdString(s.text);
|
||||
QFile file(QString::fromStdString(s.file));
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
return false;
|
||||
|
||||
if (s.useTime) {
|
||||
QDateTime newLastMod = QFileInfo(file).lastModified();
|
||||
if (s.lastMod == newLastMod)
|
||||
return false;
|
||||
s.lastMod = newLastMod;
|
||||
}
|
||||
|
||||
if (s.useRegex) {
|
||||
QTextStream in(&file);
|
||||
QRegExp rx(t);
|
||||
equal = rx.exactMatch(in.readAll());
|
||||
} else {
|
||||
QTextStream in(&file);
|
||||
QString filedata = in.readAll();
|
||||
equal = compareIgnoringLineEnding(filedata, t);
|
||||
}
|
||||
file.close();
|
||||
return equal;
|
||||
}
|
||||
|
||||
void SwitcherData::checkFileContent(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition)
|
||||
{
|
||||
for (FileSwitch &s : fileSwitches) {
|
||||
bool equal = false;
|
||||
if (s.remote) {
|
||||
equal = checkRemoteFileContent(s);
|
||||
} else {
|
||||
equal = checkLocalFileContent(s);
|
||||
}
|
||||
|
||||
if (equal) {
|
||||
scene = s.scene;
|
||||
transition = s.transition;
|
||||
match = true;
|
||||
|
||||
if (verbose)
|
||||
s.logMatch();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::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 AdvSceneSwitcher::on_fileType_currentIndexChanged(int idx)
|
||||
{
|
||||
if (idx == -1)
|
||||
return;
|
||||
if (idx == LOCAL_FILE_IDX) {
|
||||
ui->browseButton_3->setDisabled(false);
|
||||
ui->fileContentTimeCheckBox->setDisabled(false);
|
||||
ui->remoteFileWarningLabel->hide();
|
||||
}
|
||||
if (idx == REMOTE_FILE_IDX) {
|
||||
ui->browseButton_3->setDisabled(true);
|
||||
ui->fileContentTimeCheckBox->setDisabled(true);
|
||||
ui->remoteFileWarningLabel->show();
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_fileAdd_clicked()
|
||||
{
|
||||
QString sceneName = ui->fileScenes->currentText();
|
||||
QString transitionName = ui->fileTransitions->currentText();
|
||||
QString fileName = ui->filePathLineEdit->text();
|
||||
QString text = ui->fileTextEdit->toPlainText();
|
||||
bool remote = (ui->fileType->currentIndex() == REMOTE_FILE_IDX);
|
||||
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);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->fileSwitches.emplace_back(source, transition,
|
||||
fileName.toUtf8().constData(),
|
||||
text.toUtf8().constData(), remote,
|
||||
useRegex, useTime);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_fileRemove_clicked()
|
||||
{
|
||||
QListWidgetItem *item = ui->fileScenesList->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
int idx = ui->fileScenesList->currentRow();
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
auto &switches = switcher->fileSwitches;
|
||||
switches.erase(switches.begin() + idx);
|
||||
}
|
||||
qDeleteAll(ui->fileScenesList->selectedItems());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_fileScenesList_currentRowChanged(int idx)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
if ((int)switcher->fileSwitches.size() <= idx)
|
||||
return;
|
||||
FileSwitch s = switcher->fileSwitches[idx];
|
||||
|
||||
std::string sceneName = GetWeakSourceName(s.scene);
|
||||
std::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());
|
||||
if (s.remote)
|
||||
ui->fileType->setCurrentIndex(REMOTE_FILE_IDX);
|
||||
else
|
||||
ui->fileType->setCurrentIndex(LOCAL_FILE_IDX);
|
||||
ui->fileContentRegExCheckBox->setChecked(s.useRegex);
|
||||
ui->fileContentTimeCheckBox->setChecked(s.useTime);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_fileUp_clicked()
|
||||
{
|
||||
int index = ui->fileScenesList->currentRow();
|
||||
if (index != -1 && index != 0) {
|
||||
ui->fileScenesList->insertItem(
|
||||
index - 1, ui->fileScenesList->takeItem(index));
|
||||
ui->fileScenesList->setCurrentRow(index - 1);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
iter_swap(switcher->fileSwitches.begin() + index,
|
||||
switcher->fileSwitches.begin() + index - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_fileDown_clicked()
|
||||
{
|
||||
int index = ui->fileScenesList->currentRow();
|
||||
if (index != -1 && index != ui->fileScenesList->count() - 1) {
|
||||
ui->fileScenesList->insertItem(
|
||||
index + 1, ui->fileScenesList->takeItem(index));
|
||||
ui->fileScenesList->setCurrentRow(index + 1);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
iter_swap(switcher->fileSwitches.begin() + index,
|
||||
switcher->fileSwitches.begin() + index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void SwitcherData::saveFileSwitches(obs_data_t *obj)
|
||||
{
|
||||
obs_data_array_t *fileArray = obs_data_array_create();
|
||||
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, "remote", s.remote);
|
||||
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);
|
||||
}
|
||||
obs_data_set_array(obj, "fileSwitches", fileArray);
|
||||
obs_data_array_release(fileArray);
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
void SwitcherData::loadFileSwitches(obs_data_t *obj)
|
||||
{
|
||||
switcher->fileSwitches.clear();
|
||||
obs_data_array_t *fileArray = obs_data_get_array(obj, "fileSwitches");
|
||||
size_t 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 remote = obs_data_get_bool(array_obj, "remote");
|
||||
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, remote,
|
||||
useRegex, useTime);
|
||||
|
||||
obs_data_release(array_obj);
|
||||
}
|
||||
obs_data_array_release(fileArray);
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupFileTab()
|
||||
{
|
||||
populateSceneSelection(ui->fileScenes, false);
|
||||
populateTransitionSelection(ui->fileTransitions);
|
||||
|
||||
ui->fileType->addItem("local");
|
||||
ui->fileType->addItem("remote");
|
||||
ui->remoteFileWarningLabel->setText(
|
||||
"Note that the scene switcher will try to access the remote location every " +
|
||||
QString::number(switcher->interval) + "ms");
|
||||
|
||||
if (switcher->curl)
|
||||
ui->libcurlWarning->setVisible(false);
|
||||
|
||||
for (auto &s : switcher->fileSwitches) {
|
||||
std::string sceneName = GetWeakSourceName(s.scene);
|
||||
std::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->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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
89
src/switch-generic.cpp
Normal file
89
src/switch-generic.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
#include "headers/utility.hpp"
|
||||
|
||||
bool SceneSwitcherEntry::initialized()
|
||||
{
|
||||
return (usePreviousScene || WeakSourceValid(scene)) && transition;
|
||||
}
|
||||
|
||||
bool SceneSwitcherEntry::valid()
|
||||
{
|
||||
return !initialized() ||
|
||||
((usePreviousScene || WeakSourceValid(scene)) &&
|
||||
WeakSourceValid(transition));
|
||||
}
|
||||
|
||||
void SceneSwitcherEntry::logMatch()
|
||||
{
|
||||
const char *sceneName = previous_scene_name;
|
||||
if (!usePreviousScene) {
|
||||
obs_source_t *s = obs_weak_source_get_source(scene);
|
||||
sceneName = obs_source_get_name(s);
|
||||
obs_source_release(s);
|
||||
}
|
||||
blog(LOG_INFO, "match for '%s' - switch to scene '%s'", getType(),
|
||||
sceneName);
|
||||
}
|
||||
|
||||
SwitchWidget::SwitchWidget(SceneSwitcherEntry *s, bool usePreviousScene)
|
||||
{
|
||||
scenes = new QComboBox();
|
||||
transitions = new QComboBox();
|
||||
|
||||
QWidget::connect(scenes, SIGNAL(currentTextChanged(const QString &)),
|
||||
this, SLOT(SceneChanged(const QString &)));
|
||||
QWidget::connect(transitions,
|
||||
SIGNAL(currentTextChanged(const QString &)), this,
|
||||
SLOT(TransitionChanged(const QString &)));
|
||||
|
||||
AdvSceneSwitcher::populateSceneSelection(scenes, usePreviousScene);
|
||||
AdvSceneSwitcher::populateTransitionSelection(transitions);
|
||||
|
||||
if (s) {
|
||||
if (s->usePreviousScene)
|
||||
scenes->setCurrentText(previous_scene_name);
|
||||
else
|
||||
scenes->setCurrentText(
|
||||
GetWeakSourceName(s->scene).c_str());
|
||||
transitions->setCurrentText(
|
||||
GetWeakSourceName(s->transition).c_str());
|
||||
}
|
||||
|
||||
switchData = s;
|
||||
}
|
||||
|
||||
SceneSwitcherEntry *SwitchWidget::getSwitchData()
|
||||
{
|
||||
return switchData;
|
||||
}
|
||||
|
||||
void SwitchWidget::setSwitchData(SceneSwitcherEntry *s)
|
||||
{
|
||||
switchData = s;
|
||||
}
|
||||
|
||||
void SwitchWidget::swapSwitchData(SwitchWidget *s1, SwitchWidget *s2)
|
||||
{
|
||||
SceneSwitcherEntry *t = s1->getSwitchData();
|
||||
s1->setSwitchData(s2->getSwitchData());
|
||||
s2->setSwitchData(t);
|
||||
}
|
||||
|
||||
void SwitchWidget::SceneChanged(const QString &text)
|
||||
{
|
||||
if (loading || !switchData)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->usePreviousScene = text.compare(previous_scene_name) == 0;
|
||||
if (switchData->usePreviousScene)
|
||||
return;
|
||||
switchData->scene = GetWeakSourceByQString(text);
|
||||
}
|
||||
|
||||
void SwitchWidget::TransitionChanged(const QString &text)
|
||||
{
|
||||
if (loading || !switchData)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->transition = GetWeakTransitionByQString(text);
|
||||
}
|
||||
300
src/switch-idle.cpp
Normal file
300
src/switch-idle.cpp
Normal file
@@ -0,0 +1,300 @@
|
||||
#include <regex>
|
||||
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
#include "headers/utility.hpp"
|
||||
|
||||
void SwitcherData::checkIdleSwitch(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition)
|
||||
{
|
||||
if (!idleData.idleEnable)
|
||||
return;
|
||||
|
||||
std::string title;
|
||||
bool ignoreIdle = false;
|
||||
//lock.unlock();
|
||||
GetCurrentWindowTitle(title);
|
||||
//lock.lock();
|
||||
|
||||
for (std::string &window : ignoreIdleWindows) {
|
||||
if (window == title) {
|
||||
ignoreIdle = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ignoreIdle) {
|
||||
for (std::string &window : ignoreIdleWindows) {
|
||||
try {
|
||||
bool matches = std::regex_match(
|
||||
title, std::regex(window));
|
||||
if (matches) {
|
||||
ignoreIdle = true;
|
||||
break;
|
||||
}
|
||||
} catch (const std::regex_error &) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ignoreIdle && secondsSinceLastInput() > idleData.time) {
|
||||
if (idleData.alreadySwitched)
|
||||
return;
|
||||
scene = (idleData.usePreviousScene) ? previousScene
|
||||
: idleData.scene;
|
||||
transition = idleData.transition;
|
||||
match = true;
|
||||
idleData.alreadySwitched = true;
|
||||
|
||||
if (verbose)
|
||||
idleData.logMatch();
|
||||
} else
|
||||
idleData.alreadySwitched = false;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_idleCheckBox_stateChanged(int state)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> 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 AdvSceneSwitcher::UpdateIdleDataTransition(const QString &name)
|
||||
{
|
||||
obs_weak_source_t *transition = GetWeakTransitionByQString(name);
|
||||
switcher->idleData.transition = transition;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::UpdateIdleDataScene(const QString &name)
|
||||
{
|
||||
switcher->idleData.usePreviousScene = (name == previous_scene_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 AdvSceneSwitcher::on_idleTransitions_currentTextChanged(const QString &text)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
UpdateIdleDataTransition(text);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_idleScenes_currentTextChanged(const QString &text)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
UpdateIdleDataScene(text);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_idleSpinBox_valueChanged(int i)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->idleData.time = i;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::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();
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
for (auto &w : switcher->ignoreIdleWindows) {
|
||||
if (window.compare(w.c_str()) == 0) {
|
||||
ui->ignoreIdleWindowsWindows->setCurrentText(w.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_ignoreIdleAdd_clicked()
|
||||
{
|
||||
QString windowName = ui->ignoreIdleWindowsWindows->currentText();
|
||||
|
||||
if (windowName.isEmpty())
|
||||
return;
|
||||
|
||||
QVariant v = QVariant::fromValue(windowName);
|
||||
|
||||
QList<QListWidgetItem *> items =
|
||||
ui->ignoreIdleWindows->findItems(windowName, Qt::MatchExactly);
|
||||
|
||||
if (items.size() == 0) {
|
||||
QListWidgetItem *item =
|
||||
new QListWidgetItem(windowName, ui->ignoreIdleWindows);
|
||||
item->setData(Qt::UserRole, v);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->ignoreIdleWindows.emplace_back(
|
||||
windowName.toUtf8().constData());
|
||||
ui->ignoreIdleWindows->sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_ignoreIdleRemove_clicked()
|
||||
{
|
||||
QListWidgetItem *item = ui->ignoreIdleWindows->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
QString windowName = item->data(Qt::UserRole).toString();
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> 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 AdvSceneSwitcher::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;
|
||||
}
|
||||
|
||||
void SwitcherData::saveIdleSwitches(obs_data_t *obj)
|
||||
{
|
||||
obs_data_array_t *ignoreIdleWindowsArray = obs_data_array_create();
|
||||
for (std::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);
|
||||
}
|
||||
obs_data_set_array(obj, "ignoreIdleWindows", ignoreIdleWindowsArray);
|
||||
obs_data_array_release(ignoreIdleWindowsArray);
|
||||
|
||||
std::string idleSceneName = GetWeakSourceName(switcher->idleData.scene);
|
||||
std::string idleTransitionName =
|
||||
GetWeakSourceName(switcher->idleData.transition);
|
||||
obs_data_set_bool(obj, "idleEnable", switcher->idleData.idleEnable);
|
||||
obs_data_set_string(obj, "idleSceneName",
|
||||
switcher->idleData.usePreviousScene
|
||||
? previous_scene_name
|
||||
: idleSceneName.c_str());
|
||||
obs_data_set_string(obj, "idleTransitionName",
|
||||
idleTransitionName.c_str());
|
||||
obs_data_set_int(obj, "idleTime", switcher->idleData.time);
|
||||
}
|
||||
|
||||
void SwitcherData::loadIdleSwitches(obs_data_t *obj)
|
||||
{
|
||||
switcher->ignoreIdleWindows.clear();
|
||||
|
||||
obs_data_array_t *ignoreIdleWindowsArray =
|
||||
obs_data_get_array(obj, "ignoreIdleWindows");
|
||||
size_t 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);
|
||||
}
|
||||
obs_data_array_release(ignoreIdleWindowsArray);
|
||||
|
||||
std::string idleSceneName = obs_data_get_string(obj, "idleSceneName");
|
||||
std::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");
|
||||
switcher->idleData.usePreviousScene =
|
||||
(idleSceneName == previous_scene_name);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupIdleTab()
|
||||
{
|
||||
populateSceneSelection(ui->idleScenes, true);
|
||||
populateTransitionSelection(ui->idleTransitions);
|
||||
populateWindowSelection(ui->ignoreIdleWindowsWindows);
|
||||
|
||||
for (auto &window : switcher->ignoreIdleWindows) {
|
||||
QString text = QString::fromStdString(window);
|
||||
|
||||
QListWidgetItem *item =
|
||||
new QListWidgetItem(text, ui->ignoreIdleWindows);
|
||||
item->setData(Qt::UserRole, text);
|
||||
}
|
||||
|
||||
ui->idleCheckBox->setChecked(switcher->idleData.idleEnable);
|
||||
ui->idleScenes->setCurrentText(
|
||||
switcher->idleData.usePreviousScene
|
||||
? previous_scene_name
|
||||
: 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);
|
||||
}
|
||||
}
|
||||
535
src/switch-media.cpp
Normal file
535
src/switch-media.cpp
Normal file
@@ -0,0 +1,535 @@
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
#include "headers/utility.hpp"
|
||||
|
||||
static QMetaObject::Connection addPulse;
|
||||
|
||||
void AdvSceneSwitcher::on_mediaAdd_clicked()
|
||||
{
|
||||
ui->mediaAdd->disconnect(addPulse);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->mediaSwitches.emplace_back();
|
||||
|
||||
QListWidgetItem *item;
|
||||
item = new QListWidgetItem(ui->mediaSwitches);
|
||||
ui->mediaSwitches->addItem(item);
|
||||
MediaSwitchWidget *sw =
|
||||
new MediaSwitchWidget(&switcher->mediaSwitches.back());
|
||||
item->setSizeHint(sw->minimumSizeHint());
|
||||
ui->mediaSwitches->setItemWidget(item, sw);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_mediaRemove_clicked()
|
||||
{
|
||||
QListWidgetItem *item = ui->mediaSwitches->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
int idx = ui->mediaSwitches->currentRow();
|
||||
auto &switches = switcher->mediaSwitches;
|
||||
switches.erase(switches.begin() + idx);
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_mediaUp_clicked()
|
||||
{
|
||||
int index = ui->mediaSwitches->currentRow();
|
||||
if (!listMoveUp(ui->mediaSwitches))
|
||||
return;
|
||||
|
||||
MediaSwitchWidget *s1 =
|
||||
(MediaSwitchWidget *)ui->mediaSwitches->itemWidget(
|
||||
ui->mediaSwitches->item(index));
|
||||
MediaSwitchWidget *s2 =
|
||||
(MediaSwitchWidget *)ui->mediaSwitches->itemWidget(
|
||||
ui->mediaSwitches->item(index - 1));
|
||||
MediaSwitchWidget::swapSwitchData(s1, s2);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
std::swap(switcher->mediaSwitches[index],
|
||||
switcher->mediaSwitches[index - 1]);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_mediaDown_clicked()
|
||||
{
|
||||
int index = ui->mediaSwitches->currentRow();
|
||||
|
||||
if (!listMoveDown(ui->mediaSwitches))
|
||||
return;
|
||||
|
||||
MediaSwitchWidget *s1 =
|
||||
(MediaSwitchWidget *)ui->mediaSwitches->itemWidget(
|
||||
ui->mediaSwitches->item(index));
|
||||
MediaSwitchWidget *s2 =
|
||||
(MediaSwitchWidget *)ui->mediaSwitches->itemWidget(
|
||||
ui->mediaSwitches->item(index + 1));
|
||||
MediaSwitchWidget::swapSwitchData(s1, s2);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
std::swap(switcher->mediaSwitches[index],
|
||||
switcher->mediaSwitches[index + 1]);
|
||||
}
|
||||
|
||||
void SwitcherData::checkMediaSwitch(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition)
|
||||
{
|
||||
for (MediaSwitch &mediaSwitch : mediaSwitches) {
|
||||
if (!mediaSwitch.initialized())
|
||||
continue;
|
||||
|
||||
obs_source_t *source =
|
||||
obs_weak_source_get_source(mediaSwitch.source);
|
||||
auto duration = obs_source_media_get_duration(source);
|
||||
auto time = obs_source_media_get_time(source);
|
||||
obs_media_state state = obs_source_media_get_state(source);
|
||||
obs_source_release(source);
|
||||
|
||||
bool matchedStopped = mediaSwitch.state ==
|
||||
OBS_MEDIA_STATE_STOPPED &&
|
||||
mediaSwitch.stopped;
|
||||
|
||||
// The signal for the state ended is intentionally not used here
|
||||
// so matchedEnded can be used to specify the end of a VLC playlist
|
||||
// by two consequtive matches of OBS_MEDIA_STATE_ENDED
|
||||
//
|
||||
// This was done to reduce the likelyhood of interpreting a single
|
||||
// OBS_MEDIA_STATE_ENDED caught by obs_source_media_get_state()
|
||||
// as the end of the playlist of the VLC source, while actually being
|
||||
// in the middle of switching to the next item of the playlist
|
||||
//
|
||||
// If there is a separate obs_media_sate in the future for the
|
||||
// "end of playlist reached" signal the line below can be used
|
||||
// and an additional check for this new singal can be introduced
|
||||
//
|
||||
// bool matchedEnded = mediaSwitch.state == OBS_MEDIA_STATE_ENDED &&
|
||||
// mediaSwitch.ended;
|
||||
|
||||
bool matchedEnded = false;
|
||||
|
||||
if (state == OBS_MEDIA_STATE_ENDED) {
|
||||
matchedEnded = mediaSwitch.previousStateEnded;
|
||||
mediaSwitch.previousStateEnded = true;
|
||||
} else {
|
||||
mediaSwitch.previousStateEnded = false;
|
||||
}
|
||||
|
||||
// reset for next check
|
||||
mediaSwitch.stopped = false;
|
||||
mediaSwitch.ended = false;
|
||||
|
||||
bool matchedState = ((state == mediaSwitch.state) ||
|
||||
mediaSwitch.anyState) ||
|
||||
matchedStopped || matchedEnded;
|
||||
|
||||
bool matchedTimeNone =
|
||||
(mediaSwitch.restriction == TIME_RESTRICTION_NONE);
|
||||
bool matchedTimeLonger =
|
||||
(mediaSwitch.restriction == TIME_RESTRICTION_LONGER) &&
|
||||
(time > mediaSwitch.time);
|
||||
bool matchedTimeShorter =
|
||||
(mediaSwitch.restriction == TIME_RESTRICTION_SHORTER) &&
|
||||
(time < mediaSwitch.time);
|
||||
bool matchedTimeRemainLonger =
|
||||
(mediaSwitch.restriction ==
|
||||
TIME_RESTRICTION_REMAINING_LONGER) &&
|
||||
(duration > time && duration - time > mediaSwitch.time);
|
||||
bool matchedTimeRemainShorter =
|
||||
(mediaSwitch.restriction ==
|
||||
TIME_RESTRICTION_REMAINING_SHORTER) &&
|
||||
(duration > time && duration - time < mediaSwitch.time);
|
||||
|
||||
bool matchedTime = matchedTimeNone || matchedTimeLonger ||
|
||||
matchedTimeShorter ||
|
||||
matchedTimeRemainLonger ||
|
||||
matchedTimeRemainShorter;
|
||||
|
||||
bool matched = matchedState && matchedTime;
|
||||
|
||||
if (matched) {
|
||||
match = true;
|
||||
scene = (mediaSwitch.usePreviousScene)
|
||||
? previousScene
|
||||
: mediaSwitch.scene;
|
||||
transition = mediaSwitch.transition;
|
||||
|
||||
if (verbose)
|
||||
mediaSwitch.logMatch();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SwitcherData::saveMediaSwitches(obs_data_t *obj)
|
||||
{
|
||||
obs_data_array_t *mediaArray = obs_data_array_create();
|
||||
for (MediaSwitch &s : switcher->mediaSwitches) {
|
||||
obs_data_t *array_obj = obs_data_create();
|
||||
|
||||
obs_source_t *source = obs_weak_source_get_source(s.source);
|
||||
obs_source_t *sceneSource = obs_weak_source_get_source(s.scene);
|
||||
obs_source_t *transition =
|
||||
obs_weak_source_get_source(s.transition);
|
||||
if ((s.usePreviousScene || sceneSource) && source &&
|
||||
transition) {
|
||||
const char *sourceName = obs_source_get_name(source);
|
||||
const char *sceneName =
|
||||
obs_source_get_name(sceneSource);
|
||||
const char *transitionName =
|
||||
obs_source_get_name(transition);
|
||||
obs_data_set_string(array_obj, "source", sourceName);
|
||||
obs_data_set_string(array_obj, "scene",
|
||||
s.usePreviousScene
|
||||
? previous_scene_name
|
||||
: sceneName);
|
||||
obs_data_set_string(array_obj, "transition",
|
||||
transitionName);
|
||||
obs_data_set_int(array_obj, "state", s.state);
|
||||
obs_data_set_int(array_obj, "restriction",
|
||||
s.restriction);
|
||||
obs_data_set_int(array_obj, "time", s.time);
|
||||
obs_data_array_push_back(mediaArray, array_obj);
|
||||
}
|
||||
obs_source_release(source);
|
||||
obs_source_release(sceneSource);
|
||||
obs_source_release(transition);
|
||||
|
||||
obs_data_release(array_obj);
|
||||
}
|
||||
obs_data_set_array(obj, "mediaSwitches", mediaArray);
|
||||
obs_data_array_release(mediaArray);
|
||||
}
|
||||
|
||||
void SwitcherData::loadMediaSwitches(obs_data_t *obj)
|
||||
{
|
||||
obs_data_array_t *mediaArray = obs_data_get_array(obj, "mediaSwitches");
|
||||
switcher->mediaSwitches.clear();
|
||||
size_t count = obs_data_array_count(mediaArray);
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
obs_data_t *array_obj = obs_data_array_item(mediaArray, i);
|
||||
|
||||
const char *source = obs_data_get_string(array_obj, "source");
|
||||
const char *scene = obs_data_get_string(array_obj, "scene");
|
||||
const char *transition =
|
||||
obs_data_get_string(array_obj, "transition");
|
||||
obs_media_state state =
|
||||
(obs_media_state)obs_data_get_int(array_obj, "state");
|
||||
time_restriction restriction =
|
||||
(time_restriction)obs_data_get_int(array_obj,
|
||||
"restriction");
|
||||
uint64_t time = obs_data_get_int(array_obj, "time");
|
||||
|
||||
switcher->mediaSwitches.emplace_back(
|
||||
GetWeakSourceByName(scene), GetWeakSourceByName(source),
|
||||
GetWeakTransitionByName(transition), state, restriction,
|
||||
time, (strcmp(scene, previous_scene_name) == 0));
|
||||
|
||||
obs_data_release(array_obj);
|
||||
}
|
||||
obs_data_array_release(mediaArray);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupMediaTab()
|
||||
{
|
||||
for (auto &s : switcher->mediaSwitches) {
|
||||
QListWidgetItem *item;
|
||||
item = new QListWidgetItem(ui->mediaSwitches);
|
||||
ui->mediaSwitches->addItem(item);
|
||||
MediaSwitchWidget *sw = new MediaSwitchWidget(&s);
|
||||
item->setSizeHint(sw->minimumSizeHint());
|
||||
ui->mediaSwitches->setItemWidget(item, sw);
|
||||
}
|
||||
|
||||
if (switcher->mediaSwitches.size() == 0)
|
||||
addPulse = PulseWidget(ui->mediaAdd, QColor(Qt::green));
|
||||
}
|
||||
|
||||
bool MediaSwitch::initialized()
|
||||
{
|
||||
return SceneSwitcherEntry::initialized() && source;
|
||||
}
|
||||
|
||||
bool MediaSwitch::valid()
|
||||
{
|
||||
return !initialized() ||
|
||||
(SceneSwitcherEntry::valid() && WeakSourceValid(source));
|
||||
}
|
||||
|
||||
void MediaSwitch::clearSignalHandler()
|
||||
{
|
||||
obs_source_t *mediasource = obs_weak_source_get_source(source);
|
||||
signal_handler_t *sh = obs_source_get_signal_handler(mediasource);
|
||||
signal_handler_disconnect(sh, "media_stopped", MediaStopped, this);
|
||||
signal_handler_disconnect(sh, "media_ended", MediaEnded, this);
|
||||
obs_source_release(mediasource);
|
||||
}
|
||||
|
||||
void MediaSwitch::resetSignalHandler()
|
||||
{
|
||||
obs_source_t *mediasource = obs_weak_source_get_source(source);
|
||||
signal_handler_t *sh = obs_source_get_signal_handler(mediasource);
|
||||
signal_handler_disconnect(sh, "media_stopped", MediaStopped, this);
|
||||
signal_handler_disconnect(sh, "media_ended", MediaEnded, this);
|
||||
signal_handler_connect(sh, "media_stopped", MediaStopped, this);
|
||||
signal_handler_connect(sh, "media_ended", MediaEnded, this);
|
||||
obs_source_release(mediasource);
|
||||
}
|
||||
|
||||
void MediaSwitch::MediaStopped(void *data, calldata_t *)
|
||||
{
|
||||
MediaSwitch *media = static_cast<MediaSwitch *>(data);
|
||||
media->stopped = true;
|
||||
}
|
||||
|
||||
void MediaSwitch::MediaEnded(void *data, calldata_t *)
|
||||
{
|
||||
MediaSwitch *media = static_cast<MediaSwitch *>(data);
|
||||
media->ended = true;
|
||||
}
|
||||
|
||||
inline MediaSwitch::MediaSwitch(OBSWeakSource scene_, OBSWeakSource source_,
|
||||
OBSWeakSource transition_,
|
||||
obs_media_state state_,
|
||||
time_restriction restriction_, uint64_t time_,
|
||||
bool usePreviousScene_)
|
||||
: SceneSwitcherEntry(scene_, transition_, usePreviousScene_),
|
||||
source(source_),
|
||||
state(state_),
|
||||
restriction(restriction_),
|
||||
time(time_)
|
||||
{
|
||||
anyState = state > 7;
|
||||
obs_source_t *mediasource = obs_weak_source_get_source(source);
|
||||
signal_handler_t *sh = obs_source_get_signal_handler(mediasource);
|
||||
signal_handler_connect(sh, "media_stopped", MediaStopped, this);
|
||||
signal_handler_connect(sh, "media_ended", MediaEnded, this);
|
||||
obs_source_release(mediasource);
|
||||
}
|
||||
|
||||
MediaSwitch::MediaSwitch(const MediaSwitch &other)
|
||||
: SceneSwitcherEntry(other.scene, other.transition,
|
||||
other.usePreviousScene),
|
||||
source(other.source),
|
||||
state(other.state),
|
||||
restriction(other.restriction),
|
||||
time(other.time)
|
||||
{
|
||||
anyState = state > 7;
|
||||
obs_source_t *mediasource = obs_weak_source_get_source(source);
|
||||
signal_handler_t *sh = obs_source_get_signal_handler(mediasource);
|
||||
signal_handler_connect(sh, "media_stopped", MediaStopped, this);
|
||||
signal_handler_connect(sh, "media_ended", MediaEnded, this);
|
||||
obs_source_release(mediasource);
|
||||
}
|
||||
|
||||
MediaSwitch::MediaSwitch(MediaSwitch &&other)
|
||||
: SceneSwitcherEntry(other.scene, other.transition,
|
||||
other.usePreviousScene),
|
||||
source(other.source),
|
||||
state(other.state),
|
||||
anyState(other.anyState),
|
||||
restriction(other.restriction),
|
||||
time(other.time)
|
||||
{
|
||||
}
|
||||
|
||||
MediaSwitch::~MediaSwitch()
|
||||
{
|
||||
obs_source_t *mediasource = obs_weak_source_get_source(source);
|
||||
signal_handler_t *sh = obs_source_get_signal_handler(mediasource);
|
||||
signal_handler_disconnect(sh, "media_stopped", MediaStopped, this);
|
||||
signal_handler_disconnect(sh, "media_ended", MediaEnded, this);
|
||||
obs_source_release(mediasource);
|
||||
}
|
||||
|
||||
MediaSwitch &MediaSwitch::operator=(const MediaSwitch &other)
|
||||
{
|
||||
MediaSwitch t(other);
|
||||
swap(*this, t);
|
||||
return *this = MediaSwitch(other);
|
||||
}
|
||||
|
||||
MediaSwitch &MediaSwitch::operator=(MediaSwitch &&other) noexcept
|
||||
{
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
swap(*this, other);
|
||||
|
||||
obs_source_t *mediasource = obs_weak_source_get_source(other.source);
|
||||
signal_handler_t *sh = obs_source_get_signal_handler(mediasource);
|
||||
signal_handler_disconnect(sh, "media_stopped", MediaStopped, &other);
|
||||
signal_handler_disconnect(sh, "media_ended", MediaEnded, &other);
|
||||
obs_source_release(mediasource);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(MediaSwitch &first, MediaSwitch &second)
|
||||
{
|
||||
std::swap(first.scene, second.scene);
|
||||
std::swap(first.transition, second.transition);
|
||||
std::swap(first.usePreviousScene, second.usePreviousScene);
|
||||
std::swap(first.source, second.source);
|
||||
std::swap(first.state, second.state);
|
||||
std::swap(first.restriction, second.restriction);
|
||||
std::swap(first.time, second.time);
|
||||
std::swap(first.anyState, second.anyState);
|
||||
first.resetSignalHandler();
|
||||
second.resetSignalHandler();
|
||||
}
|
||||
|
||||
void populateMediaStates(QComboBox *list)
|
||||
{
|
||||
list->addItem("None");
|
||||
list->addItem("Playing");
|
||||
list->addItem("Opening");
|
||||
list->addItem("Buffering");
|
||||
list->addItem("Paused");
|
||||
list->addItem("Stopped");
|
||||
list->addItem("Ended");
|
||||
list->addItem("Error");
|
||||
list->addItem("Any");
|
||||
}
|
||||
|
||||
void populateTimeRestrictions(QComboBox *list)
|
||||
{
|
||||
list->addItem("None");
|
||||
list->addItem("Time shorter");
|
||||
list->addItem("Time longer");
|
||||
list->addItem("Time remaining shorter");
|
||||
list->addItem("Time remaining longer");
|
||||
}
|
||||
|
||||
MediaSwitchWidget::MediaSwitchWidget(MediaSwitch *s) : SwitchWidget(s)
|
||||
{
|
||||
meidaSources = new QComboBox();
|
||||
states = new QComboBox();
|
||||
timeRestrictions = new QComboBox();
|
||||
time = new QSpinBox();
|
||||
|
||||
whenLabel = new QLabel("When");
|
||||
stateLabel = new QLabel("state is");
|
||||
andLabel = new QLabel("and");
|
||||
switchLabel = new QLabel("switch to");
|
||||
usingLabel = new QLabel("using");
|
||||
|
||||
time->setSuffix("ms");
|
||||
time->setMaximum(99999999);
|
||||
time->setMinimum(0);
|
||||
|
||||
QWidget::connect(meidaSources,
|
||||
SIGNAL(currentTextChanged(const QString &)), this,
|
||||
SLOT(SourceChanged(const QString &)));
|
||||
QWidget::connect(states, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(StateChanged(int)));
|
||||
QWidget::connect(timeRestrictions, SIGNAL(currentIndexChanged(int)),
|
||||
this, SLOT(TimeRestrictionChanged(int)));
|
||||
QWidget::connect(time, SIGNAL(valueChanged(int)), this,
|
||||
SLOT(TimeChanged(int)));
|
||||
|
||||
AdvSceneSwitcher::populateMediaSelection(meidaSources);
|
||||
populateMediaStates(states);
|
||||
populateTimeRestrictions(timeRestrictions);
|
||||
|
||||
if (s) {
|
||||
meidaSources->setCurrentText(
|
||||
GetWeakSourceName(s->source).c_str());
|
||||
states->setCurrentIndex(s->state);
|
||||
timeRestrictions->setCurrentIndex(s->restriction);
|
||||
time->setValue(s->time);
|
||||
if (s->restriction == TIME_RESTRICTION_NONE)
|
||||
time->setDisabled(true);
|
||||
}
|
||||
|
||||
setStyleSheet("* { background-color: transparent; }");
|
||||
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||
|
||||
mainLayout->addWidget(whenLabel);
|
||||
mainLayout->addWidget(meidaSources);
|
||||
mainLayout->addWidget(stateLabel);
|
||||
mainLayout->addWidget(states);
|
||||
mainLayout->addWidget(andLabel);
|
||||
mainLayout->addWidget(timeRestrictions);
|
||||
mainLayout->addWidget(time);
|
||||
mainLayout->addWidget(switchLabel);
|
||||
mainLayout->addWidget(scenes);
|
||||
mainLayout->addWidget(usingLabel);
|
||||
mainLayout->addWidget(transitions);
|
||||
mainLayout->addStretch();
|
||||
|
||||
setLayout(mainLayout);
|
||||
|
||||
switchData = s;
|
||||
|
||||
loading = false;
|
||||
}
|
||||
|
||||
MediaSwitch *MediaSwitchWidget::getSwitchData()
|
||||
{
|
||||
return switchData;
|
||||
}
|
||||
|
||||
void MediaSwitchWidget::setSwitchData(MediaSwitch *s)
|
||||
{
|
||||
switchData = s;
|
||||
}
|
||||
|
||||
void MediaSwitchWidget::swapSwitchData(MediaSwitchWidget *s1,
|
||||
MediaSwitchWidget *s2)
|
||||
{
|
||||
SwitchWidget::swapSwitchData(s1, s2);
|
||||
|
||||
MediaSwitch *t = s1->getSwitchData();
|
||||
s1->setSwitchData(s2->getSwitchData());
|
||||
s2->setSwitchData(t);
|
||||
}
|
||||
|
||||
void MediaSwitchWidget::SourceChanged(const QString &text)
|
||||
{
|
||||
if (loading || !switchData)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->clearSignalHandler();
|
||||
switchData->source = GetWeakSourceByQString(text);
|
||||
switchData->resetSignalHandler();
|
||||
}
|
||||
|
||||
void MediaSwitchWidget::StateChanged(int index)
|
||||
{
|
||||
if (loading || !switchData)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->state = (obs_media_state)index;
|
||||
switchData->anyState = switchData->state > 7;
|
||||
}
|
||||
|
||||
void MediaSwitchWidget::TimeRestrictionChanged(int index)
|
||||
{
|
||||
if (loading || !switchData)
|
||||
return;
|
||||
|
||||
if ((time_restriction)index == TIME_RESTRICTION_NONE)
|
||||
time->setDisabled(true);
|
||||
else
|
||||
time->setDisabled(false);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->restriction = (time_restriction)index;
|
||||
}
|
||||
|
||||
void MediaSwitchWidget::TimeChanged(int time)
|
||||
{
|
||||
if (loading || !switchData)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->time = time;
|
||||
}
|
||||
324
src/switch-pause.cpp
Normal file
324
src/switch-pause.cpp
Normal file
@@ -0,0 +1,324 @@
|
||||
#include <regex>
|
||||
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
#include "headers/utility.hpp"
|
||||
|
||||
void AdvSceneSwitcher::on_pauseScenesAdd_clicked()
|
||||
{
|
||||
QString sceneName = ui->pauseScenesScenes->currentText();
|
||||
|
||||
if (sceneName.isEmpty())
|
||||
return;
|
||||
|
||||
OBSWeakSource source = GetWeakSourceByQString(sceneName);
|
||||
QVariant v = QVariant::fromValue(sceneName);
|
||||
|
||||
QList<QListWidgetItem *> items =
|
||||
ui->pauseScenes->findItems(sceneName, Qt::MatchExactly);
|
||||
|
||||
if (items.size() == 0) {
|
||||
QListWidgetItem *item =
|
||||
new QListWidgetItem(sceneName, ui->pauseScenes);
|
||||
item->setData(Qt::UserRole, v);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->pauseScenesSwitches.emplace_back(source);
|
||||
ui->pauseScenes->sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_pauseScenesRemove_clicked()
|
||||
{
|
||||
QListWidgetItem *item = ui->pauseScenes->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
QString pauseScene = item->data(Qt::UserRole).toString();
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> 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 AdvSceneSwitcher::on_pauseWindowsAdd_clicked()
|
||||
{
|
||||
QString windowName = ui->pauseWindowsWindows->currentText();
|
||||
|
||||
if (windowName.isEmpty())
|
||||
return;
|
||||
|
||||
QVariant v = QVariant::fromValue(windowName);
|
||||
|
||||
QList<QListWidgetItem *> items =
|
||||
ui->pauseWindows->findItems(windowName, Qt::MatchExactly);
|
||||
|
||||
if (items.size() == 0) {
|
||||
QListWidgetItem *item =
|
||||
new QListWidgetItem(windowName, ui->pauseWindows);
|
||||
item->setData(Qt::UserRole, v);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->pauseWindowsSwitches.emplace_back(
|
||||
windowName.toUtf8().constData());
|
||||
ui->pauseWindows->sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_pauseWindowsRemove_clicked()
|
||||
{
|
||||
QListWidgetItem *item = ui->pauseWindows->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
QString windowName = item->data(Qt::UserRole).toString();
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> 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 AdvSceneSwitcher::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();
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
for (auto &s : switcher->pauseScenesSwitches) {
|
||||
std::string name = GetWeakSourceName(s);
|
||||
if (scene.compare(name.c_str()) == 0) {
|
||||
ui->pauseScenesScenes->setCurrentText(name.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::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();
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
for (auto &s : switcher->pauseWindowsSwitches) {
|
||||
if (window.compare(s.c_str()) == 0) {
|
||||
ui->pauseWindowsWindows->setCurrentText(s.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int AdvSceneSwitcher::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 AdvSceneSwitcher::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);
|
||||
|
||||
std::string title;
|
||||
if (!pause) {
|
||||
//lock.unlock();
|
||||
GetCurrentWindowTitle(title);
|
||||
//lock.lock();
|
||||
for (std::string &window : pauseWindowsSwitches) {
|
||||
if (window == title) {
|
||||
pause = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!pause) {
|
||||
//lock.unlock();
|
||||
GetCurrentWindowTitle(title);
|
||||
//lock.lock();
|
||||
for (std::string &window : pauseWindowsSwitches) {
|
||||
try {
|
||||
bool matches = std::regex_match(
|
||||
title, std::regex(window));
|
||||
if (matches) {
|
||||
pause = true;
|
||||
break;
|
||||
}
|
||||
} catch (const std::regex_error &) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose && pause)
|
||||
blog(LOG_INFO, "pause match");
|
||||
|
||||
return pause;
|
||||
}
|
||||
|
||||
void SwitcherData::savePauseSwitches(obs_data_t *obj)
|
||||
{
|
||||
obs_data_array_t *pauseScenesArray = obs_data_array_create();
|
||||
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);
|
||||
}
|
||||
obs_data_set_array(obj, "pauseScenes", pauseScenesArray);
|
||||
obs_data_array_release(pauseScenesArray);
|
||||
|
||||
obs_data_array_t *pauseWindowsArray = obs_data_array_create();
|
||||
for (std::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);
|
||||
}
|
||||
obs_data_set_array(obj, "pauseWindows", pauseWindowsArray);
|
||||
obs_data_array_release(pauseWindowsArray);
|
||||
}
|
||||
|
||||
void SwitcherData::loadPauseSwitches(obs_data_t *obj)
|
||||
{
|
||||
switcher->pauseScenesSwitches.clear();
|
||||
|
||||
obs_data_array_t *pauseScenesArray =
|
||||
obs_data_get_array(obj, "pauseScenes");
|
||||
size_t 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);
|
||||
}
|
||||
obs_data_array_release(pauseScenesArray);
|
||||
|
||||
switcher->pauseWindowsSwitches.clear();
|
||||
|
||||
obs_data_array_t *pauseWindowsArray =
|
||||
obs_data_get_array(obj, "pauseWindows");
|
||||
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);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupPauseTab()
|
||||
{
|
||||
populateSceneSelection(ui->pauseScenesScenes, false);
|
||||
populateWindowSelection(ui->pauseWindowsWindows);
|
||||
|
||||
for (auto &scene : switcher->pauseScenesSwitches) {
|
||||
std::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);
|
||||
}
|
||||
}
|
||||
69
src/switch-priority.cpp
Normal file
69
src/switch-priority.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
|
||||
void AdvSceneSwitcher::on_threadPriority_currentTextChanged(const QString &text)
|
||||
{
|
||||
if (loading || ui->threadPriority->count() !=
|
||||
(int)switcher->threadPriorities.size())
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
for (auto p : switcher->threadPriorities) {
|
||||
if (p.name == text.toUtf8().constData()) {
|
||||
switcher->threadPriority = p.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::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);
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
iter_swap(switcher->functionNamesByPriority.begin() +
|
||||
currentIndex,
|
||||
switcher->functionNamesByPriority.begin() +
|
||||
currentIndex - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::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);
|
||||
std::lock_guard<std::mutex> 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 > 8)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
205
src/switch-random.cpp
Normal file
205
src/switch-random.cpp
Normal file
@@ -0,0 +1,205 @@
|
||||
#include <random>
|
||||
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
#include "headers/utility.hpp"
|
||||
|
||||
static QMetaObject::Connection addPulse;
|
||||
|
||||
void AdvSceneSwitcher::on_randomAdd_clicked()
|
||||
{
|
||||
ui->randomAdd->disconnect(addPulse);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->randomSwitches.emplace_back();
|
||||
|
||||
QListWidgetItem *item;
|
||||
item = new QListWidgetItem(ui->randomSwitches);
|
||||
ui->randomSwitches->addItem(item);
|
||||
RandomSwitchWidget *sw =
|
||||
new RandomSwitchWidget(&switcher->randomSwitches.back());
|
||||
item->setSizeHint(sw->minimumSizeHint());
|
||||
ui->randomSwitches->setItemWidget(item, sw);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_randomRemove_clicked()
|
||||
{
|
||||
QListWidgetItem *item = ui->randomSwitches->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
int idx = ui->randomSwitches->currentRow();
|
||||
auto &switches = switcher->randomSwitches;
|
||||
switches.erase(switches.begin() + idx);
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void SwitcherData::checkRandom(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition, int &delay)
|
||||
{
|
||||
if (randomSwitches.size() == 0)
|
||||
return;
|
||||
|
||||
std::deque<RandomSwitch> rs(randomSwitches);
|
||||
std::random_device rng;
|
||||
std::mt19937 urng(rng());
|
||||
std::shuffle(rs.begin(), rs.end(), urng);
|
||||
for (RandomSwitch &r : rs) {
|
||||
if (!r.initialized())
|
||||
continue;
|
||||
|
||||
if (r.scene == lastRandomScene)
|
||||
continue;
|
||||
scene = r.scene;
|
||||
transition = r.transition;
|
||||
delay = (int)r.delay * 1000;
|
||||
match = true;
|
||||
lastRandomScene = r.scene;
|
||||
|
||||
if (verbose)
|
||||
r.logMatch();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SwitcherData::saveRandomSwitches(obs_data_t *obj)
|
||||
{
|
||||
obs_data_array_t *randomArray = obs_data_array_create();
|
||||
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_array_push_back(randomArray, array_obj);
|
||||
}
|
||||
obs_source_release(source);
|
||||
obs_source_release(transition);
|
||||
obs_data_release(array_obj);
|
||||
}
|
||||
obs_data_set_array(obj, "randomSwitches", randomArray);
|
||||
obs_data_array_release(randomArray);
|
||||
}
|
||||
|
||||
void SwitcherData::loadRandomSwitches(obs_data_t *obj)
|
||||
{
|
||||
switcher->randomSwitches.clear();
|
||||
|
||||
obs_data_array_t *randomArray =
|
||||
obs_data_get_array(obj, "randomSwitches");
|
||||
size_t 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");
|
||||
|
||||
switcher->randomSwitches.emplace_back(
|
||||
GetWeakSourceByName(scene),
|
||||
GetWeakTransitionByName(transition), delay);
|
||||
|
||||
obs_data_release(array_obj);
|
||||
}
|
||||
obs_data_array_release(randomArray);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupRandomTab()
|
||||
{
|
||||
for (auto &s : switcher->randomSwitches) {
|
||||
QListWidgetItem *item;
|
||||
item = new QListWidgetItem(ui->randomSwitches);
|
||||
ui->randomSwitches->addItem(item);
|
||||
RandomSwitchWidget *sw = new RandomSwitchWidget(&s);
|
||||
item->setSizeHint(sw->minimumSizeHint());
|
||||
ui->randomSwitches->setItemWidget(item, sw);
|
||||
}
|
||||
|
||||
if (switcher->randomSwitches.size() == 0)
|
||||
addPulse = PulseWidget(ui->randomAdd, QColor(Qt::green));
|
||||
|
||||
if (switcher->switchIfNotMatching != RANDOM_SWITCH)
|
||||
PulseWidget(ui->randomDisabledWarning, QColor(Qt::red),
|
||||
QColor(0, 0, 0, 0), "QLabel ");
|
||||
else
|
||||
ui->randomDisabledWarning->setVisible(false);
|
||||
}
|
||||
|
||||
RandomSwitchWidget::RandomSwitchWidget(RandomSwitch *s) : SwitchWidget(s, false)
|
||||
{
|
||||
delay = new QDoubleSpinBox();
|
||||
|
||||
switchLabel = new QLabel("If no switch condition is met switch to ");
|
||||
usingLabel = new QLabel("using");
|
||||
forLabel = new QLabel("for");
|
||||
|
||||
QWidget::connect(delay, SIGNAL(valueChanged(double)), this,
|
||||
SLOT(DelayChanged(double)));
|
||||
|
||||
delay->setSuffix("s");
|
||||
delay->setMaximum(999999999.9);
|
||||
|
||||
if (s) {
|
||||
delay->setValue(s->delay);
|
||||
}
|
||||
|
||||
setStyleSheet("* { background-color: transparent; }");
|
||||
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||
|
||||
mainLayout->addWidget(switchLabel);
|
||||
mainLayout->addWidget(scenes);
|
||||
mainLayout->addWidget(usingLabel);
|
||||
mainLayout->addWidget(transitions);
|
||||
mainLayout->addWidget(forLabel);
|
||||
mainLayout->addWidget(delay);
|
||||
mainLayout->addStretch();
|
||||
|
||||
setLayout(mainLayout);
|
||||
|
||||
switchData = s;
|
||||
|
||||
loading = false;
|
||||
}
|
||||
|
||||
RandomSwitch *RandomSwitchWidget::getSwitchData()
|
||||
{
|
||||
return switchData;
|
||||
}
|
||||
|
||||
void RandomSwitchWidget::setSwitchData(RandomSwitch *s)
|
||||
{
|
||||
switchData = s;
|
||||
}
|
||||
|
||||
void RandomSwitchWidget::swapSwitchData(RandomSwitchWidget *s1,
|
||||
RandomSwitchWidget *s2)
|
||||
{
|
||||
SwitchWidget::swapSwitchData(s1, s2);
|
||||
|
||||
RandomSwitch *t = s1->getSwitchData();
|
||||
s1->setSwitchData(s2->getSwitchData());
|
||||
s2->setSwitchData(t);
|
||||
}
|
||||
|
||||
void RandomSwitchWidget::DelayChanged(double d)
|
||||
{
|
||||
if (loading || !switchData)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->delay = d;
|
||||
}
|
||||
394
src/switch-screen-region.cpp
Normal file
394
src/switch-screen-region.cpp
Normal file
@@ -0,0 +1,394 @@
|
||||
#include <QTimer>
|
||||
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
#include "headers/utility.hpp"
|
||||
|
||||
static QMetaObject::Connection addPulse;
|
||||
|
||||
void clearFrames(QListWidget *list)
|
||||
{
|
||||
for (int i = 0; i < list->count(); ++i) {
|
||||
ScreenRegionWidget *sw =
|
||||
(ScreenRegionWidget *)list->itemWidget(list->item(i));
|
||||
sw->hideFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void showCurrentFrame(QListWidget *list)
|
||||
{
|
||||
QListWidgetItem *item = list->currentItem();
|
||||
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
ScreenRegionWidget *sw = (ScreenRegionWidget *)list->itemWidget(item);
|
||||
sw->showFrame();
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_showFrame_clicked()
|
||||
{
|
||||
switcher->showFrame = !switcher->showFrame;
|
||||
|
||||
if (switcher->showFrame) {
|
||||
ui->showFrame->setText("Hide guide frames");
|
||||
showCurrentFrame(ui->screenRegionSwitches);
|
||||
} else {
|
||||
ui->showFrame->setText("Show guide frames");
|
||||
clearFrames(ui->screenRegionSwitches);
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_screenRegionSwitches_currentRowChanged(int idx)
|
||||
{
|
||||
UNUSED_PARAMETER(idx);
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
if (switcher->showFrame) {
|
||||
clearFrames(ui->screenRegionSwitches);
|
||||
showCurrentFrame(ui->screenRegionSwitches);
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_screenRegionAdd_clicked()
|
||||
{
|
||||
ui->screenRegionAdd->disconnect(addPulse);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->screenRegionSwitches.emplace_back();
|
||||
|
||||
QListWidgetItem *item;
|
||||
item = new QListWidgetItem(ui->screenRegionSwitches);
|
||||
ui->screenRegionSwitches->addItem(item);
|
||||
ScreenRegionWidget *sw =
|
||||
new ScreenRegionWidget(&switcher->screenRegionSwitches.back());
|
||||
item->setSizeHint(sw->minimumSizeHint());
|
||||
ui->screenRegionSwitches->setItemWidget(item, sw);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_screenRegionRemove_clicked()
|
||||
{
|
||||
QListWidgetItem *item = ui->screenRegionSwitches->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
int idx = ui->screenRegionSwitches->currentRow();
|
||||
auto &switches = switcher->screenRegionSwitches;
|
||||
switches.erase(switches.begin() + idx);
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_screenRegionUp_clicked()
|
||||
{
|
||||
int index = ui->screenRegionSwitches->currentRow();
|
||||
if (!listMoveUp(ui->screenRegionSwitches))
|
||||
return;
|
||||
|
||||
ScreenRegionWidget *s1 =
|
||||
(ScreenRegionWidget *)ui->screenRegionSwitches->itemWidget(
|
||||
ui->screenRegionSwitches->item(index));
|
||||
ScreenRegionWidget *s2 =
|
||||
(ScreenRegionWidget *)ui->screenRegionSwitches->itemWidget(
|
||||
ui->screenRegionSwitches->item(index - 1));
|
||||
ScreenRegionWidget::swapSwitchData(s1, s2);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
std::swap(switcher->screenRegionSwitches[index],
|
||||
switcher->screenRegionSwitches[index - 1]);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_screenRegionDown_clicked()
|
||||
{
|
||||
int index = ui->screenRegionSwitches->currentRow();
|
||||
|
||||
if (!listMoveDown(ui->screenRegionSwitches))
|
||||
return;
|
||||
|
||||
ScreenRegionWidget *s1 =
|
||||
(ScreenRegionWidget *)ui->screenRegionSwitches->itemWidget(
|
||||
ui->screenRegionSwitches->item(index));
|
||||
ScreenRegionWidget *s2 =
|
||||
(ScreenRegionWidget *)ui->screenRegionSwitches->itemWidget(
|
||||
ui->screenRegionSwitches->item(index + 1));
|
||||
ScreenRegionWidget::swapSwitchData(s1, s2);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
std::swap(switcher->screenRegionSwitches[index],
|
||||
switcher->screenRegionSwitches[index + 1]);
|
||||
}
|
||||
|
||||
void SwitcherData::checkScreenRegionSwitch(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition)
|
||||
{
|
||||
std::pair<int, int> cursorPos = getCursorPos();
|
||||
int minRegionSize = 99999;
|
||||
|
||||
for (auto &s : screenRegionSwitches) {
|
||||
if (!s.initialized())
|
||||
continue;
|
||||
|
||||
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;
|
||||
|
||||
if (verbose)
|
||||
s.logMatch();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::updateScreenRegionCursorPos()
|
||||
{
|
||||
std::pair<int, int> position = getCursorPos();
|
||||
ui->cursorXPosition->setText(QString::number(position.first));
|
||||
ui->cursorYPosition->setText(QString::number(position.second));
|
||||
}
|
||||
|
||||
void SwitcherData::saveScreenRegionSwitches(obs_data_t *obj)
|
||||
{
|
||||
obs_data_array_t *screenRegionArray = obs_data_array_create();
|
||||
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_array_push_back(screenRegionArray, array_obj);
|
||||
}
|
||||
obs_source_release(source);
|
||||
obs_source_release(transition);
|
||||
obs_data_release(array_obj);
|
||||
}
|
||||
obs_data_set_array(obj, "screenRegion", screenRegionArray);
|
||||
obs_data_array_release(screenRegionArray);
|
||||
}
|
||||
|
||||
void SwitcherData::loadScreenRegionSwitches(obs_data_t *obj)
|
||||
{
|
||||
switcher->screenRegionSwitches.clear();
|
||||
|
||||
obs_data_array_t *screenRegionArray =
|
||||
obs_data_get_array(obj, "screenRegion");
|
||||
size_t 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");
|
||||
|
||||
switcher->screenRegionSwitches.emplace_back(
|
||||
GetWeakSourceByName(scene),
|
||||
GetWeakTransitionByName(transition), minX, minY, maxX,
|
||||
maxY);
|
||||
|
||||
obs_data_release(array_obj);
|
||||
}
|
||||
obs_data_array_release(screenRegionArray);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupRegionTab()
|
||||
{
|
||||
for (auto &s : switcher->screenRegionSwitches) {
|
||||
QListWidgetItem *item;
|
||||
item = new QListWidgetItem(ui->screenRegionSwitches);
|
||||
ui->screenRegionSwitches->addItem(item);
|
||||
ScreenRegionWidget *sw = new ScreenRegionWidget(&s);
|
||||
item->setSizeHint(sw->minimumSizeHint());
|
||||
ui->screenRegionSwitches->setItemWidget(item, sw);
|
||||
}
|
||||
|
||||
if (switcher->screenRegionSwitches.size() == 0)
|
||||
addPulse = PulseWidget(ui->screenRegionAdd, QColor(Qt::green));
|
||||
|
||||
// screen region cursor position
|
||||
QTimer *screenRegionTimer = new QTimer(this);
|
||||
connect(screenRegionTimer, SIGNAL(timeout()), this,
|
||||
SLOT(updateScreenRegionCursorPos()));
|
||||
screenRegionTimer->start(1000);
|
||||
}
|
||||
|
||||
ScreenRegionWidget::ScreenRegionWidget(ScreenRegionSwitch *s)
|
||||
: SwitchWidget(s, false)
|
||||
{
|
||||
minX = new QSpinBox();
|
||||
minY = new QSpinBox();
|
||||
maxX = new QSpinBox();
|
||||
maxY = new QSpinBox();
|
||||
|
||||
cursorLabel = new QLabel("If cursor is in");
|
||||
xLabel = new QLabel("x");
|
||||
switchLabel = new QLabel("switch to");
|
||||
usingLabel = new QLabel("using");
|
||||
|
||||
minX->setPrefix("Min X: ");
|
||||
minY->setPrefix("Min Y: ");
|
||||
maxX->setPrefix("Max X: ");
|
||||
maxY->setPrefix("Max Y: ");
|
||||
|
||||
minX->setMinimum(-1000000);
|
||||
minY->setMinimum(-1000000);
|
||||
maxX->setMinimum(-1000000);
|
||||
maxY->setMinimum(-1000000);
|
||||
|
||||
minX->setMaximum(1000000);
|
||||
minY->setMaximum(1000000);
|
||||
maxX->setMaximum(1000000);
|
||||
maxY->setMaximum(1000000);
|
||||
|
||||
QWidget::connect(minX, SIGNAL(valueChanged(int)), this,
|
||||
SLOT(MinXChanged(int)));
|
||||
QWidget::connect(minY, SIGNAL(valueChanged(int)), this,
|
||||
SLOT(MinYChanged(int)));
|
||||
QWidget::connect(maxX, SIGNAL(valueChanged(int)), this,
|
||||
SLOT(MaxXChanged(int)));
|
||||
QWidget::connect(maxY, SIGNAL(valueChanged(int)), this,
|
||||
SLOT(MaxYChanged(int)));
|
||||
|
||||
if (s) {
|
||||
minX->setValue(s->minX);
|
||||
minY->setValue(s->minY);
|
||||
maxX->setValue(s->maxX);
|
||||
maxY->setValue(s->maxY);
|
||||
}
|
||||
|
||||
setStyleSheet("* { background-color: transparent; }");
|
||||
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||
|
||||
mainLayout->addWidget(cursorLabel);
|
||||
mainLayout->addWidget(minX);
|
||||
mainLayout->addWidget(minY);
|
||||
mainLayout->addWidget(xLabel);
|
||||
mainLayout->addWidget(maxX);
|
||||
mainLayout->addWidget(maxY);
|
||||
mainLayout->addWidget(switchLabel);
|
||||
mainLayout->addWidget(scenes);
|
||||
mainLayout->addWidget(usingLabel);
|
||||
mainLayout->addWidget(transitions);
|
||||
mainLayout->addStretch();
|
||||
|
||||
setLayout(mainLayout);
|
||||
|
||||
switchData = s;
|
||||
|
||||
loading = false;
|
||||
}
|
||||
|
||||
ScreenRegionSwitch *ScreenRegionWidget::getSwitchData()
|
||||
{
|
||||
return switchData;
|
||||
}
|
||||
|
||||
void ScreenRegionWidget::setSwitchData(ScreenRegionSwitch *s)
|
||||
{
|
||||
switchData = s;
|
||||
}
|
||||
|
||||
void ScreenRegionWidget::swapSwitchData(ScreenRegionWidget *s1,
|
||||
ScreenRegionWidget *s2)
|
||||
{
|
||||
SwitchWidget::swapSwitchData(s1, s2);
|
||||
|
||||
ScreenRegionSwitch *t = s1->getSwitchData();
|
||||
s1->setSwitchData(s2->getSwitchData());
|
||||
s2->setSwitchData(t);
|
||||
}
|
||||
|
||||
void ScreenRegionWidget::showFrame()
|
||||
{
|
||||
drawFrame();
|
||||
helperFrame.show();
|
||||
}
|
||||
|
||||
void ScreenRegionWidget::hideFrame()
|
||||
{
|
||||
helperFrame.hide();
|
||||
}
|
||||
|
||||
void ScreenRegionWidget::MinXChanged(int pos)
|
||||
{
|
||||
if (loading || !switchData)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->minX = pos;
|
||||
|
||||
drawFrame();
|
||||
}
|
||||
|
||||
void ScreenRegionWidget::MinYChanged(int pos)
|
||||
{
|
||||
if (loading || !switchData)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->minY = pos;
|
||||
|
||||
drawFrame();
|
||||
}
|
||||
|
||||
void ScreenRegionWidget::MaxXChanged(int pos)
|
||||
{
|
||||
if (loading || !switchData)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->maxX = pos;
|
||||
|
||||
drawFrame();
|
||||
}
|
||||
|
||||
void ScreenRegionWidget::MaxYChanged(int pos)
|
||||
{
|
||||
if (loading || !switchData)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->maxY = pos;
|
||||
|
||||
drawFrame();
|
||||
}
|
||||
|
||||
void ScreenRegionWidget::drawFrame()
|
||||
{
|
||||
helperFrame.setFrameStyle(QFrame::Box | QFrame::Plain);
|
||||
helperFrame.setWindowFlags(Qt::FramelessWindowHint | Qt::Tool |
|
||||
Qt::WindowTransparentForInput |
|
||||
Qt::WindowDoesNotAcceptFocus |
|
||||
Qt::WindowStaysOnTopHint);
|
||||
helperFrame.setAttribute(Qt::WA_TranslucentBackground, true);
|
||||
|
||||
if (switchData)
|
||||
helperFrame.setGeometry(switchData->minX, switchData->minY,
|
||||
switchData->maxX - switchData->minX,
|
||||
switchData->maxY - switchData->minY);
|
||||
}
|
||||
419
src/switch-sequence.cpp
Normal file
419
src/switch-sequence.cpp
Normal file
@@ -0,0 +1,419 @@
|
||||
#include <QFileDialog>
|
||||
#include <QTextStream>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
#include "headers/utility.hpp"
|
||||
|
||||
static QMetaObject::Connection addPulse;
|
||||
|
||||
void AdvSceneSwitcher::on_sceneSequenceAdd_clicked()
|
||||
{
|
||||
ui->sceneSequenceAdd->disconnect(addPulse);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->sceneSequenceSwitches.emplace_back();
|
||||
|
||||
QListWidgetItem *item;
|
||||
item = new QListWidgetItem(ui->sceneSequenceSwitches);
|
||||
ui->sceneSequenceSwitches->addItem(item);
|
||||
SequenceWidget *sw =
|
||||
new SequenceWidget(&switcher->sceneSequenceSwitches.back());
|
||||
item->setSizeHint(sw->minimumSizeHint());
|
||||
ui->sceneSequenceSwitches->setItemWidget(item, sw);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_sceneSequenceRemove_clicked()
|
||||
{
|
||||
QListWidgetItem *item = ui->sceneSequenceSwitches->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
int idx = ui->sceneSequenceSwitches->currentRow();
|
||||
auto &switches = switcher->sceneSequenceSwitches;
|
||||
switches.erase(switches.begin() + idx);
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_sceneSequenceUp_clicked()
|
||||
{
|
||||
int index = ui->sceneSequenceSwitches->currentRow();
|
||||
if (!listMoveUp(ui->sceneSequenceSwitches))
|
||||
return;
|
||||
|
||||
SequenceWidget *s1 =
|
||||
(SequenceWidget *)ui->sceneSequenceSwitches->itemWidget(
|
||||
ui->sceneSequenceSwitches->item(index));
|
||||
SequenceWidget *s2 =
|
||||
(SequenceWidget *)ui->sceneSequenceSwitches->itemWidget(
|
||||
ui->sceneSequenceSwitches->item(index - 1));
|
||||
SequenceWidget::swapSwitchData(s1, s2);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
std::swap(switcher->sceneSequenceSwitches[index],
|
||||
switcher->sceneSequenceSwitches[index - 1]);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_sceneSequenceDown_clicked()
|
||||
{
|
||||
int index = ui->sceneSequenceSwitches->currentRow();
|
||||
|
||||
if (!listMoveDown(ui->sceneSequenceSwitches))
|
||||
return;
|
||||
|
||||
SequenceWidget *s1 =
|
||||
(SequenceWidget *)ui->sceneSequenceSwitches->itemWidget(
|
||||
ui->sceneSequenceSwitches->item(index));
|
||||
SequenceWidget *s2 =
|
||||
(SequenceWidget *)ui->sceneSequenceSwitches->itemWidget(
|
||||
ui->sceneSequenceSwitches->item(index + 1));
|
||||
SequenceWidget::swapSwitchData(s1, s2);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
std::swap(switcher->sceneSequenceSwitches[index],
|
||||
switcher->sceneSequenceSwitches[index + 1]);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_sceneSequenceSave_clicked()
|
||||
{
|
||||
QString directory = QFileDialog::getSaveFileName(
|
||||
this, tr("Save Scene Sequence to file ..."),
|
||||
QDir::currentPath(), tr("Text files (*.txt)"));
|
||||
if (directory.isEmpty())
|
||||
return;
|
||||
QFile file(directory);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
|
||||
return;
|
||||
|
||||
obs_data_t *obj = obs_data_create();
|
||||
switcher->saveSceneSequenceSwitches(obj);
|
||||
obs_data_save_json(obj, file.fileName().toUtf8().constData());
|
||||
obs_data_release(obj);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_sceneSequenceLoad_clicked()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
QString directory = QFileDialog::getOpenFileName(
|
||||
this, tr("Select a file to read Scene Sequence from ..."),
|
||||
QDir::currentPath(), tr("Text files (*.txt)"));
|
||||
if (directory.isEmpty())
|
||||
return;
|
||||
|
||||
QFile file(directory);
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
return;
|
||||
|
||||
obs_data_t *obj = obs_data_create_from_json_file(
|
||||
file.fileName().toUtf8().constData());
|
||||
|
||||
if (!obj) {
|
||||
QMessageBox Msgbox;
|
||||
Msgbox.setText(
|
||||
"Advanced Scene Switcher failed to import settings!");
|
||||
Msgbox.exec();
|
||||
return;
|
||||
}
|
||||
switcher->loadSceneSequenceSwitches(obj);
|
||||
obs_data_release(obj);
|
||||
|
||||
QMessageBox Msgbox;
|
||||
Msgbox.setText(
|
||||
"Advanced Scene Switcher settings imported successfully!");
|
||||
Msgbox.exec();
|
||||
close();
|
||||
}
|
||||
|
||||
void SwitcherData::checkSceneSequence(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition,
|
||||
std::unique_lock<std::mutex> &lock)
|
||||
{
|
||||
obs_source_t *currentSource = obs_frontend_get_current_scene();
|
||||
obs_weak_source_t *ws = obs_source_get_weak_source(currentSource);
|
||||
|
||||
for (SceneSequenceSwitch &s : sceneSequenceSwitches) {
|
||||
if (!s.initialized())
|
||||
continue;
|
||||
|
||||
if (s.startScene == ws) {
|
||||
int dur = s.delay * 1000 - interval;
|
||||
if (dur > 0) {
|
||||
waitScene = currentSource;
|
||||
|
||||
if (verbose)
|
||||
s.logSleep(dur);
|
||||
|
||||
cv.wait_for(lock,
|
||||
std::chrono::milliseconds(dur));
|
||||
waitScene = nullptr;
|
||||
}
|
||||
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.usePreviousScene) ? previousScene
|
||||
: s.scene;
|
||||
transition = s.transition;
|
||||
if (verbose)
|
||||
s.logMatch();
|
||||
}
|
||||
obs_source_release(currentSource2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
obs_source_release(currentSource);
|
||||
obs_weak_source_release(ws);
|
||||
}
|
||||
|
||||
void SwitcherData::saveSceneSequenceSwitches(obs_data_t *obj)
|
||||
{
|
||||
obs_data_array_t *sceneSequenceArray = obs_data_array_create();
|
||||
for (SceneSequenceSwitch &s : switcher->sceneSequenceSwitches) {
|
||||
obs_data_t *array_obj = obs_data_create();
|
||||
|
||||
obs_source_t *source1 =
|
||||
obs_weak_source_get_source(s.startScene);
|
||||
obs_source_t *source2 = obs_weak_source_get_source(s.scene);
|
||||
obs_source_t *transition =
|
||||
obs_weak_source_get_source(s.transition);
|
||||
if (source1 && (s.usePreviousScene || source2) && transition) {
|
||||
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",
|
||||
s.usePreviousScene
|
||||
? previous_scene_name
|
||||
: sceneName2);
|
||||
obs_data_set_string(array_obj, "transition",
|
||||
transitionName);
|
||||
obs_data_set_double(array_obj, "delay", s.delay);
|
||||
obs_data_set_int(array_obj, "delayMultiplier",
|
||||
s.delayMultiplier);
|
||||
obs_data_array_push_back(sceneSequenceArray, array_obj);
|
||||
}
|
||||
|
||||
obs_source_release(source1);
|
||||
obs_source_release(source2);
|
||||
obs_source_release(transition);
|
||||
obs_data_release(array_obj);
|
||||
}
|
||||
obs_data_set_array(obj, "sceneRoundTrip", sceneSequenceArray);
|
||||
obs_data_array_release(sceneSequenceArray);
|
||||
}
|
||||
|
||||
void SwitcherData::loadSceneSequenceSwitches(obs_data_t *obj)
|
||||
{
|
||||
switcher->sceneSequenceSwitches.clear();
|
||||
|
||||
obs_data_array_t *sceneSequenceArray =
|
||||
obs_data_get_array(obj, "sceneRoundTrip");
|
||||
size_t count = obs_data_array_count(sceneSequenceArray);
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
obs_data_t *array_obj =
|
||||
obs_data_array_item(sceneSequenceArray, 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");
|
||||
double delay = obs_data_get_double(array_obj, "delay");
|
||||
int delayMultiplier =
|
||||
obs_data_get_int(array_obj, "delayMultiplier");
|
||||
if (delayMultiplier == 0 ||
|
||||
(delayMultiplier != 1 && delayMultiplier % 60 != 0))
|
||||
delayMultiplier = 1;
|
||||
|
||||
switcher->sceneSequenceSwitches.emplace_back(
|
||||
GetWeakSourceByName(scene1),
|
||||
GetWeakSourceByName(scene2),
|
||||
GetWeakTransitionByName(transition), delay,
|
||||
delayMultiplier,
|
||||
(strcmp(scene2, previous_scene_name) == 0));
|
||||
|
||||
obs_data_release(array_obj);
|
||||
}
|
||||
obs_data_array_release(sceneSequenceArray);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupSequenceTab()
|
||||
{
|
||||
for (auto &s : switcher->sceneSequenceSwitches) {
|
||||
QListWidgetItem *item;
|
||||
item = new QListWidgetItem(ui->sceneSequenceSwitches);
|
||||
ui->sceneSequenceSwitches->addItem(item);
|
||||
SequenceWidget *sw = new SequenceWidget(&s);
|
||||
item->setSizeHint(sw->minimumSizeHint());
|
||||
ui->sceneSequenceSwitches->setItemWidget(item, sw);
|
||||
}
|
||||
|
||||
if (switcher->sceneSequenceSwitches.size() == 0)
|
||||
addPulse = PulseWidget(ui->sceneSequenceAdd, QColor(Qt::green));
|
||||
}
|
||||
|
||||
bool SceneSequenceSwitch::initialized()
|
||||
{
|
||||
return SceneSwitcherEntry::initialized() && startScene;
|
||||
}
|
||||
|
||||
bool SceneSequenceSwitch::valid()
|
||||
{
|
||||
return !initialized() ||
|
||||
(SceneSwitcherEntry::valid() && WeakSourceValid(startScene));
|
||||
}
|
||||
|
||||
void SceneSequenceSwitch::logSleep(int dur)
|
||||
{
|
||||
blog(LOG_INFO, "sequence sleep %d", dur);
|
||||
}
|
||||
|
||||
void populateDelayUnits(QComboBox *list)
|
||||
{
|
||||
list->addItem("seconds");
|
||||
list->addItem("minutes");
|
||||
list->addItem("hours");
|
||||
}
|
||||
|
||||
SequenceWidget::SequenceWidget(SceneSequenceSwitch *s) : SwitchWidget(s)
|
||||
{
|
||||
delay = new QDoubleSpinBox();
|
||||
delayUnits = new QComboBox();
|
||||
startScenes = new QComboBox();
|
||||
|
||||
whenLabel = new QLabel("When");
|
||||
switchLabel = new QLabel("is active switch to");
|
||||
afterLabel = new QLabel("after");
|
||||
usingLabel = new QLabel("using");
|
||||
|
||||
QWidget::connect(delay, SIGNAL(valueChanged(double)), this,
|
||||
SLOT(DelayChanged(double)));
|
||||
QWidget::connect(delayUnits, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(DelayUnitsChanged(int)));
|
||||
QWidget::connect(startScenes,
|
||||
SIGNAL(currentTextChanged(const QString &)), this,
|
||||
SLOT(StartSceneChanged(const QString &)));
|
||||
|
||||
delay->setMaximum(99999.000000);
|
||||
AdvSceneSwitcher::populateSceneSelection(startScenes, false);
|
||||
populateDelayUnits(delayUnits);
|
||||
|
||||
if (s) {
|
||||
switch (s->delayMultiplier) {
|
||||
case 1:
|
||||
delayUnits->setCurrentIndex(0);
|
||||
break;
|
||||
case 60:
|
||||
delayUnits->setCurrentIndex(1);
|
||||
break;
|
||||
case 3600:
|
||||
delayUnits->setCurrentIndex(2);
|
||||
break;
|
||||
default:
|
||||
delayUnits->setCurrentIndex(0);
|
||||
}
|
||||
startScenes->setCurrentText(
|
||||
GetWeakSourceName(s->startScene).c_str());
|
||||
}
|
||||
|
||||
setStyleSheet("* { background-color: transparent; }");
|
||||
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||
|
||||
mainLayout->addWidget(whenLabel);
|
||||
mainLayout->addWidget(startScenes);
|
||||
mainLayout->addWidget(switchLabel);
|
||||
mainLayout->addWidget(scenes);
|
||||
mainLayout->addWidget(afterLabel);
|
||||
mainLayout->addWidget(delay);
|
||||
mainLayout->addWidget(delayUnits);
|
||||
mainLayout->addWidget(usingLabel);
|
||||
mainLayout->addWidget(transitions);
|
||||
mainLayout->addStretch();
|
||||
|
||||
setLayout(mainLayout);
|
||||
|
||||
switchData = s;
|
||||
|
||||
loading = false;
|
||||
|
||||
UpdateDelay();
|
||||
}
|
||||
|
||||
SceneSequenceSwitch *SequenceWidget::getSwitchData()
|
||||
{
|
||||
return switchData;
|
||||
}
|
||||
|
||||
void SequenceWidget::setSwitchData(SceneSequenceSwitch *s)
|
||||
{
|
||||
switchData = s;
|
||||
}
|
||||
|
||||
void SequenceWidget::swapSwitchData(SequenceWidget *s1, SequenceWidget *s2)
|
||||
{
|
||||
SwitchWidget::swapSwitchData(s1, s2);
|
||||
|
||||
SceneSequenceSwitch *t = s1->getSwitchData();
|
||||
s1->setSwitchData(s2->getSwitchData());
|
||||
s2->setSwitchData(t);
|
||||
}
|
||||
|
||||
void SequenceWidget::UpdateDelay()
|
||||
{
|
||||
if (switchData)
|
||||
delay->setValue(switchData->delay /
|
||||
switchData->delayMultiplier);
|
||||
}
|
||||
|
||||
void SequenceWidget::DelayChanged(double delay)
|
||||
{
|
||||
if (loading || !switchData)
|
||||
return;
|
||||
switchData->delay = delay * switchData->delayMultiplier;
|
||||
}
|
||||
|
||||
void SequenceWidget::DelayUnitsChanged(int idx)
|
||||
{
|
||||
if (loading || !switchData)
|
||||
return;
|
||||
|
||||
delay_units unit = (delay_units)idx;
|
||||
|
||||
switch (unit) {
|
||||
case SECONDS:
|
||||
switchData->delayMultiplier = 1;
|
||||
break;
|
||||
case MINUTES:
|
||||
switchData->delayMultiplier = 60;
|
||||
break;
|
||||
case HOURS:
|
||||
switchData->delayMultiplier = 60 * 60;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
UpdateDelay();
|
||||
}
|
||||
|
||||
void SequenceWidget::StartSceneChanged(const QString &text)
|
||||
{
|
||||
if (loading || !switchData)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->startScene = GetWeakSourceByQString(text);
|
||||
}
|
||||
309
src/switch-time.cpp
Normal file
309
src/switch-time.cpp
Normal file
@@ -0,0 +1,309 @@
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
#include "headers/utility.hpp"
|
||||
|
||||
static QMetaObject::Connection addPulse;
|
||||
|
||||
void AdvSceneSwitcher::on_timeAdd_clicked()
|
||||
{
|
||||
ui->timeAdd->disconnect(addPulse);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->timeSwitches.emplace_back();
|
||||
|
||||
QListWidgetItem *item;
|
||||
item = new QListWidgetItem(ui->timeSwitches);
|
||||
ui->timeSwitches->addItem(item);
|
||||
TimeSwitchWidget *sw =
|
||||
new TimeSwitchWidget(&switcher->timeSwitches.back());
|
||||
item->setSizeHint(sw->minimumSizeHint());
|
||||
ui->timeSwitches->setItemWidget(item, sw);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_timeRemove_clicked()
|
||||
{
|
||||
QListWidgetItem *item = ui->timeSwitches->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
int idx = ui->timeSwitches->currentRow();
|
||||
auto &switches = switcher->timeSwitches;
|
||||
switches.erase(switches.begin() + idx);
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_timeUp_clicked()
|
||||
{
|
||||
int index = ui->timeSwitches->currentRow();
|
||||
if (!listMoveUp(ui->timeSwitches))
|
||||
return;
|
||||
|
||||
TimeSwitchWidget *s1 = (TimeSwitchWidget *)ui->timeSwitches->itemWidget(
|
||||
ui->timeSwitches->item(index));
|
||||
TimeSwitchWidget *s2 = (TimeSwitchWidget *)ui->timeSwitches->itemWidget(
|
||||
ui->timeSwitches->item(index - 1));
|
||||
TimeSwitchWidget::swapSwitchData(s1, s2);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
std::swap(switcher->timeSwitches[index],
|
||||
switcher->timeSwitches[index - 1]);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_timeDown_clicked()
|
||||
{
|
||||
int index = ui->timeSwitches->currentRow();
|
||||
|
||||
if (!listMoveDown(ui->timeSwitches))
|
||||
return;
|
||||
|
||||
TimeSwitchWidget *s1 = (TimeSwitchWidget *)ui->timeSwitches->itemWidget(
|
||||
ui->timeSwitches->item(index));
|
||||
TimeSwitchWidget *s2 = (TimeSwitchWidget *)ui->timeSwitches->itemWidget(
|
||||
ui->timeSwitches->item(index + 1));
|
||||
TimeSwitchWidget::swapSwitchData(s1, s2);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
std::swap(switcher->timeSwitches[index],
|
||||
switcher->timeSwitches[index + 1]);
|
||||
}
|
||||
|
||||
bool timesAreInInterval(QTime &time1, QTime &time2, int &interval)
|
||||
{
|
||||
bool ret = false;
|
||||
QTime validSwitchTimeWindow = time1.addMSecs(interval);
|
||||
|
||||
ret = time1 <= time2 && time2 <= validSwitchTimeWindow;
|
||||
// check for overflow
|
||||
if (!ret && validSwitchTimeWindow.msecsSinceStartOfDay() < interval) {
|
||||
ret = time2 >= time1 || time2 <= validSwitchTimeWindow;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool checkLiveTime(TimeSwitch &s, QDateTime &start, int &interval)
|
||||
{
|
||||
if (start.isNull())
|
||||
return false;
|
||||
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
QTime timePassed = QTime(0, 0).addMSecs(start.msecsTo(now));
|
||||
|
||||
return timesAreInInterval(s.time, timePassed, interval);
|
||||
}
|
||||
|
||||
bool checkRegularTime(TimeSwitch &s, int &interval)
|
||||
{
|
||||
if (s.trigger != ANY_DAY &&
|
||||
s.trigger != QDate::currentDate().dayOfWeek())
|
||||
return false;
|
||||
|
||||
QTime now = QTime::currentTime();
|
||||
|
||||
return timesAreInInterval(s.time, now, interval);
|
||||
}
|
||||
|
||||
void SwitcherData::checkTimeSwitch(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition)
|
||||
{
|
||||
if (timeSwitches.size() == 0)
|
||||
return;
|
||||
|
||||
for (TimeSwitch &s : timeSwitches) {
|
||||
if (!s.initialized())
|
||||
continue;
|
||||
|
||||
if (s.trigger == LIVE)
|
||||
match = checkLiveTime(s, liveTime, interval);
|
||||
else
|
||||
match = checkRegularTime(s, interval);
|
||||
|
||||
if (match) {
|
||||
scene = (s.usePreviousScene) ? previousScene : s.scene;
|
||||
transition = s.transition;
|
||||
match = true;
|
||||
|
||||
if (verbose)
|
||||
s.logMatch();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SwitcherData::saveTimeSwitches(obs_data_t *obj)
|
||||
{
|
||||
obs_data_array_t *timeArray = obs_data_array_create();
|
||||
for (TimeSwitch &s : switcher->timeSwitches) {
|
||||
obs_data_t *array_obj = obs_data_create();
|
||||
|
||||
obs_source_t *sceneSource = obs_weak_source_get_source(s.scene);
|
||||
obs_source_t *transition =
|
||||
obs_weak_source_get_source(s.transition);
|
||||
if ((s.usePreviousScene || sceneSource) && transition) {
|
||||
const char *sceneName =
|
||||
obs_source_get_name(sceneSource);
|
||||
const char *transitionName =
|
||||
obs_source_get_name(transition);
|
||||
obs_data_set_string(array_obj, "scene",
|
||||
s.usePreviousScene
|
||||
? previous_scene_name
|
||||
: sceneName);
|
||||
obs_data_set_string(array_obj, "transition",
|
||||
transitionName);
|
||||
obs_data_set_int(array_obj, "trigger", s.trigger);
|
||||
obs_data_set_string(
|
||||
array_obj, "time",
|
||||
s.time.toString().toStdString().c_str());
|
||||
obs_data_array_push_back(timeArray, array_obj);
|
||||
}
|
||||
obs_source_release(sceneSource);
|
||||
obs_source_release(transition);
|
||||
|
||||
obs_data_release(array_obj);
|
||||
}
|
||||
obs_data_set_array(obj, "timeSwitches", timeArray);
|
||||
obs_data_array_release(timeArray);
|
||||
}
|
||||
|
||||
void SwitcherData::loadTimeSwitches(obs_data_t *obj)
|
||||
{
|
||||
switcher->timeSwitches.clear();
|
||||
|
||||
obs_data_array_t *timeArray = obs_data_get_array(obj, "timeSwitches");
|
||||
size_t count = obs_data_array_count(timeArray);
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
obs_data_t *array_obj = obs_data_array_item(timeArray, i);
|
||||
|
||||
const char *scene = obs_data_get_string(array_obj, "scene");
|
||||
const char *transition =
|
||||
obs_data_get_string(array_obj, "transition");
|
||||
timeTrigger trigger =
|
||||
(timeTrigger)obs_data_get_int(array_obj, "trigger");
|
||||
QTime time = QTime::fromString(
|
||||
obs_data_get_string(array_obj, "time"));
|
||||
|
||||
switcher->timeSwitches.emplace_back(
|
||||
GetWeakSourceByName(scene),
|
||||
GetWeakTransitionByName(transition), trigger, time,
|
||||
(strcmp(scene, previous_scene_name) == 0));
|
||||
|
||||
obs_data_release(array_obj);
|
||||
}
|
||||
obs_data_array_release(timeArray);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupTimeTab()
|
||||
{
|
||||
for (auto &s : switcher->timeSwitches) {
|
||||
QListWidgetItem *item;
|
||||
item = new QListWidgetItem(ui->timeSwitches);
|
||||
ui->timeSwitches->addItem(item);
|
||||
TimeSwitchWidget *sw = new TimeSwitchWidget(&s);
|
||||
item->setSizeHint(sw->minimumSizeHint());
|
||||
ui->timeSwitches->setItemWidget(item, sw);
|
||||
}
|
||||
|
||||
if (switcher->timeSwitches.size() == 0)
|
||||
addPulse = PulseWidget(ui->timeAdd, QColor(Qt::green));
|
||||
}
|
||||
|
||||
void populateTriggers(QComboBox *list)
|
||||
{
|
||||
list->addItem("On any day");
|
||||
list->addItem("Mondays");
|
||||
list->addItem("Tuesdays");
|
||||
list->addItem("Wednesdays");
|
||||
list->addItem("Thursdays");
|
||||
list->addItem("Fridays");
|
||||
list->addItem("Saturdays");
|
||||
list->addItem("Sundays");
|
||||
list->addItem("Atfer streaming/recording start");
|
||||
|
||||
list->setItemData(
|
||||
8,
|
||||
"The time relative to the start of streaming / recording will be used",
|
||||
Qt::ToolTipRole);
|
||||
}
|
||||
|
||||
TimeSwitchWidget::TimeSwitchWidget(TimeSwitch *s) : SwitchWidget(s)
|
||||
{
|
||||
triggers = new QComboBox();
|
||||
time = new QTimeEdit();
|
||||
|
||||
atLabel = new QLabel("at");
|
||||
switchLabel = new QLabel("switch to");
|
||||
usingLabel = new QLabel("using");
|
||||
|
||||
QWidget::connect(triggers, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(TriggerChanged(int)));
|
||||
QWidget::connect(time, SIGNAL(timeChanged(const QTime &)), this,
|
||||
SLOT(TimeChanged(const QTime &)));
|
||||
|
||||
populateTriggers(triggers);
|
||||
time->setDisplayFormat("HH:mm:ss");
|
||||
|
||||
if (s) {
|
||||
triggers->setCurrentIndex(s->trigger);
|
||||
time->setTime(s->time);
|
||||
}
|
||||
|
||||
setStyleSheet("* { background-color: transparent; }");
|
||||
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||
|
||||
mainLayout->addWidget(triggers);
|
||||
mainLayout->addWidget(atLabel);
|
||||
mainLayout->addWidget(time);
|
||||
mainLayout->addWidget(switchLabel);
|
||||
mainLayout->addWidget(scenes);
|
||||
mainLayout->addWidget(usingLabel);
|
||||
mainLayout->addWidget(transitions);
|
||||
mainLayout->addStretch();
|
||||
|
||||
setLayout(mainLayout);
|
||||
|
||||
switchData = s;
|
||||
|
||||
loading = false;
|
||||
}
|
||||
|
||||
TimeSwitch *TimeSwitchWidget::getSwitchData()
|
||||
{
|
||||
return switchData;
|
||||
}
|
||||
|
||||
void TimeSwitchWidget::setSwitchData(TimeSwitch *s)
|
||||
{
|
||||
switchData = s;
|
||||
}
|
||||
|
||||
void TimeSwitchWidget::swapSwitchData(TimeSwitchWidget *s1,
|
||||
TimeSwitchWidget *s2)
|
||||
{
|
||||
SwitchWidget::swapSwitchData(s1, s2);
|
||||
|
||||
TimeSwitch *t = s1->getSwitchData();
|
||||
s1->setSwitchData(s2->getSwitchData());
|
||||
s2->setSwitchData(t);
|
||||
}
|
||||
|
||||
void TimeSwitchWidget::TriggerChanged(int index)
|
||||
{
|
||||
if (loading || !switchData)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->trigger = (timeTrigger)index;
|
||||
}
|
||||
|
||||
void TimeSwitchWidget::TimeChanged(const QTime &time)
|
||||
{
|
||||
if (loading || !switchData)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->time = time;
|
||||
}
|
||||
519
src/switch-transitions.cpp
Normal file
519
src/switch-transitions.cpp
Normal file
@@ -0,0 +1,519 @@
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
#include "headers/utility.hpp"
|
||||
|
||||
void AdvSceneSwitcher::on_transitionsAdd_clicked()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->sceneTransitions.emplace_back();
|
||||
|
||||
QListWidgetItem *item;
|
||||
item = new QListWidgetItem(ui->sceneTransitions);
|
||||
ui->sceneTransitions->addItem(item);
|
||||
TransitionSwitchWidget *sw =
|
||||
new TransitionSwitchWidget(&switcher->sceneTransitions.back());
|
||||
item->setSizeHint(sw->minimumSizeHint());
|
||||
ui->sceneTransitions->setItemWidget(item, sw);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_transitionsRemove_clicked()
|
||||
{
|
||||
QListWidgetItem *item = ui->sceneTransitions->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
int idx = ui->sceneTransitions->currentRow();
|
||||
auto &switches = switcher->sceneTransitions;
|
||||
switches.erase(switches.begin() + idx);
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_transitionsUp_clicked()
|
||||
{
|
||||
int index = ui->sceneTransitions->currentRow();
|
||||
if (!listMoveUp(ui->sceneTransitions))
|
||||
return;
|
||||
|
||||
TransitionSwitchWidget *s1 =
|
||||
(TransitionSwitchWidget *)ui->sceneTransitions->itemWidget(
|
||||
ui->sceneTransitions->item(index));
|
||||
TransitionSwitchWidget *s2 =
|
||||
(TransitionSwitchWidget *)ui->sceneTransitions->itemWidget(
|
||||
ui->sceneTransitions->item(index - 1));
|
||||
TransitionSwitchWidget::swapSwitchData(s1, s2);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
std::swap(switcher->sceneTransitions[index],
|
||||
switcher->sceneTransitions[index - 1]);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_transitionsDown_clicked()
|
||||
{
|
||||
int index = ui->sceneTransitions->currentRow();
|
||||
|
||||
if (!listMoveDown(ui->sceneTransitions))
|
||||
return;
|
||||
|
||||
TransitionSwitchWidget *s1 =
|
||||
(TransitionSwitchWidget *)ui->sceneTransitions->itemWidget(
|
||||
ui->sceneTransitions->item(index));
|
||||
TransitionSwitchWidget *s2 =
|
||||
(TransitionSwitchWidget *)ui->sceneTransitions->itemWidget(
|
||||
ui->sceneTransitions->item(index + 1));
|
||||
TransitionSwitchWidget::swapSwitchData(s1, s2);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
std::swap(switcher->sceneTransitions[index],
|
||||
switcher->sceneTransitions[index + 1]);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_defaultTransitionsAdd_clicked()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->defaultSceneTransitions.emplace_back();
|
||||
|
||||
QListWidgetItem *item;
|
||||
item = new QListWidgetItem(ui->defaultTransitions);
|
||||
ui->defaultTransitions->addItem(item);
|
||||
DefTransitionSwitchWidget *sw = new DefTransitionSwitchWidget(
|
||||
&switcher->defaultSceneTransitions.back());
|
||||
item->setSizeHint(sw->minimumSizeHint());
|
||||
ui->defaultTransitions->setItemWidget(item, sw);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_defaultTransitionsRemove_clicked()
|
||||
{
|
||||
QListWidgetItem *item = ui->defaultTransitions->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
int idx = ui->defaultTransitions->currentRow();
|
||||
auto &switches = switcher->defaultSceneTransitions;
|
||||
switches.erase(switches.begin() + idx);
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_defaultTransitionsUp_clicked()
|
||||
{
|
||||
int index = ui->defaultTransitions->currentRow();
|
||||
if (!listMoveUp(ui->defaultTransitions))
|
||||
return;
|
||||
|
||||
TransitionSwitchWidget *s1 =
|
||||
(TransitionSwitchWidget *)ui->defaultTransitions->itemWidget(
|
||||
ui->defaultTransitions->item(index));
|
||||
TransitionSwitchWidget *s2 =
|
||||
(TransitionSwitchWidget *)ui->defaultTransitions->itemWidget(
|
||||
ui->defaultTransitions->item(index - 1));
|
||||
TransitionSwitchWidget::swapSwitchData(s1, s2);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
std::swap(switcher->defaultSceneTransitions[index],
|
||||
switcher->defaultSceneTransitions[index - 1]);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_defaultTransitionsDown_clicked()
|
||||
{
|
||||
int index = ui->defaultTransitions->currentRow();
|
||||
|
||||
if (!listMoveDown(ui->defaultTransitions))
|
||||
return;
|
||||
|
||||
DefTransitionSwitchWidget *s1 =
|
||||
(DefTransitionSwitchWidget *)ui->defaultTransitions->itemWidget(
|
||||
ui->defaultTransitions->item(index));
|
||||
DefTransitionSwitchWidget *s2 =
|
||||
(DefTransitionSwitchWidget *)ui->defaultTransitions->itemWidget(
|
||||
ui->defaultTransitions->item(index + 1));
|
||||
DefTransitionSwitchWidget::swapSwitchData(s1, s2);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
std::swap(switcher->defaultSceneTransitions[index],
|
||||
switcher->defaultSceneTransitions[index + 1]);
|
||||
}
|
||||
|
||||
void SwitcherData::setDefaultSceneTransitions()
|
||||
{
|
||||
if (changedDefTransitionRecently)
|
||||
return;
|
||||
|
||||
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) {
|
||||
if (!s.initialized())
|
||||
continue;
|
||||
|
||||
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);
|
||||
|
||||
if (verbose)
|
||||
s.logMatch();
|
||||
|
||||
obs_source_release(transition);
|
||||
break;
|
||||
}
|
||||
}
|
||||
obs_source_release(currentSource);
|
||||
obs_weak_source_release(ws);
|
||||
changedDefTransitionRecently = true;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_transitionOverridecheckBox_stateChanged(int state)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
if (!state) {
|
||||
switcher->tansitionOverrideOverride = false;
|
||||
} else {
|
||||
switcher->tansitionOverrideOverride = true;
|
||||
}
|
||||
}
|
||||
|
||||
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.initialized())
|
||||
continue;
|
||||
|
||||
if (t.scene == scene1 && t.scene2 == scene2) {
|
||||
ws = t.transition;
|
||||
break;
|
||||
}
|
||||
}
|
||||
obs_weak_source_addref(ws);
|
||||
}
|
||||
return ws;
|
||||
}
|
||||
|
||||
void overwriteTransitionOverride(obs_weak_source_t *sceneWs,
|
||||
obs_source_t *transition, transitionData &td)
|
||||
{
|
||||
obs_source_t *scene = obs_weak_source_get_source(sceneWs);
|
||||
obs_data_t *data = obs_source_get_private_settings(scene);
|
||||
|
||||
td.name = obs_data_get_string(data, "transition");
|
||||
td.duration = obs_data_get_int(data, "duration");
|
||||
|
||||
const char *name = obs_source_get_name(transition);
|
||||
int duration = obs_frontend_get_transition_duration();
|
||||
|
||||
obs_data_set_string(data, "transition", name);
|
||||
obs_data_set_int(data, "transition_duration", duration);
|
||||
|
||||
obs_data_release(data);
|
||||
obs_source_release(scene);
|
||||
}
|
||||
|
||||
void restoreTransitionOverride(obs_source_t *scene, transitionData td)
|
||||
{
|
||||
obs_data_t *data = obs_source_get_private_settings(scene);
|
||||
|
||||
obs_data_set_string(data, "transition", td.name.c_str());
|
||||
obs_data_set_int(data, "transition_duration", td.duration);
|
||||
|
||||
obs_data_release(data);
|
||||
}
|
||||
|
||||
void setNextTransition(OBSWeakSource &targetScene, obs_source_t *currentSource,
|
||||
OBSWeakSource &transition,
|
||||
bool &transitionOverrideOverride, transitionData &td)
|
||||
{
|
||||
obs_weak_source_t *currentScene =
|
||||
obs_source_get_weak_source(currentSource);
|
||||
obs_weak_source_t *nextTransitionWs =
|
||||
getNextTransition(currentScene, targetScene);
|
||||
obs_weak_source_release(currentScene);
|
||||
|
||||
obs_source_t *nextTransition = nullptr;
|
||||
if (nextTransitionWs) {
|
||||
nextTransition = obs_weak_source_get_source(nextTransitionWs);
|
||||
} else if (transition) {
|
||||
nextTransition = obs_weak_source_get_source(transition);
|
||||
}
|
||||
|
||||
if (nextTransition) {
|
||||
obs_frontend_set_current_transition(nextTransition);
|
||||
}
|
||||
|
||||
if (transitionOverrideOverride)
|
||||
overwriteTransitionOverride(targetScene, nextTransition, td);
|
||||
|
||||
obs_weak_source_release(nextTransitionWs);
|
||||
obs_source_release(nextTransition);
|
||||
}
|
||||
|
||||
void SwitcherData::saveSceneTransitions(obs_data_t *obj)
|
||||
{
|
||||
obs_data_array_t *sceneTransitionsArray = obs_data_array_create();
|
||||
for (SceneTransition &s : switcher->sceneTransitions) {
|
||||
obs_data_t *array_obj = obs_data_create();
|
||||
|
||||
obs_source_t *source1 = obs_weak_source_get_source(s.scene);
|
||||
obs_source_t *source2 = obs_weak_source_get_source(s.scene2);
|
||||
obs_source_t *transition =
|
||||
obs_weak_source_get_source(s.transition);
|
||||
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_array_push_back(sceneTransitionsArray,
|
||||
array_obj);
|
||||
}
|
||||
obs_source_release(source1);
|
||||
obs_source_release(source2);
|
||||
obs_source_release(transition);
|
||||
obs_data_release(array_obj);
|
||||
}
|
||||
obs_data_set_array(obj, "sceneTransitions", sceneTransitionsArray);
|
||||
obs_data_array_release(sceneTransitionsArray);
|
||||
|
||||
obs_data_array_t *defaultTransitionsArray = obs_data_array_create();
|
||||
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_array_push_back(defaultTransitionsArray,
|
||||
array_obj);
|
||||
}
|
||||
obs_source_release(source);
|
||||
obs_source_release(transition);
|
||||
obs_data_release(array_obj);
|
||||
}
|
||||
obs_data_set_array(obj, "defaultTransitions", defaultTransitionsArray);
|
||||
obs_data_array_release(defaultTransitionsArray);
|
||||
|
||||
obs_data_set_bool(obj, "tansitionOverrideOverride",
|
||||
switcher->tansitionOverrideOverride);
|
||||
}
|
||||
|
||||
void SwitcherData::loadSceneTransitions(obs_data_t *obj)
|
||||
{
|
||||
switcher->sceneTransitions.clear();
|
||||
|
||||
obs_data_array_t *sceneTransitionsArray =
|
||||
obs_data_get_array(obj, "sceneTransitions");
|
||||
size_t 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");
|
||||
|
||||
switcher->sceneTransitions.emplace_back(
|
||||
GetWeakSourceByName(scene1),
|
||||
GetWeakSourceByName(scene2),
|
||||
GetWeakTransitionByName(transition));
|
||||
|
||||
obs_data_release(array_obj);
|
||||
}
|
||||
obs_data_array_release(sceneTransitionsArray);
|
||||
|
||||
switcher->defaultSceneTransitions.clear();
|
||||
|
||||
obs_data_array_t *defaultTransitionsArray =
|
||||
obs_data_get_array(obj, "defaultTransitions");
|
||||
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");
|
||||
|
||||
switcher->defaultSceneTransitions.emplace_back(
|
||||
GetWeakSourceByName(scene),
|
||||
GetWeakTransitionByName(transition));
|
||||
|
||||
obs_data_release(array_obj);
|
||||
}
|
||||
obs_data_array_release(defaultTransitionsArray);
|
||||
|
||||
switcher->tansitionOverrideOverride =
|
||||
obs_data_get_bool(obj, "tansitionOverrideOverride");
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupTransitionsTab()
|
||||
{
|
||||
for (auto &s : switcher->sceneTransitions) {
|
||||
QListWidgetItem *item;
|
||||
item = new QListWidgetItem(ui->sceneTransitions);
|
||||
ui->sceneTransitions->addItem(item);
|
||||
TransitionSwitchWidget *sw = new TransitionSwitchWidget(&s);
|
||||
item->setSizeHint(sw->minimumSizeHint());
|
||||
ui->sceneTransitions->setItemWidget(item, sw);
|
||||
}
|
||||
|
||||
for (auto &s : switcher->defaultSceneTransitions) {
|
||||
QListWidgetItem *item;
|
||||
item = new QListWidgetItem(ui->defaultTransitions);
|
||||
ui->defaultTransitions->addItem(item);
|
||||
DefTransitionSwitchWidget *sw =
|
||||
new DefTransitionSwitchWidget(&s);
|
||||
item->setSizeHint(sw->minimumSizeHint());
|
||||
ui->defaultTransitions->setItemWidget(item, sw);
|
||||
}
|
||||
|
||||
ui->transitionOverridecheckBox->setChecked(
|
||||
switcher->tansitionOverrideOverride);
|
||||
}
|
||||
|
||||
bool SceneTransition::initialized()
|
||||
{
|
||||
return SceneSwitcherEntry::initialized() && scene2;
|
||||
}
|
||||
|
||||
bool SceneTransition::valid()
|
||||
{
|
||||
return !initialized() ||
|
||||
(SceneSwitcherEntry::valid() && WeakSourceValid(scene2));
|
||||
}
|
||||
|
||||
TransitionSwitchWidget::TransitionSwitchWidget(SceneTransition *s)
|
||||
: SwitchWidget(s, false)
|
||||
{
|
||||
scenes2 = new QComboBox();
|
||||
|
||||
switchLabel = new QLabel("Switch from scene");
|
||||
toLabel = new QLabel("to scene");
|
||||
usingLabel = new QLabel("using transition");
|
||||
|
||||
QWidget::connect(scenes2, SIGNAL(currentTextChanged(const QString &)),
|
||||
this, SLOT(Scene2Changed(const QString &)));
|
||||
|
||||
AdvSceneSwitcher::populateSceneSelection(scenes2, false);
|
||||
|
||||
if (s) {
|
||||
scenes2->setCurrentText(GetWeakSourceName(s->scene2).c_str());
|
||||
}
|
||||
|
||||
setStyleSheet("* { background-color: transparent; }");
|
||||
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||
|
||||
mainLayout->addWidget(switchLabel);
|
||||
mainLayout->addWidget(scenes);
|
||||
mainLayout->addWidget(toLabel);
|
||||
mainLayout->addWidget(scenes2);
|
||||
mainLayout->addWidget(usingLabel);
|
||||
mainLayout->addWidget(transitions);
|
||||
mainLayout->addStretch();
|
||||
|
||||
setLayout(mainLayout);
|
||||
|
||||
switchData = s;
|
||||
|
||||
loading = false;
|
||||
}
|
||||
|
||||
SceneTransition *TransitionSwitchWidget::getSwitchData()
|
||||
{
|
||||
return switchData;
|
||||
}
|
||||
|
||||
void TransitionSwitchWidget::setSwitchData(SceneTransition *s)
|
||||
{
|
||||
switchData = s;
|
||||
}
|
||||
|
||||
void TransitionSwitchWidget::swapSwitchData(TransitionSwitchWidget *s1,
|
||||
TransitionSwitchWidget *s2)
|
||||
{
|
||||
SwitchWidget::swapSwitchData(s1, s2);
|
||||
|
||||
SceneTransition *t = s1->getSwitchData();
|
||||
s1->setSwitchData(s2->getSwitchData());
|
||||
s2->setSwitchData(t);
|
||||
}
|
||||
|
||||
void TransitionSwitchWidget::Scene2Changed(const QString &text)
|
||||
{
|
||||
if (loading || !switchData)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->scene2 = GetWeakSourceByQString(text);
|
||||
}
|
||||
|
||||
DefTransitionSwitchWidget::DefTransitionSwitchWidget(DefaultSceneTransition *s)
|
||||
: SwitchWidget(s, false)
|
||||
{
|
||||
whenLabel = new QLabel("When scene");
|
||||
switchLabel =
|
||||
new QLabel("is active change default scene transition to ");
|
||||
|
||||
setStyleSheet("* { background-color: transparent; }");
|
||||
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||
|
||||
mainLayout->addWidget(whenLabel);
|
||||
mainLayout->addWidget(scenes);
|
||||
mainLayout->addWidget(switchLabel);
|
||||
mainLayout->addWidget(transitions);
|
||||
mainLayout->addStretch();
|
||||
|
||||
setLayout(mainLayout);
|
||||
|
||||
switchData = s;
|
||||
|
||||
loading = false;
|
||||
}
|
||||
|
||||
DefaultSceneTransition *DefTransitionSwitchWidget::getSwitchData()
|
||||
{
|
||||
return switchData;
|
||||
}
|
||||
|
||||
void DefTransitionSwitchWidget::setSwitchData(DefaultSceneTransition *s)
|
||||
{
|
||||
switchData = s;
|
||||
}
|
||||
|
||||
void DefTransitionSwitchWidget::swapSwitchData(DefTransitionSwitchWidget *s1,
|
||||
DefTransitionSwitchWidget *s2)
|
||||
{
|
||||
SwitchWidget::swapSwitchData(s1, s2);
|
||||
|
||||
DefaultSceneTransition *t = s1->getSwitchData();
|
||||
s1->setSwitchData(s2->getSwitchData());
|
||||
s2->setSwitchData(t);
|
||||
}
|
||||
477
src/switch-window.cpp
Normal file
477
src/switch-window.cpp
Normal file
@@ -0,0 +1,477 @@
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
#include "headers/utility.hpp"
|
||||
|
||||
static QMetaObject::Connection addPulse;
|
||||
|
||||
void AdvSceneSwitcher::on_windowAdd_clicked()
|
||||
{
|
||||
ui->windowAdd->disconnect(addPulse);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->windowSwitches.emplace_back();
|
||||
|
||||
QListWidgetItem *item;
|
||||
item = new QListWidgetItem(ui->windowSwitches);
|
||||
ui->windowSwitches->addItem(item);
|
||||
WindowSwitchWidget *sw =
|
||||
new WindowSwitchWidget(&switcher->windowSwitches.back());
|
||||
item->setSizeHint(sw->minimumSizeHint());
|
||||
ui->windowSwitches->setItemWidget(item, sw);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_windowRemove_clicked()
|
||||
{
|
||||
QListWidgetItem *item = ui->windowSwitches->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
int idx = ui->windowSwitches->currentRow();
|
||||
auto &switches = switcher->windowSwitches;
|
||||
switches.erase(switches.begin() + idx);
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_windowUp_clicked()
|
||||
{
|
||||
int index = ui->windowSwitches->currentRow();
|
||||
if (!listMoveUp(ui->windowSwitches))
|
||||
return;
|
||||
|
||||
WindowSwitchWidget *s1 =
|
||||
(WindowSwitchWidget *)ui->windowSwitches->itemWidget(
|
||||
ui->windowSwitches->item(index));
|
||||
WindowSwitchWidget *s2 =
|
||||
(WindowSwitchWidget *)ui->windowSwitches->itemWidget(
|
||||
ui->windowSwitches->item(index - 1));
|
||||
WindowSwitchWidget::swapSwitchData(s1, s2);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
std::swap(switcher->windowSwitches[index],
|
||||
switcher->windowSwitches[index - 1]);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_windowDown_clicked()
|
||||
{
|
||||
int index = ui->windowSwitches->currentRow();
|
||||
|
||||
if (!listMoveDown(ui->windowSwitches))
|
||||
return;
|
||||
|
||||
WindowSwitchWidget *s1 =
|
||||
(WindowSwitchWidget *)ui->windowSwitches->itemWidget(
|
||||
ui->windowSwitches->item(index));
|
||||
WindowSwitchWidget *s2 =
|
||||
(WindowSwitchWidget *)ui->windowSwitches->itemWidget(
|
||||
ui->windowSwitches->item(index + 1));
|
||||
WindowSwitchWidget::swapSwitchData(s1, s2);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
std::swap(switcher->windowSwitches[index],
|
||||
switcher->windowSwitches[index + 1]);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_ignoreWindowsAdd_clicked()
|
||||
{
|
||||
QString windowName = ui->ignoreWindowsWindows->currentText();
|
||||
|
||||
if (windowName.isEmpty())
|
||||
return;
|
||||
|
||||
QVariant v = QVariant::fromValue(windowName);
|
||||
|
||||
QList<QListWidgetItem *> items =
|
||||
ui->ignoreWindows->findItems(windowName, Qt::MatchExactly);
|
||||
|
||||
if (items.size() == 0) {
|
||||
QListWidgetItem *item =
|
||||
new QListWidgetItem(windowName, ui->ignoreWindows);
|
||||
item->setData(Qt::UserRole, v);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->ignoreWindowsSwitches.emplace_back(
|
||||
windowName.toUtf8().constData());
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_ignoreWindowsRemove_clicked()
|
||||
{
|
||||
QListWidgetItem *item = ui->ignoreWindows->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
QString windowName = item->data(Qt::UserRole).toString();
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> 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 AdvSceneSwitcher::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 AdvSceneSwitcher::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();
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
for (auto &s : switcher->ignoreWindowsSwitches) {
|
||||
if (window.compare(s.c_str()) == 0) {
|
||||
ui->ignoreWindowsWindows->setCurrentText(s.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool isRunning(std::string &title)
|
||||
{
|
||||
QStringList windows;
|
||||
|
||||
GetWindowList(windows);
|
||||
// True if switch is running (direct)
|
||||
bool equals = windows.contains(QString::fromStdString(title));
|
||||
// True if switch is running (regex)
|
||||
bool matches = (windows.indexOf(QRegularExpression(
|
||||
QString::fromStdString(title))) != -1);
|
||||
|
||||
return (equals || matches);
|
||||
}
|
||||
|
||||
bool isFocused(std::string &title)
|
||||
{
|
||||
std::string current;
|
||||
|
||||
GetCurrentWindowTitle(current);
|
||||
// True if switch equals current window
|
||||
bool equals = (title == current);
|
||||
// True if switch matches current window
|
||||
bool matches = QString::fromStdString(current).contains(
|
||||
QRegularExpression(QString::fromStdString(title)));
|
||||
|
||||
return (equals || matches);
|
||||
}
|
||||
|
||||
void SwitcherData::checkWindowTitleSwitch(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition)
|
||||
{
|
||||
std::string title;
|
||||
bool ignored = false;
|
||||
|
||||
// Check if current window is ignored
|
||||
GetCurrentWindowTitle(title);
|
||||
for (auto &window : ignoreWindowsSwitches) {
|
||||
// True if ignored switch equals current window
|
||||
bool equals = (title == window);
|
||||
// True if ignored switch matches current window
|
||||
bool matches = QString::fromStdString(title).contains(
|
||||
QRegularExpression(QString::fromStdString(window)));
|
||||
|
||||
if (equals || matches) {
|
||||
ignored = true;
|
||||
title = lastTitle;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
lastTitle = title;
|
||||
|
||||
// Check for match
|
||||
for (WindowSwitch &s : windowSwitches) {
|
||||
if (!s.initialized())
|
||||
continue;
|
||||
|
||||
// True if fullscreen is disabled OR current window is fullscreen
|
||||
bool fullscreen = (!s.fullscreen || isFullscreen(s.window));
|
||||
// True if maximized is disabled OR current window is maximized
|
||||
bool max = (!s.maximized || isMaximized(s.window));
|
||||
// True if focus is disabled OR switch is focused
|
||||
bool focus = (!s.focus || isFocused(s.window));
|
||||
// True if current window is ignored AND switch equals OR matches last window
|
||||
bool ignore =
|
||||
(ignored &&
|
||||
(title == s.window ||
|
||||
QString::fromStdString(title).contains(
|
||||
QRegularExpression(
|
||||
QString::fromStdString(s.window)))));
|
||||
|
||||
if (isRunning(s.window) &&
|
||||
(fullscreen && (max && (focus || ignore)))) {
|
||||
match = true;
|
||||
scene = s.scene;
|
||||
transition = s.transition;
|
||||
|
||||
if (verbose)
|
||||
s.logMatch();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SwitcherData::saveWindowTitleSwitches(obs_data_t *obj)
|
||||
{
|
||||
obs_data_array_t *windowTitleArray = obs_data_array_create();
|
||||
for (WindowSwitch &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_set_bool(array_obj, "maximized", s.maximized);
|
||||
obs_data_set_bool(array_obj, "focus", s.focus);
|
||||
obs_data_array_push_back(windowTitleArray, array_obj);
|
||||
}
|
||||
obs_source_release(source);
|
||||
obs_source_release(transition);
|
||||
obs_data_release(array_obj);
|
||||
}
|
||||
obs_data_set_array(obj, "switches", windowTitleArray);
|
||||
obs_data_array_release(windowTitleArray);
|
||||
|
||||
obs_data_array_t *ignoreWindowsArray = obs_data_array_create();
|
||||
for (std::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);
|
||||
}
|
||||
obs_data_set_array(obj, "ignoreWindows", ignoreWindowsArray);
|
||||
obs_data_array_release(ignoreWindowsArray);
|
||||
}
|
||||
|
||||
void SwitcherData::loadWindowTitleSwitches(obs_data_t *obj)
|
||||
{
|
||||
switcher->windowSwitches.clear();
|
||||
|
||||
obs_data_array_t *windowTitleArray =
|
||||
obs_data_get_array(obj, "switches");
|
||||
size_t count = obs_data_array_count(windowTitleArray);
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
obs_data_t *array_obj =
|
||||
obs_data_array_item(windowTitleArray, 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");
|
||||
#if __APPLE__
|
||||
// TODO:
|
||||
// not implemented on MacOS as I cannot test it
|
||||
bool maximized = false;
|
||||
#else
|
||||
bool maximized = obs_data_get_bool(array_obj, "maximized");
|
||||
#endif
|
||||
bool focus = obs_data_get_bool(array_obj, "focus") ||
|
||||
!obs_data_has_user_value(array_obj, "focus");
|
||||
|
||||
switcher->windowSwitches.emplace_back(
|
||||
GetWeakSourceByName(scene), window,
|
||||
GetWeakTransitionByName(transition), fullscreen,
|
||||
maximized, focus);
|
||||
|
||||
obs_data_release(array_obj);
|
||||
}
|
||||
obs_data_array_release(windowTitleArray);
|
||||
|
||||
switcher->ignoreWindowsSwitches.clear();
|
||||
|
||||
obs_data_array_t *ignoreWindowsArray =
|
||||
obs_data_get_array(obj, "ignoreWindows");
|
||||
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);
|
||||
}
|
||||
obs_data_array_release(ignoreWindowsArray);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupTitleTab()
|
||||
{
|
||||
for (auto &s : switcher->windowSwitches) {
|
||||
QListWidgetItem *item;
|
||||
item = new QListWidgetItem(ui->windowSwitches);
|
||||
ui->windowSwitches->addItem(item);
|
||||
WindowSwitchWidget *sw = new WindowSwitchWidget(&s);
|
||||
item->setSizeHint(sw->minimumSizeHint());
|
||||
ui->windowSwitches->setItemWidget(item, sw);
|
||||
}
|
||||
|
||||
if (switcher->windowSwitches.size() == 0)
|
||||
addPulse = PulseWidget(ui->windowAdd, QColor(Qt::green));
|
||||
|
||||
populateWindowSelection(ui->ignoreWindowsWindows);
|
||||
|
||||
for (auto &window : switcher->ignoreWindowsSwitches) {
|
||||
QString text = QString::fromStdString(window);
|
||||
|
||||
QListWidgetItem *item =
|
||||
new QListWidgetItem(text, ui->ignoreWindows);
|
||||
item->setData(Qt::UserRole, text);
|
||||
}
|
||||
}
|
||||
|
||||
WindowSwitchWidget::WindowSwitchWidget(WindowSwitch *s) : SwitchWidget(s, false)
|
||||
{
|
||||
windows = new QComboBox();
|
||||
fullscreen = new QCheckBox("if fullscreen");
|
||||
maximized = new QCheckBox("if maximized");
|
||||
focused = new QCheckBox("if focused");
|
||||
|
||||
QWidget::connect(windows, SIGNAL(currentTextChanged(const QString &)),
|
||||
this, SLOT(WindowChanged(const QString &)));
|
||||
QWidget::connect(fullscreen, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(FullscreenChanged(int)));
|
||||
QWidget::connect(maximized, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(MaximizedChanged(int)));
|
||||
QWidget::connect(focused, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(FocusChanged(int)));
|
||||
|
||||
AdvSceneSwitcher::populateWindowSelection(windows);
|
||||
|
||||
windows->setEditable(true);
|
||||
windows->setMaxVisibleItems(20);
|
||||
#if __APPLE__
|
||||
// TODO:
|
||||
// not implemented on MacOS as I cannot test it
|
||||
maximized->setDisabled(true);
|
||||
maximized->setVisible(false);
|
||||
#endif
|
||||
|
||||
if (s) {
|
||||
windows->setCurrentText(s->window.c_str());
|
||||
fullscreen->setChecked(s->fullscreen);
|
||||
maximized->setChecked(s->maximized);
|
||||
focused->setChecked(s->focus);
|
||||
}
|
||||
|
||||
setStyleSheet("* { background-color: transparent; }");
|
||||
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||
|
||||
mainLayout->addWidget(windows);
|
||||
mainLayout->addWidget(scenes);
|
||||
mainLayout->addWidget(transitions);
|
||||
mainLayout->addWidget(scenes);
|
||||
mainLayout->addWidget(fullscreen);
|
||||
mainLayout->addWidget(maximized);
|
||||
mainLayout->addWidget(focused);
|
||||
mainLayout->addStretch();
|
||||
|
||||
setLayout(mainLayout);
|
||||
|
||||
switchData = s;
|
||||
|
||||
loading = false;
|
||||
}
|
||||
|
||||
WindowSwitch *WindowSwitchWidget::getSwitchData()
|
||||
{
|
||||
return switchData;
|
||||
}
|
||||
|
||||
void WindowSwitchWidget::setSwitchData(WindowSwitch *s)
|
||||
{
|
||||
switchData = s;
|
||||
}
|
||||
|
||||
void WindowSwitchWidget::swapSwitchData(WindowSwitchWidget *s1,
|
||||
WindowSwitchWidget *s2)
|
||||
{
|
||||
SwitchWidget::swapSwitchData(s1, s2);
|
||||
|
||||
WindowSwitch *t = s1->getSwitchData();
|
||||
s1->setSwitchData(s2->getSwitchData());
|
||||
s2->setSwitchData(t);
|
||||
}
|
||||
|
||||
void WindowSwitchWidget::WindowChanged(const QString &text)
|
||||
{
|
||||
if (loading || !switchData)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->window = text.toStdString();
|
||||
}
|
||||
|
||||
void WindowSwitchWidget::FullscreenChanged(int state)
|
||||
{
|
||||
if (loading || !switchData)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->fullscreen = state;
|
||||
}
|
||||
|
||||
void WindowSwitchWidget::MaximizedChanged(int state)
|
||||
{
|
||||
if (loading || !switchData)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->maximized = state;
|
||||
}
|
||||
|
||||
void WindowSwitchWidget::FocusChanged(int state)
|
||||
{
|
||||
if (loading || !switchData)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->focus = state;
|
||||
}
|
||||
96
src/switcher-data-structs.cpp
Normal file
96
src/switcher-data-structs.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
#include "headers/switcher-data-structs.hpp"
|
||||
#include "headers/utility.hpp"
|
||||
|
||||
void SwitcherData::Prune()
|
||||
{
|
||||
for (size_t i = 0; i < windowSwitches.size(); i++) {
|
||||
WindowSwitch &s = windowSwitches[i];
|
||||
if (!s.valid())
|
||||
windowSwitches.erase(windowSwitches.begin() + i--);
|
||||
}
|
||||
|
||||
if (nonMatchingScene && !WeakSourceValid(nonMatchingScene)) {
|
||||
switchIfNotMatching = NO_SWITCH;
|
||||
nonMatchingScene = nullptr;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < randomSwitches.size(); i++) {
|
||||
RandomSwitch &s = randomSwitches[i];
|
||||
if (!s.valid())
|
||||
randomSwitches.erase(randomSwitches.begin() + i--);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < screenRegionSwitches.size(); i++) {
|
||||
ScreenRegionSwitch &s = screenRegionSwitches[i];
|
||||
if (!s.valid())
|
||||
screenRegionSwitches.erase(
|
||||
screenRegionSwitches.begin() + i--);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < pauseScenesSwitches.size(); i++) {
|
||||
OBSWeakSource &scene = pauseScenesSwitches[i];
|
||||
if (!WeakSourceValid(scene))
|
||||
pauseScenesSwitches.erase(pauseScenesSwitches.begin() +
|
||||
i--);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < sceneSequenceSwitches.size(); i++) {
|
||||
SceneSequenceSwitch &s = sceneSequenceSwitches[i];
|
||||
if (!s.valid())
|
||||
sceneSequenceSwitches.erase(
|
||||
sceneSequenceSwitches.begin() + i--);
|
||||
}
|
||||
|
||||
if (!WeakSourceValid(autoStopScene)) {
|
||||
autoStopScene = nullptr;
|
||||
autoStopEnable = false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < sceneTransitions.size(); i++) {
|
||||
SceneTransition &s = sceneTransitions[i];
|
||||
if (!s.valid())
|
||||
sceneTransitions.erase(sceneTransitions.begin() + i--);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < defaultSceneTransitions.size(); i++) {
|
||||
DefaultSceneTransition &s = defaultSceneTransitions[i];
|
||||
if (!s.valid())
|
||||
defaultSceneTransitions.erase(
|
||||
defaultSceneTransitions.begin() + i--);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < executableSwitches.size(); i++) {
|
||||
ExecutableSwitch &s = executableSwitches[i];
|
||||
if (!s.valid())
|
||||
executableSwitches.erase(executableSwitches.begin() +
|
||||
i--);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < fileSwitches.size(); i++) {
|
||||
FileSwitch &s = fileSwitches[i];
|
||||
if (!s.valid())
|
||||
fileSwitches.erase(fileSwitches.begin() + i--);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < timeSwitches.size(); i++) {
|
||||
TimeSwitch &s = timeSwitches[i];
|
||||
if (!s.valid())
|
||||
timeSwitches.erase(timeSwitches.begin() + i--);
|
||||
}
|
||||
|
||||
if (!idleData.valid()) {
|
||||
idleData.idleEnable = false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < mediaSwitches.size(); i++) {
|
||||
MediaSwitch &s = mediaSwitches[i];
|
||||
if (!s.valid())
|
||||
mediaSwitches.erase(mediaSwitches.begin() + i--);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < audioSwitches.size(); i++) {
|
||||
AudioSwitch &s = audioSwitches[i];
|
||||
if (!s.valid())
|
||||
audioSwitches.erase(audioSwitches.begin() + i--);
|
||||
}
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
|
||||
void SceneSwitcher::on_timeSwitches_currentRowChanged(int idx)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
QListWidgetItem *item = ui->timeSwitches->item(idx);
|
||||
|
||||
QString timeScenestr = item->data(Qt::UserRole).toString();
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto &s : switcher->timeSwitches) {
|
||||
if (timeScenestr.compare(s.timeSwitchStr.c_str()) == 0) {
|
||||
QString sceneName = GetWeakSourceName(s.scene).c_str();
|
||||
QString transitionName =
|
||||
GetWeakSourceName(s.transition).c_str();
|
||||
ui->timeScenes->setCurrentText(sceneName);
|
||||
ui->timeEdit->setTime(s.time);
|
||||
ui->timeTransitions->setCurrentText(transitionName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int SceneSwitcher::timeFindByData(const QString &timeStr)
|
||||
{
|
||||
QRegExp rx("At " + timeStr + " switch to .*");
|
||||
int count = ui->timeSwitches->count();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
QListWidgetItem *item = ui->timeSwitches->item(i);
|
||||
QString str = item->data(Qt::UserRole).toString();
|
||||
|
||||
if (rx.exactMatch(str))
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_timeAdd_clicked()
|
||||
{
|
||||
QString sceneName = ui->timeScenes->currentText();
|
||||
QString transitionName = ui->timeTransitions->currentText();
|
||||
QTime time = ui->timeEdit->time();
|
||||
|
||||
if (sceneName.isEmpty())
|
||||
return;
|
||||
|
||||
OBSWeakSource source = GetWeakSourceByQString(sceneName);
|
||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
||||
|
||||
QString text = MakeTimeSwitchName(sceneName, transitionName, time);
|
||||
QVariant v = QVariant::fromValue(text);
|
||||
|
||||
int idx = timeFindByData(time.toString());
|
||||
|
||||
if (idx == -1) {
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->timeSwitches.emplace_back(
|
||||
source, transition, time,
|
||||
(sceneName == QString(PREVIOUS_SCENE_NAME)),
|
||||
text.toUtf8().constData());
|
||||
|
||||
QListWidgetItem *item =
|
||||
new QListWidgetItem(text, ui->timeSwitches);
|
||||
item->setData(Qt::UserRole, v);
|
||||
} else {
|
||||
QListWidgetItem *item = ui->timeSwitches->item(idx);
|
||||
item->setText(text);
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto &s : switcher->timeSwitches) {
|
||||
if (s.time == time) {
|
||||
s.scene = source;
|
||||
s.transition = transition;
|
||||
s.usePreviousScene =
|
||||
(sceneName ==
|
||||
QString(PREVIOUS_SCENE_NAME));
|
||||
s.timeSwitchStr =
|
||||
text.toUtf8().constData();
|
||||
;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui->timeSwitches->sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_timeRemove_clicked()
|
||||
{
|
||||
QListWidgetItem *item = ui->timeSwitches->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
string text = item->data(Qt::UserRole).toString().toUtf8().constData();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
auto &switches = switcher->timeSwitches;
|
||||
|
||||
for (auto it = switches.begin(); it != switches.end(); ++it) {
|
||||
auto &s = *it;
|
||||
|
||||
if (s.timeSwitchStr == text) {
|
||||
switches.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void SwitcherData::checkTimeSwitch(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition)
|
||||
{
|
||||
if (timeSwitches.size() == 0)
|
||||
return;
|
||||
|
||||
QTime now = QTime::currentTime();
|
||||
|
||||
for (TimeSwitch &s : timeSwitches) {
|
||||
|
||||
QTime validSwitchTimeWindow = s.time.addMSecs(interval);
|
||||
|
||||
match = s.time <= now && now <= validSwitchTimeWindow;
|
||||
if (!match &&
|
||||
validSwitchTimeWindow.msecsSinceStartOfDay() < interval) {
|
||||
// check for overflow
|
||||
match = now >= s.time || now <= validSwitchTimeWindow;
|
||||
}
|
||||
|
||||
if (match) {
|
||||
scene = (s.usePreviousScene) ? previousScene : s.scene;
|
||||
transition = s.transition;
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
1003
src/volume-control.cpp
Normal file
1003
src/volume-control.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -3,13 +3,16 @@
|
||||
#include "../headers/advanced-scene-switcher.hpp"
|
||||
#include <TlHelp32.h>
|
||||
#include <Psapi.h>
|
||||
#include <locale>
|
||||
#include <codecvt>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
#define MAX_SEARCH 1000
|
||||
|
||||
static bool GetWindowTitle(HWND window, string& title)
|
||||
static bool GetWindowTitle(HWND window, std::string &title)
|
||||
{
|
||||
size_t len = (size_t)GetWindowTextLengthW(window);
|
||||
wstring wtitle;
|
||||
std::wstring wtitle;
|
||||
|
||||
wtitle.resize(len);
|
||||
if (!GetWindowTextW(window, &wtitle[0], (int)len + 1))
|
||||
@@ -23,8 +26,7 @@ static bool GetWindowTitle(HWND window, string& title)
|
||||
|
||||
static bool WindowValid(HWND window)
|
||||
{
|
||||
LONG_PTR styles, ex_styles;
|
||||
RECT rect;
|
||||
LONG_PTR styles;
|
||||
DWORD id;
|
||||
|
||||
if (!IsWindowVisible(window))
|
||||
@@ -33,32 +35,63 @@ static bool WindowValid(HWND window)
|
||||
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<string>& windows)
|
||||
BOOL CALLBACK GetTitleCB(HWND hwnd, LPARAM lParam)
|
||||
{
|
||||
HWND window = GetWindow(GetDesktopWindow(), GW_CHILD);
|
||||
if (!WindowValid(hwnd)) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
while (window)
|
||||
{
|
||||
string title;
|
||||
if (WindowValid(window) && GetWindowTitle(window, title))
|
||||
windows.emplace_back(title);
|
||||
window = GetNextWindow(window, GW_HWNDNEXT);
|
||||
std::string title;
|
||||
GetWindowTitle(hwnd, title);
|
||||
if (title.empty())
|
||||
return TRUE;
|
||||
|
||||
std::vector<std::string> &titles =
|
||||
*reinterpret_cast<std::vector<std::string> *>(lParam);
|
||||
titles.push_back(title);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID EnumWindowsWithMetro(__in WNDENUMPROC lpEnumFunc, __in LPARAM lParam)
|
||||
{
|
||||
HWND childWindow = NULL;
|
||||
int i = 0;
|
||||
|
||||
while (i < MAX_SEARCH &&
|
||||
(childWindow = FindWindowEx(NULL, childWindow, NULL, NULL))) {
|
||||
if (!lpEnumFunc(childWindow, lParam))
|
||||
return;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void GetCurrentWindowTitle(string& title)
|
||||
void GetWindowList(std::vector<std::string> &windows)
|
||||
{
|
||||
windows.resize(0);
|
||||
EnumWindowsWithMetro(GetTitleCB, reinterpret_cast<LPARAM>(&windows));
|
||||
}
|
||||
|
||||
void GetWindowList(QStringList &windows)
|
||||
{
|
||||
windows.clear();
|
||||
|
||||
std::vector<std::string> w;
|
||||
GetWindowList(w);
|
||||
for (auto window : w) {
|
||||
windows << QString::fromStdString(window);
|
||||
}
|
||||
}
|
||||
|
||||
void GetCurrentWindowTitle(std::string &title)
|
||||
{
|
||||
HWND window = GetForegroundWindow();
|
||||
DWORD pid;
|
||||
@@ -75,43 +108,94 @@ void GetCurrentWindowTitle(string& title)
|
||||
GetWindowTitle(window, title);
|
||||
}
|
||||
|
||||
pair<int, int> getCursorPos()
|
||||
std::pair<int, int> getCursorPos()
|
||||
{
|
||||
pair<int, int> pos(0, 0);
|
||||
std::pair<int, int> pos(0, 0);
|
||||
POINT cursorPos;
|
||||
if (GetPhysicalCursorPos(&cursorPos))
|
||||
{
|
||||
if (GetPhysicalCursorPos(&cursorPos)) {
|
||||
pos.first = cursorPos.x;
|
||||
pos.second = cursorPos.y;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
bool isFullscreen()
|
||||
HWND getHWNDfromTitle(std::string title)
|
||||
{
|
||||
HWND hwnd = NULL;
|
||||
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||
std::wstring wTitle = converter.from_bytes(title);
|
||||
|
||||
hwnd = FindWindowEx(NULL, NULL, NULL, wTitle.c_str());
|
||||
return hwnd;
|
||||
}
|
||||
|
||||
bool isMaximized(std::string &title)
|
||||
{
|
||||
RECT appBounds;
|
||||
RECT rc;
|
||||
GetWindowRect(GetDesktopWindow(), &rc);
|
||||
HWND hwnd = GetForegroundWindow();
|
||||
if (hwnd != GetDesktopWindow() && hwnd != GetShellWindow())
|
||||
{
|
||||
MONITORINFO monitorInfo = {0};
|
||||
HWND hwnd = NULL;
|
||||
|
||||
hwnd = getHWNDfromTitle(title);
|
||||
if (!hwnd)
|
||||
return false;
|
||||
|
||||
monitorInfo.cbSize = sizeof(MONITORINFO);
|
||||
GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST),
|
||||
&monitorInfo);
|
||||
|
||||
if (hwnd && hwnd != GetDesktopWindow() && hwnd != GetShellWindow()) {
|
||||
if (IsZoomed(hwnd)) {
|
||||
return true;
|
||||
}
|
||||
GetWindowRect(hwnd, &appBounds);
|
||||
if (rc.bottom == appBounds.bottom && rc.top == appBounds.top && rc.left == appBounds.left
|
||||
&& rc.right == appBounds.right)
|
||||
{
|
||||
if (monitorInfo.rcMonitor.bottom == appBounds.bottom &&
|
||||
monitorInfo.rcMonitor.top == appBounds.top &&
|
||||
monitorInfo.rcMonitor.left == appBounds.left &&
|
||||
monitorInfo.rcMonitor.right == appBounds.right) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GetProcessList(QStringList &processes) {
|
||||
bool isFullscreen(std::string &title)
|
||||
{
|
||||
RECT appBounds;
|
||||
MONITORINFO monitorInfo = {0};
|
||||
|
||||
HWND hwnd = NULL;
|
||||
hwnd = getHWNDfromTitle(title);
|
||||
|
||||
if (!hwnd)
|
||||
return false;
|
||||
|
||||
monitorInfo.cbSize = sizeof(MONITORINFO);
|
||||
GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST),
|
||||
&monitorInfo);
|
||||
|
||||
if (hwnd && hwnd != GetDesktopWindow() && hwnd != GetShellWindow()) {
|
||||
GetWindowRect(hwnd, &appBounds);
|
||||
if (monitorInfo.rcMonitor.bottom == appBounds.bottom &&
|
||||
monitorInfo.rcMonitor.top == appBounds.top &&
|
||||
monitorInfo.rcMonitor.left == appBounds.left &&
|
||||
monitorInfo.rcMonitor.right == appBounds.right) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void GetProcessList(QStringList &processes)
|
||||
{
|
||||
|
||||
HANDLE procSnapshot;
|
||||
PROCESSENTRY32 procEntry;
|
||||
|
||||
procSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (procSnapshot == INVALID_HANDLE_VALUE) return;
|
||||
if (procSnapshot == INVALID_HANDLE_VALUE)
|
||||
return;
|
||||
|
||||
procEntry.dwSize = sizeof(PROCESSENTRY32);
|
||||
|
||||
@@ -122,30 +206,45 @@ void GetProcessList(QStringList &processes) {
|
||||
|
||||
do {
|
||||
QString tempexe = QString::fromWCharArray(procEntry.szExeFile);
|
||||
if (tempexe == "System") continue;
|
||||
if (tempexe == "[System Process]") continue;
|
||||
if (processes.contains(tempexe)) continue;
|
||||
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) {
|
||||
bool isInFocus(const QString &executable)
|
||||
{
|
||||
// only checks if the current foreground window is from the same executable,
|
||||
// may return true for incorrent not meant windows from a program
|
||||
// may return true for any window 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;
|
||||
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();
|
||||
QString file = QString::fromWCharArray(executablePath)
|
||||
.split(QRegularExpression("(/|\\\\)"))
|
||||
.back();
|
||||
|
||||
// True if executable switch equals current window
|
||||
bool equals = (executable == file);
|
||||
// True if executable switch matches current window
|
||||
bool matches = file.contains(QRegularExpression(executable));
|
||||
|
||||
return (equals || matches);
|
||||
}
|
||||
|
||||
int getLastInputTime()
|
||||
|
||||
@@ -1,280 +0,0 @@
|
||||
#include <obs-module.h>
|
||||
#include "headers/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<mutex> 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<mutex> 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<mutex> 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<QListWidgetItem*> 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<mutex> 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<mutex> 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<mutex> 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<mutex> 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&)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user