mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-09-07 09:05:57 -05:00
Compare commits
67 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a354daa71d | ||
|
|
a84a205608 | ||
|
|
a5f0eb8da8 | ||
|
|
35151ea134 | ||
|
|
1510a2c2fa | ||
|
|
8e8cb4bf3e | ||
|
|
a480be3ea0 | ||
|
|
27ae5107cd | ||
|
|
69d452f978 | ||
|
|
fe9457427f | ||
|
|
d989c2b570 | ||
|
|
1f4679433e | ||
|
|
b42de8d5c8 | ||
|
|
0950d93828 | ||
|
|
5156c66b26 | ||
|
|
346240473a | ||
|
|
17c4fefb37 | ||
|
|
2b90493ae9 | ||
|
|
bf97975fa8 | ||
|
|
4e971f59a9 | ||
|
|
2f0b900745 | ||
|
|
c6a25f9d85 | ||
|
|
e78383d3ed | ||
|
|
281e9325dd | ||
|
|
caa2833272 | ||
|
|
fae50024ea | ||
|
|
a05e38d3cb | ||
|
|
d73749fc3a | ||
|
|
d20cdac5e4 | ||
|
|
e377be3999 | ||
|
|
80e2b3dd14 | ||
|
|
3a05e61814 | ||
|
|
dda44a2931 | ||
|
|
8ba78b12c1 | ||
|
|
07b95cb8ae | ||
|
|
faca5f8863 | ||
|
|
084c263260 | ||
|
|
a1c592f1ec | ||
|
|
41f34f8f40 | ||
|
|
9711390aac | ||
|
|
25f28b9796 | ||
|
|
a1484f9621 | ||
|
|
b54506c5ee | ||
|
|
4af7540497 | ||
|
|
ba15e6812f | ||
|
|
22a90c7d64 | ||
|
|
f6c3c65e26 | ||
|
|
4f6275619a | ||
|
|
d461342835 | ||
|
|
16c4a2d5a9 | ||
|
|
45a880d8f8 | ||
|
|
bcf132685b | ||
|
|
e5c1e81d81 | ||
|
|
2ae97cd90e | ||
|
|
e5fffa0b82 | ||
|
|
a0119426d6 | ||
|
|
45e5738d2c | ||
|
|
cdd1259f12 | ||
|
|
e5d6f2eef0 | ||
|
|
e026bd7420 | ||
|
|
4cc1a53244 | ||
|
|
8eb99a3fde | ||
|
|
bf30a058ee | ||
|
|
0c6a7b140e | ||
|
|
d279b35086 | ||
|
|
8e26148255 | ||
|
|
1a3ed0d09c |
174
.github/workflows/build.yml
vendored
174
.github/workflows/build.yml
vendored
@@ -15,16 +15,16 @@ jobs:
|
|||||||
name: "macOS 64-bit"
|
name: "macOS 64-bit"
|
||||||
runs-on: [macos-latest]
|
runs-on: [macos-latest]
|
||||||
env:
|
env:
|
||||||
QT_VERSION: 5.14.1
|
QT_VERSION: '5.15.2'
|
||||||
MACOS_DEPS_VERSION: '2020-08-30'
|
MACOS_DEPS_VERSION: '2020-12-11'
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2.3.4
|
||||||
with:
|
with:
|
||||||
repository: obsproject/obs-studio
|
repository: obsproject/obs-studio
|
||||||
submodules: 'recursive'
|
submodules: 'recursive'
|
||||||
- name: "Checkout plugin"
|
- name: "Checkout plugin"
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2.3.4
|
||||||
with:
|
with:
|
||||||
path: UI/frontend-plugins/${{ env.PLUGIN_NAME }}
|
path: UI/frontend-plugins/${{ env.PLUGIN_NAME }}
|
||||||
- name: Fetch Git Tags
|
- name: Fetch Git Tags
|
||||||
@@ -34,12 +34,15 @@ jobs:
|
|||||||
- name: 'Install prerequisites (Homebrew)'
|
- name: 'Install prerequisites (Homebrew)'
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
cd UI/frontend-plugins/${{ env.PLUGIN_NAME }}/CI/macos
|
if [ -d /usr/local/opt/openssl@1.0.2t ]; then
|
||||||
brew untap local/openssl
|
brew uninstall openssl@1.0.2t
|
||||||
brew untap local/python2
|
brew untap local/openssl
|
||||||
brew update
|
fi
|
||||||
brew bundle
|
if [ -d /usr/local/opt/python@2.7.17 ]; then
|
||||||
cd -
|
brew uninstall python@2.7.17
|
||||||
|
brew untap local/python2
|
||||||
|
fi
|
||||||
|
brew bundle --file ./CI/scripts/macos/Brewfile
|
||||||
- name: 'Install prerequisite: Pre-built dependencies'
|
- name: 'Install prerequisite: Pre-built dependencies'
|
||||||
if: steps.deps-cache.outputs.cache-hit != 'true'
|
if: steps.deps-cache.outputs.cache-hit != 'true'
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -59,7 +62,7 @@ jobs:
|
|||||||
echo "add_subdirectory(${{ env.PLUGIN_NAME }})" >> UI/frontend-plugins/CMakeLists.txt
|
echo "add_subdirectory(${{ env.PLUGIN_NAME }})" >> UI/frontend-plugins/CMakeLists.txt
|
||||||
mkdir ./build
|
mkdir ./build
|
||||||
cd ./build
|
cd ./build
|
||||||
cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.11 -DDISABLE_PYTHON=ON -DDepsPath="/tmp/obsdeps" -DQTDIR="/tmp/obsdeps" ..
|
cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 -DDISABLE_PYTHON=ON -DDepsPath="/tmp/obsdeps" -DQTDIR="/tmp/obsdeps" ..
|
||||||
cd -
|
cd -
|
||||||
- name: Build
|
- name: Build
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -86,14 +89,14 @@ jobs:
|
|||||||
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
|
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_DATE=$(date +%Y-%m-%d)
|
||||||
FILE_NAME=${{ env.PLUGIN_NAME }}-$FILE_DATE-${{ github.sha }}-macos.pkg
|
FILE_NAME=${{ env.PLUGIN_NAME }}-$FILE_DATE-${{ github.sha }}-macos.pkg
|
||||||
echo "::set-env name=FILE_NAME::${FILE_NAME}"
|
echo "FILE_NAME=${FILE_NAME}" >> $GITHUB_ENV
|
||||||
packagesbuild ./CI/macos/${{ env.PLUGIN_NAME }}.pkgproj
|
packagesbuild ./CI/macos/${{ env.PLUGIN_NAME }}.pkgproj
|
||||||
cd -
|
cd -
|
||||||
mkdir ./nightly
|
mkdir ./nightly
|
||||||
mv UI/frontend-plugins/${{ env.PLUGIN_NAME }}/${{ env.PLUGIN_NAME }}.pkg ./nightly/${FILE_NAME}
|
mv UI/frontend-plugins/${{ env.PLUGIN_NAME }}/${{ env.PLUGIN_NAME }}.pkg ./nightly/${FILE_NAME}
|
||||||
- name: Publish
|
- name: Publish
|
||||||
if: success()
|
if: success()
|
||||||
uses: actions/upload-artifact@v2-preview
|
uses: actions/upload-artifact@v2.2.1
|
||||||
with:
|
with:
|
||||||
name: '${{ env.FILE_NAME }}'
|
name: '${{ env.FILE_NAME }}'
|
||||||
path: ./nightly/*.pkg
|
path: ./nightly/*.pkg
|
||||||
@@ -102,12 +105,12 @@ jobs:
|
|||||||
runs-on: [ubuntu-latest]
|
runs-on: [ubuntu-latest]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2.3.4
|
||||||
with:
|
with:
|
||||||
repository: obsproject/obs-studio
|
repository: obsproject/obs-studio
|
||||||
submodules: 'recursive'
|
submodules: 'recursive'
|
||||||
- name: "Checkout plugin"
|
- name: "Checkout plugin"
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2.3.4
|
||||||
with:
|
with:
|
||||||
path: UI/frontend-plugins/${{ env.PLUGIN_NAME }}
|
path: UI/frontend-plugins/${{ env.PLUGIN_NAME }}
|
||||||
- name: Add plugin to obs cmake
|
- name: Add plugin to obs cmake
|
||||||
@@ -166,7 +169,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
mkdir ./build
|
mkdir ./build
|
||||||
cd ./build
|
cd ./build
|
||||||
cmake -DUNIX_STRUCTURE=0 -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}/obs-studio-portable" -DBUILD_CAPTIONS=OFF -DWITH_RTMPS=OFF -DBUILD_BROWSER=OFF ..
|
cmake -DUNIX_STRUCTURE=0 -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}/obs-studio-portable" -DWITH_RTMPS=OFF -DBUILD_BROWSER=OFF ..
|
||||||
- name: 'Build'
|
- name: 'Build'
|
||||||
shell: bash
|
shell: bash
|
||||||
working-directory: ${{ github.workspace }}/build
|
working-directory: ${{ github.workspace }}/build
|
||||||
@@ -176,32 +179,34 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
FILE_DATE=$(date +%Y-%m-%d)
|
FILE_DATE=$(date +%Y-%m-%d)
|
||||||
FILE_NAME=${{ env.PLUGIN_NAME }}-$FILE_DATE-${{ github.sha }}-linux64.tar.gz
|
FILE_NAME=${{ env.PLUGIN_NAME }}-$FILE_DATE-${{ github.sha }}-linux64.tar.gz
|
||||||
echo "::set-env name=FILE_NAME::${FILE_NAME}"
|
echo "FILE_NAME=${FILE_NAME}" >> $GITHUB_ENV
|
||||||
mkdir -p ./${{ env.PLUGIN_NAME }}/bin/64bit/
|
mkdir -p ./${{ env.LIB_NAME }}/bin/64bit/
|
||||||
mv ./build/UI/frontend-plugins/${{ env.PLUGIN_NAME }}/${{ env.LIB_NAME }}.so ./${{ env.PLUGIN_NAME }}/bin/64bit/${{ env.LIB_NAME }}.so
|
mv ./build/UI/frontend-plugins/${{ env.PLUGIN_NAME }}/${{ env.LIB_NAME }}.so ./${{ env.LIB_NAME }}/bin/64bit/${{ env.LIB_NAME }}.so
|
||||||
tar -cvzf "${FILE_NAME}" ${{ env.PLUGIN_NAME }}
|
mv ./UI/frontend-plugins/${{ env.PLUGIN_NAME }}/data ./${{ env.LIB_NAME }}/data
|
||||||
|
tar -cvzf "${FILE_NAME}" ${{ env.LIB_NAME }}
|
||||||
- name: 'Publish'
|
- name: 'Publish'
|
||||||
uses: actions/upload-artifact@v2-preview
|
uses: actions/upload-artifact@v2.2.1
|
||||||
with:
|
with:
|
||||||
name: '${{ env.FILE_NAME }}'
|
name: '${{ env.FILE_NAME }}'
|
||||||
path: '*.tar.gz'
|
path: '*.tar.gz'
|
||||||
win64:
|
windows:
|
||||||
name: Windows 64-bit
|
name: Windows
|
||||||
runs-on: [windows-latest]
|
runs-on: [windows-latest]
|
||||||
env:
|
env:
|
||||||
QT_VERSION: 5.10.1
|
QT_VERSION: 5.10.1
|
||||||
CMAKE_GENERATOR: "Visual Studio 16 2019"
|
CMAKE_GENERATOR: "Visual Studio 16 2019"
|
||||||
CMAKE_SYSTEM_VERSION: "10.0.18363.657"
|
CMAKE_SYSTEM_VERSION: "10.0.18363.657"
|
||||||
|
WINDOWS_DEPS_VERSION: '2017'
|
||||||
steps:
|
steps:
|
||||||
- name: Add msbuild to PATH
|
- name: Add msbuild to PATH
|
||||||
uses: microsoft/setup-msbuild@v1.0.0
|
uses: microsoft/setup-msbuild@v1.0.2
|
||||||
- name: Checkout obs
|
- name: Checkout obs
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2.3.4
|
||||||
with:
|
with:
|
||||||
repository: obsproject/obs-studio
|
repository: obsproject/obs-studio
|
||||||
submodules: 'recursive'
|
submodules: 'recursive'
|
||||||
- name: Checkout plugin
|
- name: Checkout plugin
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2.3.4
|
||||||
with:
|
with:
|
||||||
path: UI/frontend-plugins/${{ env.PLUGIN_NAME}}
|
path: UI/frontend-plugins/${{ env.PLUGIN_NAME}}
|
||||||
- name: Add plugin to obs cmake
|
- name: Add plugin to obs cmake
|
||||||
@@ -215,81 +220,82 @@ jobs:
|
|||||||
7z x Qt_${{ env.QT_VERSION }}.7z -o"${{ github.workspace }}/cmbuild/QT"
|
7z x Qt_${{ env.QT_VERSION }}.7z -o"${{ github.workspace }}/cmbuild/QT"
|
||||||
- name: 'Install prerequisite: Pre-built dependencies'
|
- name: 'Install prerequisite: Pre-built dependencies'
|
||||||
run: |
|
run: |
|
||||||
curl -kLO https://cdn-fastly.obsproject.com/downloads/dependencies2017.zip -f --retry 5 -C -
|
curl -kLO https://cdn-fastly.obsproject.com/downloads/dependencies${{ env.WINDOWS_DEPS_VERSION }}.zip -f --retry 5 -C -
|
||||||
7z x dependencies2017.zip -o"${{ github.workspace }}/cmbuild/deps"
|
7z x dependencies${{ env.WINDOWS_DEPS_VERSION }}.zip -o"${{ github.workspace }}/cmbuild/deps"
|
||||||
- name: Configure
|
- name: Configure
|
||||||
run: |
|
run: |
|
||||||
mkdir ./build
|
mkdir ./package
|
||||||
|
mkdir ./build32
|
||||||
|
cd ./build32
|
||||||
|
cmake -G"${{ env.CMAKE_GENERATOR }}" -A"Win32" -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DBUILD_BROWSER=false -DBUILD_CAPTIONS=false -DCOMPILE_D3D12_HOOK=false -DDepsPath="${{ github.workspace }}/cmbuild/deps/win32" -DQTDIR="${{ github.workspace }}/cmbuild/QT/${{ env.QT_VERSION }}/msvc2017" -DCOPIED_DEPENDENCIES=FALSE -DCOPY_DEPENDENCIES=TRUE ..
|
||||||
|
cd ..
|
||||||
mkdir ./build64
|
mkdir ./build64
|
||||||
cd ./build64
|
cd ./build64
|
||||||
cmake -G"${{ env.CMAKE_GENERATOR }}" -A"x64" -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DBUILD_BROWSER=false -DBUILD_CAPTIONS=false -DCOMPILE_D3D12_HOOK=false -DDepsPath="${{ github.workspace }}/cmbuild/deps/win64" -DQTDIR="${{ github.workspace }}/cmbuild/QT/${{ env.QT_VERSION }}/msvc2017_64" -DCOPIED_DEPENDENCIES=FALSE -DCOPY_DEPENDENCIES=TRUE ..
|
cmake -G"${{ env.CMAKE_GENERATOR }}" -A"x64" -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DBUILD_BROWSER=false -DBUILD_CAPTIONS=false -DCOMPILE_D3D12_HOOK=false -DDepsPath="${{ github.workspace }}/cmbuild/deps/win64" -DQTDIR="${{ github.workspace }}/cmbuild/QT/${{ env.QT_VERSION }}/msvc2017_64" -DCOPIED_DEPENDENCIES=FALSE -DCOPY_DEPENDENCIES=TRUE ..
|
||||||
- name: Build
|
- name: Build
|
||||||
run: msbuild /m /p:Configuration=RelWithDebInfo .\build64\obs-studio.sln
|
run: |
|
||||||
|
msbuild /m /p:Configuration=RelWithDebInfo .\build32\obs-studio.sln
|
||||||
|
msbuild /m /p:Configuration=RelWithDebInfo .\build64\obs-studio.sln
|
||||||
- name: Package
|
- name: Package
|
||||||
if: success()
|
if: success()
|
||||||
run: |
|
run: |
|
||||||
$env:FILE_DATE=(Get-Date -UFormat "%F")
|
$env:FILE_DATE=(Get-Date -UFormat "%F")
|
||||||
$env:FILE_NAME="${{ env.PLUGIN_NAME }}-${env:FILE_DATE}-${{ github.sha }}-win64.zip"
|
$env:FILE_NAME="${{ env.PLUGIN_NAME }}-${env:FILE_DATE}-${{ github.sha }}-windows"
|
||||||
echo "::set-env name=FILE_NAME::${env:FILE_NAME}"
|
echo "FILE_NAME=${env:FILE_NAME}" >> ${env:GITHUB_ENV}
|
||||||
robocopy .\build64\rundir\RelWithDebInfo\obs-plugins\64bit\ .\build\obs-plugins\64bit ${{ env.LIB_NAME }}.* /E /XF .gitignore
|
robocopy .\build32\rundir\RelWithDebInfo\obs-plugins\32bit\ .\package\obs-plugins\32bit ${{ env.LIB_NAME }}.* /E /XF .gitignore
|
||||||
7z a ${env:FILE_NAME} .\build\*
|
robocopy .\build64\rundir\RelWithDebInfo\obs-plugins\64bit\ .\package\obs-plugins\64bit ${{ env.LIB_NAME }}.* /E /XF .gitignore
|
||||||
- name: Publish
|
robocopy .\build64\rundir\RelWithDebInfo\data\obs-plugins\${{ env.LIB_NAME }}\ .\package\data\obs-plugins\${{ env.LIB_NAME }}\ /E /XF .gitignore
|
||||||
|
exit 0
|
||||||
|
- name: Publish zip
|
||||||
if: success()
|
if: success()
|
||||||
uses: actions/upload-artifact@v2-preview
|
uses: actions/upload-artifact@v2.2.1
|
||||||
with:
|
with:
|
||||||
name: '${{ env.FILE_NAME }}'
|
name: '${{ env.FILE_NAME }}'
|
||||||
path: '*-win64.zip'
|
path: package/*
|
||||||
win32:
|
- name: "Package Installer (Prereqs)"
|
||||||
name: Windows 32-bit
|
run: |
|
||||||
runs-on: [windows-latest]
|
curl "-kL" "https://github.com/Xaymar/msvc-redist-helper/releases/download/0.1/msvc-redist-helper-64.exe" "-f" "--retry" "5" "-o" "msvc-redist-helper-64.exe"
|
||||||
env:
|
curl "-kL" "https://github.com/Xaymar/msvc-redist-helper/releases/download/0.1/msvc-redist-helper-32.exe" "-f" "--retry" "5" "-o" "msvc-redist-helper-32.exe"
|
||||||
QT_VERSION: 5.10.1
|
curl "-kL" "https://files.jrsoftware.org/is/6/innosetup-6.0.3.exe" "-f" "--retry" "5" "-o" "inno.exe"
|
||||||
CMAKE_GENERATOR: "Visual Studio 16 2019"
|
.\inno.exe /VERYSILENT /SP- /SUPPRESSMSGBOXES /NORESTART
|
||||||
CMAKE_SYSTEM_VERSION: "10.0.18363.657"
|
- name: "Package Installer (Compile)"
|
||||||
|
run: |
|
||||||
|
& 'C:\Program Files (x86)\Inno Setup 6\ISCC.exe' /Qp ".\build64\UI\frontend-plugins\${{ env.PLUGIN_NAME }}\CI\windows\setup.iss"
|
||||||
|
- name: Publish installer
|
||||||
|
if: success()
|
||||||
|
uses: actions/upload-artifact@v2.2.0
|
||||||
|
with:
|
||||||
|
name: '${{ env.FILE_NAME }}-installer'
|
||||||
|
path: build64/UI/frontend-plugins/SceneSwitcher/CI/windows/Output/*.exe
|
||||||
|
release:
|
||||||
|
needs: [macos64, ubuntu64, windows]
|
||||||
|
name: 'Create Release'
|
||||||
|
runs-on: [ubuntu-latest]
|
||||||
steps:
|
steps:
|
||||||
- name: Add msbuild to PATH
|
- name: "Checkout plugin"
|
||||||
uses: microsoft/setup-msbuild@v1.0.0
|
uses: actions/checkout@v2.3.4
|
||||||
- name: Checkout obs
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
with:
|
with:
|
||||||
repository: obsproject/obs-studio
|
path: plugin/${{ env.PLUGIN_NAME }}
|
||||||
submodules: 'recursive'
|
- name: Download artifacts
|
||||||
- name: Checkout plugin
|
uses: actions/download-artifact@v2
|
||||||
uses: actions/checkout@v2
|
|
||||||
with:
|
with:
|
||||||
path: UI/frontend-plugins/${{ env.PLUGIN_NAME }}
|
path: artifacts
|
||||||
- name: Add plugin to obs cmake
|
- name: 'Package'
|
||||||
shell: cmd
|
shell: bash
|
||||||
run: echo add_subdirectory(${{ env.PLUGIN_NAME }}) >> UI/frontend-plugins/CMakeLists.txt
|
|
||||||
- name: Fetch Git Tags
|
|
||||||
run: git fetch --prune --tags --unshallow
|
|
||||||
- name: 'Install prerequisite: QT'
|
|
||||||
run: |
|
run: |
|
||||||
curl -kLO https://cdn-fastly.obsproject.com/downloads/Qt_${{ env.QT_VERSION }}.7z -f --retry 5 -C -
|
mkdir -p ${{ env.PLUGIN_NAME }}/Linux ${{ env.PLUGIN_NAME }}/MacOs ${{ env.PLUGIN_NAME }}/Windows
|
||||||
7z x Qt_${{ env.QT_VERSION }}.7z -o"${{ github.workspace }}/cmbuild/QT"
|
tar xf artifacts/${{ env.PLUGIN_NAME }}*-linux64.tar.gz/${{ env.PLUGIN_NAME }}*-linux64.tar.gz -C ${{ env.PLUGIN_NAME }}/Linux/
|
||||||
- name: 'Install prerequisite: Pre-built dependencies'
|
mv artifacts/${{ env.PLUGIN_NAME }}*-macos.pkg/${{ env.PLUGIN_NAME }}*-macos.pkg ${{ env.PLUGIN_NAME }}/MacOs/${{ env.PLUGIN_NAME }}.pkg
|
||||||
run: |
|
mv ./artifacts/${{ env.PLUGIN_NAME }}*-windows/* ${{ env.PLUGIN_NAME }}/Windows/
|
||||||
curl -kLO https://cdn-fastly.obsproject.com/downloads/dependencies2017.zip -f --retry 5 -C -
|
mv ./artifacts/${{ env.PLUGIN_NAME }}*-windows-installer/*.exe ${{ env.PLUGIN_NAME }}/Windows/
|
||||||
7z x dependencies2017.zip -o"${{ github.workspace }}/cmbuild/deps"
|
rm ${{ env.PLUGIN_NAME }}/Windows/obs-plugins/32bit/advanced-scene-switcher.pdb
|
||||||
- name: Configure
|
rm ${{ env.PLUGIN_NAME }}/Windows/obs-plugins/64bit/advanced-scene-switcher.pdb
|
||||||
run: |
|
cp plugin/${{ env.PLUGIN_NAME }}/CI/release/README.txt ${{ env.PLUGIN_NAME }}/
|
||||||
mkdir ./build
|
FILE_NAME=${{ env.PLUGIN_NAME }}.zip
|
||||||
mkdir ./build32
|
zip -r ${FILE_NAME} ${{ env.PLUGIN_NAME }}/
|
||||||
cd ./build32
|
|
||||||
cmake -G"${{ env.CMAKE_GENERATOR }}" -A"Win32" -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DBUILD_BROWSER=false -DBUILD_CAPTIONS=false -DCOMPILE_D3D12_HOOK=false -DDepsPath="${{ github.workspace }}/cmbuild/deps/win32" -DQTDIR="${{ github.workspace }}/cmbuild/QT/${{ env.QT_VERSION }}/msvc2017" -DCOPIED_DEPENDENCIES=FALSE -DCOPY_DEPENDENCIES=TRUE ..
|
|
||||||
- name: Build
|
|
||||||
run: msbuild /m /p:Configuration=RelWithDebInfo .\build32\obs-studio.sln
|
|
||||||
- name: Package
|
|
||||||
if: success()
|
|
||||||
run: |
|
|
||||||
$env:FILE_DATE=(Get-Date -UFormat "%F")
|
|
||||||
$env:FILE_NAME="${{ env.PLUGIN_NAME }}-${env:FILE_DATE}-${{ github.sha }}-win32.zip"
|
|
||||||
echo "::set-env name=FILE_NAME::${env:FILE_NAME}"
|
|
||||||
robocopy .\build32\rundir\RelWithDebInfo\obs-plugins\32bit\ .\build\obs-plugins\32bit ${{ env.LIB_NAME }}.* /E /XF .gitignore
|
|
||||||
7z a ${env:FILE_NAME} .\build\*
|
|
||||||
- name: Publish
|
- name: Publish
|
||||||
if: success()
|
if: success()
|
||||||
uses: actions/upload-artifact@v2-preview
|
uses: actions/upload-artifact@v2.2.1
|
||||||
with:
|
with:
|
||||||
name: '${{ env.FILE_NAME }}'
|
name: "Release"
|
||||||
path: '*-win32.zip'
|
path: '*.zip'
|
||||||
|
|||||||
32
.github/workflows/clang-format.yml
vendored
Normal file
32
.github/workflows/clang-format.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
name: Clang Format Check
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
ubuntu64:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: 'recursive'
|
||||||
|
|
||||||
|
- name: Install clang format
|
||||||
|
run: |
|
||||||
|
# gets us newer clang
|
||||||
|
sudo bash -c "cat >> /etc/apt/sources.list" << LLVMAPT
|
||||||
|
# 3.8
|
||||||
|
deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main
|
||||||
|
deb-src http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main
|
||||||
|
LLVMAPT
|
||||||
|
|
||||||
|
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add -
|
||||||
|
|
||||||
|
sudo apt-get -qq update
|
||||||
|
|
||||||
|
sudo apt-get install -y clang-format-8
|
||||||
|
|
||||||
|
- name: Check the Formatting
|
||||||
|
run: |
|
||||||
|
./CI/formatcode.sh
|
||||||
|
./CI/check-format.sh
|
||||||
11
CI/check-format.sh
Executable file
11
CI/check-format.sh
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
dirty=$(git ls-files --modified)
|
||||||
|
|
||||||
|
set +x
|
||||||
|
if [[ $dirty ]]; then
|
||||||
|
echo "================================="
|
||||||
|
echo "Files were not formatted properly"
|
||||||
|
echo "$dirty"
|
||||||
|
echo "================================="
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
31
CI/formatcode.sh
Executable file
31
CI/formatcode.sh
Executable file
@@ -0,0 +1,31 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Original source https://github.com/Project-OSRM/osrm-backend/blob/master/scripts/format.sh
|
||||||
|
|
||||||
|
set +x
|
||||||
|
set -o errexit
|
||||||
|
set -o pipefail
|
||||||
|
set -o nounset
|
||||||
|
|
||||||
|
# Runs the Clang Formatter in parallel on the code base.
|
||||||
|
# Return codes:
|
||||||
|
# - 1 there are files to be formatted
|
||||||
|
# - 0 everything looks fine
|
||||||
|
|
||||||
|
# Get CPU count
|
||||||
|
OS=$(uname)
|
||||||
|
NPROC=1
|
||||||
|
if [[ $OS = "Linux" || $OS = "Darwin" ]] ; then
|
||||||
|
NPROC=$(getconf _NPROCESSORS_ONLN)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Discover clang-format
|
||||||
|
if type clang-format-8 2> /dev/null ; then
|
||||||
|
CLANG_FORMAT=clang-format-8
|
||||||
|
else
|
||||||
|
CLANG_FORMAT=clang-format
|
||||||
|
fi
|
||||||
|
|
||||||
|
find .. -type d \( -path ./deps \
|
||||||
|
-o -path ./cmake \
|
||||||
|
-o -path ./build \) -prune -type f -o -name '*.h' -or -name '*.hpp' -or -name '*.m' -or -name '*.mm' -or -name '*.c' -or -name '*.cpp' \
|
||||||
|
| xargs -L100 -P${NPROC} ${CLANG_FORMAT} -i -style=file -fallback-style=none
|
||||||
@@ -60,6 +60,22 @@
|
|||||||
<key>UID</key>
|
<key>UID</key>
|
||||||
<integer>0</integer>
|
<integer>0</integer>
|
||||||
</dict>
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array/>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>80</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>../../data</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>493</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>3</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
<key>GID</key>
|
<key>GID</key>
|
||||||
<integer>80</integer>
|
<integer>80</integer>
|
||||||
|
|||||||
38
CI/release/README.txt
Normal file
38
CI/release/README.txt
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
Note that you will have to use OBS version 26.1 or newer!
|
||||||
|
|
||||||
|
--- Windows ---
|
||||||
|
Recommended: Run the provided installer. (You might have to click 'More info' and select 'Run anyway' if it is blocked by Windows)
|
||||||
|
|
||||||
|
Alternatively manually copy the 'obs-plugins' and 'data' folders in the respective OBS Studio installation directory.
|
||||||
|
It is usually located at 'C:\Program Files (x86)\obs-studio\'.
|
||||||
|
Remember to install the Visual C++ Redistributable for Visual Studio 2019, if you have not done so already. (See plugin overview page)
|
||||||
|
|
||||||
|
--- macOS ---
|
||||||
|
Recommended: Run the provided installer. (You might have to right-click or control-click and select 'open' if it is blocked)
|
||||||
|
|
||||||
|
Alternatively extract the *so file and data folder and either ...
|
||||||
|
|
||||||
|
... right-click the OBS app inside your Applications folder and choose 'Show Package Contents'.
|
||||||
|
Copy the advanced-scene-switcher.so file to 'Contents/Plugins' and the 'data' folder to 'Contents/Resources'.
|
||||||
|
|
||||||
|
... or copy the advanced-scene-switcher.so file to Library/Application Support/obs-studio/plugins/advanced-scene-switcher/bin/ .
|
||||||
|
And the 'data' folder to 'Library/Application Support/obs-studio/plugins/advanced-scene-switcher/'.
|
||||||
|
|
||||||
|
--- Linux ---
|
||||||
|
Copy the advanced-scene-switcher.so file and into the OBS Studio plugin folder.
|
||||||
|
The location of this folder can vary, so you might have to look around a bit.
|
||||||
|
|
||||||
|
Examples are ...
|
||||||
|
/usr/lib/obs-plugins/
|
||||||
|
/usr/lib/x86_64-linux-gnu/obs-plugins/
|
||||||
|
/usr/share/obs/obs-plugins/
|
||||||
|
~/.config/obs-studio/plugins/advanced-scene-switcher/bin/64bit/
|
||||||
|
|
||||||
|
Unfortunately the expected location of the locale, which can be found in the data folder, can vary also.
|
||||||
|
The data folder usually should be copied to:
|
||||||
|
~/.config/obs-studio/plugins/advanced-scene-switcher/
|
||||||
|
|
||||||
|
If this does not work you can try to copy the "locale" folder found inside the data folder to:
|
||||||
|
/usr/share/obs/obs-plugins/advanced-scene-switcher/locale
|
||||||
|
|
||||||
|
In doubt please check where other "en-US.ini" files are located on your system.
|
||||||
64
CI/windows/setup.iss.in
Normal file
64
CI/windows/setup.iss.in
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
; Script generated by the Inno Setup Script Wizard.
|
||||||
|
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
|
||||||
|
|
||||||
|
#define MyAppName "Advanced Scene Switcher"
|
||||||
|
#define MyAppVersion "@GIT_SHA1@"
|
||||||
|
#define MyAppURL "https://github.com/WarmUpTill/SceneSwitcher"
|
||||||
|
|
||||||
|
[Setup]
|
||||||
|
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
|
||||||
|
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
|
||||||
|
AppId={{A4ADDF26-4426-4D2E-B26A-C7C878DA8FC9}
|
||||||
|
AppName={#MyAppName}
|
||||||
|
AppVersion={#MyAppVersion}
|
||||||
|
AppPublisherURL={#MyAppURL}
|
||||||
|
AppSupportURL={#MyAppURL}
|
||||||
|
AppUpdatesURL={#MyAppURL}
|
||||||
|
DefaultDirName={code:GetDirName}
|
||||||
|
DefaultGroupName={#MyAppName}
|
||||||
|
AllowNoIcons=yes
|
||||||
|
; Uncomment the following line to run in non administrative install mode (install for current user only.)
|
||||||
|
;PrivilegesRequired=lowest
|
||||||
|
OutputBaseFilename=AdvancedSceneSwitcherSetup
|
||||||
|
Compression=lzma
|
||||||
|
SolidCompression=yes
|
||||||
|
WizardStyle=modern
|
||||||
|
ArchitecturesInstallIn64BitMode=x64
|
||||||
|
|
||||||
|
[Languages]
|
||||||
|
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||||
|
|
||||||
|
[Files]
|
||||||
|
Source: "@ISS_MSVC_REDIST_HELPER_DIR@\msvc-redist-helper-64.exe"; DestDir: "{app}"; DestName: "msvc-redist-helper.exe"; Flags: ignoreversion dontcopy; Check: Is64BitInstallMode
|
||||||
|
Source: "@ISS_MSVC_REDIST_HELPER_DIR@\msvc-redist-helper-32.exe"; DestDir: "{app}"; DestName: "msvc-redist-helper.exe"; Flags: ignoreversion dontcopy; Check: not Is64BitInstallMode
|
||||||
|
Source: "@ISS_PLUGIN_FILES_DIR@\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||||
|
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
|
||||||
|
|
||||||
|
[Icons]
|
||||||
|
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
|
||||||
|
|
||||||
|
[Code]
|
||||||
|
// credit where it's due:
|
||||||
|
// following function comes from https://github.com/Xaymar/obs-studio_amf-encoder-plugin/blob/master/%23Resources/Installer.in.iss#L45
|
||||||
|
function GetDirName(Value: string): string;
|
||||||
|
var
|
||||||
|
InstallPath: string;
|
||||||
|
begin
|
||||||
|
// initialize default path, which will be returned when the following registry
|
||||||
|
// key queries fail due to missing keys or for some different reason
|
||||||
|
Result := ExpandConstant('{pf}\obs-studio');
|
||||||
|
// query the first registry value; if this succeeds, return the obtained value
|
||||||
|
if RegQueryStringValue(HKLM32, 'SOFTWARE\OBS Studio', '', InstallPath) then
|
||||||
|
Result := InstallPath
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure CurStepChanged(CurStep: TSetupStep);
|
||||||
|
var
|
||||||
|
ResultCode: Integer;
|
||||||
|
begin
|
||||||
|
if (CurStep=ssPostInstall) then
|
||||||
|
begin
|
||||||
|
ExtractTemporaryFile('msvc-redist-helper.exe');
|
||||||
|
Exec(ExpandConstant('{tmp}\msvc-redist-helper.exe'), '2019', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
289
CMakeLists.txt
289
CMakeLists.txt
@@ -2,9 +2,21 @@ cmake_minimum_required(VERSION 3.5)
|
|||||||
|
|
||||||
project(advanced-scene-switcher)
|
project(advanced-scene-switcher)
|
||||||
|
|
||||||
|
# generate version info
|
||||||
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
|
||||||
|
include(GetGitRevisionDescription)
|
||||||
|
get_git_head_revision(GIT_REFSPEC GIT_SHA1)
|
||||||
|
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/src/version.cpp" @ONLY)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
get_filename_component(ISS_PLUGIN_FILES_DIR "${CMAKE_BINARY_DIR}\\..\\package" ABSOLUTE)
|
||||||
|
file(TO_NATIVE_PATH "${ISS_PLUGIN_FILES_DIR}" ISS_PLUGIN_FILES_DIR)
|
||||||
|
get_filename_component(ISS_MSVC_REDIST_HELPER_DIR "${CMAKE_PACKAGE_PREFIX}\\.." ABSOLUTE)
|
||||||
|
file(TO_NATIVE_PATH "${ISS_MSVC_REDIST_HELPER_DIR}" ISS_MSVC_REDIST_HELPER_DIR)
|
||||||
|
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/CI/windows/setup.iss.in" "${CMAKE_CURRENT_BINARY_DIR}/CI/windows/setup.iss" @ONLY)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(BUILD_OUT_OF_TREE)
|
if(BUILD_OUT_OF_TREE)
|
||||||
# out of tree builds
|
|
||||||
# credits to c3r1c3
|
|
||||||
set(CMAKE_PREFIX_PATH "${QTDIR}")
|
set(CMAKE_PREFIX_PATH "${QTDIR}")
|
||||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/external")
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/external")
|
||||||
@@ -16,101 +28,111 @@ if(BUILD_OUT_OF_TREE)
|
|||||||
find_package(Libcurl REQUIRED)
|
find_package(Libcurl REQUIRED)
|
||||||
find_path(LIBOBS_FRONTEND_INCLUDE_DIR HINTS ${LIBOBS_INCLUDE_DIRS})
|
find_path(LIBOBS_FRONTEND_INCLUDE_DIR HINTS ${LIBOBS_INCLUDE_DIRS})
|
||||||
find_file(LIBOBS_FRONTEND_API_LIB NAMES libobs-frontend-api.* HINTS ${LIBOBS_LIB} )
|
find_file(LIBOBS_FRONTEND_API_LIB NAMES libobs-frontend-api.* HINTS ${LIBOBS_LIB} )
|
||||||
|
endif()
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
find_library(COCOA Cocoa)
|
find_library(COCOA Cocoa)
|
||||||
|
if(BUILD_OUT_OF_TREE)
|
||||||
find_package(Qt5MacExtras REQUIRED)
|
find_package(Qt5MacExtras REQUIRED)
|
||||||
include_directories(${COCOA})
|
|
||||||
add_link_options("-v")
|
|
||||||
endif()
|
endif()
|
||||||
|
include_directories(${COCOA})
|
||||||
|
endif()
|
||||||
|
|
||||||
if(UNIX AND NOT APPLE)
|
|
||||||
find_package(X11 REQUIRED)
|
|
||||||
link_libraries(${X11_LIBRARIES})
|
|
||||||
include_directories(${X11_INCLUDE_DIR})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(advanced-scene-switcher_HEADERS
|
if(UNIX AND NOT APPLE)
|
||||||
${advanced-scene-switcher_HEADERS}
|
find_package(X11 REQUIRED)
|
||||||
src/headers/advanced-scene-switcher.hpp
|
link_libraries(${X11_LIBRARIES})
|
||||||
src/headers/switcher-data-structs.hpp
|
include_directories(${X11_INCLUDE_DIR})
|
||||||
src/headers/utility.hpp
|
endif()
|
||||||
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
|
set(advanced-scene-switcher_HEADERS
|
||||||
${advanced-scene-switcher_SOURCES}
|
${advanced-scene-switcher_HEADERS}
|
||||||
src/advanced-scene-switcher.cpp
|
src/headers/advanced-scene-switcher.hpp
|
||||||
src/advanced-scene-switcher-module.c
|
src/headers/switcher-data-structs.hpp
|
||||||
src/switcher-data-structs.cpp
|
src/headers/utility.hpp
|
||||||
src/switch-transitions.cpp
|
src/headers/curl-helper.hpp
|
||||||
src/switch-screen-region.cpp
|
src/headers/volume-control.hpp
|
||||||
src/switch-priority.cpp
|
src/headers/scene-group.hpp
|
||||||
src/switch-executable.cpp
|
src/headers/scene-trigger.hpp
|
||||||
src/switch-idle.cpp
|
src/headers/switch-audio.hpp
|
||||||
src/switch-sequence.cpp
|
src/headers/switch-executable.hpp
|
||||||
src/switch-file.cpp
|
src/headers/switch-file.hpp
|
||||||
src/switch-window.cpp
|
src/headers/switch-idle.hpp
|
||||||
src/switch-media.cpp
|
src/headers/switch-media.hpp
|
||||||
src/hotkey.cpp
|
src/headers/switch-pause.hpp
|
||||||
src/general.cpp
|
src/headers/switch-random.hpp
|
||||||
src/switch-pause.cpp
|
src/headers/switch-screen-region.hpp
|
||||||
src/switch-random.cpp
|
src/headers/switch-time.hpp
|
||||||
src/switch-time.cpp
|
src/headers/switch-transitions.hpp
|
||||||
src/switch-audio.cpp
|
src/headers/switch-window.hpp
|
||||||
src/switch-generic.cpp
|
src/headers/switch-sequence.hpp
|
||||||
src/curl-helper.cpp
|
src/headers/switch-generic.hpp
|
||||||
src/volume-control.cpp
|
src/headers/version.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(advanced-scene-switcher_UI
|
set(advanced-scene-switcher_SOURCES
|
||||||
${advanced-scene-switcher_UI}
|
${advanced-scene-switcher_SOURCES}
|
||||||
forms/advanced-scene-switcher.ui
|
src/advanced-scene-switcher.cpp
|
||||||
)
|
src/advanced-scene-switcher-module.c
|
||||||
|
src/switcher-data-structs.cpp
|
||||||
|
src/scene-group.cpp
|
||||||
|
src/scene-trigger.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/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
|
||||||
|
src/version.cpp
|
||||||
|
)
|
||||||
|
|
||||||
if(WIN32)
|
set(advanced-scene-switcher_UI
|
||||||
set(advanced-scene-switcher_PLATFORM_SOURCES
|
${advanced-scene-switcher_UI}
|
||||||
src/win/advanced-scene-switcher-win.cpp)
|
forms/advanced-scene-switcher.ui
|
||||||
|
)
|
||||||
|
|
||||||
elseif(APPLE)
|
if(WIN32)
|
||||||
set(advanced-scene-switcher_PLATFORM_SOURCES
|
set(advanced-scene-switcher_PLATFORM_SOURCES
|
||||||
src/osx/advanced-scene-switcher-osx.mm)
|
src/win/advanced-scene-switcher-win.cpp)
|
||||||
set_source_files_properties(advanced-scene-switcher-osx.mm
|
elseif(APPLE)
|
||||||
PROPERTIES COMPILE_FLAGS "-fobjc-arc")
|
set(advanced-scene-switcher_PLATFORM_SOURCES
|
||||||
set(advanced-scene-switcher_PLATFORM_LIBS
|
src/osx/advanced-scene-switcher-osx.mm)
|
||||||
${COCOA})
|
set_source_files_properties(advanced-scene-switcher-osx.mm
|
||||||
|
PROPERTIES COMPILE_FLAGS "-fobjc-arc")
|
||||||
|
set(advanced-scene-switcher_PLATFORM_LIBS
|
||||||
|
${COCOA})
|
||||||
|
else()
|
||||||
|
set(advanced-scene-switcher_PLATFORM_SOURCES
|
||||||
|
src/linux/advanced-scene-switcher-nix.cpp)
|
||||||
|
set(advanced-scene-switcher_PLATFORM_LIBS
|
||||||
|
Xss)
|
||||||
|
endif()
|
||||||
|
|
||||||
elseif("${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
|
qt5_wrap_ui(advanced-scene-switcher_UI_HEADERS
|
||||||
set(advanced-scene-switcher_PLATFORM_SOURCES
|
${advanced-scene-switcher_UI}
|
||||||
src/linux/advanced-scene-switcher-nix.cpp)
|
${advanced-scene-switcher_PLATFORM_UI})
|
||||||
set(advanced-scene-switcher_PLATFORM_LIBS
|
|
||||||
Xss)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
qt5_wrap_ui(advanced-scene-switcher_UI_HEADERS
|
add_library(advanced-scene-switcher MODULE
|
||||||
${advanced-scene-switcher_UI}
|
${advanced-scene-switcher_HEADERS}
|
||||||
${advanced-scene-switcher_PLATFORM_UI})
|
${advanced-scene-switcher_SOURCES}
|
||||||
|
${advanced-scene-switcher_UI_HEADERS}
|
||||||
add_library(advanced-scene-switcher MODULE
|
${advanced-scene-switcher_PLATFORM_SOURCES}
|
||||||
${advanced-scene-switcher_HEADERS}
|
${advanced-scene-switcher_PLATFORM_HEADERS}
|
||||||
${advanced-scene-switcher_SOURCES}
|
)
|
||||||
${advanced-scene-switcher_UI_HEADERS}
|
|
||||||
${advanced-scene-switcher_PLATFORM_SOURCES}
|
|
||||||
${advanced-scene-switcher_PLATFORM_HEADERS}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
if(BUILD_OUT_OF_TREE)
|
||||||
include_directories(
|
include_directories(
|
||||||
"${LIBOBS_INCLUDE_DIRS}"
|
"${LIBOBS_INCLUDE_DIRS}"
|
||||||
"${LIBOBS_FRONTEND_INCLUDE_DIR}"
|
"${LIBOBS_FRONTEND_INCLUDE_DIR}"
|
||||||
@@ -146,7 +168,6 @@ if(BUILD_OUT_OF_TREE)
|
|||||||
# OSX
|
# OSX
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
set_target_properties(advanced-scene-switcher PROPERTIES PREFIX "")
|
set_target_properties(advanced-scene-switcher PROPERTIES PREFIX "")
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Linux
|
# Linux
|
||||||
@@ -166,104 +187,12 @@ if(BUILD_OUT_OF_TREE)
|
|||||||
install(FILES ${ASS_TRANSLATION_FILES}
|
install(FILES ${ASS_TRANSLATION_FILES}
|
||||||
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/obs/obs-plugins/advanced-scene-switcher/locale")
|
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/obs/obs-plugins/advanced-scene-switcher/locale")
|
||||||
endif()
|
endif()
|
||||||
else ()
|
else()
|
||||||
# in-tree build
|
|
||||||
if(APPLE)
|
|
||||||
find_library(COCOA Cocoa)
|
|
||||||
include_directories(${COCOA})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(UNIX AND NOT APPLE)
|
|
||||||
find_package(X11 REQUIRED)
|
|
||||||
link_libraries(${X11_LIBRARIES})
|
|
||||||
include_directories(${X11_INCLUDE_DIR})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(advanced-scene-switcher_HEADERS
|
|
||||||
${advanced-scene-switcher_HEADERS}
|
|
||||||
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/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/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
|
|
||||||
${advanced-scene-switcher_UI}
|
|
||||||
forms/advanced-scene-switcher.ui
|
|
||||||
)
|
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
set(advanced-scene-switcher_PLATFORM_SOURCES
|
|
||||||
src/win/advanced-scene-switcher-win.cpp)
|
|
||||||
elseif(APPLE)
|
|
||||||
set(advanced-scene-switcher_PLATFORM_SOURCES
|
|
||||||
src/osx/advanced-scene-switcher-osx.mm)
|
|
||||||
set_source_files_properties(advanced-scene-switcher-osx.mm
|
|
||||||
PROPERTIES COMPILE_FLAGS "-fobjc-arc")
|
|
||||||
set(advanced-scene-switcher_PLATFORM_LIBS
|
|
||||||
${COCOA})
|
|
||||||
else()
|
|
||||||
set(advanced-scene-switcher_PLATFORM_SOURCES
|
|
||||||
src/linux/advanced-scene-switcher-nix.cpp)
|
|
||||||
set(advanced-scene-switcher_PLATFORM_LIBS
|
|
||||||
Xss)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
qt5_wrap_ui(advanced-scene-switcher_UI_HEADERS
|
|
||||||
${advanced-scene-switcher_UI}
|
|
||||||
${advanced-scene-switcher_PLATFORM_UI})
|
|
||||||
|
|
||||||
add_library(advanced-scene-switcher MODULE
|
|
||||||
${advanced-scene-switcher_HEADERS}
|
|
||||||
${advanced-scene-switcher_SOURCES}
|
|
||||||
${advanced-scene-switcher_UI_HEADERS}
|
|
||||||
${advanced-scene-switcher_PLATFORM_SOURCES}
|
|
||||||
${advanced-scene-switcher_PLATFORM_HEADERS}
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(advanced-scene-switcher
|
target_link_libraries(advanced-scene-switcher
|
||||||
${advanced-scene-switcher_PLATFORM_LIBS}
|
${advanced-scene-switcher_PLATFORM_LIBS}
|
||||||
obs-frontend-api
|
obs-frontend-api
|
||||||
Qt5::Widgets
|
Qt5::Widgets
|
||||||
libobs)
|
libobs)
|
||||||
|
|
||||||
install_obs_plugin(advanced-scene-switcher data)
|
install_obs_plugin_with_data(advanced-scene-switcher data)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ An automated scene switcher for OBS Studio
|
|||||||
|
|
||||||
More information can be found on https://obsproject.com/forum/resources/automatic-scene-switching.395/
|
More information can be found on https://obsproject.com/forum/resources/automatic-scene-switching.395/
|
||||||
|
|
||||||
## Compiling in tree
|
## Compiling in tree (recommended)
|
||||||
Add the "SceneSwitcher" source directory to your obs-studio source directory under obs-studio/UI/frontend-plugins/:
|
Add the "SceneSwitcher" source directory to your obs-studio source directory under obs-studio/UI/frontend-plugins/:
|
||||||
```
|
```
|
||||||
cd obs-studio/UI/frontend-plugins/
|
cd obs-studio/UI/frontend-plugins/
|
||||||
@@ -49,9 +49,10 @@ Most versions of Linux you can use cmake-gui or the command line.
|
|||||||
|
|
||||||
**For the command line:**
|
**For the command line:**
|
||||||
```
|
```
|
||||||
cmake -DBUILD_OUT_OF_TREE=1 -DLIBOBS_INCLUDE_DIR="<path to the libobs/ sub-folder in obs-studio's source code>"
|
cmake -DBUILD_OUT_OF_TREE=1 -DLIBOBS_INCLUDE_DIR="<path to the libobs/ sub-folder in obs-studio's source code>" \
|
||||||
-DLIBOBS_FRONTEND_INCLUDE_DIR="<path to the UI/obs-frontend-api/ sub-folder in obs-studio's source code>"
|
-DLIBOBS_FRONTEND_INCLUDE_DIR="<path to the UI/obs-frontend-api/ sub-folder in obs-studio's source code>" \
|
||||||
-DLIBOBS_FRONTEND_API_LIB="< path to the libobs-frontend-api.so file (usually in the same place as LIBOBS_LIB)>"
|
-DLIBOBS_LIB="<path to the libobs.so file>" \
|
||||||
|
-DLIBOBS_FRONTEND_API_LIB="<path to the libobs-frontend-api.so file (usually in the same place as LIBOBS_LIB)>" \
|
||||||
-DCMAKE_INSTALL_PREFIX=/usr ..
|
-DCMAKE_INSTALL_PREFIX=/usr ..
|
||||||
make -j4
|
make -j4
|
||||||
sudo make install
|
sudo make install
|
||||||
|
|||||||
279
cmake/GetGitRevisionDescription.cmake
Normal file
279
cmake/GetGitRevisionDescription.cmake
Normal file
@@ -0,0 +1,279 @@
|
|||||||
|
# - Returns a version string from Git
|
||||||
|
#
|
||||||
|
# These functions force a re-configure on each git commit so that you can
|
||||||
|
# trust the values of the variables in your build system.
|
||||||
|
#
|
||||||
|
# get_git_head_revision(<refspecvar> <hashvar> [<additional arguments to git describe> ...])
|
||||||
|
#
|
||||||
|
# Returns the refspec and sha hash of the current head revision
|
||||||
|
#
|
||||||
|
# git_describe(<var> [<additional arguments to git describe> ...])
|
||||||
|
#
|
||||||
|
# Returns the results of git describe on the source tree, and adjusting
|
||||||
|
# the output so that it tests false if an error occurs.
|
||||||
|
#
|
||||||
|
# git_describe_working_tree(<var> [<additional arguments to git describe> ...])
|
||||||
|
#
|
||||||
|
# Returns the results of git describe on the working tree (--dirty option),
|
||||||
|
# and adjusting the output so that it tests false if an error occurs.
|
||||||
|
#
|
||||||
|
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
|
||||||
|
#
|
||||||
|
# Returns the results of git describe --exact-match on the source tree,
|
||||||
|
# and adjusting the output so that it tests false if there was no exact
|
||||||
|
# matching tag.
|
||||||
|
#
|
||||||
|
# git_local_changes(<var>)
|
||||||
|
#
|
||||||
|
# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes.
|
||||||
|
# Uses the return code of "git diff-index --quiet HEAD --".
|
||||||
|
# Does not regard untracked files.
|
||||||
|
#
|
||||||
|
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||||
|
#
|
||||||
|
# Original Author:
|
||||||
|
# 2009-2020 Ryan Pavlik <ryan.pavlik@gmail.com> <abiryan@ryand.net>
|
||||||
|
# http://academic.cleardefinition.com
|
||||||
|
#
|
||||||
|
# Copyright 2009-2013, Iowa State University.
|
||||||
|
# Copyright 2013-2020, Ryan Pavlik
|
||||||
|
# Copyright 2013-2020, Contributors
|
||||||
|
# SPDX-License-Identifier: BSL-1.0
|
||||||
|
# Distributed under the Boost Software License, Version 1.0.
|
||||||
|
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
# http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
if(__get_git_revision_description)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(__get_git_revision_description YES)
|
||||||
|
|
||||||
|
# We must run the following at "include" time, not at function call time,
|
||||||
|
# to find the path to this module rather than the path to a calling list file
|
||||||
|
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
|
||||||
|
|
||||||
|
# Function _git_find_closest_git_dir finds the next closest .git directory
|
||||||
|
# that is part of any directory in the path defined by _start_dir.
|
||||||
|
# The result is returned in the parent scope variable whose name is passed
|
||||||
|
# as variable _git_dir_var. If no .git directory can be found, the
|
||||||
|
# function returns an empty string via _git_dir_var.
|
||||||
|
#
|
||||||
|
# Example: Given a path C:/bla/foo/bar and assuming C:/bla/.git exists and
|
||||||
|
# neither foo nor bar contain a file/directory .git. This wil return
|
||||||
|
# C:/bla/.git
|
||||||
|
#
|
||||||
|
function(_git_find_closest_git_dir _start_dir _git_dir_var)
|
||||||
|
set(cur_dir "${_start_dir}")
|
||||||
|
set(git_dir "${_start_dir}/.git")
|
||||||
|
while(NOT EXISTS "${git_dir}")
|
||||||
|
# .git dir not found, search parent directories
|
||||||
|
set(git_previous_parent "${cur_dir}")
|
||||||
|
get_filename_component(cur_dir ${cur_dir} DIRECTORY)
|
||||||
|
if(cur_dir STREQUAL git_previous_parent)
|
||||||
|
# We have reached the root directory, we are not in git
|
||||||
|
set(${_git_dir_var}
|
||||||
|
""
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(git_dir "${cur_dir}/.git")
|
||||||
|
endwhile()
|
||||||
|
set(${_git_dir_var}
|
||||||
|
"${git_dir}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(get_git_head_revision _refspecvar _hashvar)
|
||||||
|
_git_find_closest_git_dir("${CMAKE_CURRENT_SOURCE_DIR}" GIT_DIR)
|
||||||
|
|
||||||
|
if(NOT "${GIT_DIR}" STREQUAL "")
|
||||||
|
file(RELATIVE_PATH _relative_to_source_dir "${CMAKE_SOURCE_DIR}"
|
||||||
|
"${GIT_DIR}")
|
||||||
|
if("${_relative_to_source_dir}" MATCHES "[.][.]")
|
||||||
|
# We've gone above the CMake root dir.
|
||||||
|
set(GIT_DIR "")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
if("${GIT_DIR}" STREQUAL "")
|
||||||
|
set(${_refspecvar}
|
||||||
|
"GITDIR-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
set(${_hashvar}
|
||||||
|
"GITDIR-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Check if the current source dir is a git submodule or a worktree.
|
||||||
|
# In both cases .git is a file instead of a directory.
|
||||||
|
#
|
||||||
|
if(NOT IS_DIRECTORY ${GIT_DIR})
|
||||||
|
# The following git command will return a non empty string that
|
||||||
|
# points to the super project working tree if the current
|
||||||
|
# source dir is inside a git submodule.
|
||||||
|
# Otherwise the command will return an empty string.
|
||||||
|
#
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${GIT_EXECUTABLE}" rev-parse
|
||||||
|
--show-superproject-working-tree
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
OUTPUT_VARIABLE out
|
||||||
|
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
if(NOT "${out}" STREQUAL "")
|
||||||
|
# If out is empty, GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a submodule
|
||||||
|
file(READ ${GIT_DIR} submodule)
|
||||||
|
string(REGEX REPLACE "gitdir: (.*)$" "\\1" GIT_DIR_RELATIVE
|
||||||
|
${submodule})
|
||||||
|
string(STRIP ${GIT_DIR_RELATIVE} GIT_DIR_RELATIVE)
|
||||||
|
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
|
||||||
|
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE}
|
||||||
|
ABSOLUTE)
|
||||||
|
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
|
||||||
|
else()
|
||||||
|
# GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a worktree
|
||||||
|
file(READ ${GIT_DIR} worktree_ref)
|
||||||
|
# The .git directory contains a path to the worktree information directory
|
||||||
|
# inside the parent git repo of the worktree.
|
||||||
|
#
|
||||||
|
string(REGEX REPLACE "gitdir: (.*)$" "\\1" git_worktree_dir
|
||||||
|
${worktree_ref})
|
||||||
|
string(STRIP ${git_worktree_dir} git_worktree_dir)
|
||||||
|
_git_find_closest_git_dir("${git_worktree_dir}" GIT_DIR)
|
||||||
|
set(HEAD_SOURCE_FILE "${git_worktree_dir}/HEAD")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
|
||||||
|
endif()
|
||||||
|
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
|
||||||
|
if(NOT EXISTS "${GIT_DATA}")
|
||||||
|
file(MAKE_DIRECTORY "${GIT_DATA}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT EXISTS "${HEAD_SOURCE_FILE}")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(HEAD_FILE "${GIT_DATA}/HEAD")
|
||||||
|
configure_file("${HEAD_SOURCE_FILE}" "${HEAD_FILE}" COPYONLY)
|
||||||
|
|
||||||
|
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
|
||||||
|
"${GIT_DATA}/grabRef.cmake" @ONLY)
|
||||||
|
include("${GIT_DATA}/grabRef.cmake")
|
||||||
|
|
||||||
|
set(${_refspecvar}
|
||||||
|
"${HEAD_REF}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
set(${_hashvar}
|
||||||
|
"${HEAD_HASH}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(git_describe _var)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
find_package(Git QUIET)
|
||||||
|
endif()
|
||||||
|
get_git_head_revision(refspec hash)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
set(${_var}
|
||||||
|
"GIT-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
if(NOT hash)
|
||||||
|
set(${_var}
|
||||||
|
"HEAD-HASH-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# TODO sanitize
|
||||||
|
#if((${ARGN}" MATCHES "&&") OR
|
||||||
|
# (ARGN MATCHES "||") OR
|
||||||
|
# (ARGN MATCHES "\\;"))
|
||||||
|
# message("Please report the following error to the project!")
|
||||||
|
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
|
||||||
|
#endif()
|
||||||
|
|
||||||
|
#message(STATUS "Arguments to execute_process: ${ARGN}")
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${GIT_EXECUTABLE}" describe --tags --always ${hash} ${ARGN}
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
RESULT_VARIABLE res
|
||||||
|
OUTPUT_VARIABLE out
|
||||||
|
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
if(NOT res EQUAL 0)
|
||||||
|
set(out "${out}-${res}-NOTFOUND")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(${_var}
|
||||||
|
"${out}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(git_describe_working_tree _var)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
find_package(Git QUIET)
|
||||||
|
endif()
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
set(${_var}
|
||||||
|
"GIT-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${GIT_EXECUTABLE}" describe --dirty ${ARGN}
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
RESULT_VARIABLE res
|
||||||
|
OUTPUT_VARIABLE out
|
||||||
|
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
if(NOT res EQUAL 0)
|
||||||
|
set(out "${out}-${res}-NOTFOUND")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(${_var}
|
||||||
|
"${out}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(git_get_exact_tag _var)
|
||||||
|
git_describe(out --exact-match ${ARGN})
|
||||||
|
set(${_var}
|
||||||
|
"${out}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(git_local_changes _var)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
find_package(Git QUIET)
|
||||||
|
endif()
|
||||||
|
get_git_head_revision(refspec hash)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
set(${_var}
|
||||||
|
"GIT-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
if(NOT hash)
|
||||||
|
set(${_var}
|
||||||
|
"HEAD-HASH-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${GIT_EXECUTABLE}" diff-index --quiet HEAD --
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
RESULT_VARIABLE res
|
||||||
|
OUTPUT_VARIABLE out
|
||||||
|
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
if(res EQUAL 0)
|
||||||
|
set(${_var}
|
||||||
|
"CLEAN"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
else()
|
||||||
|
set(${_var}
|
||||||
|
"DIRTY"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
41
cmake/GetGitRevisionDescription.cmake.in
Normal file
41
cmake/GetGitRevisionDescription.cmake.in
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#
|
||||||
|
# Internal file for GetGitRevisionDescription.cmake
|
||||||
|
#
|
||||||
|
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||||
|
#
|
||||||
|
# Original Author:
|
||||||
|
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
||||||
|
# http://academic.cleardefinition.com
|
||||||
|
# Iowa State University HCI Graduate Program/VRAC
|
||||||
|
#
|
||||||
|
# Copyright Iowa State University 2009-2010.
|
||||||
|
# Distributed under the Boost Software License, Version 1.0.
|
||||||
|
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
# http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
set(HEAD_HASH)
|
||||||
|
|
||||||
|
file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
|
||||||
|
|
||||||
|
string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
|
||||||
|
if(HEAD_CONTENTS MATCHES "ref")
|
||||||
|
# named branch
|
||||||
|
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
|
||||||
|
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
|
||||||
|
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
|
||||||
|
else()
|
||||||
|
configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
|
||||||
|
file(READ "@GIT_DATA@/packed-refs" PACKED_REFS)
|
||||||
|
if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
|
||||||
|
set(HEAD_HASH "${CMAKE_MATCH_1}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
# detached HEAD
|
||||||
|
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT HEAD_HASH)
|
||||||
|
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
|
||||||
|
string(STRIP "${HEAD_HASH}" HEAD_HASH)
|
||||||
|
endif()
|
||||||
3
cmake/version.cpp.in
Normal file
3
cmake/version.cpp.in
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#include "src/headers/version.h"
|
||||||
|
#define GIT_SHA1 "@GIT_SHA1@"
|
||||||
|
const char g_GIT_SHA1[] = GIT_SHA1;
|
||||||
268
data/locale/de-DE.ini
Normal file
268
data/locale/de-DE.ini
Normal file
@@ -0,0 +1,268 @@
|
|||||||
|
AdvSceneSwitcher.pluginName="Erweiterter Automatischer Szenenwechsler"
|
||||||
|
AdvSceneSwitcher.windowTitle="Erweiterter Automatischer Szenenwechsler"
|
||||||
|
|
||||||
|
; General Tab
|
||||||
|
AdvSceneSwitcher.generalTab.title="Allgemein"
|
||||||
|
AdvSceneSwitcher.generalTab.status="Status"
|
||||||
|
AdvSceneSwitcher.generalTab.status.hotkeytips="Hotkeys können in den OBS Einstellungen konfiguriert werden"
|
||||||
|
AdvSceneSwitcher.generalTab.status.currentStatus="Erweiterter Automatischer Szenenwechsler ist:"
|
||||||
|
AdvSceneSwitcher.generalTab.status.onStartup="Beim Start von OBS:"
|
||||||
|
AdvSceneSwitcher.generalTab.status.onStartup.asLastRun="Aktiviere den Szenenwechsler wenn er aktiv war"
|
||||||
|
AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Aktiviere den Szenenwechsler"
|
||||||
|
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Aktiviere den Szenenwechsler nicht"
|
||||||
|
AdvSceneSwitcher.generalTab.status.start="Start"
|
||||||
|
AdvSceneSwitcher.generalTab.status.stop="Stop"
|
||||||
|
AdvSceneSwitcher.generalTab.status.autoStart="Starte auotmatischen den Szenenwechsler beim:"
|
||||||
|
AdvSceneSwitcher.generalTab.status.autoStart.never="Niemals"
|
||||||
|
AdvSceneSwitcher.generalTab.status.autoStart.recording="Aufnehmen"
|
||||||
|
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Streamen"
|
||||||
|
AdvSceneSwitcher.generalTab.status.autoStart.recordingAndStreaming="Aufnehmen oder Streamen"
|
||||||
|
AdvSceneSwitcher.generalTab.status.checkInterval="Teste Bedingungen alle"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior="Allgemeines Verhalten"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet="Wenn keine Bedingung erfüllt ist für "
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.onNoMetDelayTooltip="Kann nur so genau sein wie das eingestellte Interval zum Testen der Bedingungen."
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.dontSwitch="Nicht wechseln"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchToRandom="Wechsle zu einer Szene auf dem Zufall-Tab"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchTo="Wechsle zu:"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.cooldown="Nach einem automatisierten Szenenwechsel wechsle nicht mehr für"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint="In diesem Zeitraum werden potentielle erfüllte Bedingungen ignoriert!"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Ausführliches Logging"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="Deaktiviere UI Tipps"
|
||||||
|
AdvSceneSwitcher.generalTab.priority="Priorität"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.description="Szenenwechselmethoden sortiert nach Priorität"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.threadPriority="Benutze Thread Priorität"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.threadPriorityNotice="(Erhöhen der Priorität über \"Normal\" ist nicht empfohlen)"
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings="Speichern / Laden der Einstellungen"
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="Exportieren"
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Importieren"
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Exportiere Erweiterter Automatischer Szenenwechsler Einstellungen zu Datei ..."
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Exportiere Erweiterter Automatischer Szenenwechsler Einstellungen von Datei ..."
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Text Dateien (*.txt)"
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="Importieren der Einstellungen ist fehlgeschlagen"
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Einstellungen wurden erfolgreich importiert"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.fileContent="Datei Inhalt"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.sceneSequence="Szenenfolge"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.idleDetection="Inaktivitätserkennung"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.executable="Prozess"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.screenRegion="Bildschrimbereich"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.windowTitle="Fenstername"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.media="Medien"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.time="Zeit"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.audio="Audio"
|
||||||
|
|
||||||
|
; Transition Tab
|
||||||
|
AdvSceneSwitcher.transitionTab.title="Szenenübergänge"
|
||||||
|
AdvSceneSwitcher.transitionTab.transitionOverride="Szenenübergänge, die im Szenenwechsler konfiguriert werden, haben Vorrang vor Übergangsüberschreibung"
|
||||||
|
AdvSceneSwitcher.transitionTab.transitionForAToB="Szenenübergänge für automatisierte Szenenwechsel von Szene A zu Szene B"
|
||||||
|
AdvSceneSwitcher.transitionTab.transitionsHelp="<html><head/><body><p>Diese Einstellungen beeinflussen <span style=\"font-style:italic;\">nur</span> vom Szenenwechsler ausgelöste Szenenübergänge - Siehe <a href=\"https://obsproject.com/forum/resources/transition-table.1174/\"><span style=\" text-decoration: underline; color:#268bd2;\">Transition Table</span></a> um auch manuelle Szenenübergänge zu konfigurieren.<br/>Einstellungen auf diesem Tab haben Vorrang, vor denen welche auf den übrigen Tabs konfiguriert wurden.<br/><br/>Klicke auf das Plus Symbol, um einen neuen Eintrag hinzuzufügen.</p></body></html>"
|
||||||
|
AdvSceneSwitcher.transitionTab.defaultTransition="Ändere den Szenenübergang wenn eine Szene aktiv ist"
|
||||||
|
AdvSceneSwitcher.transitionTab.entry="Wechsle von {{scenes}} zu {{scenes2}} mit {{transitions}}"
|
||||||
|
AdvSceneSwitcher.transitionTab.defaultTransitionEntry="Wenn {{scenes}} aktiv ist ändere den Szenenübergang zu {{transitions}}"
|
||||||
|
AdvSceneSwitcher.transitionTab.defaultTransitionsHelp="Klicke auf das Plus Symbol, um einen neuen Eintrag hinzuzufügen."
|
||||||
|
|
||||||
|
; Pause Scenes Tab
|
||||||
|
AdvSceneSwitcher.pauseTab.title="Pause"
|
||||||
|
AdvSceneSwitcher.pauseTab.pauseOnScene="Pausiere den Szenenwechsler auf einer Szene"
|
||||||
|
AdvSceneSwitcher.pauseTab.pauseInFocus1="Pausiere den Szenenwechsler wenn "
|
||||||
|
AdvSceneSwitcher.pauseTab.pauseInFocus2="im Fokus ist"
|
||||||
|
AdvSceneSwitcher.pauseTab.pauseTypeScene="Szene aktiv ist"
|
||||||
|
AdvSceneSwitcher.pauseTab.pauseTypeWindow="Fenster im Fokus ist"
|
||||||
|
AdvSceneSwitcher.pauseTab.pauseTargetAll="alle"
|
||||||
|
AdvSceneSwitcher.pauseTab.pauseEntry="Pausiere {{pauseTargets}} Überprüfungen wenn {{scenes}} {{windows}} {{pauseTypes}}"
|
||||||
|
AdvSceneSwitcher.pauseTab.help="Auf diesem Tab können einzelne Szenenwechselmethoden pausiert werden, wenn eine Szene aktiv oder ein Fenster im Fokus ist.\n\nKlicke auf das markierte Plus Symbol, um einen neuen Eintrag hinzuzufügen."
|
||||||
|
|
||||||
|
; Window Title Tab
|
||||||
|
AdvSceneSwitcher.windowTitleTab.title="Fenstername"
|
||||||
|
AdvSceneSwitcher.windowTitleTab.regexrDescription="<html><head/><body><p>Gib entweder den gesamten Fensternamen ein oder eine gültigen regulären Ausdruck. Die Syntax für regulärer Ausdrücke (regex) kann hier überprüft werden: <a href=\"https://regexr.com\"><span style=\" text-decoration: underline; color:#268bd2;\">RegExr</span></a></p></body></html>"
|
||||||
|
AdvSceneSwitcher.windowTitleTab.stayInFocus1="Ignoriere diesen Fensternamen"
|
||||||
|
AdvSceneSwitcher.windowTitleTab.stayInFocus2=" "
|
||||||
|
AdvSceneSwitcher.windowTitleTab.fullscreen="wenn Vollbild"
|
||||||
|
AdvSceneSwitcher.windowTitleTab.maximized="wenn maximiert"
|
||||||
|
AdvSceneSwitcher.windowTitleTab.focused="wenn fokussiert"
|
||||||
|
AdvSceneSwitcher.windowTitleTab.entry="{{windows}} {{scenes}} {{transitions}} {{fullscreen}} {{maximized}} {{focused}}"
|
||||||
|
AdvSceneSwitcher.windowTitleTab.windowsHelp="Wechsle Szenen basiert auf dem Fensternamen eines laufenden Prozesses.\nFolgende zusätzliche Bedingungen können ausgewählt werden:\nDas Fenster ist im Vollbildmodus\nDas Fenster ist maximiert\nDas Fenster ist fokussiert\n\nKlicke auf das markierte Plus Symbol, um einen neuen Eintrag hinzuzufügen."
|
||||||
|
AdvSceneSwitcher.windowTitleTab.ignoreWindowsHelp="Ist ein Fenstername ignoriert so verhält sich der Szenenwechsler als ob das vorhergehende Fenster immer noch fokussiert ist.\nDies kann in Situationen nützlich sein, in den oft zwischen Fenster gewechselt wird, dies aber nicht immer einen Szenenwechsel auslösen soll.\n\nWähle oben ein Fenster aus oder gib einen Fensternamen ein und klicke auf das Plus Symbol um es zur Liste hinzuzufügen."
|
||||||
|
|
||||||
|
; Executable Tab
|
||||||
|
AdvSceneSwitcher.executableTab.title="Prozess"
|
||||||
|
AdvSceneSwitcher.executableTab.implemented="Implementiert von dasOven"
|
||||||
|
AdvSceneSwitcher.executableTab.requiresFocus="nur wenn dieser fokussiert ist"
|
||||||
|
AdvSceneSwitcher.executableTab.entry="Wenn {{processes}} läuft wechsle zu {{scenes}} mit {{transitions}} {{requiresFocus}}"
|
||||||
|
AdvSceneSwitcher.executableTab.help="Dieser Tab erlaubt es Szenen zu wechseln, wenn bestimmte Prozesse laufen.\nDas kann nützlich sein, wenn sich der Name eines Fensters ändern kann oder dieser nicht bekannt ist.\n\nKlicke auf das markierte Plus Symbol, um einen neuen Eintrag hinzuzufügen."
|
||||||
|
|
||||||
|
; Screen Region Tab
|
||||||
|
AdvSceneSwitcher.screenRegionTab.title="Bildschrimbereich"
|
||||||
|
AdvSceneSwitcher.screenRegionTab.currentPosition="Mauszeiger ist bei:"
|
||||||
|
AdvSceneSwitcher.screenRegionTab.showGuideFrames="Hilfsrahmen einblenden"
|
||||||
|
AdvSceneSwitcher.screenRegionTab.hideGuideFrames="Hilfsrahmen ausblenden"
|
||||||
|
AdvSceneSwitcher.screenRegionTab.excludeScenes.None="Keine Auswahl"
|
||||||
|
AdvSceneSwitcher.screenRegionTab.entry="Wenn der Mauszeiger in {{minX}} {{minY}} x {{maxX}} {{maxY}} ist wechsle zu {{scenes}} mit {{transitions}} außer wenn auf {{excludeScenes}}"
|
||||||
|
AdvSceneSwitcher.screenRegionTab.help="Dieser Tab ermöglicht es basierend auf der Position des Mauszeigers Szenen zu wechseln.\n\nKlicke auf das markierte Plus Symbol, um einen neuen Eintrag hinzuzufügen."
|
||||||
|
|
||||||
|
; Media Tab
|
||||||
|
AdvSceneSwitcher.mediaTab.title="Medien"
|
||||||
|
AdvSceneSwitcher.mediaTab.implemented="Implementiert von Exeldro"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.none="Keine Auswahl"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.playing="Abspielen"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.opening="Öffnen"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.buffering="Buffern"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.Paused="Pausiert"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.stopped="Gestoppt"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.ended="Beendet"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.error="Fehler"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.playedToEnd="Zu Ende gespielt"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.any="Beliebig"
|
||||||
|
AdvSceneSwitcher.mediaTab.timeRestriction.none="Keine Auswahl"
|
||||||
|
AdvSceneSwitcher.mediaTab.timeRestriction.shorter="Dauer kürzer"
|
||||||
|
AdvSceneSwitcher.mediaTab.timeRestriction.longer="Dauer länger"
|
||||||
|
AdvSceneSwitcher.mediaTab.timeRestriction.remainShorter="übrige Zeit kürzer"
|
||||||
|
AdvSceneSwitcher.mediaTab.timeRestriction.remainLonger="übrige Zeit länger"
|
||||||
|
AdvSceneSwitcher.mediaTab.entry="Wenn {{mediaSources}} im Status {{states}} ist und{{timeRestrictions}} {{time}} ist wechsle zu {{scenes}} mit {{transitions}}"
|
||||||
|
AdvSceneSwitcher.mediaTab.help="Dieser Tab ermöglicht es basieren auf dem Status von Medienquellen Szenen zu wechseln.\nZum Beispiel kann automatisch zur vorhergehenden Szene gewechselt werden, sobald sich eine Medienquelle im Status Beendet befindet.\n\nKlicke auf das markierte Plus Symbol, um einen neuen Eintrag hinzuzufügen."
|
||||||
|
|
||||||
|
; File Tab
|
||||||
|
AdvSceneSwitcher.fileTab.title="Datei Inhalt"
|
||||||
|
AdvSceneSwitcher.fileTab.readWriteSceneFile="Lese / schreibe Szene von / zu Datei"
|
||||||
|
AdvSceneSwitcher.fileTab.currentSceneOutputFile="Schreibe den Namen der aktiven Szene in folgende Datei:"
|
||||||
|
AdvSceneSwitcher.fileTab.switchSceneBaseOnFile="Aktiviere Lesen der Szene aus Datei"
|
||||||
|
AdvSceneSwitcher.fileTab.switchSceneNameInputFile="Lies den Namen der Scene zu der gewechselt werden soll von folgender Datei:"
|
||||||
|
AdvSceneSwitcher.fileTab.switchSceneBaseOnFileContent="Wechsle Scene basierend auf Datei Inhalt"
|
||||||
|
AdvSceneSwitcher.fileTab.remoteFileWarning="Vorsicht: Der Szenenwechsler wird versuchen den angegebenen Pfad alle x ms zu öffnen!"
|
||||||
|
AdvSceneSwitcher.fileTab.remoteFileWarning1="Vorsicht: Der Szenenwechsler öffnet den angegebenen Pfad alle "
|
||||||
|
AdvSceneSwitcher.fileTab.remoteFileWarning2="ms"
|
||||||
|
AdvSceneSwitcher.fileTab.libcurlWarning="Laden von libcurl fehlgeschlagen! Erreichen von remote Dateien wird nicht möglich sein!"
|
||||||
|
AdvSceneSwitcher.fileTab.selectWrite=Datei auswählen in die geschrieben werden soll ..."
|
||||||
|
AdvSceneSwitcher.fileTab.selectRead="Datei auswählen die gelesen werden soll ..."
|
||||||
|
AdvSceneSwitcher.fileTab.textFileType="Text Dateien (*.txt)"
|
||||||
|
AdvSceneSwitcher.fileTab.anyFileType="Beliebige Dateien (*.*)"
|
||||||
|
AdvSceneSwitcher.fileTab.remote="remote Datei"
|
||||||
|
AdvSceneSwitcher.fileTab.local="lokale Datei"
|
||||||
|
AdvSceneSwitcher.fileTab.useRegExp="verwende reguläre Ausdrücke"
|
||||||
|
AdvSceneSwitcher.fileTab.checkfileContentTime="nur wenn sich das Änderungsdatum geändert"
|
||||||
|
AdvSceneSwitcher.fileTab.checkfileContent="nur wenn sich der Inhalt geänder hat"
|
||||||
|
AdvSceneSwitcher.fileTab.entry="Wechsle zu {{scenes}} mit {{transitions}} wenn der Inhalt von {{fileType}} {{filePath}} {{browseButton}} passt zu:"
|
||||||
|
AdvSceneSwitcher.fileTab.entry2="{{matchText}}"
|
||||||
|
AdvSceneSwitcher.fileTab.entry3="{{useRegex}} {{checkModificationDate}} {{checkFileContent}}"
|
||||||
|
AdvSceneSwitcher.fileTab.help="Dieser Tab erlaubt es Szenen zu wechseln basierend auf dem Inhalt von lokalen oder remote Dateien.\n\nKlicke auf das markierte Plus Symbol, um einen neuen Eintrag hinzuzufügen."
|
||||||
|
|
||||||
|
; Random Tab
|
||||||
|
AdvSceneSwitcher.randomTab.title="Zufall"
|
||||||
|
AdvSceneSwitcher.randomTab.randomDisabledWarning="Funktionalität deaktiviert - Um diese zu aktivieren wähle \"Wenn keine Bedingung erfüllt ist wechsle zu einer Szene auf dem Zufall-Tab\" auf dem Allgemein-Tab aus"
|
||||||
|
AdvSceneSwitcher.randomTab.entry="Wenn keine Bedingung erfüllt ist wechsle zu {{scenes}} mit {{transitions}} für {{delay}}"
|
||||||
|
AdvSceneSwitcher.randomTab.help="Der Szenenwechsler wählt zufällig einen Eintrag auf diesem Tab aus, zu dem er für die angegebene Zeit wechseln wird.\nDer gleiche Eintrag wird nicht zweimal nacheinander ausgewählt werden.\n\nKlicke auf das markierte Plus Symbol, um einen neuen Eintrag hinzuzufügen."
|
||||||
|
|
||||||
|
; Time Tab
|
||||||
|
AdvSceneSwitcher.timeTab.title="Zeit"
|
||||||
|
AdvSceneSwitcher.timeTab.anyDay="An allen Tagen"
|
||||||
|
AdvSceneSwitcher.timeTab.mondays="Montags"
|
||||||
|
AdvSceneSwitcher.timeTab.tuesdays="Dienstags"
|
||||||
|
AdvSceneSwitcher.timeTab.wednesdays="Mittwochs"
|
||||||
|
AdvSceneSwitcher.timeTab.thursdays="Donnerstags"
|
||||||
|
AdvSceneSwitcher.timeTab.fridays="Freitags"
|
||||||
|
AdvSceneSwitcher.timeTab.saturdays="Samstags"
|
||||||
|
AdvSceneSwitcher.timeTab.sundays="Sonntags"
|
||||||
|
AdvSceneSwitcher.timeTab.afterstart="Nach Streamen-/Aufnehmenstart"
|
||||||
|
AdvSceneSwitcher.timeTab.afterstart.tip="Hier wird die Zeit relativ zum Starten des Streamen/Aufnehmen gemessen"
|
||||||
|
AdvSceneSwitcher.timeTab.entry="{{triggers}} um {{time}} wechsle zu {{scenes}} mit {{transitions}}"
|
||||||
|
AdvSceneSwitcher.timeTab.help="Dieser Tab ermöglicht es Szenen basierend auf der aktuellen Uhrzeit zu wechseln.\n\nDer Szenenwechsler versucht den Szenenwechsel nur zur eingestellten Uhrzeit auszulösen.\nBeachte, dass die Prioritätseinstellungen auf dem Allgemein Tab entsprechend konfiguriert sind, sodass keine andere Szenenwechselmethode hier konfiguriert Einstellungen zur gegebenen Uhrzeit übertrifft.\n\nKlicke auf das markierte Plus Symbol, um einen neuen Eintrag hinzuzufügen."
|
||||||
|
|
||||||
|
; Idle Tab
|
||||||
|
AdvSceneSwitcher.idleTab.title="Inaktivitätserkennung"
|
||||||
|
AdvSceneSwitcher.idleTab.enable="Aktiviere Inaktivitätserkennung"
|
||||||
|
AdvSceneSwitcher.idleTab.idleswitch="After {{duration}} ohne Keyboard- oder Mauseingaben wechsle zu {{scenes}} mit {{transitions}}"
|
||||||
|
AdvSceneSwitcher.idleTab.dontSwitchIfFocus1="Wechsle nicht wenn"
|
||||||
|
AdvSceneSwitcher.idleTab.dontSwitchIfFocus2="im Fokus ist"
|
||||||
|
|
||||||
|
; Scene Sequence Tab
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.title="Szenenfolge"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.description="Eine Szenenfolge kann durch Pausieren, Stoppen des Szenenwechslers oder manuelle Szenenwechsel abgebrochen werden"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.save="Speichere Szenenfolgen in eine Datei"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.load="Lade Szenenfolgen von einer Datei"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.saveTitle="Speichere Szenenfolgen in eine Datei ..."
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.loadTitle="Wähle eine Datei aus von der Szenenfolgen gelesen werden sollen ..."
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.loadFail="Laden der Einstellungen ist fehlgeschlagen!"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.loadSuccess="Laden der Einstellungen war erfolgreich!"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.fileType="Text Dateien (*.txt)"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.interruptible="kann unterbrochen werden"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.interruptibleHint="Andere Szenenwechselmethoden können diese Sequenz unterbrechen"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.entry="Wenn {{startScenes}} aktiv ist wechsle zu {{scenes}} nach {{delay}} {{delayUnits}} mit {{transitions}} {{interruptible}}"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.help="Dieser Tab ermöglicht es automatisiert zu einer anderen Szene zu wechseln, nachdem eine Szene für die konfigurierte Zeit aktiv war.\nZum Beispiel kann so automatisch zwischen zwei Szenen hin und her gewechselt werden.\n\nKlicke auf das markierte Plus Symbol, um einen neuen Eintrag hinzuzufügen."
|
||||||
|
|
||||||
|
; Audio Tab
|
||||||
|
AdvSceneSwitcher.audioTab.title="Audio"
|
||||||
|
AdvSceneSwitcher.audioTab.condition.above="über"
|
||||||
|
AdvSceneSwitcher.audioTab.condition.below="unter"
|
||||||
|
AdvSceneSwitcher.audioTab.entry="Wenn die Lautstärke von {{audioSources}} {{condition}} {{volumeWidget}} ist für {{duration}} wechsle zu {{scenes}} mit {{transitions}}"
|
||||||
|
AdvSceneSwitcher.audioTab.multiMatchfallbackCondition="Wenn mehrere Einträge zutreffen ..."
|
||||||
|
AdvSceneSwitcher.audioTab.multiMatchfallback="... für {{duration}} wechsle zu {{scenes}} mit {{transitions}}"
|
||||||
|
AdvSceneSwitcher.audioTab.help="Dieser Tab ermöglicht es basierend auf der Lautstärke von Audioquellen Szenen zu wechseln.\nSo kann zum Beispiel automatisch zu einer Szene gewechselt werden, wenn die Lautstärke eines Mikrofons eine konfigurierte Schwelle überschreitet.\n\nKlicke auf das markierte Plus Symbol, um einen neuen Eintrag hinzuzufügen."
|
||||||
|
|
||||||
|
; Scene Group Tab
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.title="Szenengruppe"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.list="Szenengruppen"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.edit="Szenengruppe bearbeiten"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.edit.name="Name:"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.edit.type="Typ: {{type}}"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.type.count="Anzahl"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.type.time="Zeit"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.type.random="Zufall"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.edit.count="Schreite zur nächsten Szene in dieser Gruppe fort nach {{count}} Szenewechseln"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.edit.time="Schreite zur nächsten Szene in dieser Gruppe fort nach {{time}}"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.edit.random="Wähle eine zufällig Szene in der Liste aus"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.edit.repeat="Beginne von vorne wenn Ende der Szenenliste erreicht ist"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.edit.addScene="Szene hinzufügen"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.add="Szenengruppe hinzufügen"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.defaultname="Szenengruppe %1"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.exists="Szenengruppen- oder Szenenname existiert bereits"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.help="Szenengruppen können, genau wie reguläre Szenen, als Ziel eines Szenenwechsler Eintrags ausgewählt werden.\n\nSzenengruppen bestehen aus einer Liste von Szenen.\nDie aktive Szene der Szenengruppe schreitet abhängig von den konfigurierten Einstellungen durch die Liste der zugewiesenen Szenen fort.\n\nMögliche Einstellungen zum Fortschreiten der aktiven Szene sind:\nAnzahl der Szenenwechsel.\nZeit seit dem letzten Szenenwechsel in der Szenengruppe.\nOder zufällig.\n\nSo kann zum Beispiel eine Szenengruppe welche die folgenden Szenen enthält ...\nSzene 1\nSzene 2\nSzene 3 \n... beim erstem Mal zu \"Szene 1\" wechseln.\nBeim zweiten Mal zu \"Szene 2\".\nDie restlichem Male wechselt die Szenengruppe zu \"Szene 3\".\n\nKlicke auf das markierte Plus Symbol, um eine neuen Szenengruppe hinzuzufügen."
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.scenes.help="Wähle die Szenengruppe, die du bearbeiten möchtest, auf der linken Seite aus.\n\nWähle oben eine Szene aus, die du zur Szenengruppe hinzufügen möchtest, und klicke das Plus Symbol.\n\nDie gleiche Szene kann mehrfach in derselben Szenengruppe auftauchen."
|
||||||
|
|
||||||
|
; Scene Trigger Tab
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.title="Szenen Trigger"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.none="--Trigger auswählen--"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.sceneActive="aktiv ist"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.sceneInactive="nicht aktiv ist"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.sceneLeave="verlassen wird"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.none="--Aktion auswählen--"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startRecording="Aufnahme starten"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.pauseRecording="Aufnahme pausieren"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.unpauseRecording="Aufnahme fortsetzen"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopRecording="Aufnahme stoppen"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopStreaming="Streamen stoppen"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startStreaming="Streamen starten"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startReplayBuffer="Replay Buffer starten"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopReplayBuffer="Replay Buffer stoppen"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.muteSource="Quelle stumm schalten"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.entry="Wenn {{scenes}} {{triggers}} {{actions}} {{audioSources}} nach {{duration}} "
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.help="Dieser Tab ermöglicht es automatisiert Handlungen, wie etwa das Stoppen von einer Aufnahme oder des Streamens, bei einem Szenenwechsel auszuführen."
|
||||||
|
|
||||||
|
|
||||||
|
; Hotkey
|
||||||
|
AdvSceneSwitcher.hotkey.startSwitcherHotkey="Starte den Erweiteren Szenenwechsler"
|
||||||
|
AdvSceneSwitcher.hotkey.stopSwitcherHotkey="Stoppe den Erweiteren Szenenwechsler"
|
||||||
|
AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Starte/Stoppe den Erweiteren Szenenwechsler"
|
||||||
|
|
||||||
|
AdvSceneSwitcher.askBackup="Neue Version des Erweiterten Automatischen Szenenwechslers wurde erkannt.\nSoll ein Backup der alten Einstellungen angelegt werden?"
|
||||||
|
|
||||||
|
AdvSceneSwitcher.close="Schließen"
|
||||||
|
AdvSceneSwitcher.browse="Öffnen"
|
||||||
|
|
||||||
|
AdvSceneSwitcher.selectScene="--Szene auswählen--"
|
||||||
|
AdvSceneSwitcher.selectPreviousScene="Vorhergehende Szene"
|
||||||
|
AdvSceneSwitcher.selectTransition="--Szenenübergang auswählen--"
|
||||||
|
AdvSceneSwitcher.selectWindow="--Fenster auswählen--"
|
||||||
|
AdvSceneSwitcher.selectAudioSource="--Audio Quelle auswählen--"
|
||||||
|
AdvSceneSwitcher.selectMediaSource="--Medien Quelle auswählen--"
|
||||||
|
AdvSceneSwitcher.selectProcess="--Prozess auswählen--"
|
||||||
|
AdvSceneSwitcher.enterPath="--Pfad eingeben--"
|
||||||
|
AdvSceneSwitcher.enterText="--Text eingeben--"
|
||||||
|
AdvSceneSwitcher.invaildEntriesWillNotBeSaved="Ungültige Einträge werden nicht gespeichert"
|
||||||
|
AdvSceneSwitcher.selectWindowTip="Benutze \"OBS\" um das OBS-Studio Fenster auszuwählen\nBenutze\"Task Switching\"um die ALT + TAB Tastenkombination auszuwählen"
|
||||||
|
|
||||||
|
AdvSceneSwitcher.status.active="Aktiv"
|
||||||
|
AdvSceneSwitcher.status.inactive="Inaktiv"
|
||||||
|
|
||||||
|
AdvSceneSwitcher.unit.milliseconds="Millisekunden"
|
||||||
|
AdvSceneSwitcher.unit.secends="Sekunden"
|
||||||
|
AdvSceneSwitcher.unit.minutes="Minuten"
|
||||||
|
AdvSceneSwitcher.unit.hours="Stunden"
|
||||||
267
data/locale/en-US.ini
Normal file
267
data/locale/en-US.ini
Normal file
@@ -0,0 +1,267 @@
|
|||||||
|
AdvSceneSwitcher.pluginName="Advanced Scene Switcher"
|
||||||
|
AdvSceneSwitcher.windowTitle="Advanced Scene Switcher"
|
||||||
|
|
||||||
|
; General Tab
|
||||||
|
AdvSceneSwitcher.generalTab.title="General"
|
||||||
|
AdvSceneSwitcher.generalTab.status="Status"
|
||||||
|
AdvSceneSwitcher.generalTab.status.hotkeytips="Hotkeys can be defined in the OBS settings"
|
||||||
|
AdvSceneSwitcher.generalTab.status.currentStatus="Advanced Scene Switcher is:"
|
||||||
|
AdvSceneSwitcher.generalTab.status.onStartup="On startup of OBS:"
|
||||||
|
AdvSceneSwitcher.generalTab.status.onStartup.asLastRun="Start the scene switcher if it was running"
|
||||||
|
AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Always start the scene switcher"
|
||||||
|
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Do not start the scene switcher"
|
||||||
|
AdvSceneSwitcher.generalTab.status.start="Start"
|
||||||
|
AdvSceneSwitcher.generalTab.status.stop="Stop"
|
||||||
|
AdvSceneSwitcher.generalTab.status.autoStart="Automatically start the scene switcher when:"
|
||||||
|
AdvSceneSwitcher.generalTab.status.autoStart.never="Never"
|
||||||
|
AdvSceneSwitcher.generalTab.status.autoStart.recording="Recording"
|
||||||
|
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Streaming"
|
||||||
|
AdvSceneSwitcher.generalTab.status.autoStart.recordingAndStreaming="Recording or Streaming"
|
||||||
|
AdvSceneSwitcher.generalTab.status.checkInterval="Check switch conditions every"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior="General behavior"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet="If no switch condition is met for"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.onNoMetDelayTooltip="Will only ever be as accurate as the configured check interval."
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.dontSwitch="Don't switch"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchToRandom="Switch to any scene in Random tab"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchTo="Switch to:"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.cooldown="After a match do not switch scenes for"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint="During this time potential matches will be ignored!"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Enable verbose logging"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="Disable UI hints"
|
||||||
|
AdvSceneSwitcher.generalTab.priority="Priority"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.description="Switching methods priority (Highest priority is at the top)"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.threadPriority="Use thread priority"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.threadPriorityNotice="(Raising the priority above \"Normal\" is not recommended)"
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings="Save / load settings"
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="Export"
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Import"
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Export Advanced Scene Switcher settings to file ..."
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Import Advanced Scene Switcher settings from file ..."
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Text files (*.txt)"
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="Advanced Scene Switcher failed to import settings"
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Advanced Scene Switcher settings imported successfully"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.fileContent="File Content"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.sceneSequence="Scene Sequence"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.idleDetection="Idle Detection"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.executable="Executable"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.screenRegion="Screen Region"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.windowTitle="Window Title"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.media="Media"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.time="Time"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.audio="Audio"
|
||||||
|
|
||||||
|
; Transition Tab
|
||||||
|
AdvSceneSwitcher.transitionTab.title="Transition"
|
||||||
|
AdvSceneSwitcher.transitionTab.transitionOverride="Scene transitions defined in the scene switcher take priority over Transition Overrides defined per scene"
|
||||||
|
AdvSceneSwitcher.transitionTab.transitionForAToB="Use transition for automated scene switch from scene A to scene B"
|
||||||
|
AdvSceneSwitcher.transitionTab.transitionsHelp="<html><head/><body><p>These settings <span style=\"font-style:italic;\">only</span> affect transitions caused by the scene switcher - Check out <a href=\"https://obsproject.com/forum/resources/transition-table.1174/\"><span style=\" text-decoration: underline; color:#268bd2;\">Transition Table</span></a> if you want to configure this for manual scene changes.<br/>Settings defined here take priority over transition settings configured elsewhere in the scene switcher.<br/><br/>Click the plus symbol below to add a new entry.</p></body></html>"
|
||||||
|
AdvSceneSwitcher.transitionTab.defaultTransition="Change transition if scene is active"
|
||||||
|
AdvSceneSwitcher.transitionTab.entry="Switch from {{scenes}} to {{scenes2}} using {{transitions}}"
|
||||||
|
AdvSceneSwitcher.transitionTab.defaultTransitionEntry="When scene {{scenes}} is active change default scene transition to {{transitions}}"
|
||||||
|
AdvSceneSwitcher.transitionTab.defaultTransitionsHelp="Click on the plus symbol to add an entry."
|
||||||
|
|
||||||
|
; Pause Scenes Tab
|
||||||
|
AdvSceneSwitcher.pauseTab.title="Pause"
|
||||||
|
AdvSceneSwitcher.pauseTab.pauseOnScene="Pause the Scene Switcher on scene"
|
||||||
|
AdvSceneSwitcher.pauseTab.pauseInFocus1="Pause the Scene Switcher when "
|
||||||
|
AdvSceneSwitcher.pauseTab.pauseInFocus2="is in focus"
|
||||||
|
AdvSceneSwitcher.pauseTab.pauseTypeScene="scene is active"
|
||||||
|
AdvSceneSwitcher.pauseTab.pauseTypeWindow="window is in focus"
|
||||||
|
AdvSceneSwitcher.pauseTab.pauseTargetAll="all"
|
||||||
|
AdvSceneSwitcher.pauseTab.pauseEntry="Pause {{pauseTargets}} checks when {{pauseTypes}} {{scenes}} {{windows}}"
|
||||||
|
AdvSceneSwitcher.pauseTab.help="On this tab you can configure to pause individual switching methods if a scene is active or window is in focus.\n\nClick on the highlighted plus symbol to continue."
|
||||||
|
|
||||||
|
; Window Title Tab
|
||||||
|
AdvSceneSwitcher.windowTitleTab.title="Title"
|
||||||
|
AdvSceneSwitcher.windowTitleTab.regexrDescription="<html><head/><body><p>Enter either direct window titles or valid regex. You can check syntax and matches for regular expressions using <a href=\"https://regexr.com\"><span style=\" text-decoration: underline; color:#268bd2;\">RegExr</span></a></p></body></html>"
|
||||||
|
AdvSceneSwitcher.windowTitleTab.stayInFocus1="Ignore this window name"
|
||||||
|
AdvSceneSwitcher.windowTitleTab.stayInFocus2=" "
|
||||||
|
AdvSceneSwitcher.windowTitleTab.fullscreen="if fullscreen"
|
||||||
|
AdvSceneSwitcher.windowTitleTab.maximized="if maximized"
|
||||||
|
AdvSceneSwitcher.windowTitleTab.focused="if focused"
|
||||||
|
AdvSceneSwitcher.windowTitleTab.entry="{{windows}} {{scenes}} {{transitions}} {{fullscreen}} {{maximized}} {{focused}}"
|
||||||
|
AdvSceneSwitcher.windowTitleTab.windowsHelp="Switch scenes based on the window title of running applications.\nThe following additional conditions can be selected:\nThe window is Fullscreen\nThe window is maximized\nThe window is focused\n\nClick on the highlighted plus symbol to continue."
|
||||||
|
AdvSceneSwitcher.windowTitleTab.ignoreWindowsHelp="If a window title is ignored the scene switcher will act as if the previously selected window is still in focus.\nThis will allow you to avoid scene switches, if you frequently switch to a different window, which shall not trigger a scene change.\n\nChoose a window or enter a window title above and click on the plus symbol below to add it to the list."
|
||||||
|
|
||||||
|
; Executable Tab
|
||||||
|
AdvSceneSwitcher.executableTab.title="Executable"
|
||||||
|
AdvSceneSwitcher.executableTab.implemented="Implemented by dasOven"
|
||||||
|
AdvSceneSwitcher.executableTab.requiresFocus="only if focused"
|
||||||
|
AdvSceneSwitcher.executableTab.entry="When {{processes}} is running switch to {{scenes}} using {{transitions}} {{requiresFocus}}"
|
||||||
|
AdvSceneSwitcher.executableTab.help="This tab will allow you to automatically switch scenes if a process is running.\nThis can be useful in situations where the window name could change or is not known.\n\nClick on the highlighted plus symbol to continue."
|
||||||
|
|
||||||
|
; Screen Region Tab
|
||||||
|
AdvSceneSwitcher.screenRegionTab.title="Region"
|
||||||
|
AdvSceneSwitcher.screenRegionTab.currentPosition="Cursor is currently at:"
|
||||||
|
AdvSceneSwitcher.screenRegionTab.showGuideFrames="Show guide frames"
|
||||||
|
AdvSceneSwitcher.screenRegionTab.hideGuideFrames="Hide guide frames"
|
||||||
|
AdvSceneSwitcher.screenRegionTab.excludeScenes.None="No selection"
|
||||||
|
AdvSceneSwitcher.screenRegionTab.entry="If cursor is in {{minX}} {{minY}} x {{maxX}} {{maxY}} switch to {{scenes}} using {{transitions}} unless in {{excludeScenes}}"
|
||||||
|
AdvSceneSwitcher.screenRegionTab.help="This tab will allow you to automatically switch scenes based on the current position of your mouse cursor.\n\nClick on the highlighted plus symbol to continue."
|
||||||
|
|
||||||
|
; Media Tab
|
||||||
|
AdvSceneSwitcher.mediaTab.title="Media"
|
||||||
|
AdvSceneSwitcher.mediaTab.implemented="Implemented by Exeldro"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.none="None"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.playing="Playing"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.opening="Opening"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.buffering="Buffering"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.Paused="Paused"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.stopped="Stopped"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.ended="Ended"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.error="Error"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.playedToEnd="Played to end"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.any="Any"
|
||||||
|
AdvSceneSwitcher.mediaTab.timeRestriction.none="None"
|
||||||
|
AdvSceneSwitcher.mediaTab.timeRestriction.shorter="Time shorter"
|
||||||
|
AdvSceneSwitcher.mediaTab.timeRestriction.longer="Time longer"
|
||||||
|
AdvSceneSwitcher.mediaTab.timeRestriction.remainShorter="Time remaining shorter"
|
||||||
|
AdvSceneSwitcher.mediaTab.timeRestriction.remainLonger="Time remaining longer"
|
||||||
|
AdvSceneSwitcher.mediaTab.entry="When {{mediaSources}} state is {{states}} and {{timeRestrictions}} {{time}} switch to {{scenes}} using {{transitions}}"
|
||||||
|
AdvSceneSwitcher.mediaTab.help="This tab will allow you to switch scenes based on the states of media sources.\nFor example, you can automatically switch back to the previous scene once the selected media sourced ended its playback.\n\nClick on the highlighted plus symbol to continue."
|
||||||
|
|
||||||
|
; File Tab
|
||||||
|
AdvSceneSwitcher.fileTab.title="File"
|
||||||
|
AdvSceneSwitcher.fileTab.readWriteSceneFile="Read / write scene from / to file"
|
||||||
|
AdvSceneSwitcher.fileTab.currentSceneOutputFile="Write the name of the current scene to this file:"
|
||||||
|
AdvSceneSwitcher.fileTab.switchSceneBaseOnFile="Enable switching of scenes based on file input"
|
||||||
|
AdvSceneSwitcher.fileTab.switchSceneNameInputFile="Read scene name to be switched to from this file:"
|
||||||
|
AdvSceneSwitcher.fileTab.switchSceneBaseOnFileContent="Switch scene based on file contents"
|
||||||
|
AdvSceneSwitcher.fileTab.remoteFileWarning="Please note that if you choose the remote option the scene switcher will try to access the remote location every x ms as specified on the General tab!"
|
||||||
|
AdvSceneSwitcher.fileTab.remoteFileWarning1="Note that the scene switcher will try to access the remote location every "
|
||||||
|
AdvSceneSwitcher.fileTab.remoteFileWarning2="ms"
|
||||||
|
AdvSceneSwitcher.fileTab.libcurlWarning="Failed to load libcurl! Accessing remote files will not be possible!"
|
||||||
|
AdvSceneSwitcher.fileTab.selectWrite="Select a file to write to ..."
|
||||||
|
AdvSceneSwitcher.fileTab.selectRead="Select a file to read from ..."
|
||||||
|
AdvSceneSwitcher.fileTab.textFileType="Text files (*.txt)"
|
||||||
|
AdvSceneSwitcher.fileTab.anyFileType="Any files (*.*)"
|
||||||
|
AdvSceneSwitcher.fileTab.remote="remote file"
|
||||||
|
AdvSceneSwitcher.fileTab.local="local file"
|
||||||
|
AdvSceneSwitcher.fileTab.useRegExp="use regular expressions (pattern matching)"
|
||||||
|
AdvSceneSwitcher.fileTab.checkfileContentTime="if modification date changed"
|
||||||
|
AdvSceneSwitcher.fileTab.checkfileContent="if content changed"
|
||||||
|
AdvSceneSwitcher.fileTab.entry="Switch to {{scenes}} using {{transitions}} if content of {{fileType}} {{filePath}} {{browseButton}} matches:"
|
||||||
|
AdvSceneSwitcher.fileTab.entry2="{{matchText}}"
|
||||||
|
AdvSceneSwitcher.fileTab.entry3="{{useRegex}} {{checkModificationDate}} {{checkFileContent}}"
|
||||||
|
AdvSceneSwitcher.fileTab.help="This tab will allow you to automatically switch scenes based on the content of remote or local files.\n\nClick on the highlighted plus symbol to continue."
|
||||||
|
|
||||||
|
; Random Tab
|
||||||
|
AdvSceneSwitcher.randomTab.title="Random"
|
||||||
|
AdvSceneSwitcher.randomTab.randomDisabledWarning="Functionality disabled - To activate select \"If no switch condition is met switch to any scene in Random tab\" on General tab"
|
||||||
|
AdvSceneSwitcher.randomTab.entry="If no switch condition is met switch to {{scenes}} using {{transitions}} for {{delay}}"
|
||||||
|
AdvSceneSwitcher.randomTab.help="The scene switcher will randomly choose an entry on this tab to switch to for the configured time.\nNote that the same entry will not be chosen twice in a row.\n\nClick on the highlighted plus symbol to continue."
|
||||||
|
|
||||||
|
; Time Tab
|
||||||
|
AdvSceneSwitcher.timeTab.title="Time"
|
||||||
|
AdvSceneSwitcher.timeTab.anyDay="On any day"
|
||||||
|
AdvSceneSwitcher.timeTab.mondays="Mondays"
|
||||||
|
AdvSceneSwitcher.timeTab.tuesdays="Tuesdays"
|
||||||
|
AdvSceneSwitcher.timeTab.wednesdays="Wednesdays"
|
||||||
|
AdvSceneSwitcher.timeTab.thursdays="Thursdays"
|
||||||
|
AdvSceneSwitcher.timeTab.fridays="Fridays"
|
||||||
|
AdvSceneSwitcher.timeTab.saturdays="Saturdays"
|
||||||
|
AdvSceneSwitcher.timeTab.sundays="Sundays"
|
||||||
|
AdvSceneSwitcher.timeTab.afterstart="After streaming/recording start"
|
||||||
|
AdvSceneSwitcher.timeTab.afterstart.tip="The time relative to the start of streaming / recording will be used"
|
||||||
|
AdvSceneSwitcher.timeTab.entry="{{triggers}} at {{time}} switch to {{scenes}} using {{transitions}}"
|
||||||
|
AdvSceneSwitcher.timeTab.help="This tab will allow you to automatically switch to a different scene based on the current local time.\n\nNote that the scene switcher will only switch scenes at the exact time you specified.\nMake sure you have configured the priority settings on the General tab to your liking so the selected time point will not be missed due to other switching methods having a higher priority.\n\nClick on the highlighted plus symbol to continue."
|
||||||
|
|
||||||
|
; Idle Tab
|
||||||
|
AdvSceneSwitcher.idleTab.title="Idle"
|
||||||
|
AdvSceneSwitcher.idleTab.enable="Enable Idle Detection"
|
||||||
|
AdvSceneSwitcher.idleTab.idleswitch="After {{duration}} of no keyboard or mouse inputs switch to scene {{scenes}} using the {{transitions}}"
|
||||||
|
AdvSceneSwitcher.idleTab.dontSwitchIfFocus1="Do not switch if"
|
||||||
|
AdvSceneSwitcher.idleTab.dontSwitchIfFocus2="is in focus"
|
||||||
|
|
||||||
|
; Scene Sequence Tab
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.title="Sequence"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.description="A sequence of automatic scene switches can be cancelled by either pausing/stopping the scene switcher or manually switching to a different scene"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.save="Save scene sequences to file"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.load="Load scene sequences from file"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.saveTitle="Save Scene Sequence to file ..."
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.loadTitle="Select a file to read Scene Sequence from ..."
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.loadFail="Advanced Scene Switcher failed to import settings!"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.loadSuccess="Advanced Scene Switcher settings imported successfully!"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.fileType="Text files (*.txt)"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.interruptible="interruptible"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.interruptibleHint="Other switching methods are allowed to interrupt this scene sequence"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.entry="When {{startScenes}} is active switch to {{scenes}} after {{delay}} {{delayUnits}} using {{transitions}} {{interruptible}}"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.help="This tab will allow you to automatically switch to a different scene if a scene was active for a configured period of time.\nFor example, you could automatically cycle back and forth between two scenes automatically.\n\nClick on the highlighted plus symbol to continue."
|
||||||
|
|
||||||
|
; Audio Tab
|
||||||
|
AdvSceneSwitcher.audioTab.title="Audio"
|
||||||
|
AdvSceneSwitcher.audioTab.condition.above="above"
|
||||||
|
AdvSceneSwitcher.audioTab.condition.below="below"
|
||||||
|
AdvSceneSwitcher.audioTab.entry="When the volume of {{audioSources}} is {{condition}} {{volumeWidget}} for {{duration}} switch to {{scenes}} using {{transitions}}"
|
||||||
|
AdvSceneSwitcher.audioTab.multiMatchfallbackCondition="If multiple entries match ..."
|
||||||
|
AdvSceneSwitcher.audioTab.multiMatchfallback="... for {{duration}} switch to {{scenes}} using {{transitions}}"
|
||||||
|
AdvSceneSwitcher.audioTab.help="This tab will allow you to switch scenes based on the volume of sources.\nFor example, you could automatically switch to a different scene if the volume of your microphone reaches a certain threshold.\n\nClick on the highlighted plus symbol to continue."
|
||||||
|
|
||||||
|
; Scene Group Tab
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.title="Scene Group"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.list="Scene Groups"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.edit="Edit Scene Groups"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.edit.name="Name:"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.edit.type="Type: {{type}}"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.type.count="Count"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.type.time="Time"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.type.random="Random"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.edit.count="Advance to next scene in list after {{count}} matches"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.edit.time="Advance to next scene in list after {{time}} has passed"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.edit.random="Choose next scene in list at random"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.edit.repeat="Start from beginning if end of scene list is reached"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.edit.addScene="Add scene"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.add="Add Scene Group"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.defaultname="Scene Group %1"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.exists="Scene Group or Scene name exists already"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.help="Scene Groups can be selected as a target just like a regular scene.\n\nAs the name suggests a scene group is a collection of multiple scenes.\nThe scene group will advance through the list of its assigned scenes depending on the configured settings, which can be found on the right side.\n\nYou can configure the scene group to advance to the next scene in the list:\nAfter a number of times the scene group is selected as a target.\nAfter a certain amount of time has passed.\nOr randomly.\n\nFor example, a scene group containing the scenes ...\nScene 1\nScene 2\nScene 3 \n... will activate \"Scene 1\" the first time it is selected as a target.\nThe second time it will activate \"Scene 2\".\nThe remaining times \"Scene 3\" will be activated.\n\nClick the highlighted plus symbol below to add a new scene group."
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.scenes.help="Select the scene group you want to modify on the left.\n\nSelect a scene to add to this scene group by selecting the scene above and clicking the plus symbol below.\n\nA scene can be added multiple times to the same scene group."
|
||||||
|
|
||||||
|
; Scene Trigger Tab
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.title="Scene Triggers"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.none="--select trigger--"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.sceneActive="is active"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.sceneInactive="is not active"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.sceneLeave="switched away from"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.none="--select action--"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startRecording="start recording"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.pauseRecording="pause recording"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.unpauseRecording="unpause recording"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopRecording="stop recording"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopStreaming="stop streaming"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startStreaming="start streaming"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startReplayBuffer="start replay buffer"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopReplayBuffer="stop replay buffer"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.muteSource="mute source"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.entry="When {{scenes}} {{triggers}} {{actions}} {{audioSources}} after {{duration}}"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.help="This tab allows you to trigger actions on scene changes, like stopping recording or streaming."
|
||||||
|
|
||||||
|
; Hotkey
|
||||||
|
AdvSceneSwitcher.hotkey.startSwitcherHotkey="Start the Advanced Scene Switcher"
|
||||||
|
AdvSceneSwitcher.hotkey.stopSwitcherHotkey="Stop the Advanced Scene Switcher"
|
||||||
|
AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Toggle Start/Stop for the Advanced Scene Switcher"
|
||||||
|
|
||||||
|
AdvSceneSwitcher.askBackup="Detected a new version of the Advanced Scene Switcher.\nShould a backup of the old settings be created?"
|
||||||
|
|
||||||
|
AdvSceneSwitcher.close="Close"
|
||||||
|
AdvSceneSwitcher.browse="Browse"
|
||||||
|
|
||||||
|
AdvSceneSwitcher.selectScene="--select scene--"
|
||||||
|
AdvSceneSwitcher.selectPreviousScene="Previous Scene"
|
||||||
|
AdvSceneSwitcher.selectTransition="--select transition--"
|
||||||
|
AdvSceneSwitcher.selectWindow="--select window--"
|
||||||
|
AdvSceneSwitcher.selectAudioSource="--select audio source--"
|
||||||
|
AdvSceneSwitcher.selectMediaSource="--select media source--"
|
||||||
|
AdvSceneSwitcher.selectProcess="--select process--"
|
||||||
|
AdvSceneSwitcher.enterPath="--enter path--"
|
||||||
|
AdvSceneSwitcher.enterText="--enter text--"
|
||||||
|
AdvSceneSwitcher.invaildEntriesWillNotBeSaved="invalid entries will not be saved"
|
||||||
|
AdvSceneSwitcher.selectWindowTip="Use \"OBS\" to specify OBS window\nUse \"Task Switching\"to specify ALT + TAB"
|
||||||
|
|
||||||
|
AdvSceneSwitcher.status.active="Active"
|
||||||
|
AdvSceneSwitcher.status.inactive="Inactive"
|
||||||
|
|
||||||
|
AdvSceneSwitcher.unit.milliseconds="milliseconds"
|
||||||
|
AdvSceneSwitcher.unit.secends="seconds"
|
||||||
|
AdvSceneSwitcher.unit.minutes="minutes"
|
||||||
|
AdvSceneSwitcher.unit.hours="hours"
|
||||||
203
data/locale/zh-CN.ini
Normal file
203
data/locale/zh-CN.ini
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
AdvSceneSwitcher.pluginName="高级场景切换器"
|
||||||
|
AdvSceneSwitcher.windowTitle="高级场景切换器"
|
||||||
|
|
||||||
|
; General Tab
|
||||||
|
AdvSceneSwitcher.generalTab.title="通用"
|
||||||
|
AdvSceneSwitcher.generalTab.status="状态"
|
||||||
|
AdvSceneSwitcher.generalTab.status.hotkeytips="快捷键可在OBS设置中设置"
|
||||||
|
AdvSceneSwitcher.generalTab.status.currentStatus="当前状态:"
|
||||||
|
AdvSceneSwitcher.generalTab.status.onStartup="在OBS启动时"
|
||||||
|
AdvSceneSwitcher.generalTab.status.onStartup.asLastRun="按照最后运行时的状态"
|
||||||
|
AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="总是自动启动"
|
||||||
|
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="不要启动"
|
||||||
|
AdvSceneSwitcher.generalTab.status.start="启动"
|
||||||
|
AdvSceneSwitcher.generalTab.status.stop="停止"
|
||||||
|
AdvSceneSwitcher.generalTab.status.autoStart.recording="录制"
|
||||||
|
AdvSceneSwitcher.generalTab.status.autoStart.streaming="推流"
|
||||||
|
AdvSceneSwitcher.generalTab.status.autoStart.recordingAndStreaming="录制和推流"
|
||||||
|
AdvSceneSwitcher.generalTab.status.checkInterval="检查切换条件时间间隔"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior="一般表现"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet="如果不符合任何切换条件"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.onNoMetDelayTooltip="时间精度最高只能达到配置的轮询间隔"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.dontSwitch="不切换"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchToRandom="切换到随机场景列表中任意随机场景"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchTo="切换到"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="详细日志输出"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="禁用UI提示"
|
||||||
|
AdvSceneSwitcher.generalTab.priority="优先级"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.description="切换场景优先级 (最上方的项优先级最高)"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.threadPriority="使用线程优先级"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.threadPriorityNotice="(不推荐使用高于 \"Normal\" 的优先级)"
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings="导出或导入设置"
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="导出设置"
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="导入设置"
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="导出高级场景切换器到文件..."
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="导入高级场景切换器到文件..."
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="文本文件 (*.txt)"
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="高级场景切换器导入设置失败"
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="高级场景切换器导入设置成功"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.fileContent="文件内容"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.sceneSequence="场景序列"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.idleDetection="闲置检测"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.executable="程序"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.screenRegion="屏幕区域"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.windowTitle="窗口标题"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.media="媒体"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.time="时间"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.audio="音频"
|
||||||
|
|
||||||
|
; Transition Tab
|
||||||
|
AdvSceneSwitcher.transitionTab.title="转场特效"
|
||||||
|
AdvSceneSwitcher.transitionTab.transitionOverride="在场景切换器中设定的转场特效优先级高于场景设定的转场特效"
|
||||||
|
AdvSceneSwitcher.transitionTab.transitionForAToB="当自动从场景A切换到场景B时使用的转场特效"
|
||||||
|
AdvSceneSwitcher.transitionTab.transitionsHelp="<html><head/><body><p>这里的设定<span style=\"font-style:bold;\">只影响由场景切换器引起的转场有效</span>,不影响你手动的引起的转场。<br/>在这里设定的转场特效优先级高于场景切换器其他地方设置的<br/><br/>Click the plus symbol below to continue.</p></body></html>"
|
||||||
|
AdvSceneSwitcher.transitionTab.defaultTransition="当切换到这个场景时修改默认转场特效"
|
||||||
|
AdvSceneSwitcher.transitionTab.switchDefaultLabel="活跃时切换默认转场特效为"
|
||||||
|
AdvSceneSwitcher.transitionTab.entry="从场景 {{scenes}} 切换到场景 {{scenes2}} 时使用转场特效 {{transitions}}"
|
||||||
|
AdvSceneSwitcher.transitionTab.defaultTransitionEntry="当场景 {{scenes}} 被激活时更改默认转场特效为 {{transitions}}"
|
||||||
|
|
||||||
|
; Pause Scenes Tab
|
||||||
|
AdvSceneSwitcher.pauseTab.title="暂停"
|
||||||
|
AdvSceneSwitcher.pauseTab.pauseOnScene="当切换到这个场景时暂停场景切换器"
|
||||||
|
AdvSceneSwitcher.pauseTab.pauseInFocus1="当窗口"
|
||||||
|
AdvSceneSwitcher.pauseTab.pauseInFocus2="获得焦点时暂停场景切换器"
|
||||||
|
|
||||||
|
; Window Title Tab
|
||||||
|
AdvSceneSwitcher.windowTitleTab.title="窗口标题"
|
||||||
|
AdvSceneSwitcher.windowTitleTab.regexrDescription="<html><head/><body><p>你可以直接输入窗口标题或正则表达式. 你可以使用<a href=\"https://regexr.com\"><span style=\" text-decoration: underline; color:#268bd2;\">RegExr</span></a>来检查验证你的正则表达式</p></body></html>"
|
||||||
|
AdvSceneSwitcher.windowTitleTab.stayInFocus1="当前焦点窗口标题为"
|
||||||
|
AdvSceneSwitcher.windowTitleTab.stayInFocus2="时保持当前场景"
|
||||||
|
AdvSceneSwitcher.windowTitleTab.fullscreen="全屏时"
|
||||||
|
AdvSceneSwitcher.windowTitleTab.maximized="最大化时"
|
||||||
|
AdvSceneSwitcher.windowTitleTab.focused="窗口聚集时"
|
||||||
|
AdvSceneSwitcher.windowTitleTab.entry="{{windows}} {{scenes}} {{transitions}} {{fullscreen}} {{maximized}} {{focused}}"
|
||||||
|
|
||||||
|
; Executable Tab
|
||||||
|
AdvSceneSwitcher.executableTab.title="程序"
|
||||||
|
AdvSceneSwitcher.executableTab.implemented="感谢dasOven的实现"
|
||||||
|
AdvSceneSwitcher.executableTab.requiresFocus="仅获得焦点时"
|
||||||
|
AdvSceneSwitcher.executableTab.entry="当 {{processes}} 正在运行时使用 {{transitions}} 切换到 {{scenes}} {{requiresFocus}}"
|
||||||
|
|
||||||
|
; Screen Region Tab
|
||||||
|
AdvSceneSwitcher.screenRegionTab.title="屏幕区域"
|
||||||
|
AdvSceneSwitcher.screenRegionTab.currentPosition="鼠标当前位置:"
|
||||||
|
AdvSceneSwitcher.screenRegionTab.showGuideFrames="显示区域边界"
|
||||||
|
AdvSceneSwitcher.screenRegionTab.hideGuideFrames="隐藏区域边界"
|
||||||
|
AdvSceneSwitcher.screenRegionTab.entry="如果鼠标在 {{minX}} {{minY}} x {{maxX}} {{maxY}} 使用转场特效 {{transitions}} 切换到场景 {{scenes}} unless in {{excludeScenes}}"
|
||||||
|
|
||||||
|
; Media Tab
|
||||||
|
AdvSceneSwitcher.mediaTab.title="媒体"
|
||||||
|
AdvSceneSwitcher.mediaTab.implemented="感谢Exeldro的实现"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.none="空"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.playing="播放中"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.opening="正在打开"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.buffering="缓冲中"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.Paused="暂停"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.stopped="停止"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.ended="结束"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.error="错误"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.any="任意"
|
||||||
|
AdvSceneSwitcher.mediaTab.timeRestriction.none="无"
|
||||||
|
AdvSceneSwitcher.mediaTab.timeRestriction.shorter="播放时间小于"
|
||||||
|
AdvSceneSwitcher.mediaTab.timeRestriction.longer="播放时间大于"
|
||||||
|
AdvSceneSwitcher.mediaTab.timeRestriction.remainShorter="剩余时间少于"
|
||||||
|
AdvSceneSwitcher.mediaTab.timeRestriction.remainLonger="剩余时间多于"
|
||||||
|
AdvSceneSwitcher.mediaTab.entry="当 {{mediaSources}} 状态为 {{states}} 并且 {{timeRestrictions}} {{time}} 时使用转场特效 {{transitions}} 切换到场景 {{scenes}}"
|
||||||
|
|
||||||
|
; File Tab
|
||||||
|
AdvSceneSwitcher.fileTab.title="文件"
|
||||||
|
AdvSceneSwitcher.fileTab.readWriteSceneFile="从文件加载或保存当前场景名"
|
||||||
|
AdvSceneSwitcher.fileTab.currentSceneOutputFile="将当前场景写入到这个文件:"
|
||||||
|
AdvSceneSwitcher.fileTab.switchSceneBaseOnFile="启用从文件读取应切换到的场景名"
|
||||||
|
AdvSceneSwitcher.fileTab.switchSceneNameInputFile="从这个文件读取应切换到的场景名:"
|
||||||
|
AdvSceneSwitcher.fileTab.switchSceneBaseOnFileContent="根据文件内容切换场景"
|
||||||
|
AdvSceneSwitcher.fileTab.remoteFileWarning="请注意 如果你使用网络文件,场景切换器会按照你在通用页设置的间隔时间尝试访问网络文件!"
|
||||||
|
AdvSceneSwitcher.fileTab.remoteFileWarning1="注意,场景切换器会每 "
|
||||||
|
AdvSceneSwitcher.fileTab.remoteFileWarning2="毫秒尝试访问网络文件"
|
||||||
|
AdvSceneSwitcher.fileTab.libcurlWarning="无法加载 libcurl 库! 访问网络文件功能将不可用!"
|
||||||
|
AdvSceneSwitcher.fileTab.selectWrite="写入到文件..."
|
||||||
|
AdvSceneSwitcher.fileTab.selectRead="从文件读取..."
|
||||||
|
AdvSceneSwitcher.fileTab.textFileType="文本文件 (*.txt)"
|
||||||
|
AdvSceneSwitcher.fileTab.anyFileType="任意文件 (*.*)"
|
||||||
|
AdvSceneSwitcher.fileTab.remote="网络"
|
||||||
|
AdvSceneSwitcher.fileTab.local="本地"
|
||||||
|
AdvSceneSwitcher.fileTab.useRegExp="使用正则表达式(模式匹配)"
|
||||||
|
AdvSceneSwitcher.fileTab.checkfileContentTime="仅当文件修改时间改变时检查文件内容"
|
||||||
|
AdvSceneSwitcher.fileTab.checkfileContent="仅当文件发生修改时"
|
||||||
|
AdvSceneSwitcher.fileTab.entry="如果 {{fileType}} 文件 {{filePath}} {{browseButton}} 匹配下列规则,使用转场特效 {{transitions}} 切换到场景 {{scenes}}"
|
||||||
|
AdvSceneSwitcher.fileTab.entry2="{{matchText}}"
|
||||||
|
AdvSceneSwitcher.fileTab.entry3="{{useRegex}} {{checkModificationDate}} {{checkFileContent}}"
|
||||||
|
|
||||||
|
; Random Tab
|
||||||
|
AdvSceneSwitcher.randomTab.title="随机场景列表"
|
||||||
|
AdvSceneSwitcher.randomTab.randomDisabledWarning="功能已被禁用 - 可通过在通用页设置\"如果不符合任何切换条件切换到随机场景列表中任意随机场景\"启用"
|
||||||
|
AdvSceneSwitcher.randomTab.entry="如果没有切换器条件满足,使用转场特效 {{transitions}} 切换到场景 {{scenes}} 并停留 {{delay}}"
|
||||||
|
|
||||||
|
; Time Tab
|
||||||
|
AdvSceneSwitcher.timeTab.title="时间"
|
||||||
|
AdvSceneSwitcher.timeTab.anyDay="每天"
|
||||||
|
AdvSceneSwitcher.timeTab.mondays="每周一"
|
||||||
|
AdvSceneSwitcher.timeTab.tuesdays="每周二"
|
||||||
|
AdvSceneSwitcher.timeTab.wednesdays="每周三"
|
||||||
|
AdvSceneSwitcher.timeTab.thursdays="每周四"
|
||||||
|
AdvSceneSwitcher.timeTab.fridays="每周五"
|
||||||
|
AdvSceneSwitcher.timeTab.saturdays="每周六"
|
||||||
|
AdvSceneSwitcher.timeTab.sundays="每周日"
|
||||||
|
AdvSceneSwitcher.timeTab.afterstart="推流或录制开始后"
|
||||||
|
AdvSceneSwitcher.timeTab.afterstart.tip="相对于直播或录制开始之后的时间点"
|
||||||
|
AdvSceneSwitcher.timeTab.entry="{{triggers}} 的 {{time}} 使用转场特效 {{transitions}} 切换到场景 {{scenes}}"
|
||||||
|
|
||||||
|
; Idle Tab
|
||||||
|
AdvSceneSwitcher.idleTab.title="闲置检测"
|
||||||
|
AdvSceneSwitcher.idleTab.enable="启用闲置检测"
|
||||||
|
AdvSceneSwitcher.idleTab.condition1="超过"
|
||||||
|
AdvSceneSwitcher.idleTab.condition2="没有鼠标或键盘操作"
|
||||||
|
AdvSceneSwitcher.idleTab.switchToScene="切换到场景"
|
||||||
|
AdvSceneSwitcher.idleTab.usingTransition1="使用"
|
||||||
|
AdvSceneSwitcher.idleTab.usingTransition2="转场特效"
|
||||||
|
AdvSceneSwitcher.idleTab.dontSwitchIfFocus1="如果当前窗口焦点在"
|
||||||
|
AdvSceneSwitcher.idleTab.dontSwitchIfFocus2="时不切换"
|
||||||
|
|
||||||
|
; Scene Sequence Tab
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.title="场景序列"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.description="自动场景序列可以通过暂停或停止场景切换器或者手动切换到其他场景来取消"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.save="保存当前序列到文件"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.load="从文件加载序列"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.saveTitle="保存当前序列到文件 ..."
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.loadTitle="从文件加载序列 ..."
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.loadFail="导入失败"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.loadSuccess="导入失败成功"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.fileType="文本文件 (*.txt)"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.entry="当场景 {{startScenes}} 被激活 {{delay}} {{delayUnits}}后使用转场特效 {{transitions}} 切换到场景 {{scenes}} {{interruptible}}"
|
||||||
|
|
||||||
|
; Audio Tab
|
||||||
|
AdvSceneSwitcher.audioTab.title="音频"
|
||||||
|
AdvSceneSwitcher.audioTab.entry="当{{audioSources}} is {{condition}} {{volumeWidget}} for {{duration}} 使用转场特效 {{transitions}} 切换到场景 {{scenes}}"
|
||||||
|
|
||||||
|
; Hotkey
|
||||||
|
AdvSceneSwitcher.hotkey.startSwitcherHotkey="启动高级场景切换器"
|
||||||
|
AdvSceneSwitcher.hotkey.stopSwitcherHotkey="停止高级场景切换器"
|
||||||
|
AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="切换(启动/停止)高级场景切换器"
|
||||||
|
|
||||||
|
AdvSceneSwitcher.close="关闭"
|
||||||
|
AdvSceneSwitcher.browse="浏览文件"
|
||||||
|
|
||||||
|
AdvSceneSwitcher.selectScene="--选择场景--"
|
||||||
|
AdvSceneSwitcher.selectTransition="--选择转场特效--"
|
||||||
|
AdvSceneSwitcher.selectWindow="--选择窗口--"
|
||||||
|
AdvSceneSwitcher.selectAudioSource="--选择音频源--"
|
||||||
|
AdvSceneSwitcher.selectMediaSource="--选择媒体源--"
|
||||||
|
AdvSceneSwitcher.selectProcess="--选择进程--"
|
||||||
|
AdvSceneSwitcher.enterPath="--输入路径--"
|
||||||
|
AdvSceneSwitcher.enterText="--输入文本--"
|
||||||
|
AdvSceneSwitcher.invaildEntriesWillNotBeSaved="无效项将不会被保存"
|
||||||
|
AdvSceneSwitcher.selectWindowTip="使用 \"OBS\" 来指定OBS窗口\n使用 \"Task Switching\" 来指定 Alt + Tab"
|
||||||
|
|
||||||
|
AdvSceneSwitcher.status.active="运行中"
|
||||||
|
AdvSceneSwitcher.status.inactive="已停止"
|
||||||
|
|
||||||
|
AdvSceneSwitcher.unit.milliseconds="毫秒"
|
||||||
|
AdvSceneSwitcher.unit.secends="秒"
|
||||||
|
AdvSceneSwitcher.unit.minutes="分钟"
|
||||||
|
AdvSceneSwitcher.unit.hours="小时"
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,15 @@
|
|||||||
#include <obs-module.h>
|
#include <obs-module.h>
|
||||||
|
#include <obs-frontend-api.h>
|
||||||
|
|
||||||
OBS_DECLARE_MODULE()
|
OBS_DECLARE_MODULE()
|
||||||
|
OBS_MODULE_USE_DEFAULT_LOCALE("advanced-scene-switcher", "en-US")
|
||||||
|
|
||||||
void InitSceneSwitcher();
|
void InitSceneSwitcher();
|
||||||
void FreeSceneSwitcher();
|
void FreeSceneSwitcher();
|
||||||
|
|
||||||
bool obs_module_load(void)
|
bool obs_module_load(void)
|
||||||
{
|
{
|
||||||
|
obs_frontend_push_ui_translation(obs_module_get_string);
|
||||||
InitSceneSwitcher();
|
InitSceneSwitcher();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,18 +3,21 @@
|
|||||||
#include <QtGui/qstandarditemmodel.h>
|
#include <QtGui/qstandarditemmodel.h>
|
||||||
#include <QPropertyAnimation>
|
#include <QPropertyAnimation>
|
||||||
#include <QGraphicsColorizeEffect>
|
#include <QGraphicsColorizeEffect>
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
#include <obs-module.h>
|
||||||
#include <obs-frontend-api.h>
|
#include <obs-frontend-api.h>
|
||||||
#include <util/util.hpp>
|
#include <util/util.hpp>
|
||||||
|
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
#include "headers/curl-helper.hpp"
|
#include "headers/curl-helper.hpp"
|
||||||
|
#include "headers/version.h"
|
||||||
|
|
||||||
SwitcherData *switcher = nullptr;
|
SwitcherData *switcher = nullptr;
|
||||||
|
|
||||||
/********************************************************************************
|
/******************************************************************************
|
||||||
* Create the Advanced Scene Switcher settings window
|
* Create the Advanced Scene Switcher settings window
|
||||||
********************************************************************************/
|
******************************************************************************/
|
||||||
AdvSceneSwitcher::AdvSceneSwitcher(QWidget *parent)
|
AdvSceneSwitcher::AdvSceneSwitcher(QWidget *parent)
|
||||||
: QDialog(parent), ui(new Ui_AdvSceneSwitcher)
|
: QDialog(parent), ui(new Ui_AdvSceneSwitcher)
|
||||||
{
|
{
|
||||||
@@ -26,8 +29,20 @@ AdvSceneSwitcher::AdvSceneSwitcher(QWidget *parent)
|
|||||||
loadUI();
|
loadUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool translationAvailable()
|
||||||
|
{
|
||||||
|
return !!strcmp(obs_module_text("AdvSceneSwitcher.pluginName"),
|
||||||
|
"AdvSceneSwitcher.pluginName");
|
||||||
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::loadUI()
|
void AdvSceneSwitcher::loadUI()
|
||||||
{
|
{
|
||||||
|
if (!translationAvailable()) {
|
||||||
|
(void)DisplayMessage(
|
||||||
|
"Failed to find plug-in's 'data' directory.\n"
|
||||||
|
"Please check installation instructions!");
|
||||||
|
}
|
||||||
|
|
||||||
#if __APPLE__
|
#if __APPLE__
|
||||||
setMinimumHeight(700);
|
setMinimumHeight(700);
|
||||||
#endif
|
#endif
|
||||||
@@ -44,15 +59,38 @@ void AdvSceneSwitcher::loadUI()
|
|||||||
setupFileTab();
|
setupFileTab();
|
||||||
setupTimeTab();
|
setupTimeTab();
|
||||||
setupAudioTab();
|
setupAudioTab();
|
||||||
|
setupSceneGroupTab();
|
||||||
|
setupTriggerTab();
|
||||||
|
|
||||||
setTabOrder();
|
setTabOrder();
|
||||||
|
|
||||||
loading = false;
|
loading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************************
|
/******************************************************************************
|
||||||
* UI helpers
|
* UI helpers
|
||||||
********************************************************************************/
|
******************************************************************************/
|
||||||
|
bool AdvSceneSwitcher::DisplayMessage(QString msg, bool question)
|
||||||
|
{
|
||||||
|
if (question) {
|
||||||
|
QMessageBox::StandardButton reply;
|
||||||
|
reply = QMessageBox::question(
|
||||||
|
nullptr, "Advanced Scene Switcher", msg,
|
||||||
|
QMessageBox::Yes | QMessageBox::No);
|
||||||
|
if (reply == QMessageBox::Yes) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QMessageBox Msgbox;
|
||||||
|
Msgbox.setWindowTitle("Advanced Scene Switcher");
|
||||||
|
Msgbox.setText(msg);
|
||||||
|
Msgbox.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void addSelectionEntry(QComboBox *sel, const char *description,
|
void addSelectionEntry(QComboBox *sel, const char *description,
|
||||||
const char *tooltip = "")
|
const char *tooltip = "")
|
||||||
@@ -73,11 +111,23 @@ void addSelectionEntry(QComboBox *sel, const char *description,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::populateSceneSelection(QComboBox *sel, bool addPrevious,
|
void AdvSceneSwitcher::populateSceneSelection(QComboBox *sel, bool addPrevious,
|
||||||
bool addSelect)
|
bool addSceneGroup,
|
||||||
|
bool addSelect,
|
||||||
|
std::string selectText)
|
||||||
{
|
{
|
||||||
if (addSelect)
|
sel->clear();
|
||||||
addSelectionEntry(sel, "--select scene--",
|
|
||||||
"invalid entries will not be saved");
|
if (addSelect) {
|
||||||
|
if (selectText.empty()) {
|
||||||
|
addSelectionEntry(
|
||||||
|
sel,
|
||||||
|
obs_module_text("AdvSceneSwitcher.selectScene"),
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.invaildEntriesWillNotBeSaved"));
|
||||||
|
} else {
|
||||||
|
addSelectionEntry(sel, selectText.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BPtr<char *> scenes = obs_frontend_get_scene_names();
|
BPtr<char *> scenes = obs_frontend_get_scene_names();
|
||||||
char **temp = scenes;
|
char **temp = scenes;
|
||||||
@@ -87,15 +137,26 @@ void AdvSceneSwitcher::populateSceneSelection(QComboBox *sel, bool addPrevious,
|
|||||||
temp++;
|
temp++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addPrevious)
|
if (addPrevious) {
|
||||||
sel->addItem(previous_scene_name);
|
sel->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.selectPreviousScene"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addSceneGroup) {
|
||||||
|
for (auto &sg : switcher->sceneGroups) {
|
||||||
|
sel->addItem(QString::fromStdString(sg.name));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::populateTransitionSelection(QComboBox *sel,
|
void AdvSceneSwitcher::populateTransitionSelection(QComboBox *sel,
|
||||||
bool addSelect)
|
bool addSelect)
|
||||||
{
|
{
|
||||||
if (addSelect)
|
if (addSelect) {
|
||||||
addSelectionEntry(sel, "--select transition--");
|
addSelectionEntry(
|
||||||
|
sel,
|
||||||
|
obs_module_text("AdvSceneSwitcher.selectTransition"));
|
||||||
|
}
|
||||||
|
|
||||||
obs_frontend_source_list *transitions = new obs_frontend_source_list();
|
obs_frontend_source_list *transitions = new obs_frontend_source_list();
|
||||||
obs_frontend_get_transitions(transitions);
|
obs_frontend_get_transitions(transitions);
|
||||||
@@ -111,8 +172,10 @@ void AdvSceneSwitcher::populateTransitionSelection(QComboBox *sel,
|
|||||||
|
|
||||||
void AdvSceneSwitcher::populateWindowSelection(QComboBox *sel, bool addSelect)
|
void AdvSceneSwitcher::populateWindowSelection(QComboBox *sel, bool addSelect)
|
||||||
{
|
{
|
||||||
if (addSelect)
|
if (addSelect) {
|
||||||
addSelectionEntry(sel, "--select window--");
|
addSelectionEntry(
|
||||||
|
sel, obs_module_text("AdvSceneSwitcher.selectWindow"));
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::string> windows;
|
std::vector<std::string> windows;
|
||||||
GetWindowList(windows);
|
GetWindowList(windows);
|
||||||
@@ -123,71 +186,115 @@ void AdvSceneSwitcher::populateWindowSelection(QComboBox *sel, bool addSelect)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
sel->setItemData(
|
sel->setItemData(0, obs_module_text("AdvSceneSwitcher.selectWindowTip"),
|
||||||
0,
|
Qt::ToolTipRole);
|
||||||
"Use \"OBS\" to specify OBS window\nUse \"Task Switching\"to specify ALT + TAB",
|
|
||||||
Qt::ToolTipRole);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::populateAudioSelection(QComboBox *sel, bool addSelect)
|
void AdvSceneSwitcher::populateAudioSelection(QComboBox *sel, bool addSelect)
|
||||||
{
|
{
|
||||||
if (addSelect)
|
if (addSelect) {
|
||||||
addSelectionEntry(sel, "--select audio source--",
|
addSelectionEntry(
|
||||||
"invalid entries will not be saved");
|
sel,
|
||||||
|
obs_module_text("AdvSceneSwitcher.selectAudioSource"),
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.invaildEntriesWillNotBeSaved"));
|
||||||
|
}
|
||||||
|
|
||||||
auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */
|
auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */
|
||||||
{
|
{
|
||||||
QComboBox *combo = reinterpret_cast<QComboBox *>(data);
|
std::vector<std::string> *list =
|
||||||
|
reinterpret_cast<std::vector<std::string> *>(data);
|
||||||
uint32_t flags = obs_source_get_output_flags(source);
|
uint32_t flags = obs_source_get_output_flags(source);
|
||||||
|
|
||||||
if ((flags & OBS_SOURCE_AUDIO) != 0) {
|
if ((flags & OBS_SOURCE_AUDIO) != 0) {
|
||||||
const char *name = obs_source_get_name(source);
|
list->push_back(obs_source_get_name(source));
|
||||||
combo->addItem(name);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
obs_enum_sources(sourceEnum, sel);
|
std::vector<std::string> audioSources;
|
||||||
|
obs_enum_sources(sourceEnum, &audioSources);
|
||||||
|
sort(audioSources.begin(), audioSources.end());
|
||||||
|
for (std::string &source : audioSources) {
|
||||||
|
sel->addItem(source.c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::populateMediaSelection(QComboBox *sel, bool addSelect)
|
void AdvSceneSwitcher::populateMediaSelection(QComboBox *sel, bool addSelect)
|
||||||
{
|
{
|
||||||
if (addSelect)
|
if (addSelect) {
|
||||||
addSelectionEntry(sel, "--select media source--",
|
addSelectionEntry(
|
||||||
"invalid entries will not be saved");
|
sel,
|
||||||
|
obs_module_text("AdvSceneSwitcher.selectMediaSource"),
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.invaildEntriesWillNotBeSaved"));
|
||||||
|
}
|
||||||
|
|
||||||
auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */
|
auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */
|
||||||
{
|
{
|
||||||
QComboBox *combo = reinterpret_cast<QComboBox *>(data);
|
std::vector<std::string> *list =
|
||||||
|
reinterpret_cast<std::vector<std::string> *>(data);
|
||||||
std::string sourceId = obs_source_get_id(source);
|
std::string sourceId = obs_source_get_id(source);
|
||||||
if (sourceId.compare("ffmpeg_source") == 0 ||
|
if (sourceId.compare("ffmpeg_source") == 0 ||
|
||||||
sourceId.compare("vlc_source") == 0) {
|
sourceId.compare("vlc_source") == 0) {
|
||||||
const char *name = obs_source_get_name(source);
|
list->push_back(obs_source_get_name(source));
|
||||||
combo->addItem(name);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
obs_enum_sources(sourceEnum, sel);
|
std::vector<std::string> mediaSources;
|
||||||
|
obs_enum_sources(sourceEnum, &mediaSources);
|
||||||
|
sort(mediaSources.begin(), mediaSources.end());
|
||||||
|
for (std::string &source : mediaSources) {
|
||||||
|
sel->addItem(source.c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::populateProcessSelection(QComboBox *sel, bool addSelect)
|
void AdvSceneSwitcher::populateProcessSelection(QComboBox *sel, bool addSelect)
|
||||||
{
|
{
|
||||||
if (addSelect)
|
if (addSelect) {
|
||||||
addSelectionEntry(sel, "--select process--");
|
addSelectionEntry(
|
||||||
|
sel, obs_module_text("AdvSceneSwitcher.selectProcess"));
|
||||||
|
}
|
||||||
|
|
||||||
QStringList processes;
|
QStringList processes;
|
||||||
GetProcessList(processes);
|
GetProcessList(processes);
|
||||||
|
processes.sort();
|
||||||
for (QString &process : processes)
|
for (QString &process : processes)
|
||||||
sel->addItem(process);
|
sel->addItem(process);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::listAddClicked(QListWidget *list,
|
||||||
|
SwitchWidget *newWidget,
|
||||||
|
QPushButton *addButton,
|
||||||
|
QMetaObject::Connection *addHighlight)
|
||||||
|
{
|
||||||
|
if (!list || !newWidget) {
|
||||||
|
blog(LOG_WARNING,
|
||||||
|
"listAddClicked called without valid list or widget");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addButton && addHighlight) {
|
||||||
|
addButton->disconnect(*addHighlight);
|
||||||
|
}
|
||||||
|
|
||||||
|
QListWidgetItem *item;
|
||||||
|
item = new QListWidgetItem(list);
|
||||||
|
list->addItem(item);
|
||||||
|
item->setSizeHint(newWidget->minimumSizeHint());
|
||||||
|
list->setItemWidget(item, newWidget);
|
||||||
|
|
||||||
|
list->scrollToItem(item);
|
||||||
|
}
|
||||||
|
|
||||||
bool AdvSceneSwitcher::listMoveUp(QListWidget *list)
|
bool AdvSceneSwitcher::listMoveUp(QListWidget *list)
|
||||||
{
|
{
|
||||||
int index = list->currentRow();
|
int index = list->currentRow();
|
||||||
if (index == -1 || index == 0)
|
if (index == -1 || index == 0) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
QWidget *row = list->itemWidget(list->currentItem());
|
QWidget *row = list->itemWidget(list->currentItem());
|
||||||
QListWidgetItem *itemN = list->currentItem()->clone();
|
QListWidgetItem *itemN = list->currentItem()->clone();
|
||||||
@@ -203,8 +310,9 @@ bool AdvSceneSwitcher::listMoveUp(QListWidget *list)
|
|||||||
bool AdvSceneSwitcher::listMoveDown(QListWidget *list)
|
bool AdvSceneSwitcher::listMoveDown(QListWidget *list)
|
||||||
{
|
{
|
||||||
int index = list->currentRow();
|
int index = list->currentRow();
|
||||||
if (index == -1 || index == list->count() - 1)
|
if (index == -1 || index == list->count() - 1) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
QWidget *row = list->itemWidget(list->currentItem());
|
QWidget *row = list->itemWidget(list->currentItem());
|
||||||
QListWidgetItem *itemN = list->currentItem()->clone();
|
QListWidgetItem *itemN = list->currentItem()->clone();
|
||||||
@@ -222,8 +330,9 @@ QMetaObject::Connection AdvSceneSwitcher::PulseWidget(QWidget *widget,
|
|||||||
QColor startColor,
|
QColor startColor,
|
||||||
QString specifier)
|
QString specifier)
|
||||||
{
|
{
|
||||||
if (switcher->disableHints)
|
if (switcher->disableHints) {
|
||||||
return QMetaObject::Connection();
|
return QMetaObject::Connection();
|
||||||
|
}
|
||||||
|
|
||||||
widget->setStyleSheet(specifier + "{ \
|
widget->setStyleSheet(specifier + "{ \
|
||||||
border-style: outset; \
|
border-style: outset; \
|
||||||
@@ -239,7 +348,7 @@ QMetaObject::Connection AdvSceneSwitcher::PulseWidget(QWidget *widget,
|
|||||||
paAnimation->setStartValue(startColor);
|
paAnimation->setStartValue(startColor);
|
||||||
paAnimation->setEndValue(endColor);
|
paAnimation->setEndValue(endColor);
|
||||||
paAnimation->setDuration(1000);
|
paAnimation->setDuration(1000);
|
||||||
// play backward to return to original state on timer end
|
// Play backwards to return to original state on timer end
|
||||||
paAnimation->setDirection(QAbstractAnimation::Backward);
|
paAnimation->setDirection(QAbstractAnimation::Backward);
|
||||||
|
|
||||||
auto con = QWidget::connect(
|
auto con = QWidget::connect(
|
||||||
@@ -254,9 +363,9 @@ QMetaObject::Connection AdvSceneSwitcher::PulseWidget(QWidget *widget,
|
|||||||
return con;
|
return con;
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************************
|
/******************************************************************************
|
||||||
* Saving and loading
|
* Saving and loading
|
||||||
********************************************************************************/
|
******************************************************************************/
|
||||||
static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
||||||
{
|
{
|
||||||
if (saving) {
|
if (saving) {
|
||||||
@@ -266,20 +375,7 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
|||||||
|
|
||||||
obs_data_t *obj = obs_data_create();
|
obs_data_t *obj = obs_data_create();
|
||||||
|
|
||||||
switcher->saveWindowTitleSwitches(obj);
|
switcher->saveSettings(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_set_obj(save_data, "advanced-scene-switcher", obj);
|
obs_data_set_obj(save_data, "advanced-scene-switcher", obj);
|
||||||
|
|
||||||
@@ -290,84 +386,88 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
|||||||
obs_data_t *obj =
|
obs_data_t *obj =
|
||||||
obs_data_get_obj(save_data, "advanced-scene-switcher");
|
obs_data_get_obj(save_data, "advanced-scene-switcher");
|
||||||
|
|
||||||
if (!obj)
|
if (!obj) {
|
||||||
obj = obs_data_create();
|
obj = obs_data_create();
|
||||||
|
}
|
||||||
|
if (switcher->versionChanged(obj, g_GIT_SHA1)) {
|
||||||
|
AdvSceneSwitcher::AskBackup(obj);
|
||||||
|
}
|
||||||
|
|
||||||
switcher->loadWindowTitleSwitches(obj);
|
switcher->loadSettings(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);
|
obs_data_release(obj);
|
||||||
|
|
||||||
switcher->m.unlock();
|
switcher->m.unlock();
|
||||||
|
|
||||||
// stop the scene switcher at least once
|
// Stop the scene switcher at least once to
|
||||||
// to avoid issues with scene collection changes
|
// avoid scene duplication issues with scene collection changes
|
||||||
bool start = !switcher->stop;
|
bool start = !switcher->stop;
|
||||||
switcher->Stop();
|
switcher->Stop();
|
||||||
if (start)
|
if (start) {
|
||||||
switcher->Start();
|
switcher->Start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************************
|
/******************************************************************************
|
||||||
* Main switcher thread
|
* Main switcher thread
|
||||||
********************************************************************************/
|
******************************************************************************/
|
||||||
void SwitcherData::Thread()
|
void SwitcherData::Thread()
|
||||||
{
|
{
|
||||||
blog(LOG_INFO, "started");
|
blog(LOG_INFO, "started");
|
||||||
int sleep = 0;
|
int sleep = 0;
|
||||||
|
int linger = 0;
|
||||||
|
std::chrono::milliseconds duration;
|
||||||
|
auto startTime = std::chrono::high_resolution_clock::now();
|
||||||
|
auto endTime = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
startLoop:
|
|
||||||
std::unique_lock<std::mutex> lock(m);
|
std::unique_lock<std::mutex> lock(m);
|
||||||
|
|
||||||
bool match = false;
|
bool match = false;
|
||||||
OBSWeakSource scene;
|
OBSWeakSource scene;
|
||||||
OBSWeakSource transition;
|
OBSWeakSource transition;
|
||||||
std::chrono::milliseconds duration;
|
|
||||||
if (sleep > interval) {
|
bool defTransitionMatch = false;
|
||||||
|
OBSWeakSource defTransition;
|
||||||
|
|
||||||
|
endTime = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
auto runTime =
|
||||||
|
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||||
|
endTime - startTime);
|
||||||
|
|
||||||
|
if (sleep) {
|
||||||
duration = std::chrono::milliseconds(sleep);
|
duration = std::chrono::milliseconds(sleep);
|
||||||
if (verbose)
|
|
||||||
blog(LOG_INFO, "sleep for %d", sleep);
|
|
||||||
} else {
|
} else {
|
||||||
duration = std::chrono::milliseconds(interval);
|
duration = std::chrono::milliseconds(interval) +
|
||||||
if (verbose)
|
std::chrono::milliseconds(linger) - runTime;
|
||||||
blog(LOG_INFO, "sleep for %d", interval);
|
if (duration.count() < 1) {
|
||||||
|
blog(LOG_INFO,
|
||||||
|
"detected busy loop - refusing to sleep less than 1ms");
|
||||||
|
duration = std::chrono::milliseconds(50);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sleep = 0;
|
|
||||||
switcher->Prune();
|
vblog(LOG_INFO, "sleep for %ld", duration.count());
|
||||||
writeSceneInfoToFile();
|
|
||||||
//sleep for a bit
|
|
||||||
cv.wait_for(lock, duration);
|
cv.wait_for(lock, duration);
|
||||||
|
|
||||||
|
startTime = std::chrono::high_resolution_clock::now();
|
||||||
|
sleep = 0;
|
||||||
|
linger = 0;
|
||||||
|
|
||||||
|
switcher->Prune();
|
||||||
|
|
||||||
if (switcher->stop) {
|
if (switcher->stop) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
setDefaultSceneTransitions();
|
|
||||||
|
|
||||||
if (autoStopEnable) {
|
|
||||||
autoStopStreamAndRecording();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (autoStartEnable) {
|
|
||||||
autoStartStreamRecording();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (checkPause()) {
|
if (checkPause()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkDefaultSceneTransitions(defTransitionMatch, defTransition);
|
||||||
|
|
||||||
for (int switchFuncName : functionNamesByPriority) {
|
for (int switchFuncName : functionNamesByPriority) {
|
||||||
switch (switchFuncName) {
|
switch (switchFuncName) {
|
||||||
case read_file_func:
|
case read_file_func:
|
||||||
@@ -381,7 +481,6 @@ void SwitcherData::Thread()
|
|||||||
case exe_func:
|
case exe_func:
|
||||||
checkExeSwitch(match, scene, transition);
|
checkExeSwitch(match, scene, transition);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case screen_region_func:
|
case screen_region_func:
|
||||||
checkScreenRegionSwitch(match, scene,
|
checkScreenRegionSwitch(match, scene,
|
||||||
transition);
|
transition);
|
||||||
@@ -392,11 +491,7 @@ void SwitcherData::Thread()
|
|||||||
break;
|
break;
|
||||||
case round_trip_func:
|
case round_trip_func:
|
||||||
checkSceneSequence(match, scene, transition,
|
checkSceneSequence(match, scene, transition,
|
||||||
lock);
|
linger);
|
||||||
if (sceneChangedDuringWait()) //scene might have changed during the sleep
|
|
||||||
{
|
|
||||||
goto startLoop;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case media_func:
|
case media_func:
|
||||||
checkMediaSwitch(match, scene, transition);
|
checkMediaSwitch(match, scene, transition);
|
||||||
@@ -417,64 +512,81 @@ void SwitcherData::Thread()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!match && switchIfNotMatching == SWITCH &&
|
checkNoMatchSwitch(match, scene, transition, sleep);
|
||||||
nonMatchingScene) {
|
|
||||||
match = true;
|
checkSwitchCooldown(match);
|
||||||
scene = nonMatchingScene;
|
|
||||||
transition = nullptr;
|
if (linger) {
|
||||||
|
duration = std::chrono::milliseconds(linger);
|
||||||
|
vblog(LOG_INFO, "sleep for %ld before switching scene",
|
||||||
|
duration.count());
|
||||||
|
|
||||||
|
cv.wait_for(lock, duration);
|
||||||
|
|
||||||
|
if (switcher->stop) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sceneChangedDuringWait()) {
|
||||||
|
vblog(LOG_INFO,
|
||||||
|
"scene was changed manually - ignoring match");
|
||||||
|
|
||||||
|
match = false;
|
||||||
|
linger = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!match && switchIfNotMatching == RANDOM_SWITCH) {
|
|
||||||
checkRandom(match, scene, transition, sleep);
|
// After this point we will call frontend functions
|
||||||
|
// obs_frontend_set_current_scene() and
|
||||||
|
// obs_frontend_set_current_transition()
|
||||||
|
//
|
||||||
|
// During this time SaveSceneSwitcher() could be called
|
||||||
|
// leading to a deadlock, so we have to unlock()
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
|
if (!match && defTransitionMatch) {
|
||||||
|
setCurrentDefTransition(defTransition);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match) {
|
if (match) {
|
||||||
switchScene(scene, transition,
|
switchScene(scene, transition,
|
||||||
tansitionOverrideOverride, lock);
|
tansitionOverrideOverride);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writeSceneInfoToFile();
|
||||||
}
|
}
|
||||||
endLoop:
|
endLoop:
|
||||||
blog(LOG_INFO, "stopped");
|
blog(LOG_INFO, "stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
void switchScene(OBSWeakSource &scene, OBSWeakSource &transition,
|
void switchScene(OBSWeakSource &scene, OBSWeakSource &transition,
|
||||||
bool &transitionOverrideOverride,
|
bool &transitionOverrideOverride)
|
||||||
std::unique_lock<std::mutex> &lock)
|
|
||||||
{
|
{
|
||||||
|
if (!scene && switcher->verbose) {
|
||||||
|
blog(LOG_INFO, "nothing to switch to");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
obs_source_t *source = obs_weak_source_get_source(scene);
|
obs_source_t *source = obs_weak_source_get_source(scene);
|
||||||
obs_source_t *currentSource = obs_frontend_get_current_scene();
|
obs_source_t *currentSource = obs_frontend_get_current_scene();
|
||||||
|
|
||||||
if (source && source != currentSource) {
|
if (source && source != currentSource) {
|
||||||
|
|
||||||
// this call might block when OBS_FRONTEND_EVENT_SCENE_CHANGED is active and mutex is held
|
|
||||||
// thus unlock mutex to avoid deadlock
|
|
||||||
lock.unlock();
|
|
||||||
|
|
||||||
transitionData td;
|
transitionData td;
|
||||||
setNextTransition(scene, currentSource, transition,
|
setNextTransition(scene, currentSource, transition,
|
||||||
transitionOverrideOverride, td);
|
transitionOverrideOverride, td);
|
||||||
obs_frontend_set_current_scene(source);
|
obs_frontend_set_current_scene(source);
|
||||||
if (transitionOverrideOverride)
|
if (transitionOverrideOverride) {
|
||||||
restoreTransitionOverride(source, td);
|
restoreTransitionOverride(source, td);
|
||||||
lock.lock();
|
}
|
||||||
|
|
||||||
if (switcher->verbose)
|
if (switcher->verbose) {
|
||||||
blog(LOG_INFO, "switched scene");
|
blog(LOG_INFO, "switched scene");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
obs_source_release(currentSource);
|
obs_source_release(currentSource);
|
||||||
obs_source_release(source);
|
obs_source_release(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SwitcherData::sceneChangedDuringWait()
|
|
||||||
{
|
|
||||||
bool r = false;
|
|
||||||
obs_source_t *currentSource = obs_frontend_get_current_scene();
|
|
||||||
if (!currentSource)
|
|
||||||
return true;
|
|
||||||
obs_source_release(currentSource);
|
|
||||||
if (waitScene && currentSource != waitScene)
|
|
||||||
r = true;
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SwitcherData::Start()
|
void SwitcherData::Start()
|
||||||
{
|
{
|
||||||
if (!(th && th->isRunning())) {
|
if (!(th && th->isRunning())) {
|
||||||
@@ -482,6 +594,9 @@ void SwitcherData::Start()
|
|||||||
switcher->th = new SwitcherThread();
|
switcher->th = new SwitcherThread();
|
||||||
switcher->th->start(
|
switcher->th->start(
|
||||||
(QThread::Priority)switcher->threadPriority);
|
(QThread::Priority)switcher->threadPriority);
|
||||||
|
|
||||||
|
// Will be overwritten quickly but might be useful
|
||||||
|
writeToStatusFile("Advanced Scene Switcher running");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,17 +609,30 @@ void SwitcherData::Stop()
|
|||||||
th->wait();
|
th->wait();
|
||||||
delete th;
|
delete th;
|
||||||
th = nullptr;
|
th = nullptr;
|
||||||
|
|
||||||
|
writeToStatusFile("Advanced Scene Switcher stopped");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************************
|
bool SwitcherData::sceneChangedDuringWait()
|
||||||
|
{
|
||||||
|
obs_source_t *currentSource = obs_frontend_get_current_scene();
|
||||||
|
if (!currentSource) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
obs_source_release(currentSource);
|
||||||
|
return (waitScene && currentSource != waitScene);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
* OBS module setup
|
* OBS module setup
|
||||||
********************************************************************************/
|
******************************************************************************/
|
||||||
extern "C" void FreeSceneSwitcher()
|
extern "C" void FreeSceneSwitcher()
|
||||||
{
|
{
|
||||||
if (loaded_curl_lib) {
|
if (loaded_curl_lib) {
|
||||||
if (switcher->curl && f_curl_cleanup)
|
if (switcher->curl && f_curl_cleanup) {
|
||||||
f_curl_cleanup(switcher->curl);
|
f_curl_cleanup(switcher->curl);
|
||||||
|
}
|
||||||
delete loaded_curl_lib;
|
delete loaded_curl_lib;
|
||||||
loaded_curl_lib = nullptr;
|
loaded_curl_lib = nullptr;
|
||||||
}
|
}
|
||||||
@@ -515,24 +643,27 @@ extern "C" void FreeSceneSwitcher()
|
|||||||
|
|
||||||
void handleSceneChange(SwitcherData *s)
|
void handleSceneChange(SwitcherData *s)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(s->m);
|
// Stop waiting if scene was manually changed
|
||||||
//stop waiting if scene was manually changed
|
if (s->sceneChangedDuringWait()) {
|
||||||
if (s->sceneChangedDuringWait())
|
|
||||||
s->cv.notify_one();
|
s->cv.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
//set previous scene
|
// Set previous scene
|
||||||
obs_source_t *source = obs_frontend_get_current_scene();
|
obs_source_t *source = obs_frontend_get_current_scene();
|
||||||
obs_weak_source_t *ws = obs_source_get_weak_source(source);
|
obs_weak_source_t *ws = obs_source_get_weak_source(source);
|
||||||
obs_source_release(source);
|
obs_source_release(source);
|
||||||
obs_weak_source_release(ws);
|
obs_weak_source_release(ws);
|
||||||
if (source && s->PreviousScene2 != ws) {
|
if (source && s->previousSceneHelper != ws) {
|
||||||
s->previousScene = s->PreviousScene2;
|
s->previousScene = s->previousSceneHelper;
|
||||||
s->PreviousScene2 = ws;
|
s->previousSceneHelper = ws;
|
||||||
}
|
}
|
||||||
|
|
||||||
//reset events only hanled on scene change
|
switcher->checkTriggers();
|
||||||
s->autoStartedRecently = false;
|
}
|
||||||
s->changedDefTransitionRecently = false;
|
|
||||||
|
void handleTransitionStop(SwitcherData *s)
|
||||||
|
{
|
||||||
|
s->checkedDefTransition = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setLiveTime(SwitcherData *s)
|
void setLiveTime(SwitcherData *s)
|
||||||
@@ -545,6 +676,23 @@ void resetLiveTime(SwitcherData *s)
|
|||||||
s->liveTime = QDateTime();
|
s->liveTime = QDateTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void checkAutoStartRecording(SwitcherData *s)
|
||||||
|
{
|
||||||
|
if (s->autoStartEvent == AutoStartEvent::RECORDING ||
|
||||||
|
s->autoStartEvent == AutoStartEvent::RECORINDG_OR_STREAMING)
|
||||||
|
s->Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkAutoStartStreaming(SwitcherData *s)
|
||||||
|
{
|
||||||
|
if (s->autoStartEvent == AutoStartEvent::STREAMING ||
|
||||||
|
s->autoStartEvent == AutoStartEvent::RECORINDG_OR_STREAMING)
|
||||||
|
s->Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note to future self:
|
||||||
|
// be careful using switcher->m here as there is potential for deadlocks when using
|
||||||
|
// frontend functions such as obs_frontend_set_current_scene()
|
||||||
static void OBSEvent(enum obs_frontend_event event, void *switcher)
|
static void OBSEvent(enum obs_frontend_event event, void *switcher)
|
||||||
{
|
{
|
||||||
switch (event) {
|
switch (event) {
|
||||||
@@ -554,9 +702,16 @@ static void OBSEvent(enum obs_frontend_event event, void *switcher)
|
|||||||
case OBS_FRONTEND_EVENT_SCENE_CHANGED:
|
case OBS_FRONTEND_EVENT_SCENE_CHANGED:
|
||||||
handleSceneChange((SwitcherData *)switcher);
|
handleSceneChange((SwitcherData *)switcher);
|
||||||
break;
|
break;
|
||||||
|
case OBS_FRONTEND_EVENT_TRANSITION_STOPPED:
|
||||||
|
handleTransitionStop((SwitcherData *)switcher);
|
||||||
|
break;
|
||||||
case OBS_FRONTEND_EVENT_RECORDING_STARTED:
|
case OBS_FRONTEND_EVENT_RECORDING_STARTED:
|
||||||
|
setLiveTime((SwitcherData *)switcher);
|
||||||
|
checkAutoStartRecording((SwitcherData *)switcher);
|
||||||
|
break;
|
||||||
case OBS_FRONTEND_EVENT_STREAMING_STARTED:
|
case OBS_FRONTEND_EVENT_STREAMING_STARTED:
|
||||||
setLiveTime((SwitcherData *)switcher);
|
setLiveTime((SwitcherData *)switcher);
|
||||||
|
checkAutoStartStreaming((SwitcherData *)switcher);
|
||||||
break;
|
break;
|
||||||
case OBS_FRONTEND_EVENT_RECORDING_STOPPED:
|
case OBS_FRONTEND_EVENT_RECORDING_STOPPED:
|
||||||
case OBS_FRONTEND_EVENT_STREAMING_STOPPED:
|
case OBS_FRONTEND_EVENT_STREAMING_STOPPED:
|
||||||
@@ -569,8 +724,10 @@ static void OBSEvent(enum obs_frontend_event event, void *switcher)
|
|||||||
|
|
||||||
extern "C" void InitSceneSwitcher()
|
extern "C" void InitSceneSwitcher()
|
||||||
{
|
{
|
||||||
|
blog(LOG_INFO, "version: %s", g_GIT_SHA1);
|
||||||
|
|
||||||
QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction(
|
QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction(
|
||||||
"Advanced Scene Switcher");
|
obs_module_text("AdvSceneSwitcher.pluginName"));
|
||||||
|
|
||||||
switcher = new SwitcherData;
|
switcher = new SwitcherData;
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,8 @@ bool loadCurl()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (QString path : locations) {
|
for (QString path : locations) {
|
||||||
blog(LOG_INFO, "[adv-ss] trying '%s'", path.toUtf8().constData());
|
blog(LOG_INFO, "[adv-ss] trying '%s'",
|
||||||
|
path.toUtf8().constData());
|
||||||
QFileInfo libPath(
|
QFileInfo libPath(
|
||||||
QDir(path).absoluteFilePath(curl_library_name));
|
QDir(path).absoluteFilePath(curl_library_name));
|
||||||
|
|
||||||
@@ -53,9 +54,9 @@ bool loadCurl()
|
|||||||
libFilePath.toUtf8().constData());
|
libFilePath.toUtf8().constData());
|
||||||
|
|
||||||
loaded_curl_lib = new QLibrary(libFilePath, nullptr);
|
loaded_curl_lib = new QLibrary(libFilePath, nullptr);
|
||||||
if (resolveCurl())
|
if (resolveCurl()) {
|
||||||
return true;
|
return true;
|
||||||
else {
|
} else {
|
||||||
delete loaded_curl_lib;
|
delete loaded_curl_lib;
|
||||||
loaded_curl_lib = nullptr;
|
loaded_curl_lib = nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
696
src/general.cpp
696
src/general.cpp
@@ -1,8 +1,10 @@
|
|||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QMessageBox>
|
|
||||||
|
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
|
#include "headers/version.h"
|
||||||
|
|
||||||
|
constexpr auto tab_count = 15;
|
||||||
|
|
||||||
QMetaObject::Connection inactivePluse;
|
QMetaObject::Connection inactivePluse;
|
||||||
|
|
||||||
@@ -24,8 +26,9 @@ void AdvSceneSwitcher::UpdateNonMatchingScene(const QString &name)
|
|||||||
|
|
||||||
void AdvSceneSwitcher::on_noMatchDontSwitch_clicked()
|
void AdvSceneSwitcher::on_noMatchDontSwitch_clicked()
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switcher->switchIfNotMatching = NO_SWITCH;
|
switcher->switchIfNotMatching = NO_SWITCH;
|
||||||
@@ -35,8 +38,9 @@ void AdvSceneSwitcher::on_noMatchDontSwitch_clicked()
|
|||||||
|
|
||||||
void AdvSceneSwitcher::on_noMatchSwitch_clicked()
|
void AdvSceneSwitcher::on_noMatchSwitch_clicked()
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switcher->switchIfNotMatching = SWITCH;
|
switcher->switchIfNotMatching = SWITCH;
|
||||||
@@ -47,8 +51,9 @@ void AdvSceneSwitcher::on_noMatchSwitch_clicked()
|
|||||||
|
|
||||||
void AdvSceneSwitcher::on_noMatchRandomSwitch_clicked()
|
void AdvSceneSwitcher::on_noMatchRandomSwitch_clicked()
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switcher->switchIfNotMatching = RANDOM_SWITCH;
|
switcher->switchIfNotMatching = RANDOM_SWITCH;
|
||||||
@@ -56,29 +61,62 @@ void AdvSceneSwitcher::on_noMatchRandomSwitch_clicked()
|
|||||||
ui->randomDisabledWarning->setVisible(false);
|
ui->randomDisabledWarning->setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_noMatchDelay_valueChanged(double i)
|
||||||
|
{
|
||||||
|
if (loading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switcher->noMatchDelay = i;
|
||||||
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_startupBehavior_currentIndexChanged(int index)
|
void AdvSceneSwitcher::on_startupBehavior_currentIndexChanged(int index)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switcher->startupBehavior = (StartupBehavior)index;
|
switcher->startupBehavior = (StartupBehavior)index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_autoStartEvent_currentIndexChanged(int index)
|
||||||
|
{
|
||||||
|
if (loading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switcher->autoStartEvent = static_cast<AutoStartEvent>(index);
|
||||||
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_noMatchSwitchScene_currentTextChanged(
|
void AdvSceneSwitcher::on_noMatchSwitchScene_currentTextChanged(
|
||||||
const QString &text)
|
const QString &text)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
UpdateNonMatchingScene(text);
|
UpdateNonMatchingScene(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_cooldownTime_valueChanged(double i)
|
||||||
|
{
|
||||||
|
if (loading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switcher->cooldown = i;
|
||||||
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_checkInterval_valueChanged(int value)
|
void AdvSceneSwitcher::on_checkInterval_valueChanged(int value)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switcher->interval = value;
|
switcher->interval = value;
|
||||||
@@ -86,15 +124,19 @@ void AdvSceneSwitcher::on_checkInterval_valueChanged(int value)
|
|||||||
|
|
||||||
void AdvSceneSwitcher::SetStarted()
|
void AdvSceneSwitcher::SetStarted()
|
||||||
{
|
{
|
||||||
ui->toggleStartButton->setText("Stop");
|
ui->toggleStartButton->setText(
|
||||||
ui->pluginRunningText->setText("Active");
|
obs_module_text("AdvSceneSwitcher.generalTab.status.stop"));
|
||||||
|
ui->pluginRunningText->setText(
|
||||||
|
obs_module_text("AdvSceneSwitcher.status.active"));
|
||||||
ui->pluginRunningText->disconnect(inactivePluse);
|
ui->pluginRunningText->disconnect(inactivePluse);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::SetStopped()
|
void AdvSceneSwitcher::SetStopped()
|
||||||
{
|
{
|
||||||
ui->toggleStartButton->setText("Start");
|
ui->toggleStartButton->setText(
|
||||||
ui->pluginRunningText->setText("Inactive");
|
obs_module_text("AdvSceneSwitcher.generalTab.status.start"));
|
||||||
|
ui->pluginRunningText->setText(
|
||||||
|
obs_module_text("AdvSceneSwitcher.status.inactive"));
|
||||||
inactivePluse = PulseWidget(ui->pluginRunningText, QColor(Qt::red),
|
inactivePluse = PulseWidget(ui->pluginRunningText, QColor(Qt::red),
|
||||||
QColor(0, 0, 0, 0), "QLabel ");
|
QColor(0, 0, 0, 0), "QLabel ");
|
||||||
}
|
}
|
||||||
@@ -115,172 +157,73 @@ void AdvSceneSwitcher::closeEvent(QCloseEvent *)
|
|||||||
obs_frontend_save();
|
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)
|
void AdvSceneSwitcher::on_verboseLogging_stateChanged(int state)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switcher->verbose = state;
|
switcher->verbose = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_uiHintsDisable_stateChanged(int state)
|
void AdvSceneSwitcher::on_uiHintsDisable_stateChanged(int state)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switcher->disableHints = state;
|
switcher->disableHints = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::AskBackup(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
bool backupSettings = DisplayMessage(
|
||||||
|
obs_module_text("AdvSceneSwitcher.askBackup"), true);
|
||||||
|
|
||||||
|
if (!backupSettings) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString directory = QFileDialog::getSaveFileName(
|
||||||
|
nullptr,
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle"),
|
||||||
|
QDir::currentPath(),
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType"));
|
||||||
|
if (directory.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile file(directory);
|
||||||
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_data_save_json(obj, file.fileName().toUtf8().constData());
|
||||||
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_exportSettings_clicked()
|
void AdvSceneSwitcher::on_exportSettings_clicked()
|
||||||
{
|
{
|
||||||
QString directory = QFileDialog::getSaveFileName(
|
QString directory = QFileDialog::getSaveFileName(
|
||||||
this, tr("Export Advanced Scene Switcher settings to file ..."),
|
this,
|
||||||
QDir::currentPath(), tr("Text files (*.txt)"));
|
tr(obs_module_text(
|
||||||
if (directory.isEmpty())
|
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle")),
|
||||||
|
QDir::currentPath(),
|
||||||
|
tr(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType")));
|
||||||
|
if (directory.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QFile file(directory);
|
QFile file(directory);
|
||||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
obs_data_t *obj = obs_data_create();
|
obs_data_t *obj = obs_data_create();
|
||||||
|
|
||||||
switcher->saveWindowTitleSwitches(obj);
|
switcher->saveSettings(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_save_json(obj, file.fileName().toUtf8().constData());
|
||||||
|
|
||||||
@@ -289,30 +232,156 @@ void AdvSceneSwitcher::on_exportSettings_clicked()
|
|||||||
|
|
||||||
void AdvSceneSwitcher::on_importSettings_clicked()
|
void AdvSceneSwitcher::on_importSettings_clicked()
|
||||||
{
|
{
|
||||||
|
// Scene switcher could be stuck in a sequence
|
||||||
|
// so it needs to be stopped before importing new settings
|
||||||
|
bool start = !switcher->stop;
|
||||||
|
switcher->Stop();
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
|
||||||
QString directory = QFileDialog::getOpenFileName(
|
QString directory = QFileDialog::getOpenFileName(
|
||||||
this,
|
this,
|
||||||
tr("Import Advanced Scene Switcher settings from file ..."),
|
tr(obs_module_text(
|
||||||
QDir::currentPath(), tr("Text files (*.txt)"));
|
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle")),
|
||||||
if (directory.isEmpty())
|
QDir::currentPath(),
|
||||||
|
tr(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType")));
|
||||||
|
if (directory.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QFile file(directory);
|
QFile file(directory);
|
||||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
obs_data_t *obj = obs_data_create_from_json_file(
|
obs_data_t *obj = obs_data_create_from_json_file(
|
||||||
file.fileName().toUtf8().constData());
|
file.fileName().toUtf8().constData());
|
||||||
|
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
QMessageBox Msgbox;
|
(void)DisplayMessage(obs_module_text(
|
||||||
Msgbox.setText(
|
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail"));
|
||||||
"Advanced Scene Switcher failed to import settings");
|
|
||||||
Msgbox.exec();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switcher->loadSettings(obj);
|
||||||
|
|
||||||
|
obs_data_release(obj);
|
||||||
|
|
||||||
|
(void)DisplayMessage(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess"));
|
||||||
|
close();
|
||||||
|
|
||||||
|
// Restart scene switcher if it was active
|
||||||
|
if (start) {
|
||||||
|
switcher->Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int findTabIndex(QTabWidget *tabWidget, int pos)
|
||||||
|
{
|
||||||
|
int at = -1;
|
||||||
|
|
||||||
|
QString tabName = "";
|
||||||
|
switch (pos) {
|
||||||
|
case 0:
|
||||||
|
tabName = "generalTab";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
tabName = "transitionsTab";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
tabName = "pauseTab";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
tabName = "windowTitleTab";
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
tabName = "executableTab";
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
tabName = "screenRegionTab";
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
tabName = "mediaTab";
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
tabName = "fileTab";
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
tabName = "randomTab";
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
tabName = "timeTab";
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
tabName = "idleTab";
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
tabName = "sceneSequenceTab";
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
tabName = "audioTab";
|
||||||
|
break;
|
||||||
|
case 13:
|
||||||
|
tabName = "sceneGroupTab";
|
||||||
|
break;
|
||||||
|
case 14:
|
||||||
|
tabName = "sceneTriggerTab";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget *page = tabWidget->findChild<QWidget *>(tabName);
|
||||||
|
if (page) {
|
||||||
|
at = tabWidget->indexOf(page);
|
||||||
|
}
|
||||||
|
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(ui->tabWidget, 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 AdvSceneSwitcher::on_tabWidget_currentChanged(int index)
|
||||||
|
{
|
||||||
|
UNUSED_PARAMETER(index);
|
||||||
|
|
||||||
|
switcher->showFrame = false;
|
||||||
|
clearFrames(ui->screenRegionSwitches);
|
||||||
|
SetShowFrames();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitcherData::loadSettings(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
if (!obj) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switcher->loadSceneGroups(obj);
|
||||||
switcher->loadWindowTitleSwitches(obj);
|
switcher->loadWindowTitleSwitches(obj);
|
||||||
switcher->loadScreenRegionSwitches(obj);
|
switcher->loadScreenRegionSwitches(obj);
|
||||||
switcher->loadPauseSwitches(obj);
|
switcher->loadPauseSwitches(obj);
|
||||||
@@ -325,96 +394,34 @@ void AdvSceneSwitcher::on_importSettings_clicked()
|
|||||||
switcher->loadMediaSwitches(obj);
|
switcher->loadMediaSwitches(obj);
|
||||||
switcher->loadTimeSwitches(obj);
|
switcher->loadTimeSwitches(obj);
|
||||||
switcher->loadAudioSwitches(obj);
|
switcher->loadAudioSwitches(obj);
|
||||||
|
switcher->loadSceneTriggers(obj);
|
||||||
switcher->loadGeneralSettings(obj);
|
switcher->loadGeneralSettings(obj);
|
||||||
switcher->loadHotkeys(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)
|
void SwitcherData::saveSettings(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
int at = -1;
|
if (!obj) {
|
||||||
|
|
||||||
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;
|
return;
|
||||||
std::swap(switcher->tabOrder[from], switcher->tabOrder[to]);
|
}
|
||||||
|
|
||||||
|
saveSceneGroups(obj);
|
||||||
|
saveWindowTitleSwitches(obj);
|
||||||
|
saveScreenRegionSwitches(obj);
|
||||||
|
savePauseSwitches(obj);
|
||||||
|
saveSceneSequenceSwitches(obj);
|
||||||
|
saveSceneTransitions(obj);
|
||||||
|
saveIdleSwitches(obj);
|
||||||
|
saveExecutableSwitches(obj);
|
||||||
|
saveRandomSwitches(obj);
|
||||||
|
saveFileSwitches(obj);
|
||||||
|
saveMediaSwitches(obj);
|
||||||
|
saveTimeSwitches(obj);
|
||||||
|
saveAudioSwitches(obj);
|
||||||
|
saveSceneTriggers(obj);
|
||||||
|
saveGeneralSettings(obj);
|
||||||
|
saveHotkeys(obj);
|
||||||
|
saveVersion(obj, g_GIT_SHA1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitcherData::saveGeneralSettings(obs_data_t *obj)
|
void SwitcherData::saveGeneralSettings(obs_data_t *obj)
|
||||||
@@ -427,22 +434,15 @@ void SwitcherData::saveGeneralSettings(obs_data_t *obj)
|
|||||||
nonMatchingSceneName.c_str());
|
nonMatchingSceneName.c_str());
|
||||||
obs_data_set_int(obj, "switch_if_not_matching",
|
obs_data_set_int(obj, "switch_if_not_matching",
|
||||||
switcher->switchIfNotMatching);
|
switcher->switchIfNotMatching);
|
||||||
|
obs_data_set_double(obj, "noMatchDelay", switcher->noMatchDelay);
|
||||||
|
|
||||||
|
obs_data_set_double(obj, "cooldown", switcher->cooldown);
|
||||||
|
|
||||||
obs_data_set_bool(obj, "active", !switcher->stop);
|
obs_data_set_bool(obj, "active", !switcher->stop);
|
||||||
obs_data_set_int(obj, "startup_behavior", switcher->startupBehavior);
|
obs_data_set_int(obj, "startup_behavior", switcher->startupBehavior);
|
||||||
|
|
||||||
std::string autoStopSceneName =
|
obs_data_set_int(obj, "autoStartEvent",
|
||||||
GetWeakSourceName(switcher->autoStopScene);
|
static_cast<int>(switcher->autoStartEvent));
|
||||||
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, "verbose", switcher->verbose);
|
||||||
obs_data_set_bool(obj, "disableHints", switcher->disableHints);
|
obs_data_set_bool(obj, "disableHints", switcher->disableHints);
|
||||||
@@ -468,6 +468,14 @@ void SwitcherData::saveGeneralSettings(obs_data_t *obj)
|
|||||||
|
|
||||||
obs_data_set_int(obj, "threadPriority", switcher->threadPriority);
|
obs_data_set_int(obj, "threadPriority", switcher->threadPriority);
|
||||||
|
|
||||||
|
// After fresh install of OBS the vector can be empty
|
||||||
|
// as save() might be called before first load()
|
||||||
|
if (switcher->tabOrder.size() < tab_count) {
|
||||||
|
switcher->tabOrder = std::vector<int>(tab_count);
|
||||||
|
std::iota(switcher->tabOrder.begin(), switcher->tabOrder.end(),
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
obs_data_set_int(obj, "generalTabPos", switcher->tabOrder[0]);
|
obs_data_set_int(obj, "generalTabPos", switcher->tabOrder[0]);
|
||||||
obs_data_set_int(obj, "transitionTabPos", switcher->tabOrder[1]);
|
obs_data_set_int(obj, "transitionTabPos", switcher->tabOrder[1]);
|
||||||
obs_data_set_int(obj, "pauseTabPos", switcher->tabOrder[2]);
|
obs_data_set_int(obj, "pauseTabPos", switcher->tabOrder[2]);
|
||||||
@@ -481,6 +489,8 @@ void SwitcherData::saveGeneralSettings(obs_data_t *obj)
|
|||||||
obs_data_set_int(obj, "idleTabPos", switcher->tabOrder[10]);
|
obs_data_set_int(obj, "idleTabPos", switcher->tabOrder[10]);
|
||||||
obs_data_set_int(obj, "sequenceTabPos", switcher->tabOrder[11]);
|
obs_data_set_int(obj, "sequenceTabPos", switcher->tabOrder[11]);
|
||||||
obs_data_set_int(obj, "audioTabPos", switcher->tabOrder[12]);
|
obs_data_set_int(obj, "audioTabPos", switcher->tabOrder[12]);
|
||||||
|
obs_data_set_int(obj, "sceneGroupTabPos", switcher->tabOrder[13]);
|
||||||
|
obs_data_set_int(obj, "triggerTabPos", switcher->tabOrder[14]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitcherData::loadGeneralSettings(obs_data_t *obj)
|
void SwitcherData::loadGeneralSettings(obs_data_t *obj)
|
||||||
@@ -495,26 +505,22 @@ void SwitcherData::loadGeneralSettings(obs_data_t *obj)
|
|||||||
obs_data_get_string(obj, "non_matching_scene");
|
obs_data_get_string(obj, "non_matching_scene");
|
||||||
switcher->nonMatchingScene =
|
switcher->nonMatchingScene =
|
||||||
GetWeakSourceByName(nonMatchingScene.c_str());
|
GetWeakSourceByName(nonMatchingScene.c_str());
|
||||||
|
switcher->noMatchDelay = obs_data_get_double(obj, "noMatchDelay");
|
||||||
|
|
||||||
|
switcher->cooldown = obs_data_get_double(obj, "cooldown");
|
||||||
|
|
||||||
switcher->stop = !obs_data_get_bool(obj, "active");
|
switcher->stop = !obs_data_get_bool(obj, "active");
|
||||||
switcher->startupBehavior =
|
switcher->startupBehavior =
|
||||||
(StartupBehavior)obs_data_get_int(obj, "startup_behavior");
|
(StartupBehavior)obs_data_get_int(obj, "startup_behavior");
|
||||||
if (switcher->startupBehavior == START)
|
if (switcher->startupBehavior == START) {
|
||||||
switcher->stop = false;
|
switcher->stop = false;
|
||||||
if (switcher->startupBehavior == STOP)
|
}
|
||||||
|
if (switcher->startupBehavior == STOP) {
|
||||||
switcher->stop = true;
|
switcher->stop = true;
|
||||||
|
}
|
||||||
|
|
||||||
std::string autoStopScene =
|
switcher->autoStartEvent = static_cast<AutoStartEvent>(
|
||||||
obs_data_get_string(obj, "autoStopSceneName");
|
obs_data_get_int(obj, "autoStartEvent"));
|
||||||
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->verbose = obs_data_get_bool(obj, "verbose");
|
||||||
switcher->disableHints = obs_data_get_bool(obj, "disableHints");
|
switcher->disableHints = obs_data_get_bool(obj, "disableHints");
|
||||||
@@ -576,6 +582,8 @@ void SwitcherData::loadGeneralSettings(obs_data_t *obj)
|
|||||||
obs_data_set_default_int(obj, "idleTabPos", 10);
|
obs_data_set_default_int(obj, "idleTabPos", 10);
|
||||||
obs_data_set_default_int(obj, "sequenceTabPos", 11);
|
obs_data_set_default_int(obj, "sequenceTabPos", 11);
|
||||||
obs_data_set_default_int(obj, "audioTabPos", 12);
|
obs_data_set_default_int(obj, "audioTabPos", 12);
|
||||||
|
obs_data_set_default_int(obj, "sceneGroupTabPos", 13);
|
||||||
|
obs_data_set_default_int(obj, "triggerTabPos", 14);
|
||||||
|
|
||||||
switcher->tabOrder.emplace_back(
|
switcher->tabOrder.emplace_back(
|
||||||
(int)(obs_data_get_int(obj, "generalTabPos")));
|
(int)(obs_data_get_int(obj, "generalTabPos")));
|
||||||
@@ -603,13 +611,79 @@ void SwitcherData::loadGeneralSettings(obs_data_t *obj)
|
|||||||
(int)(obs_data_get_int(obj, "sequenceTabPos")));
|
(int)(obs_data_get_int(obj, "sequenceTabPos")));
|
||||||
switcher->tabOrder.emplace_back(
|
switcher->tabOrder.emplace_back(
|
||||||
(int)(obs_data_get_int(obj, "audioTabPos")));
|
(int)(obs_data_get_int(obj, "audioTabPos")));
|
||||||
|
switcher->tabOrder.emplace_back(
|
||||||
|
(int)(obs_data_get_int(obj, "sceneGroupTabPos")));
|
||||||
|
switcher->tabOrder.emplace_back(
|
||||||
|
(int)(obs_data_get_int(obj, "triggerTabPos")));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitcherData::checkNoMatchSwitch(bool &match, OBSWeakSource &scene,
|
||||||
|
OBSWeakSource &transition, int &sleep)
|
||||||
|
{
|
||||||
|
if (match) {
|
||||||
|
noMatchCount = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((noMatchCount * interval) / 1000.0 < noMatchDelay) {
|
||||||
|
noMatchCount++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (switchIfNotMatching == SWITCH && nonMatchingScene) {
|
||||||
|
match = true;
|
||||||
|
scene = nonMatchingScene;
|
||||||
|
transition = nullptr;
|
||||||
|
}
|
||||||
|
if (switchIfNotMatching == RANDOM_SWITCH) {
|
||||||
|
checkRandom(match, scene, transition, sleep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitcherData::checkSwitchCooldown(bool &match)
|
||||||
|
{
|
||||||
|
if (!match || cooldown == 0.) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto now = std::chrono::high_resolution_clock::now();
|
||||||
|
auto timePassed = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||||
|
now - lastMatchTime);
|
||||||
|
|
||||||
|
if (timePassed.count() > cooldown * 1000) {
|
||||||
|
lastMatchTime = now;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match = false;
|
||||||
|
vblog(LOG_INFO, "cooldown active - ignoring match");
|
||||||
|
}
|
||||||
|
|
||||||
|
void populateStartupBehavior(QComboBox *cb)
|
||||||
|
{
|
||||||
|
cb->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.generalTab.status.onStartup.asLastRun"));
|
||||||
|
cb->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart"));
|
||||||
|
cb->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.generalTab.status.onStartup.doNotStart"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void populateAutoStartEventSelection(QComboBox *cb)
|
||||||
|
{
|
||||||
|
cb->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.generalTab.status.autoStart.never"));
|
||||||
|
cb->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.generalTab.status.autoStart.recording"));
|
||||||
|
cb->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.generalTab.status.autoStart.streaming"));
|
||||||
|
cb->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.generalTab.status.autoStart.recordingAndStreaming"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::setupGeneralTab()
|
void AdvSceneSwitcher::setupGeneralTab()
|
||||||
{
|
{
|
||||||
populateSceneSelection(ui->noMatchSwitchScene, false);
|
populateSceneSelection(ui->noMatchSwitchScene, false);
|
||||||
populateSceneSelection(ui->autoStopScenes, false);
|
|
||||||
populateSceneSelection(ui->autoStartScenes, false);
|
|
||||||
|
|
||||||
if (switcher->switchIfNotMatching == SWITCH) {
|
if (switcher->switchIfNotMatching == SWITCH) {
|
||||||
ui->noMatchSwitch->setChecked(true);
|
ui->noMatchSwitch->setChecked(true);
|
||||||
@@ -623,34 +697,14 @@ void AdvSceneSwitcher::setupGeneralTab()
|
|||||||
}
|
}
|
||||||
ui->noMatchSwitchScene->setCurrentText(
|
ui->noMatchSwitchScene->setCurrentText(
|
||||||
GetWeakSourceName(switcher->nonMatchingScene).c_str());
|
GetWeakSourceName(switcher->nonMatchingScene).c_str());
|
||||||
|
ui->noMatchDelay->setValue(switcher->noMatchDelay);
|
||||||
|
ui->noMatchDelay->setToolTip(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.generalTab.generalBehavior.onNoMetDelayTooltip"));
|
||||||
ui->checkInterval->setValue(switcher->interval);
|
ui->checkInterval->setValue(switcher->interval);
|
||||||
|
|
||||||
ui->autoStopSceneCheckBox->setChecked(switcher->autoStopEnable);
|
ui->cooldownTime->setValue(switcher->cooldown);
|
||||||
ui->autoStopScenes->setCurrentText(
|
ui->cooldownTime->setToolTip(obs_module_text(
|
||||||
GetWeakSourceName(switcher->autoStopScene).c_str());
|
"AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint"));
|
||||||
|
|
||||||
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->verboseLogging->setChecked(switcher->verbose);
|
||||||
ui->uiHintsDisable->setChecked(switcher->disableHints);
|
ui->uiHintsDisable->setChecked(switcher->disableHints);
|
||||||
@@ -659,31 +713,40 @@ void AdvSceneSwitcher::setupGeneralTab()
|
|||||||
std::string s = "";
|
std::string s = "";
|
||||||
switch (p) {
|
switch (p) {
|
||||||
case read_file_func:
|
case read_file_func:
|
||||||
s = "File Content";
|
s = obs_module_text(
|
||||||
|
"AdvSceneSwitcher.generalTab.priority.fileContent");
|
||||||
break;
|
break;
|
||||||
case round_trip_func:
|
case round_trip_func:
|
||||||
s = "Scene Sequence";
|
s = obs_module_text(
|
||||||
|
"AdvSceneSwitcher.generalTab.priority.sceneSequence");
|
||||||
break;
|
break;
|
||||||
case idle_func:
|
case idle_func:
|
||||||
s = "Idle Detection";
|
s = obs_module_text(
|
||||||
|
"AdvSceneSwitcher.generalTab.priority.idleDetection");
|
||||||
break;
|
break;
|
||||||
case exe_func:
|
case exe_func:
|
||||||
s = "Executable";
|
s = obs_module_text(
|
||||||
|
"AdvSceneSwitcher.generalTab.priority.executable");
|
||||||
break;
|
break;
|
||||||
case screen_region_func:
|
case screen_region_func:
|
||||||
s = "Screen Region";
|
s = obs_module_text(
|
||||||
|
"AdvSceneSwitcher.generalTab.priority.screenRegion");
|
||||||
break;
|
break;
|
||||||
case window_title_func:
|
case window_title_func:
|
||||||
s = "Window Title";
|
s = obs_module_text(
|
||||||
|
"AdvSceneSwitcher.generalTab.priority.windowTitle");
|
||||||
break;
|
break;
|
||||||
case media_func:
|
case media_func:
|
||||||
s = "Media";
|
s = obs_module_text(
|
||||||
|
"AdvSceneSwitcher.generalTab.priority.media");
|
||||||
break;
|
break;
|
||||||
case time_func:
|
case time_func:
|
||||||
s = "Time";
|
s = obs_module_text(
|
||||||
|
"AdvSceneSwitcher.generalTab.priority.time");
|
||||||
break;
|
break;
|
||||||
case audio_func:
|
case audio_func:
|
||||||
s = "Audio";
|
s = obs_module_text(
|
||||||
|
"AdvSceneSwitcher.generalTab.priority.audio");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
QString text(s.c_str());
|
QString text(s.c_str());
|
||||||
@@ -705,15 +768,16 @@ void AdvSceneSwitcher::setupGeneralTab()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->startupBehavior->addItem(
|
populateStartupBehavior(ui->startupBehavior);
|
||||||
"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);
|
ui->startupBehavior->setCurrentIndex(switcher->startupBehavior);
|
||||||
|
|
||||||
if (switcher->th && switcher->th->isRunning())
|
populateAutoStartEventSelection(ui->autoStartEvent);
|
||||||
|
ui->autoStartEvent->setCurrentIndex(
|
||||||
|
static_cast<int>(switcher->autoStartEvent));
|
||||||
|
|
||||||
|
if (switcher->th && switcher->th->isRunning()) {
|
||||||
SetStarted();
|
SetStarted();
|
||||||
else
|
} else {
|
||||||
SetStopped();
|
SetStopped();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,10 @@
|
|||||||
#include "switcher-data-structs.hpp"
|
#include "switcher-data-structs.hpp"
|
||||||
|
|
||||||
#define blog(level, msg, ...) blog(level, "[adv-ss] " msg, ##__VA_ARGS__)
|
#define blog(level, msg, ...) blog(level, "[adv-ss] " msg, ##__VA_ARGS__)
|
||||||
|
#define vblog(level, msg, ...) \
|
||||||
|
if (verbose) { \
|
||||||
|
blog(level, "[adv-ss] " msg, ##__VA_ARGS__); \
|
||||||
|
}
|
||||||
|
|
||||||
class QCloseEvent;
|
class QCloseEvent;
|
||||||
|
|
||||||
@@ -27,16 +31,15 @@ public:
|
|||||||
void SetStarted();
|
void SetStarted();
|
||||||
void SetStopped();
|
void SetStopped();
|
||||||
|
|
||||||
int PauseScenesFindByData(const QString &scene);
|
void SetShowFrames();
|
||||||
int PauseWindowsFindByData(const QString &window);
|
void SetHideFrames();
|
||||||
|
void clearFrames(QListWidget *list);
|
||||||
|
|
||||||
int IgnoreWindowsFindByData(const QString &window);
|
int IgnoreWindowsFindByData(const QString &window);
|
||||||
int IgnoreIdleWindowsFindByData(const QString &window);
|
int IgnoreIdleWindowsFindByData(const QString &window);
|
||||||
|
|
||||||
void UpdateNonMatchingScene(const QString &name);
|
void UpdateNonMatchingScene(const QString &name);
|
||||||
void UpdateAutoStopScene(const QString &name);
|
void SetEditSceneGroup(SceneGroup &sg);
|
||||||
void UpdateAutoStartScene(const QString &name);
|
|
||||||
void UpdateIdleDataTransition(const QString &name);
|
|
||||||
void UpdateIdleDataScene(const QString &name);
|
|
||||||
|
|
||||||
void loadUI();
|
void loadUI();
|
||||||
void setupGeneralTab();
|
void setupGeneralTab();
|
||||||
@@ -52,11 +55,19 @@ public:
|
|||||||
void setupFileTab();
|
void setupFileTab();
|
||||||
void setupTimeTab();
|
void setupTimeTab();
|
||||||
void setupAudioTab();
|
void setupAudioTab();
|
||||||
|
void setupSceneGroupTab();
|
||||||
|
void setupTriggerTab();
|
||||||
void setTabOrder();
|
void setTabOrder();
|
||||||
|
|
||||||
|
static bool DisplayMessage(QString msg, bool question = false);
|
||||||
|
static void AskBackup(obs_data_t *obj);
|
||||||
|
|
||||||
static void populateSceneSelection(QComboBox *sel,
|
static void populateSceneSelection(QComboBox *sel,
|
||||||
bool addPrevious = false,
|
bool addPrevious = false,
|
||||||
bool addSelect = true);
|
bool addSceneGroup = false,
|
||||||
|
bool addSelect = true,
|
||||||
|
std::string selectText = "");
|
||||||
|
|
||||||
static void populateTransitionSelection(QComboBox *sel,
|
static void populateTransitionSelection(QComboBox *sel,
|
||||||
bool addSelect = true);
|
bool addSelect = true);
|
||||||
static void populateWindowSelection(QComboBox *sel,
|
static void populateWindowSelection(QComboBox *sel,
|
||||||
@@ -71,9 +82,17 @@ public:
|
|||||||
QColor = QColor(0, 0, 0, 0),
|
QColor = QColor(0, 0, 0, 0),
|
||||||
QString specifier = "QLabel ");
|
QString specifier = "QLabel ");
|
||||||
|
|
||||||
|
void listAddClicked(QListWidget *list, SwitchWidget *newWidget,
|
||||||
|
QPushButton *addButton = nullptr,
|
||||||
|
QMetaObject::Connection *addHighlight = nullptr);
|
||||||
bool listMoveUp(QListWidget *list);
|
bool listMoveUp(QListWidget *list);
|
||||||
bool listMoveDown(QListWidget *list);
|
bool listMoveDown(QListWidget *list);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void SceneGroupAdded(const QString &name);
|
||||||
|
void SceneGroupRemoved(const QString &name);
|
||||||
|
void SceneGroupRenamed(const QString &oldName, const QString newName);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void on_windowUp_clicked();
|
void on_windowUp_clicked();
|
||||||
void on_windowDown_clicked();
|
void on_windowDown_clicked();
|
||||||
@@ -82,11 +101,15 @@ public slots:
|
|||||||
void on_noMatchDontSwitch_clicked();
|
void on_noMatchDontSwitch_clicked();
|
||||||
void on_noMatchSwitch_clicked();
|
void on_noMatchSwitch_clicked();
|
||||||
void on_noMatchRandomSwitch_clicked();
|
void on_noMatchRandomSwitch_clicked();
|
||||||
|
void on_noMatchDelay_valueChanged(double i);
|
||||||
|
void on_cooldownTime_valueChanged(double i);
|
||||||
void on_startupBehavior_currentIndexChanged(int index);
|
void on_startupBehavior_currentIndexChanged(int index);
|
||||||
|
void on_autoStartEvent_currentIndexChanged(int index);
|
||||||
void on_noMatchSwitchScene_currentTextChanged(const QString &text);
|
void on_noMatchSwitchScene_currentTextChanged(const QString &text);
|
||||||
void on_checkInterval_valueChanged(int value);
|
void on_checkInterval_valueChanged(int value);
|
||||||
void on_toggleStartButton_clicked();
|
void on_toggleStartButton_clicked();
|
||||||
void on_tabMoved(int from, int to);
|
void on_tabMoved(int from, int to);
|
||||||
|
void on_tabWidget_currentChanged(int index);
|
||||||
|
|
||||||
void on_screenRegionSwitches_currentRowChanged(int idx);
|
void on_screenRegionSwitches_currentRowChanged(int idx);
|
||||||
void on_showFrame_clicked();
|
void on_showFrame_clicked();
|
||||||
@@ -95,13 +118,10 @@ public slots:
|
|||||||
void on_screenRegionUp_clicked();
|
void on_screenRegionUp_clicked();
|
||||||
void on_screenRegionDown_clicked();
|
void on_screenRegionDown_clicked();
|
||||||
|
|
||||||
void on_pauseScenes_currentRowChanged(int idx);
|
void on_pauseUp_clicked();
|
||||||
void on_pauseScenesAdd_clicked();
|
void on_pauseDown_clicked();
|
||||||
void on_pauseScenesRemove_clicked();
|
void on_pauseAdd_clicked();
|
||||||
|
void on_pauseRemove_clicked();
|
||||||
void on_pauseWindows_currentRowChanged(int idx);
|
|
||||||
void on_pauseWindowsAdd_clicked();
|
|
||||||
void on_pauseWindowsRemove_clicked();
|
|
||||||
|
|
||||||
void on_ignoreWindows_currentRowChanged(int idx);
|
void on_ignoreWindows_currentRowChanged(int idx);
|
||||||
void on_ignoreWindowsAdd_clicked();
|
void on_ignoreWindowsAdd_clicked();
|
||||||
@@ -114,13 +134,6 @@ public slots:
|
|||||||
void on_sceneSequenceUp_clicked();
|
void on_sceneSequenceUp_clicked();
|
||||||
void on_sceneSequenceDown_clicked();
|
void on_sceneSequenceDown_clicked();
|
||||||
|
|
||||||
void on_autoStopSceneCheckBox_stateChanged(int state);
|
|
||||||
void on_autoStopScenes_currentTextChanged(const QString &text);
|
|
||||||
|
|
||||||
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_verboseLogging_stateChanged(int state);
|
||||||
void on_uiHintsDisable_stateChanged(int state);
|
void on_uiHintsDisable_stateChanged(int state);
|
||||||
|
|
||||||
@@ -139,7 +152,6 @@ public slots:
|
|||||||
|
|
||||||
void on_browseButton_clicked();
|
void on_browseButton_clicked();
|
||||||
void on_readFileCheckBox_stateChanged(int state);
|
void on_readFileCheckBox_stateChanged(int state);
|
||||||
void on_fileType_currentIndexChanged(int idx);
|
|
||||||
void on_readPathLineEdit_textChanged(const QString &text);
|
void on_readPathLineEdit_textChanged(const QString &text);
|
||||||
void on_writePathLineEdit_textChanged(const QString &text);
|
void on_writePathLineEdit_textChanged(const QString &text);
|
||||||
void on_browseButton_2_clicked();
|
void on_browseButton_2_clicked();
|
||||||
@@ -150,9 +162,6 @@ public slots:
|
|||||||
void on_executableRemove_clicked();
|
void on_executableRemove_clicked();
|
||||||
|
|
||||||
void on_idleCheckBox_stateChanged(int state);
|
void on_idleCheckBox_stateChanged(int state);
|
||||||
void on_idleTransitions_currentTextChanged(const QString &text);
|
|
||||||
void on_idleScenes_currentTextChanged(const QString &text);
|
|
||||||
void on_idleSpinBox_valueChanged(int i);
|
|
||||||
void on_ignoreIdleWindows_currentRowChanged(int idx);
|
void on_ignoreIdleWindows_currentRowChanged(int idx);
|
||||||
void on_ignoreIdleAdd_clicked();
|
void on_ignoreIdleAdd_clicked();
|
||||||
void on_ignoreIdleRemove_clicked();
|
void on_ignoreIdleRemove_clicked();
|
||||||
@@ -162,8 +171,7 @@ public slots:
|
|||||||
|
|
||||||
void on_fileAdd_clicked();
|
void on_fileAdd_clicked();
|
||||||
void on_fileRemove_clicked();
|
void on_fileRemove_clicked();
|
||||||
void on_fileScenesList_currentRowChanged(int idx);
|
void on_fileSwitches_currentRowChanged(int idx);
|
||||||
void on_browseButton_3_clicked();
|
|
||||||
void on_fileUp_clicked();
|
void on_fileUp_clicked();
|
||||||
void on_fileDown_clicked();
|
void on_fileDown_clicked();
|
||||||
|
|
||||||
@@ -181,6 +189,24 @@ public slots:
|
|||||||
void on_audioRemove_clicked();
|
void on_audioRemove_clicked();
|
||||||
void on_audioUp_clicked();
|
void on_audioUp_clicked();
|
||||||
void on_audioDown_clicked();
|
void on_audioDown_clicked();
|
||||||
|
void on_audioFallback_toggled(bool on);
|
||||||
|
|
||||||
|
void on_sceneGroupAdd_clicked();
|
||||||
|
void on_sceneGroupRemove_clicked();
|
||||||
|
void on_sceneGroupUp_clicked();
|
||||||
|
void on_sceneGroupDown_clicked();
|
||||||
|
void on_sceneGroupName_editingFinished();
|
||||||
|
void on_sceneGroups_currentRowChanged(int idx);
|
||||||
|
|
||||||
|
void on_sceneGroupSceneAdd_clicked();
|
||||||
|
void on_sceneGroupSceneRemove_clicked();
|
||||||
|
void on_sceneGroupSceneUp_clicked();
|
||||||
|
void on_sceneGroupSceneDown_clicked();
|
||||||
|
|
||||||
|
void on_triggerAdd_clicked();
|
||||||
|
void on_triggerRemove_clicked();
|
||||||
|
void on_triggerUp_clicked();
|
||||||
|
void on_triggerDown_clicked();
|
||||||
|
|
||||||
void on_priorityUp_clicked();
|
void on_priorityUp_clicked();
|
||||||
void on_priorityDown_clicked();
|
void on_priorityDown_clicked();
|
||||||
@@ -193,34 +219,34 @@ public slots:
|
|||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|
||||||
/********************************************************************************
|
/******************************************************************************
|
||||||
* Windowtitle helper
|
* Windowtitle helper
|
||||||
********************************************************************************/
|
******************************************************************************/
|
||||||
void GetWindowList(std::vector<std::string> &windows);
|
void GetWindowList(std::vector<std::string> &windows);
|
||||||
void GetWindowList(QStringList &windows); // Overloaded
|
void GetWindowList(QStringList &windows);
|
||||||
void GetCurrentWindowTitle(std::string &title);
|
void GetCurrentWindowTitle(std::string &title);
|
||||||
bool isFullscreen(std::string &title);
|
bool isFullscreen(std::string &title);
|
||||||
bool isMaximized(std::string &title);
|
bool isMaximized(std::string &title);
|
||||||
|
|
||||||
/********************************************************************************
|
/******************************************************************************
|
||||||
* Screenregion helper
|
* Screenregion helper
|
||||||
********************************************************************************/
|
******************************************************************************/
|
||||||
std::pair<int, int> getCursorPos();
|
std::pair<int, int> getCursorPos();
|
||||||
|
|
||||||
/********************************************************************************
|
/******************************************************************************
|
||||||
* Idle detection helper
|
* Idle detection helper
|
||||||
********************************************************************************/
|
******************************************************************************/
|
||||||
int secondsSinceLastInput();
|
int secondsSinceLastInput();
|
||||||
|
|
||||||
/********************************************************************************
|
/******************************************************************************
|
||||||
* Executable helper
|
* Executable helper
|
||||||
********************************************************************************/
|
******************************************************************************/
|
||||||
void GetProcessList(QStringList &processes);
|
void GetProcessList(QStringList &processes);
|
||||||
bool isInFocus(const QString &executable);
|
bool isInFocus(const QString &executable);
|
||||||
|
|
||||||
/********************************************************************************
|
/******************************************************************************
|
||||||
* Sceneswitch helper
|
* Sceneswitch helper
|
||||||
********************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
void setNextTransition(OBSWeakSource &targetScene, obs_source_t *currentSource,
|
void setNextTransition(OBSWeakSource &targetScene, obs_source_t *currentSource,
|
||||||
OBSWeakSource &transition,
|
OBSWeakSource &transition,
|
||||||
@@ -228,13 +254,11 @@ void setNextTransition(OBSWeakSource &targetScene, obs_source_t *currentSource,
|
|||||||
void overwriteTransitionOverride(obs_weak_source_t *sceneWs,
|
void overwriteTransitionOverride(obs_weak_source_t *sceneWs,
|
||||||
obs_source_t *transition, transitionData &td);
|
obs_source_t *transition, transitionData &td);
|
||||||
void restoreTransitionOverride(obs_source_t *scene, transitionData td);
|
void restoreTransitionOverride(obs_source_t *scene, transitionData td);
|
||||||
|
|
||||||
void switchScene(OBSWeakSource &scene, OBSWeakSource &transition,
|
void switchScene(OBSWeakSource &scene, OBSWeakSource &transition,
|
||||||
bool &transitionOverrideOverride,
|
bool &transitionOverrideOverride);
|
||||||
std::unique_lock<std::mutex> &lock);
|
|
||||||
|
|
||||||
/********************************************************************************
|
/******************************************************************************
|
||||||
* Main SwitcherData
|
* Main SwitcherData
|
||||||
********************************************************************************/
|
******************************************************************************/
|
||||||
struct SwitcherData;
|
struct SwitcherData;
|
||||||
extern SwitcherData *switcher;
|
extern SwitcherData *switcher;
|
||||||
|
|||||||
108
src/headers/scene-group.hpp
Normal file
108
src/headers/scene-group.hpp
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QSpinBox>
|
||||||
|
#include <QDoubleSpinBox>
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <obs.hpp>
|
||||||
|
|
||||||
|
auto constexpr invalid_scene_group_name = "invalid-scene-group";
|
||||||
|
|
||||||
|
enum class AdvanceCondition {
|
||||||
|
Count,
|
||||||
|
Time,
|
||||||
|
Random,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SceneGroup {
|
||||||
|
OBSWeakSource getCurrentScene();
|
||||||
|
OBSWeakSource getNextScene();
|
||||||
|
OBSWeakSource getNextSceneCount();
|
||||||
|
OBSWeakSource getNextSceneTime();
|
||||||
|
OBSWeakSource getNextSceneRandom();
|
||||||
|
void advanceIdx();
|
||||||
|
|
||||||
|
std::string name = invalid_scene_group_name;
|
||||||
|
AdvanceCondition type = AdvanceCondition::Count;
|
||||||
|
std::vector<OBSWeakSource> scenes = {};
|
||||||
|
int count = 1;
|
||||||
|
double time = 0;
|
||||||
|
bool repeat = false;
|
||||||
|
|
||||||
|
size_t currentIdx = 0;
|
||||||
|
|
||||||
|
int currentCount = -1;
|
||||||
|
std::chrono::high_resolution_clock::time_point lastAdvTime;
|
||||||
|
OBSWeakSource lastRandomScene = nullptr;
|
||||||
|
|
||||||
|
inline SceneGroup(){};
|
||||||
|
inline SceneGroup(std::string name_) : name(name_){};
|
||||||
|
inline SceneGroup(std::string name_, AdvanceCondition type_,
|
||||||
|
std::vector<OBSWeakSource> scenes_, int count_,
|
||||||
|
double time_, bool repeat_)
|
||||||
|
: name(name_),
|
||||||
|
type(type_),
|
||||||
|
scenes(scenes_),
|
||||||
|
count(count_),
|
||||||
|
time(time_),
|
||||||
|
repeat(repeat_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SwitchTargetType {
|
||||||
|
Scene,
|
||||||
|
SceneGroup,
|
||||||
|
};
|
||||||
|
|
||||||
|
class SceneGroupEditWidget : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
SceneGroupEditWidget();
|
||||||
|
void SetEditSceneGroup(SceneGroup *sg);
|
||||||
|
void ShowCurrentTypeEdit();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void TypeChanged(int type);
|
||||||
|
void CountChanged(int count);
|
||||||
|
void TimeChanged(double time);
|
||||||
|
void RepeatChanged(int state);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QComboBox *type;
|
||||||
|
|
||||||
|
QWidget *timeEdit;
|
||||||
|
QWidget *countEdit;
|
||||||
|
|
||||||
|
QSpinBox *count;
|
||||||
|
QDoubleSpinBox *time;
|
||||||
|
QLabel *random;
|
||||||
|
|
||||||
|
QCheckBox *repeat;
|
||||||
|
|
||||||
|
SceneGroup *sceneGroup = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Based on OBS's NameDialog
|
||||||
|
class SGNameDialog : public QDialog {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
SGNameDialog(QWidget *parent);
|
||||||
|
|
||||||
|
// Returns true if user clicks OK, false otherwise
|
||||||
|
// userTextInput returns string that user typed into dialog
|
||||||
|
static bool AskForName(QWidget *parent, const QString &title,
|
||||||
|
const QString &text, std::string &userTextInput,
|
||||||
|
const QString &placeHolder = QString(""),
|
||||||
|
int maxSize = 170);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QLabel *label;
|
||||||
|
QLineEdit *userText;
|
||||||
|
};
|
||||||
68
src/headers/scene-trigger.hpp
Normal file
68
src/headers/scene-trigger.hpp
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "switch-generic.hpp"
|
||||||
|
|
||||||
|
enum class sceneTriggerType {
|
||||||
|
NONE = 0,
|
||||||
|
SCENE_ACTIVE = 1,
|
||||||
|
SCENE_INACTIVE = 2,
|
||||||
|
SCENE_LEAVE = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class sceneTriggerAction {
|
||||||
|
NONE = 0,
|
||||||
|
START_RECORDING,
|
||||||
|
PAUSE_RECORDING,
|
||||||
|
UNPAUSE_RECORDING,
|
||||||
|
STOP_RECORDING,
|
||||||
|
|
||||||
|
START_STREAMING,
|
||||||
|
STOP_STREAMING,
|
||||||
|
|
||||||
|
START_REPLAY_BUFFER,
|
||||||
|
STOP_REPLAY_BUFFER,
|
||||||
|
|
||||||
|
MUTE_SOURCE,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SceneTrigger : SceneSwitcherEntry {
|
||||||
|
static bool pause;
|
||||||
|
sceneTriggerType triggerType = sceneTriggerType::NONE;
|
||||||
|
sceneTriggerAction triggerAction = sceneTriggerAction::NONE;
|
||||||
|
double duration = 0;
|
||||||
|
OBSWeakSource audioSource = nullptr;
|
||||||
|
|
||||||
|
const char *getType() { return "trigger"; }
|
||||||
|
void save(obs_data_t *obj);
|
||||||
|
void load(obs_data_t *obj);
|
||||||
|
|
||||||
|
bool checkMatch(OBSWeakSource previousScene);
|
||||||
|
void performAction();
|
||||||
|
void logMatch();
|
||||||
|
};
|
||||||
|
|
||||||
|
class SceneTriggerWidget : public SwitchWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
SceneTriggerWidget(QWidget *parent, SceneTrigger *s);
|
||||||
|
SceneTrigger *getSwitchData();
|
||||||
|
void setSwitchData(SceneTrigger *s);
|
||||||
|
|
||||||
|
static void swapSwitchData(SceneTriggerWidget *s1,
|
||||||
|
SceneTriggerWidget *s2);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void TriggerTypeChanged(int index);
|
||||||
|
void TriggerActionChanged(int index);
|
||||||
|
void DurationChanged(double dur);
|
||||||
|
void AudioSourceChanged(const QString &text);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QComboBox *triggers;
|
||||||
|
QComboBox *actions;
|
||||||
|
QDoubleSpinBox *duration;
|
||||||
|
QComboBox *audioSources;
|
||||||
|
|
||||||
|
SceneTrigger *switchData;
|
||||||
|
};
|
||||||
@@ -7,15 +7,26 @@
|
|||||||
constexpr auto audio_func = 8;
|
constexpr auto audio_func = 8;
|
||||||
constexpr auto default_priority_8 = audio_func;
|
constexpr auto default_priority_8 = audio_func;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ABOVE,
|
||||||
|
BELOW,
|
||||||
|
} audioCondition;
|
||||||
|
|
||||||
struct AudioSwitch : virtual SceneSwitcherEntry {
|
struct AudioSwitch : virtual SceneSwitcherEntry {
|
||||||
|
static bool pause;
|
||||||
OBSWeakSource audioSource = nullptr;
|
OBSWeakSource audioSource = nullptr;
|
||||||
int volumeThreshold = 0;
|
int volumeThreshold = 0;
|
||||||
|
audioCondition condition = ABOVE;
|
||||||
|
double duration = 0;
|
||||||
|
unsigned int matchCount = 0;
|
||||||
float peak = -1;
|
float peak = -1;
|
||||||
obs_volmeter_t *volmeter = nullptr;
|
obs_volmeter_t *volmeter = nullptr;
|
||||||
|
|
||||||
const char *getType() { return "audio"; }
|
const char *getType() { return "audio"; }
|
||||||
bool initialized();
|
bool initialized();
|
||||||
bool valid();
|
bool valid();
|
||||||
|
void save(obs_data_t *obj);
|
||||||
|
void load(obs_data_t *obj);
|
||||||
static void setVolumeLevel(void *data,
|
static void setVolumeLevel(void *data,
|
||||||
const float magnitude[MAX_AUDIO_CHANNELS],
|
const float magnitude[MAX_AUDIO_CHANNELS],
|
||||||
const float peak[MAX_AUDIO_CHANNELS],
|
const float peak[MAX_AUDIO_CHANNELS],
|
||||||
@@ -23,9 +34,6 @@ struct AudioSwitch : virtual SceneSwitcherEntry {
|
|||||||
void resetVolmeter();
|
void resetVolmeter();
|
||||||
|
|
||||||
AudioSwitch(){};
|
AudioSwitch(){};
|
||||||
AudioSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
|
||||||
OBSWeakSource audioSource_, int volumeThreshold_,
|
|
||||||
bool usePreviousScene_);
|
|
||||||
AudioSwitch(const AudioSwitch &other);
|
AudioSwitch(const AudioSwitch &other);
|
||||||
AudioSwitch(AudioSwitch &&other);
|
AudioSwitch(AudioSwitch &&other);
|
||||||
~AudioSwitch();
|
~AudioSwitch();
|
||||||
@@ -34,11 +42,21 @@ struct AudioSwitch : virtual SceneSwitcherEntry {
|
|||||||
friend void swap(AudioSwitch &first, AudioSwitch &second);
|
friend void swap(AudioSwitch &first, AudioSwitch &second);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AudioSwitchFallback : virtual SceneSwitcherEntry {
|
||||||
|
const char *getType() { return "audio_fallback"; }
|
||||||
|
void save(obs_data_t *obj);
|
||||||
|
void load(obs_data_t *obj);
|
||||||
|
|
||||||
|
bool enable = false;
|
||||||
|
double duration = 0;
|
||||||
|
unsigned int matchCount = 0;
|
||||||
|
};
|
||||||
|
|
||||||
class AudioSwitchWidget : public SwitchWidget {
|
class AudioSwitchWidget : public SwitchWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AudioSwitchWidget(AudioSwitch *s);
|
AudioSwitchWidget(QWidget *parent, AudioSwitch *s);
|
||||||
void UpdateVolmeterSource();
|
void UpdateVolmeterSource();
|
||||||
AudioSwitch *getSwitchData();
|
AudioSwitch *getSwitchData();
|
||||||
void setSwitchData(AudioSwitch *s);
|
void setSwitchData(AudioSwitch *s);
|
||||||
@@ -49,17 +67,30 @@ public:
|
|||||||
private slots:
|
private slots:
|
||||||
void SourceChanged(const QString &text);
|
void SourceChanged(const QString &text);
|
||||||
void VolumeThresholdChanged(int vol);
|
void VolumeThresholdChanged(int vol);
|
||||||
|
void ConditionChanged(int cond);
|
||||||
|
void DurationChanged(double dur);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QComboBox *audioSources;
|
QComboBox *audioSources;
|
||||||
|
QComboBox *condition;
|
||||||
QSpinBox *audioVolumeThreshold;
|
QSpinBox *audioVolumeThreshold;
|
||||||
|
QDoubleSpinBox *duration;
|
||||||
VolControl *volMeter;
|
VolControl *volMeter;
|
||||||
|
|
||||||
QLabel *whenLabel;
|
|
||||||
QLabel *aboveLabel;
|
|
||||||
QLabel *switchLabel;
|
|
||||||
QLabel *usingLabel;
|
|
||||||
|
|
||||||
AudioSwitch *switchData;
|
AudioSwitch *switchData;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class AudioSwitchFallbackWidget : public SwitchWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
AudioSwitchFallbackWidget(QWidget *parent, AudioSwitchFallback *s);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void DurationChanged(double dur);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QDoubleSpinBox *duration;
|
||||||
|
|
||||||
|
AudioSwitchFallback *switchData;
|
||||||
|
};
|
||||||
|
|||||||
@@ -6,26 +6,20 @@ constexpr auto exe_func = 3;
|
|||||||
constexpr auto default_priority_3 = exe_func;
|
constexpr auto default_priority_3 = exe_func;
|
||||||
|
|
||||||
struct ExecutableSwitch : SceneSwitcherEntry {
|
struct ExecutableSwitch : SceneSwitcherEntry {
|
||||||
|
static bool pause;
|
||||||
QString exe = "";
|
QString exe = "";
|
||||||
bool inFocus = false;
|
bool inFocus = false;
|
||||||
|
|
||||||
const char *getType() { return "exec"; }
|
const char *getType() { return "exec"; }
|
||||||
|
void save(obs_data_t *obj);
|
||||||
inline ExecutableSwitch(){};
|
void load(obs_data_t *obj);
|
||||||
inline ExecutableSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
|
||||||
const QString &exe_, bool inFocus_)
|
|
||||||
: SceneSwitcherEntry(scene_, transition_),
|
|
||||||
exe(exe_),
|
|
||||||
inFocus(inFocus_)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ExecutableSwitchWidget : public SwitchWidget {
|
class ExecutableSwitchWidget : public SwitchWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ExecutableSwitchWidget(ExecutableSwitch *s);
|
ExecutableSwitchWidget(QWidget *parent, ExecutableSwitch *s);
|
||||||
ExecutableSwitch *getSwitchData();
|
ExecutableSwitch *getSwitchData();
|
||||||
void setSwitchData(ExecutableSwitch *s);
|
void setSwitchData(ExecutableSwitch *s);
|
||||||
|
|
||||||
@@ -40,9 +34,5 @@ private:
|
|||||||
QComboBox *processes;
|
QComboBox *processes;
|
||||||
QCheckBox *requiresFocus;
|
QCheckBox *requiresFocus;
|
||||||
|
|
||||||
QLabel *whenLabel;
|
|
||||||
QLabel *switchLabel;
|
|
||||||
QLabel *usingLabel;
|
|
||||||
|
|
||||||
ExecutableSwitch *switchData;
|
ExecutableSwitch *switchData;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,31 +1,62 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "switch-generic.hpp"
|
#include "switch-generic.hpp"
|
||||||
|
#include <QPlainTextEdit>
|
||||||
|
#include <obs-module.h>
|
||||||
|
|
||||||
constexpr auto read_file_func = 0;
|
constexpr auto read_file_func = 0;
|
||||||
constexpr auto default_priority_0 = read_file_func;
|
constexpr auto default_priority_0 = read_file_func;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
LOCAL,
|
||||||
|
REMOTE,
|
||||||
|
} file_type;
|
||||||
|
|
||||||
struct FileSwitch : SceneSwitcherEntry {
|
struct FileSwitch : SceneSwitcherEntry {
|
||||||
std::string file;
|
static bool pause;
|
||||||
std::string text;
|
std::string file = obs_module_text("AdvSceneSwitcher.enterPath");
|
||||||
|
std::string text = obs_module_text("AdvSceneSwitcher.enterText");
|
||||||
bool remote = false;
|
bool remote = false;
|
||||||
bool useRegex = false;
|
bool useRegex = false;
|
||||||
bool useTime = false;
|
bool useTime = false;
|
||||||
|
bool onlyMatchIfChanged = false;
|
||||||
QDateTime lastMod;
|
QDateTime lastMod;
|
||||||
|
size_t lastHash = 0;
|
||||||
|
|
||||||
const char *getType() { return "file"; }
|
const char *getType() { return "file"; }
|
||||||
|
void save(obs_data_t *obj);
|
||||||
|
void load(obs_data_t *obj);
|
||||||
|
};
|
||||||
|
|
||||||
inline FileSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
class FileSwitchWidget : public SwitchWidget {
|
||||||
const char *file_, const char *text_, bool remote_,
|
Q_OBJECT
|
||||||
bool useRegex_, bool useTime_)
|
|
||||||
: SceneSwitcherEntry(scene_, transition_),
|
public:
|
||||||
file(file_),
|
FileSwitchWidget(QWidget *parent, FileSwitch *s);
|
||||||
text(text_),
|
FileSwitch *getSwitchData();
|
||||||
remote(remote_),
|
void setSwitchData(FileSwitch *s);
|
||||||
useRegex(useRegex_),
|
|
||||||
useTime(useTime_),
|
static void swapSwitchData(FileSwitchWidget *as1,
|
||||||
lastMod()
|
FileSwitchWidget *as2);
|
||||||
{
|
|
||||||
}
|
private slots:
|
||||||
|
void FileTypeChanged(int index);
|
||||||
|
void FilePathChanged();
|
||||||
|
void MatchTextChanged();
|
||||||
|
void UseRegexChanged(int state);
|
||||||
|
void CheckModificationDateChanged(int state);
|
||||||
|
void CheckFileContentChanged(int state);
|
||||||
|
void BrowseButtonClicked();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QComboBox *fileType;
|
||||||
|
QLineEdit *filePath;
|
||||||
|
QPushButton *browseButton;
|
||||||
|
QPlainTextEdit *matchText;
|
||||||
|
QCheckBox *useRegex;
|
||||||
|
QCheckBox *checkModificationDate;
|
||||||
|
QCheckBox *checkFileContent;
|
||||||
|
|
||||||
|
FileSwitch *switchData;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FileIOData {
|
struct FileIOData {
|
||||||
@@ -39,4 +70,4 @@ static inline QString MakeFileSwitchName(const QString &scene,
|
|||||||
const QString &transition,
|
const QString &transition,
|
||||||
const QString &fileName,
|
const QString &fileName,
|
||||||
const QString &text, bool useRegex,
|
const QString &text, bool useRegex,
|
||||||
bool useTime);
|
bool useTime, bool onlyMatchIfChanged);
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
|
|
||||||
struct SceneSwitcherEntry {
|
struct SceneSwitcherEntry {
|
||||||
|
SwitchTargetType targetType = SwitchTargetType::Scene;
|
||||||
|
SceneGroup *group = nullptr;
|
||||||
OBSWeakSource scene = nullptr;
|
OBSWeakSource scene = nullptr;
|
||||||
OBSWeakSource transition = nullptr;
|
OBSWeakSource transition = nullptr;
|
||||||
bool usePreviousScene = false;
|
bool usePreviousScene = false;
|
||||||
@@ -10,7 +12,18 @@ struct SceneSwitcherEntry {
|
|||||||
virtual const char *getType() = 0;
|
virtual const char *getType() = 0;
|
||||||
virtual bool initialized();
|
virtual bool initialized();
|
||||||
virtual bool valid();
|
virtual bool valid();
|
||||||
|
virtual void logMatchScene();
|
||||||
|
virtual void logMatchSceneGroup();
|
||||||
virtual void logMatch();
|
virtual void logMatch();
|
||||||
|
virtual OBSWeakSource getScene();
|
||||||
|
virtual void save(obs_data_t *obj,
|
||||||
|
const char *targetTypeSaveName = "targetType",
|
||||||
|
const char *targetSaveName = "target",
|
||||||
|
const char *transitionSaveName = "transition");
|
||||||
|
virtual void load(obs_data_t *obj,
|
||||||
|
const char *targetTypeLoadName = "targetType",
|
||||||
|
const char *targetLoadName = "target",
|
||||||
|
const char *transitionLoadName = "transition");
|
||||||
|
|
||||||
inline SceneSwitcherEntry() {}
|
inline SceneSwitcherEntry() {}
|
||||||
|
|
||||||
@@ -23,6 +36,26 @@ struct SceneSwitcherEntry {
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline SceneSwitcherEntry(SceneGroup *group_, OBSWeakSource transition_,
|
||||||
|
bool usePreviousScene_ = false)
|
||||||
|
: group(group_),
|
||||||
|
transition(transition_),
|
||||||
|
usePreviousScene(usePreviousScene_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline SceneSwitcherEntry(SwitchTargetType targetType_,
|
||||||
|
SceneGroup *group_, OBSWeakSource scene_,
|
||||||
|
OBSWeakSource transition_,
|
||||||
|
bool usePreviousScene_ = false)
|
||||||
|
: targetType(targetType_),
|
||||||
|
group(group_),
|
||||||
|
scene(scene_),
|
||||||
|
transition(transition_),
|
||||||
|
usePreviousScene(usePreviousScene_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
virtual ~SceneSwitcherEntry() {}
|
virtual ~SceneSwitcherEntry() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -30,15 +63,20 @@ class SwitchWidget : public QWidget {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SwitchWidget(SceneSwitcherEntry *s, bool usePreviousScene = true);
|
SwitchWidget(QWidget *parent, SceneSwitcherEntry *s,
|
||||||
|
bool usePreviousScene = true, bool addSceneGroup = false);
|
||||||
virtual SceneSwitcherEntry *getSwitchData();
|
virtual SceneSwitcherEntry *getSwitchData();
|
||||||
virtual void setSwitchData(SceneSwitcherEntry *s);
|
virtual void setSwitchData(SceneSwitcherEntry *s);
|
||||||
|
void showSwitchData();
|
||||||
|
|
||||||
static void swapSwitchData(SwitchWidget *s1, SwitchWidget *s2);
|
static void swapSwitchData(SwitchWidget *s1, SwitchWidget *s2);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void SceneChanged(const QString &text);
|
void SceneChanged(const QString &text);
|
||||||
void TransitionChanged(const QString &text);
|
void TransitionChanged(const QString &text);
|
||||||
|
void SceneGroupAdd(const QString &name);
|
||||||
|
void SceneGroupRemove(const QString &name);
|
||||||
|
void SceneGroupRename(const QString &oldName, const QString &newName);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool loading = true;
|
bool loading = true;
|
||||||
|
|||||||
@@ -6,9 +6,27 @@ constexpr auto idle_func = 2;
|
|||||||
constexpr auto default_priority_2 = idle_func;
|
constexpr auto default_priority_2 = idle_func;
|
||||||
|
|
||||||
struct IdleData : SceneSwitcherEntry {
|
struct IdleData : SceneSwitcherEntry {
|
||||||
|
static bool pause;
|
||||||
bool idleEnable = false;
|
bool idleEnable = false;
|
||||||
int time = default_idle_time;
|
int time = default_idle_time;
|
||||||
bool alreadySwitched = false;
|
bool alreadySwitched = false;
|
||||||
|
|
||||||
const char *getType() { return "idle"; }
|
const char *getType() { return "idle"; }
|
||||||
|
void save(obs_data_t *obj);
|
||||||
|
void load(obs_data_t *obj);
|
||||||
|
};
|
||||||
|
|
||||||
|
class IdleWidget : public SwitchWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
IdleWidget(QWidget *parent, IdleData *s);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void DurationChanged(int dur);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QSpinBox *duration;
|
||||||
|
|
||||||
|
IdleData *switchData;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,20 +13,29 @@ typedef enum {
|
|||||||
} time_restriction;
|
} time_restriction;
|
||||||
|
|
||||||
struct MediaSwitch : SceneSwitcherEntry {
|
struct MediaSwitch : SceneSwitcherEntry {
|
||||||
|
static bool pause;
|
||||||
OBSWeakSource source = nullptr;
|
OBSWeakSource source = nullptr;
|
||||||
obs_media_state state = OBS_MEDIA_STATE_NONE;
|
obs_media_state state = OBS_MEDIA_STATE_NONE;
|
||||||
bool anyState = false;
|
bool anyState = false;
|
||||||
time_restriction restriction = TIME_RESTRICTION_NONE;
|
time_restriction restriction = TIME_RESTRICTION_NONE;
|
||||||
int64_t time = 0;
|
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
|
// Trigger scene change only once even if media state might trigger repeatedly
|
||||||
|
bool matched = false;
|
||||||
|
|
||||||
|
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;
|
bool previousStateEnded = false;
|
||||||
|
|
||||||
|
bool playedToEnd = false;
|
||||||
|
|
||||||
const char *getType() { return "media"; }
|
const char *getType() { return "media"; }
|
||||||
bool initialized();
|
bool initialized();
|
||||||
bool valid();
|
bool valid();
|
||||||
|
void save(obs_data_t *obj);
|
||||||
|
void load(obs_data_t *obj);
|
||||||
|
|
||||||
void clearSignalHandler();
|
void clearSignalHandler();
|
||||||
void resetSignalHandler();
|
void resetSignalHandler();
|
||||||
@@ -34,10 +43,7 @@ struct MediaSwitch : SceneSwitcherEntry {
|
|||||||
static void MediaEnded(void *data, calldata_t *);
|
static void MediaEnded(void *data, calldata_t *);
|
||||||
|
|
||||||
inline MediaSwitch(){};
|
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(const MediaSwitch &other);
|
||||||
MediaSwitch(MediaSwitch &&other);
|
MediaSwitch(MediaSwitch &&other);
|
||||||
~MediaSwitch();
|
~MediaSwitch();
|
||||||
@@ -50,7 +56,7 @@ class MediaSwitchWidget : public SwitchWidget {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MediaSwitchWidget(MediaSwitch *s);
|
MediaSwitchWidget(QWidget *parent, MediaSwitch *s);
|
||||||
MediaSwitch *getSwitchData();
|
MediaSwitch *getSwitchData();
|
||||||
void setSwitchData(MediaSwitch *s);
|
void setSwitchData(MediaSwitch *s);
|
||||||
|
|
||||||
@@ -64,16 +70,10 @@ private slots:
|
|||||||
void TimeChanged(int time);
|
void TimeChanged(int time);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QComboBox *meidaSources;
|
QComboBox *mediaSources;
|
||||||
QComboBox *states;
|
QComboBox *states;
|
||||||
QComboBox *timeRestrictions;
|
QComboBox *timeRestrictions;
|
||||||
QSpinBox *time;
|
QSpinBox *time;
|
||||||
|
|
||||||
QLabel *whenLabel;
|
|
||||||
QLabel *stateLabel;
|
|
||||||
QLabel *andLabel;
|
|
||||||
QLabel *switchLabel;
|
|
||||||
QLabel *usingLabel;
|
|
||||||
|
|
||||||
MediaSwitch *switchData;
|
MediaSwitch *switchData;
|
||||||
};
|
};
|
||||||
|
|||||||
64
src/headers/switch-pause.hpp
Normal file
64
src/headers/switch-pause.hpp
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "switch-generic.hpp"
|
||||||
|
|
||||||
|
enum class PauseType {
|
||||||
|
Scene,
|
||||||
|
Window,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class PauseTarget {
|
||||||
|
All,
|
||||||
|
Transition,
|
||||||
|
Window,
|
||||||
|
Executable,
|
||||||
|
Region,
|
||||||
|
Media,
|
||||||
|
File,
|
||||||
|
Random,
|
||||||
|
Time,
|
||||||
|
Idle,
|
||||||
|
Sequence,
|
||||||
|
Audio,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PauseEntry : SceneSwitcherEntry {
|
||||||
|
PauseType pauseType = PauseType::Scene;
|
||||||
|
PauseTarget pauseTarget = PauseTarget::All;
|
||||||
|
std::string window = "";
|
||||||
|
|
||||||
|
const char *getType() { return "pause"; }
|
||||||
|
bool valid();
|
||||||
|
|
||||||
|
inline PauseEntry(){};
|
||||||
|
inline PauseEntry(OBSWeakSource scene_, PauseType pauseType_,
|
||||||
|
PauseTarget pauseTarget_, const std::string &window_)
|
||||||
|
: SceneSwitcherEntry(scene_, nullptr),
|
||||||
|
pauseType(pauseType_),
|
||||||
|
pauseTarget(pauseTarget_),
|
||||||
|
window(window_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class PauseEntryWidget : public SwitchWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
PauseEntryWidget(QWidget *parent, PauseEntry *s);
|
||||||
|
PauseEntry *getSwitchData();
|
||||||
|
void setSwitchData(PauseEntry *s);
|
||||||
|
|
||||||
|
static void swapSwitchData(PauseEntryWidget *s1, PauseEntryWidget *s2);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void PauseTypeChanged(int index);
|
||||||
|
void PauseTargetChanged(int index);
|
||||||
|
void WindowChanged(const QString &text);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QComboBox *pauseTypes;
|
||||||
|
QComboBox *pauseTargets;
|
||||||
|
QComboBox *windows;
|
||||||
|
|
||||||
|
PauseEntry *switchData;
|
||||||
|
};
|
||||||
@@ -2,23 +2,19 @@
|
|||||||
#include "switch-generic.hpp"
|
#include "switch-generic.hpp"
|
||||||
|
|
||||||
struct RandomSwitch : SceneSwitcherEntry {
|
struct RandomSwitch : SceneSwitcherEntry {
|
||||||
|
static bool pause;
|
||||||
double delay = 0.0;
|
double delay = 0.0;
|
||||||
|
|
||||||
const char *getType() { return "random"; }
|
const char *getType() { return "random"; }
|
||||||
|
void save(obs_data_t *obj);
|
||||||
inline RandomSwitch() {}
|
void load(obs_data_t *obj);
|
||||||
inline RandomSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
|
||||||
double delay_)
|
|
||||||
: SceneSwitcherEntry(scene_, transition_), delay(delay_)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class RandomSwitchWidget : public SwitchWidget {
|
class RandomSwitchWidget : public SwitchWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RandomSwitchWidget(RandomSwitch *s);
|
RandomSwitchWidget(QWidget *parent, RandomSwitch *s);
|
||||||
RandomSwitch *getSwitchData();
|
RandomSwitch *getSwitchData();
|
||||||
void setSwitchData(RandomSwitch *s);
|
void setSwitchData(RandomSwitch *s);
|
||||||
|
|
||||||
@@ -31,9 +27,5 @@ private slots:
|
|||||||
private:
|
private:
|
||||||
QDoubleSpinBox *delay;
|
QDoubleSpinBox *delay;
|
||||||
|
|
||||||
QLabel *switchLabel;
|
|
||||||
QLabel *usingLabel;
|
|
||||||
QLabel *forLabel;
|
|
||||||
|
|
||||||
RandomSwitch *switchData;
|
RandomSwitch *switchData;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,28 +6,20 @@ constexpr auto screen_region_func = 4;
|
|||||||
constexpr auto default_priority_4 = screen_region_func;
|
constexpr auto default_priority_4 = screen_region_func;
|
||||||
|
|
||||||
struct ScreenRegionSwitch : SceneSwitcherEntry {
|
struct ScreenRegionSwitch : SceneSwitcherEntry {
|
||||||
|
static bool pause;
|
||||||
|
OBSWeakSource excludeScene = nullptr;
|
||||||
int minX = 0, minY = 0, maxX = 0, maxY = 0;
|
int minX = 0, minY = 0, maxX = 0, maxY = 0;
|
||||||
|
|
||||||
const char *getType() { return "region"; }
|
const char *getType() { return "region"; }
|
||||||
|
void save(obs_data_t *obj);
|
||||||
inline ScreenRegionSwitch(){};
|
void load(obs_data_t *obj);
|
||||||
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 {
|
class ScreenRegionWidget : public SwitchWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ScreenRegionWidget(ScreenRegionSwitch *s);
|
ScreenRegionWidget(QWidget *parent, ScreenRegionSwitch *s);
|
||||||
ScreenRegionSwitch *getSwitchData();
|
ScreenRegionSwitch *getSwitchData();
|
||||||
void setSwitchData(ScreenRegionSwitch *s);
|
void setSwitchData(ScreenRegionSwitch *s);
|
||||||
|
|
||||||
@@ -38,12 +30,14 @@ public:
|
|||||||
void hideFrame();
|
void hideFrame();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
void ExcludeSceneChanged(const QString &text);
|
||||||
void MinXChanged(int pos);
|
void MinXChanged(int pos);
|
||||||
void MinYChanged(int pos);
|
void MinYChanged(int pos);
|
||||||
void MaxXChanged(int pos);
|
void MaxXChanged(int pos);
|
||||||
void MaxYChanged(int pos);
|
void MaxYChanged(int pos);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QComboBox *excludeScenes;
|
||||||
QSpinBox *minX;
|
QSpinBox *minX;
|
||||||
QSpinBox *minY;
|
QSpinBox *minY;
|
||||||
QSpinBox *maxX;
|
QSpinBox *maxX;
|
||||||
@@ -51,11 +45,6 @@ private:
|
|||||||
|
|
||||||
QFrame helperFrame;
|
QFrame helperFrame;
|
||||||
|
|
||||||
QLabel *cursorLabel;
|
|
||||||
QLabel *xLabel;
|
|
||||||
QLabel *switchLabel;
|
|
||||||
QLabel *usingLabel;
|
|
||||||
|
|
||||||
ScreenRegionSwitch *switchData;
|
ScreenRegionSwitch *switchData;
|
||||||
|
|
||||||
void drawFrame();
|
void drawFrame();
|
||||||
|
|||||||
@@ -11,33 +11,25 @@ typedef enum {
|
|||||||
} delay_units;
|
} delay_units;
|
||||||
|
|
||||||
struct SceneSequenceSwitch : SceneSwitcherEntry {
|
struct SceneSequenceSwitch : SceneSwitcherEntry {
|
||||||
|
static bool pause;
|
||||||
OBSWeakSource startScene = nullptr;
|
OBSWeakSource startScene = nullptr;
|
||||||
double delay = 0;
|
double delay = 0;
|
||||||
int delayMultiplier = 1;
|
int delayMultiplier = 1;
|
||||||
|
bool interruptible = false;
|
||||||
|
unsigned int matchCount = 0;
|
||||||
|
|
||||||
const char *getType() { return "sequence"; }
|
const char *getType() { return "sequence"; }
|
||||||
bool initialized();
|
bool initialized();
|
||||||
bool valid();
|
bool valid();
|
||||||
void logSleep(int dur);
|
void save(obs_data_t *obj);
|
||||||
|
void load(obs_data_t *obj);
|
||||||
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 {
|
class SequenceWidget : public SwitchWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SequenceWidget(SceneSequenceSwitch *s);
|
SequenceWidget(QWidget *parent, SceneSequenceSwitch *s);
|
||||||
SceneSequenceSwitch *getSwitchData();
|
SceneSequenceSwitch *getSwitchData();
|
||||||
void setSwitchData(SceneSequenceSwitch *s);
|
void setSwitchData(SceneSequenceSwitch *s);
|
||||||
|
|
||||||
@@ -49,16 +41,13 @@ private slots:
|
|||||||
void DelayChanged(double delay);
|
void DelayChanged(double delay);
|
||||||
void DelayUnitsChanged(int idx);
|
void DelayUnitsChanged(int idx);
|
||||||
void StartSceneChanged(const QString &text);
|
void StartSceneChanged(const QString &text);
|
||||||
|
void InterruptibleChanged(int state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QDoubleSpinBox *delay;
|
QDoubleSpinBox *delay;
|
||||||
QComboBox *delayUnits;
|
QComboBox *delayUnits;
|
||||||
QComboBox *startScenes;
|
QComboBox *startScenes;
|
||||||
|
QCheckBox *interruptible;
|
||||||
QLabel *whenLabel;
|
|
||||||
QLabel *switchLabel;
|
|
||||||
QLabel *afterLabel;
|
|
||||||
QLabel *usingLabel;
|
|
||||||
|
|
||||||
SceneSequenceSwitch *switchData;
|
SceneSequenceSwitch *switchData;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,27 +19,20 @@ typedef enum {
|
|||||||
} timeTrigger;
|
} timeTrigger;
|
||||||
|
|
||||||
struct TimeSwitch : SceneSwitcherEntry {
|
struct TimeSwitch : SceneSwitcherEntry {
|
||||||
|
static bool pause;
|
||||||
timeTrigger trigger = ANY_DAY;
|
timeTrigger trigger = ANY_DAY;
|
||||||
QTime time = QTime();
|
QTime time = QTime(0, 0);
|
||||||
|
|
||||||
const char *getType() { return "time"; }
|
const char *getType() { return "time"; }
|
||||||
|
void save(obs_data_t *obj);
|
||||||
inline TimeSwitch(){};
|
void load(obs_data_t *obj);
|
||||||
inline TimeSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
|
||||||
timeTrigger trigger_, QTime time_,
|
|
||||||
bool usePreviousScene_)
|
|
||||||
: SceneSwitcherEntry(scene_, transition_, usePreviousScene_),
|
|
||||||
trigger(trigger_),
|
|
||||||
time(time_)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class TimeSwitchWidget : public SwitchWidget {
|
class TimeSwitchWidget : public SwitchWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TimeSwitchWidget(TimeSwitch *s);
|
TimeSwitchWidget(QWidget *parent, TimeSwitch *s);
|
||||||
TimeSwitch *getSwitchData();
|
TimeSwitch *getSwitchData();
|
||||||
void setSwitchData(TimeSwitch *s);
|
void setSwitchData(TimeSwitch *s);
|
||||||
|
|
||||||
@@ -53,9 +46,5 @@ private:
|
|||||||
QComboBox *triggers;
|
QComboBox *triggers;
|
||||||
QTimeEdit *time;
|
QTimeEdit *time;
|
||||||
|
|
||||||
QLabel *atLabel;
|
|
||||||
QLabel *switchLabel;
|
|
||||||
QLabel *usingLabel;
|
|
||||||
|
|
||||||
TimeSwitch *switchData;
|
TimeSwitch *switchData;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ struct SceneTransition : SceneSwitcherEntry {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct DefaultSceneTransition : SceneSwitcherEntry {
|
struct DefaultSceneTransition : SceneSwitcherEntry {
|
||||||
|
static bool pause;
|
||||||
|
|
||||||
const char *getType() { return "def_transition"; }
|
const char *getType() { return "def_transition"; }
|
||||||
|
|
||||||
@@ -32,7 +33,7 @@ class TransitionSwitchWidget : public SwitchWidget {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TransitionSwitchWidget(SceneTransition *s);
|
TransitionSwitchWidget(QWidget *parent, SceneTransition *s);
|
||||||
SceneTransition *getSwitchData();
|
SceneTransition *getSwitchData();
|
||||||
void setSwitchData(SceneTransition *s);
|
void setSwitchData(SceneTransition *s);
|
||||||
|
|
||||||
@@ -45,10 +46,6 @@ private slots:
|
|||||||
private:
|
private:
|
||||||
QComboBox *scenes2;
|
QComboBox *scenes2;
|
||||||
|
|
||||||
QLabel *switchLabel;
|
|
||||||
QLabel *toLabel;
|
|
||||||
QLabel *usingLabel;
|
|
||||||
|
|
||||||
SceneTransition *switchData;
|
SceneTransition *switchData;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -56,7 +53,7 @@ class DefTransitionSwitchWidget : public SwitchWidget {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DefTransitionSwitchWidget(DefaultSceneTransition *s);
|
DefTransitionSwitchWidget(QWidget *parent, DefaultSceneTransition *s);
|
||||||
DefaultSceneTransition *getSwitchData();
|
DefaultSceneTransition *getSwitchData();
|
||||||
void setSwitchData(DefaultSceneTransition *s);
|
void setSwitchData(DefaultSceneTransition *s);
|
||||||
|
|
||||||
@@ -64,8 +61,5 @@ public:
|
|||||||
DefTransitionSwitchWidget *s2);
|
DefTransitionSwitchWidget *s2);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QLabel *whenLabel;
|
|
||||||
QLabel *switchLabel;
|
|
||||||
|
|
||||||
DefaultSceneTransition *switchData;
|
DefaultSceneTransition *switchData;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,31 +5,22 @@ constexpr auto window_title_func = 5;
|
|||||||
constexpr auto default_priority_5 = window_title_func;
|
constexpr auto default_priority_5 = window_title_func;
|
||||||
|
|
||||||
struct WindowSwitch : SceneSwitcherEntry {
|
struct WindowSwitch : SceneSwitcherEntry {
|
||||||
|
static bool pause;
|
||||||
std::string window = "";
|
std::string window = "";
|
||||||
bool fullscreen = false;
|
bool fullscreen = false;
|
||||||
bool maximized = false;
|
bool maximized = false;
|
||||||
bool focus = true;
|
bool focus = true;
|
||||||
|
|
||||||
const char *getType() { return "window"; }
|
const char *getType() { return "window"; }
|
||||||
|
void save(obs_data_t *obj);
|
||||||
inline WindowSwitch() {}
|
void load(obs_data_t *obj);
|
||||||
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 {
|
class WindowSwitchWidget : public SwitchWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
WindowSwitchWidget(WindowSwitch *s);
|
WindowSwitchWidget(QWidget *parent, WindowSwitch *s);
|
||||||
WindowSwitch *getSwitchData();
|
WindowSwitch *getSwitchData();
|
||||||
void setSwitchData(WindowSwitch *s);
|
void setSwitchData(WindowSwitch *s);
|
||||||
|
|
||||||
|
|||||||
@@ -7,11 +7,14 @@
|
|||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
#include "scene-group.hpp"
|
||||||
|
#include "scene-trigger.hpp"
|
||||||
#include "switch-audio.hpp"
|
#include "switch-audio.hpp"
|
||||||
#include "switch-executable.hpp"
|
#include "switch-executable.hpp"
|
||||||
#include "switch-file.hpp"
|
#include "switch-file.hpp"
|
||||||
#include "switch-idle.hpp"
|
#include "switch-idle.hpp"
|
||||||
#include "switch-media.hpp"
|
#include "switch-media.hpp"
|
||||||
|
#include "switch-pause.hpp"
|
||||||
#include "switch-random.hpp"
|
#include "switch-random.hpp"
|
||||||
#include "switch-screen-region.hpp"
|
#include "switch-screen-region.hpp"
|
||||||
#include "switch-time.hpp"
|
#include "switch-time.hpp"
|
||||||
@@ -24,11 +27,13 @@ constexpr auto previous_scene_name = "Previous Scene";
|
|||||||
|
|
||||||
typedef enum { NO_SWITCH = 0, SWITCH = 1, RANDOM_SWITCH = 2 } NoMatch;
|
typedef enum { NO_SWITCH = 0, SWITCH = 1, RANDOM_SWITCH = 2 } NoMatch;
|
||||||
typedef enum { PERSIST = 0, START = 1, STOP = 2 } StartupBehavior;
|
typedef enum { PERSIST = 0, START = 1, STOP = 2 } StartupBehavior;
|
||||||
typedef enum {
|
|
||||||
RECORDING = 0,
|
enum class AutoStartEvent {
|
||||||
STREAMING = 1,
|
NEVER,
|
||||||
RECORINDGSTREAMING = 2
|
RECORDING,
|
||||||
} AutoStartType;
|
STREAMING,
|
||||||
|
RECORINDG_OR_STREAMING,
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct transitionData {
|
typedef struct transitionData {
|
||||||
std::string name = "";
|
std::string name = "";
|
||||||
@@ -57,13 +62,19 @@ struct SwitcherData {
|
|||||||
|
|
||||||
int interval = default_interval;
|
int interval = default_interval;
|
||||||
|
|
||||||
obs_source_t *waitScene = NULL;
|
obs_source_t *waitScene = nullptr;
|
||||||
OBSWeakSource previousScene = NULL;
|
OBSWeakSource previousScene = nullptr;
|
||||||
OBSWeakSource PreviousScene2 = NULL;
|
OBSWeakSource previousSceneHelper = nullptr;
|
||||||
OBSWeakSource lastRandomScene;
|
OBSWeakSource lastRandomScene;
|
||||||
OBSWeakSource nonMatchingScene;
|
OBSWeakSource nonMatchingScene;
|
||||||
NoMatch switchIfNotMatching = NO_SWITCH;
|
NoMatch switchIfNotMatching = NO_SWITCH;
|
||||||
|
double noMatchDelay;
|
||||||
|
double noMatchCount = 0;
|
||||||
StartupBehavior startupBehavior = PERSIST;
|
StartupBehavior startupBehavior = PERSIST;
|
||||||
|
AutoStartEvent autoStartEvent = AutoStartEvent::NEVER;
|
||||||
|
|
||||||
|
double cooldown = 0.;
|
||||||
|
std::chrono::high_resolution_clock::time_point lastMatchTime;
|
||||||
|
|
||||||
std::deque<WindowSwitch> windowSwitches;
|
std::deque<WindowSwitch> windowSwitches;
|
||||||
std::vector<std::string> ignoreIdleWindows;
|
std::vector<std::string> ignoreIdleWindows;
|
||||||
@@ -71,10 +82,6 @@ struct SwitcherData {
|
|||||||
|
|
||||||
std::deque<ScreenRegionSwitch> screenRegionSwitches;
|
std::deque<ScreenRegionSwitch> screenRegionSwitches;
|
||||||
|
|
||||||
std::vector<OBSWeakSource> pauseScenesSwitches;
|
|
||||||
|
|
||||||
std::vector<std::string> pauseWindowsSwitches;
|
|
||||||
|
|
||||||
std::vector<std::string> ignoreWindowsSwitches;
|
std::vector<std::string> ignoreWindowsSwitches;
|
||||||
|
|
||||||
std::deque<SceneSequenceSwitch> sceneSequenceSwitches;
|
std::deque<SceneSequenceSwitch> sceneSequenceSwitches;
|
||||||
@@ -84,29 +91,28 @@ struct SwitcherData {
|
|||||||
IdleData idleData;
|
IdleData idleData;
|
||||||
|
|
||||||
FileIOData fileIO;
|
FileIOData fileIO;
|
||||||
std::vector<FileSwitch> fileSwitches;
|
std::deque<FileSwitch> fileSwitches;
|
||||||
CURL *curl = nullptr;
|
CURL *curl = nullptr;
|
||||||
|
|
||||||
std::deque<ExecutableSwitch> executableSwitches;
|
std::deque<ExecutableSwitch> executableSwitches;
|
||||||
|
|
||||||
bool autoStopEnable = false;
|
std::deque<SceneTrigger> sceneTriggers;
|
||||||
OBSWeakSource autoStopScene;
|
|
||||||
|
|
||||||
bool autoStartEnable = false;
|
|
||||||
AutoStartType autoStartType = RECORDING;
|
|
||||||
OBSWeakSource autoStartScene;
|
|
||||||
bool autoStartedRecently = false;
|
|
||||||
|
|
||||||
std::deque<SceneTransition> sceneTransitions;
|
std::deque<SceneTransition> sceneTransitions;
|
||||||
std::deque<DefaultSceneTransition> defaultSceneTransitions;
|
std::deque<DefaultSceneTransition> defaultSceneTransitions;
|
||||||
bool changedDefTransitionRecently = false;
|
bool checkedDefTransition = false;
|
||||||
|
|
||||||
std::deque<MediaSwitch> mediaSwitches;
|
std::deque<MediaSwitch> mediaSwitches;
|
||||||
|
|
||||||
|
std::deque<PauseEntry> pauseEntries;
|
||||||
|
|
||||||
std::deque<TimeSwitch> timeSwitches;
|
std::deque<TimeSwitch> timeSwitches;
|
||||||
QDateTime liveTime;
|
QDateTime liveTime;
|
||||||
|
|
||||||
std::deque<AudioSwitch> audioSwitches;
|
std::deque<AudioSwitch> audioSwitches;
|
||||||
|
AudioSwitchFallback audioFallback;
|
||||||
|
|
||||||
|
std::deque<SceneGroup> sceneGroups;
|
||||||
|
|
||||||
std::vector<int> functionNamesByPriority = std::vector<int>{
|
std::vector<int> functionNamesByPriority = std::vector<int>{
|
||||||
default_priority_0, default_priority_1, default_priority_2,
|
default_priority_0, default_priority_1, default_priority_2,
|
||||||
@@ -143,9 +149,11 @@ struct SwitcherData {
|
|||||||
std::vector<int> tabOrder;
|
std::vector<int> tabOrder;
|
||||||
|
|
||||||
bool hotkeysRegistered = false;
|
bool hotkeysRegistered = false;
|
||||||
obs_hotkey_id startHotkey;
|
obs_hotkey_id startHotkey = 0;
|
||||||
obs_hotkey_id stopHotkey;
|
obs_hotkey_id stopHotkey = 0;
|
||||||
obs_hotkey_id toggleHotkey;
|
obs_hotkey_id toggleHotkey = 0;
|
||||||
|
|
||||||
|
bool versionChanged(obs_data_t *obj, std::string currentVersion);
|
||||||
|
|
||||||
void Thread();
|
void Thread();
|
||||||
void Start();
|
void Start();
|
||||||
@@ -154,13 +162,13 @@ struct SwitcherData {
|
|||||||
bool sceneChangedDuringWait();
|
bool sceneChangedDuringWait();
|
||||||
bool prioFuncsValid();
|
bool prioFuncsValid();
|
||||||
void writeSceneInfoToFile();
|
void writeSceneInfoToFile();
|
||||||
void setDefaultSceneTransitions();
|
void writeToStatusFile(QString status);
|
||||||
void autoStopStreamAndRecording();
|
|
||||||
void autoStartStreamRecording();
|
|
||||||
bool checkPause();
|
bool checkPause();
|
||||||
|
void checkDefaultSceneTransitions(bool &match,
|
||||||
|
OBSWeakSource &transition);
|
||||||
|
void setCurrentDefTransition(OBSWeakSource &transition);
|
||||||
void checkSceneSequence(bool &match, OBSWeakSource &scene,
|
void checkSceneSequence(bool &match, OBSWeakSource &scene,
|
||||||
OBSWeakSource &transition,
|
OBSWeakSource &transition, int &linger);
|
||||||
std::unique_lock<std::mutex> &lock);
|
|
||||||
void checkIdleSwitch(bool &match, OBSWeakSource &scene,
|
void checkIdleSwitch(bool &match, OBSWeakSource &scene,
|
||||||
OBSWeakSource &transition);
|
OBSWeakSource &transition);
|
||||||
void checkWindowTitleSwitch(bool &match, OBSWeakSource &scene,
|
void checkWindowTitleSwitch(bool &match, OBSWeakSource &scene,
|
||||||
@@ -181,7 +189,14 @@ struct SwitcherData {
|
|||||||
OBSWeakSource &transition);
|
OBSWeakSource &transition);
|
||||||
void checkAudioSwitch(bool &match, OBSWeakSource &scene,
|
void checkAudioSwitch(bool &match, OBSWeakSource &scene,
|
||||||
OBSWeakSource &transition);
|
OBSWeakSource &transition);
|
||||||
|
void checkAudioSwitchFallback(OBSWeakSource &scene,
|
||||||
|
OBSWeakSource &transition);
|
||||||
|
void checkNoMatchSwitch(bool &match, OBSWeakSource &scene,
|
||||||
|
OBSWeakSource &transition, int &sleep);
|
||||||
|
void checkSwitchCooldown(bool &match);
|
||||||
|
void checkTriggers();
|
||||||
|
|
||||||
|
void saveSettings(obs_data_t *obj);
|
||||||
void saveWindowTitleSwitches(obs_data_t *obj);
|
void saveWindowTitleSwitches(obs_data_t *obj);
|
||||||
void saveScreenRegionSwitches(obs_data_t *obj);
|
void saveScreenRegionSwitches(obs_data_t *obj);
|
||||||
void savePauseSwitches(obs_data_t *obj);
|
void savePauseSwitches(obs_data_t *obj);
|
||||||
@@ -194,12 +209,17 @@ struct SwitcherData {
|
|||||||
void saveMediaSwitches(obs_data_t *obj);
|
void saveMediaSwitches(obs_data_t *obj);
|
||||||
void saveTimeSwitches(obs_data_t *obj);
|
void saveTimeSwitches(obs_data_t *obj);
|
||||||
void saveAudioSwitches(obs_data_t *obj);
|
void saveAudioSwitches(obs_data_t *obj);
|
||||||
|
void saveSceneGroups(obs_data_t *obj);
|
||||||
|
void saveSceneTriggers(obs_data_t *obj);
|
||||||
void saveGeneralSettings(obs_data_t *obj);
|
void saveGeneralSettings(obs_data_t *obj);
|
||||||
void saveHotkeys(obs_data_t *obj);
|
void saveHotkeys(obs_data_t *obj);
|
||||||
|
void saveVersion(obs_data_t *obj, std::string currentVersion);
|
||||||
|
|
||||||
|
void loadSettings(obs_data_t *obj);
|
||||||
void loadWindowTitleSwitches(obs_data_t *obj);
|
void loadWindowTitleSwitches(obs_data_t *obj);
|
||||||
void loadScreenRegionSwitches(obs_data_t *obj);
|
void loadScreenRegionSwitches(obs_data_t *obj);
|
||||||
void loadPauseSwitches(obs_data_t *obj);
|
void loadPauseSwitches(obs_data_t *obj);
|
||||||
|
void loadOldPauseSwitches(obs_data_t *obj);
|
||||||
void loadSceneSequenceSwitches(obs_data_t *obj);
|
void loadSceneSequenceSwitches(obs_data_t *obj);
|
||||||
void loadSceneTransitions(obs_data_t *obj);
|
void loadSceneTransitions(obs_data_t *obj);
|
||||||
void loadIdleSwitches(obs_data_t *obj);
|
void loadIdleSwitches(obs_data_t *obj);
|
||||||
@@ -209,10 +229,13 @@ struct SwitcherData {
|
|||||||
void loadMediaSwitches(obs_data_t *obj);
|
void loadMediaSwitches(obs_data_t *obj);
|
||||||
void loadTimeSwitches(obs_data_t *obj);
|
void loadTimeSwitches(obs_data_t *obj);
|
||||||
void loadAudioSwitches(obs_data_t *obj);
|
void loadAudioSwitches(obs_data_t *obj);
|
||||||
|
void loadSceneGroups(obs_data_t *obj);
|
||||||
|
void loadSceneTriggers(obs_data_t *obj);
|
||||||
void loadGeneralSettings(obs_data_t *obj);
|
void loadGeneralSettings(obs_data_t *obj);
|
||||||
void loadHotkeys(obs_data_t *obj);
|
void loadHotkeys(obs_data_t *obj);
|
||||||
|
|
||||||
void Prune();
|
void Prune();
|
||||||
|
|
||||||
inline ~SwitcherData() { Stop(); }
|
inline ~SwitcherData() { Stop(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,28 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <obs.hpp>
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include <obs.hpp>
|
||||||
|
#include <obs-module.h>
|
||||||
#include <obs-frontend-api.h>
|
#include <obs-frontend-api.h>
|
||||||
|
|
||||||
|
static inline bool SceneGroupValid(SceneGroup *group)
|
||||||
|
{
|
||||||
|
if (group) {
|
||||||
|
return group->name != invalid_scene_group_name;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool WeakSourceValid(obs_weak_source_t *ws)
|
static inline bool WeakSourceValid(obs_weak_source_t *ws)
|
||||||
{
|
{
|
||||||
obs_source_t *source = obs_weak_source_get_source(ws);
|
obs_source_t *source = obs_weak_source_get_source(ws);
|
||||||
if (source)
|
if (source) {
|
||||||
obs_source_release(source);
|
obs_source_release(source);
|
||||||
|
}
|
||||||
return !!source;
|
return !!source;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,6 +39,26 @@ static inline std::string GetWeakSourceName(obs_weak_source_t *weak_source)
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline SceneGroup *GetSceneGroupByName(const char *name)
|
||||||
|
{
|
||||||
|
if (!switcher) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (SceneGroup &sg : switcher->sceneGroups) {
|
||||||
|
if (sg.name == name) {
|
||||||
|
return &sg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline SceneGroup *GetSceneGroupByQString(const QString &name)
|
||||||
|
{
|
||||||
|
return GetSceneGroupByName(name.toUtf8().constData());
|
||||||
|
}
|
||||||
|
|
||||||
static inline OBSWeakSource GetWeakSourceByName(const char *name)
|
static inline OBSWeakSource GetWeakSourceByName(const char *name)
|
||||||
{
|
{
|
||||||
OBSWeakSource weak;
|
OBSWeakSource weak;
|
||||||
@@ -82,3 +117,68 @@ static inline OBSWeakSource GetWeakTransitionByQString(const QString &name)
|
|||||||
{
|
{
|
||||||
return GetWeakTransitionByName(name.toUtf8().constData());
|
return GetWeakTransitionByName(name.toUtf8().constData());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline std::string
|
||||||
|
getNextDelim(std::string text,
|
||||||
|
std::unordered_map<std::string, QWidget *> placeholders)
|
||||||
|
{
|
||||||
|
size_t pos = std::string::npos;
|
||||||
|
std::string res = "";
|
||||||
|
|
||||||
|
for (const auto &ph : placeholders) {
|
||||||
|
size_t newPos = text.find(ph.first);
|
||||||
|
if (newPos <= pos) {
|
||||||
|
pos = newPos;
|
||||||
|
res = ph.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos == std::string::npos) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populate layout with labels and widgets based on provided text
|
||||||
|
*
|
||||||
|
* @param text Text based on which labels are generated and widgets are placed.
|
||||||
|
* @param layout Layout in which the widgets and labels will be placed.
|
||||||
|
* @param placeholders Map containing a mapping of placeholder strings to widgets.
|
||||||
|
* @param addStretch Add addStretch() to layout.
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
placeWidgets(std::string text, QBoxLayout *layout,
|
||||||
|
std::unordered_map<std::string, QWidget *> placeholders,
|
||||||
|
bool addStretch = true)
|
||||||
|
{
|
||||||
|
std::vector<std::pair<std::string, QWidget *>> labelsWidgetsPairs;
|
||||||
|
|
||||||
|
std::string delim = getNextDelim(text, placeholders);
|
||||||
|
while (delim != "") {
|
||||||
|
size_t pos = text.find(delim);
|
||||||
|
if (pos != std::string::npos) {
|
||||||
|
labelsWidgetsPairs.emplace_back(text.substr(0, pos),
|
||||||
|
placeholders[delim]);
|
||||||
|
text.erase(0, pos + delim.length());
|
||||||
|
}
|
||||||
|
delim = getNextDelim(text, placeholders);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text != "") {
|
||||||
|
labelsWidgetsPairs.emplace_back(text, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &lw : labelsWidgetsPairs) {
|
||||||
|
if (lw.first != "") {
|
||||||
|
layout->addWidget(new QLabel(lw.first.c_str()));
|
||||||
|
}
|
||||||
|
if (lw.second) {
|
||||||
|
layout->addWidget(lw.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (addStretch) {
|
||||||
|
layout->addStretch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
1
src/headers/version.h
Normal file
1
src/headers/version.h
Normal file
@@ -0,0 +1 @@
|
|||||||
|
extern const char g_GIT_SHA1[];
|
||||||
@@ -11,8 +11,9 @@ void startHotkeyFunc(void *data, obs_hotkey_id id, obs_hotkey_t *hotkey,
|
|||||||
UNUSED_PARAMETER(hotkey);
|
UNUSED_PARAMETER(hotkey);
|
||||||
|
|
||||||
if (pressed) {
|
if (pressed) {
|
||||||
if (!(switcher->th && switcher->th->isRunning()))
|
if (!(switcher->th && switcher->th->isRunning())) {
|
||||||
switcher->Start();
|
switcher->Start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,8 +25,9 @@ void stopHotkeyFunc(void *data, obs_hotkey_id id, obs_hotkey_t *hotkey,
|
|||||||
UNUSED_PARAMETER(hotkey);
|
UNUSED_PARAMETER(hotkey);
|
||||||
|
|
||||||
if (pressed) {
|
if (pressed) {
|
||||||
if (switcher->th && switcher->th->isRunning())
|
if (switcher->th && switcher->th->isRunning()) {
|
||||||
switcher->Stop();
|
switcher->Stop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,24 +39,28 @@ void startStopToggleHotkeyFunc(void *data, obs_hotkey_id id,
|
|||||||
UNUSED_PARAMETER(hotkey);
|
UNUSED_PARAMETER(hotkey);
|
||||||
|
|
||||||
if (pressed) {
|
if (pressed) {
|
||||||
if (switcher->th && switcher->th->isRunning())
|
if (switcher->th && switcher->th->isRunning()) {
|
||||||
switcher->Stop();
|
switcher->Stop();
|
||||||
else
|
} else {
|
||||||
switcher->Start();
|
switcher->Start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void registerHotkeys()
|
void registerHotkeys()
|
||||||
{
|
{
|
||||||
switcher->startHotkey = obs_hotkey_register_frontend(
|
switcher->startHotkey = obs_hotkey_register_frontend(
|
||||||
"startSwitcherHotkey", "Start the Advanced Scene Switcher",
|
"startSwitcherHotkey",
|
||||||
|
obs_module_text("AdvSceneSwitcher.hotkey.startSwitcherHotkey"),
|
||||||
startHotkeyFunc, NULL);
|
startHotkeyFunc, NULL);
|
||||||
switcher->stopHotkey = obs_hotkey_register_frontend(
|
switcher->stopHotkey = obs_hotkey_register_frontend(
|
||||||
"stopSwitcherHotkey", "Stop the Advanced Scene Switcher",
|
"stopSwitcherHotkey",
|
||||||
|
obs_module_text("AdvSceneSwitcher.hotkey.stopSwitcherHotkey"),
|
||||||
stopHotkeyFunc, NULL);
|
stopHotkeyFunc, NULL);
|
||||||
switcher->toggleHotkey = obs_hotkey_register_frontend(
|
switcher->toggleHotkey = obs_hotkey_register_frontend(
|
||||||
"startStopToggleSwitcherHotkey",
|
"startStopToggleSwitcherHotkey",
|
||||||
"Toggle Start/Stop for the Advanced Scene Switcher",
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey"),
|
||||||
startStopToggleHotkeyFunc, NULL);
|
startStopToggleHotkeyFunc, NULL);
|
||||||
|
|
||||||
switcher->hotkeysRegistered = true;
|
switcher->hotkeysRegistered = true;
|
||||||
@@ -81,8 +87,9 @@ void SwitcherData::saveHotkeys(obs_data_t *obj)
|
|||||||
|
|
||||||
void SwitcherData::loadHotkeys(obs_data_t *obj)
|
void SwitcherData::loadHotkeys(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
if (!switcher->hotkeysRegistered)
|
if (!switcher->hotkeysRegistered) {
|
||||||
registerHotkeys();
|
registerHotkeys();
|
||||||
|
}
|
||||||
|
|
||||||
obs_data_array_t *startHotkeyArrray =
|
obs_data_array_t *startHotkeyArrray =
|
||||||
obs_data_get_array(obj, "startHotkey");
|
obs_data_get_array(obj, "startHotkey");
|
||||||
|
|||||||
@@ -17,15 +17,16 @@ void GetWindowList(std::vector<std::string> &windows)
|
|||||||
for (NSDictionary *app in apps) {
|
for (NSDictionary *app in apps) {
|
||||||
// Construct string from NSString accounting for nil
|
// Construct string from NSString accounting for nil
|
||||||
std::string name([[app objectForKey:@"kCGWindowName"]
|
std::string name([[app objectForKey:@"kCGWindowName"]
|
||||||
UTF8String],
|
UTF8String],
|
||||||
[[app objectForKey:@"kCGWindowName"]
|
[[app objectForKey:@"kCGWindowName"]
|
||||||
lengthOfBytesUsingEncoding:
|
lengthOfBytesUsingEncoding:
|
||||||
NSUTF8StringEncoding]);
|
NSUTF8StringEncoding]);
|
||||||
std::string owner([[app objectForKey:@"kCGWindowOwnerName"]
|
std::string owner(
|
||||||
UTF8String],
|
[[app objectForKey:@"kCGWindowOwnerName"]
|
||||||
[[app objectForKey:@"kCGWindowOwnerName"]
|
UTF8String],
|
||||||
lengthOfBytesUsingEncoding:
|
[[app objectForKey:@"kCGWindowOwnerName"]
|
||||||
NSUTF8StringEncoding]);
|
lengthOfBytesUsingEncoding:
|
||||||
|
NSUTF8StringEncoding]);
|
||||||
|
|
||||||
// Check if name exists
|
// Check if name exists
|
||||||
if (!name.empty() &&
|
if (!name.empty() &&
|
||||||
@@ -53,15 +54,16 @@ void GetWindowList(QStringList &windows)
|
|||||||
for (NSDictionary *app in apps) {
|
for (NSDictionary *app in apps) {
|
||||||
// Construct string from NSString accounting for nil
|
// Construct string from NSString accounting for nil
|
||||||
std::string name([[app objectForKey:@"kCGWindowName"]
|
std::string name([[app objectForKey:@"kCGWindowName"]
|
||||||
UTF8String],
|
UTF8String],
|
||||||
[[app objectForKey:@"kCGWindowName"]
|
[[app objectForKey:@"kCGWindowName"]
|
||||||
lengthOfBytesUsingEncoding:
|
lengthOfBytesUsingEncoding:
|
||||||
NSUTF8StringEncoding]);
|
NSUTF8StringEncoding]);
|
||||||
std::string owner([[app objectForKey:@"kCGWindowOwnerName"]
|
std::string owner(
|
||||||
UTF8String],
|
[[app objectForKey:@"kCGWindowOwnerName"]
|
||||||
[[app objectForKey:@"kCGWindowOwnerName"]
|
UTF8String],
|
||||||
lengthOfBytesUsingEncoding:
|
[[app objectForKey:@"kCGWindowOwnerName"]
|
||||||
NSUTF8StringEncoding]);
|
lengthOfBytesUsingEncoding:
|
||||||
|
NSUTF8StringEncoding]);
|
||||||
|
|
||||||
// Check if name exists
|
// Check if name exists
|
||||||
if (!name.empty() &&
|
if (!name.empty() &&
|
||||||
@@ -144,15 +146,16 @@ bool isFullscreen(std::string &title)
|
|||||||
for (NSDictionary *app in apps) {
|
for (NSDictionary *app in apps) {
|
||||||
// Construct string from NSString accounting for nil
|
// Construct string from NSString accounting for nil
|
||||||
std::string name([[app objectForKey:@"kCGWindowName"]
|
std::string name([[app objectForKey:@"kCGWindowName"]
|
||||||
UTF8String],
|
UTF8String],
|
||||||
[[app objectForKey:@"kCGWindowName"]
|
[[app objectForKey:@"kCGWindowName"]
|
||||||
lengthOfBytesUsingEncoding:
|
lengthOfBytesUsingEncoding:
|
||||||
NSUTF8StringEncoding]);
|
NSUTF8StringEncoding]);
|
||||||
std::string owner([[app objectForKey:@"kCGWindowOwnerName"]
|
std::string owner(
|
||||||
UTF8String],
|
[[app objectForKey:@"kCGWindowOwnerName"]
|
||||||
[[app objectForKey:@"kCGWindowOwnerName"]
|
UTF8String],
|
||||||
lengthOfBytesUsingEncoding:
|
[[app objectForKey:@"kCGWindowOwnerName"]
|
||||||
NSUTF8StringEncoding]);
|
lengthOfBytesUsingEncoding:
|
||||||
|
NSUTF8StringEncoding]);
|
||||||
|
|
||||||
// True if switch equals app
|
// True if switch equals app
|
||||||
bool equals = (title == name || title == owner);
|
bool equals = (title == name || title == owner);
|
||||||
|
|||||||
744
src/scene-group.cpp
Normal file
744
src/scene-group.cpp
Normal file
@@ -0,0 +1,744 @@
|
|||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
#include <random>
|
||||||
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
|
static QMetaObject::Connection addPulse;
|
||||||
|
SceneGroupEditWidget *typeEdit = nullptr;
|
||||||
|
|
||||||
|
void SceneGroup::advanceIdx()
|
||||||
|
{
|
||||||
|
currentIdx++;
|
||||||
|
|
||||||
|
if (currentIdx >= scenes.size()) {
|
||||||
|
if (repeat) {
|
||||||
|
currentIdx = 0;
|
||||||
|
} else {
|
||||||
|
currentIdx = scenes.size() - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OBSWeakSource SceneGroup::getNextSceneCount()
|
||||||
|
{
|
||||||
|
currentCount++;
|
||||||
|
if (currentCount >= count) {
|
||||||
|
advanceIdx();
|
||||||
|
currentCount = 0;
|
||||||
|
}
|
||||||
|
return scenes[currentIdx];
|
||||||
|
}
|
||||||
|
|
||||||
|
OBSWeakSource SceneGroup::getNextSceneTime()
|
||||||
|
{
|
||||||
|
if (lastAdvTime.time_since_epoch().count() == 0) {
|
||||||
|
lastAdvTime = std::chrono::high_resolution_clock::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto now = std::chrono::high_resolution_clock::now();
|
||||||
|
auto passedTime = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||||
|
now - lastAdvTime);
|
||||||
|
|
||||||
|
if (passedTime.count() >= time * 1000) {
|
||||||
|
advanceIdx();
|
||||||
|
lastAdvTime = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
return scenes[currentIdx];
|
||||||
|
}
|
||||||
|
|
||||||
|
OBSWeakSource SceneGroup::getNextSceneRandom()
|
||||||
|
{
|
||||||
|
if (scenes.size() == 1) {
|
||||||
|
return *scenes.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<OBSWeakSource> rs(scenes);
|
||||||
|
std::random_device rng;
|
||||||
|
std::mt19937 urng(rng());
|
||||||
|
std::shuffle(rs.begin(), rs.end(), urng);
|
||||||
|
for (OBSWeakSource &s : rs) {
|
||||||
|
if (s == lastRandomScene) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastRandomScene = s;
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
OBSWeakSource SceneGroup::getCurrentScene()
|
||||||
|
{
|
||||||
|
return scenes[currentIdx];
|
||||||
|
}
|
||||||
|
|
||||||
|
OBSWeakSource SceneGroup::getNextScene()
|
||||||
|
{
|
||||||
|
if (scenes.empty()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case AdvanceCondition::Count:
|
||||||
|
return getNextSceneCount();
|
||||||
|
break;
|
||||||
|
case AdvanceCondition::Time:
|
||||||
|
return getNextSceneTime();
|
||||||
|
break;
|
||||||
|
case AdvanceCondition::Random:
|
||||||
|
return getNextSceneRandom();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
blog(LOG_INFO, "unknown scene group type!");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sceneGroupNameExists(std::string name)
|
||||||
|
{
|
||||||
|
obs_source_t *source = obs_get_source_by_name(name.c_str());
|
||||||
|
if (source) {
|
||||||
|
obs_source_release(source);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (SceneGroup &sg : switcher->sceneGroups) {
|
||||||
|
if (sg.name == name) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (name == obs_module_text(
|
||||||
|
"AdvSceneSwitcher.selectPreviousScene") ||
|
||||||
|
(name == invalid_scene_group_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_sceneGroupAdd_clicked()
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
QString format{
|
||||||
|
obs_module_text("AdvSceneSwitcher.sceneGroupTab.defaultname")};
|
||||||
|
|
||||||
|
int i = 1;
|
||||||
|
QString placeHolderText = format.arg(i);
|
||||||
|
while ((sceneGroupNameExists(placeHolderText.toUtf8().constData()))) {
|
||||||
|
placeHolderText = format.arg(++i);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool accepted = SGNameDialog::AskForName(
|
||||||
|
this, obs_module_text("AdvSceneSwitcher.sceneGroupTab.add"),
|
||||||
|
obs_module_text("AdvSceneSwitcher.sceneGroupTab.add"), name,
|
||||||
|
placeHolderText);
|
||||||
|
|
||||||
|
if (!accepted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sceneGroupNameExists(name)) {
|
||||||
|
DisplayMessage(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.sceneGroupTab.exists"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switcher->sceneGroups.emplace_back(name);
|
||||||
|
}
|
||||||
|
QString text = QString::fromStdString(name);
|
||||||
|
|
||||||
|
QListWidgetItem *item = new QListWidgetItem(text, ui->sceneGroups);
|
||||||
|
item->setData(Qt::UserRole, text);
|
||||||
|
ui->sceneGroups->setCurrentItem(item);
|
||||||
|
|
||||||
|
ui->sceneGroupAdd->disconnect(addPulse);
|
||||||
|
ui->sceneGroupHelp->setVisible(false);
|
||||||
|
|
||||||
|
emit SceneGroupAdded(QString::fromStdString(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_sceneGroupRemove_clicked()
|
||||||
|
{
|
||||||
|
QListWidgetItem *item = ui->sceneGroups->currentItem();
|
||||||
|
if (!item) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString name;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
int idx = ui->sceneGroups->currentRow();
|
||||||
|
auto &sg = switcher->sceneGroups;
|
||||||
|
name = QString::fromStdString(sg[idx].name);
|
||||||
|
sg.erase(sg.begin() + idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete item;
|
||||||
|
|
||||||
|
emit SceneGroupRemoved(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_sceneGroupUp_clicked()
|
||||||
|
{
|
||||||
|
int index = ui->sceneGroups->currentRow();
|
||||||
|
if (index != -1 && index != 0) {
|
||||||
|
ui->sceneGroups->insertItem(index - 1,
|
||||||
|
ui->sceneGroups->takeItem(index));
|
||||||
|
ui->sceneGroups->setCurrentRow(index - 1);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
|
||||||
|
iter_swap(switcher->sceneGroups.begin() + index,
|
||||||
|
switcher->sceneGroups.begin() + index - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_sceneGroupDown_clicked()
|
||||||
|
{
|
||||||
|
int index = ui->sceneGroups->currentRow();
|
||||||
|
if (index != -1 && index != ui->sceneGroups->count() - 1) {
|
||||||
|
ui->sceneGroups->insertItem(index + 1,
|
||||||
|
ui->sceneGroups->takeItem(index));
|
||||||
|
ui->sceneGroups->setCurrentRow(index + 1);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
|
||||||
|
iter_swap(switcher->sceneGroups.begin() + index,
|
||||||
|
switcher->sceneGroups.begin() + index + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneGroup *getSelectedSG(Ui_AdvSceneSwitcher *ui)
|
||||||
|
{
|
||||||
|
SceneGroup *currentSG = nullptr;
|
||||||
|
QListWidgetItem *sgItem = ui->sceneGroups->currentItem();
|
||||||
|
|
||||||
|
if (!sgItem) {
|
||||||
|
return currentSG;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString sgName = sgItem->data(Qt::UserRole).toString();
|
||||||
|
for (auto &sg : switcher->sceneGroups) {
|
||||||
|
if (sgName.compare(sg.name.c_str()) == 0) {
|
||||||
|
currentSG = &sg;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentSG;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_sceneGroupName_editingFinished()
|
||||||
|
{
|
||||||
|
bool nameValid = true;
|
||||||
|
|
||||||
|
SceneGroup *currentSG = getSelectedSG(ui.get());
|
||||||
|
if (!currentSG) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString newName = ui->sceneGroupName->text();
|
||||||
|
QString oldName = QString::fromStdString(currentSG->name);
|
||||||
|
|
||||||
|
if (newName.isEmpty() || newName == oldName) {
|
||||||
|
nameValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nameValid && sceneGroupNameExists(newName.toUtf8().constData())) {
|
||||||
|
DisplayMessage(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.sceneGroupTab.exists"));
|
||||||
|
nameValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
if (nameValid) {
|
||||||
|
currentSG->name = newName.toUtf8().constData();
|
||||||
|
QListWidgetItem *sgItem =
|
||||||
|
ui->sceneGroups->currentItem();
|
||||||
|
sgItem->setData(Qt::UserRole, newName);
|
||||||
|
sgItem->setText(newName);
|
||||||
|
} else {
|
||||||
|
ui->sceneGroupName->setText(oldName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emit SceneGroupRenamed(oldName, newName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::SetEditSceneGroup(SceneGroup &sg)
|
||||||
|
{
|
||||||
|
ui->sceneGroupName->setText(sg.name.c_str());
|
||||||
|
ui->sceneGroupScenes->clear();
|
||||||
|
|
||||||
|
for (auto &s : sg.scenes) {
|
||||||
|
QString sceneName =
|
||||||
|
QString::fromStdString(GetWeakSourceName(s));
|
||||||
|
QVariant v = QVariant::fromValue(sceneName);
|
||||||
|
QListWidgetItem *item =
|
||||||
|
new QListWidgetItem(sceneName, ui->sceneGroupScenes);
|
||||||
|
item->setData(Qt::UserRole, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->sceneGroupEdit->setDisabled(false);
|
||||||
|
typeEdit->SetEditSceneGroup(&sg);
|
||||||
|
|
||||||
|
if (sg.scenes.size() == 0) {
|
||||||
|
ui->sceneGroupScenesHelp->setVisible(true);
|
||||||
|
} else {
|
||||||
|
ui->sceneGroupScenesHelp->setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_sceneGroups_currentRowChanged(int idx)
|
||||||
|
{
|
||||||
|
if (loading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx == -1) {
|
||||||
|
ui->sceneGroupEdit->setDisabled(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QListWidgetItem *item = ui->sceneGroups->item(idx);
|
||||||
|
QString sgName = item->data(Qt::UserRole).toString();
|
||||||
|
|
||||||
|
for (auto &sg : switcher->sceneGroups) {
|
||||||
|
if (sgName.compare(sg.name.c_str()) == 0) {
|
||||||
|
SetEditSceneGroup(sg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_sceneGroupSceneAdd_clicked()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
SceneGroup *currentSG = getSelectedSG(ui.get());
|
||||||
|
if (!currentSG) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString sceneName = ui->sceneGroupSceneSelection->currentText();
|
||||||
|
|
||||||
|
if (sceneName.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OBSWeakSource source = GetWeakSourceByQString(sceneName);
|
||||||
|
if (!source) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant v = QVariant::fromValue(sceneName);
|
||||||
|
QListWidgetItem *item =
|
||||||
|
new QListWidgetItem(sceneName, ui->sceneGroupScenes);
|
||||||
|
item->setData(Qt::UserRole, v);
|
||||||
|
|
||||||
|
currentSG->scenes.emplace_back(source);
|
||||||
|
|
||||||
|
ui->sceneGroupScenesHelp->setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_sceneGroupSceneRemove_clicked()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
SceneGroup *currentSG = getSelectedSG(ui.get());
|
||||||
|
if (!currentSG) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int idx = ui->sceneGroupScenes->currentRow();
|
||||||
|
if (idx == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &scenes = currentSG->scenes;
|
||||||
|
scenes.erase(scenes.begin() + idx);
|
||||||
|
|
||||||
|
auto item = ui->sceneGroupScenes->currentItem();
|
||||||
|
delete item;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_sceneGroupSceneUp_clicked()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
SceneGroup *currentSG = getSelectedSG(ui.get());
|
||||||
|
if (!currentSG) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = ui->sceneGroupScenes->currentRow();
|
||||||
|
if (index != -1 && index != 0) {
|
||||||
|
ui->sceneGroupScenes->insertItem(
|
||||||
|
index - 1, ui->sceneGroupScenes->takeItem(index));
|
||||||
|
ui->sceneGroupScenes->setCurrentRow(index - 1);
|
||||||
|
|
||||||
|
iter_swap(currentSG->scenes.begin() + index,
|
||||||
|
currentSG->scenes.begin() + index - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_sceneGroupSceneDown_clicked()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
SceneGroup *currentSG = getSelectedSG(ui.get());
|
||||||
|
if (!currentSG) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = ui->sceneGroupScenes->currentRow();
|
||||||
|
if (index != -1 && index != ui->sceneGroupScenes->count() - 1) {
|
||||||
|
ui->sceneGroupScenes->insertItem(
|
||||||
|
index + 1, ui->sceneGroupScenes->takeItem(index));
|
||||||
|
ui->sceneGroupScenes->setCurrentRow(index + 1);
|
||||||
|
|
||||||
|
iter_swap(currentSG->scenes.begin() + index,
|
||||||
|
currentSG->scenes.begin() + index + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitcherData::saveSceneGroups(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
obs_data_array_t *sceneGroupArray = obs_data_array_create();
|
||||||
|
for (SceneGroup &sg : switcher->sceneGroups) {
|
||||||
|
obs_data_t *array_obj = obs_data_create();
|
||||||
|
|
||||||
|
obs_data_set_string(array_obj, "name", sg.name.c_str());
|
||||||
|
obs_data_set_int(array_obj, "type", static_cast<int>(sg.type));
|
||||||
|
|
||||||
|
obs_data_array_t *scenesArray = obs_data_array_create();
|
||||||
|
|
||||||
|
for (OBSWeakSource s : sg.scenes) {
|
||||||
|
obs_data_t *sceneArray_obj = obs_data_create();
|
||||||
|
obs_source_t *source = obs_weak_source_get_source(s);
|
||||||
|
|
||||||
|
if (source) {
|
||||||
|
const char *name = obs_source_get_name(source);
|
||||||
|
obs_data_set_string(sceneArray_obj, "scene",
|
||||||
|
name);
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_source_release(source);
|
||||||
|
|
||||||
|
obs_data_array_push_back(scenesArray, sceneArray_obj);
|
||||||
|
obs_data_release(sceneArray_obj);
|
||||||
|
}
|
||||||
|
obs_data_set_array(array_obj, "scenes", scenesArray);
|
||||||
|
obs_data_array_release(scenesArray);
|
||||||
|
|
||||||
|
obs_data_set_int(array_obj, "count", sg.count);
|
||||||
|
obs_data_set_double(array_obj, "time", sg.time);
|
||||||
|
obs_data_set_bool(array_obj, "repeat", sg.repeat);
|
||||||
|
|
||||||
|
obs_data_array_push_back(sceneGroupArray, array_obj);
|
||||||
|
obs_data_release(array_obj);
|
||||||
|
}
|
||||||
|
obs_data_set_array(obj, "sceneGroups", sceneGroupArray);
|
||||||
|
obs_data_array_release(sceneGroupArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitcherData::loadSceneGroups(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
switcher->sceneGroups.clear();
|
||||||
|
|
||||||
|
obs_data_array_t *sceneGroupArray =
|
||||||
|
obs_data_get_array(obj, "sceneGroups");
|
||||||
|
size_t count = obs_data_array_count(sceneGroupArray);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
obs_data_t *array_obj = obs_data_array_item(sceneGroupArray, i);
|
||||||
|
|
||||||
|
const char *name = obs_data_get_string(array_obj, "name");
|
||||||
|
AdvanceCondition type = static_cast<AdvanceCondition>(
|
||||||
|
obs_data_get_int(array_obj, "type"));
|
||||||
|
|
||||||
|
std::vector<OBSWeakSource> scenes;
|
||||||
|
obs_data_array_t *scenesArray =
|
||||||
|
obs_data_get_array(array_obj, "scenes");
|
||||||
|
size_t scenesCount = obs_data_array_count(scenesArray);
|
||||||
|
for (size_t j = 0; j < scenesCount; j++) {
|
||||||
|
obs_data_t *scenesArray_obj =
|
||||||
|
obs_data_array_item(scenesArray, j);
|
||||||
|
const char *scene =
|
||||||
|
obs_data_get_string(scenesArray_obj, "scene");
|
||||||
|
scenes.emplace_back(GetWeakSourceByName(scene));
|
||||||
|
obs_data_release(scenesArray_obj);
|
||||||
|
}
|
||||||
|
obs_data_array_release(scenesArray);
|
||||||
|
|
||||||
|
int count = obs_data_get_int(array_obj, "count");
|
||||||
|
double time = obs_data_get_double(array_obj, "time");
|
||||||
|
bool repeat = obs_data_get_bool(array_obj, "repeat");
|
||||||
|
|
||||||
|
switcher->sceneGroups.emplace_back(name, type, scenes, count,
|
||||||
|
time, repeat);
|
||||||
|
|
||||||
|
obs_data_release(array_obj);
|
||||||
|
}
|
||||||
|
obs_data_array_release(sceneGroupArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::setupSceneGroupTab()
|
||||||
|
{
|
||||||
|
populateSceneSelection(ui->sceneGroupSceneSelection);
|
||||||
|
|
||||||
|
for (auto &sg : switcher->sceneGroups) {
|
||||||
|
QString text = QString::fromStdString(sg.name);
|
||||||
|
|
||||||
|
QListWidgetItem *item =
|
||||||
|
new QListWidgetItem(text, ui->sceneGroups);
|
||||||
|
item->setData(Qt::UserRole, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (switcher->sceneGroups.size() == 0) {
|
||||||
|
addPulse = PulseWidget(ui->sceneGroupAdd, QColor(Qt::green));
|
||||||
|
ui->sceneGroupHelp->setVisible(true);
|
||||||
|
} else {
|
||||||
|
ui->sceneGroupHelp->setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
typeEdit = new SceneGroupEditWidget();
|
||||||
|
ui->sceneGroupTypeEdit->addWidget(typeEdit);
|
||||||
|
|
||||||
|
ui->sceneGroupEdit->setDisabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
SGNameDialog::SGNameDialog(QWidget *parent) : QDialog(parent)
|
||||||
|
{
|
||||||
|
setModal(true);
|
||||||
|
setWindowModality(Qt::WindowModality::WindowModal);
|
||||||
|
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||||
|
setFixedWidth(555);
|
||||||
|
setMinimumHeight(100);
|
||||||
|
QVBoxLayout *layout = new QVBoxLayout;
|
||||||
|
setLayout(layout);
|
||||||
|
|
||||||
|
label = new QLabel(this);
|
||||||
|
layout->addWidget(label);
|
||||||
|
label->setText("Set Text");
|
||||||
|
|
||||||
|
userText = new QLineEdit(this);
|
||||||
|
layout->addWidget(userText);
|
||||||
|
|
||||||
|
QDialogButtonBox *buttonbox = new QDialogButtonBox(
|
||||||
|
QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||||
|
layout->addWidget(buttonbox);
|
||||||
|
buttonbox->setCenterButtons(true);
|
||||||
|
connect(buttonbox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||||
|
connect(buttonbox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IsWhitespace(char ch)
|
||||||
|
{
|
||||||
|
return ch == ' ' || ch == '\t';
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CleanWhitespace(std::string &str)
|
||||||
|
{
|
||||||
|
while (str.size() && IsWhitespace(str.back()))
|
||||||
|
str.erase(str.end() - 1);
|
||||||
|
while (str.size() && IsWhitespace(str.front()))
|
||||||
|
str.erase(str.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SGNameDialog::AskForName(QWidget *parent, const QString &title,
|
||||||
|
const QString &text, std::string &userTextInput,
|
||||||
|
const QString &placeHolder, int maxSize)
|
||||||
|
{
|
||||||
|
if (maxSize <= 0 || maxSize > 32767) {
|
||||||
|
maxSize = 170;
|
||||||
|
}
|
||||||
|
|
||||||
|
SGNameDialog dialog(parent);
|
||||||
|
dialog.setWindowTitle(title);
|
||||||
|
|
||||||
|
dialog.label->setText(text);
|
||||||
|
dialog.userText->setMaxLength(maxSize);
|
||||||
|
dialog.userText->setText(placeHolder);
|
||||||
|
dialog.userText->selectAll();
|
||||||
|
|
||||||
|
if (dialog.exec() != DialogCode::Accepted) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
userTextInput = dialog.userText->text().toUtf8().constData();
|
||||||
|
CleanWhitespace(userTextInput);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void populateTypeSelection(QComboBox *list)
|
||||||
|
{
|
||||||
|
list->addItem(
|
||||||
|
obs_module_text("AdvSceneSwitcher.sceneGroupTab.type.count"));
|
||||||
|
list->addItem(
|
||||||
|
obs_module_text("AdvSceneSwitcher.sceneGroupTab.type.time"));
|
||||||
|
list->addItem(
|
||||||
|
obs_module_text("AdvSceneSwitcher.sceneGroupTab.type.random"));
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneGroupEditWidget::SceneGroupEditWidget()
|
||||||
|
{
|
||||||
|
type = new QComboBox();
|
||||||
|
populateTypeSelection(type);
|
||||||
|
|
||||||
|
QWidget::connect(type, SIGNAL(currentIndexChanged(int)), this,
|
||||||
|
SLOT(TypeChanged(int)));
|
||||||
|
|
||||||
|
QHBoxLayout *typeLayout = new QHBoxLayout();
|
||||||
|
typeLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
|
{"{{type}}", type}};
|
||||||
|
placeWidgets(
|
||||||
|
obs_module_text("AdvSceneSwitcher.sceneGroupTab.edit.type"),
|
||||||
|
typeLayout, widgetPlaceholders);
|
||||||
|
|
||||||
|
countEdit = new QWidget();
|
||||||
|
count = new QSpinBox();
|
||||||
|
|
||||||
|
count->setMinimum(1);
|
||||||
|
count->setMaximum(999);
|
||||||
|
|
||||||
|
QWidget::connect(count, SIGNAL(valueChanged(int)), this,
|
||||||
|
SLOT(CountChanged(int)));
|
||||||
|
|
||||||
|
QHBoxLayout *countLayout = new QHBoxLayout(countEdit);
|
||||||
|
countLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
|
widgetPlaceholders = {{"{{count}}", count}};
|
||||||
|
placeWidgets(
|
||||||
|
obs_module_text("AdvSceneSwitcher.sceneGroupTab.edit.count"),
|
||||||
|
countLayout, widgetPlaceholders);
|
||||||
|
|
||||||
|
timeEdit = new QWidget();
|
||||||
|
time = new QDoubleSpinBox();
|
||||||
|
|
||||||
|
time->setMinimum(0.0);
|
||||||
|
time->setMaximum(99999999.00);
|
||||||
|
time->setSuffix("s");
|
||||||
|
|
||||||
|
QWidget::connect(time, SIGNAL(valueChanged(double)), this,
|
||||||
|
SLOT(TimeChanged(double)));
|
||||||
|
|
||||||
|
QHBoxLayout *timeLayout = new QHBoxLayout(timeEdit);
|
||||||
|
timeLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
|
widgetPlaceholders = {{"{{time}}", time}};
|
||||||
|
placeWidgets(
|
||||||
|
obs_module_text("AdvSceneSwitcher.sceneGroupTab.edit.time"),
|
||||||
|
timeLayout, widgetPlaceholders);
|
||||||
|
|
||||||
|
repeat = new QCheckBox(
|
||||||
|
obs_module_text("AdvSceneSwitcher.sceneGroupTab.edit.repeat"));
|
||||||
|
|
||||||
|
QWidget::connect(repeat, SIGNAL(stateChanged(int)), this,
|
||||||
|
SLOT(RepeatChanged(int)));
|
||||||
|
|
||||||
|
random = new QLabel(
|
||||||
|
obs_module_text("AdvSceneSwitcher.sceneGroupTab.edit.random"));
|
||||||
|
|
||||||
|
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||||
|
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
mainLayout->addLayout(typeLayout);
|
||||||
|
mainLayout->addWidget(countEdit);
|
||||||
|
mainLayout->addWidget(timeEdit);
|
||||||
|
mainLayout->addWidget(repeat);
|
||||||
|
mainLayout->addWidget(random);
|
||||||
|
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
countEdit->setVisible(false);
|
||||||
|
timeEdit->setVisible(false);
|
||||||
|
repeat->setVisible(false);
|
||||||
|
random->setVisible(false);
|
||||||
|
|
||||||
|
sceneGroup = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneGroupEditWidget::ShowCurrentTypeEdit()
|
||||||
|
{
|
||||||
|
if (!sceneGroup) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
countEdit->setVisible(false);
|
||||||
|
timeEdit->setVisible(false);
|
||||||
|
repeat->setVisible(false);
|
||||||
|
random->setVisible(false);
|
||||||
|
|
||||||
|
switch (sceneGroup->type) {
|
||||||
|
case AdvanceCondition::Count:
|
||||||
|
countEdit->setVisible(true);
|
||||||
|
repeat->setVisible(true);
|
||||||
|
break;
|
||||||
|
case AdvanceCondition::Time:
|
||||||
|
timeEdit->setVisible(true);
|
||||||
|
repeat->setVisible(true);
|
||||||
|
break;
|
||||||
|
case AdvanceCondition::Random:
|
||||||
|
random->setVisible(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneGroupEditWidget::SetEditSceneGroup(SceneGroup *sg)
|
||||||
|
{
|
||||||
|
if (!sg) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sceneGroup = sg;
|
||||||
|
type->setCurrentIndex(static_cast<int>(sg->type));
|
||||||
|
count->setValue(sg->count);
|
||||||
|
time->setValue(sg->time);
|
||||||
|
repeat->setChecked(sg->repeat);
|
||||||
|
ShowCurrentTypeEdit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneGroupEditWidget::TypeChanged(int type)
|
||||||
|
{
|
||||||
|
if (!sceneGroup) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
sceneGroup->type = static_cast<AdvanceCondition>(type);
|
||||||
|
|
||||||
|
ShowCurrentTypeEdit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneGroupEditWidget::CountChanged(int count)
|
||||||
|
{
|
||||||
|
if (!sceneGroup) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
sceneGroup->count = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneGroupEditWidget::TimeChanged(double time)
|
||||||
|
{
|
||||||
|
if (!sceneGroup) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
sceneGroup->time = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneGroupEditWidget::RepeatChanged(int state)
|
||||||
|
{
|
||||||
|
if (!sceneGroup) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
sceneGroup->repeat = state;
|
||||||
|
}
|
||||||
588
src/scene-trigger.cpp
Normal file
588
src/scene-trigger.cpp
Normal file
@@ -0,0 +1,588 @@
|
|||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
|
bool SceneTrigger::pause = false;
|
||||||
|
static QMetaObject::Connection addPulse;
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_triggerAdd_clicked()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switcher->sceneTriggers.emplace_back();
|
||||||
|
|
||||||
|
listAddClicked(ui->sceneTriggers,
|
||||||
|
new SceneTriggerWidget(this,
|
||||||
|
&switcher->sceneTriggers.back()),
|
||||||
|
ui->triggerAdd, &addPulse);
|
||||||
|
|
||||||
|
ui->triggerHelp->setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_triggerRemove_clicked()
|
||||||
|
{
|
||||||
|
QListWidgetItem *item = ui->sceneTriggers->currentItem();
|
||||||
|
if (!item) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
int idx = ui->sceneTriggers->currentRow();
|
||||||
|
auto &switches = switcher->sceneTriggers;
|
||||||
|
switches.erase(switches.begin() + idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete item;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_triggerUp_clicked()
|
||||||
|
{
|
||||||
|
int index = ui->sceneTriggers->currentRow();
|
||||||
|
if (!listMoveUp(ui->sceneTriggers)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneTriggerWidget *s1 =
|
||||||
|
(SceneTriggerWidget *)ui->sceneTriggers->itemWidget(
|
||||||
|
ui->sceneTriggers->item(index));
|
||||||
|
SceneTriggerWidget *s2 =
|
||||||
|
(SceneTriggerWidget *)ui->sceneTriggers->itemWidget(
|
||||||
|
ui->sceneTriggers->item(index - 1));
|
||||||
|
SceneTriggerWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
|
||||||
|
std::swap(switcher->sceneTriggers[index],
|
||||||
|
switcher->sceneTriggers[index - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_triggerDown_clicked()
|
||||||
|
{
|
||||||
|
int index = ui->sceneTriggers->currentRow();
|
||||||
|
|
||||||
|
if (!listMoveDown(ui->sceneTriggers)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneTriggerWidget *s1 =
|
||||||
|
(SceneTriggerWidget *)ui->sceneTriggers->itemWidget(
|
||||||
|
ui->sceneTriggers->item(index));
|
||||||
|
SceneTriggerWidget *s2 =
|
||||||
|
(SceneTriggerWidget *)ui->sceneTriggers->itemWidget(
|
||||||
|
ui->sceneTriggers->item(index + 1));
|
||||||
|
SceneTriggerWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
|
||||||
|
std::swap(switcher->sceneTriggers[index],
|
||||||
|
switcher->sceneTriggers[index + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneTrigger::logMatch()
|
||||||
|
{
|
||||||
|
std::string sceneName = "";
|
||||||
|
std::string statusName = "";
|
||||||
|
std::string actionName = "";
|
||||||
|
|
||||||
|
switch (triggerType) {
|
||||||
|
case sceneTriggerType::NONE:
|
||||||
|
statusName = "NONE";
|
||||||
|
break;
|
||||||
|
case sceneTriggerType::SCENE_ACTIVE:
|
||||||
|
statusName = "SCENE ACTIVE";
|
||||||
|
break;
|
||||||
|
case sceneTriggerType::SCENE_INACTIVE:
|
||||||
|
statusName = "SCENE INACTIVE";
|
||||||
|
break;
|
||||||
|
case sceneTriggerType::SCENE_LEAVE:
|
||||||
|
statusName = "SCENE LEAVE";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (triggerAction) {
|
||||||
|
case sceneTriggerAction::NONE:
|
||||||
|
actionName = "NONE";
|
||||||
|
break;
|
||||||
|
case sceneTriggerAction::START_RECORDING:
|
||||||
|
actionName = "START RECORDING";
|
||||||
|
break;
|
||||||
|
case sceneTriggerAction::PAUSE_RECORDING:
|
||||||
|
actionName = "PAUSE RECORDING";
|
||||||
|
break;
|
||||||
|
case sceneTriggerAction::UNPAUSE_RECORDING:
|
||||||
|
actionName = "UNPAUSE RECORDING";
|
||||||
|
break;
|
||||||
|
case sceneTriggerAction::STOP_RECORDING:
|
||||||
|
actionName = "STOP RECORDING";
|
||||||
|
break;
|
||||||
|
case sceneTriggerAction::START_STREAMING:
|
||||||
|
actionName = "START STREAMING";
|
||||||
|
break;
|
||||||
|
case sceneTriggerAction::STOP_STREAMING:
|
||||||
|
actionName = "STOP STREAMING";
|
||||||
|
break;
|
||||||
|
case sceneTriggerAction::START_REPLAY_BUFFER:
|
||||||
|
actionName = "START REPLAY BUFFER";
|
||||||
|
break;
|
||||||
|
case sceneTriggerAction::STOP_REPLAY_BUFFER:
|
||||||
|
actionName = "STOP REPLAY BUFFER";
|
||||||
|
break;
|
||||||
|
case sceneTriggerAction::MUTE_SOURCE:
|
||||||
|
actionName = "MUTE (" + GetWeakSourceName(audioSource) + ")";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
actionName = "UNKOWN";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
blog(LOG_INFO,
|
||||||
|
"scene '%s' in status '%s' triggering action '%s' after %f seconds",
|
||||||
|
GetWeakSourceName(scene).c_str(), statusName.c_str(),
|
||||||
|
actionName.c_str(), duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
void frontEndActionThread(sceneTriggerAction action, double delay)
|
||||||
|
{
|
||||||
|
long long mil = delay * 1000;
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(mil));
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case sceneTriggerAction::NONE:
|
||||||
|
break;
|
||||||
|
case sceneTriggerAction::START_RECORDING:
|
||||||
|
obs_frontend_recording_start();
|
||||||
|
break;
|
||||||
|
case sceneTriggerAction::PAUSE_RECORDING:
|
||||||
|
obs_frontend_recording_pause(true);
|
||||||
|
break;
|
||||||
|
case sceneTriggerAction::UNPAUSE_RECORDING:
|
||||||
|
obs_frontend_recording_pause(false);
|
||||||
|
break;
|
||||||
|
case sceneTriggerAction::STOP_RECORDING:
|
||||||
|
obs_frontend_recording_stop();
|
||||||
|
break;
|
||||||
|
case sceneTriggerAction::START_STREAMING:
|
||||||
|
obs_frontend_streaming_start();
|
||||||
|
break;
|
||||||
|
case sceneTriggerAction::STOP_STREAMING:
|
||||||
|
obs_frontend_streaming_stop();
|
||||||
|
break;
|
||||||
|
case sceneTriggerAction::START_REPLAY_BUFFER:
|
||||||
|
obs_frontend_replay_buffer_start();
|
||||||
|
break;
|
||||||
|
case sceneTriggerAction::STOP_REPLAY_BUFFER:
|
||||||
|
obs_frontend_replay_buffer_stop();
|
||||||
|
break;
|
||||||
|
case sceneTriggerAction::MUTE_SOURCE:
|
||||||
|
obs_frontend_replay_buffer_stop();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void muteThread(OBSWeakSource source, double delay)
|
||||||
|
{
|
||||||
|
long long mil = delay * 1000;
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(mil));
|
||||||
|
|
||||||
|
auto s = obs_weak_source_get_source(source);
|
||||||
|
obs_source_set_muted(s, true);
|
||||||
|
obs_source_release(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isFrontendAction(sceneTriggerAction triggerAction)
|
||||||
|
{
|
||||||
|
return triggerAction == sceneTriggerAction::START_RECORDING ||
|
||||||
|
triggerAction == sceneTriggerAction::PAUSE_RECORDING ||
|
||||||
|
triggerAction == sceneTriggerAction::UNPAUSE_RECORDING ||
|
||||||
|
triggerAction == sceneTriggerAction::STOP_RECORDING ||
|
||||||
|
triggerAction == sceneTriggerAction::START_STREAMING ||
|
||||||
|
triggerAction == sceneTriggerAction::STOP_STREAMING ||
|
||||||
|
triggerAction == sceneTriggerAction::START_REPLAY_BUFFER ||
|
||||||
|
triggerAction == sceneTriggerAction::STOP_REPLAY_BUFFER;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneTrigger::performAction()
|
||||||
|
{
|
||||||
|
if (triggerAction == sceneTriggerAction::NONE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::thread t;
|
||||||
|
|
||||||
|
if (isFrontendAction(triggerAction)) {
|
||||||
|
t = std::thread(frontEndActionThread, triggerAction, duration);
|
||||||
|
} else {
|
||||||
|
t = std::thread(muteThread, audioSource, duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
t.detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SceneTrigger::checkMatch(OBSWeakSource previousScene)
|
||||||
|
{
|
||||||
|
OBSSource source = obs_frontend_get_current_scene();
|
||||||
|
OBSWeakSource currentScene = obs_source_get_weak_source(source);
|
||||||
|
obs_source_release(source);
|
||||||
|
obs_weak_source_release(currentScene);
|
||||||
|
|
||||||
|
switch (triggerType) {
|
||||||
|
case sceneTriggerType::NONE:
|
||||||
|
return false;
|
||||||
|
case sceneTriggerType::SCENE_ACTIVE:
|
||||||
|
return currentScene == scene;
|
||||||
|
case sceneTriggerType::SCENE_INACTIVE:
|
||||||
|
return currentScene != scene;
|
||||||
|
case sceneTriggerType::SCENE_LEAVE:
|
||||||
|
return previousScene == scene;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitcherData::checkTriggers()
|
||||||
|
{
|
||||||
|
if (SceneTrigger::pause || stop) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &t : sceneTriggers) {
|
||||||
|
if (t.checkMatch(previousScene)) {
|
||||||
|
t.logMatch();
|
||||||
|
t.performAction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitcherData::saveSceneTriggers(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
obs_data_array_t *triggerArray = obs_data_array_create();
|
||||||
|
for (auto &s : switcher->sceneTriggers) {
|
||||||
|
obs_data_t *array_obj = obs_data_create();
|
||||||
|
|
||||||
|
s.save(array_obj);
|
||||||
|
obs_data_array_push_back(triggerArray, array_obj);
|
||||||
|
|
||||||
|
obs_data_release(array_obj);
|
||||||
|
}
|
||||||
|
obs_data_set_array(obj, "triggers", triggerArray);
|
||||||
|
obs_data_array_release(triggerArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
// To be removed in future version
|
||||||
|
void loadOldAutoStopStart(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
typedef enum {
|
||||||
|
RECORDING = 0,
|
||||||
|
STREAMING = 1,
|
||||||
|
RECORINDGSTREAMING = 2
|
||||||
|
} AutoStartStopType;
|
||||||
|
|
||||||
|
if (obs_data_get_bool(obj, "autoStopEnable")) {
|
||||||
|
std::string autoStopScene =
|
||||||
|
obs_data_get_string(obj, "autoStopSceneName");
|
||||||
|
int action = obs_data_get_int(obj, "autoStopType");
|
||||||
|
|
||||||
|
if (action == RECORDING) {
|
||||||
|
switcher->sceneTriggers.emplace_back();
|
||||||
|
auto &s = switcher->sceneTriggers.back();
|
||||||
|
s.scene = GetWeakSourceByName(autoStopScene.c_str());
|
||||||
|
s.triggerType = sceneTriggerType::SCENE_ACTIVE;
|
||||||
|
s.triggerAction = sceneTriggerAction::STOP_RECORDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action == STREAMING) {
|
||||||
|
switcher->sceneTriggers.emplace_back();
|
||||||
|
auto &s = switcher->sceneTriggers.back();
|
||||||
|
s.scene = GetWeakSourceByName(autoStopScene.c_str());
|
||||||
|
s.triggerType = sceneTriggerType::SCENE_ACTIVE;
|
||||||
|
s.triggerAction = sceneTriggerAction::STOP_STREAMING;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action == RECORINDGSTREAMING) {
|
||||||
|
switcher->sceneTriggers.emplace_back();
|
||||||
|
auto &s = switcher->sceneTriggers.back();
|
||||||
|
s.scene = GetWeakSourceByName(autoStopScene.c_str());
|
||||||
|
s.triggerType = sceneTriggerType::SCENE_ACTIVE;
|
||||||
|
s.triggerAction = sceneTriggerAction::STOP_RECORDING;
|
||||||
|
|
||||||
|
switcher->sceneTriggers.emplace_back();
|
||||||
|
auto &s2 = switcher->sceneTriggers.back();
|
||||||
|
s2.scene = GetWeakSourceByName(autoStopScene.c_str());
|
||||||
|
s2.triggerType = sceneTriggerType::SCENE_ACTIVE;
|
||||||
|
s2.triggerAction = sceneTriggerAction::STOP_STREAMING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obs_data_get_bool(obj, "autoStartEnable")) {
|
||||||
|
std::string autoStartScene =
|
||||||
|
obs_data_get_string(obj, "autoStartSceneName");
|
||||||
|
int action = obs_data_get_int(obj, "autoStartType");
|
||||||
|
|
||||||
|
if (action == RECORDING) {
|
||||||
|
switcher->sceneTriggers.emplace_back();
|
||||||
|
auto &s = switcher->sceneTriggers.back();
|
||||||
|
s.scene = GetWeakSourceByName(autoStartScene.c_str());
|
||||||
|
s.triggerType = sceneTriggerType::SCENE_ACTIVE;
|
||||||
|
s.triggerAction = sceneTriggerAction::START_RECORDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action == STREAMING) {
|
||||||
|
switcher->sceneTriggers.emplace_back();
|
||||||
|
auto &s = switcher->sceneTriggers.back();
|
||||||
|
s.scene = GetWeakSourceByName(autoStartScene.c_str());
|
||||||
|
s.triggerType = sceneTriggerType::SCENE_ACTIVE;
|
||||||
|
s.triggerAction = sceneTriggerAction::START_STREAMING;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action == RECORINDGSTREAMING) {
|
||||||
|
switcher->sceneTriggers.emplace_back();
|
||||||
|
auto &s = switcher->sceneTriggers.back();
|
||||||
|
s.scene = GetWeakSourceByName(autoStartScene.c_str());
|
||||||
|
s.triggerType = sceneTriggerType::SCENE_ACTIVE;
|
||||||
|
s.triggerAction = sceneTriggerAction::START_RECORDING;
|
||||||
|
|
||||||
|
switcher->sceneTriggers.emplace_back();
|
||||||
|
auto &s2 = switcher->sceneTriggers.back();
|
||||||
|
s2.scene = GetWeakSourceByName(autoStartScene.c_str());
|
||||||
|
s2.triggerType = sceneTriggerType::SCENE_ACTIVE;
|
||||||
|
s2.triggerAction = sceneTriggerAction::START_STREAMING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitcherData::loadSceneTriggers(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
switcher->sceneTriggers.clear();
|
||||||
|
|
||||||
|
loadOldAutoStopStart(obj);
|
||||||
|
|
||||||
|
obs_data_array_t *triggerArray = obs_data_get_array(obj, "triggers");
|
||||||
|
size_t count = obs_data_array_count(triggerArray);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
obs_data_t *array_obj = obs_data_array_item(triggerArray, i);
|
||||||
|
|
||||||
|
switcher->sceneTriggers.emplace_back();
|
||||||
|
sceneTriggers.back().load(array_obj);
|
||||||
|
|
||||||
|
obs_data_release(array_obj);
|
||||||
|
}
|
||||||
|
obs_data_array_release(triggerArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::setupTriggerTab()
|
||||||
|
{
|
||||||
|
for (auto &s : switcher->sceneTriggers) {
|
||||||
|
QListWidgetItem *item;
|
||||||
|
item = new QListWidgetItem(ui->sceneTriggers);
|
||||||
|
ui->sceneTriggers->addItem(item);
|
||||||
|
SceneTriggerWidget *sw = new SceneTriggerWidget(this, &s);
|
||||||
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
|
ui->sceneTriggers->setItemWidget(item, sw);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (switcher->sceneTriggers.size() == 0) {
|
||||||
|
addPulse = PulseWidget(ui->triggerAdd, QColor(Qt::green));
|
||||||
|
ui->triggerHelp->setVisible(true);
|
||||||
|
} else {
|
||||||
|
ui->triggerHelp->setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneTrigger::save(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
obs_source_t *sceneSource = obs_weak_source_get_source(scene);
|
||||||
|
const char *sceneName = obs_source_get_name(sceneSource);
|
||||||
|
obs_data_set_string(obj, "scene", sceneName);
|
||||||
|
obs_source_release(sceneSource);
|
||||||
|
|
||||||
|
obs_data_set_int(obj, "triggerType", static_cast<int>(triggerType));
|
||||||
|
obs_data_set_int(obj, "triggerAction", static_cast<int>(triggerAction));
|
||||||
|
obs_data_set_double(obj, "duration", duration);
|
||||||
|
|
||||||
|
obs_source_t *source = obs_weak_source_get_source(audioSource);
|
||||||
|
const char *audioSourceName = obs_source_get_name(source);
|
||||||
|
obs_data_set_string(obj, "audioSource", audioSourceName);
|
||||||
|
obs_source_release(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneTrigger::load(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
const char *sceneName = obs_data_get_string(obj, "scene");
|
||||||
|
scene = GetWeakSourceByName(sceneName);
|
||||||
|
|
||||||
|
triggerType = static_cast<sceneTriggerType>(
|
||||||
|
obs_data_get_int(obj, "triggerType"));
|
||||||
|
triggerAction = static_cast<sceneTriggerAction>(
|
||||||
|
obs_data_get_int(obj, "triggerAction"));
|
||||||
|
duration = obs_data_get_double(obj, "duration");
|
||||||
|
|
||||||
|
const char *audioSourceName = obs_data_get_string(obj, "audioSource");
|
||||||
|
audioSource = GetWeakSourceByName(audioSourceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void populateTriggers(QComboBox *list)
|
||||||
|
{
|
||||||
|
list->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.none"));
|
||||||
|
list->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.sceneActive"));
|
||||||
|
list->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.sceneInactive"));
|
||||||
|
list->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.sceneLeave"));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void populateActions(QComboBox *list)
|
||||||
|
{
|
||||||
|
list->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.none"));
|
||||||
|
list->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startRecording"));
|
||||||
|
list->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.pauseRecording"));
|
||||||
|
list->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.unpauseRecording"));
|
||||||
|
list->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopRecording"));
|
||||||
|
list->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startStreaming"));
|
||||||
|
list->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopStreaming"));
|
||||||
|
list->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startReplayBuffer"));
|
||||||
|
list->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopReplayBuffer"));
|
||||||
|
list->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.muteSource"));
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneTriggerWidget::SceneTriggerWidget(QWidget *parent, SceneTrigger *s)
|
||||||
|
: SwitchWidget(parent, s, false, false)
|
||||||
|
{
|
||||||
|
triggers = new QComboBox();
|
||||||
|
actions = new QComboBox();
|
||||||
|
duration = new QDoubleSpinBox();
|
||||||
|
audioSources = new QComboBox();
|
||||||
|
|
||||||
|
duration->setMinimum(0.0);
|
||||||
|
duration->setMaximum(99.000000);
|
||||||
|
duration->setSuffix("s");
|
||||||
|
|
||||||
|
QWidget::connect(triggers, SIGNAL(currentIndexChanged(int)), this,
|
||||||
|
SLOT(TriggerTypeChanged(int)));
|
||||||
|
QWidget::connect(actions, SIGNAL(currentIndexChanged(int)), this,
|
||||||
|
SLOT(TriggerActionChanged(int)));
|
||||||
|
QWidget::connect(duration, SIGNAL(valueChanged(double)), this,
|
||||||
|
SLOT(DurationChanged(double)));
|
||||||
|
QWidget::connect(audioSources,
|
||||||
|
SIGNAL(currentTextChanged(const QString &)), this,
|
||||||
|
SLOT(AudioSourceChanged(const QString &)));
|
||||||
|
|
||||||
|
populateTriggers(triggers);
|
||||||
|
populateActions(actions);
|
||||||
|
AdvSceneSwitcher::populateAudioSelection(audioSources);
|
||||||
|
|
||||||
|
if (s) {
|
||||||
|
triggers->setCurrentIndex(static_cast<int>(s->triggerType));
|
||||||
|
actions->setCurrentIndex(static_cast<int>(s->triggerAction));
|
||||||
|
duration->setValue(s->duration);
|
||||||
|
|
||||||
|
audioSources->setCurrentText(
|
||||||
|
GetWeakSourceName(s->audioSource).c_str());
|
||||||
|
|
||||||
|
if (s->triggerAction == sceneTriggerAction::MUTE_SOURCE) {
|
||||||
|
audioSources->show();
|
||||||
|
} else {
|
||||||
|
audioSources->hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
|
{"{{triggers}}", triggers},
|
||||||
|
{"{{actions}}", actions},
|
||||||
|
{"{{audioSources}}", audioSources},
|
||||||
|
{"{{duration}}", duration},
|
||||||
|
{"{{scenes}}", scenes}};
|
||||||
|
placeWidgets(obs_module_text("AdvSceneSwitcher.sceneTriggerTab.entry"),
|
||||||
|
mainLayout, widgetPlaceholders);
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
switchData = s;
|
||||||
|
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneTrigger *SceneTriggerWidget::getSwitchData()
|
||||||
|
{
|
||||||
|
return switchData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneTriggerWidget::setSwitchData(SceneTrigger *s)
|
||||||
|
{
|
||||||
|
switchData = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneTriggerWidget::swapSwitchData(SceneTriggerWidget *s1,
|
||||||
|
SceneTriggerWidget *s2)
|
||||||
|
{
|
||||||
|
SwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
SceneTrigger *t = s1->getSwitchData();
|
||||||
|
s1->setSwitchData(s2->getSwitchData());
|
||||||
|
s2->setSwitchData(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneTriggerWidget::TriggerTypeChanged(int index)
|
||||||
|
{
|
||||||
|
if (loading || !switchData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->triggerType = static_cast<sceneTriggerType>(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneTriggerWidget::TriggerActionChanged(int index)
|
||||||
|
{
|
||||||
|
if (loading || !switchData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->triggerAction =
|
||||||
|
static_cast<sceneTriggerAction>(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (switchData->triggerAction == sceneTriggerAction::MUTE_SOURCE) {
|
||||||
|
audioSources->show();
|
||||||
|
} else {
|
||||||
|
audioSources->hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneTriggerWidget::DurationChanged(double dur)
|
||||||
|
{
|
||||||
|
if (loading || !switchData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->duration = dur;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneTriggerWidget::AudioSourceChanged(const QString &text)
|
||||||
|
{
|
||||||
|
if (loading || !switchData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->audioSource = GetWeakSourceByQString(text);
|
||||||
|
}
|
||||||
@@ -1,30 +1,31 @@
|
|||||||
|
#include <float.h>
|
||||||
|
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
#include "headers/volume-control.hpp"
|
#include "headers/volume-control.hpp"
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
|
bool AudioSwitch::pause = false;
|
||||||
static QMetaObject::Connection addPulse;
|
static QMetaObject::Connection addPulse;
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_audioAdd_clicked()
|
void AdvSceneSwitcher::on_audioAdd_clicked()
|
||||||
{
|
{
|
||||||
ui->audioAdd->disconnect(addPulse);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switcher->audioSwitches.emplace_back();
|
switcher->audioSwitches.emplace_back();
|
||||||
|
|
||||||
QListWidgetItem *item;
|
|
||||||
item = new QListWidgetItem(ui->audioSwitches);
|
|
||||||
ui->audioSwitches->addItem(item);
|
|
||||||
AudioSwitchWidget *sw =
|
AudioSwitchWidget *sw =
|
||||||
new AudioSwitchWidget(&switcher->audioSwitches.back());
|
new AudioSwitchWidget(this, &switcher->audioSwitches.back());
|
||||||
item->setSizeHint(sw->minimumSizeHint());
|
|
||||||
ui->audioSwitches->setItemWidget(item, sw);
|
listAddClicked(ui->audioSwitches, sw, ui->audioAdd, &addPulse);
|
||||||
|
|
||||||
|
ui->audioHelp->setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_audioRemove_clicked()
|
void AdvSceneSwitcher::on_audioRemove_clicked()
|
||||||
{
|
{
|
||||||
QListWidgetItem *item = ui->audioSwitches->currentItem();
|
QListWidgetItem *item = ui->audioSwitches->currentItem();
|
||||||
if (!item)
|
if (!item) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
@@ -39,8 +40,9 @@ void AdvSceneSwitcher::on_audioRemove_clicked()
|
|||||||
void AdvSceneSwitcher::on_audioUp_clicked()
|
void AdvSceneSwitcher::on_audioUp_clicked()
|
||||||
{
|
{
|
||||||
int index = ui->audioSwitches->currentRow();
|
int index = ui->audioSwitches->currentRow();
|
||||||
if (!listMoveUp(ui->audioSwitches))
|
if (!listMoveUp(ui->audioSwitches)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
AudioSwitchWidget *s1 =
|
AudioSwitchWidget *s1 =
|
||||||
(AudioSwitchWidget *)ui->audioSwitches->itemWidget(
|
(AudioSwitchWidget *)ui->audioSwitches->itemWidget(
|
||||||
@@ -60,8 +62,9 @@ void AdvSceneSwitcher::on_audioDown_clicked()
|
|||||||
{
|
{
|
||||||
int index = ui->audioSwitches->currentRow();
|
int index = ui->audioSwitches->currentRow();
|
||||||
|
|
||||||
if (!listMoveDown(ui->audioSwitches))
|
if (!listMoveDown(ui->audioSwitches)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
AudioSwitchWidget *s1 =
|
AudioSwitchWidget *s1 =
|
||||||
(AudioSwitchWidget *)ui->audioSwitches->itemWidget(
|
(AudioSwitchWidget *)ui->audioSwitches->itemWidget(
|
||||||
@@ -77,34 +80,104 @@ void AdvSceneSwitcher::on_audioDown_clicked()
|
|||||||
switcher->audioSwitches[index + 1]);
|
switcher->audioSwitches[index + 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_audioFallback_toggled(bool on)
|
||||||
|
{
|
||||||
|
if (loading || !switcher) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switcher->audioFallback.enable = on;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitcherData::checkAudioSwitchFallback(OBSWeakSource &scene,
|
||||||
|
OBSWeakSource &transition)
|
||||||
|
{
|
||||||
|
bool durationReached =
|
||||||
|
((unsigned long long)audioFallback.matchCount * interval) /
|
||||||
|
1000.0 >=
|
||||||
|
audioFallback.duration;
|
||||||
|
|
||||||
|
if (durationReached) {
|
||||||
|
|
||||||
|
scene = audioFallback.getScene();
|
||||||
|
transition = audioFallback.transition;
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
audioFallback.logMatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
audioFallback.matchCount++;
|
||||||
|
}
|
||||||
|
|
||||||
void SwitcherData::checkAudioSwitch(bool &match, OBSWeakSource &scene,
|
void SwitcherData::checkAudioSwitch(bool &match, OBSWeakSource &scene,
|
||||||
OBSWeakSource &transition)
|
OBSWeakSource &transition)
|
||||||
{
|
{
|
||||||
if (audioSwitches.size() == 0)
|
if (AudioSwitch::pause) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fallbackChecked = false; // false if only one or no match
|
||||||
|
|
||||||
for (AudioSwitch &s : audioSwitches) {
|
for (AudioSwitch &s : audioSwitches) {
|
||||||
if (!s.initialized())
|
if (!s.initialized()) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
obs_source_t *as = obs_weak_source_get_source(s.audioSource);
|
obs_source_t *as = obs_weak_source_get_source(s.audioSource);
|
||||||
bool audioActive = obs_source_active(as);
|
bool audioActive = obs_source_active(as);
|
||||||
obs_source_release(as);
|
obs_source_release(as);
|
||||||
|
|
||||||
// peak will have a value from -60 db to 0 db
|
// peak will have a value from -60 db to 0 db
|
||||||
bool volumeThresholdreached = ((double)s.peak + 60) * 1.7 >
|
bool volumeThresholdreached = false;
|
||||||
s.volumeThreshold;
|
|
||||||
|
|
||||||
if (volumeThresholdreached && audioActive) {
|
if (s.condition == ABOVE) {
|
||||||
scene = (s.usePreviousScene) ? previousScene : s.scene;
|
volumeThresholdreached = ((double)s.peak + 60) * 1.7 >
|
||||||
|
s.volumeThreshold;
|
||||||
|
} else {
|
||||||
|
volumeThresholdreached = ((double)s.peak + 60) * 1.7 <
|
||||||
|
s.volumeThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset for next check
|
||||||
|
s.peak = -FLT_MAX;
|
||||||
|
|
||||||
|
if (volumeThresholdreached) {
|
||||||
|
s.matchCount++;
|
||||||
|
} else {
|
||||||
|
s.matchCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool durationReached =
|
||||||
|
((unsigned long long)s.matchCount * interval) /
|
||||||
|
1000.0 >=
|
||||||
|
s.duration;
|
||||||
|
|
||||||
|
if (volumeThresholdreached && durationReached && audioActive) {
|
||||||
|
if (match) {
|
||||||
|
checkAudioSwitchFallback(scene, transition);
|
||||||
|
fallbackChecked = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
scene = s.getScene();
|
||||||
transition = s.transition;
|
transition = s.transition;
|
||||||
match = true;
|
match = true;
|
||||||
|
|
||||||
if (verbose)
|
if (verbose) {
|
||||||
s.logMatch();
|
s.logMatch();
|
||||||
break;
|
}
|
||||||
|
|
||||||
|
if (!audioFallback.enable) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!fallbackChecked) {
|
||||||
|
audioFallback.matchCount = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitcherData::saveAudioSwitches(obs_data_t *obj)
|
void SwitcherData::saveAudioSwitches(obs_data_t *obj)
|
||||||
@@ -113,39 +186,15 @@ void SwitcherData::saveAudioSwitches(obs_data_t *obj)
|
|||||||
for (AudioSwitch &s : switcher->audioSwitches) {
|
for (AudioSwitch &s : switcher->audioSwitches) {
|
||||||
obs_data_t *array_obj = obs_data_create();
|
obs_data_t *array_obj = obs_data_create();
|
||||||
|
|
||||||
obs_source_t *sceneSource = obs_weak_source_get_source(s.scene);
|
s.save(array_obj);
|
||||||
obs_source_t *transition =
|
obs_data_array_push_back(audioArray, array_obj);
|
||||||
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_release(array_obj);
|
||||||
}
|
}
|
||||||
obs_data_set_array(obj, "audioSwitches", audioArray);
|
obs_data_set_array(obj, "audioSwitches", audioArray);
|
||||||
obs_data_array_release(audioArray);
|
obs_data_array_release(audioArray);
|
||||||
|
|
||||||
|
audioFallback.save(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitcherData::loadAudioSwitches(obs_data_t *obj)
|
void SwitcherData::loadAudioSwitches(obs_data_t *obj)
|
||||||
@@ -158,22 +207,14 @@ void SwitcherData::loadAudioSwitches(obs_data_t *obj)
|
|||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
obs_data_t *array_obj = obs_data_array_item(audioArray, i);
|
obs_data_t *array_obj = obs_data_array_item(audioArray, i);
|
||||||
|
|
||||||
const char *scene = obs_data_get_string(array_obj, "scene");
|
switcher->audioSwitches.emplace_back();
|
||||||
const char *transition =
|
audioSwitches.back().load(array_obj);
|
||||||
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_release(array_obj);
|
||||||
}
|
}
|
||||||
obs_data_array_release(audioArray);
|
obs_data_array_release(audioArray);
|
||||||
|
|
||||||
|
audioFallback.load(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::setupAudioTab()
|
void AdvSceneSwitcher::setupAudioTab()
|
||||||
@@ -182,13 +223,22 @@ void AdvSceneSwitcher::setupAudioTab()
|
|||||||
QListWidgetItem *item;
|
QListWidgetItem *item;
|
||||||
item = new QListWidgetItem(ui->audioSwitches);
|
item = new QListWidgetItem(ui->audioSwitches);
|
||||||
ui->audioSwitches->addItem(item);
|
ui->audioSwitches->addItem(item);
|
||||||
AudioSwitchWidget *sw = new AudioSwitchWidget(&s);
|
AudioSwitchWidget *sw = new AudioSwitchWidget(this, &s);
|
||||||
item->setSizeHint(sw->minimumSizeHint());
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
ui->audioSwitches->setItemWidget(item, sw);
|
ui->audioSwitches->setItemWidget(item, sw);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switcher->audioSwitches.size() == 0)
|
if (switcher->audioSwitches.size() == 0) {
|
||||||
addPulse = PulseWidget(ui->audioAdd, QColor(Qt::green));
|
addPulse = PulseWidget(ui->audioAdd, QColor(Qt::green));
|
||||||
|
ui->audioHelp->setVisible(true);
|
||||||
|
} else {
|
||||||
|
ui->audioHelp->setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioSwitchFallbackWidget *fb =
|
||||||
|
new AudioSwitchFallbackWidget(this, &switcher->audioFallback);
|
||||||
|
ui->audioFallbackLayout->addWidget(fb);
|
||||||
|
ui->audioFallback->setChecked(switcher->audioFallback.enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioSwitch::setVolumeLevel(void *data,
|
void AudioSwitch::setVolumeLevel(void *data,
|
||||||
@@ -200,10 +250,26 @@ void AudioSwitch::setVolumeLevel(void *data,
|
|||||||
UNUSED_PARAMETER(inputPeak);
|
UNUSED_PARAMETER(inputPeak);
|
||||||
AudioSwitch *s = static_cast<AudioSwitch *>(data);
|
AudioSwitch *s = static_cast<AudioSwitch *>(data);
|
||||||
|
|
||||||
s->peak = peak[0];
|
for (int i = 1; i < MAX_AUDIO_CHANNELS; i++) {
|
||||||
for (int i = 1; i < MAX_AUDIO_CHANNELS; i++)
|
if (peak[i] > s->peak) {
|
||||||
if (peak[i] > s->peak)
|
|
||||||
s->peak = peak[i];
|
s->peak = peak[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_volmeter_t *AddVolmeterToSource(AudioSwitch *entry, obs_weak_source *source)
|
||||||
|
{
|
||||||
|
obs_volmeter_t *volmeter = obs_volmeter_create(OBS_FADER_LOG);
|
||||||
|
obs_volmeter_add_callback(volmeter, AudioSwitch::setVolumeLevel, entry);
|
||||||
|
obs_source_t *as = obs_weak_source_get_source(source);
|
||||||
|
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);
|
||||||
|
|
||||||
|
return volmeter;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioSwitch::resetVolmeter()
|
void AudioSwitch::resetVolmeter()
|
||||||
@@ -211,15 +277,7 @@ void AudioSwitch::resetVolmeter()
|
|||||||
obs_volmeter_remove_callback(volmeter, setVolumeLevel, this);
|
obs_volmeter_remove_callback(volmeter, setVolumeLevel, this);
|
||||||
obs_volmeter_destroy(volmeter);
|
obs_volmeter_destroy(volmeter);
|
||||||
|
|
||||||
volmeter = obs_volmeter_create(OBS_FADER_LOG);
|
volmeter = AddVolmeterToSource(this, audioSource);
|
||||||
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()
|
bool AudioSwitch::initialized()
|
||||||
@@ -233,46 +291,103 @@ bool AudioSwitch::valid()
|
|||||||
(SceneSwitcherEntry::valid() && WeakSourceValid(audioSource));
|
(SceneSwitcherEntry::valid() && WeakSourceValid(audioSource));
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioSwitch::AudioSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
void AudioSwitch::save(obs_data_t *obj)
|
||||||
OBSWeakSource audioSource_, int volumeThreshold_,
|
|
||||||
bool usePreviousScene_)
|
|
||||||
: SceneSwitcherEntry(scene_, transition_, usePreviousScene_),
|
|
||||||
audioSource(audioSource_),
|
|
||||||
volumeThreshold(volumeThreshold_)
|
|
||||||
{
|
{
|
||||||
volmeter = obs_volmeter_create(OBS_FADER_LOG);
|
SceneSwitcherEntry::save(obj);
|
||||||
obs_volmeter_add_callback(volmeter, setVolumeLevel, this);
|
|
||||||
obs_source_t *as = obs_weak_source_get_source(audioSource);
|
obs_data_set_string(obj, "audioSource",
|
||||||
if (!obs_volmeter_attach_source(volmeter, as)) {
|
GetWeakSourceName(audioSource).c_str());
|
||||||
const char *name = obs_source_get_name(as);
|
|
||||||
blog(LOG_WARNING, "failed to attach volmeter to source %s",
|
obs_data_set_int(obj, "volume", volumeThreshold);
|
||||||
name);
|
obs_data_set_int(obj, "condition", condition);
|
||||||
|
obs_data_set_double(obj, "duration", duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
// To be removed in future version
|
||||||
|
bool loadOldAudio(obs_data_t *obj, AudioSwitch *s)
|
||||||
|
{
|
||||||
|
if (!s) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
obs_source_release(as);
|
|
||||||
|
const char *scene = obs_data_get_string(obj, "scene");
|
||||||
|
|
||||||
|
if (strcmp(scene, "") == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->scene = GetWeakSourceByName(scene);
|
||||||
|
|
||||||
|
const char *transition = obs_data_get_string(obj, "transition");
|
||||||
|
s->transition = GetWeakTransitionByName(transition);
|
||||||
|
|
||||||
|
const char *audioSource = obs_data_get_string(obj, "audioSource");
|
||||||
|
s->audioSource = GetWeakSourceByName(audioSource);
|
||||||
|
|
||||||
|
s->volumeThreshold = obs_data_get_int(obj, "volume");
|
||||||
|
s->condition = (audioCondition)obs_data_get_int(obj, "condition");
|
||||||
|
s->duration = obs_data_get_double(obj, "duration");
|
||||||
|
s->usePreviousScene = strcmp(scene, previous_scene_name) == 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioSwitch::load(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
if (loadOldAudio(obj, this)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneSwitcherEntry::load(obj);
|
||||||
|
|
||||||
|
const char *audioSourceName = obs_data_get_string(obj, "audioSource");
|
||||||
|
audioSource = GetWeakSourceByName(audioSourceName);
|
||||||
|
|
||||||
|
volumeThreshold = obs_data_get_int(obj, "volume");
|
||||||
|
condition = (audioCondition)obs_data_get_int(obj, "condition");
|
||||||
|
duration = obs_data_get_double(obj, "duration");
|
||||||
|
|
||||||
|
volmeter = AddVolmeterToSource(this, audioSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioSwitchFallback::save(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
SceneSwitcherEntry::save(obj, "audioFallbackTargetType",
|
||||||
|
"audioFallbackScene",
|
||||||
|
"audioFallbackTransition");
|
||||||
|
|
||||||
|
obs_data_set_bool(obj, "audioFallbackEnable", enable);
|
||||||
|
obs_data_set_double(obj, "audioFallbackDuration", duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioSwitchFallback::load(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
SceneSwitcherEntry::load(obj, "audioFallbackTargetType",
|
||||||
|
"audioFallbackScene",
|
||||||
|
"audioFallbackTransition");
|
||||||
|
|
||||||
|
enable = obs_data_get_bool(obj, "audioFallbackEnable");
|
||||||
|
duration = obs_data_get_double(obj, "audioFallbackDuration");
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioSwitch::AudioSwitch(const AudioSwitch &other)
|
AudioSwitch::AudioSwitch(const AudioSwitch &other)
|
||||||
: SceneSwitcherEntry(other.scene, other.transition,
|
: SceneSwitcherEntry(other.targetType, other.group, other.scene,
|
||||||
other.usePreviousScene),
|
other.transition, other.usePreviousScene),
|
||||||
audioSource(other.audioSource),
|
audioSource(other.audioSource),
|
||||||
volumeThreshold(other.volumeThreshold)
|
volumeThreshold(other.volumeThreshold),
|
||||||
|
condition(other.condition),
|
||||||
|
duration(other.duration)
|
||||||
{
|
{
|
||||||
volmeter = obs_volmeter_create(OBS_FADER_LOG);
|
volmeter = AddVolmeterToSource(this, other.audioSource);
|
||||||
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)
|
AudioSwitch::AudioSwitch(AudioSwitch &&other)
|
||||||
: SceneSwitcherEntry(other.scene, other.transition,
|
: SceneSwitcherEntry(other.targetType, other.group, other.scene,
|
||||||
other.usePreviousScene),
|
other.transition, other.usePreviousScene),
|
||||||
audioSource(other.audioSource),
|
audioSource(other.audioSource),
|
||||||
volumeThreshold(other.volumeThreshold),
|
volumeThreshold(other.volumeThreshold),
|
||||||
|
condition(other.condition),
|
||||||
|
duration(other.duration),
|
||||||
volmeter(other.volmeter)
|
volmeter(other.volmeter)
|
||||||
{
|
{
|
||||||
other.volmeter = nullptr;
|
other.volmeter = nullptr;
|
||||||
@@ -308,68 +423,87 @@ AudioSwitch &AudioSwitch::operator=(AudioSwitch &&other) noexcept
|
|||||||
|
|
||||||
void swap(AudioSwitch &first, AudioSwitch &second)
|
void swap(AudioSwitch &first, AudioSwitch &second)
|
||||||
{
|
{
|
||||||
|
std::swap(first.targetType, second.targetType);
|
||||||
|
std::swap(first.group, second.group);
|
||||||
std::swap(first.scene, second.scene);
|
std::swap(first.scene, second.scene);
|
||||||
std::swap(first.transition, second.transition);
|
std::swap(first.transition, second.transition);
|
||||||
std::swap(first.usePreviousScene, second.usePreviousScene);
|
std::swap(first.usePreviousScene, second.usePreviousScene);
|
||||||
std::swap(first.audioSource, second.audioSource);
|
std::swap(first.audioSource, second.audioSource);
|
||||||
std::swap(first.volumeThreshold, second.volumeThreshold);
|
std::swap(first.volumeThreshold, second.volumeThreshold);
|
||||||
|
std::swap(first.condition, second.condition);
|
||||||
|
std::swap(first.duration, second.duration);
|
||||||
std::swap(first.peak, second.peak);
|
std::swap(first.peak, second.peak);
|
||||||
std::swap(first.volmeter, second.volmeter);
|
std::swap(first.volmeter, second.volmeter);
|
||||||
first.resetVolmeter();
|
first.resetVolmeter();
|
||||||
second.resetVolmeter();
|
second.resetVolmeter();
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioSwitchWidget::AudioSwitchWidget(AudioSwitch *s) : SwitchWidget(s)
|
void populateConditionSelection(QComboBox *list)
|
||||||
|
{
|
||||||
|
list->addItem(
|
||||||
|
obs_module_text("AdvSceneSwitcher.audioTab.condition.above"));
|
||||||
|
list->addItem(
|
||||||
|
obs_module_text("AdvSceneSwitcher.audioTab.condition.below"));
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioSwitchWidget::AudioSwitchWidget(QWidget *parent, AudioSwitch *s)
|
||||||
|
: SwitchWidget(parent, s, true, true)
|
||||||
{
|
{
|
||||||
audioSources = new QComboBox();
|
audioSources = new QComboBox();
|
||||||
|
condition = new QComboBox();
|
||||||
audioVolumeThreshold = new QSpinBox();
|
audioVolumeThreshold = new QSpinBox();
|
||||||
|
duration = new QDoubleSpinBox();
|
||||||
|
|
||||||
obs_source_t *soruce = nullptr;
|
obs_source_t *source = nullptr;
|
||||||
if (s)
|
if (s) {
|
||||||
soruce = obs_weak_source_get_source(s->audioSource);
|
source = obs_weak_source_get_source(s->audioSource);
|
||||||
volMeter = new VolControl(soruce);
|
}
|
||||||
obs_source_release(soruce);
|
volMeter = new VolControl(source);
|
||||||
|
obs_source_release(source);
|
||||||
whenLabel = new QLabel("When the volume of");
|
|
||||||
aboveLabel = new QLabel("is above");
|
|
||||||
switchLabel = new QLabel("switch to");
|
|
||||||
usingLabel = new QLabel("using");
|
|
||||||
|
|
||||||
audioVolumeThreshold->setSuffix("%");
|
audioVolumeThreshold->setSuffix("%");
|
||||||
audioVolumeThreshold->setMaximum(100);
|
audioVolumeThreshold->setMaximum(100);
|
||||||
audioVolumeThreshold->setMinimum(0);
|
audioVolumeThreshold->setMinimum(0);
|
||||||
|
|
||||||
|
duration->setMinimum(0.0);
|
||||||
|
duration->setMaximum(99.000000);
|
||||||
|
duration->setSuffix("s");
|
||||||
|
|
||||||
QWidget::connect(volMeter->GetSlider(), SIGNAL(valueChanged(int)),
|
QWidget::connect(volMeter->GetSlider(), SIGNAL(valueChanged(int)),
|
||||||
audioVolumeThreshold, SLOT(setValue(int)));
|
audioVolumeThreshold, SLOT(setValue(int)));
|
||||||
QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)),
|
QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)),
|
||||||
volMeter->GetSlider(), SLOT(setValue(int)));
|
volMeter->GetSlider(), SLOT(setValue(int)));
|
||||||
QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)), this,
|
QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)), this,
|
||||||
SLOT(VolumeThresholdChanged(int)));
|
SLOT(VolumeThresholdChanged(int)));
|
||||||
|
QWidget::connect(condition, SIGNAL(currentIndexChanged(int)), this,
|
||||||
|
SLOT(ConditionChanged(int)));
|
||||||
|
QWidget::connect(duration, SIGNAL(valueChanged(double)), this,
|
||||||
|
SLOT(DurationChanged(double)));
|
||||||
QWidget::connect(audioSources,
|
QWidget::connect(audioSources,
|
||||||
SIGNAL(currentTextChanged(const QString &)), this,
|
SIGNAL(currentTextChanged(const QString &)), this,
|
||||||
SLOT(SourceChanged(const QString &)));
|
SLOT(SourceChanged(const QString &)));
|
||||||
|
|
||||||
AdvSceneSwitcher::populateAudioSelection(audioSources);
|
AdvSceneSwitcher::populateAudioSelection(audioSources);
|
||||||
|
populateConditionSelection(condition);
|
||||||
|
|
||||||
if (s) {
|
if (s) {
|
||||||
audioSources->setCurrentText(
|
audioSources->setCurrentText(
|
||||||
GetWeakSourceName(s->audioSource).c_str());
|
GetWeakSourceName(s->audioSource).c_str());
|
||||||
audioVolumeThreshold->setValue(s->volumeThreshold);
|
audioVolumeThreshold->setValue(s->volumeThreshold);
|
||||||
|
condition->setCurrentIndex(s->condition);
|
||||||
|
duration->setValue(s->duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
setStyleSheet("* { background-color: transparent; }");
|
|
||||||
|
|
||||||
QHBoxLayout *switchLayout = new QHBoxLayout;
|
QHBoxLayout *switchLayout = new QHBoxLayout;
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
switchLayout->addWidget(whenLabel);
|
{"{{audioSources}}", audioSources},
|
||||||
switchLayout->addWidget(audioSources);
|
{"{{volumeWidget}}", audioVolumeThreshold},
|
||||||
switchLayout->addWidget(aboveLabel);
|
{"{{condition}}", condition},
|
||||||
switchLayout->addWidget(audioVolumeThreshold);
|
{"{{duration}}", duration},
|
||||||
switchLayout->addWidget(switchLabel);
|
{"{{scenes}}", scenes},
|
||||||
switchLayout->addWidget(scenes);
|
{"{{transitions}}", transitions}};
|
||||||
switchLayout->addWidget(usingLabel);
|
placeWidgets(obs_module_text("AdvSceneSwitcher.audioTab.entry"),
|
||||||
switchLayout->addWidget(transitions);
|
switchLayout, widgetPlaceholders);
|
||||||
switchLayout->addStretch();
|
|
||||||
|
|
||||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||||
|
|
||||||
@@ -425,8 +559,10 @@ void AudioSwitchWidget::UpdateVolmeterSource()
|
|||||||
|
|
||||||
void AudioSwitchWidget::SourceChanged(const QString &text)
|
void AudioSwitchWidget::SourceChanged(const QString &text)
|
||||||
{
|
{
|
||||||
if (loading || !switchData)
|
if (loading || !switchData) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switchData->audioSource = GetWeakSourceByQString(text);
|
switchData->audioSource = GetWeakSourceByQString(text);
|
||||||
switchData->resetVolmeter();
|
switchData->resetVolmeter();
|
||||||
@@ -435,8 +571,72 @@ void AudioSwitchWidget::SourceChanged(const QString &text)
|
|||||||
|
|
||||||
void AudioSwitchWidget::VolumeThresholdChanged(int vol)
|
void AudioSwitchWidget::VolumeThresholdChanged(int vol)
|
||||||
{
|
{
|
||||||
if (loading || !switchData)
|
if (loading || !switchData) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switchData->volumeThreshold = vol;
|
switchData->volumeThreshold = vol;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioSwitchWidget::ConditionChanged(int cond)
|
||||||
|
{
|
||||||
|
if (loading || !switchData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->condition = (audioCondition)cond;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioSwitchWidget::DurationChanged(double dur)
|
||||||
|
{
|
||||||
|
if (loading || !switchData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->duration = dur;
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioSwitchFallbackWidget::AudioSwitchFallbackWidget(QWidget *parent,
|
||||||
|
AudioSwitchFallback *s)
|
||||||
|
: SwitchWidget(parent, s, true, true)
|
||||||
|
{
|
||||||
|
duration = new QDoubleSpinBox();
|
||||||
|
|
||||||
|
duration->setMinimum(0.0);
|
||||||
|
duration->setMaximum(99.000000);
|
||||||
|
duration->setSuffix("s");
|
||||||
|
|
||||||
|
QWidget::connect(duration, SIGNAL(valueChanged(double)), this,
|
||||||
|
SLOT(DurationChanged(double)));
|
||||||
|
|
||||||
|
if (s) {
|
||||||
|
duration->setValue(s->duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
|
{"{{scenes}}", scenes},
|
||||||
|
{"{{duration}}", duration},
|
||||||
|
{"{{transitions}}", transitions}};
|
||||||
|
placeWidgets(
|
||||||
|
obs_module_text("AdvSceneSwitcher.audioTab.multiMatchfallback"),
|
||||||
|
mainLayout, widgetPlaceholders);
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
switchData = s;
|
||||||
|
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioSwitchFallbackWidget::DurationChanged(double dur)
|
||||||
|
{
|
||||||
|
if (loading || !switchData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->duration = dur;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,29 +1,28 @@
|
|||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
|
bool ExecutableSwitch::pause = false;
|
||||||
static QMetaObject::Connection addPulse;
|
static QMetaObject::Connection addPulse;
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_executableAdd_clicked()
|
void AdvSceneSwitcher::on_executableAdd_clicked()
|
||||||
{
|
{
|
||||||
ui->executableAdd->disconnect(addPulse);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switcher->executableSwitches.emplace_back();
|
switcher->executableSwitches.emplace_back();
|
||||||
|
|
||||||
QListWidgetItem *item;
|
listAddClicked(ui->executables,
|
||||||
item = new QListWidgetItem(ui->executables);
|
new ExecutableSwitchWidget(
|
||||||
ui->executables->addItem(item);
|
this, &switcher->executableSwitches.back()),
|
||||||
ExecutableSwitchWidget *sw = new ExecutableSwitchWidget(
|
ui->executableAdd, &addPulse);
|
||||||
&switcher->executableSwitches.back());
|
|
||||||
item->setSizeHint(sw->minimumSizeHint());
|
ui->exeHelp->setVisible(false);
|
||||||
ui->executables->setItemWidget(item, sw);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_executableRemove_clicked()
|
void AdvSceneSwitcher::on_executableRemove_clicked()
|
||||||
{
|
{
|
||||||
QListWidgetItem *item = ui->executables->currentItem();
|
QListWidgetItem *item = ui->executables->currentItem();
|
||||||
if (!item)
|
if (!item) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
@@ -38,8 +37,9 @@ void AdvSceneSwitcher::on_executableRemove_clicked()
|
|||||||
void AdvSceneSwitcher::on_executableUp_clicked()
|
void AdvSceneSwitcher::on_executableUp_clicked()
|
||||||
{
|
{
|
||||||
int index = ui->executables->currentRow();
|
int index = ui->executables->currentRow();
|
||||||
if (!listMoveUp(ui->executables))
|
if (!listMoveUp(ui->executables)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ExecutableSwitchWidget *s1 =
|
ExecutableSwitchWidget *s1 =
|
||||||
(ExecutableSwitchWidget *)ui->executables->itemWidget(
|
(ExecutableSwitchWidget *)ui->executables->itemWidget(
|
||||||
@@ -59,8 +59,9 @@ void AdvSceneSwitcher::on_executableDown_clicked()
|
|||||||
{
|
{
|
||||||
int index = ui->executables->currentRow();
|
int index = ui->executables->currentRow();
|
||||||
|
|
||||||
if (!listMoveDown(ui->executables))
|
if (!listMoveDown(ui->executables)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ExecutableSwitchWidget *s1 =
|
ExecutableSwitchWidget *s1 =
|
||||||
(ExecutableSwitchWidget *)ui->executables->itemWidget(
|
(ExecutableSwitchWidget *)ui->executables->itemWidget(
|
||||||
@@ -79,6 +80,10 @@ void AdvSceneSwitcher::on_executableDown_clicked()
|
|||||||
void SwitcherData::checkExeSwitch(bool &match, OBSWeakSource &scene,
|
void SwitcherData::checkExeSwitch(bool &match, OBSWeakSource &scene,
|
||||||
OBSWeakSource &transition)
|
OBSWeakSource &transition)
|
||||||
{
|
{
|
||||||
|
if (executableSwitches.size() == 0 || ExecutableSwitch::pause) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::string title;
|
std::string title;
|
||||||
QStringList runningProcesses;
|
QStringList runningProcesses;
|
||||||
bool ignored = false;
|
bool ignored = false;
|
||||||
@@ -104,15 +109,15 @@ void SwitcherData::checkExeSwitch(bool &match, OBSWeakSource &scene,
|
|||||||
// Check for match
|
// Check for match
|
||||||
GetProcessList(runningProcesses);
|
GetProcessList(runningProcesses);
|
||||||
for (ExecutableSwitch &s : executableSwitches) {
|
for (ExecutableSwitch &s : executableSwitches) {
|
||||||
if (!s.initialized())
|
if (!s.initialized()) {
|
||||||
continue;
|
continue;
|
||||||
// True if executable switch is running (direct)
|
}
|
||||||
|
|
||||||
bool equals = runningProcesses.contains(s.exe);
|
bool equals = runningProcesses.contains(s.exe);
|
||||||
// True if executable switch is running (regex)
|
|
||||||
bool matches = (runningProcesses.indexOf(
|
bool matches = (runningProcesses.indexOf(
|
||||||
QRegularExpression(s.exe)) != -1);
|
QRegularExpression(s.exe)) != -1);
|
||||||
// True if focus is disabled OR switch is focused
|
|
||||||
bool focus = (!s.inFocus || isInFocus(s.exe));
|
bool focus = (!s.inFocus || isInFocus(s.exe));
|
||||||
|
|
||||||
// True if current window is ignored AND switch equals OR matches last window
|
// True if current window is ignored AND switch equals OR matches last window
|
||||||
bool ignore =
|
bool ignore =
|
||||||
(ignored && (title == s.exe.toStdString() ||
|
(ignored && (title == s.exe.toStdString() ||
|
||||||
@@ -121,11 +126,12 @@ void SwitcherData::checkExeSwitch(bool &match, OBSWeakSource &scene,
|
|||||||
|
|
||||||
if ((equals || matches) && (focus || ignore)) {
|
if ((equals || matches) && (focus || ignore)) {
|
||||||
match = true;
|
match = true;
|
||||||
scene = s.scene;
|
scene = s.getScene();
|
||||||
transition = s.transition;
|
transition = s.transition;
|
||||||
|
|
||||||
if (verbose)
|
if (verbose) {
|
||||||
s.logMatch();
|
s.logMatch();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -137,24 +143,9 @@ void SwitcherData::saveExecutableSwitches(obs_data_t *obj)
|
|||||||
for (ExecutableSwitch &s : switcher->executableSwitches) {
|
for (ExecutableSwitch &s : switcher->executableSwitches) {
|
||||||
obs_data_t *array_obj = obs_data_create();
|
obs_data_t *array_obj = obs_data_create();
|
||||||
|
|
||||||
obs_source_t *source = obs_weak_source_get_source(s.scene);
|
s.save(array_obj);
|
||||||
obs_source_t *transition =
|
obs_data_array_push_back(executableArray, array_obj);
|
||||||
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_release(array_obj);
|
||||||
}
|
}
|
||||||
obs_data_set_array(obj, "executableSwitches", executableArray);
|
obs_data_set_array(obj, "executableSwitches", executableArray);
|
||||||
@@ -172,15 +163,8 @@ void SwitcherData::loadExecutableSwitches(obs_data_t *obj)
|
|||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
obs_data_t *array_obj = obs_data_array_item(executableArray, i);
|
obs_data_t *array_obj = obs_data_array_item(executableArray, i);
|
||||||
|
|
||||||
const char *scene = obs_data_get_string(array_obj, "scene");
|
switcher->executableSwitches.emplace_back();
|
||||||
const char *transition =
|
executableSwitches.back().load(array_obj);
|
||||||
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_release(array_obj);
|
||||||
}
|
}
|
||||||
@@ -193,24 +177,72 @@ void AdvSceneSwitcher::setupExecutableTab()
|
|||||||
QListWidgetItem *item;
|
QListWidgetItem *item;
|
||||||
item = new QListWidgetItem(ui->executables);
|
item = new QListWidgetItem(ui->executables);
|
||||||
ui->executables->addItem(item);
|
ui->executables->addItem(item);
|
||||||
ExecutableSwitchWidget *sw = new ExecutableSwitchWidget(&s);
|
ExecutableSwitchWidget *sw =
|
||||||
|
new ExecutableSwitchWidget(this, &s);
|
||||||
item->setSizeHint(sw->minimumSizeHint());
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
ui->executables->setItemWidget(item, sw);
|
ui->executables->setItemWidget(item, sw);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switcher->executableSwitches.size() == 0)
|
if (switcher->executableSwitches.size() == 0) {
|
||||||
addPulse = PulseWidget(ui->executableAdd, QColor(Qt::green));
|
addPulse = PulseWidget(ui->executableAdd, QColor(Qt::green));
|
||||||
|
ui->exeHelp->setVisible(true);
|
||||||
|
} else {
|
||||||
|
ui->exeHelp->setVisible(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ExecutableSwitchWidget::ExecutableSwitchWidget(ExecutableSwitch *s)
|
void ExecutableSwitch::save(obs_data_t *obj)
|
||||||
: SwitchWidget(s, false)
|
{
|
||||||
|
SceneSwitcherEntry::save(obj);
|
||||||
|
|
||||||
|
obs_data_set_string(obj, "exefile", exe.toUtf8());
|
||||||
|
obs_data_set_bool(obj, "infocus", inFocus);
|
||||||
|
}
|
||||||
|
|
||||||
|
// To be removed in future version
|
||||||
|
bool loadOldExe(obs_data_t *obj, ExecutableSwitch *s)
|
||||||
|
{
|
||||||
|
if (!s) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *scene = obs_data_get_string(obj, "scene");
|
||||||
|
|
||||||
|
if (strcmp(scene, "") == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->scene = GetWeakSourceByName(scene);
|
||||||
|
|
||||||
|
const char *transition = obs_data_get_string(obj, "transition");
|
||||||
|
s->transition = GetWeakTransitionByName(transition);
|
||||||
|
|
||||||
|
s->exe = obs_data_get_string(obj, "exefile");
|
||||||
|
s->inFocus = obs_data_get_bool(obj, "infocus");
|
||||||
|
s->usePreviousScene = strcmp(scene, previous_scene_name) == 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExecutableSwitch::load(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
if (loadOldExe(obj, this)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneSwitcherEntry::load(obj);
|
||||||
|
|
||||||
|
exe = obs_data_get_string(obj, "exefile");
|
||||||
|
inFocus = obs_data_get_bool(obj, "infocus");
|
||||||
|
}
|
||||||
|
|
||||||
|
ExecutableSwitchWidget::ExecutableSwitchWidget(QWidget *parent,
|
||||||
|
ExecutableSwitch *s)
|
||||||
|
: SwitchWidget(parent, s, true, true)
|
||||||
{
|
{
|
||||||
processes = new QComboBox();
|
processes = new QComboBox();
|
||||||
requiresFocus = new QCheckBox("only if focused");
|
requiresFocus = new QCheckBox(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.executableTab.requiresFocus"));
|
||||||
whenLabel = new QLabel("When");
|
|
||||||
switchLabel = new QLabel("is running switch to");
|
|
||||||
usingLabel = new QLabel("using");
|
|
||||||
|
|
||||||
QWidget::connect(processes, SIGNAL(currentTextChanged(const QString &)),
|
QWidget::connect(processes, SIGNAL(currentTextChanged(const QString &)),
|
||||||
this, SLOT(ProcessChanged(const QString &)));
|
this, SLOT(ProcessChanged(const QString &)));
|
||||||
@@ -227,19 +259,14 @@ ExecutableSwitchWidget::ExecutableSwitchWidget(ExecutableSwitch *s)
|
|||||||
requiresFocus->setChecked(s->inFocus);
|
requiresFocus->setChecked(s->inFocus);
|
||||||
}
|
}
|
||||||
|
|
||||||
setStyleSheet("* { background-color: transparent; }");
|
|
||||||
|
|
||||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
mainLayout->addWidget(whenLabel);
|
{"{{processes}}", processes},
|
||||||
mainLayout->addWidget(processes);
|
{"{{requiresFocus}}", requiresFocus},
|
||||||
mainLayout->addWidget(switchLabel);
|
{"{{scenes}}", scenes},
|
||||||
mainLayout->addWidget(scenes);
|
{"{{transitions}}", transitions}};
|
||||||
mainLayout->addWidget(usingLabel);
|
placeWidgets(obs_module_text("AdvSceneSwitcher.executableTab.entry"),
|
||||||
mainLayout->addWidget(transitions);
|
mainLayout, widgetPlaceholders);
|
||||||
mainLayout->addWidget(requiresFocus);
|
|
||||||
mainLayout->addStretch();
|
|
||||||
|
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
|
||||||
switchData = s;
|
switchData = s;
|
||||||
@@ -269,16 +296,20 @@ void ExecutableSwitchWidget::swapSwitchData(ExecutableSwitchWidget *s1,
|
|||||||
|
|
||||||
void ExecutableSwitchWidget::ProcessChanged(const QString &text)
|
void ExecutableSwitchWidget::ProcessChanged(const QString &text)
|
||||||
{
|
{
|
||||||
if (loading || !switchData)
|
if (loading || !switchData) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switchData->exe = text;
|
switchData->exe = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExecutableSwitchWidget::FocusChanged(int state)
|
void ExecutableSwitchWidget::FocusChanged(int state)
|
||||||
{
|
{
|
||||||
if (loading || !switchData)
|
if (loading || !switchData) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switchData->inFocus = state;
|
switchData->inFocus = state;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,34 @@
|
|||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
#include <functional>
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
|
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
#include "headers/curl-helper.hpp"
|
#include "headers/curl-helper.hpp"
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
#define LOCAL_FILE_IDX 0
|
bool FileSwitch::pause = false;
|
||||||
#define REMOTE_FILE_IDX 1
|
static QMetaObject::Connection addPulse;
|
||||||
|
static std::hash<std::string> strHash;
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_browseButton_clicked()
|
void AdvSceneSwitcher::on_browseButton_clicked()
|
||||||
{
|
{
|
||||||
QString path = QFileDialog::getOpenFileName(
|
QString path = QFileDialog::getOpenFileName(
|
||||||
this, tr("Select a file to write to ..."), QDir::currentPath(),
|
this,
|
||||||
tr("Text files (*.txt)"));
|
tr(obs_module_text("AdvSceneSwitcher.fileTab.selectWrite")),
|
||||||
if (!path.isEmpty())
|
QDir::currentPath(),
|
||||||
|
tr(obs_module_text("AdvSceneSwitcher.fileTab.textFileType")));
|
||||||
|
if (!path.isEmpty()) {
|
||||||
ui->writePathLineEdit->setText(path);
|
ui->writePathLineEdit->setText(path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_readFileCheckBox_stateChanged(int state)
|
void AdvSceneSwitcher::on_readFileCheckBox_stateChanged(int state)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
if (!state) {
|
if (!state) {
|
||||||
@@ -38,8 +44,9 @@ void AdvSceneSwitcher::on_readFileCheckBox_stateChanged(int state)
|
|||||||
|
|
||||||
void AdvSceneSwitcher::on_readPathLineEdit_textChanged(const QString &text)
|
void AdvSceneSwitcher::on_readPathLineEdit_textChanged(const QString &text)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
if (text.isEmpty()) {
|
if (text.isEmpty()) {
|
||||||
@@ -52,8 +59,9 @@ void AdvSceneSwitcher::on_readPathLineEdit_textChanged(const QString &text)
|
|||||||
|
|
||||||
void AdvSceneSwitcher::on_writePathLineEdit_textChanged(const QString &text)
|
void AdvSceneSwitcher::on_writePathLineEdit_textChanged(const QString &text)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
if (text.isEmpty()) {
|
if (text.isEmpty()) {
|
||||||
@@ -67,16 +75,20 @@ void AdvSceneSwitcher::on_writePathLineEdit_textChanged(const QString &text)
|
|||||||
void AdvSceneSwitcher::on_browseButton_2_clicked()
|
void AdvSceneSwitcher::on_browseButton_2_clicked()
|
||||||
{
|
{
|
||||||
QString path = QFileDialog::getOpenFileName(
|
QString path = QFileDialog::getOpenFileName(
|
||||||
this, tr("Select a file to read from ..."), QDir::currentPath(),
|
this,
|
||||||
tr("Any files (*.*)"));
|
tr(obs_module_text("AdvSceneSwitcher.fileTab.selectRead")),
|
||||||
if (!path.isEmpty())
|
QDir::currentPath(),
|
||||||
|
tr(obs_module_text("AdvSceneSwitcher.fileTab.anyFileType")));
|
||||||
|
if (!path.isEmpty()) {
|
||||||
ui->readPathLineEdit->setText(path);
|
ui->readPathLineEdit->setText(path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitcherData::writeSceneInfoToFile()
|
void SwitcherData::writeSceneInfoToFile()
|
||||||
{
|
{
|
||||||
if (!fileIO.writeEnabled || fileIO.writePath.empty())
|
if (!fileIO.writeEnabled || fileIO.writePath.empty()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
obs_source_t *currentSource = obs_frontend_get_current_scene();
|
obs_source_t *currentSource = obs_frontend_get_current_scene();
|
||||||
|
|
||||||
@@ -89,11 +101,26 @@ void SwitcherData::writeSceneInfoToFile()
|
|||||||
obs_source_release(currentSource);
|
obs_source_release(currentSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SwitcherData::writeToStatusFile(QString msg)
|
||||||
|
{
|
||||||
|
if (!fileIO.writeEnabled || fileIO.writePath.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile file(QString::fromStdString(fileIO.writePath));
|
||||||
|
if (file.open(QIODevice::ReadWrite)) {
|
||||||
|
QTextStream stream(&file);
|
||||||
|
stream << msg << endl;
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
void SwitcherData::checkSwitchInfoFromFile(bool &match, OBSWeakSource &scene,
|
void SwitcherData::checkSwitchInfoFromFile(bool &match, OBSWeakSource &scene,
|
||||||
OBSWeakSource &transition)
|
OBSWeakSource &transition)
|
||||||
{
|
{
|
||||||
if (!fileIO.readEnabled || fileIO.readPath.empty())
|
if (!fileIO.readEnabled || fileIO.readPath.empty()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QFile file(QString::fromStdString(fileIO.readPath));
|
QFile file(QString::fromStdString(fileIO.readPath));
|
||||||
if (file.open(QIODevice::ReadOnly)) {
|
if (file.open(QIODevice::ReadOnly)) {
|
||||||
@@ -148,63 +175,82 @@ bool compareIgnoringLineEnding(QString &s1, QString &s2)
|
|||||||
QTextStream s1stream(&s1);
|
QTextStream s1stream(&s1);
|
||||||
QTextStream s2stream(&s2);
|
QTextStream s2stream(&s2);
|
||||||
|
|
||||||
while (!s1stream.atEnd() && !s2stream.atEnd()) {
|
while (!s1stream.atEnd() || !s2stream.atEnd()) {
|
||||||
QString s1s = s1stream.readLine();
|
QString s1s = s1stream.readLine();
|
||||||
QString s2s = s2stream.readLine();
|
QString s2s = s2stream.readLine();
|
||||||
if (QString::compare(s1s, s2s, Qt::CaseSensitive) != 0) {
|
if (s1s != s2s) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!s1stream.atEnd() && !s2stream.atEnd()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool matchFileContent(QString &filedata, FileSwitch &s)
|
||||||
|
{
|
||||||
|
if (s.onlyMatchIfChanged) {
|
||||||
|
size_t newHash = strHash(filedata.toUtf8().constData());
|
||||||
|
if (newHash == s.lastHash) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
s.lastHash = newHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s.useRegex) {
|
||||||
|
QRegExp rx(QString::fromStdString(s.text));
|
||||||
|
return rx.exactMatch(filedata);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString text = QString::fromStdString(s.text);
|
||||||
|
return compareIgnoringLineEnding(text, filedata);
|
||||||
|
}
|
||||||
|
|
||||||
bool checkRemoteFileContent(FileSwitch &s)
|
bool checkRemoteFileContent(FileSwitch &s)
|
||||||
{
|
{
|
||||||
std::string data = getRemoteData(s.file);
|
std::string data = getRemoteData(s.file);
|
||||||
bool ret = false;
|
QString qdata = QString::fromStdString(data);
|
||||||
if (s.useRegex) {
|
return matchFileContent(qdata, s);
|
||||||
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 checkLocalFileContent(FileSwitch &s)
|
||||||
{
|
{
|
||||||
bool equal = false;
|
|
||||||
QString t = QString::fromStdString(s.text);
|
QString t = QString::fromStdString(s.text);
|
||||||
QFile file(QString::fromStdString(s.file));
|
QFile file(QString::fromStdString(s.file));
|
||||||
if (!file.open(QIODevice::ReadOnly))
|
if (s.file.empty() || !file.open(QIODevice::ReadOnly)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (s.useTime) {
|
if (s.useTime) {
|
||||||
QDateTime newLastMod = QFileInfo(file).lastModified();
|
QDateTime newLastMod = QFileInfo(file).lastModified();
|
||||||
if (s.lastMod == newLastMod)
|
if (s.lastMod == newLastMod) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
s.lastMod = newLastMod;
|
s.lastMod = newLastMod;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s.useRegex) {
|
QString filedata = QTextStream(&file).readAll();
|
||||||
QTextStream in(&file);
|
bool match = matchFileContent(filedata, s);
|
||||||
QRegExp rx(t);
|
|
||||||
equal = rx.exactMatch(in.readAll());
|
|
||||||
} else {
|
|
||||||
QTextStream in(&file);
|
|
||||||
QString filedata = in.readAll();
|
|
||||||
equal = compareIgnoringLineEnding(filedata, t);
|
|
||||||
}
|
|
||||||
file.close();
|
file.close();
|
||||||
return equal;
|
return match;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitcherData::checkFileContent(bool &match, OBSWeakSource &scene,
|
void SwitcherData::checkFileContent(bool &match, OBSWeakSource &scene,
|
||||||
OBSWeakSource &transition)
|
OBSWeakSource &transition)
|
||||||
{
|
{
|
||||||
|
if (FileSwitch::pause) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (FileSwitch &s : fileSwitches) {
|
for (FileSwitch &s : fileSwitches) {
|
||||||
|
if (!s.initialized()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
bool equal = false;
|
bool equal = false;
|
||||||
if (s.remote) {
|
if (s.remote) {
|
||||||
equal = checkRemoteFileContent(s);
|
equal = checkRemoteFileContent(s);
|
||||||
@@ -213,149 +259,107 @@ void SwitcherData::checkFileContent(bool &match, OBSWeakSource &scene,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (equal) {
|
if (equal) {
|
||||||
scene = s.scene;
|
scene = s.getScene();
|
||||||
transition = s.transition;
|
transition = s.transition;
|
||||||
match = true;
|
match = true;
|
||||||
|
|
||||||
if (verbose)
|
if (verbose) {
|
||||||
s.logMatch();
|
s.logMatch();
|
||||||
|
}
|
||||||
break;
|
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()
|
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);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switcher->fileSwitches.emplace_back(source, transition,
|
switcher->fileSwitches.emplace_back();
|
||||||
fileName.toUtf8().constData(),
|
|
||||||
text.toUtf8().constData(), remote,
|
listAddClicked(ui->fileSwitches,
|
||||||
useRegex, useTime);
|
new FileSwitchWidget(this,
|
||||||
|
&switcher->fileSwitches.back()),
|
||||||
|
ui->fileAdd, &addPulse);
|
||||||
|
|
||||||
|
ui->fileHelp->setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_fileRemove_clicked()
|
void AdvSceneSwitcher::on_fileRemove_clicked()
|
||||||
{
|
{
|
||||||
QListWidgetItem *item = ui->fileScenesList->currentItem();
|
QListWidgetItem *item = ui->fileSwitches->currentItem();
|
||||||
if (!item)
|
if (!item) {
|
||||||
return;
|
|
||||||
|
|
||||||
int idx = ui->fileScenesList->currentRow();
|
|
||||||
if (idx == -1)
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
int idx = ui->fileSwitches->currentRow();
|
||||||
auto &switches = switcher->fileSwitches;
|
auto &switches = switcher->fileSwitches;
|
||||||
switches.erase(switches.begin() + idx);
|
switches.erase(switches.begin() + idx);
|
||||||
}
|
}
|
||||||
qDeleteAll(ui->fileScenesList->selectedItems());
|
|
||||||
|
delete item;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_fileScenesList_currentRowChanged(int idx)
|
void AdvSceneSwitcher::on_fileSwitches_currentRowChanged(int idx)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading) {
|
||||||
return;
|
return;
|
||||||
if (idx == -1)
|
}
|
||||||
|
if (idx == -1) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
|
||||||
if ((int)switcher->fileSwitches.size() <= idx)
|
if ((int)switcher->fileSwitches.size() <= idx) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
FileSwitch s = switcher->fileSwitches[idx];
|
FileSwitch s = switcher->fileSwitches[idx];
|
||||||
|
if (s.remote) {
|
||||||
std::string sceneName = GetWeakSourceName(s.scene);
|
ui->remoteFileWarningLabel->show();
|
||||||
std::string transitionName = GetWeakSourceName(s.transition);
|
} else {
|
||||||
|
ui->remoteFileWarningLabel->hide();
|
||||||
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()
|
void AdvSceneSwitcher::on_fileUp_clicked()
|
||||||
{
|
{
|
||||||
int index = ui->fileScenesList->currentRow();
|
int index = ui->fileSwitches->currentRow();
|
||||||
if (index != -1 && index != 0) {
|
if (!listMoveUp(ui->fileSwitches)) {
|
||||||
ui->fileScenesList->insertItem(
|
return;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileSwitchWidget *s1 = (FileSwitchWidget *)ui->fileSwitches->itemWidget(
|
||||||
|
ui->fileSwitches->item(index));
|
||||||
|
FileSwitchWidget *s2 = (FileSwitchWidget *)ui->fileSwitches->itemWidget(
|
||||||
|
ui->fileSwitches->item(index - 1));
|
||||||
|
FileSwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
|
||||||
|
std::swap(switcher->fileSwitches[index],
|
||||||
|
switcher->fileSwitches[index - 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_fileDown_clicked()
|
void AdvSceneSwitcher::on_fileDown_clicked()
|
||||||
{
|
{
|
||||||
int index = ui->fileScenesList->currentRow();
|
int index = ui->fileSwitches->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);
|
if (!listMoveDown(ui->fileSwitches)) {
|
||||||
|
return;
|
||||||
iter_swap(switcher->fileSwitches.begin() + index,
|
|
||||||
switcher->fileSwitches.begin() + index + 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileSwitchWidget *s1 = (FileSwitchWidget *)ui->fileSwitches->itemWidget(
|
||||||
|
ui->fileSwitches->item(index));
|
||||||
|
FileSwitchWidget *s2 = (FileSwitchWidget *)ui->fileSwitches->itemWidget(
|
||||||
|
ui->fileSwitches->item(index + 1));
|
||||||
|
FileSwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
|
||||||
|
std::swap(switcher->fileSwitches[index],
|
||||||
|
switcher->fileSwitches[index + 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitcherData::saveFileSwitches(obs_data_t *obj)
|
void SwitcherData::saveFileSwitches(obs_data_t *obj)
|
||||||
@@ -364,26 +368,9 @@ void SwitcherData::saveFileSwitches(obs_data_t *obj)
|
|||||||
for (FileSwitch &s : switcher->fileSwitches) {
|
for (FileSwitch &s : switcher->fileSwitches) {
|
||||||
obs_data_t *array_obj = obs_data_create();
|
obs_data_t *array_obj = obs_data_create();
|
||||||
|
|
||||||
obs_source_t *source = obs_weak_source_get_source(s.scene);
|
s.save(array_obj);
|
||||||
obs_source_t *transition =
|
obs_data_array_push_back(fileArray, array_obj);
|
||||||
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_release(array_obj);
|
||||||
}
|
}
|
||||||
obs_data_set_array(obj, "fileSwitches", fileArray);
|
obs_data_set_array(obj, "fileSwitches", fileArray);
|
||||||
@@ -405,19 +392,8 @@ void SwitcherData::loadFileSwitches(obs_data_t *obj)
|
|||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
obs_data_t *array_obj = obs_data_array_item(fileArray, i);
|
obs_data_t *array_obj = obs_data_array_item(fileArray, i);
|
||||||
|
|
||||||
const char *scene = obs_data_get_string(array_obj, "scene");
|
switcher->fileSwitches.emplace_back();
|
||||||
const char *transition =
|
fileSwitches.back().load(array_obj);
|
||||||
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_release(array_obj);
|
||||||
}
|
}
|
||||||
@@ -433,28 +409,30 @@ void SwitcherData::loadFileSwitches(obs_data_t *obj)
|
|||||||
|
|
||||||
void AdvSceneSwitcher::setupFileTab()
|
void AdvSceneSwitcher::setupFileTab()
|
||||||
{
|
{
|
||||||
populateSceneSelection(ui->fileScenes, false);
|
|
||||||
populateTransitionSelection(ui->fileTransitions);
|
|
||||||
|
|
||||||
ui->fileType->addItem("local");
|
|
||||||
ui->fileType->addItem("remote");
|
|
||||||
ui->remoteFileWarningLabel->setText(
|
ui->remoteFileWarningLabel->setText(
|
||||||
"Note that the scene switcher will try to access the remote location every " +
|
obs_module_text("AdvSceneSwitcher.fileTab.remoteFileWarning1") +
|
||||||
QString::number(switcher->interval) + "ms");
|
QString::number(switcher->interval) +
|
||||||
|
obs_module_text("AdvSceneSwitcher.fileTab.remoteFileWarning2"));
|
||||||
|
ui->remoteFileWarningLabel->hide();
|
||||||
|
|
||||||
if (switcher->curl)
|
if (switcher->curl) {
|
||||||
ui->libcurlWarning->setVisible(false);
|
ui->libcurlWarning->setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
for (auto &s : switcher->fileSwitches) {
|
for (auto &s : switcher->fileSwitches) {
|
||||||
std::string sceneName = GetWeakSourceName(s.scene);
|
QListWidgetItem *item;
|
||||||
std::string transitionName = GetWeakSourceName(s.transition);
|
item = new QListWidgetItem(ui->fileSwitches);
|
||||||
QString listText = MakeFileSwitchName(
|
ui->fileSwitches->addItem(item);
|
||||||
sceneName.c_str(), transitionName.c_str(),
|
FileSwitchWidget *sw = new FileSwitchWidget(this, &s);
|
||||||
s.file.c_str(), s.text.c_str(), s.useRegex, s.useTime);
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
|
ui->fileSwitches->setItemWidget(item, sw);
|
||||||
|
}
|
||||||
|
|
||||||
QListWidgetItem *item =
|
if (switcher->fileSwitches.size() == 0) {
|
||||||
new QListWidgetItem(listText, ui->fileScenesList);
|
addPulse = PulseWidget(ui->fileAdd, QColor(Qt::green));
|
||||||
item->setData(Qt::UserRole, listText);
|
ui->fileHelp->setVisible(true);
|
||||||
|
} else {
|
||||||
|
ui->fileHelp->setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->readPathLineEdit->setText(
|
ui->readPathLineEdit->setText(
|
||||||
@@ -472,26 +450,245 @@ void AdvSceneSwitcher::setupFileTab()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline QString MakeFileSwitchName(const QString &scene,
|
void FileSwitch::save(obs_data_t *obj)
|
||||||
const QString &transition,
|
|
||||||
const QString &fileName,
|
|
||||||
const QString &text, bool useRegex,
|
|
||||||
bool useTime)
|
|
||||||
{
|
{
|
||||||
QString switchName = QStringLiteral("Switch to ") + scene +
|
SceneSwitcherEntry::save(obj);
|
||||||
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;
|
obs_data_set_string(obj, "file", file.c_str());
|
||||||
|
obs_data_set_string(obj, "text", text.c_str());
|
||||||
|
obs_data_set_bool(obj, "remote", remote);
|
||||||
|
obs_data_set_bool(obj, "useRegex", useRegex);
|
||||||
|
obs_data_set_bool(obj, "useTime", useTime);
|
||||||
|
obs_data_set_bool(obj, "onlyMatchIfChanged", onlyMatchIfChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
// To be removed in future version
|
||||||
|
bool loadOldFile(obs_data_t *obj, FileSwitch *s)
|
||||||
|
{
|
||||||
|
if (!s) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *scene = obs_data_get_string(obj, "scene");
|
||||||
|
|
||||||
|
if (strcmp(scene, "") == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->scene = GetWeakSourceByName(scene);
|
||||||
|
|
||||||
|
const char *transition = obs_data_get_string(obj, "transition");
|
||||||
|
s->transition = GetWeakTransitionByName(transition);
|
||||||
|
|
||||||
|
s->file = obs_data_get_string(obj, "file");
|
||||||
|
s->text = obs_data_get_string(obj, "text");
|
||||||
|
s->remote = obs_data_get_bool(obj, "remote");
|
||||||
|
s->useRegex = obs_data_get_bool(obj, "useRegex");
|
||||||
|
s->useTime = obs_data_get_bool(obj, "useTime");
|
||||||
|
s->onlyMatchIfChanged = obs_data_get_bool(obj, "onlyMatchIfChanged");
|
||||||
|
s->usePreviousScene = strcmp(scene, previous_scene_name) == 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSwitch::load(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
if (loadOldFile(obj, this)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneSwitcherEntry::load(obj);
|
||||||
|
|
||||||
|
file = obs_data_get_string(obj, "file");
|
||||||
|
text = obs_data_get_string(obj, "text");
|
||||||
|
remote = obs_data_get_bool(obj, "remote");
|
||||||
|
useRegex = obs_data_get_bool(obj, "useRegex");
|
||||||
|
useTime = obs_data_get_bool(obj, "useTime");
|
||||||
|
onlyMatchIfChanged = obs_data_get_bool(obj, "onlyMatchIfChanged");
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSwitchWidget::FileSwitchWidget(QWidget *parent, FileSwitch *s)
|
||||||
|
: SwitchWidget(parent, s, true, true)
|
||||||
|
{
|
||||||
|
fileType = new QComboBox();
|
||||||
|
filePath = new QLineEdit();
|
||||||
|
browseButton =
|
||||||
|
new QPushButton(obs_module_text("AdvSceneSwitcher.browse"));
|
||||||
|
browseButton->setStyleSheet("border:1px solid gray;");
|
||||||
|
matchText = new QPlainTextEdit();
|
||||||
|
useRegex = new QCheckBox(
|
||||||
|
obs_module_text("AdvSceneSwitcher.fileTab.useRegExp"));
|
||||||
|
checkModificationDate = new QCheckBox(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.fileTab.checkfileContentTime"));
|
||||||
|
checkFileContent = new QCheckBox(
|
||||||
|
obs_module_text("AdvSceneSwitcher.fileTab.checkfileContent"));
|
||||||
|
|
||||||
|
QWidget::connect(fileType, SIGNAL(currentIndexChanged(int)), this,
|
||||||
|
SLOT(FileTypeChanged(int)));
|
||||||
|
QWidget::connect(filePath, SIGNAL(editingFinished()), this,
|
||||||
|
SLOT(FilePathChanged()));
|
||||||
|
QWidget::connect(browseButton, SIGNAL(clicked()), this,
|
||||||
|
SLOT(BrowseButtonClicked()));
|
||||||
|
QWidget::connect(matchText, SIGNAL(textChanged()), this,
|
||||||
|
SLOT(MatchTextChanged()));
|
||||||
|
QWidget::connect(useRegex, SIGNAL(stateChanged(int)), this,
|
||||||
|
SLOT(UseRegexChanged(int)));
|
||||||
|
QWidget::connect(checkModificationDate, SIGNAL(stateChanged(int)), this,
|
||||||
|
SLOT(CheckModificationDateChanged(int)));
|
||||||
|
QWidget::connect(checkFileContent, SIGNAL(stateChanged(int)), this,
|
||||||
|
SLOT(CheckFileContentChanged(int)));
|
||||||
|
|
||||||
|
fileType->addItem(obs_module_text("AdvSceneSwitcher.fileTab.local"));
|
||||||
|
fileType->addItem(obs_module_text("AdvSceneSwitcher.fileTab.remote"));
|
||||||
|
|
||||||
|
if (s) {
|
||||||
|
if (s->remote) {
|
||||||
|
fileType->setCurrentIndex(1);
|
||||||
|
} else {
|
||||||
|
fileType->setCurrentIndex(0);
|
||||||
|
}
|
||||||
|
filePath->setText(QString::fromStdString(s->file));
|
||||||
|
matchText->setPlainText(QString::fromStdString(s->text));
|
||||||
|
useRegex->setChecked(s->useRegex);
|
||||||
|
checkModificationDate->setChecked(s->useTime);
|
||||||
|
checkFileContent->setChecked(s->onlyMatchIfChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
|
{"{{fileType}}", fileType},
|
||||||
|
{"{{filePath}}", filePath},
|
||||||
|
{"{{browseButton}}", browseButton},
|
||||||
|
{"{{matchText}}", matchText},
|
||||||
|
{"{{useRegex}}", useRegex},
|
||||||
|
{"{{checkModificationDate}}", checkModificationDate},
|
||||||
|
{"{{checkFileContent}}", checkFileContent},
|
||||||
|
{"{{scenes}}", scenes},
|
||||||
|
{"{{transitions}}", transitions}};
|
||||||
|
|
||||||
|
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||||
|
QHBoxLayout *line1Layout = new QHBoxLayout;
|
||||||
|
QHBoxLayout *line2Layout = new QHBoxLayout;
|
||||||
|
QHBoxLayout *line3Layout = new QHBoxLayout;
|
||||||
|
placeWidgets(obs_module_text("AdvSceneSwitcher.fileTab.entry"),
|
||||||
|
line1Layout, widgetPlaceholders);
|
||||||
|
placeWidgets(obs_module_text("AdvSceneSwitcher.fileTab.entry2"),
|
||||||
|
line2Layout, widgetPlaceholders, false);
|
||||||
|
placeWidgets(obs_module_text("AdvSceneSwitcher.fileTab.entry3"),
|
||||||
|
line3Layout, widgetPlaceholders);
|
||||||
|
mainLayout->addLayout(line1Layout);
|
||||||
|
mainLayout->addLayout(line2Layout);
|
||||||
|
mainLayout->addLayout(line3Layout);
|
||||||
|
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
switchData = s;
|
||||||
|
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSwitch *FileSwitchWidget::getSwitchData()
|
||||||
|
{
|
||||||
|
return switchData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSwitchWidget::setSwitchData(FileSwitch *s)
|
||||||
|
{
|
||||||
|
switchData = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSwitchWidget::swapSwitchData(FileSwitchWidget *s1,
|
||||||
|
FileSwitchWidget *s2)
|
||||||
|
{
|
||||||
|
SwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
FileSwitch *t = s1->getSwitchData();
|
||||||
|
s1->setSwitchData(s2->getSwitchData());
|
||||||
|
s2->setSwitchData(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSwitchWidget::FileTypeChanged(int index)
|
||||||
|
{
|
||||||
|
if (loading || !switchData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((file_type)index == LOCAL) {
|
||||||
|
browseButton->setDisabled(false);
|
||||||
|
checkModificationDate->setDisabled(false);
|
||||||
|
} else {
|
||||||
|
browseButton->setDisabled(true);
|
||||||
|
checkModificationDate->setDisabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->remote = (file_type)index == REMOTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSwitchWidget::FilePathChanged()
|
||||||
|
{
|
||||||
|
if (loading || !switchData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->file = filePath->text().toUtf8().constData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSwitchWidget::BrowseButtonClicked()
|
||||||
|
{
|
||||||
|
if (loading || !switchData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString path = QFileDialog::getOpenFileName(
|
||||||
|
this,
|
||||||
|
tr(obs_module_text("AdvSceneSwitcher.fileTab.selectRead")),
|
||||||
|
QDir::currentPath(),
|
||||||
|
tr(obs_module_text("AdvSceneSwitcher.fileTab.anyFileType")));
|
||||||
|
if (path.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
filePath->setText(path);
|
||||||
|
FilePathChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSwitchWidget::MatchTextChanged()
|
||||||
|
{
|
||||||
|
if (loading || !switchData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->text = matchText->toPlainText().toUtf8().constData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSwitchWidget::UseRegexChanged(int state)
|
||||||
|
{
|
||||||
|
if (loading || !switchData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->useRegex = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSwitchWidget::CheckModificationDateChanged(int state)
|
||||||
|
{
|
||||||
|
if (loading || !switchData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->useTime = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSwitchWidget::CheckFileContentChanged(int state)
|
||||||
|
{
|
||||||
|
if (loading || !switchData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->onlyMatchIfChanged = state;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,53 +3,201 @@
|
|||||||
|
|
||||||
bool SceneSwitcherEntry::initialized()
|
bool SceneSwitcherEntry::initialized()
|
||||||
{
|
{
|
||||||
return (usePreviousScene || WeakSourceValid(scene)) && transition;
|
return (usePreviousScene || WeakSourceValid(scene) ||
|
||||||
|
SceneGroupValid(group)) &&
|
||||||
|
transition;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SceneSwitcherEntry::valid()
|
bool SceneSwitcherEntry::valid()
|
||||||
{
|
{
|
||||||
return !initialized() ||
|
return !initialized() || ((usePreviousScene || WeakSourceValid(scene) ||
|
||||||
((usePreviousScene || WeakSourceValid(scene)) &&
|
SceneGroupValid(group)) &&
|
||||||
WeakSourceValid(transition));
|
WeakSourceValid(transition));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneSwitcherEntry::logMatchScene()
|
||||||
|
{
|
||||||
|
std::string sceneName = previous_scene_name;
|
||||||
|
if (!usePreviousScene) {
|
||||||
|
sceneName = GetWeakSourceName(scene);
|
||||||
|
}
|
||||||
|
blog(LOG_INFO, "match for '%s' - switch to scene '%s'", getType(),
|
||||||
|
sceneName.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneSwitcherEntry::logMatchSceneGroup()
|
||||||
|
{
|
||||||
|
if (group->scenes.empty()) {
|
||||||
|
blog(LOG_INFO,
|
||||||
|
"match for '%s' - but no scenes specified in '%s'",
|
||||||
|
getType(), group->name.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string sceneName = GetWeakSourceName(group->getCurrentScene());
|
||||||
|
|
||||||
|
blog(LOG_INFO, "match for '%s' - switch to scene '%s' using '%s'",
|
||||||
|
getType(), sceneName.c_str(), group->name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcherEntry::logMatch()
|
void SceneSwitcherEntry::logMatch()
|
||||||
{
|
{
|
||||||
const char *sceneName = previous_scene_name;
|
if (targetType == SwitchTargetType::Scene) {
|
||||||
if (!usePreviousScene) {
|
logMatchScene();
|
||||||
obs_source_t *s = obs_weak_source_get_source(scene);
|
} else if (targetType == SwitchTargetType::SceneGroup) {
|
||||||
sceneName = obs_source_get_name(s);
|
logMatchSceneGroup();
|
||||||
obs_source_release(s);
|
|
||||||
}
|
}
|
||||||
blog(LOG_INFO, "match for '%s' - switch to scene '%s'", getType(),
|
|
||||||
sceneName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SwitchWidget::SwitchWidget(SceneSwitcherEntry *s, bool usePreviousScene)
|
OBSWeakSource SceneSwitcherEntry::getScene()
|
||||||
|
{
|
||||||
|
if (targetType == SwitchTargetType::Scene) {
|
||||||
|
if (usePreviousScene && switcher) {
|
||||||
|
return switcher->previousScene;
|
||||||
|
}
|
||||||
|
return scene;
|
||||||
|
} else if (targetType == SwitchTargetType::SceneGroup) {
|
||||||
|
return group->getNextScene();
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneSwitcherEntry::save(obs_data_t *obj, const char *targetTypeSaveName,
|
||||||
|
const char *targetSaveName,
|
||||||
|
const char *transitionSaveName)
|
||||||
|
{
|
||||||
|
obs_data_set_int(obj, targetTypeSaveName, static_cast<int>(targetType));
|
||||||
|
|
||||||
|
std::string targetName = "";
|
||||||
|
|
||||||
|
if (targetType == SwitchTargetType::Scene) {
|
||||||
|
if (usePreviousScene) {
|
||||||
|
targetName = previous_scene_name;
|
||||||
|
} else {
|
||||||
|
targetName = GetWeakSourceName(scene);
|
||||||
|
}
|
||||||
|
} else if (targetType == SwitchTargetType::SceneGroup) {
|
||||||
|
targetName = group->name.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_data_set_string(obj, targetSaveName, targetName.c_str());
|
||||||
|
|
||||||
|
obs_data_set_string(obj, transitionSaveName,
|
||||||
|
GetWeakSourceName(transition).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneSwitcherEntry::load(obs_data_t *obj, const char *targetTypeLoadName,
|
||||||
|
const char *targetLoadName,
|
||||||
|
const char *transitionLoadName)
|
||||||
|
{
|
||||||
|
targetType = static_cast<SwitchTargetType>(
|
||||||
|
obs_data_get_int(obj, targetTypeLoadName));
|
||||||
|
|
||||||
|
const char *targetName = obs_data_get_string(obj, targetLoadName);
|
||||||
|
|
||||||
|
if (targetType == SwitchTargetType::Scene) {
|
||||||
|
usePreviousScene = strcmp(targetName, previous_scene_name) == 0;
|
||||||
|
if (!usePreviousScene) {
|
||||||
|
scene = GetWeakSourceByName(targetName);
|
||||||
|
}
|
||||||
|
} else if (targetType == SwitchTargetType::SceneGroup) {
|
||||||
|
group = GetSceneGroupByName(targetName);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *transitionName =
|
||||||
|
obs_data_get_string(obj, transitionLoadName);
|
||||||
|
transition = GetWeakTransitionByName(transitionName);
|
||||||
|
|
||||||
|
usePreviousScene = strcmp(targetName, previous_scene_name) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitchWidget::SceneGroupAdd(const QString &name)
|
||||||
|
{
|
||||||
|
if (!scenes) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
scenes->addItem(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitchWidget::SceneGroupRemove(const QString &name)
|
||||||
|
{
|
||||||
|
if (!scenes) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int idx = scenes->findText(name);
|
||||||
|
|
||||||
|
if (idx == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
scenes->removeItem(idx);
|
||||||
|
|
||||||
|
if (switchData && switchData->group == GetSceneGroupByQString(name)) {
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->targetType = SwitchTargetType::Scene;
|
||||||
|
switchData->scene = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
scenes->setCurrentIndex(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitchWidget::SceneGroupRename(const QString &oldName,
|
||||||
|
const QString &newName)
|
||||||
|
{
|
||||||
|
if (!scenes) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool renameSelected = scenes->currentText() == oldName;
|
||||||
|
int idx = scenes->findText(oldName);
|
||||||
|
|
||||||
|
if (idx == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
scenes->removeItem(idx);
|
||||||
|
scenes->insertItem(idx, newName);
|
||||||
|
|
||||||
|
if (renameSelected) {
|
||||||
|
scenes->setCurrentIndex(scenes->findText(newName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SwitchWidget::SwitchWidget(QWidget *parent, SceneSwitcherEntry *s,
|
||||||
|
bool usePreviousScene, bool addSceneGroup)
|
||||||
{
|
{
|
||||||
scenes = new QComboBox();
|
scenes = new QComboBox();
|
||||||
transitions = new QComboBox();
|
transitions = new QComboBox();
|
||||||
|
|
||||||
|
// Depending on selected OBS theme some widgets might have a different
|
||||||
|
// background color than the listwidget and might look out of place
|
||||||
|
setStyleSheet("QLabel { background-color: transparent; }\
|
||||||
|
QSlider { background-color: transparent; }\
|
||||||
|
QCheckBox { background-color: transparent; }");
|
||||||
|
|
||||||
QWidget::connect(scenes, SIGNAL(currentTextChanged(const QString &)),
|
QWidget::connect(scenes, SIGNAL(currentTextChanged(const QString &)),
|
||||||
this, SLOT(SceneChanged(const QString &)));
|
this, SLOT(SceneChanged(const QString &)));
|
||||||
QWidget::connect(transitions,
|
QWidget::connect(transitions,
|
||||||
SIGNAL(currentTextChanged(const QString &)), this,
|
SIGNAL(currentTextChanged(const QString &)), this,
|
||||||
SLOT(TransitionChanged(const QString &)));
|
SLOT(TransitionChanged(const QString &)));
|
||||||
|
|
||||||
AdvSceneSwitcher::populateSceneSelection(scenes, usePreviousScene);
|
QWidget::connect(parent, SIGNAL(SceneGroupAdded(const QString &)), this,
|
||||||
|
SLOT(SceneGroupAdd(const QString &)));
|
||||||
|
QWidget::connect(parent, SIGNAL(SceneGroupRemoved(const QString &)),
|
||||||
|
this, SLOT(SceneGroupRemove(const QString &)));
|
||||||
|
QWidget::connect(
|
||||||
|
parent,
|
||||||
|
SIGNAL(SceneGroupRenamed(const QString &, const QString &)),
|
||||||
|
this, SLOT(SceneGroupRename(const QString &, const QString &)));
|
||||||
|
|
||||||
|
AdvSceneSwitcher::populateSceneSelection(scenes, usePreviousScene,
|
||||||
|
addSceneGroup);
|
||||||
AdvSceneSwitcher::populateTransitionSelection(transitions);
|
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;
|
switchData = s;
|
||||||
|
showSwitchData();
|
||||||
}
|
}
|
||||||
|
|
||||||
SceneSwitcherEntry *SwitchWidget::getSwitchData()
|
SceneSwitcherEntry *SwitchWidget::getSwitchData()
|
||||||
@@ -62,6 +210,30 @@ void SwitchWidget::setSwitchData(SceneSwitcherEntry *s)
|
|||||||
switchData = s;
|
switchData = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SwitchWidget::showSwitchData()
|
||||||
|
{
|
||||||
|
if (!switchData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
transitions->setCurrentText(
|
||||||
|
GetWeakSourceName(switchData->transition).c_str());
|
||||||
|
|
||||||
|
if (switchData->usePreviousScene) {
|
||||||
|
scenes->setCurrentText(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.selectPreviousScene"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
scenes->setCurrentText(GetWeakSourceName(switchData->scene).c_str());
|
||||||
|
|
||||||
|
if (switchData->group &&
|
||||||
|
switchData->targetType == SwitchTargetType::SceneGroup) {
|
||||||
|
scenes->setCurrentText(
|
||||||
|
QString::fromStdString(switchData->group->name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SwitchWidget::swapSwitchData(SwitchWidget *s1, SwitchWidget *s2)
|
void SwitchWidget::swapSwitchData(SwitchWidget *s1, SwitchWidget *s2)
|
||||||
{
|
{
|
||||||
SceneSwitcherEntry *t = s1->getSwitchData();
|
SceneSwitcherEntry *t = s1->getSwitchData();
|
||||||
@@ -69,21 +241,41 @@ void SwitchWidget::swapSwitchData(SwitchWidget *s1, SwitchWidget *s2)
|
|||||||
s2->setSwitchData(t);
|
s2->setSwitchData(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isPreviousScene(const QString &text)
|
||||||
|
{
|
||||||
|
return text.compare(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.selectPreviousScene")) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
void SwitchWidget::SceneChanged(const QString &text)
|
void SwitchWidget::SceneChanged(const QString &text)
|
||||||
{
|
{
|
||||||
if (loading || !switchData)
|
if (loading || !switchData) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switchData->usePreviousScene = text.compare(previous_scene_name) == 0;
|
|
||||||
if (switchData->usePreviousScene)
|
switchData->usePreviousScene = isPreviousScene(text);
|
||||||
|
if (switchData->usePreviousScene) {
|
||||||
|
switchData->targetType = SwitchTargetType::Scene;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switchData->scene = GetWeakSourceByQString(text);
|
switchData->scene = GetWeakSourceByQString(text);
|
||||||
|
switchData->targetType = SwitchTargetType::Scene;
|
||||||
|
|
||||||
|
if (!switchData->scene) {
|
||||||
|
switchData->group = GetSceneGroupByQString(text);
|
||||||
|
switchData->targetType = SwitchTargetType::SceneGroup;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitchWidget::TransitionChanged(const QString &text)
|
void SwitchWidget::TransitionChanged(const QString &text)
|
||||||
{
|
{
|
||||||
if (loading || !switchData)
|
if (loading || !switchData) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switchData->transition = GetWeakTransitionByQString(text);
|
switchData->transition = GetWeakTransitionByQString(text);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,17 +3,19 @@
|
|||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
|
bool IdleData::pause = false;
|
||||||
|
IdleWidget *idleWidget = nullptr;
|
||||||
|
|
||||||
void SwitcherData::checkIdleSwitch(bool &match, OBSWeakSource &scene,
|
void SwitcherData::checkIdleSwitch(bool &match, OBSWeakSource &scene,
|
||||||
OBSWeakSource &transition)
|
OBSWeakSource &transition)
|
||||||
{
|
{
|
||||||
if (!idleData.idleEnable)
|
if (!idleData.idleEnable || IdleData::pause) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::string title;
|
std::string title;
|
||||||
bool ignoreIdle = false;
|
bool ignoreIdle = false;
|
||||||
//lock.unlock();
|
|
||||||
GetCurrentWindowTitle(title);
|
GetCurrentWindowTitle(title);
|
||||||
//lock.lock();
|
|
||||||
|
|
||||||
for (std::string &window : ignoreIdleWindows) {
|
for (std::string &window : ignoreIdleWindows) {
|
||||||
if (window == title) {
|
if (window == title) {
|
||||||
@@ -37,94 +39,45 @@ void SwitcherData::checkIdleSwitch(bool &match, OBSWeakSource &scene,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!ignoreIdle && secondsSinceLastInput() > idleData.time) {
|
if (!ignoreIdle && secondsSinceLastInput() > idleData.time) {
|
||||||
if (idleData.alreadySwitched)
|
if (idleData.alreadySwitched) {
|
||||||
return;
|
return;
|
||||||
scene = (idleData.usePreviousScene) ? previousScene
|
}
|
||||||
: idleData.scene;
|
scene = idleData.getScene();
|
||||||
transition = idleData.transition;
|
transition = idleData.transition;
|
||||||
match = true;
|
match = true;
|
||||||
idleData.alreadySwitched = true;
|
idleData.alreadySwitched = true;
|
||||||
|
|
||||||
if (verbose)
|
if (verbose) {
|
||||||
idleData.logMatch();
|
idleData.logMatch();
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
idleData.alreadySwitched = false;
|
idleData.alreadySwitched = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_idleCheckBox_stateChanged(int state)
|
void AdvSceneSwitcher::on_idleCheckBox_stateChanged(int state)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
if (!state) {
|
if (!state) {
|
||||||
ui->idleScenes->setDisabled(true);
|
|
||||||
ui->idleSpinBox->setDisabled(true);
|
|
||||||
ui->idleTransitions->setDisabled(true);
|
|
||||||
|
|
||||||
switcher->idleData.idleEnable = false;
|
switcher->idleData.idleEnable = false;
|
||||||
|
idleWidget->setDisabled(true);
|
||||||
} else {
|
} else {
|
||||||
ui->idleScenes->setDisabled(false);
|
|
||||||
ui->idleSpinBox->setDisabled(false);
|
|
||||||
ui->idleTransitions->setDisabled(false);
|
|
||||||
|
|
||||||
switcher->idleData.idleEnable = true;
|
switcher->idleData.idleEnable = true;
|
||||||
|
idleWidget->setDisabled(false);
|
||||||
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)
|
void AdvSceneSwitcher::on_ignoreIdleWindows_currentRowChanged(int idx)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading) {
|
||||||
return;
|
return;
|
||||||
if (idx == -1)
|
}
|
||||||
|
if (idx == -1) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QListWidgetItem *item = ui->ignoreIdleWindows->item(idx);
|
QListWidgetItem *item = ui->ignoreIdleWindows->item(idx);
|
||||||
|
|
||||||
@@ -143,8 +96,9 @@ void AdvSceneSwitcher::on_ignoreIdleAdd_clicked()
|
|||||||
{
|
{
|
||||||
QString windowName = ui->ignoreIdleWindowsWindows->currentText();
|
QString windowName = ui->ignoreIdleWindowsWindows->currentText();
|
||||||
|
|
||||||
if (windowName.isEmpty())
|
if (windowName.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QVariant v = QVariant::fromValue(windowName);
|
QVariant v = QVariant::fromValue(windowName);
|
||||||
|
|
||||||
@@ -166,8 +120,9 @@ void AdvSceneSwitcher::on_ignoreIdleAdd_clicked()
|
|||||||
void AdvSceneSwitcher::on_ignoreIdleRemove_clicked()
|
void AdvSceneSwitcher::on_ignoreIdleRemove_clicked()
|
||||||
{
|
{
|
||||||
QListWidgetItem *item = ui->ignoreIdleWindows->currentItem();
|
QListWidgetItem *item = ui->ignoreIdleWindows->currentItem();
|
||||||
if (!item)
|
if (!item) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QString windowName = item->data(Qt::UserRole).toString();
|
QString windowName = item->data(Qt::UserRole).toString();
|
||||||
|
|
||||||
@@ -218,17 +173,7 @@ void SwitcherData::saveIdleSwitches(obs_data_t *obj)
|
|||||||
obs_data_set_array(obj, "ignoreIdleWindows", ignoreIdleWindowsArray);
|
obs_data_set_array(obj, "ignoreIdleWindows", ignoreIdleWindowsArray);
|
||||||
obs_data_array_release(ignoreIdleWindowsArray);
|
obs_data_array_release(ignoreIdleWindowsArray);
|
||||||
|
|
||||||
std::string idleSceneName = GetWeakSourceName(switcher->idleData.scene);
|
idleData.save(obj);
|
||||||
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)
|
void SwitcherData::loadIdleSwitches(obs_data_t *obj)
|
||||||
@@ -251,24 +196,14 @@ void SwitcherData::loadIdleSwitches(obs_data_t *obj)
|
|||||||
}
|
}
|
||||||
obs_data_array_release(ignoreIdleWindowsArray);
|
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);
|
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);
|
obs_data_set_default_int(obj, "idleTime", default_idle_time);
|
||||||
switcher->idleData.time = obs_data_get_int(obj, "idleTime");
|
|
||||||
switcher->idleData.usePreviousScene =
|
idleData.load(obj);
|
||||||
(idleSceneName == previous_scene_name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::setupIdleTab()
|
void AdvSceneSwitcher::setupIdleTab()
|
||||||
{
|
{
|
||||||
populateSceneSelection(ui->idleScenes, true);
|
|
||||||
populateTransitionSelection(ui->idleTransitions);
|
|
||||||
populateWindowSelection(ui->ignoreIdleWindowsWindows);
|
populateWindowSelection(ui->ignoreIdleWindowsWindows);
|
||||||
|
|
||||||
for (auto &window : switcher->ignoreIdleWindows) {
|
for (auto &window : switcher->ignoreIdleWindows) {
|
||||||
@@ -279,22 +214,71 @@ void AdvSceneSwitcher::setupIdleTab()
|
|||||||
item->setData(Qt::UserRole, text);
|
item->setData(Qt::UserRole, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
idleWidget = new IdleWidget(this, &switcher->idleData);
|
||||||
|
ui->idleWidgetLayout->addWidget(idleWidget);
|
||||||
ui->idleCheckBox->setChecked(switcher->idleData.idleEnable);
|
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()) {
|
if (ui->idleCheckBox->checkState()) {
|
||||||
ui->idleScenes->setDisabled(false);
|
idleWidget->setDisabled(false);
|
||||||
ui->idleSpinBox->setDisabled(false);
|
|
||||||
ui->idleTransitions->setDisabled(false);
|
|
||||||
} else {
|
} else {
|
||||||
ui->idleScenes->setDisabled(true);
|
idleWidget->setDisabled(true);
|
||||||
ui->idleSpinBox->setDisabled(true);
|
|
||||||
ui->idleTransitions->setDisabled(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IdleData::save(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
SceneSwitcherEntry::save(obj, "idleTargetType", "idleSceneName",
|
||||||
|
"idleTransitionName");
|
||||||
|
|
||||||
|
obs_data_set_bool(obj, "idleEnable", idleEnable);
|
||||||
|
obs_data_set_int(obj, "idleTime", time);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IdleData::load(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
SceneSwitcherEntry::load(obj, "idleTargetType", "idleSceneName",
|
||||||
|
"idleTransitionName");
|
||||||
|
|
||||||
|
idleEnable = obs_data_get_bool(obj, "idleEnable");
|
||||||
|
time = obs_data_get_int(obj, "idleTime");
|
||||||
|
}
|
||||||
|
|
||||||
|
IdleWidget::IdleWidget(QWidget *parent, IdleData *s)
|
||||||
|
: SwitchWidget(parent, s, true, true)
|
||||||
|
{
|
||||||
|
duration = new QSpinBox();
|
||||||
|
|
||||||
|
duration->setMinimum(0);
|
||||||
|
duration->setMaximum(1000000);
|
||||||
|
duration->setSuffix("s");
|
||||||
|
|
||||||
|
QWidget::connect(duration, SIGNAL(valueChanged(int)), this,
|
||||||
|
SLOT(DurationChanged(int)));
|
||||||
|
|
||||||
|
if (s) {
|
||||||
|
duration->setValue(s->time);
|
||||||
|
}
|
||||||
|
|
||||||
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
|
{"{{duration}}", duration},
|
||||||
|
{"{{scenes}}", scenes},
|
||||||
|
{"{{transitions}}", transitions}};
|
||||||
|
placeWidgets(obs_module_text("AdvSceneSwitcher.idleTab.idleswitch"),
|
||||||
|
mainLayout, widgetPlaceholders);
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
switchData = s;
|
||||||
|
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IdleWidget::DurationChanged(int dur)
|
||||||
|
{
|
||||||
|
if (loading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switcher->idleData.time = dur;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,29 +1,31 @@
|
|||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
|
bool MediaSwitch::pause = false;
|
||||||
static QMetaObject::Connection addPulse;
|
static QMetaObject::Connection addPulse;
|
||||||
|
|
||||||
|
constexpr auto media_played_to_end_idx = 8;
|
||||||
|
constexpr auto media_any_idx = 9;
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_mediaAdd_clicked()
|
void AdvSceneSwitcher::on_mediaAdd_clicked()
|
||||||
{
|
{
|
||||||
ui->mediaAdd->disconnect(addPulse);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switcher->mediaSwitches.emplace_back();
|
switcher->mediaSwitches.emplace_back();
|
||||||
|
|
||||||
QListWidgetItem *item;
|
listAddClicked(ui->mediaSwitches,
|
||||||
item = new QListWidgetItem(ui->mediaSwitches);
|
new MediaSwitchWidget(this,
|
||||||
ui->mediaSwitches->addItem(item);
|
&switcher->mediaSwitches.back()),
|
||||||
MediaSwitchWidget *sw =
|
ui->mediaAdd, &addPulse);
|
||||||
new MediaSwitchWidget(&switcher->mediaSwitches.back());
|
|
||||||
item->setSizeHint(sw->minimumSizeHint());
|
ui->mediaHelp->setVisible(false);
|
||||||
ui->mediaSwitches->setItemWidget(item, sw);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_mediaRemove_clicked()
|
void AdvSceneSwitcher::on_mediaRemove_clicked()
|
||||||
{
|
{
|
||||||
QListWidgetItem *item = ui->mediaSwitches->currentItem();
|
QListWidgetItem *item = ui->mediaSwitches->currentItem();
|
||||||
if (!item)
|
if (!item) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
@@ -38,8 +40,9 @@ void AdvSceneSwitcher::on_mediaRemove_clicked()
|
|||||||
void AdvSceneSwitcher::on_mediaUp_clicked()
|
void AdvSceneSwitcher::on_mediaUp_clicked()
|
||||||
{
|
{
|
||||||
int index = ui->mediaSwitches->currentRow();
|
int index = ui->mediaSwitches->currentRow();
|
||||||
if (!listMoveUp(ui->mediaSwitches))
|
if (!listMoveUp(ui->mediaSwitches)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
MediaSwitchWidget *s1 =
|
MediaSwitchWidget *s1 =
|
||||||
(MediaSwitchWidget *)ui->mediaSwitches->itemWidget(
|
(MediaSwitchWidget *)ui->mediaSwitches->itemWidget(
|
||||||
@@ -59,8 +62,9 @@ void AdvSceneSwitcher::on_mediaDown_clicked()
|
|||||||
{
|
{
|
||||||
int index = ui->mediaSwitches->currentRow();
|
int index = ui->mediaSwitches->currentRow();
|
||||||
|
|
||||||
if (!listMoveDown(ui->mediaSwitches))
|
if (!listMoveDown(ui->mediaSwitches)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
MediaSwitchWidget *s1 =
|
MediaSwitchWidget *s1 =
|
||||||
(MediaSwitchWidget *)ui->mediaSwitches->itemWidget(
|
(MediaSwitchWidget *)ui->mediaSwitches->itemWidget(
|
||||||
@@ -79,9 +83,14 @@ void AdvSceneSwitcher::on_mediaDown_clicked()
|
|||||||
void SwitcherData::checkMediaSwitch(bool &match, OBSWeakSource &scene,
|
void SwitcherData::checkMediaSwitch(bool &match, OBSWeakSource &scene,
|
||||||
OBSWeakSource &transition)
|
OBSWeakSource &transition)
|
||||||
{
|
{
|
||||||
|
if (MediaSwitch::pause) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (MediaSwitch &mediaSwitch : mediaSwitches) {
|
for (MediaSwitch &mediaSwitch : mediaSwitches) {
|
||||||
if (!mediaSwitch.initialized())
|
if (!mediaSwitch.initialized()) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
obs_source_t *source =
|
obs_source_t *source =
|
||||||
obs_weak_source_get_source(mediaSwitch.source);
|
obs_weak_source_get_source(mediaSwitch.source);
|
||||||
@@ -110,22 +119,42 @@ void SwitcherData::checkMediaSwitch(bool &match, OBSWeakSource &scene,
|
|||||||
// bool matchedEnded = mediaSwitch.state == OBS_MEDIA_STATE_ENDED &&
|
// bool matchedEnded = mediaSwitch.state == OBS_MEDIA_STATE_ENDED &&
|
||||||
// mediaSwitch.ended;
|
// mediaSwitch.ended;
|
||||||
|
|
||||||
bool matchedEnded = false;
|
bool ended = false;
|
||||||
|
|
||||||
if (state == OBS_MEDIA_STATE_ENDED) {
|
if (state == OBS_MEDIA_STATE_ENDED) {
|
||||||
matchedEnded = mediaSwitch.previousStateEnded;
|
ended = mediaSwitch.previousStateEnded;
|
||||||
mediaSwitch.previousStateEnded = true;
|
mediaSwitch.previousStateEnded = true;
|
||||||
} else {
|
} else {
|
||||||
mediaSwitch.previousStateEnded = false;
|
mediaSwitch.previousStateEnded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool matchedEnded =
|
||||||
|
ended && (mediaSwitch.state == OBS_MEDIA_STATE_ENDED);
|
||||||
|
|
||||||
|
// match if playedToEnd was true in last interval
|
||||||
|
// and playback is currently ended
|
||||||
|
bool matchedPlayedToEnd = mediaSwitch.state ==
|
||||||
|
media_played_to_end_idx &&
|
||||||
|
mediaSwitch.playedToEnd && ended;
|
||||||
|
|
||||||
|
// interval * 2 to make sure not to miss any state changes
|
||||||
|
// which happened during check of the conditions
|
||||||
|
mediaSwitch.playedToEnd = mediaSwitch.playedToEnd ||
|
||||||
|
(duration - time <= interval * 2);
|
||||||
|
|
||||||
|
// reset
|
||||||
|
if (ended) {
|
||||||
|
mediaSwitch.playedToEnd = false;
|
||||||
|
}
|
||||||
|
|
||||||
// reset for next check
|
// reset for next check
|
||||||
mediaSwitch.stopped = false;
|
mediaSwitch.stopped = false;
|
||||||
mediaSwitch.ended = false;
|
mediaSwitch.ended = false;
|
||||||
|
|
||||||
bool matchedState = ((state == mediaSwitch.state) ||
|
bool matchedState = ((state == mediaSwitch.state) ||
|
||||||
mediaSwitch.anyState) ||
|
mediaSwitch.anyState) ||
|
||||||
matchedStopped || matchedEnded;
|
matchedStopped || matchedEnded ||
|
||||||
|
matchedPlayedToEnd;
|
||||||
|
|
||||||
bool matchedTimeNone =
|
bool matchedTimeNone =
|
||||||
(mediaSwitch.restriction == TIME_RESTRICTION_NONE);
|
(mediaSwitch.restriction == TIME_RESTRICTION_NONE);
|
||||||
@@ -151,15 +180,19 @@ void SwitcherData::checkMediaSwitch(bool &match, OBSWeakSource &scene,
|
|||||||
|
|
||||||
bool matched = matchedState && matchedTime;
|
bool matched = matchedState && matchedTime;
|
||||||
|
|
||||||
if (matched) {
|
if (matched && !mediaSwitch.matched) {
|
||||||
match = true;
|
match = true;
|
||||||
scene = (mediaSwitch.usePreviousScene)
|
scene = mediaSwitch.getScene();
|
||||||
? previousScene
|
|
||||||
: mediaSwitch.scene;
|
|
||||||
transition = mediaSwitch.transition;
|
transition = mediaSwitch.transition;
|
||||||
|
|
||||||
if (verbose)
|
if (verbose) {
|
||||||
mediaSwitch.logMatch();
|
mediaSwitch.logMatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mediaSwitch.matched = matched;
|
||||||
|
|
||||||
|
if (match) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -171,33 +204,8 @@ void SwitcherData::saveMediaSwitches(obs_data_t *obj)
|
|||||||
for (MediaSwitch &s : switcher->mediaSwitches) {
|
for (MediaSwitch &s : switcher->mediaSwitches) {
|
||||||
obs_data_t *array_obj = obs_data_create();
|
obs_data_t *array_obj = obs_data_create();
|
||||||
|
|
||||||
obs_source_t *source = obs_weak_source_get_source(s.source);
|
s.save(array_obj);
|
||||||
obs_source_t *sceneSource = obs_weak_source_get_source(s.scene);
|
obs_data_array_push_back(mediaArray, array_obj);
|
||||||
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_release(array_obj);
|
||||||
}
|
}
|
||||||
@@ -214,21 +222,8 @@ void SwitcherData::loadMediaSwitches(obs_data_t *obj)
|
|||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
obs_data_t *array_obj = obs_data_array_item(mediaArray, i);
|
obs_data_t *array_obj = obs_data_array_item(mediaArray, i);
|
||||||
|
|
||||||
const char *source = obs_data_get_string(array_obj, "source");
|
switcher->mediaSwitches.emplace_back();
|
||||||
const char *scene = obs_data_get_string(array_obj, "scene");
|
mediaSwitches.back().load(array_obj);
|
||||||
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_release(array_obj);
|
||||||
}
|
}
|
||||||
@@ -241,13 +236,17 @@ void AdvSceneSwitcher::setupMediaTab()
|
|||||||
QListWidgetItem *item;
|
QListWidgetItem *item;
|
||||||
item = new QListWidgetItem(ui->mediaSwitches);
|
item = new QListWidgetItem(ui->mediaSwitches);
|
||||||
ui->mediaSwitches->addItem(item);
|
ui->mediaSwitches->addItem(item);
|
||||||
MediaSwitchWidget *sw = new MediaSwitchWidget(&s);
|
MediaSwitchWidget *sw = new MediaSwitchWidget(this, &s);
|
||||||
item->setSizeHint(sw->minimumSizeHint());
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
ui->mediaSwitches->setItemWidget(item, sw);
|
ui->mediaSwitches->setItemWidget(item, sw);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switcher->mediaSwitches.size() == 0)
|
if (switcher->mediaSwitches.size() == 0) {
|
||||||
addPulse = PulseWidget(ui->mediaAdd, QColor(Qt::green));
|
addPulse = PulseWidget(ui->mediaAdd, QColor(Qt::green));
|
||||||
|
ui->mediaHelp->setVisible(true);
|
||||||
|
} else {
|
||||||
|
ui->mediaHelp->setVisible(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MediaSwitch::initialized()
|
bool MediaSwitch::initialized()
|
||||||
@@ -261,6 +260,70 @@ bool MediaSwitch::valid()
|
|||||||
(SceneSwitcherEntry::valid() && WeakSourceValid(source));
|
(SceneSwitcherEntry::valid() && WeakSourceValid(source));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MediaSwitch::save(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
SceneSwitcherEntry::save(obj);
|
||||||
|
|
||||||
|
obs_data_set_string(obj, "source", GetWeakSourceName(source).c_str());
|
||||||
|
|
||||||
|
obs_data_set_int(obj, "state", state);
|
||||||
|
obs_data_set_int(obj, "restriction", restriction);
|
||||||
|
obs_data_set_int(obj, "time", time);
|
||||||
|
}
|
||||||
|
|
||||||
|
// To be removed in future version
|
||||||
|
bool loadOldMedia(obs_data_t *obj, MediaSwitch *s)
|
||||||
|
{
|
||||||
|
if (!s) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *scene = obs_data_get_string(obj, "scene");
|
||||||
|
|
||||||
|
if (strcmp(scene, "") == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->scene = GetWeakSourceByName(scene);
|
||||||
|
|
||||||
|
const char *transition = obs_data_get_string(obj, "transition");
|
||||||
|
s->transition = GetWeakTransitionByName(transition);
|
||||||
|
|
||||||
|
const char *source = obs_data_get_string(obj, "source");
|
||||||
|
s->source = GetWeakSourceByName(source);
|
||||||
|
|
||||||
|
s->state = (obs_media_state)obs_data_get_int(obj, "state");
|
||||||
|
s->restriction = (time_restriction)obs_data_get_int(obj, "restriction");
|
||||||
|
s->time = obs_data_get_int(obj, "time");
|
||||||
|
s->usePreviousScene = strcmp(scene, previous_scene_name) == 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaSwitch::load(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (loadOldMedia(obj, this)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneSwitcherEntry::load(obj);
|
||||||
|
|
||||||
|
const char *sourceName = obs_data_get_string(obj, "source");
|
||||||
|
source = GetWeakSourceByName(sourceName);
|
||||||
|
|
||||||
|
state = (obs_media_state)obs_data_get_int(obj, "state");
|
||||||
|
restriction = (time_restriction)obs_data_get_int(obj, "restriction");
|
||||||
|
time = obs_data_get_int(obj, "time");
|
||||||
|
|
||||||
|
anyState = state == media_any_idx;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
void MediaSwitch::clearSignalHandler()
|
void MediaSwitch::clearSignalHandler()
|
||||||
{
|
{
|
||||||
obs_source_t *mediasource = obs_weak_source_get_source(source);
|
obs_source_t *mediasource = obs_weak_source_get_source(source);
|
||||||
@@ -293,34 +356,15 @@ void MediaSwitch::MediaEnded(void *data, calldata_t *)
|
|||||||
media->ended = true;
|
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)
|
MediaSwitch::MediaSwitch(const MediaSwitch &other)
|
||||||
: SceneSwitcherEntry(other.scene, other.transition,
|
: SceneSwitcherEntry(other.targetType, other.group, other.scene,
|
||||||
other.usePreviousScene),
|
other.transition, other.usePreviousScene),
|
||||||
source(other.source),
|
source(other.source),
|
||||||
state(other.state),
|
state(other.state),
|
||||||
restriction(other.restriction),
|
restriction(other.restriction),
|
||||||
time(other.time)
|
time(other.time)
|
||||||
{
|
{
|
||||||
anyState = state > 7;
|
anyState = state == media_any_idx;
|
||||||
obs_source_t *mediasource = obs_weak_source_get_source(source);
|
obs_source_t *mediasource = obs_weak_source_get_source(source);
|
||||||
signal_handler_t *sh = obs_source_get_signal_handler(mediasource);
|
signal_handler_t *sh = obs_source_get_signal_handler(mediasource);
|
||||||
signal_handler_connect(sh, "media_stopped", MediaStopped, this);
|
signal_handler_connect(sh, "media_stopped", MediaStopped, this);
|
||||||
@@ -329,8 +373,8 @@ MediaSwitch::MediaSwitch(const MediaSwitch &other)
|
|||||||
}
|
}
|
||||||
|
|
||||||
MediaSwitch::MediaSwitch(MediaSwitch &&other)
|
MediaSwitch::MediaSwitch(MediaSwitch &&other)
|
||||||
: SceneSwitcherEntry(other.scene, other.transition,
|
: SceneSwitcherEntry(other.targetType, other.group, other.scene,
|
||||||
other.usePreviousScene),
|
other.transition, other.usePreviousScene),
|
||||||
source(other.source),
|
source(other.source),
|
||||||
state(other.state),
|
state(other.state),
|
||||||
anyState(other.anyState),
|
anyState(other.anyState),
|
||||||
@@ -374,6 +418,8 @@ MediaSwitch &MediaSwitch::operator=(MediaSwitch &&other) noexcept
|
|||||||
|
|
||||||
void swap(MediaSwitch &first, MediaSwitch &second)
|
void swap(MediaSwitch &first, MediaSwitch &second)
|
||||||
{
|
{
|
||||||
|
std::swap(first.targetType, second.targetType);
|
||||||
|
std::swap(first.group, second.group);
|
||||||
std::swap(first.scene, second.scene);
|
std::swap(first.scene, second.scene);
|
||||||
std::swap(first.transition, second.transition);
|
std::swap(first.transition, second.transition);
|
||||||
std::swap(first.usePreviousScene, second.usePreviousScene);
|
std::swap(first.usePreviousScene, second.usePreviousScene);
|
||||||
@@ -388,44 +434,53 @@ void swap(MediaSwitch &first, MediaSwitch &second)
|
|||||||
|
|
||||||
void populateMediaStates(QComboBox *list)
|
void populateMediaStates(QComboBox *list)
|
||||||
{
|
{
|
||||||
list->addItem("None");
|
list->addItem(obs_module_text("AdvSceneSwitcher.mediaTab.states.none"));
|
||||||
list->addItem("Playing");
|
list->addItem(
|
||||||
list->addItem("Opening");
|
obs_module_text("AdvSceneSwitcher.mediaTab.states.playing"));
|
||||||
list->addItem("Buffering");
|
list->addItem(
|
||||||
list->addItem("Paused");
|
obs_module_text("AdvSceneSwitcher.mediaTab.states.opening"));
|
||||||
list->addItem("Stopped");
|
list->addItem(
|
||||||
list->addItem("Ended");
|
obs_module_text("AdvSceneSwitcher.mediaTab.states.buffering"));
|
||||||
list->addItem("Error");
|
list->addItem(
|
||||||
list->addItem("Any");
|
obs_module_text("AdvSceneSwitcher.mediaTab.states.paused"));
|
||||||
|
list->addItem(
|
||||||
|
obs_module_text("AdvSceneSwitcher.mediaTab.states.stopped"));
|
||||||
|
list->addItem(
|
||||||
|
obs_module_text("AdvSceneSwitcher.mediaTab.states.ended"));
|
||||||
|
list->addItem(
|
||||||
|
obs_module_text("AdvSceneSwitcher.mediaTab.states.error"));
|
||||||
|
list->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.mediaTab.states.playedToEnd"));
|
||||||
|
list->addItem(obs_module_text("AdvSceneSwitcher.mediaTab.states.any"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void populateTimeRestrictions(QComboBox *list)
|
void populateTimeRestrictions(QComboBox *list)
|
||||||
{
|
{
|
||||||
list->addItem("None");
|
list->addItem(obs_module_text(
|
||||||
list->addItem("Time shorter");
|
"AdvSceneSwitcher.mediaTab.timeRestriction.none"));
|
||||||
list->addItem("Time longer");
|
list->addItem(obs_module_text(
|
||||||
list->addItem("Time remaining shorter");
|
"AdvSceneSwitcher.mediaTab.timeRestriction.shorter"));
|
||||||
list->addItem("Time remaining longer");
|
list->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.mediaTab.timeRestriction.longer"));
|
||||||
|
list->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.mediaTab.timeRestriction.remainShorter"));
|
||||||
|
list->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.mediaTab.timeRestriction.remainLonger"));
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaSwitchWidget::MediaSwitchWidget(MediaSwitch *s) : SwitchWidget(s)
|
MediaSwitchWidget::MediaSwitchWidget(QWidget *parent, MediaSwitch *s)
|
||||||
|
: SwitchWidget(parent, s, true, true)
|
||||||
{
|
{
|
||||||
meidaSources = new QComboBox();
|
mediaSources = new QComboBox();
|
||||||
states = new QComboBox();
|
states = new QComboBox();
|
||||||
timeRestrictions = new QComboBox();
|
timeRestrictions = new QComboBox();
|
||||||
time = new QSpinBox();
|
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->setSuffix("ms");
|
||||||
time->setMaximum(99999999);
|
time->setMaximum(99999999);
|
||||||
time->setMinimum(0);
|
time->setMinimum(0);
|
||||||
|
|
||||||
QWidget::connect(meidaSources,
|
QWidget::connect(mediaSources,
|
||||||
SIGNAL(currentTextChanged(const QString &)), this,
|
SIGNAL(currentTextChanged(const QString &)), this,
|
||||||
SLOT(SourceChanged(const QString &)));
|
SLOT(SourceChanged(const QString &)));
|
||||||
QWidget::connect(states, SIGNAL(currentIndexChanged(int)), this,
|
QWidget::connect(states, SIGNAL(currentIndexChanged(int)), this,
|
||||||
@@ -435,37 +490,31 @@ MediaSwitchWidget::MediaSwitchWidget(MediaSwitch *s) : SwitchWidget(s)
|
|||||||
QWidget::connect(time, SIGNAL(valueChanged(int)), this,
|
QWidget::connect(time, SIGNAL(valueChanged(int)), this,
|
||||||
SLOT(TimeChanged(int)));
|
SLOT(TimeChanged(int)));
|
||||||
|
|
||||||
AdvSceneSwitcher::populateMediaSelection(meidaSources);
|
AdvSceneSwitcher::populateMediaSelection(mediaSources);
|
||||||
populateMediaStates(states);
|
populateMediaStates(states);
|
||||||
populateTimeRestrictions(timeRestrictions);
|
populateTimeRestrictions(timeRestrictions);
|
||||||
|
|
||||||
if (s) {
|
if (s) {
|
||||||
meidaSources->setCurrentText(
|
mediaSources->setCurrentText(
|
||||||
GetWeakSourceName(s->source).c_str());
|
GetWeakSourceName(s->source).c_str());
|
||||||
states->setCurrentIndex(s->state);
|
states->setCurrentIndex(s->state);
|
||||||
timeRestrictions->setCurrentIndex(s->restriction);
|
timeRestrictions->setCurrentIndex(s->restriction);
|
||||||
time->setValue(s->time);
|
time->setValue(s->time);
|
||||||
if (s->restriction == TIME_RESTRICTION_NONE)
|
if (s->restriction == TIME_RESTRICTION_NONE) {
|
||||||
time->setDisabled(true);
|
time->setDisabled(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setStyleSheet("* { background-color: transparent; }");
|
|
||||||
|
|
||||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
mainLayout->addWidget(whenLabel);
|
{"{{mediaSources}}", mediaSources},
|
||||||
mainLayout->addWidget(meidaSources);
|
{"{{states}}", states},
|
||||||
mainLayout->addWidget(stateLabel);
|
{"{{timeRestrictions}}", timeRestrictions},
|
||||||
mainLayout->addWidget(states);
|
{"{{time}}", time},
|
||||||
mainLayout->addWidget(andLabel);
|
{"{{scenes}}", scenes},
|
||||||
mainLayout->addWidget(timeRestrictions);
|
{"{{transitions}}", transitions}};
|
||||||
mainLayout->addWidget(time);
|
placeWidgets(obs_module_text("AdvSceneSwitcher.mediaTab.entry"),
|
||||||
mainLayout->addWidget(switchLabel);
|
mainLayout, widgetPlaceholders);
|
||||||
mainLayout->addWidget(scenes);
|
|
||||||
mainLayout->addWidget(usingLabel);
|
|
||||||
mainLayout->addWidget(transitions);
|
|
||||||
mainLayout->addStretch();
|
|
||||||
|
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
|
||||||
switchData = s;
|
switchData = s;
|
||||||
@@ -495,8 +544,10 @@ void MediaSwitchWidget::swapSwitchData(MediaSwitchWidget *s1,
|
|||||||
|
|
||||||
void MediaSwitchWidget::SourceChanged(const QString &text)
|
void MediaSwitchWidget::SourceChanged(const QString &text)
|
||||||
{
|
{
|
||||||
if (loading || !switchData)
|
if (loading || !switchData) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switchData->clearSignalHandler();
|
switchData->clearSignalHandler();
|
||||||
switchData->source = GetWeakSourceByQString(text);
|
switchData->source = GetWeakSourceByQString(text);
|
||||||
@@ -505,22 +556,26 @@ void MediaSwitchWidget::SourceChanged(const QString &text)
|
|||||||
|
|
||||||
void MediaSwitchWidget::StateChanged(int index)
|
void MediaSwitchWidget::StateChanged(int index)
|
||||||
{
|
{
|
||||||
if (loading || !switchData)
|
if (loading || !switchData) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switchData->state = (obs_media_state)index;
|
switchData->state = (obs_media_state)index;
|
||||||
switchData->anyState = switchData->state > 7;
|
switchData->anyState = switchData->state == media_any_idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaSwitchWidget::TimeRestrictionChanged(int index)
|
void MediaSwitchWidget::TimeRestrictionChanged(int index)
|
||||||
{
|
{
|
||||||
if (loading || !switchData)
|
if (loading || !switchData) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ((time_restriction)index == TIME_RESTRICTION_NONE)
|
if ((time_restriction)index == TIME_RESTRICTION_NONE) {
|
||||||
time->setDisabled(true);
|
time->setDisabled(true);
|
||||||
else
|
} else {
|
||||||
time->setDisabled(false);
|
time->setDisabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switchData->restriction = (time_restriction)index;
|
switchData->restriction = (time_restriction)index;
|
||||||
@@ -528,8 +583,10 @@ void MediaSwitchWidget::TimeRestrictionChanged(int index)
|
|||||||
|
|
||||||
void MediaSwitchWidget::TimeChanged(int time)
|
void MediaSwitchWidget::TimeChanged(int time)
|
||||||
{
|
{
|
||||||
if (loading || !switchData)
|
if (loading || !switchData) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switchData->time = time;
|
switchData->time = time;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,264 +3,260 @@
|
|||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_pauseScenesAdd_clicked()
|
static QMetaObject::Connection addPulse;
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_pauseAdd_clicked()
|
||||||
{
|
{
|
||||||
QString sceneName = ui->pauseScenesScenes->currentText();
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switcher->pauseEntries.emplace_back();
|
||||||
|
|
||||||
if (sceneName.isEmpty())
|
listAddClicked(ui->pauseEntries,
|
||||||
return;
|
new PauseEntryWidget(this,
|
||||||
|
&switcher->pauseEntries.back()),
|
||||||
|
ui->pauseAdd, &addPulse);
|
||||||
|
|
||||||
OBSWeakSource source = GetWeakSourceByQString(sceneName);
|
ui->pauseHelp->setVisible(false);
|
||||||
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()
|
void AdvSceneSwitcher::on_pauseRemove_clicked()
|
||||||
{
|
{
|
||||||
QListWidgetItem *item = ui->pauseScenes->currentItem();
|
QListWidgetItem *item = ui->pauseEntries->currentItem();
|
||||||
if (!item)
|
if (!item) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
QString pauseScene = item->data(Qt::UserRole).toString();
|
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
auto &switches = switcher->pauseScenesSwitches;
|
int idx = ui->pauseEntries->currentRow();
|
||||||
|
auto &switches = switcher->pauseEntries;
|
||||||
for (auto it = switches.begin(); it != switches.end(); ++it) {
|
switches.erase(switches.begin() + idx);
|
||||||
auto &s = *it;
|
|
||||||
|
|
||||||
if (s == GetWeakSourceByQString(pauseScene)) {
|
|
||||||
switches.erase(it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete item;
|
delete item;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_pauseWindowsAdd_clicked()
|
void AdvSceneSwitcher::on_pauseUp_clicked()
|
||||||
{
|
{
|
||||||
QString windowName = ui->pauseWindowsWindows->currentText();
|
int index = ui->pauseEntries->currentRow();
|
||||||
|
if (!listMoveUp(ui->pauseEntries)) {
|
||||||
if (windowName.isEmpty())
|
|
||||||
return;
|
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;
|
PauseEntryWidget *s1 = (PauseEntryWidget *)ui->pauseEntries->itemWidget(
|
||||||
}
|
ui->pauseEntries->item(index));
|
||||||
|
PauseEntryWidget *s2 = (PauseEntryWidget *)ui->pauseEntries->itemWidget(
|
||||||
void AdvSceneSwitcher::on_pauseScenes_currentRowChanged(int idx)
|
ui->pauseEntries->item(index - 1));
|
||||||
{
|
PauseEntryWidget::swapSwitchData(s1, s2);
|
||||||
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);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
for (auto &s : switcher->pauseScenesSwitches) {
|
|
||||||
std::string name = GetWeakSourceName(s);
|
std::swap(switcher->pauseEntries[index],
|
||||||
if (scene.compare(name.c_str()) == 0) {
|
switcher->pauseEntries[index - 1]);
|
||||||
ui->pauseScenesScenes->setCurrentText(name.c_str());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_pauseWindows_currentRowChanged(int idx)
|
void AdvSceneSwitcher::on_pauseDown_clicked()
|
||||||
{
|
{
|
||||||
if (loading)
|
int index = ui->pauseEntries->currentRow();
|
||||||
return;
|
|
||||||
if (idx == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QListWidgetItem *item = ui->pauseWindows->item(idx);
|
if (!listMoveDown(ui->pauseEntries)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QString window = item->data(Qt::UserRole).toString();
|
PauseEntryWidget *s1 = (PauseEntryWidget *)ui->pauseEntries->itemWidget(
|
||||||
|
ui->pauseEntries->item(index));
|
||||||
|
PauseEntryWidget *s2 = (PauseEntryWidget *)ui->pauseEntries->itemWidget(
|
||||||
|
ui->pauseEntries->item(index + 1));
|
||||||
|
PauseEntryWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
for (auto &s : switcher->pauseWindowsSwitches) {
|
|
||||||
if (window.compare(s.c_str()) == 0) {
|
std::swap(switcher->pauseEntries[index],
|
||||||
ui->pauseWindowsWindows->setCurrentText(s.c_str());
|
switcher->pauseEntries[index + 1]);
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
|
void resetPause()
|
||||||
|
{
|
||||||
|
DefaultSceneTransition::pause = false;
|
||||||
|
WindowSwitch::pause = false;
|
||||||
|
ExecutableSwitch::pause = false;
|
||||||
|
ScreenRegionSwitch::pause = false;
|
||||||
|
MediaSwitch::pause = false;
|
||||||
|
FileSwitch::pause = false;
|
||||||
|
RandomSwitch::pause = false;
|
||||||
|
TimeSwitch::pause = false;
|
||||||
|
IdleData::pause = false;
|
||||||
|
SceneSequenceSwitch::pause = false;
|
||||||
|
AudioSwitch::pause = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPauseTarget(PauseTarget &target, bool &verbose)
|
||||||
|
{
|
||||||
|
switch (target) {
|
||||||
|
case PauseTarget::All:
|
||||||
|
vblog(LOG_INFO, "pause all switching");
|
||||||
|
break;
|
||||||
|
case PauseTarget::Transition:
|
||||||
|
vblog(LOG_INFO, "pause def_transition switching");
|
||||||
|
DefaultSceneTransition::pause = true;
|
||||||
|
break;
|
||||||
|
case PauseTarget::Window:
|
||||||
|
vblog(LOG_INFO, "pause window switching");
|
||||||
|
WindowSwitch::pause = true;
|
||||||
|
break;
|
||||||
|
case PauseTarget::Executable:
|
||||||
|
vblog(LOG_INFO, "pause exec switching");
|
||||||
|
ExecutableSwitch::pause = true;
|
||||||
|
break;
|
||||||
|
case PauseTarget::Region:
|
||||||
|
vblog(LOG_INFO, "pause region switching");
|
||||||
|
ScreenRegionSwitch::pause = true;
|
||||||
|
break;
|
||||||
|
case PauseTarget::Media:
|
||||||
|
vblog(LOG_INFO, "pause media switching");
|
||||||
|
MediaSwitch::pause = true;
|
||||||
|
break;
|
||||||
|
case PauseTarget::File:
|
||||||
|
vblog(LOG_INFO, "pause file switching");
|
||||||
|
FileSwitch::pause = true;
|
||||||
|
break;
|
||||||
|
case PauseTarget::Random:
|
||||||
|
vblog(LOG_INFO, "pause random switching");
|
||||||
|
RandomSwitch::pause = true;
|
||||||
|
break;
|
||||||
|
case PauseTarget::Time:
|
||||||
|
vblog(LOG_INFO, "pause time switching");
|
||||||
|
TimeSwitch::pause = true;
|
||||||
|
break;
|
||||||
|
case PauseTarget::Idle:
|
||||||
|
vblog(LOG_INFO, "pause idle switching");
|
||||||
|
IdleData::pause = true;
|
||||||
|
break;
|
||||||
|
case PauseTarget::Sequence:
|
||||||
|
vblog(LOG_INFO, "pause sequence switching");
|
||||||
|
SceneSequenceSwitch::pause = true;
|
||||||
|
break;
|
||||||
|
case PauseTarget::Audio:
|
||||||
|
vblog(LOG_INFO, "pause audio switching");
|
||||||
|
AudioSwitch::pause = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int AdvSceneSwitcher::PauseScenesFindByData(const QString &scene)
|
bool checkPauseScene(obs_weak_source_t *currentScene, obs_weak_source_t *scene,
|
||||||
|
PauseTarget &target, bool &verbose)
|
||||||
{
|
{
|
||||||
int count = ui->pauseScenes->count();
|
if (currentScene != scene) {
|
||||||
int idx = -1;
|
return false;
|
||||||
|
|
||||||
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;
|
setPauseTarget(target, verbose);
|
||||||
|
return (target == PauseTarget::All);
|
||||||
}
|
}
|
||||||
|
bool checkPauseWindow(std::string ¤tTitle, std::string &title,
|
||||||
int AdvSceneSwitcher::PauseWindowsFindByData(const QString &window)
|
PauseTarget &target, bool &verbose)
|
||||||
{
|
{
|
||||||
int count = ui->pauseWindows->count();
|
if (currentTitle != title) {
|
||||||
int idx = -1;
|
return false;
|
||||||
|
|
||||||
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;
|
setPauseTarget(target, verbose);
|
||||||
|
return (target == PauseTarget::All);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SwitcherData::checkPause()
|
bool SwitcherData::checkPause()
|
||||||
{
|
{
|
||||||
bool pause = false;
|
bool pauseAll = false;
|
||||||
|
|
||||||
|
std::string title;
|
||||||
|
GetCurrentWindowTitle(title);
|
||||||
|
|
||||||
|
resetPause();
|
||||||
|
|
||||||
obs_source_t *currentSource = obs_frontend_get_current_scene();
|
obs_source_t *currentSource = obs_frontend_get_current_scene();
|
||||||
obs_weak_source_t *ws = obs_source_get_weak_source(currentSource);
|
obs_weak_source_t *ws = obs_source_get_weak_source(currentSource);
|
||||||
|
|
||||||
for (OBSWeakSource &s : pauseScenesSwitches) {
|
for (PauseEntry &s : pauseEntries) {
|
||||||
if (s == ws) {
|
if (s.pauseType == PauseType::Scene) {
|
||||||
pause = true;
|
pauseAll = checkPauseScene(ws, s.scene, s.pauseTarget,
|
||||||
|
verbose);
|
||||||
|
} else {
|
||||||
|
pauseAll = checkPauseWindow(title, s.window,
|
||||||
|
s.pauseTarget, verbose);
|
||||||
|
}
|
||||||
|
if (pauseAll) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
obs_source_release(currentSource);
|
obs_source_release(currentSource);
|
||||||
obs_weak_source_release(ws);
|
obs_weak_source_release(ws);
|
||||||
|
|
||||||
std::string title;
|
return pauseAll;
|
||||||
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)
|
void SwitcherData::savePauseSwitches(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
obs_data_array_t *pauseScenesArray = obs_data_array_create();
|
obs_data_array_t *pauseScenesArray = obs_data_array_create();
|
||||||
for (OBSWeakSource &scene : switcher->pauseScenesSwitches) {
|
for (PauseEntry &s : switcher->pauseEntries) {
|
||||||
obs_data_t *array_obj = obs_data_create();
|
obs_data_t *array_obj = obs_data_create();
|
||||||
|
|
||||||
obs_source_t *source = obs_weak_source_get_source(scene);
|
obs_data_set_int(array_obj, "pauseType",
|
||||||
|
static_cast<int>(s.pauseType));
|
||||||
|
obs_data_set_int(array_obj, "pauseTarget",
|
||||||
|
static_cast<int>(s.pauseTarget));
|
||||||
|
obs_data_set_string(array_obj, "pauseWindow", s.window.c_str());
|
||||||
|
|
||||||
|
obs_source_t *source = obs_weak_source_get_source(s.scene);
|
||||||
if (source) {
|
if (source) {
|
||||||
const char *n = obs_source_get_name(source);
|
const char *n = obs_source_get_name(source);
|
||||||
obs_data_set_string(array_obj, "pauseScene", n);
|
obs_data_set_string(array_obj, "pauseScene", n);
|
||||||
obs_data_array_push_back(pauseScenesArray, array_obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
obs_data_array_push_back(pauseScenesArray, array_obj);
|
||||||
|
|
||||||
obs_source_release(source);
|
obs_source_release(source);
|
||||||
obs_data_release(array_obj);
|
obs_data_release(array_obj);
|
||||||
}
|
}
|
||||||
obs_data_set_array(obj, "pauseScenes", pauseScenesArray);
|
obs_data_set_array(obj, "pauseEntries", pauseScenesArray);
|
||||||
|
obs_data_set_int(obj, "oldPauseValuesImported", 1);
|
||||||
obs_data_array_release(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)
|
void SwitcherData::loadPauseSwitches(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
switcher->pauseScenesSwitches.clear();
|
switcher->pauseEntries.clear();
|
||||||
|
|
||||||
|
// To be removed in future builds once most users have migrated
|
||||||
|
loadOldPauseSwitches(obj);
|
||||||
|
|
||||||
|
obs_data_array_t *pauseArray = obs_data_get_array(obj, "pauseEntries");
|
||||||
|
size_t count = obs_data_array_count(pauseArray);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
obs_data_t *array_obj = obs_data_array_item(pauseArray, i);
|
||||||
|
|
||||||
|
PauseType type = static_cast<PauseType>(
|
||||||
|
obs_data_get_int(array_obj, "pauseType"));
|
||||||
|
PauseTarget target = static_cast<PauseTarget>(
|
||||||
|
obs_data_get_int(array_obj, "pauseTarget"));
|
||||||
|
const char *scene =
|
||||||
|
obs_data_get_string(array_obj, "pauseScene");
|
||||||
|
const char *window =
|
||||||
|
obs_data_get_string(array_obj, "pauseWindow");
|
||||||
|
|
||||||
|
switcher->pauseEntries.emplace_back(GetWeakSourceByName(scene),
|
||||||
|
type, target, window);
|
||||||
|
|
||||||
|
obs_data_release(array_obj);
|
||||||
|
}
|
||||||
|
obs_data_array_release(pauseArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitcherData::loadOldPauseSwitches(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
if (obs_data_get_int(obj, "oldPauseValuesImported")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
obs_data_array_t *pauseScenesArray =
|
obs_data_array_t *pauseScenesArray =
|
||||||
obs_data_get_array(obj, "pauseScenes");
|
obs_data_get_array(obj, "pauseScenes");
|
||||||
@@ -273,15 +269,14 @@ void SwitcherData::loadPauseSwitches(obs_data_t *obj)
|
|||||||
const char *scene =
|
const char *scene =
|
||||||
obs_data_get_string(array_obj, "pauseScene");
|
obs_data_get_string(array_obj, "pauseScene");
|
||||||
|
|
||||||
switcher->pauseScenesSwitches.emplace_back(
|
switcher->pauseEntries.emplace_back(GetWeakSourceByName(scene),
|
||||||
GetWeakSourceByName(scene));
|
PauseType::Scene,
|
||||||
|
PauseTarget::All, "");
|
||||||
|
|
||||||
obs_data_release(array_obj);
|
obs_data_release(array_obj);
|
||||||
}
|
}
|
||||||
obs_data_array_release(pauseScenesArray);
|
obs_data_array_release(pauseScenesArray);
|
||||||
|
|
||||||
switcher->pauseWindowsSwitches.clear();
|
|
||||||
|
|
||||||
obs_data_array_t *pauseWindowsArray =
|
obs_data_array_t *pauseWindowsArray =
|
||||||
obs_data_get_array(obj, "pauseWindows");
|
obs_data_get_array(obj, "pauseWindows");
|
||||||
count = obs_data_array_count(pauseWindowsArray);
|
count = obs_data_array_count(pauseWindowsArray);
|
||||||
@@ -293,7 +288,8 @@ void SwitcherData::loadPauseSwitches(obs_data_t *obj)
|
|||||||
const char *window =
|
const char *window =
|
||||||
obs_data_get_string(array_obj, "pauseWindow");
|
obs_data_get_string(array_obj, "pauseWindow");
|
||||||
|
|
||||||
switcher->pauseWindowsSwitches.emplace_back(window);
|
switcher->pauseEntries.emplace_back(nullptr, PauseType::Window,
|
||||||
|
PauseTarget::All, window);
|
||||||
|
|
||||||
obs_data_release(array_obj);
|
obs_data_release(array_obj);
|
||||||
}
|
}
|
||||||
@@ -302,23 +298,164 @@ void SwitcherData::loadPauseSwitches(obs_data_t *obj)
|
|||||||
|
|
||||||
void AdvSceneSwitcher::setupPauseTab()
|
void AdvSceneSwitcher::setupPauseTab()
|
||||||
{
|
{
|
||||||
populateSceneSelection(ui->pauseScenesScenes, false);
|
for (auto &s : switcher->pauseEntries) {
|
||||||
populateWindowSelection(ui->pauseWindowsWindows);
|
QListWidgetItem *item;
|
||||||
|
item = new QListWidgetItem(ui->pauseEntries);
|
||||||
for (auto &scene : switcher->pauseScenesSwitches) {
|
ui->pauseEntries->addItem(item);
|
||||||
std::string sceneName = GetWeakSourceName(scene);
|
PauseEntryWidget *sw = new PauseEntryWidget(this, &s);
|
||||||
QString text = QString::fromStdString(sceneName);
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
|
ui->pauseEntries->setItemWidget(item, sw);
|
||||||
QListWidgetItem *item =
|
|
||||||
new QListWidgetItem(text, ui->pauseScenes);
|
|
||||||
item->setData(Qt::UserRole, text);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &window : switcher->pauseWindowsSwitches) {
|
if (switcher->pauseEntries.size() == 0) {
|
||||||
QString text = QString::fromStdString(window);
|
addPulse = PulseWidget(ui->pauseAdd, QColor(Qt::green));
|
||||||
|
ui->pauseHelp->setVisible(true);
|
||||||
QListWidgetItem *item =
|
} else {
|
||||||
new QListWidgetItem(text, ui->pauseWindows);
|
ui->pauseHelp->setVisible(false);
|
||||||
item->setData(Qt::UserRole, text);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void populatePauseTypes(QComboBox *list)
|
||||||
|
{
|
||||||
|
list->addItem(
|
||||||
|
obs_module_text("AdvSceneSwitcher.pauseTab.pauseTypeScene"));
|
||||||
|
list->addItem(
|
||||||
|
obs_module_text("AdvSceneSwitcher.pauseTab.pauseTypeWindow"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void populatePauseTargets(QComboBox *list)
|
||||||
|
{
|
||||||
|
list->addItem(
|
||||||
|
obs_module_text("AdvSceneSwitcher.pauseTab.pauseTargetAll"));
|
||||||
|
list->addItem(obs_module_text("AdvSceneSwitcher.transitionTab.title"));
|
||||||
|
list->addItem(obs_module_text("AdvSceneSwitcher.windowTitleTab.title"));
|
||||||
|
list->addItem(obs_module_text("AdvSceneSwitcher.executableTab.title"));
|
||||||
|
list->addItem(
|
||||||
|
obs_module_text("AdvSceneSwitcher.screenRegionTab.title"));
|
||||||
|
list->addItem(obs_module_text("AdvSceneSwitcher.mediaTab.title"));
|
||||||
|
list->addItem(obs_module_text("AdvSceneSwitcher.fileTab.title"));
|
||||||
|
list->addItem(obs_module_text("AdvSceneSwitcher.randomTab.title"));
|
||||||
|
list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.title"));
|
||||||
|
list->addItem(obs_module_text("AdvSceneSwitcher.idleTab.title"));
|
||||||
|
list->addItem(
|
||||||
|
obs_module_text("AdvSceneSwitcher.sceneSequenceTab.title"));
|
||||||
|
list->addItem(obs_module_text("AdvSceneSwitcher.audioTab.title"));
|
||||||
|
}
|
||||||
|
|
||||||
|
PauseEntryWidget::PauseEntryWidget(QWidget *parent, PauseEntry *s)
|
||||||
|
: SwitchWidget(parent, s, false, false)
|
||||||
|
{
|
||||||
|
pauseTypes = new QComboBox();
|
||||||
|
pauseTargets = new QComboBox();
|
||||||
|
windows = new QComboBox();
|
||||||
|
|
||||||
|
QWidget::connect(pauseTypes, SIGNAL(currentIndexChanged(int)), this,
|
||||||
|
SLOT(PauseTypeChanged(int)));
|
||||||
|
QWidget::connect(pauseTargets, SIGNAL(currentIndexChanged(int)), this,
|
||||||
|
SLOT(PauseTargetChanged(int)));
|
||||||
|
QWidget::connect(windows, SIGNAL(currentTextChanged(const QString &)),
|
||||||
|
this, SLOT(WindowChanged(const QString &)));
|
||||||
|
|
||||||
|
populatePauseTypes(pauseTypes);
|
||||||
|
populatePauseTargets(pauseTargets);
|
||||||
|
AdvSceneSwitcher::populateWindowSelection(windows);
|
||||||
|
|
||||||
|
windows->setEditable(true);
|
||||||
|
windows->setMaxVisibleItems(20);
|
||||||
|
|
||||||
|
if (s) {
|
||||||
|
scenes->setCurrentText(GetWeakSourceName(s->scene).c_str());
|
||||||
|
pauseTypes->setCurrentIndex(static_cast<int>(s->pauseType));
|
||||||
|
pauseTargets->setCurrentIndex(static_cast<int>(s->pauseTarget));
|
||||||
|
windows->setCurrentText(s->window.c_str());
|
||||||
|
if (s->pauseType == PauseType::Scene) {
|
||||||
|
windows->setDisabled(true);
|
||||||
|
windows->setVisible(false);
|
||||||
|
} else {
|
||||||
|
scenes->setDisabled(true);
|
||||||
|
scenes->setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
|
{"{{scenes}}", scenes},
|
||||||
|
{"{{pauseTypes}}", pauseTypes},
|
||||||
|
{"{{pauseTargets}}", pauseTargets},
|
||||||
|
{"{{windows}}", windows}};
|
||||||
|
|
||||||
|
placeWidgets(obs_module_text("AdvSceneSwitcher.pauseTab.pauseEntry"),
|
||||||
|
mainLayout, widgetPlaceholders);
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
switchData = s;
|
||||||
|
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PauseEntry *PauseEntryWidget::getSwitchData()
|
||||||
|
{
|
||||||
|
return switchData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PauseEntryWidget::setSwitchData(PauseEntry *s)
|
||||||
|
{
|
||||||
|
switchData = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PauseEntryWidget::swapSwitchData(PauseEntryWidget *s1,
|
||||||
|
PauseEntryWidget *s2)
|
||||||
|
{
|
||||||
|
SwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
PauseEntry *t = s1->getSwitchData();
|
||||||
|
s1->setSwitchData(s2->getSwitchData());
|
||||||
|
s2->setSwitchData(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PauseEntryWidget::PauseTypeChanged(int index)
|
||||||
|
{
|
||||||
|
if (loading || !switchData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->pauseType = static_cast<PauseType>(index);
|
||||||
|
|
||||||
|
if (switchData->pauseType == PauseType::Scene) {
|
||||||
|
windows->setDisabled(true);
|
||||||
|
windows->setVisible(false);
|
||||||
|
scenes->setDisabled(false);
|
||||||
|
scenes->setVisible(true);
|
||||||
|
} else {
|
||||||
|
scenes->setDisabled(true);
|
||||||
|
scenes->setVisible(false);
|
||||||
|
windows->setDisabled(false);
|
||||||
|
windows->setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PauseEntryWidget::PauseTargetChanged(int index)
|
||||||
|
{
|
||||||
|
if (loading || !switchData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->pauseTarget = static_cast<PauseTarget>(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PauseEntryWidget::WindowChanged(const QString &text)
|
||||||
|
{
|
||||||
|
if (loading || !switchData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->window = text.toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PauseEntry::valid()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
@@ -58,12 +58,14 @@ bool SwitcherData::prioFuncsValid()
|
|||||||
auto it = std::unique(functionNamesByPriority.begin(),
|
auto it = std::unique(functionNamesByPriority.begin(),
|
||||||
functionNamesByPriority.end());
|
functionNamesByPriority.end());
|
||||||
bool wasUnique = (it == functionNamesByPriority.end());
|
bool wasUnique = (it == functionNamesByPriority.end());
|
||||||
if (!wasUnique)
|
if (!wasUnique) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (int p : functionNamesByPriority) {
|
for (int p : functionNamesByPriority) {
|
||||||
if (p < 0 || p > 8)
|
if (p < 0 || p > 8) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,29 +3,28 @@
|
|||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
|
bool RandomSwitch::pause = false;
|
||||||
static QMetaObject::Connection addPulse;
|
static QMetaObject::Connection addPulse;
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_randomAdd_clicked()
|
void AdvSceneSwitcher::on_randomAdd_clicked()
|
||||||
{
|
{
|
||||||
ui->randomAdd->disconnect(addPulse);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switcher->randomSwitches.emplace_back();
|
switcher->randomSwitches.emplace_back();
|
||||||
|
|
||||||
QListWidgetItem *item;
|
listAddClicked(ui->randomSwitches,
|
||||||
item = new QListWidgetItem(ui->randomSwitches);
|
new RandomSwitchWidget(this,
|
||||||
ui->randomSwitches->addItem(item);
|
&switcher->randomSwitches.back()),
|
||||||
RandomSwitchWidget *sw =
|
ui->randomAdd, &addPulse);
|
||||||
new RandomSwitchWidget(&switcher->randomSwitches.back());
|
|
||||||
item->setSizeHint(sw->minimumSizeHint());
|
ui->randomHelp->setVisible(false);
|
||||||
ui->randomSwitches->setItemWidget(item, sw);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_randomRemove_clicked()
|
void AdvSceneSwitcher::on_randomRemove_clicked()
|
||||||
{
|
{
|
||||||
QListWidgetItem *item = ui->randomSwitches->currentItem();
|
QListWidgetItem *item = ui->randomSwitches->currentItem();
|
||||||
if (!item)
|
if (!item) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
@@ -40,27 +39,32 @@ void AdvSceneSwitcher::on_randomRemove_clicked()
|
|||||||
void SwitcherData::checkRandom(bool &match, OBSWeakSource &scene,
|
void SwitcherData::checkRandom(bool &match, OBSWeakSource &scene,
|
||||||
OBSWeakSource &transition, int &delay)
|
OBSWeakSource &transition, int &delay)
|
||||||
{
|
{
|
||||||
if (randomSwitches.size() == 0)
|
if (randomSwitches.size() == 0 || RandomSwitch::pause) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::deque<RandomSwitch> rs(randomSwitches);
|
std::deque<RandomSwitch> rs(randomSwitches);
|
||||||
std::random_device rng;
|
std::random_device rng;
|
||||||
std::mt19937 urng(rng());
|
std::mt19937 urng(rng());
|
||||||
std::shuffle(rs.begin(), rs.end(), urng);
|
std::shuffle(rs.begin(), rs.end(), urng);
|
||||||
for (RandomSwitch &r : rs) {
|
for (RandomSwitch &r : rs) {
|
||||||
if (!r.initialized())
|
if (!r.initialized()) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (r.scene == lastRandomScene)
|
if (r.scene == lastRandomScene && randomSwitches.size() != 1) {
|
||||||
continue;
|
continue;
|
||||||
scene = r.scene;
|
}
|
||||||
|
|
||||||
|
scene = r.getScene();
|
||||||
transition = r.transition;
|
transition = r.transition;
|
||||||
delay = (int)r.delay * 1000;
|
delay = (int)r.delay * 1000;
|
||||||
match = true;
|
match = true;
|
||||||
lastRandomScene = r.scene;
|
lastRandomScene = r.scene;
|
||||||
|
|
||||||
if (verbose)
|
if (verbose) {
|
||||||
r.logMatch();
|
r.logMatch();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,22 +75,9 @@ void SwitcherData::saveRandomSwitches(obs_data_t *obj)
|
|||||||
for (RandomSwitch &s : switcher->randomSwitches) {
|
for (RandomSwitch &s : switcher->randomSwitches) {
|
||||||
obs_data_t *array_obj = obs_data_create();
|
obs_data_t *array_obj = obs_data_create();
|
||||||
|
|
||||||
obs_source_t *source = obs_weak_source_get_source(s.scene);
|
s.save(array_obj);
|
||||||
obs_source_t *transition =
|
obs_data_array_push_back(randomArray, array_obj);
|
||||||
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_release(array_obj);
|
||||||
}
|
}
|
||||||
obs_data_set_array(obj, "randomSwitches", randomArray);
|
obs_data_set_array(obj, "randomSwitches", randomArray);
|
||||||
@@ -104,14 +95,8 @@ void SwitcherData::loadRandomSwitches(obs_data_t *obj)
|
|||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
obs_data_t *array_obj = obs_data_array_item(randomArray, i);
|
obs_data_t *array_obj = obs_data_array_item(randomArray, i);
|
||||||
|
|
||||||
const char *scene = obs_data_get_string(array_obj, "scene");
|
switcher->randomSwitches.emplace_back();
|
||||||
const char *transition =
|
randomSwitches.back().load(array_obj);
|
||||||
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_release(array_obj);
|
||||||
}
|
}
|
||||||
@@ -124,29 +109,43 @@ void AdvSceneSwitcher::setupRandomTab()
|
|||||||
QListWidgetItem *item;
|
QListWidgetItem *item;
|
||||||
item = new QListWidgetItem(ui->randomSwitches);
|
item = new QListWidgetItem(ui->randomSwitches);
|
||||||
ui->randomSwitches->addItem(item);
|
ui->randomSwitches->addItem(item);
|
||||||
RandomSwitchWidget *sw = new RandomSwitchWidget(&s);
|
RandomSwitchWidget *sw = new RandomSwitchWidget(this, &s);
|
||||||
item->setSizeHint(sw->minimumSizeHint());
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
ui->randomSwitches->setItemWidget(item, sw);
|
ui->randomSwitches->setItemWidget(item, sw);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switcher->randomSwitches.size() == 0)
|
if (switcher->randomSwitches.size() == 0) {
|
||||||
addPulse = PulseWidget(ui->randomAdd, QColor(Qt::green));
|
addPulse = PulseWidget(ui->randomAdd, QColor(Qt::green));
|
||||||
|
ui->randomHelp->setVisible(true);
|
||||||
|
} else {
|
||||||
|
ui->randomHelp->setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
if (switcher->switchIfNotMatching != RANDOM_SWITCH)
|
if (switcher->switchIfNotMatching != RANDOM_SWITCH) {
|
||||||
PulseWidget(ui->randomDisabledWarning, QColor(Qt::red),
|
PulseWidget(ui->randomDisabledWarning, QColor(Qt::red),
|
||||||
QColor(0, 0, 0, 0), "QLabel ");
|
QColor(0, 0, 0, 0), "QLabel ");
|
||||||
else
|
} else {
|
||||||
ui->randomDisabledWarning->setVisible(false);
|
ui->randomDisabledWarning->setVisible(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RandomSwitchWidget::RandomSwitchWidget(RandomSwitch *s) : SwitchWidget(s, false)
|
void RandomSwitch::save(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
SceneSwitcherEntry::save(obj, "targetType", "scene");
|
||||||
|
obs_data_set_double(obj, "delay", delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RandomSwitch::load(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
SceneSwitcherEntry::load(obj, "targetType", "scene");
|
||||||
|
delay = obs_data_get_double(obj, "delay");
|
||||||
|
}
|
||||||
|
|
||||||
|
RandomSwitchWidget::RandomSwitchWidget(QWidget *parent, RandomSwitch *s)
|
||||||
|
: SwitchWidget(parent, s, false, false)
|
||||||
{
|
{
|
||||||
delay = new QDoubleSpinBox();
|
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,
|
QWidget::connect(delay, SIGNAL(valueChanged(double)), this,
|
||||||
SLOT(DelayChanged(double)));
|
SLOT(DelayChanged(double)));
|
||||||
|
|
||||||
@@ -157,18 +156,13 @@ RandomSwitchWidget::RandomSwitchWidget(RandomSwitch *s) : SwitchWidget(s, false)
|
|||||||
delay->setValue(s->delay);
|
delay->setValue(s->delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
setStyleSheet("* { background-color: transparent; }");
|
|
||||||
|
|
||||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
mainLayout->addWidget(switchLabel);
|
{"{{scenes}}", scenes},
|
||||||
mainLayout->addWidget(scenes);
|
{"{{transitions}}", transitions},
|
||||||
mainLayout->addWidget(usingLabel);
|
{"{{delay}}", delay}};
|
||||||
mainLayout->addWidget(transitions);
|
placeWidgets(obs_module_text("AdvSceneSwitcher.randomTab.entry"),
|
||||||
mainLayout->addWidget(forLabel);
|
mainLayout, widgetPlaceholders);
|
||||||
mainLayout->addWidget(delay);
|
|
||||||
mainLayout->addStretch();
|
|
||||||
|
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
|
||||||
switchData = s;
|
switchData = s;
|
||||||
@@ -198,8 +192,10 @@ void RandomSwitchWidget::swapSwitchData(RandomSwitchWidget *s1,
|
|||||||
|
|
||||||
void RandomSwitchWidget::DelayChanged(double d)
|
void RandomSwitchWidget::DelayChanged(double d)
|
||||||
{
|
{
|
||||||
if (loading || !switchData)
|
if (loading || !switchData) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switchData->delay = d;
|
switchData->delay = d;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,10 @@
|
|||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
|
bool ScreenRegionSwitch::pause = false;
|
||||||
static QMetaObject::Connection addPulse;
|
static QMetaObject::Connection addPulse;
|
||||||
|
|
||||||
void clearFrames(QListWidget *list)
|
void AdvSceneSwitcher::clearFrames(QListWidget *list)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < list->count(); ++i) {
|
for (int i = 0; i < list->count(); ++i) {
|
||||||
ScreenRegionWidget *sw =
|
ScreenRegionWidget *sw =
|
||||||
@@ -18,31 +19,44 @@ void showCurrentFrame(QListWidget *list)
|
|||||||
{
|
{
|
||||||
QListWidgetItem *item = list->currentItem();
|
QListWidgetItem *item = list->currentItem();
|
||||||
|
|
||||||
if (!item)
|
if (!item) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ScreenRegionWidget *sw = (ScreenRegionWidget *)list->itemWidget(item);
|
ScreenRegionWidget *sw = (ScreenRegionWidget *)list->itemWidget(item);
|
||||||
sw->showFrame();
|
sw->showFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::SetShowFrames()
|
||||||
|
{
|
||||||
|
ui->showFrame->setText(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.screenRegionTab.showGuideFrames"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::SetHideFrames()
|
||||||
|
{
|
||||||
|
ui->showFrame->setText(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.screenRegionTab.hideGuideFrames"));
|
||||||
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_showFrame_clicked()
|
void AdvSceneSwitcher::on_showFrame_clicked()
|
||||||
{
|
{
|
||||||
switcher->showFrame = !switcher->showFrame;
|
switcher->showFrame = !switcher->showFrame;
|
||||||
|
|
||||||
if (switcher->showFrame) {
|
if (switcher->showFrame) {
|
||||||
ui->showFrame->setText("Hide guide frames");
|
SetHideFrames();
|
||||||
showCurrentFrame(ui->screenRegionSwitches);
|
showCurrentFrame(ui->screenRegionSwitches);
|
||||||
} else {
|
} else {
|
||||||
ui->showFrame->setText("Show guide frames");
|
SetShowFrames();
|
||||||
clearFrames(ui->screenRegionSwitches);
|
clearFrames(ui->screenRegionSwitches);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_screenRegionSwitches_currentRowChanged(int idx)
|
void AdvSceneSwitcher::on_screenRegionSwitches_currentRowChanged(int idx)
|
||||||
{
|
{
|
||||||
UNUSED_PARAMETER(idx);
|
if (loading || idx == -1) {
|
||||||
if (loading)
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (switcher->showFrame) {
|
if (switcher->showFrame) {
|
||||||
clearFrames(ui->screenRegionSwitches);
|
clearFrames(ui->screenRegionSwitches);
|
||||||
@@ -52,25 +66,23 @@ void AdvSceneSwitcher::on_screenRegionSwitches_currentRowChanged(int idx)
|
|||||||
|
|
||||||
void AdvSceneSwitcher::on_screenRegionAdd_clicked()
|
void AdvSceneSwitcher::on_screenRegionAdd_clicked()
|
||||||
{
|
{
|
||||||
ui->screenRegionAdd->disconnect(addPulse);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switcher->screenRegionSwitches.emplace_back();
|
switcher->screenRegionSwitches.emplace_back();
|
||||||
|
|
||||||
QListWidgetItem *item;
|
listAddClicked(ui->screenRegionSwitches,
|
||||||
item = new QListWidgetItem(ui->screenRegionSwitches);
|
new ScreenRegionWidget(
|
||||||
ui->screenRegionSwitches->addItem(item);
|
this, &switcher->screenRegionSwitches.back()),
|
||||||
ScreenRegionWidget *sw =
|
ui->screenRegionAdd, &addPulse);
|
||||||
new ScreenRegionWidget(&switcher->screenRegionSwitches.back());
|
|
||||||
item->setSizeHint(sw->minimumSizeHint());
|
ui->regionHelp->setVisible(false);
|
||||||
ui->screenRegionSwitches->setItemWidget(item, sw);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_screenRegionRemove_clicked()
|
void AdvSceneSwitcher::on_screenRegionRemove_clicked()
|
||||||
{
|
{
|
||||||
QListWidgetItem *item = ui->screenRegionSwitches->currentItem();
|
QListWidgetItem *item = ui->screenRegionSwitches->currentItem();
|
||||||
if (!item)
|
if (!item) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
@@ -85,8 +97,9 @@ void AdvSceneSwitcher::on_screenRegionRemove_clicked()
|
|||||||
void AdvSceneSwitcher::on_screenRegionUp_clicked()
|
void AdvSceneSwitcher::on_screenRegionUp_clicked()
|
||||||
{
|
{
|
||||||
int index = ui->screenRegionSwitches->currentRow();
|
int index = ui->screenRegionSwitches->currentRow();
|
||||||
if (!listMoveUp(ui->screenRegionSwitches))
|
if (!listMoveUp(ui->screenRegionSwitches)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ScreenRegionWidget *s1 =
|
ScreenRegionWidget *s1 =
|
||||||
(ScreenRegionWidget *)ui->screenRegionSwitches->itemWidget(
|
(ScreenRegionWidget *)ui->screenRegionSwitches->itemWidget(
|
||||||
@@ -106,8 +119,9 @@ void AdvSceneSwitcher::on_screenRegionDown_clicked()
|
|||||||
{
|
{
|
||||||
int index = ui->screenRegionSwitches->currentRow();
|
int index = ui->screenRegionSwitches->currentRow();
|
||||||
|
|
||||||
if (!listMoveDown(ui->screenRegionSwitches))
|
if (!listMoveDown(ui->screenRegionSwitches)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ScreenRegionWidget *s1 =
|
ScreenRegionWidget *s1 =
|
||||||
(ScreenRegionWidget *)ui->screenRegionSwitches->itemWidget(
|
(ScreenRegionWidget *)ui->screenRegionSwitches->itemWidget(
|
||||||
@@ -123,27 +137,52 @@ void AdvSceneSwitcher::on_screenRegionDown_clicked()
|
|||||||
switcher->screenRegionSwitches[index + 1]);
|
switcher->screenRegionSwitches[index + 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool shouldIgnoreSceneSwitch(ScreenRegionSwitch &matchingRegion)
|
||||||
|
{
|
||||||
|
if (!matchingRegion.excludeScene) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_source_t *currentScene = obs_frontend_get_current_scene();
|
||||||
|
OBSWeakSource ws = obs_source_get_weak_source(currentScene);
|
||||||
|
obs_weak_source_release(ws);
|
||||||
|
obs_source_release(currentScene);
|
||||||
|
|
||||||
|
return matchingRegion.excludeScene == ws;
|
||||||
|
}
|
||||||
|
|
||||||
void SwitcherData::checkScreenRegionSwitch(bool &match, OBSWeakSource &scene,
|
void SwitcherData::checkScreenRegionSwitch(bool &match, OBSWeakSource &scene,
|
||||||
OBSWeakSource &transition)
|
OBSWeakSource &transition)
|
||||||
{
|
{
|
||||||
|
if (ScreenRegionSwitch::pause) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::pair<int, int> cursorPos = getCursorPos();
|
std::pair<int, int> cursorPos = getCursorPos();
|
||||||
int minRegionSize = 99999;
|
int minRegionSize = 99999;
|
||||||
|
|
||||||
for (auto &s : screenRegionSwitches) {
|
for (auto &s : screenRegionSwitches) {
|
||||||
if (!s.initialized())
|
if (!s.initialized()) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (cursorPos.first >= s.minX && cursorPos.second >= s.minY &&
|
if (cursorPos.first >= s.minX && cursorPos.second >= s.minY &&
|
||||||
cursorPos.first <= s.maxX && cursorPos.second <= s.maxY) {
|
cursorPos.first <= s.maxX && cursorPos.second <= s.maxY) {
|
||||||
int regionSize = (s.maxX - s.minX) + (s.maxY - s.minY);
|
int regionSize = (s.maxX - s.minX) + (s.maxY - s.minY);
|
||||||
if (regionSize < minRegionSize) {
|
if (regionSize < minRegionSize) {
|
||||||
|
if (shouldIgnoreSceneSwitch(s)) {
|
||||||
|
// We technically have a match.
|
||||||
|
// But just ignore it.
|
||||||
|
return;
|
||||||
|
}
|
||||||
match = true;
|
match = true;
|
||||||
scene = s.scene;
|
scene = s.getScene();
|
||||||
transition = s.transition;
|
transition = s.transition;
|
||||||
minRegionSize = regionSize;
|
minRegionSize = regionSize;
|
||||||
|
|
||||||
if (verbose)
|
if (verbose) {
|
||||||
s.logMatch();
|
s.logMatch();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -163,25 +202,9 @@ void SwitcherData::saveScreenRegionSwitches(obs_data_t *obj)
|
|||||||
for (ScreenRegionSwitch &s : switcher->screenRegionSwitches) {
|
for (ScreenRegionSwitch &s : switcher->screenRegionSwitches) {
|
||||||
obs_data_t *array_obj = obs_data_create();
|
obs_data_t *array_obj = obs_data_create();
|
||||||
|
|
||||||
obs_source_t *source = obs_weak_source_get_source(s.scene);
|
s.save(array_obj);
|
||||||
obs_source_t *transition =
|
obs_data_array_push_back(screenRegionArray, array_obj);
|
||||||
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_release(array_obj);
|
||||||
}
|
}
|
||||||
obs_data_set_array(obj, "screenRegion", screenRegionArray);
|
obs_data_set_array(obj, "screenRegion", screenRegionArray);
|
||||||
@@ -200,19 +223,8 @@ void SwitcherData::loadScreenRegionSwitches(obs_data_t *obj)
|
|||||||
obs_data_t *array_obj =
|
obs_data_t *array_obj =
|
||||||
obs_data_array_item(screenRegionArray, i);
|
obs_data_array_item(screenRegionArray, i);
|
||||||
|
|
||||||
const char *scene =
|
switcher->screenRegionSwitches.emplace_back();
|
||||||
obs_data_get_string(array_obj, "screenRegionScene");
|
screenRegionSwitches.back().load(array_obj);
|
||||||
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_release(array_obj);
|
||||||
}
|
}
|
||||||
@@ -225,13 +237,17 @@ void AdvSceneSwitcher::setupRegionTab()
|
|||||||
QListWidgetItem *item;
|
QListWidgetItem *item;
|
||||||
item = new QListWidgetItem(ui->screenRegionSwitches);
|
item = new QListWidgetItem(ui->screenRegionSwitches);
|
||||||
ui->screenRegionSwitches->addItem(item);
|
ui->screenRegionSwitches->addItem(item);
|
||||||
ScreenRegionWidget *sw = new ScreenRegionWidget(&s);
|
ScreenRegionWidget *sw = new ScreenRegionWidget(this, &s);
|
||||||
item->setSizeHint(sw->minimumSizeHint());
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
ui->screenRegionSwitches->setItemWidget(item, sw);
|
ui->screenRegionSwitches->setItemWidget(item, sw);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switcher->screenRegionSwitches.size() == 0)
|
if (switcher->screenRegionSwitches.size() == 0) {
|
||||||
addPulse = PulseWidget(ui->screenRegionAdd, QColor(Qt::green));
|
addPulse = PulseWidget(ui->screenRegionAdd, QColor(Qt::green));
|
||||||
|
ui->regionHelp->setVisible(true);
|
||||||
|
} else {
|
||||||
|
ui->regionHelp->setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
// screen region cursor position
|
// screen region cursor position
|
||||||
QTimer *screenRegionTimer = new QTimer(this);
|
QTimer *screenRegionTimer = new QTimer(this);
|
||||||
@@ -240,19 +256,73 @@ void AdvSceneSwitcher::setupRegionTab()
|
|||||||
screenRegionTimer->start(1000);
|
screenRegionTimer->start(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScreenRegionWidget::ScreenRegionWidget(ScreenRegionSwitch *s)
|
void ScreenRegionSwitch::save(obs_data_t *obj)
|
||||||
: SwitchWidget(s, false)
|
|
||||||
{
|
{
|
||||||
|
SceneSwitcherEntry::save(obj);
|
||||||
|
|
||||||
|
obs_data_set_string(obj, "excludeScene",
|
||||||
|
GetWeakSourceName(excludeScene).c_str());
|
||||||
|
|
||||||
|
obs_data_set_int(obj, "minX", minX);
|
||||||
|
obs_data_set_int(obj, "minY", minY);
|
||||||
|
obs_data_set_int(obj, "maxX", maxX);
|
||||||
|
obs_data_set_int(obj, "maxY", maxY);
|
||||||
|
}
|
||||||
|
|
||||||
|
// To be removed in future version
|
||||||
|
bool loadOldRegion(obs_data_t *obj, ScreenRegionSwitch *s)
|
||||||
|
{
|
||||||
|
if (!s) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *scene = obs_data_get_string(obj, "screenRegionScene");
|
||||||
|
|
||||||
|
if (strcmp(scene, "") == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->scene = GetWeakSourceByName(scene);
|
||||||
|
|
||||||
|
const char *transition = obs_data_get_string(obj, "transition");
|
||||||
|
s->transition = GetWeakTransitionByName(transition);
|
||||||
|
|
||||||
|
s->minX = obs_data_get_int(obj, "minX");
|
||||||
|
s->minY = obs_data_get_int(obj, "minY");
|
||||||
|
s->maxX = obs_data_get_int(obj, "maxX");
|
||||||
|
s->maxY = obs_data_get_int(obj, "maxY");
|
||||||
|
|
||||||
|
s->usePreviousScene = strcmp(scene, previous_scene_name) == 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenRegionSwitch::load(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
if (loadOldRegion(obj, this)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneSwitcherEntry::load(obj);
|
||||||
|
|
||||||
|
const char *excludeSceneName = obs_data_get_string(obj, "excludeScene");
|
||||||
|
excludeScene = GetWeakSourceByName(excludeSceneName);
|
||||||
|
|
||||||
|
minX = obs_data_get_int(obj, "minX");
|
||||||
|
minY = obs_data_get_int(obj, "minY");
|
||||||
|
maxX = obs_data_get_int(obj, "maxX");
|
||||||
|
maxY = obs_data_get_int(obj, "maxY");
|
||||||
|
}
|
||||||
|
|
||||||
|
ScreenRegionWidget::ScreenRegionWidget(QWidget *parent, ScreenRegionSwitch *s)
|
||||||
|
: SwitchWidget(parent, s, true, true)
|
||||||
|
{
|
||||||
|
excludeScenes = new QComboBox();
|
||||||
minX = new QSpinBox();
|
minX = new QSpinBox();
|
||||||
minY = new QSpinBox();
|
minY = new QSpinBox();
|
||||||
maxX = new QSpinBox();
|
maxX = new QSpinBox();
|
||||||
maxY = 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: ");
|
minX->setPrefix("Min X: ");
|
||||||
minY->setPrefix("Min Y: ");
|
minY->setPrefix("Min Y: ");
|
||||||
maxX->setPrefix("Max X: ");
|
maxX->setPrefix("Max X: ");
|
||||||
@@ -268,6 +338,9 @@ ScreenRegionWidget::ScreenRegionWidget(ScreenRegionSwitch *s)
|
|||||||
maxX->setMaximum(1000000);
|
maxX->setMaximum(1000000);
|
||||||
maxY->setMaximum(1000000);
|
maxY->setMaximum(1000000);
|
||||||
|
|
||||||
|
QWidget::connect(excludeScenes,
|
||||||
|
SIGNAL(currentTextChanged(const QString &)), this,
|
||||||
|
SLOT(ExcludeSceneChanged(const QString &)));
|
||||||
QWidget::connect(minX, SIGNAL(valueChanged(int)), this,
|
QWidget::connect(minX, SIGNAL(valueChanged(int)), this,
|
||||||
SLOT(MinXChanged(int)));
|
SLOT(MinXChanged(int)));
|
||||||
QWidget::connect(minY, SIGNAL(valueChanged(int)), this,
|
QWidget::connect(minY, SIGNAL(valueChanged(int)), this,
|
||||||
@@ -277,29 +350,31 @@ ScreenRegionWidget::ScreenRegionWidget(ScreenRegionSwitch *s)
|
|||||||
QWidget::connect(maxY, SIGNAL(valueChanged(int)), this,
|
QWidget::connect(maxY, SIGNAL(valueChanged(int)), this,
|
||||||
SLOT(MaxYChanged(int)));
|
SLOT(MaxYChanged(int)));
|
||||||
|
|
||||||
|
AdvSceneSwitcher::populateSceneSelection(
|
||||||
|
excludeScenes, false, false, true,
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.screenRegionTab.excludeScenes.None"));
|
||||||
|
|
||||||
if (s) {
|
if (s) {
|
||||||
|
excludeScenes->setCurrentText(
|
||||||
|
GetWeakSourceName(s->excludeScene).c_str());
|
||||||
minX->setValue(s->minX);
|
minX->setValue(s->minX);
|
||||||
minY->setValue(s->minY);
|
minY->setValue(s->minY);
|
||||||
maxX->setValue(s->maxX);
|
maxX->setValue(s->maxX);
|
||||||
maxY->setValue(s->maxY);
|
maxY->setValue(s->maxY);
|
||||||
}
|
}
|
||||||
|
|
||||||
setStyleSheet("* { background-color: transparent; }");
|
|
||||||
|
|
||||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
mainLayout->addWidget(cursorLabel);
|
{"{{minX}}", minX},
|
||||||
mainLayout->addWidget(minX);
|
{"{{minY}}", minY},
|
||||||
mainLayout->addWidget(minY);
|
{"{{maxX}}", maxX},
|
||||||
mainLayout->addWidget(xLabel);
|
{"{{maxY}}", maxY},
|
||||||
mainLayout->addWidget(maxX);
|
{"{{scenes}}", scenes},
|
||||||
mainLayout->addWidget(maxY);
|
{"{{transitions}}", transitions},
|
||||||
mainLayout->addWidget(switchLabel);
|
{"{{excludeScenes}}", excludeScenes}};
|
||||||
mainLayout->addWidget(scenes);
|
placeWidgets(obs_module_text("AdvSceneSwitcher.screenRegionTab.entry"),
|
||||||
mainLayout->addWidget(usingLabel);
|
mainLayout, widgetPlaceholders);
|
||||||
mainLayout->addWidget(transitions);
|
|
||||||
mainLayout->addStretch();
|
|
||||||
|
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
|
||||||
switchData = s;
|
switchData = s;
|
||||||
@@ -338,10 +413,22 @@ void ScreenRegionWidget::hideFrame()
|
|||||||
helperFrame.hide();
|
helperFrame.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScreenRegionWidget::ExcludeSceneChanged(const QString &text)
|
||||||
|
{
|
||||||
|
if (loading || !switchData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->excludeScene = GetWeakSourceByQString(text);
|
||||||
|
}
|
||||||
|
|
||||||
void ScreenRegionWidget::MinXChanged(int pos)
|
void ScreenRegionWidget::MinXChanged(int pos)
|
||||||
{
|
{
|
||||||
if (loading || !switchData)
|
if (loading || !switchData) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switchData->minX = pos;
|
switchData->minX = pos;
|
||||||
|
|
||||||
@@ -350,8 +437,10 @@ void ScreenRegionWidget::MinXChanged(int pos)
|
|||||||
|
|
||||||
void ScreenRegionWidget::MinYChanged(int pos)
|
void ScreenRegionWidget::MinYChanged(int pos)
|
||||||
{
|
{
|
||||||
if (loading || !switchData)
|
if (loading || !switchData) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switchData->minY = pos;
|
switchData->minY = pos;
|
||||||
|
|
||||||
@@ -360,8 +449,10 @@ void ScreenRegionWidget::MinYChanged(int pos)
|
|||||||
|
|
||||||
void ScreenRegionWidget::MaxXChanged(int pos)
|
void ScreenRegionWidget::MaxXChanged(int pos)
|
||||||
{
|
{
|
||||||
if (loading || !switchData)
|
if (loading || !switchData) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switchData->maxX = pos;
|
switchData->maxX = pos;
|
||||||
|
|
||||||
@@ -370,8 +461,10 @@ void ScreenRegionWidget::MaxXChanged(int pos)
|
|||||||
|
|
||||||
void ScreenRegionWidget::MaxYChanged(int pos)
|
void ScreenRegionWidget::MaxYChanged(int pos)
|
||||||
{
|
{
|
||||||
if (loading || !switchData)
|
if (loading || !switchData) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switchData->maxY = pos;
|
switchData->maxY = pos;
|
||||||
|
|
||||||
@@ -387,8 +480,9 @@ void ScreenRegionWidget::drawFrame()
|
|||||||
Qt::WindowStaysOnTopHint);
|
Qt::WindowStaysOnTopHint);
|
||||||
helperFrame.setAttribute(Qt::WA_TranslucentBackground, true);
|
helperFrame.setAttribute(Qt::WA_TranslucentBackground, true);
|
||||||
|
|
||||||
if (switchData)
|
if (switchData) {
|
||||||
helperFrame.setGeometry(switchData->minX, switchData->minY,
|
helperFrame.setGeometry(switchData->minX, switchData->minY,
|
||||||
switchData->maxX - switchData->minX,
|
switchData->maxX - switchData->minX,
|
||||||
switchData->maxY - switchData->minY);
|
switchData->maxY - switchData->minY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,39 +1,47 @@
|
|||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
#include <QMessageBox>
|
|
||||||
|
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
|
bool SceneSequenceSwitch::pause = false;
|
||||||
static QMetaObject::Connection addPulse;
|
static QMetaObject::Connection addPulse;
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_sceneSequenceAdd_clicked()
|
void AdvSceneSwitcher::on_sceneSequenceAdd_clicked()
|
||||||
{
|
{
|
||||||
ui->sceneSequenceAdd->disconnect(addPulse);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switcher->sceneSequenceSwitches.emplace_back();
|
switcher->sceneSequenceSwitches.emplace_back();
|
||||||
|
|
||||||
QListWidgetItem *item;
|
listAddClicked(ui->sceneSequenceSwitches,
|
||||||
item = new QListWidgetItem(ui->sceneSequenceSwitches);
|
new SequenceWidget(
|
||||||
ui->sceneSequenceSwitches->addItem(item);
|
this, &switcher->sceneSequenceSwitches.back()),
|
||||||
SequenceWidget *sw =
|
ui->sceneSequenceAdd, &addPulse);
|
||||||
new SequenceWidget(&switcher->sceneSequenceSwitches.back());
|
|
||||||
item->setSizeHint(sw->minimumSizeHint());
|
ui->sequenceHelp->setVisible(false);
|
||||||
ui->sceneSequenceSwitches->setItemWidget(item, sw);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_sceneSequenceRemove_clicked()
|
void AdvSceneSwitcher::on_sceneSequenceRemove_clicked()
|
||||||
{
|
{
|
||||||
QListWidgetItem *item = ui->sceneSequenceSwitches->currentItem();
|
QListWidgetItem *item = ui->sceneSequenceSwitches->currentItem();
|
||||||
if (!item)
|
if (!item) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
// Might be in waiting state of sequence
|
||||||
|
// causing invalid access after wakeup
|
||||||
|
// thus we need to stop the main thread before delete
|
||||||
|
bool wasRunning = !switcher->stop;
|
||||||
|
switcher->Stop();
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
int idx = ui->sceneSequenceSwitches->currentRow();
|
int idx = ui->sceneSequenceSwitches->currentRow();
|
||||||
auto &switches = switcher->sceneSequenceSwitches;
|
auto &switches = switcher->sceneSequenceSwitches;
|
||||||
switches.erase(switches.begin() + idx);
|
switches.erase(switches.begin() + idx);
|
||||||
|
|
||||||
|
if (wasRunning) {
|
||||||
|
switcher->Start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delete item;
|
delete item;
|
||||||
@@ -42,8 +50,9 @@ void AdvSceneSwitcher::on_sceneSequenceRemove_clicked()
|
|||||||
void AdvSceneSwitcher::on_sceneSequenceUp_clicked()
|
void AdvSceneSwitcher::on_sceneSequenceUp_clicked()
|
||||||
{
|
{
|
||||||
int index = ui->sceneSequenceSwitches->currentRow();
|
int index = ui->sceneSequenceSwitches->currentRow();
|
||||||
if (!listMoveUp(ui->sceneSequenceSwitches))
|
if (!listMoveUp(ui->sceneSequenceSwitches)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
SequenceWidget *s1 =
|
SequenceWidget *s1 =
|
||||||
(SequenceWidget *)ui->sceneSequenceSwitches->itemWidget(
|
(SequenceWidget *)ui->sceneSequenceSwitches->itemWidget(
|
||||||
@@ -63,8 +72,9 @@ void AdvSceneSwitcher::on_sceneSequenceDown_clicked()
|
|||||||
{
|
{
|
||||||
int index = ui->sceneSequenceSwitches->currentRow();
|
int index = ui->sceneSequenceSwitches->currentRow();
|
||||||
|
|
||||||
if (!listMoveDown(ui->sceneSequenceSwitches))
|
if (!listMoveDown(ui->sceneSequenceSwitches)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
SequenceWidget *s1 =
|
SequenceWidget *s1 =
|
||||||
(SequenceWidget *)ui->sceneSequenceSwitches->itemWidget(
|
(SequenceWidget *)ui->sceneSequenceSwitches->itemWidget(
|
||||||
@@ -83,13 +93,19 @@ void AdvSceneSwitcher::on_sceneSequenceDown_clicked()
|
|||||||
void AdvSceneSwitcher::on_sceneSequenceSave_clicked()
|
void AdvSceneSwitcher::on_sceneSequenceSave_clicked()
|
||||||
{
|
{
|
||||||
QString directory = QFileDialog::getSaveFileName(
|
QString directory = QFileDialog::getSaveFileName(
|
||||||
this, tr("Save Scene Sequence to file ..."),
|
this,
|
||||||
QDir::currentPath(), tr("Text files (*.txt)"));
|
tr(obs_module_text(
|
||||||
if (directory.isEmpty())
|
"AdvSceneSwitcher.sceneSequenceTab.saveTitle")),
|
||||||
|
QDir::currentPath(),
|
||||||
|
tr(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.sceneSequenceTab.fileType")));
|
||||||
|
if (directory.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
QFile file(directory);
|
QFile file(directory);
|
||||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
obs_data_t *obj = obs_data_create();
|
obs_data_t *obj = obs_data_create();
|
||||||
switcher->saveSceneSequenceSwitches(obj);
|
switcher->saveSceneSequenceSwitches(obj);
|
||||||
@@ -99,75 +115,111 @@ void AdvSceneSwitcher::on_sceneSequenceSave_clicked()
|
|||||||
|
|
||||||
void AdvSceneSwitcher::on_sceneSequenceLoad_clicked()
|
void AdvSceneSwitcher::on_sceneSequenceLoad_clicked()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
|
|
||||||
QString directory = QFileDialog::getOpenFileName(
|
QString directory = QFileDialog::getOpenFileName(
|
||||||
this, tr("Select a file to read Scene Sequence from ..."),
|
this,
|
||||||
QDir::currentPath(), tr("Text files (*.txt)"));
|
tr(obs_module_text(
|
||||||
if (directory.isEmpty())
|
"AdvSceneSwitcher.sceneSequenceTab.loadTitle")),
|
||||||
|
QDir::currentPath(),
|
||||||
|
tr(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.sceneSequenceTab.fileType")));
|
||||||
|
if (directory.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QFile file(directory);
|
QFile file(directory);
|
||||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
obs_data_t *obj = obs_data_create_from_json_file(
|
obs_data_t *obj = obs_data_create_from_json_file(
|
||||||
file.fileName().toUtf8().constData());
|
file.fileName().toUtf8().constData());
|
||||||
|
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
QMessageBox Msgbox;
|
DisplayMessage(obs_module_text(
|
||||||
Msgbox.setText(
|
"AdvSceneSwitcher.sceneSequenceTab.loadFail"));
|
||||||
"Advanced Scene Switcher failed to import settings!");
|
|
||||||
Msgbox.exec();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Might be in waiting state of sequence
|
||||||
|
// causing invalid access after wakeup
|
||||||
|
// thus we need to stop the main thread before delete
|
||||||
|
bool wasRunning = !switcher->stop;
|
||||||
|
switcher->Stop();
|
||||||
|
|
||||||
switcher->loadSceneSequenceSwitches(obj);
|
switcher->loadSceneSequenceSwitches(obj);
|
||||||
|
|
||||||
|
if (wasRunning) {
|
||||||
|
switcher->Start();
|
||||||
|
}
|
||||||
|
|
||||||
obs_data_release(obj);
|
obs_data_release(obj);
|
||||||
|
|
||||||
QMessageBox Msgbox;
|
DisplayMessage(obs_module_text(
|
||||||
Msgbox.setText(
|
"AdvSceneSwitcher.sceneSequenceTab.loadSuccess"));
|
||||||
"Advanced Scene Switcher settings imported successfully!");
|
|
||||||
Msgbox.exec();
|
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitcherData::checkSceneSequence(bool &match, OBSWeakSource &scene,
|
bool matchInterruptible(SwitcherData *switcher, SceneSequenceSwitch &s)
|
||||||
OBSWeakSource &transition,
|
|
||||||
std::unique_lock<std::mutex> &lock)
|
|
||||||
{
|
{
|
||||||
|
bool durationReached = s.matchCount * (switcher->interval / 1000.0) >=
|
||||||
|
s.delay;
|
||||||
|
|
||||||
|
s.matchCount++;
|
||||||
|
|
||||||
|
if (durationReached) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool matchUninterruptible(SwitcherData *switcher, SceneSequenceSwitch &s,
|
||||||
|
obs_source_t *currentSource, int &linger)
|
||||||
|
{
|
||||||
|
// scene was already active for the previous cycle so remove this time
|
||||||
|
int dur = s.delay * 1000 - switcher->interval;
|
||||||
|
if (dur > 0) {
|
||||||
|
switcher->waitScene = currentSource;
|
||||||
|
linger = dur;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitcherData::checkSceneSequence(bool &match, OBSWeakSource &scene,
|
||||||
|
OBSWeakSource &transition, int &linger)
|
||||||
|
{
|
||||||
|
if (SceneSequenceSwitch::pause) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
obs_source_t *currentSource = obs_frontend_get_current_scene();
|
obs_source_t *currentSource = obs_frontend_get_current_scene();
|
||||||
obs_weak_source_t *ws = obs_source_get_weak_source(currentSource);
|
obs_weak_source_t *ws = obs_source_get_weak_source(currentSource);
|
||||||
|
|
||||||
for (SceneSequenceSwitch &s : sceneSequenceSwitches) {
|
for (SceneSequenceSwitch &s : sceneSequenceSwitches) {
|
||||||
if (!s.initialized())
|
if (!s.initialized()) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (s.startScene == ws) {
|
if (s.startScene == ws) {
|
||||||
int dur = s.delay * 1000 - interval;
|
if (!match) {
|
||||||
if (dur > 0) {
|
if (s.interruptible) {
|
||||||
waitScene = currentSource;
|
match = matchInterruptible(switcher, s);
|
||||||
|
} else {
|
||||||
|
match = matchUninterruptible(
|
||||||
|
switcher, s, currentSource,
|
||||||
|
linger);
|
||||||
|
}
|
||||||
|
|
||||||
if (verbose)
|
if (match) {
|
||||||
s.logSleep(dur);
|
scene = s.getScene();
|
||||||
|
transition = s.transition;
|
||||||
cv.wait_for(lock,
|
if (switcher->verbose) {
|
||||||
std::chrono::milliseconds(dur));
|
s.logMatch();
|
||||||
waitScene = nullptr;
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
obs_source_t *currentSource2 =
|
} else {
|
||||||
obs_frontend_get_current_scene();
|
s.matchCount = 0;
|
||||||
|
|
||||||
// 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_source_release(currentSource);
|
||||||
@@ -180,33 +232,9 @@ void SwitcherData::saveSceneSequenceSwitches(obs_data_t *obj)
|
|||||||
for (SceneSequenceSwitch &s : switcher->sceneSequenceSwitches) {
|
for (SceneSequenceSwitch &s : switcher->sceneSequenceSwitches) {
|
||||||
obs_data_t *array_obj = obs_data_create();
|
obs_data_t *array_obj = obs_data_create();
|
||||||
|
|
||||||
obs_source_t *source1 =
|
s.save(array_obj);
|
||||||
obs_weak_source_get_source(s.startScene);
|
obs_data_array_push_back(sceneSequenceArray, array_obj);
|
||||||
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_release(array_obj);
|
||||||
}
|
}
|
||||||
obs_data_set_array(obj, "sceneRoundTrip", sceneSequenceArray);
|
obs_data_set_array(obj, "sceneRoundTrip", sceneSequenceArray);
|
||||||
@@ -225,25 +253,8 @@ void SwitcherData::loadSceneSequenceSwitches(obs_data_t *obj)
|
|||||||
obs_data_t *array_obj =
|
obs_data_t *array_obj =
|
||||||
obs_data_array_item(sceneSequenceArray, i);
|
obs_data_array_item(sceneSequenceArray, i);
|
||||||
|
|
||||||
const char *scene1 =
|
switcher->sceneSequenceSwitches.emplace_back();
|
||||||
obs_data_get_string(array_obj, "sceneRoundTripScene1");
|
sceneSequenceSwitches.back().load(array_obj);
|
||||||
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_release(array_obj);
|
||||||
}
|
}
|
||||||
@@ -256,13 +267,17 @@ void AdvSceneSwitcher::setupSequenceTab()
|
|||||||
QListWidgetItem *item;
|
QListWidgetItem *item;
|
||||||
item = new QListWidgetItem(ui->sceneSequenceSwitches);
|
item = new QListWidgetItem(ui->sceneSequenceSwitches);
|
||||||
ui->sceneSequenceSwitches->addItem(item);
|
ui->sceneSequenceSwitches->addItem(item);
|
||||||
SequenceWidget *sw = new SequenceWidget(&s);
|
SequenceWidget *sw = new SequenceWidget(this, &s);
|
||||||
item->setSizeHint(sw->minimumSizeHint());
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
ui->sceneSequenceSwitches->setItemWidget(item, sw);
|
ui->sceneSequenceSwitches->setItemWidget(item, sw);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switcher->sceneSequenceSwitches.size() == 0)
|
if (switcher->sceneSequenceSwitches.size() == 0) {
|
||||||
addPulse = PulseWidget(ui->sceneSequenceAdd, QColor(Qt::green));
|
addPulse = PulseWidget(ui->sceneSequenceAdd, QColor(Qt::green));
|
||||||
|
ui->sequenceHelp->setVisible(true);
|
||||||
|
} else {
|
||||||
|
ui->sequenceHelp->setVisible(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SceneSequenceSwitch::initialized()
|
bool SceneSequenceSwitch::initialized()
|
||||||
@@ -276,28 +291,92 @@ bool SceneSequenceSwitch::valid()
|
|||||||
(SceneSwitcherEntry::valid() && WeakSourceValid(startScene));
|
(SceneSwitcherEntry::valid() && WeakSourceValid(startScene));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSequenceSwitch::logSleep(int dur)
|
void SceneSequenceSwitch::save(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
blog(LOG_INFO, "sequence sleep %d", dur);
|
SceneSwitcherEntry::save(obj);
|
||||||
|
|
||||||
|
obs_data_set_string(obj, "startScene",
|
||||||
|
GetWeakSourceName(startScene).c_str());
|
||||||
|
|
||||||
|
obs_data_set_double(obj, "delay", delay);
|
||||||
|
|
||||||
|
obs_data_set_int(obj, "delayMultiplier", delayMultiplier);
|
||||||
|
|
||||||
|
obs_data_set_bool(obj, "interruptible", interruptible);
|
||||||
|
}
|
||||||
|
|
||||||
|
// To be removed in future version
|
||||||
|
bool loadOldScequence(obs_data_t *obj, SceneSequenceSwitch *s)
|
||||||
|
{
|
||||||
|
if (!s) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *scene1 = obs_data_get_string(obj, "sceneRoundTripScene1");
|
||||||
|
|
||||||
|
if (strcmp(scene1, "") == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->startScene = GetWeakSourceByName(scene1);
|
||||||
|
|
||||||
|
const char *scene2 = obs_data_get_string(obj, "sceneRoundTripScene2");
|
||||||
|
s->scene = GetWeakSourceByName(scene2);
|
||||||
|
|
||||||
|
const char *transition = obs_data_get_string(obj, "transition");
|
||||||
|
s->transition = GetWeakTransitionByName(transition);
|
||||||
|
|
||||||
|
s->delay = obs_data_get_double(obj, "delay");
|
||||||
|
|
||||||
|
int delayMultiplier = obs_data_get_int(obj, "delayMultiplier");
|
||||||
|
if (delayMultiplier == 0 ||
|
||||||
|
(delayMultiplier != 1 && delayMultiplier % 60 != 0))
|
||||||
|
delayMultiplier = 1;
|
||||||
|
s->delayMultiplier = delayMultiplier;
|
||||||
|
|
||||||
|
s->interruptible = obs_data_get_bool(obj, "interruptible");
|
||||||
|
|
||||||
|
s->usePreviousScene = strcmp(scene2, previous_scene_name) == 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneSequenceSwitch::load(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
if (loadOldScequence(obj, this)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneSwitcherEntry::load(obj);
|
||||||
|
|
||||||
|
const char *scene = obs_data_get_string(obj, "startScene");
|
||||||
|
startScene = GetWeakSourceByName(scene);
|
||||||
|
|
||||||
|
delay = obs_data_get_double(obj, "delay");
|
||||||
|
|
||||||
|
delayMultiplier = obs_data_get_int(obj, "delayMultiplier");
|
||||||
|
if (delayMultiplier == 0 ||
|
||||||
|
(delayMultiplier != 1 && delayMultiplier % 60 != 0))
|
||||||
|
delayMultiplier = 1;
|
||||||
|
|
||||||
|
interruptible = obs_data_get_bool(obj, "interruptible");
|
||||||
}
|
}
|
||||||
|
|
||||||
void populateDelayUnits(QComboBox *list)
|
void populateDelayUnits(QComboBox *list)
|
||||||
{
|
{
|
||||||
list->addItem("seconds");
|
list->addItem(obs_module_text("AdvSceneSwitcher.unit.secends"));
|
||||||
list->addItem("minutes");
|
list->addItem(obs_module_text("AdvSceneSwitcher.unit.minutes"));
|
||||||
list->addItem("hours");
|
list->addItem(obs_module_text("AdvSceneSwitcher.unit.hours"));
|
||||||
}
|
}
|
||||||
|
|
||||||
SequenceWidget::SequenceWidget(SceneSequenceSwitch *s) : SwitchWidget(s)
|
SequenceWidget::SequenceWidget(QWidget *parent, SceneSequenceSwitch *s)
|
||||||
|
: SwitchWidget(parent, s, true, true)
|
||||||
{
|
{
|
||||||
delay = new QDoubleSpinBox();
|
delay = new QDoubleSpinBox();
|
||||||
delayUnits = new QComboBox();
|
delayUnits = new QComboBox();
|
||||||
startScenes = new QComboBox();
|
startScenes = new QComboBox();
|
||||||
|
interruptible = new QCheckBox(obs_module_text(
|
||||||
whenLabel = new QLabel("When");
|
"AdvSceneSwitcher.sceneSequenceTab.interruptible"));
|
||||||
switchLabel = new QLabel("is active switch to");
|
|
||||||
afterLabel = new QLabel("after");
|
|
||||||
usingLabel = new QLabel("using");
|
|
||||||
|
|
||||||
QWidget::connect(delay, SIGNAL(valueChanged(double)), this,
|
QWidget::connect(delay, SIGNAL(valueChanged(double)), this,
|
||||||
SLOT(DelayChanged(double)));
|
SLOT(DelayChanged(double)));
|
||||||
@@ -306,10 +385,14 @@ SequenceWidget::SequenceWidget(SceneSequenceSwitch *s) : SwitchWidget(s)
|
|||||||
QWidget::connect(startScenes,
|
QWidget::connect(startScenes,
|
||||||
SIGNAL(currentTextChanged(const QString &)), this,
|
SIGNAL(currentTextChanged(const QString &)), this,
|
||||||
SLOT(StartSceneChanged(const QString &)));
|
SLOT(StartSceneChanged(const QString &)));
|
||||||
|
QWidget::connect(interruptible, SIGNAL(stateChanged(int)), this,
|
||||||
|
SLOT(InterruptibleChanged(int)));
|
||||||
|
|
||||||
delay->setMaximum(99999.000000);
|
delay->setMaximum(99999.000000);
|
||||||
AdvSceneSwitcher::populateSceneSelection(startScenes, false);
|
AdvSceneSwitcher::populateSceneSelection(startScenes, false);
|
||||||
populateDelayUnits(delayUnits);
|
populateDelayUnits(delayUnits);
|
||||||
|
interruptible->setToolTip(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.sceneSequenceTab.interruptibleHint"));
|
||||||
|
|
||||||
if (s) {
|
if (s) {
|
||||||
switch (s->delayMultiplier) {
|
switch (s->delayMultiplier) {
|
||||||
@@ -327,23 +410,19 @@ SequenceWidget::SequenceWidget(SceneSequenceSwitch *s) : SwitchWidget(s)
|
|||||||
}
|
}
|
||||||
startScenes->setCurrentText(
|
startScenes->setCurrentText(
|
||||||
GetWeakSourceName(s->startScene).c_str());
|
GetWeakSourceName(s->startScene).c_str());
|
||||||
|
interruptible->setChecked(s->interruptible);
|
||||||
}
|
}
|
||||||
|
|
||||||
setStyleSheet("* { background-color: transparent; }");
|
|
||||||
|
|
||||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
mainLayout->addWidget(whenLabel);
|
{"{{startScenes}}", startScenes},
|
||||||
mainLayout->addWidget(startScenes);
|
{"{{scenes}}", scenes},
|
||||||
mainLayout->addWidget(switchLabel);
|
{"{{delay}}", delay},
|
||||||
mainLayout->addWidget(scenes);
|
{"{{delayUnits}}", delayUnits},
|
||||||
mainLayout->addWidget(afterLabel);
|
{"{{transitions}}", transitions},
|
||||||
mainLayout->addWidget(delay);
|
{"{{interruptible}}", interruptible}};
|
||||||
mainLayout->addWidget(delayUnits);
|
placeWidgets(obs_module_text("AdvSceneSwitcher.sceneSequenceTab.entry"),
|
||||||
mainLayout->addWidget(usingLabel);
|
mainLayout, widgetPlaceholders);
|
||||||
mainLayout->addWidget(transitions);
|
|
||||||
mainLayout->addStretch();
|
|
||||||
|
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
|
||||||
switchData = s;
|
switchData = s;
|
||||||
@@ -374,22 +453,26 @@ void SequenceWidget::swapSwitchData(SequenceWidget *s1, SequenceWidget *s2)
|
|||||||
|
|
||||||
void SequenceWidget::UpdateDelay()
|
void SequenceWidget::UpdateDelay()
|
||||||
{
|
{
|
||||||
if (switchData)
|
if (switchData) {
|
||||||
delay->setValue(switchData->delay /
|
delay->setValue(switchData->delay /
|
||||||
switchData->delayMultiplier);
|
switchData->delayMultiplier);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SequenceWidget::DelayChanged(double delay)
|
void SequenceWidget::DelayChanged(double delay)
|
||||||
{
|
{
|
||||||
if (loading || !switchData)
|
if (loading || !switchData) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switchData->delay = delay * switchData->delayMultiplier;
|
switchData->delay = delay * switchData->delayMultiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SequenceWidget::DelayUnitsChanged(int idx)
|
void SequenceWidget::DelayUnitsChanged(int idx)
|
||||||
{
|
{
|
||||||
if (loading || !switchData)
|
if (loading || !switchData) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
delay_units unit = (delay_units)idx;
|
delay_units unit = (delay_units)idx;
|
||||||
|
|
||||||
@@ -412,8 +495,20 @@ void SequenceWidget::DelayUnitsChanged(int idx)
|
|||||||
|
|
||||||
void SequenceWidget::StartSceneChanged(const QString &text)
|
void SequenceWidget::StartSceneChanged(const QString &text)
|
||||||
{
|
{
|
||||||
if (loading || !switchData)
|
if (loading || !switchData) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switchData->startScene = GetWeakSourceByQString(text);
|
switchData->startScene = GetWeakSourceByQString(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SequenceWidget::InterruptibleChanged(int state)
|
||||||
|
{
|
||||||
|
if (loading || !switchData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->interruptible = state;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,29 +1,28 @@
|
|||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
|
bool TimeSwitch::pause = false;
|
||||||
static QMetaObject::Connection addPulse;
|
static QMetaObject::Connection addPulse;
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_timeAdd_clicked()
|
void AdvSceneSwitcher::on_timeAdd_clicked()
|
||||||
{
|
{
|
||||||
ui->timeAdd->disconnect(addPulse);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switcher->timeSwitches.emplace_back();
|
switcher->timeSwitches.emplace_back();
|
||||||
|
|
||||||
QListWidgetItem *item;
|
listAddClicked(ui->timeSwitches,
|
||||||
item = new QListWidgetItem(ui->timeSwitches);
|
new TimeSwitchWidget(this,
|
||||||
ui->timeSwitches->addItem(item);
|
&switcher->timeSwitches.back()),
|
||||||
TimeSwitchWidget *sw =
|
ui->timeAdd, &addPulse);
|
||||||
new TimeSwitchWidget(&switcher->timeSwitches.back());
|
|
||||||
item->setSizeHint(sw->minimumSizeHint());
|
ui->timeHelp->setVisible(false);
|
||||||
ui->timeSwitches->setItemWidget(item, sw);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_timeRemove_clicked()
|
void AdvSceneSwitcher::on_timeRemove_clicked()
|
||||||
{
|
{
|
||||||
QListWidgetItem *item = ui->timeSwitches->currentItem();
|
QListWidgetItem *item = ui->timeSwitches->currentItem();
|
||||||
if (!item)
|
if (!item) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
@@ -38,8 +37,9 @@ void AdvSceneSwitcher::on_timeRemove_clicked()
|
|||||||
void AdvSceneSwitcher::on_timeUp_clicked()
|
void AdvSceneSwitcher::on_timeUp_clicked()
|
||||||
{
|
{
|
||||||
int index = ui->timeSwitches->currentRow();
|
int index = ui->timeSwitches->currentRow();
|
||||||
if (!listMoveUp(ui->timeSwitches))
|
if (!listMoveUp(ui->timeSwitches)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
TimeSwitchWidget *s1 = (TimeSwitchWidget *)ui->timeSwitches->itemWidget(
|
TimeSwitchWidget *s1 = (TimeSwitchWidget *)ui->timeSwitches->itemWidget(
|
||||||
ui->timeSwitches->item(index));
|
ui->timeSwitches->item(index));
|
||||||
@@ -57,8 +57,9 @@ void AdvSceneSwitcher::on_timeDown_clicked()
|
|||||||
{
|
{
|
||||||
int index = ui->timeSwitches->currentRow();
|
int index = ui->timeSwitches->currentRow();
|
||||||
|
|
||||||
if (!listMoveDown(ui->timeSwitches))
|
if (!listMoveDown(ui->timeSwitches)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
TimeSwitchWidget *s1 = (TimeSwitchWidget *)ui->timeSwitches->itemWidget(
|
TimeSwitchWidget *s1 = (TimeSwitchWidget *)ui->timeSwitches->itemWidget(
|
||||||
ui->timeSwitches->item(index));
|
ui->timeSwitches->item(index));
|
||||||
@@ -74,11 +75,15 @@ void AdvSceneSwitcher::on_timeDown_clicked()
|
|||||||
|
|
||||||
bool timesAreInInterval(QTime &time1, QTime &time2, int &interval)
|
bool timesAreInInterval(QTime &time1, QTime &time2, int &interval)
|
||||||
{
|
{
|
||||||
|
if (time1.isNull() || time2.isNull()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
QTime validSwitchTimeWindow = time1.addMSecs(interval);
|
QTime validSwitchTimeWindow = time1.addMSecs(interval);
|
||||||
|
|
||||||
ret = time1 <= time2 && time2 <= validSwitchTimeWindow;
|
ret = time1 <= time2 && time2 <= validSwitchTimeWindow;
|
||||||
// check for overflow
|
// Check for overflow
|
||||||
if (!ret && validSwitchTimeWindow.msecsSinceStartOfDay() < interval) {
|
if (!ret && validSwitchTimeWindow.msecsSinceStartOfDay() < interval) {
|
||||||
ret = time2 >= time1 || time2 <= validSwitchTimeWindow;
|
ret = time2 >= time1 || time2 <= validSwitchTimeWindow;
|
||||||
}
|
}
|
||||||
@@ -87,8 +92,9 @@ bool timesAreInInterval(QTime &time1, QTime &time2, int &interval)
|
|||||||
|
|
||||||
bool checkLiveTime(TimeSwitch &s, QDateTime &start, int &interval)
|
bool checkLiveTime(TimeSwitch &s, QDateTime &start, int &interval)
|
||||||
{
|
{
|
||||||
if (start.isNull())
|
if (start.isNull()) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
QDateTime now = QDateTime::currentDateTime();
|
QDateTime now = QDateTime::currentDateTime();
|
||||||
QTime timePassed = QTime(0, 0).addMSecs(start.msecsTo(now));
|
QTime timePassed = QTime(0, 0).addMSecs(start.msecsTo(now));
|
||||||
@@ -110,25 +116,29 @@ bool checkRegularTime(TimeSwitch &s, int &interval)
|
|||||||
void SwitcherData::checkTimeSwitch(bool &match, OBSWeakSource &scene,
|
void SwitcherData::checkTimeSwitch(bool &match, OBSWeakSource &scene,
|
||||||
OBSWeakSource &transition)
|
OBSWeakSource &transition)
|
||||||
{
|
{
|
||||||
if (timeSwitches.size() == 0)
|
if (TimeSwitch::pause) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (TimeSwitch &s : timeSwitches) {
|
for (TimeSwitch &s : timeSwitches) {
|
||||||
if (!s.initialized())
|
if (!s.initialized()) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (s.trigger == LIVE)
|
if (s.trigger == LIVE) {
|
||||||
match = checkLiveTime(s, liveTime, interval);
|
match = checkLiveTime(s, liveTime, interval);
|
||||||
else
|
} else {
|
||||||
match = checkRegularTime(s, interval);
|
match = checkRegularTime(s, interval);
|
||||||
|
}
|
||||||
|
|
||||||
if (match) {
|
if (match) {
|
||||||
scene = (s.usePreviousScene) ? previousScene : s.scene;
|
scene = s.getScene();
|
||||||
transition = s.transition;
|
transition = s.transition;
|
||||||
match = true;
|
match = true;
|
||||||
|
|
||||||
if (verbose)
|
if (verbose) {
|
||||||
s.logMatch();
|
s.logMatch();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,28 +150,8 @@ void SwitcherData::saveTimeSwitches(obs_data_t *obj)
|
|||||||
for (TimeSwitch &s : switcher->timeSwitches) {
|
for (TimeSwitch &s : switcher->timeSwitches) {
|
||||||
obs_data_t *array_obj = obs_data_create();
|
obs_data_t *array_obj = obs_data_create();
|
||||||
|
|
||||||
obs_source_t *sceneSource = obs_weak_source_get_source(s.scene);
|
s.save(array_obj);
|
||||||
obs_source_t *transition =
|
obs_data_array_push_back(timeArray, array_obj);
|
||||||
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_release(array_obj);
|
||||||
}
|
}
|
||||||
@@ -179,18 +169,8 @@ void SwitcherData::loadTimeSwitches(obs_data_t *obj)
|
|||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
obs_data_t *array_obj = obs_data_array_item(timeArray, i);
|
obs_data_t *array_obj = obs_data_array_item(timeArray, i);
|
||||||
|
|
||||||
const char *scene = obs_data_get_string(array_obj, "scene");
|
switcher->timeSwitches.emplace_back();
|
||||||
const char *transition =
|
timeSwitches.back().load(array_obj);
|
||||||
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_release(array_obj);
|
||||||
}
|
}
|
||||||
@@ -203,42 +183,87 @@ void AdvSceneSwitcher::setupTimeTab()
|
|||||||
QListWidgetItem *item;
|
QListWidgetItem *item;
|
||||||
item = new QListWidgetItem(ui->timeSwitches);
|
item = new QListWidgetItem(ui->timeSwitches);
|
||||||
ui->timeSwitches->addItem(item);
|
ui->timeSwitches->addItem(item);
|
||||||
TimeSwitchWidget *sw = new TimeSwitchWidget(&s);
|
TimeSwitchWidget *sw = new TimeSwitchWidget(this, &s);
|
||||||
item->setSizeHint(sw->minimumSizeHint());
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
ui->timeSwitches->setItemWidget(item, sw);
|
ui->timeSwitches->setItemWidget(item, sw);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switcher->timeSwitches.size() == 0)
|
if (switcher->timeSwitches.size() == 0) {
|
||||||
addPulse = PulseWidget(ui->timeAdd, QColor(Qt::green));
|
addPulse = PulseWidget(ui->timeAdd, QColor(Qt::green));
|
||||||
|
ui->timeHelp->setVisible(true);
|
||||||
|
} else {
|
||||||
|
ui->timeHelp->setVisible(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void populateTriggers(QComboBox *list)
|
void TimeSwitch::save(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
list->addItem("On any day");
|
SceneSwitcherEntry::save(obj);
|
||||||
list->addItem("Mondays");
|
|
||||||
list->addItem("Tuesdays");
|
obs_data_set_int(obj, "trigger", trigger);
|
||||||
list->addItem("Wednesdays");
|
obs_data_set_string(obj, "time", time.toString().toStdString().c_str());
|
||||||
list->addItem("Thursdays");
|
}
|
||||||
list->addItem("Fridays");
|
|
||||||
list->addItem("Saturdays");
|
// To be removed in future version
|
||||||
list->addItem("Sundays");
|
bool loadOldTime(obs_data_t *obj, TimeSwitch *s)
|
||||||
list->addItem("Atfer streaming/recording start");
|
{
|
||||||
|
if (!s) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *scene = obs_data_get_string(obj, "scene");
|
||||||
|
|
||||||
|
if (strcmp(scene, "") == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->scene = GetWeakSourceByName(scene);
|
||||||
|
|
||||||
|
const char *transition = obs_data_get_string(obj, "transition");
|
||||||
|
s->transition = GetWeakTransitionByName(transition);
|
||||||
|
|
||||||
|
s->trigger = (timeTrigger)obs_data_get_int(obj, "trigger");
|
||||||
|
s->time = QTime::fromString(obs_data_get_string(obj, "time"));
|
||||||
|
s->usePreviousScene = strcmp(scene, previous_scene_name) == 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimeSwitch::load(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
if (loadOldTime(obj, this)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneSwitcherEntry::load(obj);
|
||||||
|
|
||||||
|
trigger = (timeTrigger)obs_data_get_int(obj, "trigger");
|
||||||
|
time = QTime::fromString(obs_data_get_string(obj, "time"));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void populateTriggers(QComboBox *list)
|
||||||
|
{
|
||||||
|
list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.anyDay"));
|
||||||
|
list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.mondays"));
|
||||||
|
list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.tuesdays"));
|
||||||
|
list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.wednesdays"));
|
||||||
|
list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.thursdays"));
|
||||||
|
list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.fridays"));
|
||||||
|
list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.saturdays"));
|
||||||
|
list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.sundays"));
|
||||||
|
list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.afterstart"));
|
||||||
|
|
||||||
list->setItemData(
|
list->setItemData(
|
||||||
8,
|
8, obs_module_text("AdvSceneSwitcher.timeTab.afterstart.tip"),
|
||||||
"The time relative to the start of streaming / recording will be used",
|
|
||||||
Qt::ToolTipRole);
|
Qt::ToolTipRole);
|
||||||
}
|
}
|
||||||
|
|
||||||
TimeSwitchWidget::TimeSwitchWidget(TimeSwitch *s) : SwitchWidget(s)
|
TimeSwitchWidget::TimeSwitchWidget(QWidget *parent, TimeSwitch *s)
|
||||||
|
: SwitchWidget(parent, s, true, true)
|
||||||
{
|
{
|
||||||
triggers = new QComboBox();
|
triggers = new QComboBox();
|
||||||
time = new QTimeEdit();
|
time = new QTimeEdit();
|
||||||
|
|
||||||
atLabel = new QLabel("at");
|
|
||||||
switchLabel = new QLabel("switch to");
|
|
||||||
usingLabel = new QLabel("using");
|
|
||||||
|
|
||||||
QWidget::connect(triggers, SIGNAL(currentIndexChanged(int)), this,
|
QWidget::connect(triggers, SIGNAL(currentIndexChanged(int)), this,
|
||||||
SLOT(TriggerChanged(int)));
|
SLOT(TriggerChanged(int)));
|
||||||
QWidget::connect(time, SIGNAL(timeChanged(const QTime &)), this,
|
QWidget::connect(time, SIGNAL(timeChanged(const QTime &)), this,
|
||||||
@@ -252,19 +277,14 @@ TimeSwitchWidget::TimeSwitchWidget(TimeSwitch *s) : SwitchWidget(s)
|
|||||||
time->setTime(s->time);
|
time->setTime(s->time);
|
||||||
}
|
}
|
||||||
|
|
||||||
setStyleSheet("* { background-color: transparent; }");
|
|
||||||
|
|
||||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
mainLayout->addWidget(triggers);
|
{"{{triggers}}", triggers},
|
||||||
mainLayout->addWidget(atLabel);
|
{"{{time}}", time},
|
||||||
mainLayout->addWidget(time);
|
{"{{scenes}}", scenes},
|
||||||
mainLayout->addWidget(switchLabel);
|
{"{{transitions}}", transitions}};
|
||||||
mainLayout->addWidget(scenes);
|
placeWidgets(obs_module_text("AdvSceneSwitcher.timeTab.entry"),
|
||||||
mainLayout->addWidget(usingLabel);
|
mainLayout, widgetPlaceholders);
|
||||||
mainLayout->addWidget(transitions);
|
|
||||||
mainLayout->addStretch();
|
|
||||||
|
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
|
||||||
switchData = s;
|
switchData = s;
|
||||||
@@ -294,16 +314,20 @@ void TimeSwitchWidget::swapSwitchData(TimeSwitchWidget *s1,
|
|||||||
|
|
||||||
void TimeSwitchWidget::TriggerChanged(int index)
|
void TimeSwitchWidget::TriggerChanged(int index)
|
||||||
{
|
{
|
||||||
if (loading || !switchData)
|
if (loading || !switchData) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switchData->trigger = (timeTrigger)index;
|
switchData->trigger = (timeTrigger)index;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimeSwitchWidget::TimeChanged(const QTime &time)
|
void TimeSwitchWidget::TimeChanged(const QTime &time)
|
||||||
{
|
{
|
||||||
if (loading || !switchData)
|
if (loading || !switchData) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switchData->time = time;
|
switchData->time = time;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,26 @@
|
|||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
|
bool DefaultSceneTransition::pause = false;
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_transitionsAdd_clicked()
|
void AdvSceneSwitcher::on_transitionsAdd_clicked()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switcher->sceneTransitions.emplace_back();
|
switcher->sceneTransitions.emplace_back();
|
||||||
|
|
||||||
QListWidgetItem *item;
|
listAddClicked(ui->sceneTransitions,
|
||||||
item = new QListWidgetItem(ui->sceneTransitions);
|
new TransitionSwitchWidget(
|
||||||
ui->sceneTransitions->addItem(item);
|
this, &switcher->sceneTransitions.back()));
|
||||||
TransitionSwitchWidget *sw =
|
|
||||||
new TransitionSwitchWidget(&switcher->sceneTransitions.back());
|
ui->transitionHelp->setVisible(false);
|
||||||
item->setSizeHint(sw->minimumSizeHint());
|
|
||||||
ui->sceneTransitions->setItemWidget(item, sw);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_transitionsRemove_clicked()
|
void AdvSceneSwitcher::on_transitionsRemove_clicked()
|
||||||
{
|
{
|
||||||
QListWidgetItem *item = ui->sceneTransitions->currentItem();
|
QListWidgetItem *item = ui->sceneTransitions->currentItem();
|
||||||
if (!item)
|
if (!item) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
@@ -34,8 +35,9 @@ void AdvSceneSwitcher::on_transitionsRemove_clicked()
|
|||||||
void AdvSceneSwitcher::on_transitionsUp_clicked()
|
void AdvSceneSwitcher::on_transitionsUp_clicked()
|
||||||
{
|
{
|
||||||
int index = ui->sceneTransitions->currentRow();
|
int index = ui->sceneTransitions->currentRow();
|
||||||
if (!listMoveUp(ui->sceneTransitions))
|
if (!listMoveUp(ui->sceneTransitions)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
TransitionSwitchWidget *s1 =
|
TransitionSwitchWidget *s1 =
|
||||||
(TransitionSwitchWidget *)ui->sceneTransitions->itemWidget(
|
(TransitionSwitchWidget *)ui->sceneTransitions->itemWidget(
|
||||||
@@ -55,8 +57,9 @@ void AdvSceneSwitcher::on_transitionsDown_clicked()
|
|||||||
{
|
{
|
||||||
int index = ui->sceneTransitions->currentRow();
|
int index = ui->sceneTransitions->currentRow();
|
||||||
|
|
||||||
if (!listMoveDown(ui->sceneTransitions))
|
if (!listMoveDown(ui->sceneTransitions)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
TransitionSwitchWidget *s1 =
|
TransitionSwitchWidget *s1 =
|
||||||
(TransitionSwitchWidget *)ui->sceneTransitions->itemWidget(
|
(TransitionSwitchWidget *)ui->sceneTransitions->itemWidget(
|
||||||
@@ -77,20 +80,20 @@ void AdvSceneSwitcher::on_defaultTransitionsAdd_clicked()
|
|||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switcher->defaultSceneTransitions.emplace_back();
|
switcher->defaultSceneTransitions.emplace_back();
|
||||||
|
|
||||||
QListWidgetItem *item;
|
listAddClicked(ui->defaultTransitions,
|
||||||
item = new QListWidgetItem(ui->defaultTransitions);
|
new DefTransitionSwitchWidget(
|
||||||
ui->defaultTransitions->addItem(item);
|
this,
|
||||||
DefTransitionSwitchWidget *sw = new DefTransitionSwitchWidget(
|
&switcher->defaultSceneTransitions.back()));
|
||||||
&switcher->defaultSceneTransitions.back());
|
|
||||||
item->setSizeHint(sw->minimumSizeHint());
|
ui->defaultTransitionHelp->setVisible(false);
|
||||||
ui->defaultTransitions->setItemWidget(item, sw);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_defaultTransitionsRemove_clicked()
|
void AdvSceneSwitcher::on_defaultTransitionsRemove_clicked()
|
||||||
{
|
{
|
||||||
QListWidgetItem *item = ui->defaultTransitions->currentItem();
|
QListWidgetItem *item = ui->defaultTransitions->currentItem();
|
||||||
if (!item)
|
if (!item) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
@@ -105,8 +108,9 @@ void AdvSceneSwitcher::on_defaultTransitionsRemove_clicked()
|
|||||||
void AdvSceneSwitcher::on_defaultTransitionsUp_clicked()
|
void AdvSceneSwitcher::on_defaultTransitionsUp_clicked()
|
||||||
{
|
{
|
||||||
int index = ui->defaultTransitions->currentRow();
|
int index = ui->defaultTransitions->currentRow();
|
||||||
if (!listMoveUp(ui->defaultTransitions))
|
if (!listMoveUp(ui->defaultTransitions)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
TransitionSwitchWidget *s1 =
|
TransitionSwitchWidget *s1 =
|
||||||
(TransitionSwitchWidget *)ui->defaultTransitions->itemWidget(
|
(TransitionSwitchWidget *)ui->defaultTransitions->itemWidget(
|
||||||
@@ -126,8 +130,9 @@ void AdvSceneSwitcher::on_defaultTransitionsDown_clicked()
|
|||||||
{
|
{
|
||||||
int index = ui->defaultTransitions->currentRow();
|
int index = ui->defaultTransitions->currentRow();
|
||||||
|
|
||||||
if (!listMoveDown(ui->defaultTransitions))
|
if (!listMoveDown(ui->defaultTransitions)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
DefTransitionSwitchWidget *s1 =
|
DefTransitionSwitchWidget *s1 =
|
||||||
(DefTransitionSwitchWidget *)ui->defaultTransitions->itemWidget(
|
(DefTransitionSwitchWidget *)ui->defaultTransitions->itemWidget(
|
||||||
@@ -143,41 +148,49 @@ void AdvSceneSwitcher::on_defaultTransitionsDown_clicked()
|
|||||||
switcher->defaultSceneTransitions[index + 1]);
|
switcher->defaultSceneTransitions[index + 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitcherData::setDefaultSceneTransitions()
|
void SwitcherData::checkDefaultSceneTransitions(bool &match,
|
||||||
|
OBSWeakSource &transition)
|
||||||
{
|
{
|
||||||
if (changedDefTransitionRecently)
|
if (checkedDefTransition || DefaultSceneTransition::pause) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
obs_source_t *currentSource = obs_frontend_get_current_scene();
|
obs_source_t *currentSource = obs_frontend_get_current_scene();
|
||||||
obs_weak_source_t *ws = obs_source_get_weak_source(currentSource);
|
obs_weak_source_t *ws = obs_source_get_weak_source(currentSource);
|
||||||
|
|
||||||
for (DefaultSceneTransition &s : defaultSceneTransitions) {
|
for (DefaultSceneTransition &s : defaultSceneTransitions) {
|
||||||
if (s.scene == ws) {
|
if (s.scene == ws) {
|
||||||
if (!s.initialized())
|
if (!s.initialized()) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
obs_source_t *transition =
|
match = true;
|
||||||
obs_weak_source_get_source(s.transition);
|
transition = 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)
|
if (verbose) {
|
||||||
s.logMatch();
|
s.logMatch();
|
||||||
|
}
|
||||||
obs_source_release(transition);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
obs_source_release(currentSource);
|
obs_source_release(currentSource);
|
||||||
obs_weak_source_release(ws);
|
obs_weak_source_release(ws);
|
||||||
changedDefTransitionRecently = true;
|
|
||||||
|
checkedDefTransition = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitcherData::setCurrentDefTransition(OBSWeakSource &transition)
|
||||||
|
{
|
||||||
|
obs_source_t *transitionSource = obs_weak_source_get_source(transition);
|
||||||
|
obs_frontend_set_current_transition(transitionSource);
|
||||||
|
obs_source_release(transitionSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_transitionOverridecheckBox_stateChanged(int state)
|
void AdvSceneSwitcher::on_transitionOverridecheckBox_stateChanged(int state)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
if (!state) {
|
if (!state) {
|
||||||
@@ -193,8 +206,9 @@ obs_weak_source_t *getNextTransition(obs_weak_source_t *scene1,
|
|||||||
obs_weak_source_t *ws = nullptr;
|
obs_weak_source_t *ws = nullptr;
|
||||||
if (scene1 && scene2) {
|
if (scene1 && scene2) {
|
||||||
for (SceneTransition &t : switcher->sceneTransitions) {
|
for (SceneTransition &t : switcher->sceneTransitions) {
|
||||||
if (!t.initialized())
|
if (!t.initialized()) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (t.scene == scene1 && t.scene2 == scene2) {
|
if (t.scene == scene1 && t.scene2 == scene2) {
|
||||||
ws = t.transition;
|
ws = t.transition;
|
||||||
@@ -256,8 +270,9 @@ void setNextTransition(OBSWeakSource &targetScene, obs_source_t *currentSource,
|
|||||||
obs_frontend_set_current_transition(nextTransition);
|
obs_frontend_set_current_transition(nextTransition);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transitionOverrideOverride)
|
if (transitionOverrideOverride) {
|
||||||
overwriteTransitionOverride(targetScene, nextTransition, td);
|
overwriteTransitionOverride(targetScene, nextTransition, td);
|
||||||
|
}
|
||||||
|
|
||||||
obs_weak_source_release(nextTransitionWs);
|
obs_weak_source_release(nextTransitionWs);
|
||||||
obs_source_release(nextTransition);
|
obs_source_release(nextTransition);
|
||||||
@@ -379,21 +394,34 @@ void AdvSceneSwitcher::setupTransitionsTab()
|
|||||||
QListWidgetItem *item;
|
QListWidgetItem *item;
|
||||||
item = new QListWidgetItem(ui->sceneTransitions);
|
item = new QListWidgetItem(ui->sceneTransitions);
|
||||||
ui->sceneTransitions->addItem(item);
|
ui->sceneTransitions->addItem(item);
|
||||||
TransitionSwitchWidget *sw = new TransitionSwitchWidget(&s);
|
TransitionSwitchWidget *sw =
|
||||||
|
new TransitionSwitchWidget(this, &s);
|
||||||
item->setSizeHint(sw->minimumSizeHint());
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
ui->sceneTransitions->setItemWidget(item, sw);
|
ui->sceneTransitions->setItemWidget(item, sw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (switcher->sceneTransitions.size() == 0) {
|
||||||
|
ui->transitionHelp->setVisible(true);
|
||||||
|
} else {
|
||||||
|
ui->transitionHelp->setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
for (auto &s : switcher->defaultSceneTransitions) {
|
for (auto &s : switcher->defaultSceneTransitions) {
|
||||||
QListWidgetItem *item;
|
QListWidgetItem *item;
|
||||||
item = new QListWidgetItem(ui->defaultTransitions);
|
item = new QListWidgetItem(ui->defaultTransitions);
|
||||||
ui->defaultTransitions->addItem(item);
|
ui->defaultTransitions->addItem(item);
|
||||||
DefTransitionSwitchWidget *sw =
|
DefTransitionSwitchWidget *sw =
|
||||||
new DefTransitionSwitchWidget(&s);
|
new DefTransitionSwitchWidget(this, &s);
|
||||||
item->setSizeHint(sw->minimumSizeHint());
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
ui->defaultTransitions->setItemWidget(item, sw);
|
ui->defaultTransitions->setItemWidget(item, sw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (switcher->defaultSceneTransitions.size() == 0) {
|
||||||
|
ui->defaultTransitionHelp->setVisible(true);
|
||||||
|
} else {
|
||||||
|
ui->defaultTransitionHelp->setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
ui->transitionOverridecheckBox->setChecked(
|
ui->transitionOverridecheckBox->setChecked(
|
||||||
switcher->tansitionOverrideOverride);
|
switcher->tansitionOverrideOverride);
|
||||||
}
|
}
|
||||||
@@ -409,15 +437,12 @@ bool SceneTransition::valid()
|
|||||||
(SceneSwitcherEntry::valid() && WeakSourceValid(scene2));
|
(SceneSwitcherEntry::valid() && WeakSourceValid(scene2));
|
||||||
}
|
}
|
||||||
|
|
||||||
TransitionSwitchWidget::TransitionSwitchWidget(SceneTransition *s)
|
TransitionSwitchWidget::TransitionSwitchWidget(QWidget *parent,
|
||||||
: SwitchWidget(s, false)
|
SceneTransition *s)
|
||||||
|
: SwitchWidget(parent, s, false)
|
||||||
{
|
{
|
||||||
scenes2 = new QComboBox();
|
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 &)),
|
QWidget::connect(scenes2, SIGNAL(currentTextChanged(const QString &)),
|
||||||
this, SLOT(Scene2Changed(const QString &)));
|
this, SLOT(Scene2Changed(const QString &)));
|
||||||
|
|
||||||
@@ -427,18 +452,13 @@ TransitionSwitchWidget::TransitionSwitchWidget(SceneTransition *s)
|
|||||||
scenes2->setCurrentText(GetWeakSourceName(s->scene2).c_str());
|
scenes2->setCurrentText(GetWeakSourceName(s->scene2).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
setStyleSheet("* { background-color: transparent; }");
|
|
||||||
|
|
||||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
mainLayout->addWidget(switchLabel);
|
{"{{scenes}}", scenes},
|
||||||
mainLayout->addWidget(scenes);
|
{"{{scenes2}}", scenes2},
|
||||||
mainLayout->addWidget(toLabel);
|
{"{{transitions}}", transitions}};
|
||||||
mainLayout->addWidget(scenes2);
|
placeWidgets(obs_module_text("AdvSceneSwitcher.transitionTab.entry"),
|
||||||
mainLayout->addWidget(usingLabel);
|
mainLayout, widgetPlaceholders);
|
||||||
mainLayout->addWidget(transitions);
|
|
||||||
mainLayout->addStretch();
|
|
||||||
|
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
|
||||||
switchData = s;
|
switchData = s;
|
||||||
@@ -468,29 +488,25 @@ void TransitionSwitchWidget::swapSwitchData(TransitionSwitchWidget *s1,
|
|||||||
|
|
||||||
void TransitionSwitchWidget::Scene2Changed(const QString &text)
|
void TransitionSwitchWidget::Scene2Changed(const QString &text)
|
||||||
{
|
{
|
||||||
if (loading || !switchData)
|
if (loading || !switchData) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switchData->scene2 = GetWeakSourceByQString(text);
|
switchData->scene2 = GetWeakSourceByQString(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
DefTransitionSwitchWidget::DefTransitionSwitchWidget(DefaultSceneTransition *s)
|
DefTransitionSwitchWidget::DefTransitionSwitchWidget(QWidget *parent,
|
||||||
: SwitchWidget(s, false)
|
DefaultSceneTransition *s)
|
||||||
|
: SwitchWidget(parent, 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;
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
mainLayout->addWidget(whenLabel);
|
{"{{scenes}}", scenes}, {"{{transitions}}", transitions}};
|
||||||
mainLayout->addWidget(scenes);
|
placeWidgets(
|
||||||
mainLayout->addWidget(switchLabel);
|
obs_module_text(
|
||||||
mainLayout->addWidget(transitions);
|
"AdvSceneSwitcher.transitionTab.defaultTransitionEntry"),
|
||||||
mainLayout->addStretch();
|
mainLayout, widgetPlaceholders);
|
||||||
|
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
|
||||||
switchData = s;
|
switchData = s;
|
||||||
|
|||||||
@@ -1,29 +1,30 @@
|
|||||||
|
#include <regex>
|
||||||
|
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
|
bool WindowSwitch::pause = false;
|
||||||
static QMetaObject::Connection addPulse;
|
static QMetaObject::Connection addPulse;
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_windowAdd_clicked()
|
void AdvSceneSwitcher::on_windowAdd_clicked()
|
||||||
{
|
{
|
||||||
ui->windowAdd->disconnect(addPulse);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switcher->windowSwitches.emplace_back();
|
switcher->windowSwitches.emplace_back();
|
||||||
|
|
||||||
QListWidgetItem *item;
|
listAddClicked(ui->windowSwitches,
|
||||||
item = new QListWidgetItem(ui->windowSwitches);
|
new WindowSwitchWidget(this,
|
||||||
ui->windowSwitches->addItem(item);
|
&switcher->windowSwitches.back()),
|
||||||
WindowSwitchWidget *sw =
|
ui->windowAdd, &addPulse);
|
||||||
new WindowSwitchWidget(&switcher->windowSwitches.back());
|
|
||||||
item->setSizeHint(sw->minimumSizeHint());
|
ui->windowHelp->setVisible(false);
|
||||||
ui->windowSwitches->setItemWidget(item, sw);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_windowRemove_clicked()
|
void AdvSceneSwitcher::on_windowRemove_clicked()
|
||||||
{
|
{
|
||||||
QListWidgetItem *item = ui->windowSwitches->currentItem();
|
QListWidgetItem *item = ui->windowSwitches->currentItem();
|
||||||
if (!item)
|
if (!item) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
@@ -38,8 +39,9 @@ void AdvSceneSwitcher::on_windowRemove_clicked()
|
|||||||
void AdvSceneSwitcher::on_windowUp_clicked()
|
void AdvSceneSwitcher::on_windowUp_clicked()
|
||||||
{
|
{
|
||||||
int index = ui->windowSwitches->currentRow();
|
int index = ui->windowSwitches->currentRow();
|
||||||
if (!listMoveUp(ui->windowSwitches))
|
if (!listMoveUp(ui->windowSwitches)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
WindowSwitchWidget *s1 =
|
WindowSwitchWidget *s1 =
|
||||||
(WindowSwitchWidget *)ui->windowSwitches->itemWidget(
|
(WindowSwitchWidget *)ui->windowSwitches->itemWidget(
|
||||||
@@ -59,8 +61,9 @@ void AdvSceneSwitcher::on_windowDown_clicked()
|
|||||||
{
|
{
|
||||||
int index = ui->windowSwitches->currentRow();
|
int index = ui->windowSwitches->currentRow();
|
||||||
|
|
||||||
if (!listMoveDown(ui->windowSwitches))
|
if (!listMoveDown(ui->windowSwitches)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
WindowSwitchWidget *s1 =
|
WindowSwitchWidget *s1 =
|
||||||
(WindowSwitchWidget *)ui->windowSwitches->itemWidget(
|
(WindowSwitchWidget *)ui->windowSwitches->itemWidget(
|
||||||
@@ -80,8 +83,9 @@ void AdvSceneSwitcher::on_ignoreWindowsAdd_clicked()
|
|||||||
{
|
{
|
||||||
QString windowName = ui->ignoreWindowsWindows->currentText();
|
QString windowName = ui->ignoreWindowsWindows->currentText();
|
||||||
|
|
||||||
if (windowName.isEmpty())
|
if (windowName.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QVariant v = QVariant::fromValue(windowName);
|
QVariant v = QVariant::fromValue(windowName);
|
||||||
|
|
||||||
@@ -97,13 +101,16 @@ void AdvSceneSwitcher::on_ignoreWindowsAdd_clicked()
|
|||||||
switcher->ignoreWindowsSwitches.emplace_back(
|
switcher->ignoreWindowsSwitches.emplace_back(
|
||||||
windowName.toUtf8().constData());
|
windowName.toUtf8().constData());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ui->ignoreWindowHelp->setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_ignoreWindowsRemove_clicked()
|
void AdvSceneSwitcher::on_ignoreWindowsRemove_clicked()
|
||||||
{
|
{
|
||||||
QListWidgetItem *item = ui->ignoreWindows->currentItem();
|
QListWidgetItem *item = ui->ignoreWindows->currentItem();
|
||||||
if (!item)
|
if (!item) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QString windowName = item->data(Qt::UserRole).toString();
|
QString windowName = item->data(Qt::UserRole).toString();
|
||||||
|
|
||||||
@@ -144,10 +151,12 @@ int AdvSceneSwitcher::IgnoreWindowsFindByData(const QString &window)
|
|||||||
|
|
||||||
void AdvSceneSwitcher::on_ignoreWindows_currentRowChanged(int idx)
|
void AdvSceneSwitcher::on_ignoreWindows_currentRowChanged(int idx)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading) {
|
||||||
return;
|
return;
|
||||||
if (idx == -1)
|
}
|
||||||
|
if (idx == -1) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QListWidgetItem *item = ui->ignoreWindows->item(idx);
|
QListWidgetItem *item = ui->ignoreWindows->item(idx);
|
||||||
|
|
||||||
@@ -162,85 +171,100 @@ void AdvSceneSwitcher::on_ignoreWindows_currentRowChanged(int idx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isRunning(std::string &title)
|
void checkWindowTitleSwitchDirect(WindowSwitch &s,
|
||||||
|
std::string ¤tWindowTitle, bool &match,
|
||||||
|
OBSWeakSource &scene,
|
||||||
|
OBSWeakSource &transition)
|
||||||
{
|
{
|
||||||
QStringList windows;
|
bool focus = s.window == currentWindowTitle;
|
||||||
|
bool fullscreen = (!s.fullscreen || isFullscreen(s.window));
|
||||||
|
bool max = (!s.maximized || isMaximized(s.window));
|
||||||
|
|
||||||
GetWindowList(windows);
|
if (focus && fullscreen && max) {
|
||||||
// True if switch is running (direct)
|
match = true;
|
||||||
bool equals = windows.contains(QString::fromStdString(title));
|
scene = s.getScene();
|
||||||
// True if switch is running (regex)
|
transition = s.transition;
|
||||||
bool matches = (windows.indexOf(QRegularExpression(
|
}
|
||||||
QString::fromStdString(title))) != -1);
|
|
||||||
|
|
||||||
return (equals || matches);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isFocused(std::string &title)
|
void checkWindowTitleSwitchRegex(WindowSwitch &s,
|
||||||
|
std::string ¤tWindowTitle,
|
||||||
|
std::vector<std::string> windowList,
|
||||||
|
bool &match, OBSWeakSource &scene,
|
||||||
|
OBSWeakSource &transition)
|
||||||
{
|
{
|
||||||
std::string current;
|
for (auto &window : windowList) {
|
||||||
|
try {
|
||||||
|
std::regex expr(s.window);
|
||||||
|
if (!std::regex_match(window, expr)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} catch (const std::regex_error &) {
|
||||||
|
}
|
||||||
|
|
||||||
GetCurrentWindowTitle(current);
|
bool focus = window == currentWindowTitle;
|
||||||
// True if switch equals current window
|
bool fullscreen = (!s.fullscreen || isFullscreen(window));
|
||||||
bool equals = (title == current);
|
bool max = (!s.maximized || isMaximized(window));
|
||||||
// True if switch matches current window
|
|
||||||
bool matches = QString::fromStdString(current).contains(
|
|
||||||
QRegularExpression(QString::fromStdString(title)));
|
|
||||||
|
|
||||||
return (equals || matches);
|
if (focus && fullscreen && max) {
|
||||||
|
match = true;
|
||||||
|
scene = s.getScene();
|
||||||
|
transition = s.transition;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitcherData::checkWindowTitleSwitch(bool &match, OBSWeakSource &scene,
|
void SwitcherData::checkWindowTitleSwitch(bool &match, OBSWeakSource &scene,
|
||||||
OBSWeakSource &transition)
|
OBSWeakSource &transition)
|
||||||
{
|
{
|
||||||
std::string title;
|
if (WindowSwitch::pause) {
|
||||||
bool ignored = false;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string currentWindowTitle;
|
||||||
|
GetCurrentWindowTitle(currentWindowTitle);
|
||||||
|
|
||||||
// Check if current window is ignored
|
// Check if current window is ignored
|
||||||
GetCurrentWindowTitle(title);
|
|
||||||
for (auto &window : ignoreWindowsSwitches) {
|
for (auto &window : ignoreWindowsSwitches) {
|
||||||
// True if ignored switch equals current window
|
bool equals = (currentWindowTitle == 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) {
|
try {
|
||||||
ignored = true;
|
std::regex expr(window);
|
||||||
title = lastTitle;
|
bool matches =
|
||||||
|
std::regex_match(currentWindowTitle, expr);
|
||||||
|
|
||||||
break;
|
if (equals || matches) {
|
||||||
|
currentWindowTitle = lastTitle;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (const std::regex_error &) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lastTitle = title;
|
|
||||||
|
|
||||||
// Check for match
|
lastTitle = currentWindowTitle;
|
||||||
|
|
||||||
|
std::vector<std::string> windowList;
|
||||||
|
GetWindowList(windowList);
|
||||||
|
|
||||||
for (WindowSwitch &s : windowSwitches) {
|
for (WindowSwitch &s : windowSwitches) {
|
||||||
if (!s.initialized())
|
if (!s.initialized()) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// True if fullscreen is disabled OR current window is fullscreen
|
if (std::find(windowList.begin(), windowList.end(), s.window) !=
|
||||||
bool fullscreen = (!s.fullscreen || isFullscreen(s.window));
|
windowList.end()) {
|
||||||
// True if maximized is disabled OR current window is maximized
|
checkWindowTitleSwitchDirect(s, currentWindowTitle,
|
||||||
bool max = (!s.maximized || isMaximized(s.window));
|
match, scene, transition);
|
||||||
// True if focus is disabled OR switch is focused
|
} else {
|
||||||
bool focus = (!s.focus || isFocused(s.window));
|
checkWindowTitleSwitchRegex(s, currentWindowTitle,
|
||||||
// True if current window is ignored AND switch equals OR matches last window
|
windowList, match, scene,
|
||||||
bool ignore =
|
transition);
|
||||||
(ignored &&
|
}
|
||||||
(title == s.window ||
|
|
||||||
QString::fromStdString(title).contains(
|
|
||||||
QRegularExpression(
|
|
||||||
QString::fromStdString(s.window)))));
|
|
||||||
|
|
||||||
if (isRunning(s.window) &&
|
if (match) {
|
||||||
(fullscreen && (max && (focus || ignore)))) {
|
if (verbose) {
|
||||||
match = true;
|
|
||||||
scene = s.scene;
|
|
||||||
transition = s.transition;
|
|
||||||
|
|
||||||
if (verbose)
|
|
||||||
s.logMatch();
|
s.logMatch();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -252,26 +276,9 @@ void SwitcherData::saveWindowTitleSwitches(obs_data_t *obj)
|
|||||||
for (WindowSwitch &s : switcher->windowSwitches) {
|
for (WindowSwitch &s : switcher->windowSwitches) {
|
||||||
obs_data_t *array_obj = obs_data_create();
|
obs_data_t *array_obj = obs_data_create();
|
||||||
|
|
||||||
obs_source_t *source = obs_weak_source_get_source(s.scene);
|
s.save(array_obj);
|
||||||
obs_source_t *transition =
|
obs_data_array_push_back(windowTitleArray, array_obj);
|
||||||
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_release(array_obj);
|
||||||
}
|
}
|
||||||
obs_data_set_array(obj, "switches", windowTitleArray);
|
obs_data_set_array(obj, "switches", windowTitleArray);
|
||||||
@@ -300,26 +307,8 @@ void SwitcherData::loadWindowTitleSwitches(obs_data_t *obj)
|
|||||||
obs_data_t *array_obj =
|
obs_data_t *array_obj =
|
||||||
obs_data_array_item(windowTitleArray, i);
|
obs_data_array_item(windowTitleArray, i);
|
||||||
|
|
||||||
const char *scene = obs_data_get_string(array_obj, "scene");
|
switcher->windowSwitches.emplace_back();
|
||||||
const char *transition =
|
windowSwitches.back().load(array_obj);
|
||||||
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_release(array_obj);
|
||||||
}
|
}
|
||||||
@@ -351,13 +340,17 @@ void AdvSceneSwitcher::setupTitleTab()
|
|||||||
QListWidgetItem *item;
|
QListWidgetItem *item;
|
||||||
item = new QListWidgetItem(ui->windowSwitches);
|
item = new QListWidgetItem(ui->windowSwitches);
|
||||||
ui->windowSwitches->addItem(item);
|
ui->windowSwitches->addItem(item);
|
||||||
WindowSwitchWidget *sw = new WindowSwitchWidget(&s);
|
WindowSwitchWidget *sw = new WindowSwitchWidget(this, &s);
|
||||||
item->setSizeHint(sw->minimumSizeHint());
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
ui->windowSwitches->setItemWidget(item, sw);
|
ui->windowSwitches->setItemWidget(item, sw);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switcher->windowSwitches.size() == 0)
|
if (switcher->windowSwitches.size() == 0) {
|
||||||
addPulse = PulseWidget(ui->windowAdd, QColor(Qt::green));
|
addPulse = PulseWidget(ui->windowAdd, QColor(Qt::green));
|
||||||
|
ui->windowHelp->setVisible(true);
|
||||||
|
} else {
|
||||||
|
ui->windowHelp->setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
populateWindowSelection(ui->ignoreWindowsWindows);
|
populateWindowSelection(ui->ignoreWindowsWindows);
|
||||||
|
|
||||||
@@ -368,14 +361,89 @@ void AdvSceneSwitcher::setupTitleTab()
|
|||||||
new QListWidgetItem(text, ui->ignoreWindows);
|
new QListWidgetItem(text, ui->ignoreWindows);
|
||||||
item->setData(Qt::UserRole, text);
|
item->setData(Qt::UserRole, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (switcher->ignoreWindowsSwitches.size() == 0) {
|
||||||
|
ui->ignoreWindowHelp->setVisible(true);
|
||||||
|
} else {
|
||||||
|
ui->ignoreWindowHelp->setVisible(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowSwitchWidget::WindowSwitchWidget(WindowSwitch *s) : SwitchWidget(s, false)
|
void WindowSwitch::save(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
SceneSwitcherEntry::save(obj);
|
||||||
|
|
||||||
|
obs_data_set_string(obj, "windowTitle", window.c_str());
|
||||||
|
obs_data_set_bool(obj, "fullscreen", fullscreen);
|
||||||
|
obs_data_set_bool(obj, "maximized", maximized);
|
||||||
|
obs_data_set_bool(obj, "focus", focus);
|
||||||
|
}
|
||||||
|
|
||||||
|
// To be removed in future version
|
||||||
|
bool loadOldWindow(obs_data_t *obj, WindowSwitch *s)
|
||||||
|
{
|
||||||
|
if (!s) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *scene = obs_data_get_string(obj, "scene");
|
||||||
|
|
||||||
|
if (strcmp(scene, "") == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->scene = GetWeakSourceByName(scene);
|
||||||
|
|
||||||
|
const char *transition = obs_data_get_string(obj, "transition");
|
||||||
|
s->transition = GetWeakTransitionByName(transition);
|
||||||
|
|
||||||
|
s->window = obs_data_get_string(obj, "window_title");
|
||||||
|
s->fullscreen = obs_data_get_bool(obj, "fullscreen");
|
||||||
|
#if __APPLE__
|
||||||
|
// TODO:
|
||||||
|
// not implemented on MacOS as I cannot test it
|
||||||
|
s->maximized = false;
|
||||||
|
#else
|
||||||
|
s->maximized = obs_data_get_bool(obj, "maximized");
|
||||||
|
#endif
|
||||||
|
s->focus = obs_data_get_bool(obj, "focus") ||
|
||||||
|
!obs_data_has_user_value(obj, "focus");
|
||||||
|
s->usePreviousScene = strcmp(scene, previous_scene_name) == 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowSwitch::load(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
if (loadOldWindow(obj, this)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneSwitcherEntry::load(obj);
|
||||||
|
|
||||||
|
window = obs_data_get_string(obj, "windowTitle");
|
||||||
|
fullscreen = obs_data_get_bool(obj, "fullscreen");
|
||||||
|
#if __APPLE__
|
||||||
|
// TODO:
|
||||||
|
// not implemented on MacOS as I cannot test it
|
||||||
|
maximized = false;
|
||||||
|
#else
|
||||||
|
maximized = obs_data_get_bool(obj, "maximized");
|
||||||
|
#endif
|
||||||
|
focus = obs_data_get_bool(obj, "focus") ||
|
||||||
|
!obs_data_has_user_value(obj, "focus");
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowSwitchWidget::WindowSwitchWidget(QWidget *parent, WindowSwitch *s)
|
||||||
|
: SwitchWidget(parent, s, true, true)
|
||||||
{
|
{
|
||||||
windows = new QComboBox();
|
windows = new QComboBox();
|
||||||
fullscreen = new QCheckBox("if fullscreen");
|
fullscreen = new QCheckBox(
|
||||||
maximized = new QCheckBox("if maximized");
|
obs_module_text("AdvSceneSwitcher.windowTitleTab.fullscreen"));
|
||||||
focused = new QCheckBox("if focused");
|
maximized = new QCheckBox(
|
||||||
|
obs_module_text("AdvSceneSwitcher.windowTitleTab.maximized"));
|
||||||
|
focused = new QCheckBox(
|
||||||
|
obs_module_text("AdvSceneSwitcher.windowTitleTab.focused"));
|
||||||
|
|
||||||
QWidget::connect(windows, SIGNAL(currentTextChanged(const QString &)),
|
QWidget::connect(windows, SIGNAL(currentTextChanged(const QString &)),
|
||||||
this, SLOT(WindowChanged(const QString &)));
|
this, SLOT(WindowChanged(const QString &)));
|
||||||
@@ -404,19 +472,16 @@ WindowSwitchWidget::WindowSwitchWidget(WindowSwitch *s) : SwitchWidget(s, false)
|
|||||||
focused->setChecked(s->focus);
|
focused->setChecked(s->focus);
|
||||||
}
|
}
|
||||||
|
|
||||||
setStyleSheet("* { background-color: transparent; }");
|
|
||||||
|
|
||||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
mainLayout->addWidget(windows);
|
{"{{windows}}", windows},
|
||||||
mainLayout->addWidget(scenes);
|
{"{{scenes}}", scenes},
|
||||||
mainLayout->addWidget(transitions);
|
{"{{transitions}}", transitions},
|
||||||
mainLayout->addWidget(scenes);
|
{"{{fullscreen}}", fullscreen},
|
||||||
mainLayout->addWidget(fullscreen);
|
{"{{maximized}}", maximized},
|
||||||
mainLayout->addWidget(maximized);
|
{"{{focused}}", focused}};
|
||||||
mainLayout->addWidget(focused);
|
placeWidgets(obs_module_text("AdvSceneSwitcher.windowTitleTab.entry"),
|
||||||
mainLayout->addStretch();
|
mainLayout, widgetPlaceholders);
|
||||||
|
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
|
||||||
switchData = s;
|
switchData = s;
|
||||||
@@ -446,32 +511,40 @@ void WindowSwitchWidget::swapSwitchData(WindowSwitchWidget *s1,
|
|||||||
|
|
||||||
void WindowSwitchWidget::WindowChanged(const QString &text)
|
void WindowSwitchWidget::WindowChanged(const QString &text)
|
||||||
{
|
{
|
||||||
if (loading || !switchData)
|
if (loading || !switchData) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switchData->window = text.toStdString();
|
switchData->window = text.toStdString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowSwitchWidget::FullscreenChanged(int state)
|
void WindowSwitchWidget::FullscreenChanged(int state)
|
||||||
{
|
{
|
||||||
if (loading || !switchData)
|
if (loading || !switchData) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switchData->fullscreen = state;
|
switchData->fullscreen = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowSwitchWidget::MaximizedChanged(int state)
|
void WindowSwitchWidget::MaximizedChanged(int state)
|
||||||
{
|
{
|
||||||
if (loading || !switchData)
|
if (loading || !switchData) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switchData->maximized = state;
|
switchData->maximized = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowSwitchWidget::FocusChanged(int state)
|
void WindowSwitchWidget::FocusChanged(int state)
|
||||||
{
|
{
|
||||||
if (loading || !switchData)
|
if (loading || !switchData) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switchData->focus = state;
|
switchData->focus = state;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,9 @@ void SwitcherData::Prune()
|
|||||||
{
|
{
|
||||||
for (size_t i = 0; i < windowSwitches.size(); i++) {
|
for (size_t i = 0; i < windowSwitches.size(); i++) {
|
||||||
WindowSwitch &s = windowSwitches[i];
|
WindowSwitch &s = windowSwitches[i];
|
||||||
if (!s.valid())
|
if (!s.valid()) {
|
||||||
windowSwitches.erase(windowSwitches.begin() + i--);
|
windowSwitches.erase(windowSwitches.begin() + i--);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nonMatchingScene && !WeakSourceValid(nonMatchingScene)) {
|
if (nonMatchingScene && !WeakSourceValid(nonMatchingScene)) {
|
||||||
@@ -16,66 +17,69 @@ void SwitcherData::Prune()
|
|||||||
|
|
||||||
for (size_t i = 0; i < randomSwitches.size(); i++) {
|
for (size_t i = 0; i < randomSwitches.size(); i++) {
|
||||||
RandomSwitch &s = randomSwitches[i];
|
RandomSwitch &s = randomSwitches[i];
|
||||||
if (!s.valid())
|
if (!s.valid()) {
|
||||||
randomSwitches.erase(randomSwitches.begin() + i--);
|
randomSwitches.erase(randomSwitches.begin() + i--);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < screenRegionSwitches.size(); i++) {
|
for (size_t i = 0; i < screenRegionSwitches.size(); i++) {
|
||||||
ScreenRegionSwitch &s = screenRegionSwitches[i];
|
ScreenRegionSwitch &s = screenRegionSwitches[i];
|
||||||
if (!s.valid())
|
if (!s.valid()) {
|
||||||
screenRegionSwitches.erase(
|
screenRegionSwitches.erase(
|
||||||
screenRegionSwitches.begin() + i--);
|
screenRegionSwitches.begin() + i--);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < pauseScenesSwitches.size(); i++) {
|
for (size_t i = 0; i < pauseEntries.size(); i++) {
|
||||||
OBSWeakSource &scene = pauseScenesSwitches[i];
|
PauseEntry &s = pauseEntries[i];
|
||||||
if (!WeakSourceValid(scene))
|
if (!s.valid()) {
|
||||||
pauseScenesSwitches.erase(pauseScenesSwitches.begin() +
|
pauseEntries.erase(pauseEntries.begin() + i--);
|
||||||
i--);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < sceneSequenceSwitches.size(); i++) {
|
for (size_t i = 0; i < sceneSequenceSwitches.size(); i++) {
|
||||||
SceneSequenceSwitch &s = sceneSequenceSwitches[i];
|
SceneSequenceSwitch &s = sceneSequenceSwitches[i];
|
||||||
if (!s.valid())
|
if (!s.valid()) {
|
||||||
sceneSequenceSwitches.erase(
|
sceneSequenceSwitches.erase(
|
||||||
sceneSequenceSwitches.begin() + i--);
|
sceneSequenceSwitches.begin() + i--);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!WeakSourceValid(autoStopScene)) {
|
|
||||||
autoStopScene = nullptr;
|
|
||||||
autoStopEnable = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < sceneTransitions.size(); i++) {
|
for (size_t i = 0; i < sceneTransitions.size(); i++) {
|
||||||
SceneTransition &s = sceneTransitions[i];
|
SceneTransition &s = sceneTransitions[i];
|
||||||
if (!s.valid())
|
if (!s.valid()) {
|
||||||
sceneTransitions.erase(sceneTransitions.begin() + i--);
|
sceneTransitions.erase(sceneTransitions.begin() + i--);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < defaultSceneTransitions.size(); i++) {
|
for (size_t i = 0; i < defaultSceneTransitions.size(); i++) {
|
||||||
DefaultSceneTransition &s = defaultSceneTransitions[i];
|
DefaultSceneTransition &s = defaultSceneTransitions[i];
|
||||||
if (!s.valid())
|
if (!s.valid()) {
|
||||||
defaultSceneTransitions.erase(
|
defaultSceneTransitions.erase(
|
||||||
defaultSceneTransitions.begin() + i--);
|
defaultSceneTransitions.begin() + i--);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < executableSwitches.size(); i++) {
|
for (size_t i = 0; i < executableSwitches.size(); i++) {
|
||||||
ExecutableSwitch &s = executableSwitches[i];
|
ExecutableSwitch &s = executableSwitches[i];
|
||||||
if (!s.valid())
|
if (!s.valid()) {
|
||||||
executableSwitches.erase(executableSwitches.begin() +
|
executableSwitches.erase(executableSwitches.begin() +
|
||||||
i--);
|
i--);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < fileSwitches.size(); i++) {
|
for (size_t i = 0; i < fileSwitches.size(); i++) {
|
||||||
FileSwitch &s = fileSwitches[i];
|
FileSwitch &s = fileSwitches[i];
|
||||||
if (!s.valid())
|
if (!s.valid()) {
|
||||||
fileSwitches.erase(fileSwitches.begin() + i--);
|
fileSwitches.erase(fileSwitches.begin() + i--);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < timeSwitches.size(); i++) {
|
for (size_t i = 0; i < timeSwitches.size(); i++) {
|
||||||
TimeSwitch &s = timeSwitches[i];
|
TimeSwitch &s = timeSwitches[i];
|
||||||
if (!s.valid())
|
if (!s.valid()) {
|
||||||
timeSwitches.erase(timeSwitches.begin() + i--);
|
timeSwitches.erase(timeSwitches.begin() + i--);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!idleData.valid()) {
|
if (!idleData.valid()) {
|
||||||
@@ -84,13 +88,33 @@ void SwitcherData::Prune()
|
|||||||
|
|
||||||
for (size_t i = 0; i < mediaSwitches.size(); i++) {
|
for (size_t i = 0; i < mediaSwitches.size(); i++) {
|
||||||
MediaSwitch &s = mediaSwitches[i];
|
MediaSwitch &s = mediaSwitches[i];
|
||||||
if (!s.valid())
|
if (!s.valid()) {
|
||||||
mediaSwitches.erase(mediaSwitches.begin() + i--);
|
mediaSwitches.erase(mediaSwitches.begin() + i--);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < audioSwitches.size(); i++) {
|
for (size_t i = 0; i < audioSwitches.size(); i++) {
|
||||||
AudioSwitch &s = audioSwitches[i];
|
AudioSwitch &s = audioSwitches[i];
|
||||||
if (!s.valid())
|
if (!s.valid()) {
|
||||||
audioSwitches.erase(audioSwitches.begin() + i--);
|
audioSwitches.erase(audioSwitches.begin() + i--);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &sg : sceneGroups) {
|
||||||
|
for (size_t i = 0; i < sg.scenes.size(); i++)
|
||||||
|
if (!WeakSourceValid(sg.scenes[i])) {
|
||||||
|
sg.scenes.erase(sg.scenes.begin() + i--);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SwitcherData::versionChanged(obs_data_t *obj, std::string currentVersion)
|
||||||
|
{
|
||||||
|
std::string previousVersion = obs_data_get_string(obj, "version");
|
||||||
|
return previousVersion != currentVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitcherData::saveVersion(obs_data_t *obj, std::string currentVersion)
|
||||||
|
{
|
||||||
|
obs_data_set_string(obj, "version", currentVersion.c_str());
|
||||||
|
}
|
||||||
|
|||||||
@@ -82,7 +82,10 @@ VolControl::VolControl(OBSSource source_, bool vertical)
|
|||||||
nameLabel = new QLabel();
|
nameLabel = new QLabel();
|
||||||
volLabel = new QLabel();
|
volLabel = new QLabel();
|
||||||
|
|
||||||
QString sourceName = obs_source_get_name(source);
|
QString sourceName = "";
|
||||||
|
if (source) {
|
||||||
|
obs_source_get_name(source);
|
||||||
|
}
|
||||||
setObjectName(sourceName);
|
setObjectName(sourceName);
|
||||||
|
|
||||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||||
|
|||||||
@@ -15,8 +15,9 @@ static bool GetWindowTitle(HWND window, std::string &title)
|
|||||||
std::wstring wtitle;
|
std::wstring wtitle;
|
||||||
|
|
||||||
wtitle.resize(len);
|
wtitle.resize(len);
|
||||||
if (!GetWindowTextW(window, &wtitle[0], (int)len + 1))
|
if (!GetWindowTextW(window, &wtitle[0], (int)len + 1)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
len = os_wcs_to_utf8(wtitle.c_str(), 0, nullptr, 0);
|
len = os_wcs_to_utf8(wtitle.c_str(), 0, nullptr, 0);
|
||||||
title.resize(len);
|
title.resize(len);
|
||||||
@@ -29,16 +30,19 @@ static bool WindowValid(HWND window)
|
|||||||
LONG_PTR styles;
|
LONG_PTR styles;
|
||||||
DWORD id;
|
DWORD id;
|
||||||
|
|
||||||
if (!IsWindowVisible(window))
|
if (!IsWindowVisible(window)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
GetWindowThreadProcessId(window, &id);
|
GetWindowThreadProcessId(window, &id);
|
||||||
if (id == GetCurrentProcessId())
|
if (id == GetCurrentProcessId()) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
styles = GetWindowLongPtr(window, GWL_STYLE);
|
styles = GetWindowLongPtr(window, GWL_STYLE);
|
||||||
|
|
||||||
if (styles & WS_CHILD)
|
if (styles & WS_CHILD) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -51,8 +55,9 @@ BOOL CALLBACK GetTitleCB(HWND hwnd, LPARAM lParam)
|
|||||||
|
|
||||||
std::string title;
|
std::string title;
|
||||||
GetWindowTitle(hwnd, title);
|
GetWindowTitle(hwnd, title);
|
||||||
if (title.empty())
|
if (title.empty()) {
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::string> &titles =
|
std::vector<std::string> &titles =
|
||||||
*reinterpret_cast<std::vector<std::string> *>(lParam);
|
*reinterpret_cast<std::vector<std::string> *>(lParam);
|
||||||
@@ -68,8 +73,9 @@ VOID EnumWindowsWithMetro(__in WNDENUMPROC lpEnumFunc, __in LPARAM lParam)
|
|||||||
|
|
||||||
while (i < MAX_SEARCH &&
|
while (i < MAX_SEARCH &&
|
||||||
(childWindow = FindWindowEx(NULL, childWindow, NULL, NULL))) {
|
(childWindow = FindWindowEx(NULL, childWindow, NULL, NULL))) {
|
||||||
if (!lpEnumFunc(childWindow, lParam))
|
if (!lpEnumFunc(childWindow, lParam)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,6 +95,9 @@ void GetWindowList(QStringList &windows)
|
|||||||
for (auto window : w) {
|
for (auto window : w) {
|
||||||
windows << QString::fromStdString(window);
|
windows << QString::fromStdString(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add entry for OBS Studio itself, see GetCurrentWindowTitle
|
||||||
|
windows << QString("OBS");
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetCurrentWindowTitle(std::string &title)
|
void GetCurrentWindowTitle(std::string &title)
|
||||||
@@ -97,10 +106,10 @@ void GetCurrentWindowTitle(std::string &title)
|
|||||||
DWORD pid;
|
DWORD pid;
|
||||||
DWORD thid;
|
DWORD thid;
|
||||||
thid = GetWindowThreadProcessId(window, &pid);
|
thid = GetWindowThreadProcessId(window, &pid);
|
||||||
/*GetWindowText will freeze if the control it is reading was created in another thread.
|
// GetWindowText will freeze if the control it is reading was created in another thread.
|
||||||
It does not directly read the control.Instead,
|
// It does not directly read the control.
|
||||||
it waits for the thread that created the control to process a WM_GETTEXT message.
|
// Instead it waits for the thread that created the control to process a WM_GETTEXT message.
|
||||||
So if that thread is frozen in a WaitFor... call you have a deadlock.*/
|
// So if that thread is frozen in a WaitFor... call you have a deadlock.
|
||||||
if (GetCurrentProcessId() == pid) {
|
if (GetCurrentProcessId() == pid) {
|
||||||
title = "OBS";
|
title = "OBS";
|
||||||
return;
|
return;
|
||||||
@@ -137,8 +146,9 @@ bool isMaximized(std::string &title)
|
|||||||
HWND hwnd = NULL;
|
HWND hwnd = NULL;
|
||||||
|
|
||||||
hwnd = getHWNDfromTitle(title);
|
hwnd = getHWNDfromTitle(title);
|
||||||
if (!hwnd)
|
if (!hwnd) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
monitorInfo.cbSize = sizeof(MONITORINFO);
|
monitorInfo.cbSize = sizeof(MONITORINFO);
|
||||||
GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST),
|
GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST),
|
||||||
@@ -167,8 +177,9 @@ bool isFullscreen(std::string &title)
|
|||||||
HWND hwnd = NULL;
|
HWND hwnd = NULL;
|
||||||
hwnd = getHWNDfromTitle(title);
|
hwnd = getHWNDfromTitle(title);
|
||||||
|
|
||||||
if (!hwnd)
|
if (!hwnd) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
monitorInfo.cbSize = sizeof(MONITORINFO);
|
monitorInfo.cbSize = sizeof(MONITORINFO);
|
||||||
GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST),
|
GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST),
|
||||||
@@ -194,8 +205,9 @@ void GetProcessList(QStringList &processes)
|
|||||||
PROCESSENTRY32 procEntry;
|
PROCESSENTRY32 procEntry;
|
||||||
|
|
||||||
procSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
procSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||||
if (procSnapshot == INVALID_HANDLE_VALUE)
|
if (procSnapshot == INVALID_HANDLE_VALUE) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
procEntry.dwSize = sizeof(PROCESSENTRY32);
|
procEntry.dwSize = sizeof(PROCESSENTRY32);
|
||||||
|
|
||||||
@@ -206,12 +218,15 @@ void GetProcessList(QStringList &processes)
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
QString tempexe = QString::fromWCharArray(procEntry.szExeFile);
|
QString tempexe = QString::fromWCharArray(procEntry.szExeFile);
|
||||||
if (tempexe == "System")
|
if (tempexe == "System") {
|
||||||
continue;
|
continue;
|
||||||
if (tempexe == "[System Process]")
|
}
|
||||||
|
if (tempexe == "[System Process]") {
|
||||||
continue;
|
continue;
|
||||||
if (processes.contains(tempexe))
|
}
|
||||||
|
if (processes.contains(tempexe)) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
processes.append(tempexe);
|
processes.append(tempexe);
|
||||||
} while (Process32Next(procSnapshot, &procEntry));
|
} while (Process32Next(procSnapshot, &procEntry));
|
||||||
|
|
||||||
@@ -228,8 +243,9 @@ bool isInFocus(const QString &executable)
|
|||||||
|
|
||||||
HANDLE process = OpenProcess(
|
HANDLE process = OpenProcess(
|
||||||
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId);
|
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId);
|
||||||
if (process == NULL)
|
if (process == NULL) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
WCHAR executablePath[600];
|
WCHAR executablePath[600];
|
||||||
GetModuleFileNameEx(process, 0, executablePath, 600);
|
GetModuleFileNameEx(process, 0, executablePath, 600);
|
||||||
@@ -251,8 +267,9 @@ int getLastInputTime()
|
|||||||
{
|
{
|
||||||
LASTINPUTINFO lastInputInfo;
|
LASTINPUTINFO lastInputInfo;
|
||||||
lastInputInfo.cbSize = sizeof(LASTINPUTINFO);
|
lastInputInfo.cbSize = sizeof(LASTINPUTINFO);
|
||||||
if (GetLastInputInfo(&lastInputInfo))
|
if (GetLastInputInfo(&lastInputInfo)) {
|
||||||
return lastInputInfo.dwTime;
|
return lastInputInfo.dwTime;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user