mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-09-07 17:16:00 -05:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
214821b69f | ||
|
|
7edb6eb6c1 |
59
.github/workflows/build.yml
vendored
59
.github/workflows/build.yml
vendored
@@ -19,12 +19,12 @@ jobs:
|
|||||||
MACOS_DEPS_VERSION: '2020-08-30'
|
MACOS_DEPS_VERSION: '2020-08-30'
|
||||||
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,12 +179,12 @@ 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.PLUGIN_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.PLUGIN_NAME }}/bin/64bit/${{ env.LIB_NAME }}.so
|
||||||
tar -cvzf "${FILE_NAME}" ${{ env.PLUGIN_NAME }}
|
tar -cvzf "${FILE_NAME}" ${{ env.PLUGIN_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'
|
||||||
@@ -194,14 +197,14 @@ jobs:
|
|||||||
CMAKE_SYSTEM_VERSION: "10.0.18363.657"
|
CMAKE_SYSTEM_VERSION: "10.0.18363.657"
|
||||||
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
|
||||||
@@ -222,7 +225,7 @@ jobs:
|
|||||||
mkdir ./build
|
mkdir ./build
|
||||||
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 -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 .\build64\obs-studio.sln
|
||||||
- name: Package
|
- name: Package
|
||||||
@@ -230,12 +233,12 @@ jobs:
|
|||||||
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 }}-win64.zip"
|
||||||
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 .\build64\rundir\RelWithDebInfo\obs-plugins\64bit\ .\build\obs-plugins\64bit ${{ env.LIB_NAME }}.* /E /XF .gitignore
|
||||||
7z a ${env:FILE_NAME} .\build\*
|
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: '${{ env.FILE_NAME }}'
|
||||||
path: '*-win64.zip'
|
path: '*-win64.zip'
|
||||||
@@ -248,14 +251,14 @@ jobs:
|
|||||||
CMAKE_SYSTEM_VERSION: "10.0.18363.657"
|
CMAKE_SYSTEM_VERSION: "10.0.18363.657"
|
||||||
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
|
||||||
@@ -276,7 +279,7 @@ jobs:
|
|||||||
mkdir ./build
|
mkdir ./build
|
||||||
mkdir ./build32
|
mkdir ./build32
|
||||||
cd ./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 ..
|
cmake -G"${{ env.CMAKE_GENERATOR }}" -A"Win32" -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DBUILD_BROWSER=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
|
- name: Build
|
||||||
run: msbuild /m /p:Configuration=RelWithDebInfo .\build32\obs-studio.sln
|
run: msbuild /m /p:Configuration=RelWithDebInfo .\build32\obs-studio.sln
|
||||||
- name: Package
|
- name: Package
|
||||||
@@ -284,12 +287,12 @@ jobs:
|
|||||||
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 }}-win32.zip"
|
$env:FILE_NAME="${{ env.PLUGIN_NAME }}-${env:FILE_DATE}-${{ github.sha }}-win32.zip"
|
||||||
echo "::set-env name=FILE_NAME::${env:FILE_NAME}"
|
echo "FILE_NAME=${env:FILE_NAME}" >> ${env:GITHUB_ENV}
|
||||||
robocopy .\build32\rundir\RelWithDebInfo\obs-plugins\32bit\ .\build\obs-plugins\32bit ${{ env.LIB_NAME }}.* /E /XF .gitignore
|
robocopy .\build32\rundir\RelWithDebInfo\obs-plugins\32bit\ .\build\obs-plugins\32bit ${{ env.LIB_NAME }}.* /E /XF .gitignore
|
||||||
7z a ${env:FILE_NAME} .\build\*
|
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: '${{ env.FILE_NAME }}'
|
||||||
path: '*-win32.zip'
|
path: '*-win32.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
|
||||||
@@ -2,6 +2,12 @@ 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(BUILD_OUT_OF_TREE)
|
if(BUILD_OUT_OF_TREE)
|
||||||
# out of tree builds
|
# out of tree builds
|
||||||
# credits to c3r1c3
|
# credits to c3r1c3
|
||||||
@@ -46,8 +52,9 @@ if(BUILD_OUT_OF_TREE)
|
|||||||
src/headers/switch-time.hpp
|
src/headers/switch-time.hpp
|
||||||
src/headers/switch-transitions.hpp
|
src/headers/switch-transitions.hpp
|
||||||
src/headers/switch-window.hpp
|
src/headers/switch-window.hpp
|
||||||
src/headers/swtich-sequence.hpp
|
src/headers/switch-sequence.hpp
|
||||||
src/headers/switch-generic.hpp
|
src/headers/switch-generic.hpp
|
||||||
|
src/headers/version.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(advanced-scene-switcher_SOURCES
|
set(advanced-scene-switcher_SOURCES
|
||||||
@@ -70,7 +77,10 @@ if(BUILD_OUT_OF_TREE)
|
|||||||
src/switch-random.cpp
|
src/switch-random.cpp
|
||||||
src/switch-time.cpp
|
src/switch-time.cpp
|
||||||
src/switch-audio.cpp
|
src/switch-audio.cpp
|
||||||
|
src/switch-generic.cpp
|
||||||
src/curl-helper.cpp
|
src/curl-helper.cpp
|
||||||
|
src/volume-control.cpp
|
||||||
|
src/version.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(advanced-scene-switcher_UI
|
set(advanced-scene-switcher_UI
|
||||||
@@ -194,8 +204,9 @@ else ()
|
|||||||
src/headers/switch-time.hpp
|
src/headers/switch-time.hpp
|
||||||
src/headers/switch-transitions.hpp
|
src/headers/switch-transitions.hpp
|
||||||
src/headers/switch-window.hpp
|
src/headers/switch-window.hpp
|
||||||
src/headers/swtich-sequence.hpp
|
src/headers/switch-sequence.hpp
|
||||||
src/headers/switch-generic.hpp
|
src/headers/switch-generic.hpp
|
||||||
|
src/headers/version.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(advanced-scene-switcher_SOURCES
|
set(advanced-scene-switcher_SOURCES
|
||||||
@@ -218,8 +229,10 @@ else ()
|
|||||||
src/switch-random.cpp
|
src/switch-random.cpp
|
||||||
src/switch-time.cpp
|
src/switch-time.cpp
|
||||||
src/switch-audio.cpp
|
src/switch-audio.cpp
|
||||||
|
src/switch-generic.cpp
|
||||||
src/curl-helper.cpp
|
src/curl-helper.cpp
|
||||||
src/volume-control.cpp
|
src/volume-control.cpp
|
||||||
|
src/version.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(advanced-scene-switcher_UI
|
set(advanced-scene-switcher_UI
|
||||||
|
|||||||
@@ -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/
|
||||||
|
|||||||
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;
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,30 +1,23 @@
|
|||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QDir>
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
|
#include <QtGui/qstandarditemmodel.h>
|
||||||
#include <condition_variable>
|
#include <QPropertyAnimation>
|
||||||
#include <chrono>
|
#include <QGraphicsColorizeEffect>
|
||||||
#include <vector>
|
|
||||||
#include <mutex>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
#include <obs-frontend-api.h>
|
#include <obs-frontend-api.h>
|
||||||
#include <obs-module.h>
|
|
||||||
#include <obs.hpp>
|
|
||||||
#include <util/util.hpp>
|
#include <util/util.hpp>
|
||||||
|
|
||||||
#include "headers/switcher-data-structs.hpp"
|
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
#include "headers/utility.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
|
||||||
********************************************************************************/
|
********************************************************************************/
|
||||||
SceneSwitcher::SceneSwitcher(QWidget *parent)
|
AdvSceneSwitcher::AdvSceneSwitcher(QWidget *parent)
|
||||||
: QDialog(parent), ui(new Ui_SceneSwitcher)
|
: QDialog(parent), ui(new Ui_AdvSceneSwitcher)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
@@ -34,46 +27,7 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
|
|||||||
loadUI();
|
loadUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::populateSceneSelection(QComboBox *sel, bool addPrevious)
|
void AdvSceneSwitcher::loadUI()
|
||||||
{
|
|
||||||
BPtr<char *> scenes = obs_frontend_get_scene_names();
|
|
||||||
char **temp = scenes;
|
|
||||||
while (*temp) {
|
|
||||||
const char *name = *temp;
|
|
||||||
sel->addItem(name);
|
|
||||||
temp++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (addPrevious)
|
|
||||||
sel->addItem(previous_scene_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::populateTransitionSelection(QComboBox *sel)
|
|
||||||
{
|
|
||||||
obs_frontend_source_list *transitions = new obs_frontend_source_list();
|
|
||||||
obs_frontend_get_transitions(transitions);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < transitions->sources.num; i++) {
|
|
||||||
const char *name =
|
|
||||||
obs_source_get_name(transitions->sources.array[i]);
|
|
||||||
sel->addItem(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
obs_frontend_source_list_free(transitions);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::populateWindowSelection(QComboBox *sel)
|
|
||||||
{
|
|
||||||
std::vector<std::string> windows;
|
|
||||||
GetWindowList(windows);
|
|
||||||
sort(windows.begin(), windows.end());
|
|
||||||
|
|
||||||
for (std::string &window : windows) {
|
|
||||||
sel->addItem(window.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::loadUI()
|
|
||||||
{
|
{
|
||||||
#if __APPLE__
|
#if __APPLE__
|
||||||
setMinimumHeight(700);
|
setMinimumHeight(700);
|
||||||
@@ -97,6 +51,210 @@ void SceneSwitcher::loadUI()
|
|||||||
loading = false;
|
loading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/********************************************************************************
|
||||||
|
* UI helpers
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
void addSelectionEntry(QComboBox *sel, const char *description,
|
||||||
|
const char *tooltip = "")
|
||||||
|
{
|
||||||
|
sel->addItem(description);
|
||||||
|
|
||||||
|
if (strcmp(tooltip, "") != 0) {
|
||||||
|
sel->setItemData(0, tooltip, Qt::ToolTipRole);
|
||||||
|
}
|
||||||
|
|
||||||
|
QStandardItemModel *model =
|
||||||
|
qobject_cast<QStandardItemModel *>(sel->model());
|
||||||
|
QModelIndex firstIndex =
|
||||||
|
model->index(0, sel->modelColumn(), sel->rootModelIndex());
|
||||||
|
QStandardItem *firstItem = model->itemFromIndex(firstIndex);
|
||||||
|
firstItem->setSelectable(false);
|
||||||
|
firstItem->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::populateSceneSelection(QComboBox *sel, bool addPrevious,
|
||||||
|
bool addSelect)
|
||||||
|
{
|
||||||
|
if (addSelect)
|
||||||
|
addSelectionEntry(sel, "--select scene--",
|
||||||
|
"invalid entries will not be saved");
|
||||||
|
|
||||||
|
BPtr<char *> scenes = obs_frontend_get_scene_names();
|
||||||
|
char **temp = scenes;
|
||||||
|
while (*temp) {
|
||||||
|
const char *name = *temp;
|
||||||
|
sel->addItem(name);
|
||||||
|
temp++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addPrevious)
|
||||||
|
sel->addItem(previous_scene_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::populateTransitionSelection(QComboBox *sel,
|
||||||
|
bool addSelect)
|
||||||
|
{
|
||||||
|
if (addSelect)
|
||||||
|
addSelectionEntry(sel, "--select transition--");
|
||||||
|
|
||||||
|
obs_frontend_source_list *transitions = new obs_frontend_source_list();
|
||||||
|
obs_frontend_get_transitions(transitions);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < transitions->sources.num; i++) {
|
||||||
|
const char *name =
|
||||||
|
obs_source_get_name(transitions->sources.array[i]);
|
||||||
|
sel->addItem(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_frontend_source_list_free(transitions);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::populateWindowSelection(QComboBox *sel, bool addSelect)
|
||||||
|
{
|
||||||
|
if (addSelect)
|
||||||
|
addSelectionEntry(sel, "--select window--");
|
||||||
|
|
||||||
|
std::vector<std::string> windows;
|
||||||
|
GetWindowList(windows);
|
||||||
|
sort(windows.begin(), windows.end());
|
||||||
|
|
||||||
|
for (std::string &window : windows) {
|
||||||
|
sel->addItem(window.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
sel->setItemData(
|
||||||
|
0,
|
||||||
|
"Use \"OBS\" to specify OBS window\nUse \"Task Switching\"to specify ALT + TAB",
|
||||||
|
Qt::ToolTipRole);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::populateAudioSelection(QComboBox *sel, bool addSelect)
|
||||||
|
{
|
||||||
|
if (addSelect)
|
||||||
|
addSelectionEntry(sel, "--select audio source--",
|
||||||
|
"invalid entries will not be saved");
|
||||||
|
|
||||||
|
auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */
|
||||||
|
{
|
||||||
|
QComboBox *combo = reinterpret_cast<QComboBox *>(data);
|
||||||
|
uint32_t flags = obs_source_get_output_flags(source);
|
||||||
|
|
||||||
|
if ((flags & OBS_SOURCE_AUDIO) != 0) {
|
||||||
|
const char *name = obs_source_get_name(source);
|
||||||
|
combo->addItem(name);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
obs_enum_sources(sourceEnum, sel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::populateMediaSelection(QComboBox *sel, bool addSelect)
|
||||||
|
{
|
||||||
|
if (addSelect)
|
||||||
|
addSelectionEntry(sel, "--select media source--",
|
||||||
|
"invalid entries will not be saved");
|
||||||
|
|
||||||
|
auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */
|
||||||
|
{
|
||||||
|
QComboBox *combo = reinterpret_cast<QComboBox *>(data);
|
||||||
|
std::string sourceId = obs_source_get_id(source);
|
||||||
|
if (sourceId.compare("ffmpeg_source") == 0 ||
|
||||||
|
sourceId.compare("vlc_source") == 0) {
|
||||||
|
const char *name = obs_source_get_name(source);
|
||||||
|
combo->addItem(name);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
obs_enum_sources(sourceEnum, sel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::populateProcessSelection(QComboBox *sel, bool addSelect)
|
||||||
|
{
|
||||||
|
if (addSelect)
|
||||||
|
addSelectionEntry(sel, "--select process--");
|
||||||
|
|
||||||
|
QStringList processes;
|
||||||
|
GetProcessList(processes);
|
||||||
|
for (QString &process : processes)
|
||||||
|
sel->addItem(process);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AdvSceneSwitcher::listMoveUp(QListWidget *list)
|
||||||
|
{
|
||||||
|
int index = list->currentRow();
|
||||||
|
if (index == -1 || index == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QWidget *row = list->itemWidget(list->currentItem());
|
||||||
|
QListWidgetItem *itemN = list->currentItem()->clone();
|
||||||
|
|
||||||
|
list->insertItem(index - 1, itemN);
|
||||||
|
list->setItemWidget(itemN, row);
|
||||||
|
|
||||||
|
list->takeItem(index + 1);
|
||||||
|
list->setCurrentRow(index - 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AdvSceneSwitcher::listMoveDown(QListWidget *list)
|
||||||
|
{
|
||||||
|
int index = list->currentRow();
|
||||||
|
if (index == -1 || index == list->count() - 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QWidget *row = list->itemWidget(list->currentItem());
|
||||||
|
QListWidgetItem *itemN = list->currentItem()->clone();
|
||||||
|
|
||||||
|
list->insertItem(index + 2, itemN);
|
||||||
|
list->setItemWidget(itemN, row);
|
||||||
|
|
||||||
|
list->takeItem(index);
|
||||||
|
list->setCurrentRow(index + 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMetaObject::Connection AdvSceneSwitcher::PulseWidget(QWidget *widget,
|
||||||
|
QColor endColor,
|
||||||
|
QColor startColor,
|
||||||
|
QString specifier)
|
||||||
|
{
|
||||||
|
if (switcher->disableHints)
|
||||||
|
return QMetaObject::Connection();
|
||||||
|
|
||||||
|
widget->setStyleSheet(specifier + "{ \
|
||||||
|
border-style: outset; \
|
||||||
|
border-width: 2px; \
|
||||||
|
border-radius: 10px; \
|
||||||
|
border-color: rgb(0,0,0,0) \
|
||||||
|
}");
|
||||||
|
|
||||||
|
QGraphicsColorizeEffect *eEffect = new QGraphicsColorizeEffect(widget);
|
||||||
|
widget->setGraphicsEffect(eEffect);
|
||||||
|
QPropertyAnimation *paAnimation =
|
||||||
|
new QPropertyAnimation(eEffect, "color");
|
||||||
|
paAnimation->setStartValue(startColor);
|
||||||
|
paAnimation->setEndValue(endColor);
|
||||||
|
paAnimation->setDuration(1000);
|
||||||
|
// play backward to return to original state on timer end
|
||||||
|
paAnimation->setDirection(QAbstractAnimation::Backward);
|
||||||
|
|
||||||
|
auto con = QWidget::connect(
|
||||||
|
paAnimation, &QPropertyAnimation::finished, [paAnimation]() {
|
||||||
|
QTimer::singleShot(1000, [paAnimation] {
|
||||||
|
paAnimation->start();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
paAnimation->start();
|
||||||
|
|
||||||
|
return con;
|
||||||
|
}
|
||||||
|
|
||||||
/********************************************************************************
|
/********************************************************************************
|
||||||
* Saving and loading
|
* Saving and loading
|
||||||
********************************************************************************/
|
********************************************************************************/
|
||||||
@@ -169,40 +327,51 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
|||||||
********************************************************************************/
|
********************************************************************************/
|
||||||
void SwitcherData::Thread()
|
void SwitcherData::Thread()
|
||||||
{
|
{
|
||||||
blog(LOG_INFO, "Advanced Scene Switcher started");
|
blog(LOG_INFO, "started");
|
||||||
int sleep = 0;
|
int sleep = 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,
|
|
||||||
"Advanced Scene Switcher sleep for %d",
|
|
||||||
sleep);
|
|
||||||
} else {
|
} else {
|
||||||
duration = std::chrono::milliseconds(interval);
|
duration =
|
||||||
if (verbose)
|
std::chrono::milliseconds(interval) - runTime;
|
||||||
blog(LOG_INFO,
|
if (duration.count() < 0)
|
||||||
"Advanced Scene Switcher sleep for %d",
|
duration = std::chrono::milliseconds(0);
|
||||||
interval);
|
|
||||||
}
|
}
|
||||||
sleep = 0;
|
|
||||||
switcher->Prune();
|
|
||||||
writeSceneInfoToFile();
|
|
||||||
//sleep for a bit
|
//sleep for a bit
|
||||||
|
if (verbose)
|
||||||
|
blog(LOG_INFO, "sleep for %d", duration.count());
|
||||||
cv.wait_for(lock, duration);
|
cv.wait_for(lock, duration);
|
||||||
|
|
||||||
|
startTime = std::chrono::high_resolution_clock::now();
|
||||||
|
sleep = 0;
|
||||||
|
|
||||||
|
switcher->Prune();
|
||||||
|
|
||||||
if (switcher->stop) {
|
if (switcher->stop) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
setDefaultSceneTransitions();
|
|
||||||
|
|
||||||
if (autoStopEnable) {
|
if (autoStopEnable) {
|
||||||
autoStopStreamAndRecording();
|
autoStopStreamAndRecording();
|
||||||
}
|
}
|
||||||
@@ -215,6 +384,8 @@ void SwitcherData::Thread()
|
|||||||
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:
|
||||||
@@ -228,7 +399,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);
|
||||||
@@ -239,11 +409,7 @@ void SwitcherData::Thread()
|
|||||||
break;
|
break;
|
||||||
case round_trip_func:
|
case round_trip_func:
|
||||||
checkSceneSequence(match, scene, transition,
|
checkSceneSequence(match, scene, transition,
|
||||||
lock);
|
lock);
|
||||||
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);
|
||||||
@@ -264,65 +430,52 @@ void SwitcherData::Thread()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!match && switchIfNotMatching == SWITCH &&
|
checkNoMatchSwitch(match, scene, transition, sleep);
|
||||||
nonMatchingScene) {
|
|
||||||
match = true;
|
// After this point we will call frontend functions
|
||||||
scene = nonMatchingScene;
|
// obs_frontend_set_current_scene() and
|
||||||
transition = nullptr;
|
// obs_frontend_set_current_transition()
|
||||||
}
|
//
|
||||||
if (!match && switchIfNotMatching == RANDOM_SWITCH) {
|
// During this time SaveSceneSwitcher() could be called
|
||||||
checkRandom(match, scene, transition, sleep);
|
// 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, "Advanced Scene Switcher 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)
|
|
||||||
{
|
{
|
||||||
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,
|
blog(LOG_INFO, "switched scene");
|
||||||
"Advanced Scene Switcher 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())) {
|
||||||
@@ -345,6 +498,15 @@ void SwitcherData::Stop()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
********************************************************************************/
|
********************************************************************************/
|
||||||
@@ -363,7 +525,6 @@ 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();
|
||||||
@@ -373,15 +534,20 @@ void handleSceneChange(SwitcherData *s)
|
|||||||
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->previousScene2 != ws) {
|
||||||
s->previousScene = s->PreviousScene2;
|
s->previousScene = s->previousScene2;
|
||||||
s->PreviousScene2 = ws;
|
s->previousScene2 = ws;
|
||||||
}
|
}
|
||||||
|
|
||||||
//reset autostart
|
//reset events only hanled on scene change
|
||||||
s->autoStartedRecently = false;
|
s->autoStartedRecently = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void handleTransitionStop(SwitcherData *s)
|
||||||
|
{
|
||||||
|
s->checkedDefTransition = false;
|
||||||
|
}
|
||||||
|
|
||||||
void setLiveTime(SwitcherData *s)
|
void setLiveTime(SwitcherData *s)
|
||||||
{
|
{
|
||||||
s->liveTime = QDateTime::currentDateTime();
|
s->liveTime = QDateTime::currentDateTime();
|
||||||
@@ -392,6 +558,9 @@ void resetLiveTime(SwitcherData *s)
|
|||||||
s->liveTime = QDateTime();
|
s->liveTime = QDateTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
@@ -401,6 +570,9 @@ 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:
|
||||||
case OBS_FRONTEND_EVENT_STREAMING_STARTED:
|
case OBS_FRONTEND_EVENT_STREAMING_STARTED:
|
||||||
setLiveTime((SwitcherData *)switcher);
|
setLiveTime((SwitcherData *)switcher);
|
||||||
@@ -416,6 +588,8 @@ 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");
|
"Advanced Scene Switcher");
|
||||||
|
|
||||||
@@ -429,7 +603,7 @@ extern "C" void InitSceneSwitcher()
|
|||||||
QMainWindow *window =
|
QMainWindow *window =
|
||||||
(QMainWindow *)obs_frontend_get_main_window();
|
(QMainWindow *)obs_frontend_get_main_window();
|
||||||
|
|
||||||
SceneSwitcher ss(window);
|
AdvSceneSwitcher ss(window);
|
||||||
ss.exec();
|
ss.exec();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -23,11 +23,11 @@ bool resolveCurl()
|
|||||||
(cleanupFunction)loaded_curl_lib->resolve("curl_easy_cleanup");
|
(cleanupFunction)loaded_curl_lib->resolve("curl_easy_cleanup");
|
||||||
|
|
||||||
if (f_curl_init && f_curl_setopt && f_curl_perform && f_curl_cleanup) {
|
if (f_curl_init && f_curl_setopt && f_curl_perform && f_curl_cleanup) {
|
||||||
blog(LOG_INFO, "curl loaded successfully");
|
blog(LOG_INFO, "[adv-ss] curl loaded successfully");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
blog(LOG_INFO, "curl symbols not resolved");
|
blog(LOG_INFO, "[adv-ss] curl symbols not resolved");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,13 +43,14 @@ bool loadCurl()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (QString path : locations) {
|
for (QString path : locations) {
|
||||||
blog(LOG_INFO, "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));
|
||||||
|
|
||||||
if (libPath.exists() && libPath.isFile()) {
|
if (libPath.exists() && libPath.isFile()) {
|
||||||
QString libFilePath = libPath.absoluteFilePath();
|
QString libFilePath = libPath.absoluteFilePath();
|
||||||
blog(LOG_INFO, "found curl library at '%s'",
|
blog(LOG_INFO, "[adv-ss] found curl library at '%s'",
|
||||||
libFilePath.toUtf8().constData());
|
libFilePath.toUtf8().constData());
|
||||||
|
|
||||||
loaded_curl_lib = new QLibrary(libFilePath, nullptr);
|
loaded_curl_lib = new QLibrary(libFilePath, nullptr);
|
||||||
@@ -62,6 +63,6 @@ bool loadCurl()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
blog(LOG_ERROR, "can't find the curl library");
|
blog(LOG_WARNING, "[adv-ss] can't find the curl library");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
193
src/general.cpp
193
src/general.cpp
@@ -1,16 +1,17 @@
|
|||||||
#include <obs-module.h>
|
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QTextStream>
|
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
void SceneSwitcher::on_close_clicked()
|
QMetaObject::Connection inactivePluse;
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_close_clicked()
|
||||||
{
|
{
|
||||||
done(0);
|
done(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::UpdateNonMatchingScene(const QString &name)
|
void AdvSceneSwitcher::UpdateNonMatchingScene(const QString &name)
|
||||||
{
|
{
|
||||||
obs_source_t *scene = obs_get_source_by_name(name.toUtf8().constData());
|
obs_source_t *scene = obs_get_source_by_name(name.toUtf8().constData());
|
||||||
obs_weak_source_t *ws = obs_source_get_weak_source(scene);
|
obs_weak_source_t *ws = obs_source_get_weak_source(scene);
|
||||||
@@ -21,7 +22,7 @@ void SceneSwitcher::UpdateNonMatchingScene(const QString &name)
|
|||||||
obs_source_release(scene);
|
obs_source_release(scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_noMatchDontSwitch_clicked()
|
void AdvSceneSwitcher::on_noMatchDontSwitch_clicked()
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading)
|
||||||
return;
|
return;
|
||||||
@@ -29,9 +30,10 @@ void SceneSwitcher::on_noMatchDontSwitch_clicked()
|
|||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switcher->switchIfNotMatching = NO_SWITCH;
|
switcher->switchIfNotMatching = NO_SWITCH;
|
||||||
ui->noMatchSwitchScene->setEnabled(false);
|
ui->noMatchSwitchScene->setEnabled(false);
|
||||||
|
ui->randomDisabledWarning->setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_noMatchSwitch_clicked()
|
void AdvSceneSwitcher::on_noMatchSwitch_clicked()
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading)
|
||||||
return;
|
return;
|
||||||
@@ -40,9 +42,10 @@ void SceneSwitcher::on_noMatchSwitch_clicked()
|
|||||||
switcher->switchIfNotMatching = SWITCH;
|
switcher->switchIfNotMatching = SWITCH;
|
||||||
ui->noMatchSwitchScene->setEnabled(true);
|
ui->noMatchSwitchScene->setEnabled(true);
|
||||||
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
|
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
|
||||||
|
ui->randomDisabledWarning->setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_noMatchRandomSwitch_clicked()
|
void AdvSceneSwitcher::on_noMatchRandomSwitch_clicked()
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading)
|
||||||
return;
|
return;
|
||||||
@@ -50,9 +53,18 @@ void SceneSwitcher::on_noMatchRandomSwitch_clicked()
|
|||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switcher->switchIfNotMatching = RANDOM_SWITCH;
|
switcher->switchIfNotMatching = RANDOM_SWITCH;
|
||||||
ui->noMatchSwitchScene->setEnabled(false);
|
ui->noMatchSwitchScene->setEnabled(false);
|
||||||
|
ui->randomDisabledWarning->setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_startupBehavior_currentIndexChanged(int index)
|
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)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading)
|
||||||
return;
|
return;
|
||||||
@@ -61,7 +73,8 @@ void SceneSwitcher::on_startupBehavior_currentIndexChanged(int index)
|
|||||||
switcher->startupBehavior = (StartupBehavior)index;
|
switcher->startupBehavior = (StartupBehavior)index;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_noMatchSwitchScene_currentTextChanged(const QString &text)
|
void AdvSceneSwitcher::on_noMatchSwitchScene_currentTextChanged(
|
||||||
|
const QString &text)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading)
|
||||||
return;
|
return;
|
||||||
@@ -70,7 +83,7 @@ void SceneSwitcher::on_noMatchSwitchScene_currentTextChanged(const QString &text
|
|||||||
UpdateNonMatchingScene(text);
|
UpdateNonMatchingScene(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_checkInterval_valueChanged(int value)
|
void AdvSceneSwitcher::on_checkInterval_valueChanged(int value)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading)
|
||||||
return;
|
return;
|
||||||
@@ -79,19 +92,22 @@ void SceneSwitcher::on_checkInterval_valueChanged(int value)
|
|||||||
switcher->interval = value;
|
switcher->interval = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::SetStarted()
|
void AdvSceneSwitcher::SetStarted()
|
||||||
{
|
{
|
||||||
ui->toggleStartButton->setText("Stop");
|
ui->toggleStartButton->setText("Stop");
|
||||||
ui->pluginRunningText->setText("Active");
|
ui->pluginRunningText->setText("Active");
|
||||||
|
ui->pluginRunningText->disconnect(inactivePluse);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::SetStopped()
|
void AdvSceneSwitcher::SetStopped()
|
||||||
{
|
{
|
||||||
ui->toggleStartButton->setText("Start");
|
ui->toggleStartButton->setText("Start");
|
||||||
ui->pluginRunningText->setText("Inactive");
|
ui->pluginRunningText->setText("Inactive");
|
||||||
|
inactivePluse = PulseWidget(ui->pluginRunningText, QColor(Qt::red),
|
||||||
|
QColor(0, 0, 0, 0), "QLabel ");
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_toggleStartButton_clicked()
|
void AdvSceneSwitcher::on_toggleStartButton_clicked()
|
||||||
{
|
{
|
||||||
if (switcher->th && switcher->th->isRunning()) {
|
if (switcher->th && switcher->th->isRunning()) {
|
||||||
switcher->Stop();
|
switcher->Stop();
|
||||||
@@ -102,12 +118,12 @@ void SceneSwitcher::on_toggleStartButton_clicked()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::closeEvent(QCloseEvent *)
|
void AdvSceneSwitcher::closeEvent(QCloseEvent *)
|
||||||
{
|
{
|
||||||
obs_frontend_save();
|
obs_frontend_save();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_autoStopScenes_currentTextChanged(const QString &text)
|
void AdvSceneSwitcher::on_autoStopScenes_currentTextChanged(const QString &text)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading)
|
||||||
return;
|
return;
|
||||||
@@ -116,7 +132,7 @@ void SceneSwitcher::on_autoStopScenes_currentTextChanged(const QString &text)
|
|||||||
UpdateAutoStopScene(text);
|
UpdateAutoStopScene(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_autoStopSceneCheckBox_stateChanged(int state)
|
void AdvSceneSwitcher::on_autoStopSceneCheckBox_stateChanged(int state)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading)
|
||||||
return;
|
return;
|
||||||
@@ -133,7 +149,7 @@ void SceneSwitcher::on_autoStopSceneCheckBox_stateChanged(int state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::UpdateAutoStopScene(const QString &name)
|
void AdvSceneSwitcher::UpdateAutoStopScene(const QString &name)
|
||||||
{
|
{
|
||||||
obs_source_t *scene = obs_get_source_by_name(name.toUtf8().constData());
|
obs_source_t *scene = obs_get_source_by_name(name.toUtf8().constData());
|
||||||
obs_weak_source_t *ws = obs_source_get_weak_source(scene);
|
obs_weak_source_t *ws = obs_source_get_weak_source(scene);
|
||||||
@@ -150,16 +166,24 @@ void SwitcherData::autoStopStreamAndRecording()
|
|||||||
obs_weak_source_t *ws = obs_source_get_weak_source(currentSource);
|
obs_weak_source_t *ws = obs_source_get_weak_source(currentSource);
|
||||||
|
|
||||||
if (ws && autoStopScene == ws) {
|
if (ws && autoStopScene == ws) {
|
||||||
if (obs_frontend_streaming_active())
|
if (obs_frontend_streaming_active()) {
|
||||||
|
blog(LOG_INFO,
|
||||||
|
"Stopping stream because scene '%s' is active",
|
||||||
|
obs_source_get_name(currentSource));
|
||||||
obs_frontend_streaming_stop();
|
obs_frontend_streaming_stop();
|
||||||
if (obs_frontend_recording_active())
|
}
|
||||||
|
if (obs_frontend_recording_active()) {
|
||||||
|
blog(LOG_INFO,
|
||||||
|
"Stopping record because scene '%s' is active",
|
||||||
|
obs_source_get_name(currentSource));
|
||||||
obs_frontend_recording_stop();
|
obs_frontend_recording_stop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
obs_source_release(currentSource);
|
obs_source_release(currentSource);
|
||||||
obs_weak_source_release(ws);
|
obs_weak_source_release(ws);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_autoStartType_currentIndexChanged(int index)
|
void AdvSceneSwitcher::on_autoStartType_currentIndexChanged(int index)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading)
|
||||||
return;
|
return;
|
||||||
@@ -167,7 +191,7 @@ void SceneSwitcher::on_autoStartType_currentIndexChanged(int index)
|
|||||||
switcher->autoStartType = (AutoStartType)index;
|
switcher->autoStartType = (AutoStartType)index;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_autoStartScenes_currentTextChanged(const QString &text)
|
void AdvSceneSwitcher::on_autoStartScenes_currentTextChanged(const QString &text)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading)
|
||||||
return;
|
return;
|
||||||
@@ -176,7 +200,7 @@ void SceneSwitcher::on_autoStartScenes_currentTextChanged(const QString &text)
|
|||||||
UpdateAutoStartScene(text);
|
UpdateAutoStartScene(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_autoStartSceneCheckBox_stateChanged(int state)
|
void AdvSceneSwitcher::on_autoStartSceneCheckBox_stateChanged(int state)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading)
|
||||||
return;
|
return;
|
||||||
@@ -196,7 +220,7 @@ void SceneSwitcher::on_autoStartSceneCheckBox_stateChanged(int state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::UpdateAutoStartScene(const QString &name)
|
void AdvSceneSwitcher::UpdateAutoStartScene(const QString &name)
|
||||||
{
|
{
|
||||||
obs_source_t *scene = obs_get_source_by_name(name.toUtf8().constData());
|
obs_source_t *scene = obs_get_source_by_name(name.toUtf8().constData());
|
||||||
obs_weak_source_t *ws = obs_source_get_weak_source(scene);
|
obs_weak_source_t *ws = obs_source_get_weak_source(scene);
|
||||||
@@ -218,12 +242,20 @@ void SwitcherData::autoStartStreamRecording()
|
|||||||
if (ws && autoStartScene == ws) {
|
if (ws && autoStartScene == ws) {
|
||||||
if ((switcher->autoStartType == STREAMING ||
|
if ((switcher->autoStartType == STREAMING ||
|
||||||
switcher->autoStartType == RECORINDGSTREAMING) &&
|
switcher->autoStartType == RECORINDGSTREAMING) &&
|
||||||
!obs_frontend_streaming_active())
|
!obs_frontend_streaming_active()) {
|
||||||
|
blog(LOG_INFO,
|
||||||
|
"Starting stream because scene '%s' is active",
|
||||||
|
obs_source_get_name(currentSource));
|
||||||
obs_frontend_streaming_start();
|
obs_frontend_streaming_start();
|
||||||
|
}
|
||||||
if ((switcher->autoStartType == RECORDING ||
|
if ((switcher->autoStartType == RECORDING ||
|
||||||
switcher->autoStartType == RECORINDGSTREAMING) &&
|
switcher->autoStartType == RECORINDGSTREAMING) &&
|
||||||
!obs_frontend_recording_active())
|
!obs_frontend_recording_active()) {
|
||||||
|
blog(LOG_INFO,
|
||||||
|
"Starting record because scene '%s' is active",
|
||||||
|
obs_source_get_name(currentSource));
|
||||||
obs_frontend_recording_start();
|
obs_frontend_recording_start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
obs_source_release(currentSource);
|
obs_source_release(currentSource);
|
||||||
obs_weak_source_release(ws);
|
obs_weak_source_release(ws);
|
||||||
@@ -231,16 +263,21 @@ void SwitcherData::autoStartStreamRecording()
|
|||||||
autoStartedRecently = true;
|
autoStartedRecently = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_verboseLogging_stateChanged(int state)
|
void AdvSceneSwitcher::on_verboseLogging_stateChanged(int state)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
switcher->verbose = state;
|
switcher->verbose = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_exportSettings_clicked()
|
void AdvSceneSwitcher::on_uiHintsDisable_stateChanged(int state)
|
||||||
|
{
|
||||||
|
if (loading)
|
||||||
|
return;
|
||||||
|
switcher->disableHints = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_exportSettings_clicked()
|
||||||
{
|
{
|
||||||
QString directory = QFileDialog::getSaveFileName(
|
QString directory = QFileDialog::getSaveFileName(
|
||||||
this, tr("Export Advanced Scene Switcher settings to file ..."),
|
this, tr("Export Advanced Scene Switcher settings to file ..."),
|
||||||
@@ -274,7 +311,7 @@ void SceneSwitcher::on_exportSettings_clicked()
|
|||||||
obs_data_release(obj);
|
obs_data_release(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_importSettings_clicked()
|
void AdvSceneSwitcher::on_importSettings_clicked()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
|
||||||
@@ -324,86 +361,93 @@ void SceneSwitcher::on_importSettings_clicked()
|
|||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
int findTabIndex(QTabBar *bar, int pos)
|
int findTabIndex(QTabWidget *tabWidget, int pos)
|
||||||
{
|
{
|
||||||
int at = -1;
|
int at = -1;
|
||||||
|
|
||||||
QString tabName = "";
|
QString tabName = "";
|
||||||
switch (pos) {
|
switch (pos) {
|
||||||
case 0:
|
case 0:
|
||||||
tabName = "General";
|
tabName = "generalTab";
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
tabName = "Transition";
|
tabName = "transitionsTab";
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
tabName = "Pause";
|
tabName = "pauseScenesTab";
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
tabName = "Title";
|
tabName = "windowTitleTab";
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
tabName = "Executable";
|
tabName = "executableTab";
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
tabName = "Region";
|
tabName = "screenRegionTab";
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
tabName = "Media";
|
tabName = "mediaTab";
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
tabName = "File";
|
tabName = "fileTab";
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
tabName = "Random";
|
tabName = "randomTab";
|
||||||
break;
|
break;
|
||||||
case 9:
|
case 9:
|
||||||
tabName = "Time";
|
tabName = "timeTab";
|
||||||
break;
|
break;
|
||||||
case 10:
|
case 10:
|
||||||
tabName = "Idle";
|
tabName = "idleTab";
|
||||||
break;
|
break;
|
||||||
case 11:
|
case 11:
|
||||||
tabName = "Sequence";
|
tabName = "sceneSequenceTab";
|
||||||
break;
|
break;
|
||||||
case 12:
|
case 12:
|
||||||
tabName = "Audio";
|
tabName = "audioTab";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < bar->count(); ++i) {
|
QWidget *page = tabWidget->findChild<QWidget *>(tabName);
|
||||||
if (bar->tabText(i).compare(tabName) == 0) {
|
if (page) {
|
||||||
at = i;
|
at = tabWidget->indexOf(page);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (at == -1)
|
if (at == -1)
|
||||||
blog(LOG_INFO, "Advanced Scene Switcher failed to find tab %s",
|
blog(LOG_INFO, "failed to find tab %s",
|
||||||
tabName.toUtf8().constData());
|
tabName.toUtf8().constData());
|
||||||
|
|
||||||
return at;
|
return at;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::setTabOrder()
|
void AdvSceneSwitcher::setTabOrder()
|
||||||
{
|
{
|
||||||
QTabBar *bar = ui->tabWidget->tabBar();
|
QTabBar *bar = ui->tabWidget->tabBar();
|
||||||
for (int i = 0; i < bar->count(); ++i) {
|
for (int i = 0; i < bar->count(); ++i) {
|
||||||
int curPos = findTabIndex(bar, switcher->tabOrder[i]);
|
int curPos = findTabIndex(ui->tabWidget, switcher->tabOrder[i]);
|
||||||
|
|
||||||
if (i != curPos && curPos != -1)
|
if (i != curPos && curPos != -1)
|
||||||
bar->moveTab(curPos, i);
|
bar->moveTab(curPos, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(bar, &QTabBar::tabMoved, this, &SceneSwitcher::on_tabMoved);
|
connect(bar, &QTabBar::tabMoved, this, &AdvSceneSwitcher::on_tabMoved);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_tabMoved(int from, int to)
|
void AdvSceneSwitcher::on_tabMoved(int from, int to)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading)
|
||||||
return;
|
return;
|
||||||
std::swap(switcher->tabOrder[from], switcher->tabOrder[to]);
|
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::saveGeneralSettings(obs_data_t *obj)
|
void SwitcherData::saveGeneralSettings(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
obs_data_set_int(obj, "interval", switcher->interval);
|
obs_data_set_int(obj, "interval", switcher->interval);
|
||||||
@@ -414,6 +458,7 @@ 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_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);
|
||||||
@@ -432,6 +477,7 @@ void SwitcherData::saveGeneralSettings(obs_data_t *obj)
|
|||||||
autoStartSceneName.c_str());
|
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_int(obj, "priority0",
|
obs_data_set_int(obj, "priority0",
|
||||||
switcher->functionNamesByPriority[0]);
|
switcher->functionNamesByPriority[0]);
|
||||||
@@ -454,6 +500,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() < 13) {
|
||||||
|
switcher->tabOrder = std::vector<int>(13);
|
||||||
|
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 +535,7 @@ 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->stop = !obs_data_get_bool(obj, "active");
|
switcher->stop = !obs_data_get_bool(obj, "active");
|
||||||
switcher->startupBehavior =
|
switcher->startupBehavior =
|
||||||
@@ -503,6 +558,7 @@ void SwitcherData::loadGeneralSettings(obs_data_t *obj)
|
|||||||
switcher->autoStartScene = GetWeakSourceByName(autoStartScene.c_str());
|
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");
|
||||||
|
|
||||||
obs_data_set_default_int(obj, "priority0", default_priority_0);
|
obs_data_set_default_int(obj, "priority0", default_priority_0);
|
||||||
obs_data_set_default_int(obj, "priority1", default_priority_1);
|
obs_data_set_default_int(obj, "priority1", default_priority_1);
|
||||||
@@ -590,7 +646,30 @@ void SwitcherData::loadGeneralSettings(obs_data_t *obj)
|
|||||||
(int)(obs_data_get_int(obj, "audioTabPos")));
|
(int)(obs_data_get_int(obj, "audioTabPos")));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::setupGeneralTab()
|
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 AdvSceneSwitcher::setupGeneralTab()
|
||||||
{
|
{
|
||||||
populateSceneSelection(ui->noMatchSwitchScene, false);
|
populateSceneSelection(ui->noMatchSwitchScene, false);
|
||||||
populateSceneSelection(ui->autoStopScenes, false);
|
populateSceneSelection(ui->autoStopScenes, false);
|
||||||
@@ -608,6 +687,9 @@ void SceneSwitcher::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(
|
||||||
|
"Will only ever be as accurate as the configured check interval.");
|
||||||
ui->checkInterval->setValue(switcher->interval);
|
ui->checkInterval->setValue(switcher->interval);
|
||||||
|
|
||||||
ui->autoStopSceneCheckBox->setChecked(switcher->autoStopEnable);
|
ui->autoStopSceneCheckBox->setChecked(switcher->autoStopEnable);
|
||||||
@@ -638,6 +720,7 @@ void SceneSwitcher::setupGeneralTab()
|
|||||||
}
|
}
|
||||||
|
|
||||||
ui->verboseLogging->setChecked(switcher->verbose);
|
ui->verboseLogging->setChecked(switcher->verbose);
|
||||||
|
ui->uiHintsDisable->setChecked(switcher->disableHints);
|
||||||
|
|
||||||
for (int p : switcher->functionNamesByPriority) {
|
for (int p : switcher->functionNamesByPriority) {
|
||||||
std::string s = "";
|
std::string s = "";
|
||||||
|
|||||||
@@ -1,63 +1,48 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QDialog>
|
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#ifdef BUILD_OUT_OF_TREE
|
#ifdef BUILD_OUT_OF_TREE
|
||||||
#include "../../forms/ui_advanced-scene-switcher.h"
|
#include "../../forms/ui_advanced-scene-switcher.h"
|
||||||
#else
|
#else
|
||||||
#include "ui_advanced-scene-switcher.h"
|
#include "ui_advanced-scene-switcher.h"
|
||||||
#endif
|
#endif
|
||||||
#include "switcher-data-structs.hpp"
|
#include "switcher-data-structs.hpp"
|
||||||
#include "volume-control.hpp"
|
|
||||||
|
#define blog(level, msg, ...) blog(level, "[adv-ss] " msg, ##__VA_ARGS__)
|
||||||
|
|
||||||
class QCloseEvent;
|
class QCloseEvent;
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Advanced Scene Switcher window
|
* Advanced Scene Switcher window
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
class SceneSwitcher : public QDialog {
|
class AdvSceneSwitcher : public QDialog {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::unique_ptr<Ui_SceneSwitcher> ui;
|
std::unique_ptr<Ui_AdvSceneSwitcher> ui;
|
||||||
VolControl *volMeter = nullptr;
|
|
||||||
bool loading = true;
|
bool loading = true;
|
||||||
|
|
||||||
SceneSwitcher(QWidget *parent);
|
AdvSceneSwitcher(QWidget *parent);
|
||||||
|
|
||||||
void closeEvent(QCloseEvent *event) override;
|
void closeEvent(QCloseEvent *event) override;
|
||||||
|
|
||||||
void SetStarted();
|
void SetStarted();
|
||||||
void SetStopped();
|
void SetStopped();
|
||||||
|
|
||||||
int FindByData(const QString &window);
|
void SetShowFrames();
|
||||||
int ScreenRegionFindByData(const QString ®ion);
|
void SetHideFrames();
|
||||||
|
void clearFrames(QListWidget *list);
|
||||||
|
|
||||||
int PauseScenesFindByData(const QString &scene);
|
int PauseScenesFindByData(const QString &scene);
|
||||||
int PauseWindowsFindByData(const QString &window);
|
int PauseWindowsFindByData(const QString &window);
|
||||||
int IgnoreWindowsFindByData(const QString &window);
|
int IgnoreWindowsFindByData(const QString &window);
|
||||||
int SceneSequenceFindByData(const QString &scene1);
|
|
||||||
int SceneTransitionsFindByData(const QString &scene1,
|
|
||||||
const QString &scene2);
|
|
||||||
int DefaultTransitionsFindByData(const QString &scene);
|
|
||||||
int executableFindByData(const QString &exe);
|
|
||||||
int IgnoreIdleWindowsFindByData(const QString &window);
|
int IgnoreIdleWindowsFindByData(const QString &window);
|
||||||
int randomFindByData(const QString &scene);
|
|
||||||
int timeFindByData(const timeTrigger &trigger, const QTime &time);
|
|
||||||
int audioFindByData(const QString &source, const int &volume);
|
|
||||||
|
|
||||||
void UpdateNonMatchingScene(const QString &name);
|
void UpdateNonMatchingScene(const QString &name);
|
||||||
void UpdateAutoStopScene(const QString &name);
|
void UpdateAutoStopScene(const QString &name);
|
||||||
void UpdateAutoStartScene(const QString &name);
|
void UpdateAutoStartScene(const QString &name);
|
||||||
void UpdateIdleDataTransition(const QString &name);
|
void UpdateIdleDataTransition(const QString &name);
|
||||||
void UpdateIdleDataScene(const QString &name);
|
void UpdateIdleDataScene(const QString &name);
|
||||||
void SetAudioVolumeMeter(const QString &name);
|
|
||||||
|
|
||||||
void loadUI();
|
void loadUI();
|
||||||
void populateSceneSelection(QComboBox *sel, bool addPrevious);
|
|
||||||
void populateTransitionSelection(QComboBox *sel);
|
|
||||||
void populateWindowSelection(QComboBox *sel);
|
|
||||||
void setupGeneralTab();
|
void setupGeneralTab();
|
||||||
void setupTitleTab();
|
void setupTitleTab();
|
||||||
void setupExecutableTab();
|
void setupExecutableTab();
|
||||||
@@ -73,22 +58,44 @@ public:
|
|||||||
void setupAudioTab();
|
void setupAudioTab();
|
||||||
void setTabOrder();
|
void setTabOrder();
|
||||||
|
|
||||||
|
static void populateSceneSelection(QComboBox *sel,
|
||||||
|
bool addPrevious = false,
|
||||||
|
bool addSelect = true);
|
||||||
|
static void populateTransitionSelection(QComboBox *sel,
|
||||||
|
bool addSelect = true);
|
||||||
|
static void populateWindowSelection(QComboBox *sel,
|
||||||
|
bool addSelect = true);
|
||||||
|
static void populateAudioSelection(QComboBox *sel,
|
||||||
|
bool addSelect = true);
|
||||||
|
static void populateMediaSelection(QComboBox *sel,
|
||||||
|
bool addSelect = true);
|
||||||
|
static void populateProcessSelection(QComboBox *sel,
|
||||||
|
bool addSelect = true);
|
||||||
|
QMetaObject::Connection PulseWidget(QWidget *widget, QColor endColor,
|
||||||
|
QColor = QColor(0, 0, 0, 0),
|
||||||
|
QString specifier = "QLabel ");
|
||||||
|
|
||||||
|
bool listMoveUp(QListWidget *list);
|
||||||
|
bool listMoveDown(QListWidget *list);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void on_switches_currentRowChanged(int idx);
|
void on_windowUp_clicked();
|
||||||
void on_up_clicked();
|
void on_windowDown_clicked();
|
||||||
void on_down_clicked();
|
void on_windowAdd_clicked();
|
||||||
void on_add_clicked();
|
void on_windowRemove_clicked();
|
||||||
void on_remove_clicked();
|
|
||||||
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_startupBehavior_currentIndexChanged(int index);
|
void on_startupBehavior_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_screenRegions_currentRowChanged(int idx);
|
void on_screenRegionSwitches_currentRowChanged(int idx);
|
||||||
|
void on_showFrame_clicked();
|
||||||
void on_screenRegionAdd_clicked();
|
void on_screenRegionAdd_clicked();
|
||||||
void on_screenRegionRemove_clicked();
|
void on_screenRegionRemove_clicked();
|
||||||
void on_screenRegionUp_clicked();
|
void on_screenRegionUp_clicked();
|
||||||
@@ -106,14 +113,12 @@ public slots:
|
|||||||
void on_ignoreWindowsAdd_clicked();
|
void on_ignoreWindowsAdd_clicked();
|
||||||
void on_ignoreWindowsRemove_clicked();
|
void on_ignoreWindowsRemove_clicked();
|
||||||
|
|
||||||
void on_sceneSequences_currentRowChanged(int idx);
|
|
||||||
void on_sceneSequenceAdd_clicked();
|
void on_sceneSequenceAdd_clicked();
|
||||||
void on_sceneSequenceRemove_clicked();
|
void on_sceneSequenceRemove_clicked();
|
||||||
void on_sceneSequenceSave_clicked();
|
void on_sceneSequenceSave_clicked();
|
||||||
void on_sceneSequenceLoad_clicked();
|
void on_sceneSequenceLoad_clicked();
|
||||||
void on_sceneSequenceUp_clicked();
|
void on_sceneSequenceUp_clicked();
|
||||||
void on_sceneSequenceDown_clicked();
|
void on_sceneSequenceDown_clicked();
|
||||||
void on_sceneSequenceDelayUnits_currentIndexChanged(int index);
|
|
||||||
|
|
||||||
void on_autoStopSceneCheckBox_stateChanged(int state);
|
void on_autoStopSceneCheckBox_stateChanged(int state);
|
||||||
void on_autoStopScenes_currentTextChanged(const QString &text);
|
void on_autoStopScenes_currentTextChanged(const QString &text);
|
||||||
@@ -123,16 +128,19 @@ public slots:
|
|||||||
void on_autoStartScenes_currentTextChanged(const QString &text);
|
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_exportSettings_clicked();
|
void on_exportSettings_clicked();
|
||||||
void on_importSettings_clicked();
|
void on_importSettings_clicked();
|
||||||
|
|
||||||
void on_sceneTransitions_currentRowChanged(int idx);
|
|
||||||
void on_transitionsAdd_clicked();
|
void on_transitionsAdd_clicked();
|
||||||
void on_transitionsRemove_clicked();
|
void on_transitionsRemove_clicked();
|
||||||
void on_defaultTransitions_currentRowChanged(int idx);
|
void on_transitionsUp_clicked();
|
||||||
|
void on_transitionsDown_clicked();
|
||||||
void on_defaultTransitionsAdd_clicked();
|
void on_defaultTransitionsAdd_clicked();
|
||||||
void on_defaultTransitionsRemove_clicked();
|
void on_defaultTransitionsRemove_clicked();
|
||||||
|
void on_defaultTransitionsUp_clicked();
|
||||||
|
void on_defaultTransitionsDown_clicked();
|
||||||
void on_transitionOverridecheckBox_stateChanged(int state);
|
void on_transitionOverridecheckBox_stateChanged(int state);
|
||||||
|
|
||||||
void on_browseButton_clicked();
|
void on_browseButton_clicked();
|
||||||
@@ -146,7 +154,6 @@ public slots:
|
|||||||
void on_executableDown_clicked();
|
void on_executableDown_clicked();
|
||||||
void on_executableAdd_clicked();
|
void on_executableAdd_clicked();
|
||||||
void on_executableRemove_clicked();
|
void on_executableRemove_clicked();
|
||||||
void on_executables_currentRowChanged(int idx);
|
|
||||||
|
|
||||||
void on_idleCheckBox_stateChanged(int state);
|
void on_idleCheckBox_stateChanged(int state);
|
||||||
void on_idleTransitions_currentTextChanged(const QString &text);
|
void on_idleTransitions_currentTextChanged(const QString &text);
|
||||||
@@ -158,7 +165,6 @@ public slots:
|
|||||||
|
|
||||||
void on_randomAdd_clicked();
|
void on_randomAdd_clicked();
|
||||||
void on_randomRemove_clicked();
|
void on_randomRemove_clicked();
|
||||||
void on_randomScenesList_currentRowChanged(int idx);
|
|
||||||
|
|
||||||
void on_fileAdd_clicked();
|
void on_fileAdd_clicked();
|
||||||
void on_fileRemove_clicked();
|
void on_fileRemove_clicked();
|
||||||
@@ -167,14 +173,11 @@ public slots:
|
|||||||
void on_fileUp_clicked();
|
void on_fileUp_clicked();
|
||||||
void on_fileDown_clicked();
|
void on_fileDown_clicked();
|
||||||
|
|
||||||
void on_mediaSwitches_currentRowChanged(int idx);
|
|
||||||
void on_mediaAdd_clicked();
|
void on_mediaAdd_clicked();
|
||||||
void on_mediaRemove_clicked();
|
void on_mediaRemove_clicked();
|
||||||
void on_mediaUp_clicked();
|
void on_mediaUp_clicked();
|
||||||
void on_mediaDown_clicked();
|
void on_mediaDown_clicked();
|
||||||
void on_mediaTimeRestrictions_currentIndexChanged(int idx);
|
|
||||||
|
|
||||||
void on_timeSwitches_currentRowChanged(int idx);
|
|
||||||
void on_timeAdd_clicked();
|
void on_timeAdd_clicked();
|
||||||
void on_timeRemove_clicked();
|
void on_timeRemove_clicked();
|
||||||
void on_timeUp_clicked();
|
void on_timeUp_clicked();
|
||||||
@@ -184,8 +187,6 @@ 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_audioSwitches_currentRowChanged(int idx);
|
|
||||||
void on_audioSources_currentTextChanged(const QString &text);
|
|
||||||
|
|
||||||
void on_priorityUp_clicked();
|
void on_priorityUp_clicked();
|
||||||
void on_priorityDown_clicked();
|
void on_priorityDown_clicked();
|
||||||
@@ -226,13 +227,6 @@ bool isInFocus(const QString &executable);
|
|||||||
/********************************************************************************
|
/********************************************************************************
|
||||||
* Sceneswitch helper
|
* Sceneswitch helper
|
||||||
********************************************************************************/
|
********************************************************************************/
|
||||||
struct obs_weak_source;
|
|
||||||
typedef struct obs_weak_source obs_weak_source_t;
|
|
||||||
|
|
||||||
typedef struct transitionData {
|
|
||||||
std::string name = "";
|
|
||||||
int duration = 0;
|
|
||||||
} transitionData;
|
|
||||||
|
|
||||||
void setNextTransition(OBSWeakSource &targetScene, obs_source_t *currentSource,
|
void setNextTransition(OBSWeakSource &targetScene, obs_source_t *currentSource,
|
||||||
OBSWeakSource &transition,
|
OBSWeakSource &transition,
|
||||||
@@ -240,10 +234,8 @@ 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
|
||||||
|
|||||||
@@ -1,115 +1,65 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
#include <QSpinBox>
|
||||||
#include "utility.hpp"
|
|
||||||
#include "switch-generic.hpp"
|
#include "switch-generic.hpp"
|
||||||
|
#include "volume-control.hpp"
|
||||||
|
|
||||||
constexpr auto audio_func = 8;
|
constexpr auto audio_func = 8;
|
||||||
constexpr auto default_priority_8 = audio_func;
|
constexpr auto default_priority_8 = audio_func;
|
||||||
|
|
||||||
struct AudioSwitch : virtual SceneSwitcherEntry {
|
struct AudioSwitch : virtual SceneSwitcherEntry {
|
||||||
OBSWeakSource audioSource;
|
OBSWeakSource audioSource = nullptr;
|
||||||
int volumeThreshold;
|
int volumeThreshold = 0;
|
||||||
float peak;
|
float peak = -1;
|
||||||
std::string audioSwitchStr;
|
obs_volmeter_t *volmeter = nullptr;
|
||||||
obs_volmeter_t *volmeter;
|
|
||||||
|
|
||||||
const char *getType() { return "audio"; }
|
const char *getType() { return "audio"; }
|
||||||
|
bool initialized();
|
||||||
|
bool valid();
|
||||||
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],
|
||||||
const float inputPeak[MAX_AUDIO_CHANNELS])
|
const float inputPeak[MAX_AUDIO_CHANNELS]);
|
||||||
{
|
void resetVolmeter();
|
||||||
UNUSED_PARAMETER(magnitude);
|
|
||||||
UNUSED_PARAMETER(inputPeak);
|
|
||||||
AudioSwitch *s = static_cast<AudioSwitch *>(data);
|
|
||||||
|
|
||||||
s->peak = peak[0];
|
AudioSwitch(){};
|
||||||
for (int i = 1; i < MAX_AUDIO_CHANNELS; i++)
|
AudioSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
||||||
if (peak[i] > s->peak)
|
OBSWeakSource audioSource_, int volumeThreshold_,
|
||||||
s->peak = peak[i];
|
bool usePreviousScene_);
|
||||||
}
|
AudioSwitch(const AudioSwitch &other);
|
||||||
|
AudioSwitch(AudioSwitch &&other);
|
||||||
bool valid()
|
~AudioSwitch();
|
||||||
{
|
AudioSwitch &operator=(const AudioSwitch &other);
|
||||||
return (usePreviousScene || WeakSourceValid(scene)) &&
|
AudioSwitch &operator=(AudioSwitch &&other) noexcept;
|
||||||
WeakSourceValid(audioSource) &&
|
friend void swap(AudioSwitch &first, AudioSwitch &second);
|
||||||
WeakSourceValid(transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline AudioSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
|
||||||
OBSWeakSource audioSource_, int volumeThreshold_,
|
|
||||||
bool usePreviousScene_, std::string audioSwitchStr_)
|
|
||||||
: SceneSwitcherEntry(scene_, transition_, usePreviousScene_),
|
|
||||||
audioSource(audioSource_),
|
|
||||||
volumeThreshold(volumeThreshold_),
|
|
||||||
audioSwitchStr(audioSwitchStr_)
|
|
||||||
{
|
|
||||||
volmeter = obs_volmeter_create(OBS_FADER_LOG);
|
|
||||||
obs_volmeter_add_callback(volmeter, setVolumeLevel, this);
|
|
||||||
obs_source_t *as = obs_weak_source_get_source(audioSource);
|
|
||||||
if (!obs_volmeter_attach_source(volmeter, as)) {
|
|
||||||
const char *name = obs_source_get_name(as);
|
|
||||||
blog(LOG_WARNING,
|
|
||||||
"failed to attach volmeter to source %s", name);
|
|
||||||
}
|
|
||||||
obs_source_release(as);
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioSwitch(const AudioSwitch &other)
|
|
||||||
: SceneSwitcherEntry(other.scene, other.transition,
|
|
||||||
other.usePreviousScene),
|
|
||||||
audioSource(other.audioSource),
|
|
||||||
volumeThreshold(other.volumeThreshold),
|
|
||||||
audioSwitchStr(other.audioSwitchStr)
|
|
||||||
{
|
|
||||||
volmeter = obs_volmeter_create(OBS_FADER_LOG);
|
|
||||||
obs_volmeter_add_callback(volmeter, setVolumeLevel, this);
|
|
||||||
obs_source_t *as =
|
|
||||||
obs_weak_source_get_source(other.audioSource);
|
|
||||||
if (!obs_volmeter_attach_source(volmeter, as)) {
|
|
||||||
const char *name = obs_source_get_name(as);
|
|
||||||
blog(LOG_WARNING,
|
|
||||||
"failed to attach volmeter to source %s", name);
|
|
||||||
}
|
|
||||||
obs_source_release(as);
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioSwitch(AudioSwitch &&other)
|
|
||||||
: SceneSwitcherEntry(other.scene, other.transition,
|
|
||||||
other.usePreviousScene),
|
|
||||||
audioSource(other.audioSource),
|
|
||||||
volumeThreshold(other.volumeThreshold),
|
|
||||||
audioSwitchStr(other.audioSwitchStr),
|
|
||||||
volmeter(other.volmeter)
|
|
||||||
{
|
|
||||||
other.volmeter = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline ~AudioSwitch()
|
|
||||||
{
|
|
||||||
obs_volmeter_remove_callback(volmeter, setVolumeLevel, this);
|
|
||||||
obs_volmeter_destroy(volmeter);
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioSwitch &operator=(const AudioSwitch &other)
|
|
||||||
{
|
|
||||||
return *this = AudioSwitch(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioSwitch &operator=(AudioSwitch &&other) noexcept
|
|
||||||
{
|
|
||||||
if (this == &other) {
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
obs_volmeter_destroy(volmeter);
|
|
||||||
volmeter = other.volmeter;
|
|
||||||
other.volmeter = nullptr;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline QString MakeAudioSwitchName(const QString &scene,
|
class AudioSwitchWidget : public SwitchWidget {
|
||||||
const QString &transition,
|
Q_OBJECT
|
||||||
const QString &audioSrouce,
|
|
||||||
const int &volume);
|
public:
|
||||||
|
AudioSwitchWidget(AudioSwitch *s);
|
||||||
|
void UpdateVolmeterSource();
|
||||||
|
AudioSwitch *getSwitchData();
|
||||||
|
void setSwitchData(AudioSwitch *s);
|
||||||
|
|
||||||
|
static void swapSwitchData(AudioSwitchWidget *as1,
|
||||||
|
AudioSwitchWidget *as2);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void SourceChanged(const QString &text);
|
||||||
|
void VolumeThresholdChanged(int vol);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QComboBox *audioSources;
|
||||||
|
QSpinBox *audioVolumeThreshold;
|
||||||
|
|
||||||
|
VolControl *volMeter;
|
||||||
|
|
||||||
|
QLabel *whenLabel;
|
||||||
|
QLabel *aboveLabel;
|
||||||
|
QLabel *switchLabel;
|
||||||
|
QLabel *usingLabel;
|
||||||
|
|
||||||
|
AudioSwitch *switchData;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,20 +1,19 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
#include <QCheckBox>
|
||||||
#include "utility.hpp"
|
|
||||||
#include "switch-generic.hpp"
|
#include "switch-generic.hpp"
|
||||||
|
|
||||||
constexpr auto exe_func = 3;
|
constexpr auto exe_func = 3;
|
||||||
constexpr auto default_priority_3 = exe_func;
|
constexpr auto default_priority_3 = exe_func;
|
||||||
|
|
||||||
struct ExecutableSceneSwitch : SceneSwitcherEntry {
|
struct ExecutableSwitch : SceneSwitcherEntry {
|
||||||
QString exe;
|
QString exe = "";
|
||||||
bool inFocus;
|
bool inFocus = false;
|
||||||
|
|
||||||
const char *getType() { return "exec"; }
|
const char *getType() { return "exec"; }
|
||||||
|
|
||||||
inline ExecutableSceneSwitch(OBSWeakSource scene_,
|
inline ExecutableSwitch(){};
|
||||||
OBSWeakSource transition_,
|
inline ExecutableSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
||||||
const QString &exe_, bool inFocus_)
|
const QString &exe_, bool inFocus_)
|
||||||
: SceneSwitcherEntry(scene_, transition_),
|
: SceneSwitcherEntry(scene_, transition_),
|
||||||
exe(exe_),
|
exe(exe_),
|
||||||
inFocus(inFocus_)
|
inFocus(inFocus_)
|
||||||
@@ -22,7 +21,28 @@ struct ExecutableSceneSwitch : SceneSwitcherEntry {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline QString MakeSwitchNameExecutable(const QString &scene,
|
class ExecutableSwitchWidget : public SwitchWidget {
|
||||||
const QString &value,
|
Q_OBJECT
|
||||||
const QString &transition,
|
|
||||||
bool inFocus);
|
public:
|
||||||
|
ExecutableSwitchWidget(ExecutableSwitch *s);
|
||||||
|
ExecutableSwitch *getSwitchData();
|
||||||
|
void setSwitchData(ExecutableSwitch *s);
|
||||||
|
|
||||||
|
static void swapSwitchData(ExecutableSwitchWidget *s1,
|
||||||
|
ExecutableSwitchWidget *s2);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void ProcessChanged(const QString &text);
|
||||||
|
void FocusChanged(int state);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QComboBox *processes;
|
||||||
|
QCheckBox *requiresFocus;
|
||||||
|
|
||||||
|
QLabel *whenLabel;
|
||||||
|
QLabel *switchLabel;
|
||||||
|
QLabel *usingLabel;
|
||||||
|
|
||||||
|
ExecutableSwitch *switchData;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
|
||||||
#include "utility.hpp"
|
|
||||||
#include "switch-generic.hpp"
|
#include "switch-generic.hpp"
|
||||||
|
|
||||||
constexpr auto read_file_func = 0;
|
constexpr auto read_file_func = 0;
|
||||||
|
|||||||
@@ -1,48 +1,50 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
|
||||||
#include <obs.hpp>
|
#include <obs.hpp>
|
||||||
|
#include <QComboBox>
|
||||||
|
|
||||||
struct SceneSwitcherEntry {
|
struct SceneSwitcherEntry {
|
||||||
OBSWeakSource scene;
|
OBSWeakSource scene = nullptr;
|
||||||
OBSWeakSource transition;
|
OBSWeakSource transition = nullptr;
|
||||||
bool usePreviousScene;
|
bool usePreviousScene = false;
|
||||||
|
|
||||||
virtual bool valid()
|
|
||||||
{
|
|
||||||
return (usePreviousScene || WeakSourceValid(scene)) &&
|
|
||||||
WeakSourceValid(transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual const char *getType() = 0;
|
virtual const char *getType() = 0;
|
||||||
|
virtual bool initialized();
|
||||||
|
virtual bool valid();
|
||||||
|
virtual void logMatch();
|
||||||
|
|
||||||
// TODO
|
inline SceneSwitcherEntry() {}
|
||||||
//virtual bool checkMatch() = 0;
|
|
||||||
|
|
||||||
virtual void logMatch()
|
|
||||||
{
|
|
||||||
obs_source_t *s = obs_weak_source_get_source(scene);
|
|
||||||
const char *sceneName = obs_source_get_name(s);
|
|
||||||
obs_source_release(s);
|
|
||||||
blog(LOG_INFO,
|
|
||||||
"Advanced Scene Switcher match for '%s' - switch to scene '%s'",
|
|
||||||
getType(), sceneName);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline SceneSwitcherEntry() : usePreviousScene(false) {}
|
|
||||||
|
|
||||||
inline SceneSwitcherEntry(OBSWeakSource scene_,
|
inline SceneSwitcherEntry(OBSWeakSource scene_,
|
||||||
OBSWeakSource transition_,
|
OBSWeakSource transition_,
|
||||||
bool usePreviousScene_)
|
bool usePreviousScene_ = false)
|
||||||
: scene(scene_),
|
: scene(scene_),
|
||||||
transition(transition_),
|
transition(transition_),
|
||||||
usePreviousScene(usePreviousScene_)
|
usePreviousScene(usePreviousScene_)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
inline SceneSwitcherEntry(OBSWeakSource scene_,
|
|
||||||
OBSWeakSource transition_)
|
virtual ~SceneSwitcherEntry() {}
|
||||||
: scene(scene_),
|
};
|
||||||
transition(transition_),
|
|
||||||
usePreviousScene(false)
|
class SwitchWidget : public QWidget {
|
||||||
{
|
Q_OBJECT
|
||||||
}
|
|
||||||
|
public:
|
||||||
|
SwitchWidget(SceneSwitcherEntry *s, bool usePreviousScene = true);
|
||||||
|
virtual SceneSwitcherEntry *getSwitchData();
|
||||||
|
virtual void setSwitchData(SceneSwitcherEntry *s);
|
||||||
|
|
||||||
|
static void swapSwitchData(SwitchWidget *s1, SwitchWidget *s2);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void SceneChanged(const QString &text);
|
||||||
|
void TransitionChanged(const QString &text);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool loading = true;
|
||||||
|
|
||||||
|
QComboBox *scenes;
|
||||||
|
QComboBox *transitions;
|
||||||
|
|
||||||
|
SceneSwitcherEntry *switchData;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
|
||||||
#include "utility.hpp"
|
|
||||||
#include "switch-generic.hpp"
|
#include "switch-generic.hpp"
|
||||||
|
|
||||||
constexpr auto default_idle_time = 60;
|
constexpr auto default_idle_time = 60;
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
|
||||||
#include "utility.hpp"
|
|
||||||
#include "switch-generic.hpp"
|
#include "switch-generic.hpp"
|
||||||
|
|
||||||
constexpr auto media_func = 6;
|
constexpr auto media_func = 6;
|
||||||
@@ -15,36 +13,73 @@ typedef enum {
|
|||||||
} time_restriction;
|
} time_restriction;
|
||||||
|
|
||||||
struct MediaSwitch : SceneSwitcherEntry {
|
struct MediaSwitch : SceneSwitcherEntry {
|
||||||
OBSWeakSource source;
|
OBSWeakSource source = nullptr;
|
||||||
obs_media_state state;
|
obs_media_state state = OBS_MEDIA_STATE_NONE;
|
||||||
time_restriction restriction;
|
bool anyState = false;
|
||||||
int64_t time;
|
time_restriction restriction = TIME_RESTRICTION_NONE;
|
||||||
bool matched;
|
int64_t time = 0;
|
||||||
std::string mediaSwitchStr;
|
|
||||||
|
|
||||||
const char *getType() { return "meida"; }
|
// trigger scene change only once even if media state might trigger repeatedly
|
||||||
|
bool matched = false;
|
||||||
|
|
||||||
bool valid()
|
std::atomic<bool> stopped = false;
|
||||||
{
|
std::atomic<bool> ended = false;
|
||||||
return (usePreviousScene || WeakSourceValid(scene)) &&
|
|
||||||
WeakSourceValid(source) && WeakSourceValid(transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// workaround to enable use of "ended" to specify end of VLC playlist
|
||||||
|
bool previousStateEnded = false;
|
||||||
|
|
||||||
|
bool playedToEnd = false;
|
||||||
|
|
||||||
|
const char *getType() { return "media"; }
|
||||||
|
bool initialized();
|
||||||
|
bool valid();
|
||||||
|
|
||||||
|
void clearSignalHandler();
|
||||||
|
void resetSignalHandler();
|
||||||
|
static void MediaStopped(void *data, calldata_t *);
|
||||||
|
static void MediaEnded(void *data, calldata_t *);
|
||||||
|
|
||||||
|
inline MediaSwitch(){};
|
||||||
inline MediaSwitch(OBSWeakSource scene_, OBSWeakSource source_,
|
inline MediaSwitch(OBSWeakSource scene_, OBSWeakSource source_,
|
||||||
OBSWeakSource transition_, obs_media_state state_,
|
OBSWeakSource transition_, obs_media_state state_,
|
||||||
time_restriction restriction_, uint64_t time_,
|
time_restriction restriction_, uint64_t time_,
|
||||||
bool usePreviousScene_, std::string mediaSwitchStr_)
|
bool usePreviousScene_);
|
||||||
: SceneSwitcherEntry(scene_, transition_, usePreviousScene_),
|
MediaSwitch(const MediaSwitch &other);
|
||||||
source(source_),
|
MediaSwitch(MediaSwitch &&other);
|
||||||
state(state_),
|
~MediaSwitch();
|
||||||
restriction(restriction_),
|
MediaSwitch &operator=(const MediaSwitch &other);
|
||||||
time(time_),
|
MediaSwitch &operator=(MediaSwitch &&other) noexcept;
|
||||||
mediaSwitchStr(mediaSwitchStr_)
|
friend void swap(MediaSwitch &first, MediaSwitch &second);
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline QString
|
class MediaSwitchWidget : public SwitchWidget {
|
||||||
MakeMediaSwitchName(const QString &source, const QString &scene,
|
Q_OBJECT
|
||||||
const QString &transition, obs_media_state state,
|
|
||||||
time_restriction restriction, uint64_t time);
|
public:
|
||||||
|
MediaSwitchWidget(MediaSwitch *s);
|
||||||
|
MediaSwitch *getSwitchData();
|
||||||
|
void setSwitchData(MediaSwitch *s);
|
||||||
|
|
||||||
|
static void swapSwitchData(MediaSwitchWidget *s1,
|
||||||
|
MediaSwitchWidget *s2);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void SourceChanged(const QString &text);
|
||||||
|
void StateChanged(int index);
|
||||||
|
void TimeRestrictionChanged(int index);
|
||||||
|
void TimeChanged(int time);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QComboBox *meidaSources;
|
||||||
|
QComboBox *states;
|
||||||
|
QComboBox *timeRestrictions;
|
||||||
|
QSpinBox *time;
|
||||||
|
|
||||||
|
QLabel *whenLabel;
|
||||||
|
QLabel *stateLabel;
|
||||||
|
QLabel *andLabel;
|
||||||
|
QLabel *switchLabel;
|
||||||
|
QLabel *usingLabel;
|
||||||
|
|
||||||
|
MediaSwitch *switchData;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,23 +1,39 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
|
||||||
#include "utility.hpp"
|
|
||||||
#include "switch-generic.hpp"
|
#include "switch-generic.hpp"
|
||||||
|
|
||||||
struct RandomSwitch : SceneSwitcherEntry {
|
struct RandomSwitch : SceneSwitcherEntry {
|
||||||
double delay;
|
double delay = 0.0;
|
||||||
std::string randomSwitchStr;
|
|
||||||
|
|
||||||
const char *getType() { return "random"; }
|
const char *getType() { return "random"; }
|
||||||
|
|
||||||
|
inline RandomSwitch() {}
|
||||||
inline RandomSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
inline RandomSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
||||||
double delay_, std::string str)
|
double delay_)
|
||||||
: SceneSwitcherEntry(scene_, transition_),
|
: SceneSwitcherEntry(scene_, transition_), delay(delay_)
|
||||||
delay(delay_),
|
|
||||||
randomSwitchStr(str)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline QString MakeRandomSwitchName(const QString &scene,
|
class RandomSwitchWidget : public SwitchWidget {
|
||||||
const QString &transition,
|
Q_OBJECT
|
||||||
double &delay);
|
|
||||||
|
public:
|
||||||
|
RandomSwitchWidget(RandomSwitch *s);
|
||||||
|
RandomSwitch *getSwitchData();
|
||||||
|
void setSwitchData(RandomSwitch *s);
|
||||||
|
|
||||||
|
static void swapSwitchData(RandomSwitchWidget *s1,
|
||||||
|
RandomSwitchWidget *s2);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void DelayChanged(double d);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QDoubleSpinBox *delay;
|
||||||
|
|
||||||
|
QLabel *switchLabel;
|
||||||
|
QLabel *usingLabel;
|
||||||
|
QLabel *forLabel;
|
||||||
|
|
||||||
|
RandomSwitch *switchData;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,32 +1,62 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
#include <QSpinBox>
|
||||||
#include "utility.hpp"
|
|
||||||
#include "switch-generic.hpp"
|
#include "switch-generic.hpp"
|
||||||
|
|
||||||
constexpr auto screen_region_func = 4;
|
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 {
|
||||||
int minX, minY, maxX, maxY;
|
int minX = 0, minY = 0, maxX = 0, maxY = 0;
|
||||||
std::string regionStr;
|
|
||||||
|
|
||||||
const char *getType() { return "region"; }
|
const char *getType() { return "region"; }
|
||||||
|
|
||||||
|
inline ScreenRegionSwitch(){};
|
||||||
inline ScreenRegionSwitch(OBSWeakSource scene_,
|
inline ScreenRegionSwitch(OBSWeakSource scene_,
|
||||||
OBSWeakSource transition_, int minX_,
|
OBSWeakSource transition_, int minX_,
|
||||||
int minY_, int maxX_, int maxY_,
|
int minY_, int maxX_, int maxY_)
|
||||||
std::string regionStr_)
|
|
||||||
: SceneSwitcherEntry(scene_, transition_),
|
: SceneSwitcherEntry(scene_, transition_),
|
||||||
minX(minX_),
|
minX(minX_),
|
||||||
minY(minY_),
|
minY(minY_),
|
||||||
maxX(maxX_),
|
maxX(maxX_),
|
||||||
maxY(maxY_),
|
maxY(maxY_)
|
||||||
regionStr(regionStr_)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline QString MakeScreenRegionSwitchName(const QString &scene,
|
class ScreenRegionWidget : public SwitchWidget {
|
||||||
const QString &transition,
|
Q_OBJECT
|
||||||
int minX, int minY, int maxX,
|
|
||||||
int maxY);
|
public:
|
||||||
|
ScreenRegionWidget(ScreenRegionSwitch *s);
|
||||||
|
ScreenRegionSwitch *getSwitchData();
|
||||||
|
void setSwitchData(ScreenRegionSwitch *s);
|
||||||
|
|
||||||
|
static void swapSwitchData(ScreenRegionWidget *s1,
|
||||||
|
ScreenRegionWidget *s2);
|
||||||
|
|
||||||
|
void showFrame();
|
||||||
|
void hideFrame();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void MinXChanged(int pos);
|
||||||
|
void MinYChanged(int pos);
|
||||||
|
void MaxXChanged(int pos);
|
||||||
|
void MaxYChanged(int pos);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QSpinBox *minX;
|
||||||
|
QSpinBox *minY;
|
||||||
|
QSpinBox *maxX;
|
||||||
|
QSpinBox *maxY;
|
||||||
|
|
||||||
|
QFrame helperFrame;
|
||||||
|
|
||||||
|
QLabel *cursorLabel;
|
||||||
|
QLabel *xLabel;
|
||||||
|
QLabel *switchLabel;
|
||||||
|
QLabel *usingLabel;
|
||||||
|
|
||||||
|
ScreenRegionSwitch *switchData;
|
||||||
|
|
||||||
|
void drawFrame();
|
||||||
|
};
|
||||||
|
|||||||
64
src/headers/switch-sequence.hpp
Normal file
64
src/headers/switch-sequence.hpp
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "switch-generic.hpp"
|
||||||
|
|
||||||
|
constexpr auto round_trip_func = 1;
|
||||||
|
constexpr auto default_priority_1 = round_trip_func;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SECONDS,
|
||||||
|
MINUTES,
|
||||||
|
HOURS,
|
||||||
|
} delay_units;
|
||||||
|
|
||||||
|
struct SceneSequenceSwitch : SceneSwitcherEntry {
|
||||||
|
OBSWeakSource startScene = nullptr;
|
||||||
|
double delay = 0;
|
||||||
|
int delayMultiplier = 1;
|
||||||
|
|
||||||
|
const char *getType() { return "sequence"; }
|
||||||
|
bool initialized();
|
||||||
|
bool valid();
|
||||||
|
void logSleep(int dur);
|
||||||
|
|
||||||
|
inline SceneSequenceSwitch(){};
|
||||||
|
inline SceneSequenceSwitch(OBSWeakSource startScene_,
|
||||||
|
OBSWeakSource scene_,
|
||||||
|
OBSWeakSource transition_, double delay_,
|
||||||
|
int delayMultiplier_, bool usePreviousScene_)
|
||||||
|
: SceneSwitcherEntry(scene_, transition_, usePreviousScene_),
|
||||||
|
startScene(startScene_),
|
||||||
|
delay(delay_),
|
||||||
|
delayMultiplier(delayMultiplier_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SequenceWidget : public SwitchWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
SequenceWidget(SceneSequenceSwitch *s);
|
||||||
|
SceneSequenceSwitch *getSwitchData();
|
||||||
|
void setSwitchData(SceneSequenceSwitch *s);
|
||||||
|
|
||||||
|
static void swapSwitchData(SequenceWidget *s1, SequenceWidget *s2);
|
||||||
|
|
||||||
|
void UpdateDelay();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void DelayChanged(double delay);
|
||||||
|
void DelayUnitsChanged(int idx);
|
||||||
|
void StartSceneChanged(const QString &text);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QDoubleSpinBox *delay;
|
||||||
|
QComboBox *delayUnits;
|
||||||
|
QComboBox *startScenes;
|
||||||
|
|
||||||
|
QLabel *whenLabel;
|
||||||
|
QLabel *switchLabel;
|
||||||
|
QLabel *afterLabel;
|
||||||
|
QLabel *usingLabel;
|
||||||
|
|
||||||
|
SceneSequenceSwitch *switchData;
|
||||||
|
};
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
#include <QTimeEdit>
|
||||||
#include <QDateTime>
|
|
||||||
#include "utility.hpp"
|
|
||||||
#include "switch-generic.hpp"
|
#include "switch-generic.hpp"
|
||||||
|
|
||||||
constexpr auto time_func = 7;
|
constexpr auto time_func = 7;
|
||||||
@@ -20,24 +19,43 @@ typedef enum {
|
|||||||
} timeTrigger;
|
} timeTrigger;
|
||||||
|
|
||||||
struct TimeSwitch : SceneSwitcherEntry {
|
struct TimeSwitch : SceneSwitcherEntry {
|
||||||
timeTrigger trigger;
|
timeTrigger trigger = ANY_DAY;
|
||||||
QTime time;
|
QTime time = QTime();
|
||||||
std::string timeSwitchStr;
|
|
||||||
|
|
||||||
const char *getType() { return "time"; }
|
const char *getType() { return "time"; }
|
||||||
|
|
||||||
|
inline TimeSwitch(){};
|
||||||
inline TimeSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
inline TimeSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
||||||
timeTrigger trigger_, QTime time_,
|
timeTrigger trigger_, QTime time_,
|
||||||
bool usePreviousScene_, std::string timeSwitchStr_)
|
bool usePreviousScene_)
|
||||||
: SceneSwitcherEntry(scene_, transition_, usePreviousScene_),
|
: SceneSwitcherEntry(scene_, transition_, usePreviousScene_),
|
||||||
trigger(trigger_),
|
trigger(trigger_),
|
||||||
time(time_),
|
time(time_)
|
||||||
timeSwitchStr(timeSwitchStr_)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline QString MakeTimeSwitchName(const QString &scene,
|
class TimeSwitchWidget : public SwitchWidget {
|
||||||
const QString &transition,
|
Q_OBJECT
|
||||||
const timeTrigger &trigger,
|
|
||||||
const QTime &time);
|
public:
|
||||||
|
TimeSwitchWidget(TimeSwitch *s);
|
||||||
|
TimeSwitch *getSwitchData();
|
||||||
|
void setSwitchData(TimeSwitch *s);
|
||||||
|
|
||||||
|
static void swapSwitchData(TimeSwitchWidget *s1, TimeSwitchWidget *s2);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void TriggerChanged(int index);
|
||||||
|
void TimeChanged(const QTime &time);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QComboBox *triggers;
|
||||||
|
QTimeEdit *time;
|
||||||
|
|
||||||
|
QLabel *atLabel;
|
||||||
|
QLabel *switchLabel;
|
||||||
|
QLabel *usingLabel;
|
||||||
|
|
||||||
|
TimeSwitch *switchData;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,47 +1,71 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
|
||||||
#include "utility.hpp"
|
|
||||||
#include "switch-generic.hpp"
|
#include "switch-generic.hpp"
|
||||||
|
|
||||||
struct SceneTransition : SceneSwitcherEntry {
|
struct SceneTransition : SceneSwitcherEntry {
|
||||||
OBSWeakSource scene2;
|
OBSWeakSource scene2 = nullptr;
|
||||||
std::string sceneTransitionStr;
|
|
||||||
|
|
||||||
const char *getType() { return "transition"; }
|
const char *getType() { return "transition"; }
|
||||||
|
bool initialized();
|
||||||
|
bool valid();
|
||||||
|
|
||||||
bool valid()
|
inline SceneTransition(){};
|
||||||
{
|
|
||||||
return (WeakSourceValid(scene) && WeakSourceValid(scene2)) &&
|
|
||||||
WeakSourceValid(transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline SceneTransition(OBSWeakSource scene_, OBSWeakSource scene2_,
|
inline SceneTransition(OBSWeakSource scene_, OBSWeakSource scene2_,
|
||||||
OBSWeakSource transition_,
|
OBSWeakSource transition_)
|
||||||
std::string sceneTransitionStr_)
|
: SceneSwitcherEntry(scene_, transition_), scene2(scene2_)
|
||||||
: SceneSwitcherEntry(scene_, transition_),
|
|
||||||
scene2(scene2_),
|
|
||||||
sceneTransitionStr(sceneTransitionStr_)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline QString MakeSceneTransitionName(const QString &scene1,
|
|
||||||
const QString &scene2,
|
|
||||||
const QString &transition);
|
|
||||||
|
|
||||||
struct DefaultSceneTransition : SceneSwitcherEntry {
|
struct DefaultSceneTransition : SceneSwitcherEntry {
|
||||||
std::string sceneTransitionStr;
|
|
||||||
|
|
||||||
const char *getType() { return "def_transition"; }
|
const char *getType() { return "def_transition"; }
|
||||||
|
|
||||||
|
inline DefaultSceneTransition(){};
|
||||||
inline DefaultSceneTransition(OBSWeakSource scene_,
|
inline DefaultSceneTransition(OBSWeakSource scene_,
|
||||||
OBSWeakSource transition_,
|
OBSWeakSource transition_)
|
||||||
std::string sceneTransitionStr_)
|
: SceneSwitcherEntry(scene_, transition_)
|
||||||
: SceneSwitcherEntry(scene_, transition_),
|
|
||||||
sceneTransitionStr(sceneTransitionStr_)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline QString MakeDefaultSceneTransitionName(const QString &scene,
|
class TransitionSwitchWidget : public SwitchWidget {
|
||||||
const QString &transition);
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
TransitionSwitchWidget(SceneTransition *s);
|
||||||
|
SceneTransition *getSwitchData();
|
||||||
|
void setSwitchData(SceneTransition *s);
|
||||||
|
|
||||||
|
static void swapSwitchData(TransitionSwitchWidget *s1,
|
||||||
|
TransitionSwitchWidget *s2);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void Scene2Changed(const QString &text);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QComboBox *scenes2;
|
||||||
|
|
||||||
|
QLabel *switchLabel;
|
||||||
|
QLabel *toLabel;
|
||||||
|
QLabel *usingLabel;
|
||||||
|
|
||||||
|
SceneTransition *switchData;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DefTransitionSwitchWidget : public SwitchWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
DefTransitionSwitchWidget(DefaultSceneTransition *s);
|
||||||
|
DefaultSceneTransition *getSwitchData();
|
||||||
|
void setSwitchData(DefaultSceneTransition *s);
|
||||||
|
|
||||||
|
static void swapSwitchData(DefTransitionSwitchWidget *s1,
|
||||||
|
DefTransitionSwitchWidget *s2);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QLabel *whenLabel;
|
||||||
|
QLabel *switchLabel;
|
||||||
|
|
||||||
|
DefaultSceneTransition *switchData;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,22 +1,21 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
|
||||||
#include "utility.hpp"
|
|
||||||
#include "switch-generic.hpp"
|
#include "switch-generic.hpp"
|
||||||
|
|
||||||
constexpr auto window_title_func = 5;
|
constexpr auto window_title_func = 5;
|
||||||
constexpr auto default_priority_5 = window_title_func;
|
constexpr auto default_priority_5 = window_title_func;
|
||||||
|
|
||||||
struct WindowSceneSwitch : SceneSwitcherEntry {
|
struct WindowSwitch : SceneSwitcherEntry {
|
||||||
std::string window;
|
std::string window = "";
|
||||||
bool fullscreen;
|
bool fullscreen = false;
|
||||||
bool maximized;
|
bool maximized = false;
|
||||||
bool focus;
|
bool focus = true;
|
||||||
|
|
||||||
const char *getType() { return "window"; }
|
const char *getType() { return "window"; }
|
||||||
|
|
||||||
inline WindowSceneSwitch(OBSWeakSource scene_, const char *window_,
|
inline WindowSwitch() {}
|
||||||
OBSWeakSource transition_, bool fullscreen_,
|
inline WindowSwitch(OBSWeakSource scene_, const char *window_,
|
||||||
bool maximized_, bool focus_)
|
OBSWeakSource transition_, bool fullscreen_,
|
||||||
|
bool maximized_, bool focus_)
|
||||||
: SceneSwitcherEntry(scene_, transition_),
|
: SceneSwitcherEntry(scene_, transition_),
|
||||||
window(window_),
|
window(window_),
|
||||||
fullscreen(fullscreen_),
|
fullscreen(fullscreen_),
|
||||||
@@ -26,8 +25,28 @@ struct WindowSceneSwitch : SceneSwitcherEntry {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline QString MakeWindowSwitchName(const QString &scene,
|
class WindowSwitchWidget : public SwitchWidget {
|
||||||
const QString &value,
|
Q_OBJECT
|
||||||
const QString &transition,
|
|
||||||
bool fullscreen, bool maximized,
|
public:
|
||||||
bool focus);
|
WindowSwitchWidget(WindowSwitch *s);
|
||||||
|
WindowSwitch *getSwitchData();
|
||||||
|
void setSwitchData(WindowSwitch *s);
|
||||||
|
|
||||||
|
static void swapSwitchData(WindowSwitchWidget *s1,
|
||||||
|
WindowSwitchWidget *s2);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void WindowChanged(const QString &text);
|
||||||
|
void FullscreenChanged(int state);
|
||||||
|
void MaximizedChanged(int state);
|
||||||
|
void FocusChanged(int state);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QComboBox *windows;
|
||||||
|
QCheckBox *fullscreen;
|
||||||
|
QCheckBox *maximized;
|
||||||
|
QCheckBox *focused;
|
||||||
|
|
||||||
|
WindowSwitch *switchData;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <deque>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
#include "switch-time.hpp"
|
#include "switch-time.hpp"
|
||||||
#include "switch-transitions.hpp"
|
#include "switch-transitions.hpp"
|
||||||
#include "switch-window.hpp"
|
#include "switch-window.hpp"
|
||||||
#include "swtich-sequence.hpp"
|
#include "switch-sequence.hpp"
|
||||||
|
|
||||||
constexpr auto default_interval = 300;
|
constexpr auto default_interval = 300;
|
||||||
constexpr auto previous_scene_name = "Previous Scene";
|
constexpr auto previous_scene_name = "Previous Scene";
|
||||||
@@ -30,6 +30,12 @@ typedef enum {
|
|||||||
RECORINDGSTREAMING = 2
|
RECORINDGSTREAMING = 2
|
||||||
} AutoStartType;
|
} AutoStartType;
|
||||||
|
|
||||||
|
typedef struct transitionData {
|
||||||
|
std::string name = "";
|
||||||
|
int duration = 0;
|
||||||
|
|
||||||
|
} transitionData;
|
||||||
|
|
||||||
class SwitcherThread;
|
class SwitcherThread;
|
||||||
|
|
||||||
/********************************************************************************
|
/********************************************************************************
|
||||||
@@ -45,23 +51,27 @@ struct SwitcherData {
|
|||||||
std::condition_variable transitionCv;
|
std::condition_variable transitionCv;
|
||||||
bool stop = false;
|
bool stop = false;
|
||||||
bool verbose = false;
|
bool verbose = false;
|
||||||
|
bool disableHints = false;
|
||||||
|
bool showFrame = false;
|
||||||
bool tansitionOverrideOverride = false;
|
bool tansitionOverrideOverride = false;
|
||||||
|
|
||||||
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 previousScene2 = 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;
|
||||||
|
|
||||||
std::vector<WindowSceneSwitch> windowSwitches;
|
std::deque<WindowSwitch> windowSwitches;
|
||||||
std::vector<std::string> ignoreIdleWindows;
|
std::vector<std::string> ignoreIdleWindows;
|
||||||
std::string lastTitle;
|
std::string lastTitle;
|
||||||
|
|
||||||
std::vector<ScreenRegionSwitch> screenRegionSwitches;
|
std::deque<ScreenRegionSwitch> screenRegionSwitches;
|
||||||
|
|
||||||
std::vector<OBSWeakSource> pauseScenesSwitches;
|
std::vector<OBSWeakSource> pauseScenesSwitches;
|
||||||
|
|
||||||
@@ -69,17 +79,17 @@ struct SwitcherData {
|
|||||||
|
|
||||||
std::vector<std::string> ignoreWindowsSwitches;
|
std::vector<std::string> ignoreWindowsSwitches;
|
||||||
|
|
||||||
std::vector<SceneSequenceSwitch> sceneSequenceSwitches;
|
std::deque<SceneSequenceSwitch> sceneSequenceSwitches;
|
||||||
int sceneSequenceMultiplier = 1;
|
|
||||||
|
|
||||||
std::vector<RandomSwitch> randomSwitches;
|
std::deque<RandomSwitch> randomSwitches;
|
||||||
|
|
||||||
|
IdleData idleData;
|
||||||
|
|
||||||
FileIOData fileIO;
|
FileIOData fileIO;
|
||||||
IdleData idleData;
|
|
||||||
std::vector<FileSwitch> fileSwitches;
|
std::vector<FileSwitch> fileSwitches;
|
||||||
CURL *curl = nullptr;
|
CURL *curl = nullptr;
|
||||||
|
|
||||||
std::vector<ExecutableSceneSwitch> executableSwitches;
|
std::deque<ExecutableSwitch> executableSwitches;
|
||||||
|
|
||||||
bool autoStopEnable = false;
|
bool autoStopEnable = false;
|
||||||
OBSWeakSource autoStopScene;
|
OBSWeakSource autoStopScene;
|
||||||
@@ -89,15 +99,16 @@ struct SwitcherData {
|
|||||||
OBSWeakSource autoStartScene;
|
OBSWeakSource autoStartScene;
|
||||||
bool autoStartedRecently = false;
|
bool autoStartedRecently = false;
|
||||||
|
|
||||||
std::vector<SceneTransition> sceneTransitions;
|
std::deque<SceneTransition> sceneTransitions;
|
||||||
std::vector<DefaultSceneTransition> defaultSceneTransitions;
|
std::deque<DefaultSceneTransition> defaultSceneTransitions;
|
||||||
|
bool checkedDefTransition = false;
|
||||||
|
|
||||||
std::vector<MediaSwitch> mediaSwitches;
|
std::deque<MediaSwitch> mediaSwitches;
|
||||||
|
|
||||||
std::vector<TimeSwitch> timeSwitches;
|
std::deque<TimeSwitch> timeSwitches;
|
||||||
QDateTime liveTime;
|
QDateTime liveTime;
|
||||||
|
|
||||||
std::vector<AudioSwitch> audioSwitches;
|
std::deque<AudioSwitch> audioSwitches;
|
||||||
|
|
||||||
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,
|
||||||
@@ -134,9 +145,9 @@ 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;
|
||||||
|
|
||||||
void Thread();
|
void Thread();
|
||||||
void Start();
|
void Start();
|
||||||
@@ -145,13 +156,15 @@ struct SwitcherData {
|
|||||||
bool sceneChangedDuringWait();
|
bool sceneChangedDuringWait();
|
||||||
bool prioFuncsValid();
|
bool prioFuncsValid();
|
||||||
void writeSceneInfoToFile();
|
void writeSceneInfoToFile();
|
||||||
void setDefaultSceneTransitions();
|
|
||||||
void autoStopStreamAndRecording();
|
void autoStopStreamAndRecording();
|
||||||
void autoStartStreamRecording();
|
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,
|
||||||
std::unique_lock<std::mutex> &lock);
|
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,
|
||||||
@@ -172,6 +185,8 @@ struct SwitcherData {
|
|||||||
OBSWeakSource &transition);
|
OBSWeakSource &transition);
|
||||||
void checkAudioSwitch(bool &match, OBSWeakSource &scene,
|
void checkAudioSwitch(bool &match, OBSWeakSource &scene,
|
||||||
OBSWeakSource &transition);
|
OBSWeakSource &transition);
|
||||||
|
void checkNoMatchSwitch(bool &match, OBSWeakSource &scene,
|
||||||
|
OBSWeakSource &transition, int &sleep);
|
||||||
|
|
||||||
void saveWindowTitleSwitches(obs_data_t *obj);
|
void saveWindowTitleSwitches(obs_data_t *obj);
|
||||||
void saveScreenRegionSwitches(obs_data_t *obj);
|
void saveScreenRegionSwitches(obs_data_t *obj);
|
||||||
@@ -204,6 +219,7 @@ struct SwitcherData {
|
|||||||
void loadHotkeys(obs_data_t *obj);
|
void loadHotkeys(obs_data_t *obj);
|
||||||
|
|
||||||
void Prune();
|
void Prune();
|
||||||
|
|
||||||
inline ~SwitcherData() { Stop(); }
|
inline ~SwitcherData() { Stop(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <string>
|
|
||||||
#include "utility.hpp"
|
|
||||||
#include "switch-generic.hpp"
|
|
||||||
|
|
||||||
constexpr auto round_trip_func = 1;
|
|
||||||
constexpr auto default_priority_1 = round_trip_func;
|
|
||||||
|
|
||||||
struct SceneSequenceSwitch : SceneSwitcherEntry {
|
|
||||||
OBSWeakSource startScene;
|
|
||||||
double delay;
|
|
||||||
std::string sceneSequenceStr;
|
|
||||||
|
|
||||||
const char *getType() { return "sequence"; }
|
|
||||||
|
|
||||||
bool valid()
|
|
||||||
{
|
|
||||||
return WeakSourceValid(startScene) &&
|
|
||||||
(usePreviousScene || WeakSourceValid(scene)) &&
|
|
||||||
WeakSourceValid(transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
void logSleep(int dur)
|
|
||||||
{
|
|
||||||
blog(LOG_INFO, "Advanced Scene Switcher sequence sleep %d",
|
|
||||||
dur);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline SceneSequenceSwitch(OBSWeakSource startScene_,
|
|
||||||
OBSWeakSource scene_,
|
|
||||||
OBSWeakSource transition_, double delay_,
|
|
||||||
bool usePreviousScene_, std::string str)
|
|
||||||
: SceneSwitcherEntry(scene_, transition_, usePreviousScene_),
|
|
||||||
startScene(startScene_),
|
|
||||||
delay(delay_),
|
|
||||||
sceneSequenceStr(str)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline QString MakeSceneSequenceSwitchName(const QString &scene1,
|
|
||||||
const QString &scene2,
|
|
||||||
const QString &transition,
|
|
||||||
double delay);
|
|
||||||
1
src/headers/version.h
Normal file
1
src/headers/version.h
Normal file
@@ -0,0 +1 @@
|
|||||||
|
extern const char g_GIT_SHA1[];
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -1,187 +1,80 @@
|
|||||||
#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"
|
||||||
|
|
||||||
void SceneSwitcher::on_audioSwitches_currentRowChanged(int idx)
|
static QMetaObject::Connection addPulse;
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_audioAdd_clicked()
|
||||||
{
|
{
|
||||||
if (loading)
|
ui->audioAdd->disconnect(addPulse);
|
||||||
return;
|
|
||||||
if (idx == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QListWidgetItem *item = ui->audioSwitches->item(idx);
|
|
||||||
|
|
||||||
QString audioScenestr = 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->audioSwitches) {
|
switcher->audioSwitches.emplace_back();
|
||||||
if (audioScenestr.compare(s.audioSwitchStr.c_str()) == 0) {
|
|
||||||
QString sceneName = GetWeakSourceName(s.scene).c_str();
|
QListWidgetItem *item;
|
||||||
QString audioSrouceName =
|
item = new QListWidgetItem(ui->audioSwitches);
|
||||||
GetWeakSourceName(s.audioSource).c_str();
|
ui->audioSwitches->addItem(item);
|
||||||
QString transitionName =
|
AudioSwitchWidget *sw =
|
||||||
GetWeakSourceName(s.transition).c_str();
|
new AudioSwitchWidget(&switcher->audioSwitches.back());
|
||||||
ui->audioScenes->setCurrentText(sceneName);
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
ui->audioTransitions->setCurrentText(transitionName);
|
ui->audioSwitches->setItemWidget(item, sw);
|
||||||
ui->audioSources->setCurrentText(audioSrouceName);
|
|
||||||
ui->audioVolumeThreshold->setValue(s.volumeThreshold);
|
|
||||||
volMeter->GetSlider()->setValue(s.volumeThreshold);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_audioSources_currentTextChanged(const QString &text)
|
void AdvSceneSwitcher::on_audioRemove_clicked()
|
||||||
{
|
|
||||||
SetAudioVolumeMeter(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::SetAudioVolumeMeter(const QString &name)
|
|
||||||
{
|
|
||||||
obs_source_t *soruce =
|
|
||||||
obs_get_source_by_name(name.toUtf8().constData());
|
|
||||||
if (!soruce) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (volMeter) {
|
|
||||||
ui->audioControlLayout->removeWidget(volMeter);
|
|
||||||
delete volMeter;
|
|
||||||
}
|
|
||||||
|
|
||||||
volMeter = new VolControl(soruce);
|
|
||||||
ui->audioControlLayout->addWidget(volMeter);
|
|
||||||
obs_source_release(soruce);
|
|
||||||
|
|
||||||
QWidget::connect(volMeter->GetSlider(), SIGNAL(valueChanged(int)),
|
|
||||||
ui->audioVolumeThreshold, SLOT(setValue(int)));
|
|
||||||
QWidget::connect(ui->audioVolumeThreshold, SIGNAL(valueChanged(int)),
|
|
||||||
volMeter->GetSlider(), SLOT(setValue(int)));
|
|
||||||
}
|
|
||||||
|
|
||||||
int SceneSwitcher::audioFindByData(const QString &source, const int &volume)
|
|
||||||
{
|
|
||||||
QRegExp rx(MakeAudioSwitchName(QStringLiteral(".*"),
|
|
||||||
QStringLiteral(".*"), source, volume));
|
|
||||||
int count = ui->audioSwitches->count();
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
QListWidgetItem *item = ui->audioSwitches->item(i);
|
|
||||||
QString str = item->data(Qt::UserRole).toString();
|
|
||||||
|
|
||||||
if (rx.exactMatch(str))
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_audioAdd_clicked()
|
|
||||||
{
|
|
||||||
QString sceneName = ui->audioScenes->currentText();
|
|
||||||
QString transitionName = ui->audioTransitions->currentText();
|
|
||||||
QString audioSourceName = ui->audioSources->currentText();
|
|
||||||
int vol = ui->audioVolumeThreshold->value();
|
|
||||||
|
|
||||||
if (sceneName.isEmpty() || audioSourceName.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
OBSWeakSource source = GetWeakSourceByQString(sceneName);
|
|
||||||
OBSWeakSource audioSource = GetWeakSourceByQString(audioSourceName);
|
|
||||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
|
||||||
|
|
||||||
QString text = MakeAudioSwitchName(sceneName, transitionName,
|
|
||||||
audioSourceName, vol);
|
|
||||||
QVariant v = QVariant::fromValue(text);
|
|
||||||
|
|
||||||
int idx = audioFindByData(audioSourceName, vol);
|
|
||||||
|
|
||||||
if (idx == -1) {
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
switcher->audioSwitches.emplace_back(
|
|
||||||
source, transition, audioSource, vol,
|
|
||||||
(sceneName == QString(previous_scene_name)),
|
|
||||||
text.toUtf8().constData());
|
|
||||||
QListWidgetItem *item =
|
|
||||||
new QListWidgetItem(text, ui->audioSwitches);
|
|
||||||
item->setData(Qt::UserRole, v);
|
|
||||||
} else {
|
|
||||||
QListWidgetItem *item = ui->audioSwitches->item(idx);
|
|
||||||
item->setText(text);
|
|
||||||
item->setData(Qt::UserRole, v);
|
|
||||||
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
for (auto &s : switcher->audioSwitches) {
|
|
||||||
if (s.audioSource == audioSource &&
|
|
||||||
s.volumeThreshold == vol) {
|
|
||||||
s.scene = source;
|
|
||||||
s.transition = transition;
|
|
||||||
s.usePreviousScene =
|
|
||||||
(sceneName ==
|
|
||||||
QString(previous_scene_name));
|
|
||||||
s.audioSwitchStr =
|
|
||||||
text.toUtf8().constData();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_audioRemove_clicked()
|
|
||||||
{
|
{
|
||||||
QListWidgetItem *item = ui->audioSwitches->currentItem();
|
QListWidgetItem *item = ui->audioSwitches->currentItem();
|
||||||
if (!item)
|
if (!item)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::string text =
|
|
||||||
item->data(Qt::UserRole).toString().toUtf8().constData();
|
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
int idx = ui->audioSwitches->currentRow();
|
||||||
auto &switches = switcher->audioSwitches;
|
auto &switches = switcher->audioSwitches;
|
||||||
|
switches.erase(switches.begin() + idx);
|
||||||
for (auto it = switches.begin(); it != switches.end(); ++it) {
|
|
||||||
auto &s = *it;
|
|
||||||
|
|
||||||
if (s.audioSwitchStr == text) {
|
|
||||||
switches.erase(it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete item;
|
delete item;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_audioUp_clicked()
|
void AdvSceneSwitcher::on_audioUp_clicked()
|
||||||
{
|
{
|
||||||
int index = ui->audioSwitches->currentRow();
|
int index = ui->audioSwitches->currentRow();
|
||||||
if (index != -1 && index != 0) {
|
if (!listMoveUp(ui->audioSwitches))
|
||||||
ui->audioSwitches->insertItem(
|
return;
|
||||||
index - 1, ui->audioSwitches->takeItem(index));
|
|
||||||
ui->audioSwitches->setCurrentRow(index - 1);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
AudioSwitchWidget *s1 =
|
||||||
|
(AudioSwitchWidget *)ui->audioSwitches->itemWidget(
|
||||||
|
ui->audioSwitches->item(index));
|
||||||
|
AudioSwitchWidget *s2 =
|
||||||
|
(AudioSwitchWidget *)ui->audioSwitches->itemWidget(
|
||||||
|
ui->audioSwitches->item(index - 1));
|
||||||
|
AudioSwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
iter_swap(switcher->audioSwitches.begin() + index,
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switcher->audioSwitches.begin() + index - 1);
|
|
||||||
}
|
std::swap(switcher->audioSwitches[index],
|
||||||
|
switcher->audioSwitches[index - 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_audioDown_clicked()
|
void AdvSceneSwitcher::on_audioDown_clicked()
|
||||||
{
|
{
|
||||||
int index = ui->audioSwitches->currentRow();
|
int index = ui->audioSwitches->currentRow();
|
||||||
if (index != -1 && index != ui->audioSwitches->count() - 1) {
|
|
||||||
ui->audioSwitches->insertItem(
|
|
||||||
index + 1, ui->audioSwitches->takeItem(index));
|
|
||||||
ui->audioSwitches->setCurrentRow(index + 1);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
if (!listMoveDown(ui->audioSwitches))
|
||||||
|
return;
|
||||||
|
|
||||||
iter_swap(switcher->audioSwitches.begin() + index,
|
AudioSwitchWidget *s1 =
|
||||||
switcher->audioSwitches.begin() + index + 1);
|
(AudioSwitchWidget *)ui->audioSwitches->itemWidget(
|
||||||
}
|
ui->audioSwitches->item(index));
|
||||||
|
AudioSwitchWidget *s2 =
|
||||||
|
(AudioSwitchWidget *)ui->audioSwitches->itemWidget(
|
||||||
|
ui->audioSwitches->item(index + 1));
|
||||||
|
AudioSwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
|
||||||
|
std::swap(switcher->audioSwitches[index],
|
||||||
|
switcher->audioSwitches[index + 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitcherData::checkAudioSwitch(bool &match, OBSWeakSource &scene,
|
void SwitcherData::checkAudioSwitch(bool &match, OBSWeakSource &scene,
|
||||||
@@ -191,12 +84,15 @@ void SwitcherData::checkAudioSwitch(bool &match, OBSWeakSource &scene,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
for (AudioSwitch &s : audioSwitches) {
|
for (AudioSwitch &s : audioSwitches) {
|
||||||
|
if (!s.initialized())
|
||||||
|
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 = (s.peak + 60) * 1.7 >
|
bool volumeThresholdreached = ((double)s.peak + 60) * 1.7 >
|
||||||
s.volumeThreshold;
|
s.volumeThreshold;
|
||||||
|
|
||||||
if (volumeThresholdreached && audioActive) {
|
if (volumeThresholdreached && audioActive) {
|
||||||
@@ -222,7 +118,8 @@ void SwitcherData::saveAudioSwitches(obs_data_t *obj)
|
|||||||
obs_weak_source_get_source(s.transition);
|
obs_weak_source_get_source(s.transition);
|
||||||
obs_source_t *audioSrouce =
|
obs_source_t *audioSrouce =
|
||||||
obs_weak_source_get_source(s.audioSource);
|
obs_weak_source_get_source(s.audioSource);
|
||||||
if ((s.usePreviousScene || sceneSource) && transition) {
|
if ((s.usePreviousScene || sceneSource) && transition &&
|
||||||
|
audioSrouce) {
|
||||||
const char *sceneName =
|
const char *sceneName =
|
||||||
obs_source_get_name(sceneSource);
|
obs_source_get_name(sceneSource);
|
||||||
const char *transitionName =
|
const char *transitionName =
|
||||||
@@ -268,68 +165,278 @@ void SwitcherData::loadAudioSwitches(obs_data_t *obj)
|
|||||||
obs_data_get_string(array_obj, "audioSource");
|
obs_data_get_string(array_obj, "audioSource");
|
||||||
int vol = obs_data_get_int(array_obj, "volume");
|
int vol = obs_data_get_int(array_obj, "volume");
|
||||||
|
|
||||||
std::string audioSwitchStr =
|
|
||||||
MakeAudioSwitchName(scene, transition, audioSource, vol)
|
|
||||||
.toUtf8()
|
|
||||||
.constData();
|
|
||||||
|
|
||||||
switcher->audioSwitches.emplace_back(
|
switcher->audioSwitches.emplace_back(
|
||||||
GetWeakSourceByName(scene),
|
GetWeakSourceByName(scene),
|
||||||
GetWeakTransitionByName(transition),
|
GetWeakTransitionByName(transition),
|
||||||
GetWeakSourceByName(audioSource), vol,
|
GetWeakSourceByName(audioSource), vol,
|
||||||
(strcmp(scene, previous_scene_name) == 0),
|
(strcmp(scene, previous_scene_name) == 0));
|
||||||
audioSwitchStr);
|
|
||||||
|
|
||||||
obs_data_release(array_obj);
|
obs_data_release(array_obj);
|
||||||
}
|
}
|
||||||
obs_data_array_release(audioArray);
|
obs_data_array_release(audioArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::setupAudioTab()
|
void AdvSceneSwitcher::setupAudioTab()
|
||||||
{
|
{
|
||||||
populateSceneSelection(ui->audioScenes, true);
|
|
||||||
populateTransitionSelection(ui->audioTransitions);
|
|
||||||
|
|
||||||
auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */
|
|
||||||
{
|
|
||||||
QComboBox *combo = reinterpret_cast<QComboBox *>(data);
|
|
||||||
uint32_t flags = obs_source_get_output_flags(source);
|
|
||||||
|
|
||||||
if ((flags & OBS_SOURCE_AUDIO) != 0) {
|
|
||||||
const char *name = obs_source_get_name(source);
|
|
||||||
combo->addItem(name);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
obs_enum_sources(sourceEnum, ui->audioSources);
|
|
||||||
|
|
||||||
for (auto &s : switcher->audioSwitches) {
|
for (auto &s : switcher->audioSwitches) {
|
||||||
std::string sceneName = (s.usePreviousScene)
|
QListWidgetItem *item;
|
||||||
? previous_scene_name
|
item = new QListWidgetItem(ui->audioSwitches);
|
||||||
: GetWeakSourceName(s.scene);
|
ui->audioSwitches->addItem(item);
|
||||||
std::string transitionName = GetWeakSourceName(s.transition);
|
AudioSwitchWidget *sw = new AudioSwitchWidget(&s);
|
||||||
std::string audioSourceName = GetWeakSourceName(s.audioSource);
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
QString listText = MakeAudioSwitchName(sceneName.c_str(),
|
ui->audioSwitches->setItemWidget(item, sw);
|
||||||
transitionName.c_str(),
|
|
||||||
audioSourceName.c_str(),
|
|
||||||
s.volumeThreshold);
|
|
||||||
|
|
||||||
QListWidgetItem *item =
|
|
||||||
new QListWidgetItem(listText, ui->audioSwitches);
|
|
||||||
item->setData(Qt::UserRole, listText);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (switcher->audioSwitches.size() == 0)
|
||||||
|
addPulse = PulseWidget(ui->audioAdd, QColor(Qt::green));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline QString MakeAudioSwitchName(const QString &scene,
|
void AudioSwitch::setVolumeLevel(void *data,
|
||||||
const QString &transition,
|
const float magnitude[MAX_AUDIO_CHANNELS],
|
||||||
const QString &audioSrouce,
|
const float peak[MAX_AUDIO_CHANNELS],
|
||||||
const int &volume)
|
const float inputPeak[MAX_AUDIO_CHANNELS])
|
||||||
{
|
{
|
||||||
QString switchName = QStringLiteral("When volume of ") + audioSrouce +
|
UNUSED_PARAMETER(magnitude);
|
||||||
QStringLiteral(" is above ") +
|
UNUSED_PARAMETER(inputPeak);
|
||||||
QString::number(volume) +
|
AudioSwitch *s = static_cast<AudioSwitch *>(data);
|
||||||
QStringLiteral("% switch to ") + scene +
|
|
||||||
QStringLiteral(" using ") + transition;
|
s->peak = peak[0];
|
||||||
return switchName;
|
for (int i = 1; i < MAX_AUDIO_CHANNELS; i++)
|
||||||
|
if (peak[i] > s->peak)
|
||||||
|
s->peak = peak[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioSwitch::resetVolmeter()
|
||||||
|
{
|
||||||
|
obs_volmeter_remove_callback(volmeter, setVolumeLevel, this);
|
||||||
|
obs_volmeter_destroy(volmeter);
|
||||||
|
|
||||||
|
volmeter = obs_volmeter_create(OBS_FADER_LOG);
|
||||||
|
obs_volmeter_add_callback(volmeter, setVolumeLevel, this);
|
||||||
|
obs_source_t *as = obs_weak_source_get_source(audioSource);
|
||||||
|
if (!obs_volmeter_attach_source(volmeter, as)) {
|
||||||
|
const char *name = obs_source_get_name(as);
|
||||||
|
blog(LOG_WARNING, "failed to attach volmeter to source %s",
|
||||||
|
name);
|
||||||
|
}
|
||||||
|
obs_source_release(as);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AudioSwitch::initialized()
|
||||||
|
{
|
||||||
|
return SceneSwitcherEntry::initialized() && audioSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AudioSwitch::valid()
|
||||||
|
{
|
||||||
|
return !initialized() ||
|
||||||
|
(SceneSwitcherEntry::valid() && WeakSourceValid(audioSource));
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioSwitch::AudioSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
||||||
|
OBSWeakSource audioSource_, int volumeThreshold_,
|
||||||
|
bool usePreviousScene_)
|
||||||
|
: SceneSwitcherEntry(scene_, transition_, usePreviousScene_),
|
||||||
|
audioSource(audioSource_),
|
||||||
|
volumeThreshold(volumeThreshold_)
|
||||||
|
{
|
||||||
|
volmeter = obs_volmeter_create(OBS_FADER_LOG);
|
||||||
|
obs_volmeter_add_callback(volmeter, setVolumeLevel, this);
|
||||||
|
obs_source_t *as = obs_weak_source_get_source(audioSource);
|
||||||
|
if (!obs_volmeter_attach_source(volmeter, as)) {
|
||||||
|
const char *name = obs_source_get_name(as);
|
||||||
|
blog(LOG_WARNING, "failed to attach volmeter to source %s",
|
||||||
|
name);
|
||||||
|
}
|
||||||
|
obs_source_release(as);
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioSwitch::AudioSwitch(const AudioSwitch &other)
|
||||||
|
: SceneSwitcherEntry(other.scene, other.transition,
|
||||||
|
other.usePreviousScene),
|
||||||
|
audioSource(other.audioSource),
|
||||||
|
volumeThreshold(other.volumeThreshold)
|
||||||
|
{
|
||||||
|
volmeter = obs_volmeter_create(OBS_FADER_LOG);
|
||||||
|
obs_volmeter_add_callback(volmeter, setVolumeLevel, this);
|
||||||
|
obs_source_t *as = obs_weak_source_get_source(other.audioSource);
|
||||||
|
if (!obs_volmeter_attach_source(volmeter, as)) {
|
||||||
|
const char *name = obs_source_get_name(as);
|
||||||
|
blog(LOG_WARNING, "failed to attach volmeter to source %s",
|
||||||
|
name);
|
||||||
|
}
|
||||||
|
obs_source_release(as);
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioSwitch::AudioSwitch(AudioSwitch &&other)
|
||||||
|
: SceneSwitcherEntry(other.scene, other.transition,
|
||||||
|
other.usePreviousScene),
|
||||||
|
audioSource(other.audioSource),
|
||||||
|
volumeThreshold(other.volumeThreshold),
|
||||||
|
volmeter(other.volmeter)
|
||||||
|
{
|
||||||
|
other.volmeter = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioSwitch::~AudioSwitch()
|
||||||
|
{
|
||||||
|
obs_volmeter_remove_callback(volmeter, setVolumeLevel, this);
|
||||||
|
obs_volmeter_destroy(volmeter);
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioSwitch &AudioSwitch::operator=(const AudioSwitch &other)
|
||||||
|
{
|
||||||
|
AudioSwitch t(other);
|
||||||
|
swap(*this, t);
|
||||||
|
return *this = AudioSwitch(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioSwitch &AudioSwitch::operator=(AudioSwitch &&other) noexcept
|
||||||
|
{
|
||||||
|
if (this == &other) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
swap(*this, other);
|
||||||
|
|
||||||
|
obs_volmeter_remove_callback(other.volmeter, setVolumeLevel, this);
|
||||||
|
obs_volmeter_destroy(other.volmeter);
|
||||||
|
other.volmeter = nullptr;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(AudioSwitch &first, AudioSwitch &second)
|
||||||
|
{
|
||||||
|
std::swap(first.scene, second.scene);
|
||||||
|
std::swap(first.transition, second.transition);
|
||||||
|
std::swap(first.usePreviousScene, second.usePreviousScene);
|
||||||
|
std::swap(first.audioSource, second.audioSource);
|
||||||
|
std::swap(first.volumeThreshold, second.volumeThreshold);
|
||||||
|
std::swap(first.peak, second.peak);
|
||||||
|
std::swap(first.volmeter, second.volmeter);
|
||||||
|
first.resetVolmeter();
|
||||||
|
second.resetVolmeter();
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioSwitchWidget::AudioSwitchWidget(AudioSwitch *s) : SwitchWidget(s)
|
||||||
|
{
|
||||||
|
audioSources = new QComboBox();
|
||||||
|
audioVolumeThreshold = new QSpinBox();
|
||||||
|
|
||||||
|
obs_source_t *soruce = nullptr;
|
||||||
|
if (s)
|
||||||
|
soruce = obs_weak_source_get_source(s->audioSource);
|
||||||
|
volMeter = new VolControl(soruce);
|
||||||
|
obs_source_release(soruce);
|
||||||
|
|
||||||
|
whenLabel = new QLabel("When the volume of");
|
||||||
|
aboveLabel = new QLabel("is above");
|
||||||
|
switchLabel = new QLabel("switch to");
|
||||||
|
usingLabel = new QLabel("using");
|
||||||
|
|
||||||
|
audioVolumeThreshold->setSuffix("%");
|
||||||
|
audioVolumeThreshold->setMaximum(100);
|
||||||
|
audioVolumeThreshold->setMinimum(0);
|
||||||
|
|
||||||
|
QWidget::connect(volMeter->GetSlider(), SIGNAL(valueChanged(int)),
|
||||||
|
audioVolumeThreshold, SLOT(setValue(int)));
|
||||||
|
QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)),
|
||||||
|
volMeter->GetSlider(), SLOT(setValue(int)));
|
||||||
|
QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)), this,
|
||||||
|
SLOT(VolumeThresholdChanged(int)));
|
||||||
|
QWidget::connect(audioSources,
|
||||||
|
SIGNAL(currentTextChanged(const QString &)), this,
|
||||||
|
SLOT(SourceChanged(const QString &)));
|
||||||
|
|
||||||
|
AdvSceneSwitcher::populateAudioSelection(audioSources);
|
||||||
|
|
||||||
|
if (s) {
|
||||||
|
audioSources->setCurrentText(
|
||||||
|
GetWeakSourceName(s->audioSource).c_str());
|
||||||
|
audioVolumeThreshold->setValue(s->volumeThreshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
setStyleSheet("* { background-color: transparent; }");
|
||||||
|
|
||||||
|
QHBoxLayout *switchLayout = new QHBoxLayout;
|
||||||
|
|
||||||
|
switchLayout->addWidget(whenLabel);
|
||||||
|
switchLayout->addWidget(audioSources);
|
||||||
|
switchLayout->addWidget(aboveLabel);
|
||||||
|
switchLayout->addWidget(audioVolumeThreshold);
|
||||||
|
switchLayout->addWidget(switchLabel);
|
||||||
|
switchLayout->addWidget(scenes);
|
||||||
|
switchLayout->addWidget(usingLabel);
|
||||||
|
switchLayout->addWidget(transitions);
|
||||||
|
switchLayout->addStretch();
|
||||||
|
|
||||||
|
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||||
|
|
||||||
|
mainLayout->addLayout(switchLayout);
|
||||||
|
mainLayout->addWidget(volMeter);
|
||||||
|
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
switchData = s;
|
||||||
|
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioSwitch *AudioSwitchWidget::getSwitchData()
|
||||||
|
{
|
||||||
|
return switchData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioSwitchWidget::setSwitchData(AudioSwitch *s)
|
||||||
|
{
|
||||||
|
switchData = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioSwitchWidget::swapSwitchData(AudioSwitchWidget *s1,
|
||||||
|
AudioSwitchWidget *s2)
|
||||||
|
{
|
||||||
|
SwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
AudioSwitch *t = s1->getSwitchData();
|
||||||
|
s1->setSwitchData(s2->getSwitchData());
|
||||||
|
s2->setSwitchData(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioSwitchWidget::UpdateVolmeterSource()
|
||||||
|
{
|
||||||
|
delete volMeter;
|
||||||
|
obs_source_t *soruce =
|
||||||
|
obs_weak_source_get_source(switchData->audioSource);
|
||||||
|
volMeter = new VolControl(soruce);
|
||||||
|
obs_source_release(soruce);
|
||||||
|
|
||||||
|
QLayout *layout = this->layout();
|
||||||
|
layout->addWidget(volMeter);
|
||||||
|
|
||||||
|
QWidget::connect(volMeter->GetSlider(), SIGNAL(valueChanged(int)),
|
||||||
|
audioVolumeThreshold, SLOT(setValue(int)));
|
||||||
|
QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)),
|
||||||
|
volMeter->GetSlider(), SLOT(setValue(int)));
|
||||||
|
|
||||||
|
// Slider will default to 0 so set it manually once
|
||||||
|
volMeter->GetSlider()->setValue(switchData->volumeThreshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioSwitchWidget::SourceChanged(const QString &text)
|
||||||
|
{
|
||||||
|
if (loading || !switchData)
|
||||||
|
return;
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->audioSource = GetWeakSourceByQString(text);
|
||||||
|
switchData->resetVolmeter();
|
||||||
|
UpdateVolmeterSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioSwitchWidget::VolumeThresholdChanged(int vol)
|
||||||
|
{
|
||||||
|
if (loading || !switchData)
|
||||||
|
return;
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->volumeThreshold = vol;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,148 +1,81 @@
|
|||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
int SceneSwitcher::executableFindByData(const QString &exe)
|
static QMetaObject::Connection addPulse;
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_executableAdd_clicked()
|
||||||
{
|
{
|
||||||
int count = ui->executables->count();
|
ui->executableAdd->disconnect(addPulse);
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
QListWidgetItem *item = ui->executables->item(i);
|
|
||||||
QString itemExe = item->data(Qt::UserRole).toString();
|
|
||||||
|
|
||||||
if (itemExe == exe)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_executables_currentRowChanged(int idx)
|
|
||||||
{
|
|
||||||
if (loading)
|
|
||||||
return;
|
|
||||||
if (idx == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QListWidgetItem *item = ui->executables->item(idx);
|
|
||||||
|
|
||||||
QString exec = item->data(Qt::UserRole).toString();
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
for (auto &s : switcher->executableSwitches) {
|
switcher->executableSwitches.emplace_back();
|
||||||
if (exec.compare(s.exe) == 0) {
|
|
||||||
QString sceneName = GetWeakSourceName(s.scene).c_str();
|
QListWidgetItem *item;
|
||||||
QString transitionName =
|
item = new QListWidgetItem(ui->executables);
|
||||||
GetWeakSourceName(s.transition).c_str();
|
ui->executables->addItem(item);
|
||||||
ui->executableScenes->setCurrentText(sceneName);
|
ExecutableSwitchWidget *sw = new ExecutableSwitchWidget(
|
||||||
ui->executable->setCurrentText(exec);
|
&switcher->executableSwitches.back());
|
||||||
ui->executableTransitions->setCurrentText(
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
transitionName);
|
ui->executables->setItemWidget(item, sw);
|
||||||
ui->requiresFocusCheckBox->setChecked(s.inFocus);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_executableUp_clicked()
|
void AdvSceneSwitcher::on_executableRemove_clicked()
|
||||||
{
|
|
||||||
int index = ui->executables->currentRow();
|
|
||||||
if (index != -1 && index != 0) {
|
|
||||||
ui->executables->insertItem(index - 1,
|
|
||||||
ui->executables->takeItem(index));
|
|
||||||
ui->executables->setCurrentRow(index - 1);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
|
|
||||||
iter_swap(switcher->executableSwitches.begin() + index,
|
|
||||||
switcher->executableSwitches.begin() + index - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_executableDown_clicked()
|
|
||||||
{
|
|
||||||
int index = ui->executables->currentRow();
|
|
||||||
if (index != -1 && index != ui->executables->count() - 1) {
|
|
||||||
ui->executables->insertItem(index + 1,
|
|
||||||
ui->executables->takeItem(index));
|
|
||||||
ui->executables->setCurrentRow(index + 1);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
|
|
||||||
iter_swap(switcher->executableSwitches.begin() + index,
|
|
||||||
switcher->executableSwitches.begin() + index + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_executableAdd_clicked()
|
|
||||||
{
|
|
||||||
QString sceneName = ui->executableScenes->currentText();
|
|
||||||
QString exeName = ui->executable->currentText();
|
|
||||||
QString transitionName = ui->executableTransitions->currentText();
|
|
||||||
bool inFocus = ui->requiresFocusCheckBox->isChecked();
|
|
||||||
|
|
||||||
if (exeName.isEmpty() || sceneName.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
OBSWeakSource source = GetWeakSourceByQString(sceneName);
|
|
||||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
|
||||||
QVariant v = QVariant::fromValue(exeName);
|
|
||||||
|
|
||||||
QString text = MakeSwitchNameExecutable(sceneName, exeName,
|
|
||||||
transitionName, inFocus);
|
|
||||||
|
|
||||||
int idx = executableFindByData(exeName);
|
|
||||||
|
|
||||||
if (idx == -1) {
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
switcher->executableSwitches.emplace_back(
|
|
||||||
source, transition, exeName.toUtf8().constData(),
|
|
||||||
inFocus);
|
|
||||||
|
|
||||||
QListWidgetItem *item =
|
|
||||||
new QListWidgetItem(text, ui->executables);
|
|
||||||
item->setData(Qt::UserRole, v);
|
|
||||||
} else {
|
|
||||||
QListWidgetItem *item = ui->executables->item(idx);
|
|
||||||
item->setText(text);
|
|
||||||
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
for (auto &s : switcher->executableSwitches) {
|
|
||||||
if (s.exe == exeName) {
|
|
||||||
s.scene = source;
|
|
||||||
s.transition = transition;
|
|
||||||
s.inFocus = inFocus;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_executableRemove_clicked()
|
|
||||||
{
|
{
|
||||||
QListWidgetItem *item = ui->executables->currentItem();
|
QListWidgetItem *item = ui->executables->currentItem();
|
||||||
if (!item)
|
if (!item)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QString exe = item->data(Qt::UserRole).toString();
|
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
int idx = ui->executables->currentRow();
|
||||||
auto &switches = switcher->executableSwitches;
|
auto &switches = switcher->executableSwitches;
|
||||||
|
switches.erase(switches.begin() + idx);
|
||||||
for (auto it = switches.begin(); it != switches.end(); ++it) {
|
|
||||||
auto &s = *it;
|
|
||||||
|
|
||||||
if (s.exe == exe) {
|
|
||||||
switches.erase(it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete item;
|
delete item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_executableUp_clicked()
|
||||||
|
{
|
||||||
|
int index = ui->executables->currentRow();
|
||||||
|
if (!listMoveUp(ui->executables))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ExecutableSwitchWidget *s1 =
|
||||||
|
(ExecutableSwitchWidget *)ui->executables->itemWidget(
|
||||||
|
ui->executables->item(index));
|
||||||
|
ExecutableSwitchWidget *s2 =
|
||||||
|
(ExecutableSwitchWidget *)ui->executables->itemWidget(
|
||||||
|
ui->executables->item(index - 1));
|
||||||
|
ExecutableSwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
|
||||||
|
std::swap(switcher->executableSwitches[index],
|
||||||
|
switcher->executableSwitches[index - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_executableDown_clicked()
|
||||||
|
{
|
||||||
|
int index = ui->executables->currentRow();
|
||||||
|
|
||||||
|
if (!listMoveDown(ui->executables))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ExecutableSwitchWidget *s1 =
|
||||||
|
(ExecutableSwitchWidget *)ui->executables->itemWidget(
|
||||||
|
ui->executables->item(index));
|
||||||
|
ExecutableSwitchWidget *s2 =
|
||||||
|
(ExecutableSwitchWidget *)ui->executables->itemWidget(
|
||||||
|
ui->executables->item(index + 1));
|
||||||
|
ExecutableSwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
|
||||||
|
std::swap(switcher->executableSwitches[index],
|
||||||
|
switcher->executableSwitches[index + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
void SwitcherData::checkExeSwitch(bool &match, OBSWeakSource &scene,
|
void SwitcherData::checkExeSwitch(bool &match, OBSWeakSource &scene,
|
||||||
OBSWeakSource &transition)
|
OBSWeakSource &transition)
|
||||||
{
|
{
|
||||||
@@ -170,7 +103,9 @@ void SwitcherData::checkExeSwitch(bool &match, OBSWeakSource &scene,
|
|||||||
|
|
||||||
// Check for match
|
// Check for match
|
||||||
GetProcessList(runningProcesses);
|
GetProcessList(runningProcesses);
|
||||||
for (ExecutableSceneSwitch &s : executableSwitches) {
|
for (ExecutableSwitch &s : executableSwitches) {
|
||||||
|
if (!s.initialized())
|
||||||
|
continue;
|
||||||
// True if executable switch is running (direct)
|
// 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)
|
// True if executable switch is running (regex)
|
||||||
@@ -199,7 +134,7 @@ void SwitcherData::checkExeSwitch(bool &match, OBSWeakSource &scene,
|
|||||||
void SwitcherData::saveExecutableSwitches(obs_data_t *obj)
|
void SwitcherData::saveExecutableSwitches(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
obs_data_array_t *executableArray = obs_data_array_create();
|
obs_data_array_t *executableArray = obs_data_array_create();
|
||||||
for (ExecutableSceneSwitch &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);
|
obs_source_t *source = obs_weak_source_get_source(s.scene);
|
||||||
@@ -217,10 +152,9 @@ void SwitcherData::saveExecutableSwitches(obs_data_t *obj)
|
|||||||
s.exe.toUtf8());
|
s.exe.toUtf8());
|
||||||
obs_data_set_bool(array_obj, "infocus", s.inFocus);
|
obs_data_set_bool(array_obj, "infocus", s.inFocus);
|
||||||
obs_data_array_push_back(executableArray, array_obj);
|
obs_data_array_push_back(executableArray, array_obj);
|
||||||
obs_source_release(source);
|
|
||||||
obs_source_release(transition);
|
|
||||||
}
|
}
|
||||||
|
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);
|
||||||
@@ -253,39 +187,98 @@ void SwitcherData::loadExecutableSwitches(obs_data_t *obj)
|
|||||||
obs_data_array_release(executableArray);
|
obs_data_array_release(executableArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::setupExecutableTab()
|
void AdvSceneSwitcher::setupExecutableTab()
|
||||||
{
|
{
|
||||||
populateSceneSelection(ui->executableScenes, false);
|
|
||||||
populateTransitionSelection(ui->executableTransitions);
|
|
||||||
|
|
||||||
QStringList processes;
|
|
||||||
GetProcessList(processes);
|
|
||||||
for (QString &process : processes)
|
|
||||||
ui->executable->addItem(process);
|
|
||||||
|
|
||||||
for (auto &s : switcher->executableSwitches) {
|
for (auto &s : switcher->executableSwitches) {
|
||||||
std::string sceneName = GetWeakSourceName(s.scene);
|
QListWidgetItem *item;
|
||||||
std::string transitionName = GetWeakSourceName(s.transition);
|
item = new QListWidgetItem(ui->executables);
|
||||||
QString text = MakeSwitchNameExecutable(sceneName.c_str(),
|
ui->executables->addItem(item);
|
||||||
s.exe,
|
ExecutableSwitchWidget *sw = new ExecutableSwitchWidget(&s);
|
||||||
transitionName.c_str(),
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
s.inFocus);
|
ui->executables->setItemWidget(item, sw);
|
||||||
|
|
||||||
QListWidgetItem *item =
|
|
||||||
new QListWidgetItem(text, ui->executables);
|
|
||||||
item->setData(Qt::UserRole, s.exe);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (switcher->executableSwitches.size() == 0)
|
||||||
|
addPulse = PulseWidget(ui->executableAdd, QColor(Qt::green));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline QString MakeSwitchNameExecutable(const QString &scene,
|
ExecutableSwitchWidget::ExecutableSwitchWidget(ExecutableSwitch *s)
|
||||||
const QString &value,
|
: SwitchWidget(s, false)
|
||||||
const QString &transition,
|
|
||||||
bool inFocus)
|
|
||||||
{
|
{
|
||||||
if (!inFocus)
|
processes = new QComboBox();
|
||||||
return QStringLiteral("[") + scene + QStringLiteral(", ") +
|
requiresFocus = new QCheckBox("only if focused");
|
||||||
transition + QStringLiteral("]: ") + value;
|
|
||||||
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition +
|
whenLabel = new QLabel("When");
|
||||||
QStringLiteral("]: ") + value +
|
switchLabel = new QLabel("is running switch to");
|
||||||
QStringLiteral(" (only if focused)");
|
usingLabel = new QLabel("using");
|
||||||
|
|
||||||
|
QWidget::connect(processes, SIGNAL(currentTextChanged(const QString &)),
|
||||||
|
this, SLOT(ProcessChanged(const QString &)));
|
||||||
|
QWidget::connect(requiresFocus, SIGNAL(stateChanged(int)), this,
|
||||||
|
SLOT(FocusChanged(int)));
|
||||||
|
|
||||||
|
AdvSceneSwitcher::populateProcessSelection(processes);
|
||||||
|
|
||||||
|
processes->setEditable(true);
|
||||||
|
processes->setMaxVisibleItems(20);
|
||||||
|
|
||||||
|
if (s) {
|
||||||
|
processes->setCurrentText(s->exe);
|
||||||
|
requiresFocus->setChecked(s->inFocus);
|
||||||
|
}
|
||||||
|
|
||||||
|
setStyleSheet("* { background-color: transparent; }");
|
||||||
|
|
||||||
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
|
||||||
|
mainLayout->addWidget(whenLabel);
|
||||||
|
mainLayout->addWidget(processes);
|
||||||
|
mainLayout->addWidget(switchLabel);
|
||||||
|
mainLayout->addWidget(scenes);
|
||||||
|
mainLayout->addWidget(usingLabel);
|
||||||
|
mainLayout->addWidget(transitions);
|
||||||
|
mainLayout->addWidget(requiresFocus);
|
||||||
|
mainLayout->addStretch();
|
||||||
|
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
switchData = s;
|
||||||
|
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExecutableSwitch *ExecutableSwitchWidget::getSwitchData()
|
||||||
|
{
|
||||||
|
return switchData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExecutableSwitchWidget::setSwitchData(ExecutableSwitch *s)
|
||||||
|
{
|
||||||
|
switchData = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExecutableSwitchWidget::swapSwitchData(ExecutableSwitchWidget *s1,
|
||||||
|
ExecutableSwitchWidget *s2)
|
||||||
|
{
|
||||||
|
SwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
ExecutableSwitch *t = s1->getSwitchData();
|
||||||
|
s1->setSwitchData(s2->getSwitchData());
|
||||||
|
s2->setSwitchData(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExecutableSwitchWidget::ProcessChanged(const QString &text)
|
||||||
|
{
|
||||||
|
if (loading || !switchData)
|
||||||
|
return;
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->exe = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExecutableSwitchWidget::FocusChanged(int state)
|
||||||
|
{
|
||||||
|
if (loading || !switchData)
|
||||||
|
return;
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->inFocus = state;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,12 @@
|
|||||||
|
|
||||||
#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"
|
||||||
|
|
||||||
#define LOCAL_FILE_IDX 0
|
#define LOCAL_FILE_IDX 0
|
||||||
#define REMOTE_FILE_IDX 1
|
#define REMOTE_FILE_IDX 1
|
||||||
|
|
||||||
void SceneSwitcher::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("Select a file to write to ..."), QDir::currentPath(),
|
||||||
@@ -18,7 +19,7 @@ void SceneSwitcher::on_browseButton_clicked()
|
|||||||
ui->writePathLineEdit->setText(path);
|
ui->writePathLineEdit->setText(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_readFileCheckBox_stateChanged(int state)
|
void AdvSceneSwitcher::on_readFileCheckBox_stateChanged(int state)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading)
|
||||||
return;
|
return;
|
||||||
@@ -35,7 +36,7 @@ void SceneSwitcher::on_readFileCheckBox_stateChanged(int state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_readPathLineEdit_textChanged(const QString &text)
|
void AdvSceneSwitcher::on_readPathLineEdit_textChanged(const QString &text)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading)
|
||||||
return;
|
return;
|
||||||
@@ -49,7 +50,7 @@ void SceneSwitcher::on_readPathLineEdit_textChanged(const QString &text)
|
|||||||
switcher->fileIO.readPath = text.toUtf8().constData();
|
switcher->fileIO.readPath = text.toUtf8().constData();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_writePathLineEdit_textChanged(const QString &text)
|
void AdvSceneSwitcher::on_writePathLineEdit_textChanged(const QString &text)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading)
|
||||||
return;
|
return;
|
||||||
@@ -63,7 +64,7 @@ void SceneSwitcher::on_writePathLineEdit_textChanged(const QString &text)
|
|||||||
switcher->fileIO.writePath = text.toUtf8().constData();
|
switcher->fileIO.writePath = text.toUtf8().constData();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::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("Select a file to read from ..."), QDir::currentPath(),
|
||||||
@@ -223,7 +224,7 @@ void SwitcherData::checkFileContent(bool &match, OBSWeakSource &scene,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_browseButton_3_clicked()
|
void AdvSceneSwitcher::on_browseButton_3_clicked()
|
||||||
{
|
{
|
||||||
QString path = QFileDialog::getOpenFileName(
|
QString path = QFileDialog::getOpenFileName(
|
||||||
this, tr("Select a file to read from ..."), QDir::currentPath(),
|
this, tr("Select a file to read from ..."), QDir::currentPath(),
|
||||||
@@ -232,7 +233,7 @@ void SceneSwitcher::on_browseButton_3_clicked()
|
|||||||
ui->filePathLineEdit->setText(path);
|
ui->filePathLineEdit->setText(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_fileType_currentIndexChanged(int idx)
|
void AdvSceneSwitcher::on_fileType_currentIndexChanged(int idx)
|
||||||
{
|
{
|
||||||
if (idx == -1)
|
if (idx == -1)
|
||||||
return;
|
return;
|
||||||
@@ -248,7 +249,7 @@ void SceneSwitcher::on_fileType_currentIndexChanged(int idx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_fileAdd_clicked()
|
void AdvSceneSwitcher::on_fileAdd_clicked()
|
||||||
{
|
{
|
||||||
QString sceneName = ui->fileScenes->currentText();
|
QString sceneName = ui->fileScenes->currentText();
|
||||||
QString transitionName = ui->fileTransitions->currentText();
|
QString transitionName = ui->fileTransitions->currentText();
|
||||||
@@ -280,7 +281,7 @@ void SceneSwitcher::on_fileAdd_clicked()
|
|||||||
useRegex, useTime);
|
useRegex, useTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_fileRemove_clicked()
|
void AdvSceneSwitcher::on_fileRemove_clicked()
|
||||||
{
|
{
|
||||||
QListWidgetItem *item = ui->fileScenesList->currentItem();
|
QListWidgetItem *item = ui->fileScenesList->currentItem();
|
||||||
if (!item)
|
if (!item)
|
||||||
@@ -299,7 +300,7 @@ void SceneSwitcher::on_fileRemove_clicked()
|
|||||||
qDeleteAll(ui->fileScenesList->selectedItems());
|
qDeleteAll(ui->fileScenesList->selectedItems());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_fileScenesList_currentRowChanged(int idx)
|
void AdvSceneSwitcher::on_fileScenesList_currentRowChanged(int idx)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading)
|
||||||
return;
|
return;
|
||||||
@@ -327,7 +328,7 @@ void SceneSwitcher::on_fileScenesList_currentRowChanged(int idx)
|
|||||||
ui->fileContentTimeCheckBox->setChecked(s.useTime);
|
ui->fileContentTimeCheckBox->setChecked(s.useTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_fileUp_clicked()
|
void AdvSceneSwitcher::on_fileUp_clicked()
|
||||||
{
|
{
|
||||||
int index = ui->fileScenesList->currentRow();
|
int index = ui->fileScenesList->currentRow();
|
||||||
if (index != -1 && index != 0) {
|
if (index != -1 && index != 0) {
|
||||||
@@ -342,7 +343,7 @@ void SceneSwitcher::on_fileUp_clicked()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_fileDown_clicked()
|
void AdvSceneSwitcher::on_fileDown_clicked()
|
||||||
{
|
{
|
||||||
int index = ui->fileScenesList->currentRow();
|
int index = ui->fileScenesList->currentRow();
|
||||||
if (index != -1 && index != ui->fileScenesList->count() - 1) {
|
if (index != -1 && index != ui->fileScenesList->count() - 1) {
|
||||||
@@ -380,10 +381,9 @@ void SwitcherData::saveFileSwitches(obs_data_t *obj)
|
|||||||
obs_data_set_bool(array_obj, "useRegex", s.useRegex);
|
obs_data_set_bool(array_obj, "useRegex", s.useRegex);
|
||||||
obs_data_set_bool(array_obj, "useTime", s.useTime);
|
obs_data_set_bool(array_obj, "useTime", s.useTime);
|
||||||
obs_data_array_push_back(fileArray, array_obj);
|
obs_data_array_push_back(fileArray, array_obj);
|
||||||
obs_source_release(source);
|
|
||||||
obs_source_release(transition);
|
|
||||||
}
|
}
|
||||||
|
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);
|
||||||
@@ -431,7 +431,7 @@ void SwitcherData::loadFileSwitches(obs_data_t *obj)
|
|||||||
switcher->fileIO.writePath = obs_data_get_string(obj, "writePath");
|
switcher->fileIO.writePath = obs_data_get_string(obj, "writePath");
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::setupFileTab()
|
void AdvSceneSwitcher::setupFileTab()
|
||||||
{
|
{
|
||||||
populateSceneSelection(ui->fileScenes, false);
|
populateSceneSelection(ui->fileScenes, false);
|
||||||
populateTransitionSelection(ui->fileTransitions);
|
populateTransitionSelection(ui->fileTransitions);
|
||||||
|
|||||||
89
src/switch-generic.cpp
Normal file
89
src/switch-generic.cpp
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
|
bool SceneSwitcherEntry::initialized()
|
||||||
|
{
|
||||||
|
return (usePreviousScene || WeakSourceValid(scene)) && transition;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SceneSwitcherEntry::valid()
|
||||||
|
{
|
||||||
|
return !initialized() ||
|
||||||
|
((usePreviousScene || WeakSourceValid(scene)) &&
|
||||||
|
WeakSourceValid(transition));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneSwitcherEntry::logMatch()
|
||||||
|
{
|
||||||
|
const char *sceneName = previous_scene_name;
|
||||||
|
if (!usePreviousScene) {
|
||||||
|
obs_source_t *s = obs_weak_source_get_source(scene);
|
||||||
|
sceneName = obs_source_get_name(s);
|
||||||
|
obs_source_release(s);
|
||||||
|
}
|
||||||
|
blog(LOG_INFO, "match for '%s' - switch to scene '%s'", getType(),
|
||||||
|
sceneName);
|
||||||
|
}
|
||||||
|
|
||||||
|
SwitchWidget::SwitchWidget(SceneSwitcherEntry *s, bool usePreviousScene)
|
||||||
|
{
|
||||||
|
scenes = new QComboBox();
|
||||||
|
transitions = new QComboBox();
|
||||||
|
|
||||||
|
QWidget::connect(scenes, SIGNAL(currentTextChanged(const QString &)),
|
||||||
|
this, SLOT(SceneChanged(const QString &)));
|
||||||
|
QWidget::connect(transitions,
|
||||||
|
SIGNAL(currentTextChanged(const QString &)), this,
|
||||||
|
SLOT(TransitionChanged(const QString &)));
|
||||||
|
|
||||||
|
AdvSceneSwitcher::populateSceneSelection(scenes, usePreviousScene);
|
||||||
|
AdvSceneSwitcher::populateTransitionSelection(transitions);
|
||||||
|
|
||||||
|
if (s) {
|
||||||
|
if (s->usePreviousScene)
|
||||||
|
scenes->setCurrentText(previous_scene_name);
|
||||||
|
else
|
||||||
|
scenes->setCurrentText(
|
||||||
|
GetWeakSourceName(s->scene).c_str());
|
||||||
|
transitions->setCurrentText(
|
||||||
|
GetWeakSourceName(s->transition).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
switchData = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneSwitcherEntry *SwitchWidget::getSwitchData()
|
||||||
|
{
|
||||||
|
return switchData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitchWidget::setSwitchData(SceneSwitcherEntry *s)
|
||||||
|
{
|
||||||
|
switchData = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitchWidget::swapSwitchData(SwitchWidget *s1, SwitchWidget *s2)
|
||||||
|
{
|
||||||
|
SceneSwitcherEntry *t = s1->getSwitchData();
|
||||||
|
s1->setSwitchData(s2->getSwitchData());
|
||||||
|
s2->setSwitchData(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitchWidget::SceneChanged(const QString &text)
|
||||||
|
{
|
||||||
|
if (loading || !switchData)
|
||||||
|
return;
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->usePreviousScene = text.compare(previous_scene_name) == 0;
|
||||||
|
if (switchData->usePreviousScene)
|
||||||
|
return;
|
||||||
|
switchData->scene = GetWeakSourceByQString(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitchWidget::TransitionChanged(const QString &text)
|
||||||
|
{
|
||||||
|
if (loading || !switchData)
|
||||||
|
return;
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->transition = GetWeakTransitionByQString(text);
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <regex>
|
#include <regex>
|
||||||
|
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
void SwitcherData::checkIdleSwitch(bool &match, OBSWeakSource &scene,
|
void SwitcherData::checkIdleSwitch(bool &match, OBSWeakSource &scene,
|
||||||
OBSWeakSource &transition)
|
OBSWeakSource &transition)
|
||||||
@@ -50,7 +51,7 @@ void SwitcherData::checkIdleSwitch(bool &match, OBSWeakSource &scene,
|
|||||||
idleData.alreadySwitched = false;
|
idleData.alreadySwitched = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_idleCheckBox_stateChanged(int state)
|
void AdvSceneSwitcher::on_idleCheckBox_stateChanged(int state)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading)
|
||||||
return;
|
return;
|
||||||
@@ -74,13 +75,13 @@ void SceneSwitcher::on_idleCheckBox_stateChanged(int state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::UpdateIdleDataTransition(const QString &name)
|
void AdvSceneSwitcher::UpdateIdleDataTransition(const QString &name)
|
||||||
{
|
{
|
||||||
obs_weak_source_t *transition = GetWeakTransitionByQString(name);
|
obs_weak_source_t *transition = GetWeakTransitionByQString(name);
|
||||||
switcher->idleData.transition = transition;
|
switcher->idleData.transition = transition;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::UpdateIdleDataScene(const QString &name)
|
void AdvSceneSwitcher::UpdateIdleDataScene(const QString &name)
|
||||||
{
|
{
|
||||||
switcher->idleData.usePreviousScene = (name == previous_scene_name);
|
switcher->idleData.usePreviousScene = (name == previous_scene_name);
|
||||||
obs_source_t *scene = obs_get_source_by_name(name.toUtf8().constData());
|
obs_source_t *scene = obs_get_source_by_name(name.toUtf8().constData());
|
||||||
@@ -92,7 +93,7 @@ void SceneSwitcher::UpdateIdleDataScene(const QString &name)
|
|||||||
obs_source_release(scene);
|
obs_source_release(scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_idleTransitions_currentTextChanged(const QString &text)
|
void AdvSceneSwitcher::on_idleTransitions_currentTextChanged(const QString &text)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading)
|
||||||
return;
|
return;
|
||||||
@@ -101,7 +102,7 @@ void SceneSwitcher::on_idleTransitions_currentTextChanged(const QString &text)
|
|||||||
UpdateIdleDataTransition(text);
|
UpdateIdleDataTransition(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_idleScenes_currentTextChanged(const QString &text)
|
void AdvSceneSwitcher::on_idleScenes_currentTextChanged(const QString &text)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading)
|
||||||
return;
|
return;
|
||||||
@@ -110,7 +111,7 @@ void SceneSwitcher::on_idleScenes_currentTextChanged(const QString &text)
|
|||||||
UpdateIdleDataScene(text);
|
UpdateIdleDataScene(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_idleSpinBox_valueChanged(int i)
|
void AdvSceneSwitcher::on_idleSpinBox_valueChanged(int i)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading)
|
||||||
return;
|
return;
|
||||||
@@ -118,7 +119,7 @@ void SceneSwitcher::on_idleSpinBox_valueChanged(int i)
|
|||||||
switcher->idleData.time = i;
|
switcher->idleData.time = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_ignoreIdleWindows_currentRowChanged(int idx)
|
void AdvSceneSwitcher::on_ignoreIdleWindows_currentRowChanged(int idx)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading)
|
||||||
return;
|
return;
|
||||||
@@ -138,7 +139,7 @@ void SceneSwitcher::on_ignoreIdleWindows_currentRowChanged(int idx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_ignoreIdleAdd_clicked()
|
void AdvSceneSwitcher::on_ignoreIdleAdd_clicked()
|
||||||
{
|
{
|
||||||
QString windowName = ui->ignoreIdleWindowsWindows->currentText();
|
QString windowName = ui->ignoreIdleWindowsWindows->currentText();
|
||||||
|
|
||||||
@@ -162,7 +163,7 @@ void SceneSwitcher::on_ignoreIdleAdd_clicked()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_ignoreIdleRemove_clicked()
|
void AdvSceneSwitcher::on_ignoreIdleRemove_clicked()
|
||||||
{
|
{
|
||||||
QListWidgetItem *item = ui->ignoreIdleWindows->currentItem();
|
QListWidgetItem *item = ui->ignoreIdleWindows->currentItem();
|
||||||
if (!item)
|
if (!item)
|
||||||
@@ -187,7 +188,7 @@ void SceneSwitcher::on_ignoreIdleRemove_clicked()
|
|||||||
delete item;
|
delete item;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SceneSwitcher::IgnoreIdleWindowsFindByData(const QString &window)
|
int AdvSceneSwitcher::IgnoreIdleWindowsFindByData(const QString &window)
|
||||||
{
|
{
|
||||||
int count = ui->ignoreIdleWindows->count();
|
int count = ui->ignoreIdleWindows->count();
|
||||||
int idx = -1;
|
int idx = -1;
|
||||||
@@ -264,7 +265,7 @@ void SwitcherData::loadIdleSwitches(obs_data_t *obj)
|
|||||||
(idleSceneName == previous_scene_name);
|
(idleSceneName == previous_scene_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::setupIdleTab()
|
void AdvSceneSwitcher::setupIdleTab()
|
||||||
{
|
{
|
||||||
populateSceneSelection(ui->idleScenes, true);
|
populateSceneSelection(ui->idleScenes, true);
|
||||||
populateTransitionSelection(ui->idleTransitions);
|
populateTransitionSelection(ui->idleTransitions);
|
||||||
|
|||||||
@@ -1,163 +1,178 @@
|
|||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
void SceneSwitcher::on_mediaSwitches_currentRowChanged(int idx)
|
static QMetaObject::Connection addPulse;
|
||||||
|
|
||||||
|
constexpr auto media_played_to_end_idx = 8;
|
||||||
|
constexpr auto media_any_idx = 9;
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_mediaAdd_clicked()
|
||||||
{
|
{
|
||||||
if (loading)
|
ui->mediaAdd->disconnect(addPulse);
|
||||||
return;
|
|
||||||
if (idx == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QListWidgetItem *item = ui->mediaSwitches->item(idx);
|
|
||||||
|
|
||||||
QString mediaSceneStr = 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->mediaSwitches) {
|
switcher->mediaSwitches.emplace_back();
|
||||||
if (mediaSceneStr.compare(s.mediaSwitchStr.c_str()) == 0) {
|
|
||||||
QString sceneName = GetWeakSourceName(s.scene).c_str();
|
QListWidgetItem *item;
|
||||||
QString sourceName =
|
item = new QListWidgetItem(ui->mediaSwitches);
|
||||||
GetWeakSourceName(s.source).c_str();
|
ui->mediaSwitches->addItem(item);
|
||||||
QString transitionName =
|
MediaSwitchWidget *sw =
|
||||||
GetWeakSourceName(s.transition).c_str();
|
new MediaSwitchWidget(&switcher->mediaSwitches.back());
|
||||||
ui->mediaScenes->setCurrentText(sceneName);
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
ui->mediaSources->setCurrentText(sourceName);
|
ui->mediaSwitches->setItemWidget(item, sw);
|
||||||
ui->mediaTransitions->setCurrentText(transitionName);
|
|
||||||
ui->mediaStates->setCurrentIndex(s.state);
|
|
||||||
ui->mediaTimeRestrictions->setCurrentIndex(
|
|
||||||
s.restriction);
|
|
||||||
ui->mediaTime->setValue(s.time);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_mediaAdd_clicked()
|
void AdvSceneSwitcher::on_mediaRemove_clicked()
|
||||||
{
|
|
||||||
QString sourceName = ui->mediaSources->currentText();
|
|
||||||
QString sceneName = ui->mediaScenes->currentText();
|
|
||||||
QString transitionName = ui->mediaTransitions->currentText();
|
|
||||||
obs_media_state state =
|
|
||||||
(obs_media_state)ui->mediaStates->currentIndex();
|
|
||||||
time_restriction restriction =
|
|
||||||
(time_restriction)ui->mediaTimeRestrictions->currentIndex();
|
|
||||||
uint64_t time = ui->mediaTime->value();
|
|
||||||
|
|
||||||
if (sceneName.isEmpty() || transitionName.isEmpty() ||
|
|
||||||
sourceName.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
OBSWeakSource source = GetWeakSourceByQString(sourceName);
|
|
||||||
OBSWeakSource scene = GetWeakSourceByQString(sceneName);
|
|
||||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
|
||||||
|
|
||||||
QString switchText = MakeMediaSwitchName(sourceName, sceneName,
|
|
||||||
transitionName, state,
|
|
||||||
restriction, time);
|
|
||||||
QVariant v = QVariant::fromValue(switchText);
|
|
||||||
|
|
||||||
QListWidgetItem *item =
|
|
||||||
new QListWidgetItem(switchText, ui->mediaSwitches);
|
|
||||||
item->setData(Qt::UserRole, v);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
switcher->mediaSwitches.emplace_back(
|
|
||||||
scene, source, transition, state, restriction, time,
|
|
||||||
(sceneName == QString(previous_scene_name)),
|
|
||||||
switchText.toUtf8().constData());
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_mediaRemove_clicked()
|
|
||||||
{
|
{
|
||||||
QListWidgetItem *item = ui->mediaSwitches->currentItem();
|
QListWidgetItem *item = ui->mediaSwitches->currentItem();
|
||||||
if (!item)
|
if (!item)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::string mediaStr =
|
|
||||||
item->data(Qt::UserRole).toString().toUtf8().constData();
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
int idx = ui->mediaSwitches->currentRow();
|
||||||
auto &switches = switcher->mediaSwitches;
|
auto &switches = switcher->mediaSwitches;
|
||||||
|
switches.erase(switches.begin() + idx);
|
||||||
for (auto it = switches.begin(); it != switches.end(); ++it) {
|
|
||||||
auto &s = *it;
|
|
||||||
|
|
||||||
if (s.mediaSwitchStr == mediaStr) {
|
|
||||||
switches.erase(it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete item;
|
delete item;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_mediaUp_clicked()
|
void AdvSceneSwitcher::on_mediaUp_clicked()
|
||||||
{
|
{
|
||||||
int index = ui->mediaSwitches->currentRow();
|
int index = ui->mediaSwitches->currentRow();
|
||||||
if (index != -1 && index != 0) {
|
if (!listMoveUp(ui->mediaSwitches))
|
||||||
ui->mediaSwitches->insertItem(
|
|
||||||
index - 1, ui->mediaSwitches->takeItem(index));
|
|
||||||
ui->mediaSwitches->setCurrentRow(index - 1);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
|
|
||||||
iter_swap(switcher->mediaSwitches.begin() + index,
|
|
||||||
switcher->mediaSwitches.begin() + index - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_mediaDown_clicked()
|
|
||||||
{
|
|
||||||
int index = ui->mediaSwitches->currentRow();
|
|
||||||
if (index != -1 && index != ui->mediaSwitches->count() - 1) {
|
|
||||||
ui->mediaSwitches->insertItem(
|
|
||||||
index + 1, ui->mediaSwitches->takeItem(index));
|
|
||||||
ui->mediaSwitches->setCurrentRow(index + 1);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
|
|
||||||
iter_swap(switcher->mediaSwitches.begin() + index,
|
|
||||||
switcher->mediaSwitches.begin() + index + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_mediaTimeRestrictions_currentIndexChanged(int idx)
|
|
||||||
{
|
|
||||||
if (idx == -1)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ((time_restriction)ui->mediaTimeRestrictions->currentIndex() ==
|
MediaSwitchWidget *s1 =
|
||||||
TIME_RESTRICTION_NONE) {
|
(MediaSwitchWidget *)ui->mediaSwitches->itemWidget(
|
||||||
ui->mediaTime->setDisabled(true);
|
ui->mediaSwitches->item(index));
|
||||||
} else {
|
MediaSwitchWidget *s2 =
|
||||||
ui->mediaTime->setDisabled(false);
|
(MediaSwitchWidget *)ui->mediaSwitches->itemWidget(
|
||||||
}
|
ui->mediaSwitches->item(index - 1));
|
||||||
|
MediaSwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
|
||||||
|
std::swap(switcher->mediaSwitches[index],
|
||||||
|
switcher->mediaSwitches[index - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_mediaDown_clicked()
|
||||||
|
{
|
||||||
|
int index = ui->mediaSwitches->currentRow();
|
||||||
|
|
||||||
|
if (!listMoveDown(ui->mediaSwitches))
|
||||||
|
return;
|
||||||
|
|
||||||
|
MediaSwitchWidget *s1 =
|
||||||
|
(MediaSwitchWidget *)ui->mediaSwitches->itemWidget(
|
||||||
|
ui->mediaSwitches->item(index));
|
||||||
|
MediaSwitchWidget *s2 =
|
||||||
|
(MediaSwitchWidget *)ui->mediaSwitches->itemWidget(
|
||||||
|
ui->mediaSwitches->item(index + 1));
|
||||||
|
MediaSwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
|
||||||
|
std::swap(switcher->mediaSwitches[index],
|
||||||
|
switcher->mediaSwitches[index + 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitcherData::checkMediaSwitch(bool &match, OBSWeakSource &scene,
|
void SwitcherData::checkMediaSwitch(bool &match, OBSWeakSource &scene,
|
||||||
OBSWeakSource &transition)
|
OBSWeakSource &transition)
|
||||||
{
|
{
|
||||||
for (MediaSwitch &mediaSwitch : mediaSwitches) {
|
for (MediaSwitch &mediaSwitch : mediaSwitches) {
|
||||||
|
if (!mediaSwitch.initialized())
|
||||||
|
continue;
|
||||||
|
|
||||||
obs_source_t *source =
|
obs_source_t *source =
|
||||||
obs_weak_source_get_source(mediaSwitch.source);
|
obs_weak_source_get_source(mediaSwitch.source);
|
||||||
auto duration = obs_source_media_get_duration(source);
|
auto duration = obs_source_media_get_duration(source);
|
||||||
auto time = obs_source_media_get_time(source);
|
auto time = obs_source_media_get_time(source);
|
||||||
obs_media_state state = obs_source_media_get_state(source);
|
obs_media_state state = obs_source_media_get_state(source);
|
||||||
bool matched =
|
obs_source_release(source);
|
||||||
state == mediaSwitch.state &&
|
|
||||||
(mediaSwitch.restriction == TIME_RESTRICTION_NONE ||
|
bool matchedStopped = mediaSwitch.state ==
|
||||||
(mediaSwitch.restriction == TIME_RESTRICTION_LONGER &&
|
OBS_MEDIA_STATE_STOPPED &&
|
||||||
time > mediaSwitch.time) ||
|
mediaSwitch.stopped;
|
||||||
(mediaSwitch.restriction == TIME_RESTRICTION_SHORTER &&
|
|
||||||
time < mediaSwitch.time) ||
|
// The signal for the state ended is intentionally not used here
|
||||||
(mediaSwitch.restriction ==
|
// so matchedEnded can be used to specify the end of a VLC playlist
|
||||||
TIME_RESTRICTION_REMAINING_SHORTER &&
|
// by two consequtive matches of OBS_MEDIA_STATE_ENDED
|
||||||
duration > time &&
|
//
|
||||||
duration - time < mediaSwitch.time) ||
|
// This was done to reduce the likelyhood of interpreting a single
|
||||||
(mediaSwitch.restriction ==
|
// OBS_MEDIA_STATE_ENDED caught by obs_source_media_get_state()
|
||||||
TIME_RESTRICTION_REMAINING_LONGER &&
|
// as the end of the playlist of the VLC source, while actually being
|
||||||
duration > time &&
|
// in the middle of switching to the next item of the playlist
|
||||||
duration - time > mediaSwitch.time));
|
//
|
||||||
|
// If there is a separate obs_media_sate in the future for the
|
||||||
|
// "end of playlist reached" signal the line below can be used
|
||||||
|
// and an additional check for this new singal can be introduced
|
||||||
|
//
|
||||||
|
// bool matchedEnded = mediaSwitch.state == OBS_MEDIA_STATE_ENDED &&
|
||||||
|
// mediaSwitch.ended;
|
||||||
|
|
||||||
|
bool ended = false;
|
||||||
|
|
||||||
|
if (state == OBS_MEDIA_STATE_ENDED) {
|
||||||
|
ended = mediaSwitch.previousStateEnded;
|
||||||
|
mediaSwitch.previousStateEnded = true;
|
||||||
|
} else {
|
||||||
|
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
|
||||||
|
mediaSwitch.stopped = false;
|
||||||
|
mediaSwitch.ended = false;
|
||||||
|
|
||||||
|
bool matchedState = ((state == mediaSwitch.state) ||
|
||||||
|
mediaSwitch.anyState) ||
|
||||||
|
matchedStopped || matchedEnded ||
|
||||||
|
matchedPlayedToEnd;
|
||||||
|
|
||||||
|
bool matchedTimeNone =
|
||||||
|
(mediaSwitch.restriction == TIME_RESTRICTION_NONE);
|
||||||
|
bool matchedTimeLonger =
|
||||||
|
(mediaSwitch.restriction == TIME_RESTRICTION_LONGER) &&
|
||||||
|
(time > mediaSwitch.time);
|
||||||
|
bool matchedTimeShorter =
|
||||||
|
(mediaSwitch.restriction == TIME_RESTRICTION_SHORTER) &&
|
||||||
|
(time < mediaSwitch.time);
|
||||||
|
bool matchedTimeRemainLonger =
|
||||||
|
(mediaSwitch.restriction ==
|
||||||
|
TIME_RESTRICTION_REMAINING_LONGER) &&
|
||||||
|
(duration > time && duration - time > mediaSwitch.time);
|
||||||
|
bool matchedTimeRemainShorter =
|
||||||
|
(mediaSwitch.restriction ==
|
||||||
|
TIME_RESTRICTION_REMAINING_SHORTER) &&
|
||||||
|
(duration > time && duration - time < mediaSwitch.time);
|
||||||
|
|
||||||
|
bool matchedTime = matchedTimeNone || matchedTimeLonger ||
|
||||||
|
matchedTimeShorter ||
|
||||||
|
matchedTimeRemainLonger ||
|
||||||
|
matchedTimeRemainShorter;
|
||||||
|
|
||||||
|
bool matched = matchedState && matchedTime;
|
||||||
|
|
||||||
if (matched && !mediaSwitch.matched) {
|
if (matched && !mediaSwitch.matched) {
|
||||||
match = true;
|
match = true;
|
||||||
scene = (mediaSwitch.usePreviousScene)
|
scene = (mediaSwitch.usePreviousScene)
|
||||||
@@ -168,8 +183,11 @@ void SwitcherData::checkMediaSwitch(bool &match, OBSWeakSource &scene,
|
|||||||
if (verbose)
|
if (verbose)
|
||||||
mediaSwitch.logMatch();
|
mediaSwitch.logMatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
mediaSwitch.matched = matched;
|
mediaSwitch.matched = matched;
|
||||||
obs_source_release(source);
|
|
||||||
|
if (match)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,113 +251,312 @@ void SwitcherData::loadMediaSwitches(obs_data_t *obj)
|
|||||||
"restriction");
|
"restriction");
|
||||||
uint64_t time = obs_data_get_int(array_obj, "time");
|
uint64_t time = obs_data_get_int(array_obj, "time");
|
||||||
|
|
||||||
std::string mediaStr = MakeMediaSwitchName(source, scene,
|
|
||||||
transition, state,
|
|
||||||
restriction, time)
|
|
||||||
.toUtf8()
|
|
||||||
.constData();
|
|
||||||
|
|
||||||
switcher->mediaSwitches.emplace_back(
|
switcher->mediaSwitches.emplace_back(
|
||||||
GetWeakSourceByName(scene), GetWeakSourceByName(source),
|
GetWeakSourceByName(scene), GetWeakSourceByName(source),
|
||||||
GetWeakTransitionByName(transition), state, restriction,
|
GetWeakTransitionByName(transition), state, restriction,
|
||||||
time, (strcmp(scene, previous_scene_name) == 0),
|
time, (strcmp(scene, previous_scene_name) == 0));
|
||||||
mediaStr);
|
|
||||||
|
|
||||||
obs_data_release(array_obj);
|
obs_data_release(array_obj);
|
||||||
}
|
}
|
||||||
obs_data_array_release(mediaArray);
|
obs_data_array_release(mediaArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::setupMediaTab()
|
void AdvSceneSwitcher::setupMediaTab()
|
||||||
{
|
{
|
||||||
populateSceneSelection(ui->mediaScenes, true);
|
|
||||||
populateTransitionSelection(ui->mediaTransitions);
|
|
||||||
|
|
||||||
auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */
|
|
||||||
{
|
|
||||||
QComboBox *combo = reinterpret_cast<QComboBox *>(data);
|
|
||||||
std::string sourceId = obs_source_get_id(source);
|
|
||||||
if (sourceId.compare("ffmpeg_source") == 0 ||
|
|
||||||
sourceId.compare("vlc_source") == 0) {
|
|
||||||
const char *name = obs_source_get_name(source);
|
|
||||||
combo->addItem(name);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
obs_enum_sources(sourceEnum, ui->mediaSources);
|
|
||||||
|
|
||||||
ui->mediaStates->addItem("None");
|
|
||||||
ui->mediaStates->addItem("Playing");
|
|
||||||
ui->mediaStates->addItem("Opening");
|
|
||||||
ui->mediaStates->addItem("Buffering");
|
|
||||||
ui->mediaStates->addItem("Paused");
|
|
||||||
ui->mediaStates->addItem("Stopped");
|
|
||||||
ui->mediaStates->addItem("Ended");
|
|
||||||
ui->mediaStates->addItem("Error");
|
|
||||||
|
|
||||||
ui->mediaTimeRestrictions->addItem("None");
|
|
||||||
ui->mediaTimeRestrictions->addItem("Time shorter");
|
|
||||||
ui->mediaTimeRestrictions->addItem("Time longer");
|
|
||||||
ui->mediaTimeRestrictions->addItem("Time remaining shorter");
|
|
||||||
ui->mediaTimeRestrictions->addItem("Time remaining longer");
|
|
||||||
|
|
||||||
for (auto &s : switcher->mediaSwitches) {
|
for (auto &s : switcher->mediaSwitches) {
|
||||||
std::string sourceName = GetWeakSourceName(s.source);
|
QListWidgetItem *item;
|
||||||
std::string sceneName = (s.usePreviousScene)
|
item = new QListWidgetItem(ui->mediaSwitches);
|
||||||
? previous_scene_name
|
ui->mediaSwitches->addItem(item);
|
||||||
: GetWeakSourceName(s.scene);
|
MediaSwitchWidget *sw = new MediaSwitchWidget(&s);
|
||||||
std::string transitionName = GetWeakSourceName(s.transition);
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
QString listText = MakeMediaSwitchName(
|
ui->mediaSwitches->setItemWidget(item, sw);
|
||||||
sourceName.c_str(), sceneName.c_str(),
|
|
||||||
transitionName.c_str(), s.state, s.restriction, s.time);
|
|
||||||
|
|
||||||
QListWidgetItem *item =
|
|
||||||
new QListWidgetItem(listText, ui->mediaSwitches);
|
|
||||||
item->setData(Qt::UserRole, listText);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (switcher->mediaSwitches.size() == 0)
|
||||||
|
addPulse = PulseWidget(ui->mediaAdd, QColor(Qt::green));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline QString
|
bool MediaSwitch::initialized()
|
||||||
MakeMediaSwitchName(const QString &source, const QString &scene,
|
|
||||||
const QString &transition, obs_media_state state,
|
|
||||||
time_restriction restriction, uint64_t time)
|
|
||||||
{
|
{
|
||||||
QString switchName = QStringLiteral("Switch to ") + scene +
|
return SceneSwitcherEntry::initialized() && source;
|
||||||
QStringLiteral(" using ") + transition +
|
}
|
||||||
QStringLiteral(" if ") + source +
|
|
||||||
QStringLiteral(" state is ");
|
bool MediaSwitch::valid()
|
||||||
if (state == OBS_MEDIA_STATE_NONE) {
|
{
|
||||||
switchName += QStringLiteral("none");
|
return !initialized() ||
|
||||||
} else if (state == OBS_MEDIA_STATE_PLAYING) {
|
(SceneSwitcherEntry::valid() && WeakSourceValid(source));
|
||||||
switchName += QStringLiteral("playing");
|
}
|
||||||
} else if (state == OBS_MEDIA_STATE_OPENING) {
|
|
||||||
switchName += QStringLiteral("opening");
|
void MediaSwitch::clearSignalHandler()
|
||||||
} else if (state == OBS_MEDIA_STATE_BUFFERING) {
|
{
|
||||||
switchName += QStringLiteral("buffering");
|
obs_source_t *mediasource = obs_weak_source_get_source(source);
|
||||||
} else if (state == OBS_MEDIA_STATE_PAUSED) {
|
signal_handler_t *sh = obs_source_get_signal_handler(mediasource);
|
||||||
switchName += QStringLiteral("paused");
|
signal_handler_disconnect(sh, "media_stopped", MediaStopped, this);
|
||||||
} else if (state == OBS_MEDIA_STATE_STOPPED) {
|
signal_handler_disconnect(sh, "media_ended", MediaEnded, this);
|
||||||
switchName += QStringLiteral("stopped");
|
obs_source_release(mediasource);
|
||||||
} else if (state == OBS_MEDIA_STATE_ENDED) {
|
}
|
||||||
switchName += QStringLiteral("ended");
|
|
||||||
} else if (state == OBS_MEDIA_STATE_ERROR) {
|
void MediaSwitch::resetSignalHandler()
|
||||||
switchName += QStringLiteral("error");
|
{
|
||||||
}
|
obs_source_t *mediasource = obs_weak_source_get_source(source);
|
||||||
if (restriction == TIME_RESTRICTION_SHORTER) {
|
signal_handler_t *sh = obs_source_get_signal_handler(mediasource);
|
||||||
switchName += QStringLiteral(" and time shorter than ");
|
signal_handler_disconnect(sh, "media_stopped", MediaStopped, this);
|
||||||
} else if (restriction == TIME_RESTRICTION_LONGER) {
|
signal_handler_disconnect(sh, "media_ended", MediaEnded, this);
|
||||||
switchName += QStringLiteral(" and time longer than ");
|
signal_handler_connect(sh, "media_stopped", MediaStopped, this);
|
||||||
} else if (restriction == TIME_RESTRICTION_REMAINING_SHORTER) {
|
signal_handler_connect(sh, "media_ended", MediaEnded, this);
|
||||||
switchName +=
|
obs_source_release(mediasource);
|
||||||
QStringLiteral(" and time remaining shorter than ");
|
}
|
||||||
} else if (restriction == TIME_RESTRICTION_REMAINING_LONGER) {
|
|
||||||
switchName +=
|
void MediaSwitch::MediaStopped(void *data, calldata_t *)
|
||||||
QStringLiteral(" and time remaining longer than ");
|
{
|
||||||
}
|
MediaSwitch *media = static_cast<MediaSwitch *>(data);
|
||||||
if (restriction != TIME_RESTRICTION_NONE) {
|
media->stopped = true;
|
||||||
switchName += std::to_string(time).c_str();
|
}
|
||||||
switchName += QStringLiteral(" ms");
|
|
||||||
}
|
void MediaSwitch::MediaEnded(void *data, calldata_t *)
|
||||||
return switchName;
|
{
|
||||||
|
MediaSwitch *media = static_cast<MediaSwitch *>(data);
|
||||||
|
media->ended = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline MediaSwitch::MediaSwitch(OBSWeakSource scene_, OBSWeakSource source_,
|
||||||
|
OBSWeakSource transition_,
|
||||||
|
obs_media_state state_,
|
||||||
|
time_restriction restriction_, uint64_t time_,
|
||||||
|
bool usePreviousScene_)
|
||||||
|
: SceneSwitcherEntry(scene_, transition_, usePreviousScene_),
|
||||||
|
source(source_),
|
||||||
|
state(state_),
|
||||||
|
restriction(restriction_),
|
||||||
|
time(time_)
|
||||||
|
{
|
||||||
|
anyState = state == 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaSwitch::MediaSwitch(const MediaSwitch &other)
|
||||||
|
: SceneSwitcherEntry(other.scene, other.transition,
|
||||||
|
other.usePreviousScene),
|
||||||
|
source(other.source),
|
||||||
|
state(other.state),
|
||||||
|
restriction(other.restriction),
|
||||||
|
time(other.time)
|
||||||
|
{
|
||||||
|
anyState = state == 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaSwitch::MediaSwitch(MediaSwitch &&other)
|
||||||
|
: SceneSwitcherEntry(other.scene, other.transition,
|
||||||
|
other.usePreviousScene),
|
||||||
|
source(other.source),
|
||||||
|
state(other.state),
|
||||||
|
anyState(other.anyState),
|
||||||
|
restriction(other.restriction),
|
||||||
|
time(other.time)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaSwitch::~MediaSwitch()
|
||||||
|
{
|
||||||
|
obs_source_t *mediasource = obs_weak_source_get_source(source);
|
||||||
|
signal_handler_t *sh = obs_source_get_signal_handler(mediasource);
|
||||||
|
signal_handler_disconnect(sh, "media_stopped", MediaStopped, this);
|
||||||
|
signal_handler_disconnect(sh, "media_ended", MediaEnded, this);
|
||||||
|
obs_source_release(mediasource);
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaSwitch &MediaSwitch::operator=(const MediaSwitch &other)
|
||||||
|
{
|
||||||
|
MediaSwitch t(other);
|
||||||
|
swap(*this, t);
|
||||||
|
return *this = MediaSwitch(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaSwitch &MediaSwitch::operator=(MediaSwitch &&other) noexcept
|
||||||
|
{
|
||||||
|
if (this == &other) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
swap(*this, other);
|
||||||
|
|
||||||
|
obs_source_t *mediasource = obs_weak_source_get_source(other.source);
|
||||||
|
signal_handler_t *sh = obs_source_get_signal_handler(mediasource);
|
||||||
|
signal_handler_disconnect(sh, "media_stopped", MediaStopped, &other);
|
||||||
|
signal_handler_disconnect(sh, "media_ended", MediaEnded, &other);
|
||||||
|
obs_source_release(mediasource);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(MediaSwitch &first, MediaSwitch &second)
|
||||||
|
{
|
||||||
|
std::swap(first.scene, second.scene);
|
||||||
|
std::swap(first.transition, second.transition);
|
||||||
|
std::swap(first.usePreviousScene, second.usePreviousScene);
|
||||||
|
std::swap(first.source, second.source);
|
||||||
|
std::swap(first.state, second.state);
|
||||||
|
std::swap(first.restriction, second.restriction);
|
||||||
|
std::swap(first.time, second.time);
|
||||||
|
std::swap(first.anyState, second.anyState);
|
||||||
|
first.resetSignalHandler();
|
||||||
|
second.resetSignalHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
void populateMediaStates(QComboBox *list)
|
||||||
|
{
|
||||||
|
list->addItem("None");
|
||||||
|
list->addItem("Playing");
|
||||||
|
list->addItem("Opening");
|
||||||
|
list->addItem("Buffering");
|
||||||
|
list->addItem("Paused");
|
||||||
|
list->addItem("Stopped");
|
||||||
|
list->addItem("Ended");
|
||||||
|
list->addItem("Error");
|
||||||
|
list->addItem("Played to end");
|
||||||
|
list->addItem("Any");
|
||||||
|
}
|
||||||
|
|
||||||
|
void populateTimeRestrictions(QComboBox *list)
|
||||||
|
{
|
||||||
|
list->addItem("None");
|
||||||
|
list->addItem("Time shorter");
|
||||||
|
list->addItem("Time longer");
|
||||||
|
list->addItem("Time remaining shorter");
|
||||||
|
list->addItem("Time remaining longer");
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaSwitchWidget::MediaSwitchWidget(MediaSwitch *s) : SwitchWidget(s)
|
||||||
|
{
|
||||||
|
meidaSources = new QComboBox();
|
||||||
|
states = new QComboBox();
|
||||||
|
timeRestrictions = new QComboBox();
|
||||||
|
time = new QSpinBox();
|
||||||
|
|
||||||
|
whenLabel = new QLabel("When");
|
||||||
|
stateLabel = new QLabel("state is");
|
||||||
|
andLabel = new QLabel("and");
|
||||||
|
switchLabel = new QLabel("switch to");
|
||||||
|
usingLabel = new QLabel("using");
|
||||||
|
|
||||||
|
time->setSuffix("ms");
|
||||||
|
time->setMaximum(99999999);
|
||||||
|
time->setMinimum(0);
|
||||||
|
|
||||||
|
QWidget::connect(meidaSources,
|
||||||
|
SIGNAL(currentTextChanged(const QString &)), this,
|
||||||
|
SLOT(SourceChanged(const QString &)));
|
||||||
|
QWidget::connect(states, SIGNAL(currentIndexChanged(int)), this,
|
||||||
|
SLOT(StateChanged(int)));
|
||||||
|
QWidget::connect(timeRestrictions, SIGNAL(currentIndexChanged(int)),
|
||||||
|
this, SLOT(TimeRestrictionChanged(int)));
|
||||||
|
QWidget::connect(time, SIGNAL(valueChanged(int)), this,
|
||||||
|
SLOT(TimeChanged(int)));
|
||||||
|
|
||||||
|
AdvSceneSwitcher::populateMediaSelection(meidaSources);
|
||||||
|
populateMediaStates(states);
|
||||||
|
populateTimeRestrictions(timeRestrictions);
|
||||||
|
|
||||||
|
if (s) {
|
||||||
|
meidaSources->setCurrentText(
|
||||||
|
GetWeakSourceName(s->source).c_str());
|
||||||
|
states->setCurrentIndex(s->state);
|
||||||
|
timeRestrictions->setCurrentIndex(s->restriction);
|
||||||
|
time->setValue(s->time);
|
||||||
|
if (s->restriction == TIME_RESTRICTION_NONE)
|
||||||
|
time->setDisabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
setStyleSheet("* { background-color: transparent; }");
|
||||||
|
|
||||||
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
|
||||||
|
mainLayout->addWidget(whenLabel);
|
||||||
|
mainLayout->addWidget(meidaSources);
|
||||||
|
mainLayout->addWidget(stateLabel);
|
||||||
|
mainLayout->addWidget(states);
|
||||||
|
mainLayout->addWidget(andLabel);
|
||||||
|
mainLayout->addWidget(timeRestrictions);
|
||||||
|
mainLayout->addWidget(time);
|
||||||
|
mainLayout->addWidget(switchLabel);
|
||||||
|
mainLayout->addWidget(scenes);
|
||||||
|
mainLayout->addWidget(usingLabel);
|
||||||
|
mainLayout->addWidget(transitions);
|
||||||
|
mainLayout->addStretch();
|
||||||
|
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
switchData = s;
|
||||||
|
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaSwitch *MediaSwitchWidget::getSwitchData()
|
||||||
|
{
|
||||||
|
return switchData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaSwitchWidget::setSwitchData(MediaSwitch *s)
|
||||||
|
{
|
||||||
|
switchData = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaSwitchWidget::swapSwitchData(MediaSwitchWidget *s1,
|
||||||
|
MediaSwitchWidget *s2)
|
||||||
|
{
|
||||||
|
SwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
MediaSwitch *t = s1->getSwitchData();
|
||||||
|
s1->setSwitchData(s2->getSwitchData());
|
||||||
|
s2->setSwitchData(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaSwitchWidget::SourceChanged(const QString &text)
|
||||||
|
{
|
||||||
|
if (loading || !switchData)
|
||||||
|
return;
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->clearSignalHandler();
|
||||||
|
switchData->source = GetWeakSourceByQString(text);
|
||||||
|
switchData->resetSignalHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaSwitchWidget::StateChanged(int index)
|
||||||
|
{
|
||||||
|
if (loading || !switchData)
|
||||||
|
return;
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->state = (obs_media_state)index;
|
||||||
|
switchData->anyState = switchData->state == media_any_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaSwitchWidget::TimeRestrictionChanged(int index)
|
||||||
|
{
|
||||||
|
if (loading || !switchData)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((time_restriction)index == TIME_RESTRICTION_NONE)
|
||||||
|
time->setDisabled(true);
|
||||||
|
else
|
||||||
|
time->setDisabled(false);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->restriction = (time_restriction)index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaSwitchWidget::TimeChanged(int time)
|
||||||
|
{
|
||||||
|
if (loading || !switchData)
|
||||||
|
return;
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->time = time;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
#include <regex>
|
#include <regex>
|
||||||
|
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
void SceneSwitcher::on_pauseScenesAdd_clicked()
|
void AdvSceneSwitcher::on_pauseScenesAdd_clicked()
|
||||||
{
|
{
|
||||||
QString sceneName = ui->pauseScenesScenes->currentText();
|
QString sceneName = ui->pauseScenesScenes->currentText();
|
||||||
|
|
||||||
@@ -26,7 +27,7 @@ void SceneSwitcher::on_pauseScenesAdd_clicked()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_pauseScenesRemove_clicked()
|
void AdvSceneSwitcher::on_pauseScenesRemove_clicked()
|
||||||
{
|
{
|
||||||
QListWidgetItem *item = ui->pauseScenes->currentItem();
|
QListWidgetItem *item = ui->pauseScenes->currentItem();
|
||||||
if (!item)
|
if (!item)
|
||||||
@@ -51,7 +52,7 @@ void SceneSwitcher::on_pauseScenesRemove_clicked()
|
|||||||
delete item;
|
delete item;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_pauseWindowsAdd_clicked()
|
void AdvSceneSwitcher::on_pauseWindowsAdd_clicked()
|
||||||
{
|
{
|
||||||
QString windowName = ui->pauseWindowsWindows->currentText();
|
QString windowName = ui->pauseWindowsWindows->currentText();
|
||||||
|
|
||||||
@@ -75,7 +76,7 @@ void SceneSwitcher::on_pauseWindowsAdd_clicked()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_pauseWindowsRemove_clicked()
|
void AdvSceneSwitcher::on_pauseWindowsRemove_clicked()
|
||||||
{
|
{
|
||||||
QListWidgetItem *item = ui->pauseWindows->currentItem();
|
QListWidgetItem *item = ui->pauseWindows->currentItem();
|
||||||
if (!item)
|
if (!item)
|
||||||
@@ -100,7 +101,7 @@ void SceneSwitcher::on_pauseWindowsRemove_clicked()
|
|||||||
delete item;
|
delete item;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_pauseScenes_currentRowChanged(int idx)
|
void AdvSceneSwitcher::on_pauseScenes_currentRowChanged(int idx)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading)
|
||||||
return;
|
return;
|
||||||
@@ -121,7 +122,7 @@ void SceneSwitcher::on_pauseScenes_currentRowChanged(int idx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_pauseWindows_currentRowChanged(int idx)
|
void AdvSceneSwitcher::on_pauseWindows_currentRowChanged(int idx)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading)
|
||||||
return;
|
return;
|
||||||
@@ -141,7 +142,7 @@ void SceneSwitcher::on_pauseWindows_currentRowChanged(int idx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int SceneSwitcher::PauseScenesFindByData(const QString &scene)
|
int AdvSceneSwitcher::PauseScenesFindByData(const QString &scene)
|
||||||
{
|
{
|
||||||
int count = ui->pauseScenes->count();
|
int count = ui->pauseScenes->count();
|
||||||
int idx = -1;
|
int idx = -1;
|
||||||
@@ -159,7 +160,7 @@ int SceneSwitcher::PauseScenesFindByData(const QString &scene)
|
|||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SceneSwitcher::PauseWindowsFindByData(const QString &window)
|
int AdvSceneSwitcher::PauseWindowsFindByData(const QString &window)
|
||||||
{
|
{
|
||||||
int count = ui->pauseWindows->count();
|
int count = ui->pauseWindows->count();
|
||||||
int idx = -1;
|
int idx = -1;
|
||||||
@@ -223,7 +224,7 @@ bool SwitcherData::checkPause()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (verbose && pause)
|
if (verbose && pause)
|
||||||
blog(LOG_INFO, "Advanced Scene Switcher pause match");
|
blog(LOG_INFO, "pause match");
|
||||||
|
|
||||||
return pause;
|
return pause;
|
||||||
}
|
}
|
||||||
@@ -239,9 +240,8 @@ void SwitcherData::savePauseSwitches(obs_data_t *obj)
|
|||||||
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, "pauseScenes", pauseScenesArray);
|
||||||
@@ -300,7 +300,7 @@ void SwitcherData::loadPauseSwitches(obs_data_t *obj)
|
|||||||
obs_data_array_release(pauseWindowsArray);
|
obs_data_array_release(pauseWindowsArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::setupPauseTab()
|
void AdvSceneSwitcher::setupPauseTab()
|
||||||
{
|
{
|
||||||
populateSceneSelection(ui->pauseScenesScenes, false);
|
populateSceneSelection(ui->pauseScenesScenes, false);
|
||||||
populateWindowSelection(ui->pauseWindowsWindows);
|
populateWindowSelection(ui->pauseWindowsWindows);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
|
||||||
void SceneSwitcher::on_threadPriority_currentTextChanged(const QString &text)
|
void AdvSceneSwitcher::on_threadPriority_currentTextChanged(const QString &text)
|
||||||
{
|
{
|
||||||
if (loading || ui->threadPriority->count() !=
|
if (loading || ui->threadPriority->count() !=
|
||||||
(int)switcher->threadPriorities.size())
|
(int)switcher->threadPriorities.size())
|
||||||
@@ -18,7 +18,7 @@ void SceneSwitcher::on_threadPriority_currentTextChanged(const QString &text)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_priorityUp_clicked()
|
void AdvSceneSwitcher::on_priorityUp_clicked()
|
||||||
{
|
{
|
||||||
int currentIndex = ui->priorityList->currentRow();
|
int currentIndex = ui->priorityList->currentRow();
|
||||||
if (currentIndex != -1 && currentIndex != 0) {
|
if (currentIndex != -1 && currentIndex != 0) {
|
||||||
@@ -35,7 +35,7 @@ void SceneSwitcher::on_priorityUp_clicked()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_priorityDown_clicked()
|
void AdvSceneSwitcher::on_priorityDown_clicked()
|
||||||
{
|
{
|
||||||
int currentIndex = ui->priorityList->currentRow();
|
int currentIndex = ui->priorityList->currentRow();
|
||||||
if (currentIndex != -1 &&
|
if (currentIndex != -1 &&
|
||||||
|
|||||||
@@ -1,115 +1,37 @@
|
|||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
void SceneSwitcher::on_randomScenesList_currentRowChanged(int idx)
|
static QMetaObject::Connection addPulse;
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_randomAdd_clicked()
|
||||||
{
|
{
|
||||||
if (loading)
|
ui->randomAdd->disconnect(addPulse);
|
||||||
return;
|
|
||||||
if (idx == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QListWidgetItem *item = ui->randomScenesList->item(idx);
|
|
||||||
|
|
||||||
QString randomSceneStr = 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->randomSwitches) {
|
switcher->randomSwitches.emplace_back();
|
||||||
if (randomSceneStr.compare(s.randomSwitchStr.c_str()) == 0) {
|
|
||||||
QString sceneName = GetWeakSourceName(s.scene).c_str();
|
QListWidgetItem *item;
|
||||||
QString transitionName =
|
item = new QListWidgetItem(ui->randomSwitches);
|
||||||
GetWeakSourceName(s.transition).c_str();
|
ui->randomSwitches->addItem(item);
|
||||||
ui->randomScenes->setCurrentText(sceneName);
|
RandomSwitchWidget *sw =
|
||||||
ui->randomSpinBox->setValue(s.delay);
|
new RandomSwitchWidget(&switcher->randomSwitches.back());
|
||||||
ui->randomTransitions->setCurrentText(transitionName);
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
break;
|
ui->randomSwitches->setItemWidget(item, sw);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int SceneSwitcher::randomFindByData(const QString &randomStr)
|
void AdvSceneSwitcher::on_randomRemove_clicked()
|
||||||
{
|
{
|
||||||
int count = ui->randomScenesList->count();
|
QListWidgetItem *item = ui->randomSwitches->currentItem();
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
QListWidgetItem *item = ui->randomScenesList->item(i);
|
|
||||||
QString str = item->data(Qt::UserRole).toString();
|
|
||||||
|
|
||||||
if (str == randomStr)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_randomAdd_clicked()
|
|
||||||
{
|
|
||||||
QString sceneName = ui->randomScenes->currentText();
|
|
||||||
QString transitionName = ui->randomTransitions->currentText();
|
|
||||||
double delay = ui->randomSpinBox->value();
|
|
||||||
|
|
||||||
if (sceneName.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
OBSWeakSource source = GetWeakSourceByQString(sceneName);
|
|
||||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
|
||||||
|
|
||||||
QString text = MakeRandomSwitchName(sceneName, transitionName, delay);
|
|
||||||
QVariant v = QVariant::fromValue(text);
|
|
||||||
|
|
||||||
int idx = randomFindByData(text);
|
|
||||||
|
|
||||||
if (idx == -1) {
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
switcher->randomSwitches.emplace_back(
|
|
||||||
source, transition, delay, text.toUtf8().constData());
|
|
||||||
|
|
||||||
QListWidgetItem *item =
|
|
||||||
new QListWidgetItem(text, ui->randomScenesList);
|
|
||||||
item->setData(Qt::UserRole, v);
|
|
||||||
} else {
|
|
||||||
QListWidgetItem *item = ui->randomScenesList->item(idx);
|
|
||||||
item->setText(text);
|
|
||||||
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
for (auto &s : switcher->randomSwitches) {
|
|
||||||
if (s.scene == source) {
|
|
||||||
s.delay = delay;
|
|
||||||
s.transition = transition;
|
|
||||||
s.randomSwitchStr =
|
|
||||||
text.toUtf8().constData();
|
|
||||||
;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ui->randomScenesList->sortItems();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_randomRemove_clicked()
|
|
||||||
{
|
|
||||||
QListWidgetItem *item = ui->randomScenesList->currentItem();
|
|
||||||
if (!item)
|
if (!item)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::string text =
|
|
||||||
item->data(Qt::UserRole).toString().toUtf8().constData();
|
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
int idx = ui->randomSwitches->currentRow();
|
||||||
auto &switches = switcher->randomSwitches;
|
auto &switches = switcher->randomSwitches;
|
||||||
|
switches.erase(switches.begin() + idx);
|
||||||
for (auto it = switches.begin(); it != switches.end(); ++it) {
|
|
||||||
auto &s = *it;
|
|
||||||
|
|
||||||
if (s.randomSwitchStr == text) {
|
|
||||||
switches.erase(it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete item;
|
delete item;
|
||||||
@@ -121,12 +43,15 @@ void SwitcherData::checkRandom(bool &match, OBSWeakSource &scene,
|
|||||||
if (randomSwitches.size() == 0)
|
if (randomSwitches.size() == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::vector<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.scene == lastRandomScene)
|
if (!r.initialized())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (r.scene == lastRandomScene && randomSwitches.size() != 1)
|
||||||
continue;
|
continue;
|
||||||
scene = r.scene;
|
scene = r.scene;
|
||||||
transition = r.transition;
|
transition = r.transition;
|
||||||
@@ -159,10 +84,9 @@ void SwitcherData::saveRandomSwitches(obs_data_t *obj)
|
|||||||
transitionName);
|
transitionName);
|
||||||
obs_data_set_double(array_obj, "delay", s.delay);
|
obs_data_set_double(array_obj, "delay", s.delay);
|
||||||
obs_data_array_push_back(randomArray, array_obj);
|
obs_data_array_push_back(randomArray, array_obj);
|
||||||
obs_source_release(source);
|
|
||||||
obs_source_release(transition);
|
|
||||||
}
|
}
|
||||||
|
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);
|
||||||
@@ -185,43 +109,97 @@ void SwitcherData::loadRandomSwitches(obs_data_t *obj)
|
|||||||
obs_data_get_string(array_obj, "transition");
|
obs_data_get_string(array_obj, "transition");
|
||||||
double delay = obs_data_get_double(array_obj, "delay");
|
double delay = obs_data_get_double(array_obj, "delay");
|
||||||
|
|
||||||
std::string randomSwitchStr =
|
|
||||||
MakeRandomSwitchName(scene, transition, delay)
|
|
||||||
.toUtf8()
|
|
||||||
.constData();
|
|
||||||
|
|
||||||
switcher->randomSwitches.emplace_back(
|
switcher->randomSwitches.emplace_back(
|
||||||
GetWeakSourceByName(scene),
|
GetWeakSourceByName(scene),
|
||||||
GetWeakTransitionByName(transition), delay,
|
GetWeakTransitionByName(transition), delay);
|
||||||
randomSwitchStr);
|
|
||||||
|
|
||||||
obs_data_release(array_obj);
|
obs_data_release(array_obj);
|
||||||
}
|
}
|
||||||
obs_data_array_release(randomArray);
|
obs_data_array_release(randomArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::setupRandomTab()
|
void AdvSceneSwitcher::setupRandomTab()
|
||||||
{
|
{
|
||||||
populateSceneSelection(ui->randomScenes, false);
|
|
||||||
populateTransitionSelection(ui->randomTransitions);
|
|
||||||
|
|
||||||
for (auto &s : switcher->randomSwitches) {
|
for (auto &s : switcher->randomSwitches) {
|
||||||
std::string sceneName = GetWeakSourceName(s.scene);
|
QListWidgetItem *item;
|
||||||
std::string transitionName = GetWeakSourceName(s.transition);
|
item = new QListWidgetItem(ui->randomSwitches);
|
||||||
QString text = MakeRandomSwitchName(
|
ui->randomSwitches->addItem(item);
|
||||||
sceneName.c_str(), transitionName.c_str(), s.delay);
|
RandomSwitchWidget *sw = new RandomSwitchWidget(&s);
|
||||||
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
QListWidgetItem *item =
|
ui->randomSwitches->setItemWidget(item, sw);
|
||||||
new QListWidgetItem(text, ui->randomScenesList);
|
|
||||||
item->setData(Qt::UserRole, text);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (switcher->randomSwitches.size() == 0)
|
||||||
|
addPulse = PulseWidget(ui->randomAdd, QColor(Qt::green));
|
||||||
|
|
||||||
|
if (switcher->switchIfNotMatching != RANDOM_SWITCH)
|
||||||
|
PulseWidget(ui->randomDisabledWarning, QColor(Qt::red),
|
||||||
|
QColor(0, 0, 0, 0), "QLabel ");
|
||||||
|
else
|
||||||
|
ui->randomDisabledWarning->setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline QString MakeRandomSwitchName(const QString &scene,
|
RandomSwitchWidget::RandomSwitchWidget(RandomSwitch *s) : SwitchWidget(s, false)
|
||||||
const QString &transition,
|
|
||||||
double &delay)
|
|
||||||
{
|
{
|
||||||
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition +
|
delay = new QDoubleSpinBox();
|
||||||
QStringLiteral("]: ") + QString::number(delay) +
|
|
||||||
QStringLiteral(" seconds");
|
switchLabel = new QLabel("If no switch condition is met switch to ");
|
||||||
|
usingLabel = new QLabel("using");
|
||||||
|
forLabel = new QLabel("for");
|
||||||
|
|
||||||
|
QWidget::connect(delay, SIGNAL(valueChanged(double)), this,
|
||||||
|
SLOT(DelayChanged(double)));
|
||||||
|
|
||||||
|
delay->setSuffix("s");
|
||||||
|
delay->setMaximum(999999999.9);
|
||||||
|
|
||||||
|
if (s) {
|
||||||
|
delay->setValue(s->delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
setStyleSheet("* { background-color: transparent; }");
|
||||||
|
|
||||||
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
|
||||||
|
mainLayout->addWidget(switchLabel);
|
||||||
|
mainLayout->addWidget(scenes);
|
||||||
|
mainLayout->addWidget(usingLabel);
|
||||||
|
mainLayout->addWidget(transitions);
|
||||||
|
mainLayout->addWidget(forLabel);
|
||||||
|
mainLayout->addWidget(delay);
|
||||||
|
mainLayout->addStretch();
|
||||||
|
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
switchData = s;
|
||||||
|
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RandomSwitch *RandomSwitchWidget::getSwitchData()
|
||||||
|
{
|
||||||
|
return switchData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RandomSwitchWidget::setSwitchData(RandomSwitch *s)
|
||||||
|
{
|
||||||
|
switchData = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RandomSwitchWidget::swapSwitchData(RandomSwitchWidget *s1,
|
||||||
|
RandomSwitchWidget *s2)
|
||||||
|
{
|
||||||
|
SwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
RandomSwitch *t = s1->getSwitchData();
|
||||||
|
s1->setSwitchData(s2->getSwitchData());
|
||||||
|
s2->setSwitchData(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RandomSwitchWidget::DelayChanged(double d)
|
||||||
|
{
|
||||||
|
if (loading || !switchData)
|
||||||
|
return;
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->delay = d;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,136 @@
|
|||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
|
static QMetaObject::Connection addPulse;
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::clearFrames(QListWidget *list)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < list->count(); ++i) {
|
||||||
|
ScreenRegionWidget *sw =
|
||||||
|
(ScreenRegionWidget *)list->itemWidget(list->item(i));
|
||||||
|
sw->hideFrame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void showCurrentFrame(QListWidget *list)
|
||||||
|
{
|
||||||
|
QListWidgetItem *item = list->currentItem();
|
||||||
|
|
||||||
|
if (!item)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ScreenRegionWidget *sw = (ScreenRegionWidget *)list->itemWidget(item);
|
||||||
|
sw->showFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::SetShowFrames()
|
||||||
|
{
|
||||||
|
ui->showFrame->setText("Show guide frames");
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::SetHideFrames()
|
||||||
|
{
|
||||||
|
ui->showFrame->setText("Hide guide frames");
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_showFrame_clicked()
|
||||||
|
{
|
||||||
|
switcher->showFrame = !switcher->showFrame;
|
||||||
|
|
||||||
|
if (switcher->showFrame) {
|
||||||
|
SetHideFrames();
|
||||||
|
showCurrentFrame(ui->screenRegionSwitches);
|
||||||
|
} else {
|
||||||
|
SetShowFrames();
|
||||||
|
clearFrames(ui->screenRegionSwitches);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_screenRegionSwitches_currentRowChanged(int idx)
|
||||||
|
{
|
||||||
|
if (loading || idx == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (switcher->showFrame) {
|
||||||
|
clearFrames(ui->screenRegionSwitches);
|
||||||
|
showCurrentFrame(ui->screenRegionSwitches);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_screenRegionAdd_clicked()
|
||||||
|
{
|
||||||
|
ui->screenRegionAdd->disconnect(addPulse);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switcher->screenRegionSwitches.emplace_back();
|
||||||
|
|
||||||
|
QListWidgetItem *item;
|
||||||
|
item = new QListWidgetItem(ui->screenRegionSwitches);
|
||||||
|
ui->screenRegionSwitches->addItem(item);
|
||||||
|
ScreenRegionWidget *sw =
|
||||||
|
new ScreenRegionWidget(&switcher->screenRegionSwitches.back());
|
||||||
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
|
ui->screenRegionSwitches->setItemWidget(item, sw);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_screenRegionRemove_clicked()
|
||||||
|
{
|
||||||
|
QListWidgetItem *item = ui->screenRegionSwitches->currentItem();
|
||||||
|
if (!item)
|
||||||
|
return;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
int idx = ui->screenRegionSwitches->currentRow();
|
||||||
|
auto &switches = switcher->screenRegionSwitches;
|
||||||
|
switches.erase(switches.begin() + idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete item;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_screenRegionUp_clicked()
|
||||||
|
{
|
||||||
|
int index = ui->screenRegionSwitches->currentRow();
|
||||||
|
if (!listMoveUp(ui->screenRegionSwitches))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ScreenRegionWidget *s1 =
|
||||||
|
(ScreenRegionWidget *)ui->screenRegionSwitches->itemWidget(
|
||||||
|
ui->screenRegionSwitches->item(index));
|
||||||
|
ScreenRegionWidget *s2 =
|
||||||
|
(ScreenRegionWidget *)ui->screenRegionSwitches->itemWidget(
|
||||||
|
ui->screenRegionSwitches->item(index - 1));
|
||||||
|
ScreenRegionWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
|
||||||
|
std::swap(switcher->screenRegionSwitches[index],
|
||||||
|
switcher->screenRegionSwitches[index - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_screenRegionDown_clicked()
|
||||||
|
{
|
||||||
|
int index = ui->screenRegionSwitches->currentRow();
|
||||||
|
|
||||||
|
if (!listMoveDown(ui->screenRegionSwitches))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ScreenRegionWidget *s1 =
|
||||||
|
(ScreenRegionWidget *)ui->screenRegionSwitches->itemWidget(
|
||||||
|
ui->screenRegionSwitches->item(index));
|
||||||
|
ScreenRegionWidget *s2 =
|
||||||
|
(ScreenRegionWidget *)ui->screenRegionSwitches->itemWidget(
|
||||||
|
ui->screenRegionSwitches->item(index + 1));
|
||||||
|
ScreenRegionWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
|
||||||
|
std::swap(switcher->screenRegionSwitches[index],
|
||||||
|
switcher->screenRegionSwitches[index + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
void SwitcherData::checkScreenRegionSwitch(bool &match, OBSWeakSource &scene,
|
void SwitcherData::checkScreenRegionSwitch(bool &match, OBSWeakSource &scene,
|
||||||
OBSWeakSource &transition)
|
OBSWeakSource &transition)
|
||||||
@@ -9,6 +139,9 @@ void SwitcherData::checkScreenRegionSwitch(bool &match, OBSWeakSource &scene,
|
|||||||
int minRegionSize = 99999;
|
int minRegionSize = 99999;
|
||||||
|
|
||||||
for (auto &s : screenRegionSwitches) {
|
for (auto &s : screenRegionSwitches) {
|
||||||
|
if (!s.initialized())
|
||||||
|
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);
|
||||||
@@ -26,170 +159,13 @@ void SwitcherData::checkScreenRegionSwitch(bool &match, OBSWeakSource &scene,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::updateScreenRegionCursorPos()
|
void AdvSceneSwitcher::updateScreenRegionCursorPos()
|
||||||
{
|
{
|
||||||
std::pair<int, int> position = getCursorPos();
|
std::pair<int, int> position = getCursorPos();
|
||||||
ui->cursorXPosition->setText(QString::number(position.first));
|
ui->cursorXPosition->setText(QString::number(position.first));
|
||||||
ui->cursorYPosition->setText(QString::number(position.second));
|
ui->cursorYPosition->setText(QString::number(position.second));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_screenRegionAdd_clicked()
|
|
||||||
{
|
|
||||||
QString sceneName = ui->screenRegionScenes->currentText();
|
|
||||||
QString transitionName = ui->screenRegionsTransitions->currentText();
|
|
||||||
|
|
||||||
if (sceneName.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
int minX = ui->screenRegionMinX->value();
|
|
||||||
int minY = ui->screenRegionMinY->value();
|
|
||||||
int maxX = ui->screenRegionMaxX->value();
|
|
||||||
int maxY = ui->screenRegionMaxY->value();
|
|
||||||
|
|
||||||
std::string regionStr =
|
|
||||||
std::to_string(minX) + ", " + std::to_string(minY) + " x " +
|
|
||||||
std::to_string(maxX) + ", " + std::to_string(maxY);
|
|
||||||
QString region = QString::fromStdString(regionStr);
|
|
||||||
|
|
||||||
OBSWeakSource source = GetWeakSourceByQString(sceneName);
|
|
||||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
|
||||||
QVariant v = QVariant::fromValue(region);
|
|
||||||
|
|
||||||
QString text = MakeScreenRegionSwitchName(sceneName, transitionName,
|
|
||||||
minX, minY, maxX, maxY);
|
|
||||||
|
|
||||||
int idx = ScreenRegionFindByData(region);
|
|
||||||
|
|
||||||
if (idx == -1) {
|
|
||||||
QListWidgetItem *item =
|
|
||||||
new QListWidgetItem(text, ui->screenRegions);
|
|
||||||
item->setData(Qt::UserRole, v);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
switcher->screenRegionSwitches.emplace_back(
|
|
||||||
source, transition, minX, minY, maxX, maxY, regionStr);
|
|
||||||
} else {
|
|
||||||
QListWidgetItem *item = ui->screenRegions->item(idx);
|
|
||||||
item->setText(text);
|
|
||||||
|
|
||||||
std::string curRegion = region.toUtf8().constData();
|
|
||||||
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
for (auto &s : switcher->screenRegionSwitches) {
|
|
||||||
if (s.regionStr == curRegion) {
|
|
||||||
s.scene = source;
|
|
||||||
s.transition = transition;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_screenRegionRemove_clicked()
|
|
||||||
{
|
|
||||||
QListWidgetItem *item = ui->screenRegions->currentItem();
|
|
||||||
if (!item)
|
|
||||||
return;
|
|
||||||
|
|
||||||
std::string region =
|
|
||||||
item->data(Qt::UserRole).toString().toUtf8().constData();
|
|
||||||
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
auto &switches = switcher->screenRegionSwitches;
|
|
||||||
|
|
||||||
for (auto it = switches.begin(); it != switches.end(); ++it) {
|
|
||||||
auto &s = *it;
|
|
||||||
|
|
||||||
if (s.regionStr == region) {
|
|
||||||
switches.erase(it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete item;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_screenRegions_currentRowChanged(int idx)
|
|
||||||
{
|
|
||||||
if (loading)
|
|
||||||
return;
|
|
||||||
if (idx == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QListWidgetItem *item = ui->screenRegions->item(idx);
|
|
||||||
|
|
||||||
QString region = item->data(Qt::UserRole).toString();
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
for (auto &s : switcher->screenRegionSwitches) {
|
|
||||||
if (region.compare(s.regionStr.c_str()) == 0) {
|
|
||||||
std::string name = GetWeakSourceName(s.scene);
|
|
||||||
std::string transitionName =
|
|
||||||
GetWeakSourceName(s.transition);
|
|
||||||
ui->screenRegionScenes->setCurrentText(name.c_str());
|
|
||||||
ui->screenRegionsTransitions->setCurrentText(
|
|
||||||
transitionName.c_str());
|
|
||||||
ui->screenRegionMinX->setValue(s.minX);
|
|
||||||
ui->screenRegionMinY->setValue(s.minY);
|
|
||||||
ui->screenRegionMaxX->setValue(s.maxX);
|
|
||||||
ui->screenRegionMaxY->setValue(s.maxY);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int SceneSwitcher::ScreenRegionFindByData(const QString ®ion)
|
|
||||||
{
|
|
||||||
int count = ui->screenRegions->count();
|
|
||||||
int idx = -1;
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
QListWidgetItem *item = ui->screenRegions->item(i);
|
|
||||||
QString itemRegion = item->data(Qt::UserRole).toString();
|
|
||||||
|
|
||||||
if (itemRegion == region) {
|
|
||||||
idx = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_screenRegionUp_clicked()
|
|
||||||
{
|
|
||||||
int index = ui->screenRegions->currentRow();
|
|
||||||
if (index != -1 && index != 0) {
|
|
||||||
ui->screenRegions->insertItem(
|
|
||||||
index - 1, ui->screenRegions->takeItem(index));
|
|
||||||
ui->screenRegions->setCurrentRow(index - 1);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
|
|
||||||
iter_swap(switcher->screenRegionSwitches.begin() + index,
|
|
||||||
switcher->screenRegionSwitches.begin() + index - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_screenRegionDown_clicked()
|
|
||||||
{
|
|
||||||
int index = ui->screenRegions->currentRow();
|
|
||||||
if (index != -1 && index != ui->screenRegions->count() - 1) {
|
|
||||||
ui->screenRegions->insertItem(
|
|
||||||
index + 1, ui->screenRegions->takeItem(index));
|
|
||||||
ui->screenRegions->setCurrentRow(index + 1);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
|
|
||||||
iter_swap(switcher->screenRegionSwitches.begin() + index,
|
|
||||||
switcher->screenRegionSwitches.begin() + index + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SwitcherData::saveScreenRegionSwitches(obs_data_t *obj)
|
void SwitcherData::saveScreenRegionSwitches(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
obs_data_array_t *screenRegionArray = obs_data_array_create();
|
obs_data_array_t *screenRegionArray = obs_data_array_create();
|
||||||
@@ -212,10 +188,9 @@ void SwitcherData::saveScreenRegionSwitches(obs_data_t *obj)
|
|||||||
obs_data_set_int(array_obj, "maxX", s.maxX);
|
obs_data_set_int(array_obj, "maxX", s.maxX);
|
||||||
obs_data_set_int(array_obj, "maxY", s.maxY);
|
obs_data_set_int(array_obj, "maxY", s.maxY);
|
||||||
obs_data_array_push_back(screenRegionArray, array_obj);
|
obs_data_array_push_back(screenRegionArray, array_obj);
|
||||||
obs_source_release(source);
|
|
||||||
obs_source_release(transition);
|
|
||||||
}
|
}
|
||||||
|
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);
|
||||||
@@ -243,39 +218,30 @@ void SwitcherData::loadScreenRegionSwitches(obs_data_t *obj)
|
|||||||
int maxX = obs_data_get_int(array_obj, "maxX");
|
int maxX = obs_data_get_int(array_obj, "maxX");
|
||||||
int maxY = obs_data_get_int(array_obj, "maxY");
|
int maxY = obs_data_get_int(array_obj, "maxY");
|
||||||
|
|
||||||
std::string regionStr =
|
|
||||||
MakeScreenRegionSwitchName(scene, transition, minX,
|
|
||||||
minY, maxX, maxY)
|
|
||||||
.toUtf8()
|
|
||||||
.constData();
|
|
||||||
|
|
||||||
switcher->screenRegionSwitches.emplace_back(
|
switcher->screenRegionSwitches.emplace_back(
|
||||||
GetWeakSourceByName(scene),
|
GetWeakSourceByName(scene),
|
||||||
GetWeakTransitionByName(transition), minX, minY, maxX,
|
GetWeakTransitionByName(transition), minX, minY, maxX,
|
||||||
maxY, regionStr);
|
maxY);
|
||||||
|
|
||||||
obs_data_release(array_obj);
|
obs_data_release(array_obj);
|
||||||
}
|
}
|
||||||
obs_data_array_release(screenRegionArray);
|
obs_data_array_release(screenRegionArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::setupRegionTab()
|
void AdvSceneSwitcher::setupRegionTab()
|
||||||
{
|
{
|
||||||
populateSceneSelection(ui->screenRegionScenes, false);
|
|
||||||
populateTransitionSelection(ui->screenRegionsTransitions);
|
|
||||||
|
|
||||||
for (auto &s : switcher->screenRegionSwitches) {
|
for (auto &s : switcher->screenRegionSwitches) {
|
||||||
std::string sceneName = GetWeakSourceName(s.scene);
|
QListWidgetItem *item;
|
||||||
std::string transitionName = GetWeakSourceName(s.transition);
|
item = new QListWidgetItem(ui->screenRegionSwitches);
|
||||||
QString text = MakeScreenRegionSwitchName(
|
ui->screenRegionSwitches->addItem(item);
|
||||||
sceneName.c_str(), transitionName.c_str(), s.minX,
|
ScreenRegionWidget *sw = new ScreenRegionWidget(&s);
|
||||||
s.minY, s.maxX, s.maxY);
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
|
ui->screenRegionSwitches->setItemWidget(item, sw);
|
||||||
QListWidgetItem *item =
|
|
||||||
new QListWidgetItem(text, ui->screenRegions);
|
|
||||||
item->setData(Qt::UserRole, s.regionStr.c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (switcher->screenRegionSwitches.size() == 0)
|
||||||
|
addPulse = PulseWidget(ui->screenRegionAdd, QColor(Qt::green));
|
||||||
|
|
||||||
// screen region cursor position
|
// screen region cursor position
|
||||||
QTimer *screenRegionTimer = new QTimer(this);
|
QTimer *screenRegionTimer = new QTimer(this);
|
||||||
connect(screenRegionTimer, SIGNAL(timeout()), this,
|
connect(screenRegionTimer, SIGNAL(timeout()), this,
|
||||||
@@ -283,14 +249,155 @@ void SceneSwitcher::setupRegionTab()
|
|||||||
screenRegionTimer->start(1000);
|
screenRegionTimer->start(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline QString MakeScreenRegionSwitchName(const QString &scene,
|
ScreenRegionWidget::ScreenRegionWidget(ScreenRegionSwitch *s)
|
||||||
const QString &transition,
|
: SwitchWidget(s, false)
|
||||||
int minX, int minY, int maxX,
|
|
||||||
int maxY)
|
|
||||||
{
|
{
|
||||||
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition +
|
minX = new QSpinBox();
|
||||||
QStringLiteral("]: ") + QString::number(minX) +
|
minY = new QSpinBox();
|
||||||
QStringLiteral(", ") + QString::number(minY) +
|
maxX = new QSpinBox();
|
||||||
QStringLiteral(" x ") + QString::number(maxX) +
|
maxY = new QSpinBox();
|
||||||
QStringLiteral(", ") + QString::number(maxY);
|
|
||||||
|
cursorLabel = new QLabel("If cursor is in");
|
||||||
|
xLabel = new QLabel("x");
|
||||||
|
switchLabel = new QLabel("switch to");
|
||||||
|
usingLabel = new QLabel("using");
|
||||||
|
|
||||||
|
minX->setPrefix("Min X: ");
|
||||||
|
minY->setPrefix("Min Y: ");
|
||||||
|
maxX->setPrefix("Max X: ");
|
||||||
|
maxY->setPrefix("Max Y: ");
|
||||||
|
|
||||||
|
minX->setMinimum(-1000000);
|
||||||
|
minY->setMinimum(-1000000);
|
||||||
|
maxX->setMinimum(-1000000);
|
||||||
|
maxY->setMinimum(-1000000);
|
||||||
|
|
||||||
|
minX->setMaximum(1000000);
|
||||||
|
minY->setMaximum(1000000);
|
||||||
|
maxX->setMaximum(1000000);
|
||||||
|
maxY->setMaximum(1000000);
|
||||||
|
|
||||||
|
QWidget::connect(minX, SIGNAL(valueChanged(int)), this,
|
||||||
|
SLOT(MinXChanged(int)));
|
||||||
|
QWidget::connect(minY, SIGNAL(valueChanged(int)), this,
|
||||||
|
SLOT(MinYChanged(int)));
|
||||||
|
QWidget::connect(maxX, SIGNAL(valueChanged(int)), this,
|
||||||
|
SLOT(MaxXChanged(int)));
|
||||||
|
QWidget::connect(maxY, SIGNAL(valueChanged(int)), this,
|
||||||
|
SLOT(MaxYChanged(int)));
|
||||||
|
|
||||||
|
if (s) {
|
||||||
|
minX->setValue(s->minX);
|
||||||
|
minY->setValue(s->minY);
|
||||||
|
maxX->setValue(s->maxX);
|
||||||
|
maxY->setValue(s->maxY);
|
||||||
|
}
|
||||||
|
|
||||||
|
setStyleSheet("* { background-color: transparent; }");
|
||||||
|
|
||||||
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
|
||||||
|
mainLayout->addWidget(cursorLabel);
|
||||||
|
mainLayout->addWidget(minX);
|
||||||
|
mainLayout->addWidget(minY);
|
||||||
|
mainLayout->addWidget(xLabel);
|
||||||
|
mainLayout->addWidget(maxX);
|
||||||
|
mainLayout->addWidget(maxY);
|
||||||
|
mainLayout->addWidget(switchLabel);
|
||||||
|
mainLayout->addWidget(scenes);
|
||||||
|
mainLayout->addWidget(usingLabel);
|
||||||
|
mainLayout->addWidget(transitions);
|
||||||
|
mainLayout->addStretch();
|
||||||
|
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
switchData = s;
|
||||||
|
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScreenRegionSwitch *ScreenRegionWidget::getSwitchData()
|
||||||
|
{
|
||||||
|
return switchData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenRegionWidget::setSwitchData(ScreenRegionSwitch *s)
|
||||||
|
{
|
||||||
|
switchData = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenRegionWidget::swapSwitchData(ScreenRegionWidget *s1,
|
||||||
|
ScreenRegionWidget *s2)
|
||||||
|
{
|
||||||
|
SwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
ScreenRegionSwitch *t = s1->getSwitchData();
|
||||||
|
s1->setSwitchData(s2->getSwitchData());
|
||||||
|
s2->setSwitchData(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenRegionWidget::showFrame()
|
||||||
|
{
|
||||||
|
drawFrame();
|
||||||
|
helperFrame.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenRegionWidget::hideFrame()
|
||||||
|
{
|
||||||
|
helperFrame.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenRegionWidget::MinXChanged(int pos)
|
||||||
|
{
|
||||||
|
if (loading || !switchData)
|
||||||
|
return;
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->minX = pos;
|
||||||
|
|
||||||
|
drawFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenRegionWidget::MinYChanged(int pos)
|
||||||
|
{
|
||||||
|
if (loading || !switchData)
|
||||||
|
return;
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->minY = pos;
|
||||||
|
|
||||||
|
drawFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenRegionWidget::MaxXChanged(int pos)
|
||||||
|
{
|
||||||
|
if (loading || !switchData)
|
||||||
|
return;
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->maxX = pos;
|
||||||
|
|
||||||
|
drawFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenRegionWidget::MaxYChanged(int pos)
|
||||||
|
{
|
||||||
|
if (loading || !switchData)
|
||||||
|
return;
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->maxY = pos;
|
||||||
|
|
||||||
|
drawFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenRegionWidget::drawFrame()
|
||||||
|
{
|
||||||
|
helperFrame.setFrameStyle(QFrame::Box | QFrame::Plain);
|
||||||
|
helperFrame.setWindowFlags(Qt::FramelessWindowHint | Qt::Tool |
|
||||||
|
Qt::WindowTransparentForInput |
|
||||||
|
Qt::WindowDoesNotAcceptFocus |
|
||||||
|
Qt::WindowStaysOnTopHint);
|
||||||
|
helperFrame.setAttribute(Qt::WA_TranslucentBackground, true);
|
||||||
|
|
||||||
|
if (switchData)
|
||||||
|
helperFrame.setGeometry(switchData->minX, switchData->minY,
|
||||||
|
switchData->maxX - switchData->minX,
|
||||||
|
switchData->maxY - switchData->minY);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,132 +3,93 @@
|
|||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
constexpr auto seconds_index = 0;
|
static QMetaObject::Connection addPulse;
|
||||||
constexpr auto minutes_index = 1;
|
|
||||||
constexpr auto hours_index = 2;
|
|
||||||
|
|
||||||
void SceneSwitcher::on_sceneSequenceDelayUnits_currentIndexChanged(int index)
|
void AdvSceneSwitcher::on_sceneSequenceAdd_clicked()
|
||||||
{
|
{
|
||||||
if (loading)
|
ui->sceneSequenceAdd->disconnect(addPulse);
|
||||||
return;
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switcher->sceneSequenceSwitches.emplace_back();
|
||||||
|
|
||||||
double val = ui->sceneSequenceSpinBox->value();
|
QListWidgetItem *item;
|
||||||
|
item = new QListWidgetItem(ui->sceneSequenceSwitches);
|
||||||
switch (switcher->sceneSequenceMultiplier) {
|
ui->sceneSequenceSwitches->addItem(item);
|
||||||
case 1:
|
SequenceWidget *sw =
|
||||||
val /= pow(60, index);
|
new SequenceWidget(&switcher->sceneSequenceSwitches.back());
|
||||||
break;
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
case 60:
|
ui->sceneSequenceSwitches->setItemWidget(item, sw);
|
||||||
val /= pow(60, index - 1);
|
|
||||||
break;
|
|
||||||
case 3600:
|
|
||||||
val /= pow(60, index - 2);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ui->sceneSequenceSpinBox->setValue(val);
|
|
||||||
|
|
||||||
switch (index) {
|
|
||||||
case seconds_index:
|
|
||||||
switcher->sceneSequenceMultiplier = 1;
|
|
||||||
break;
|
|
||||||
case minutes_index:
|
|
||||||
switcher->sceneSequenceMultiplier = 60;
|
|
||||||
break;
|
|
||||||
case hours_index:
|
|
||||||
switcher->sceneSequenceMultiplier = 3600;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_sceneSequenceAdd_clicked()
|
void AdvSceneSwitcher::on_sceneSequenceRemove_clicked()
|
||||||
{
|
{
|
||||||
QString scene1Name = ui->sceneSequenceScenes1->currentText();
|
QListWidgetItem *item = ui->sceneSequenceSwitches->currentItem();
|
||||||
QString scene2Name = ui->sceneSequenceScenes2->currentText();
|
|
||||||
QString transitionName = ui->sceneSequenceTransitions->currentText();
|
|
||||||
|
|
||||||
if (scene1Name.isEmpty() || scene2Name.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
double delay = ui->sceneSequenceSpinBox->value() *
|
|
||||||
switcher->sceneSequenceMultiplier;
|
|
||||||
|
|
||||||
if (scene1Name == scene2Name)
|
|
||||||
return;
|
|
||||||
|
|
||||||
OBSWeakSource source1 = GetWeakSourceByQString(scene1Name);
|
|
||||||
OBSWeakSource source2 = GetWeakSourceByQString(scene2Name);
|
|
||||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
|
||||||
|
|
||||||
QString text = MakeSceneSequenceSwitchName(scene1Name, scene2Name,
|
|
||||||
transitionName, delay);
|
|
||||||
QVariant v = QVariant::fromValue(text);
|
|
||||||
|
|
||||||
int idx = SceneSequenceFindByData(scene1Name);
|
|
||||||
|
|
||||||
if (idx == -1) {
|
|
||||||
QListWidgetItem *item =
|
|
||||||
new QListWidgetItem(text, ui->sceneSequences);
|
|
||||||
item->setData(Qt::UserRole, v);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
switcher->sceneSequenceSwitches.emplace_back(
|
|
||||||
source1, source2, transition, delay,
|
|
||||||
(scene2Name == QString(previous_scene_name)),
|
|
||||||
text.toUtf8().constData());
|
|
||||||
} else {
|
|
||||||
QListWidgetItem *item = ui->sceneSequences->item(idx);
|
|
||||||
item->setText(text);
|
|
||||||
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
for (auto &s : switcher->sceneSequenceSwitches) {
|
|
||||||
if (s.startScene == source1) {
|
|
||||||
s.scene = source2;
|
|
||||||
s.delay = delay;
|
|
||||||
s.transition = transition;
|
|
||||||
s.usePreviousScene =
|
|
||||||
(scene2Name ==
|
|
||||||
QString(previous_scene_name));
|
|
||||||
s.sceneSequenceStr =
|
|
||||||
text.toUtf8().constData();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_sceneSequenceRemove_clicked()
|
|
||||||
{
|
|
||||||
QListWidgetItem *item = ui->sceneSequences->currentItem();
|
|
||||||
if (!item)
|
if (!item)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::string text =
|
|
||||||
item->data(Qt::UserRole).toString().toUtf8().constData();
|
|
||||||
|
|
||||||
{
|
{
|
||||||
|
// 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();
|
||||||
auto &switches = switcher->sceneSequenceSwitches;
|
auto &switches = switcher->sceneSequenceSwitches;
|
||||||
|
switches.erase(switches.begin() + idx);
|
||||||
|
|
||||||
for (auto it = switches.begin(); it != switches.end(); ++it) {
|
if (wasRunning)
|
||||||
auto &s = *it;
|
switcher->Start();
|
||||||
|
|
||||||
if (s.sceneSequenceStr == text) {
|
|
||||||
switches.erase(it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete item;
|
delete item;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_sceneSequenceSave_clicked()
|
void AdvSceneSwitcher::on_sceneSequenceUp_clicked()
|
||||||
|
{
|
||||||
|
int index = ui->sceneSequenceSwitches->currentRow();
|
||||||
|
if (!listMoveUp(ui->sceneSequenceSwitches))
|
||||||
|
return;
|
||||||
|
|
||||||
|
SequenceWidget *s1 =
|
||||||
|
(SequenceWidget *)ui->sceneSequenceSwitches->itemWidget(
|
||||||
|
ui->sceneSequenceSwitches->item(index));
|
||||||
|
SequenceWidget *s2 =
|
||||||
|
(SequenceWidget *)ui->sceneSequenceSwitches->itemWidget(
|
||||||
|
ui->sceneSequenceSwitches->item(index - 1));
|
||||||
|
SequenceWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
|
||||||
|
std::swap(switcher->sceneSequenceSwitches[index],
|
||||||
|
switcher->sceneSequenceSwitches[index - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_sceneSequenceDown_clicked()
|
||||||
|
{
|
||||||
|
int index = ui->sceneSequenceSwitches->currentRow();
|
||||||
|
|
||||||
|
if (!listMoveDown(ui->sceneSequenceSwitches))
|
||||||
|
return;
|
||||||
|
|
||||||
|
SequenceWidget *s1 =
|
||||||
|
(SequenceWidget *)ui->sceneSequenceSwitches->itemWidget(
|
||||||
|
ui->sceneSequenceSwitches->item(index));
|
||||||
|
SequenceWidget *s2 =
|
||||||
|
(SequenceWidget *)ui->sceneSequenceSwitches->itemWidget(
|
||||||
|
ui->sceneSequenceSwitches->item(index + 1));
|
||||||
|
SequenceWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
|
||||||
|
std::swap(switcher->sceneSequenceSwitches[index],
|
||||||
|
switcher->sceneSequenceSwitches[index + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_sceneSequenceSave_clicked()
|
||||||
{
|
{
|
||||||
QString directory = QFileDialog::getSaveFileName(
|
QString directory = QFileDialog::getSaveFileName(
|
||||||
this, tr("Save Scene Sequence to file ..."),
|
this, tr("Save Scene Sequence to file ..."),
|
||||||
@@ -145,54 +106,8 @@ void SceneSwitcher::on_sceneSequenceSave_clicked()
|
|||||||
obs_data_release(obj);
|
obs_data_release(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
// to be removed once support for old file format is dropped
|
void AdvSceneSwitcher::on_sceneSequenceLoad_clicked()
|
||||||
bool oldSceneRoundTripLoad(QFile *file)
|
|
||||||
{
|
{
|
||||||
QTextStream in(file);
|
|
||||||
std::vector<QString> lines;
|
|
||||||
|
|
||||||
std::vector<SceneSequenceSwitch> newSceneRoundTripSwitch;
|
|
||||||
|
|
||||||
while (!in.atEnd()) {
|
|
||||||
QString line = in.readLine();
|
|
||||||
lines.push_back(line);
|
|
||||||
if (lines.size() == 5) {
|
|
||||||
OBSWeakSource scene1 = GetWeakSourceByQString(lines[0]);
|
|
||||||
OBSWeakSource scene2 = GetWeakSourceByQString(lines[1]);
|
|
||||||
OBSWeakSource transition =
|
|
||||||
GetWeakTransitionByQString(lines[4]);
|
|
||||||
|
|
||||||
if (WeakSourceValid(scene1) &&
|
|
||||||
((lines[1] == QString(previous_scene_name)) ||
|
|
||||||
(WeakSourceValid(scene2))) &&
|
|
||||||
WeakSourceValid(transition)) {
|
|
||||||
newSceneRoundTripSwitch.emplace_back(
|
|
||||||
SceneSequenceSwitch(
|
|
||||||
GetWeakSourceByQString(lines[0]),
|
|
||||||
GetWeakSourceByQString(lines[1]),
|
|
||||||
GetWeakTransitionByQString(
|
|
||||||
lines[4]),
|
|
||||||
lines[2].toDouble() / 1000.,
|
|
||||||
(lines[1] ==
|
|
||||||
QString(previous_scene_name)),
|
|
||||||
lines[3].toStdString()));
|
|
||||||
}
|
|
||||||
lines.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lines.size() != 0 || newSceneRoundTripSwitch.size() == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
switcher->sceneSequenceSwitches.clear();
|
|
||||||
switcher->sceneSequenceSwitches = newSceneRoundTripSwitch;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::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, tr("Select a file to read Scene Sequence from ..."),
|
||||||
QDir::currentPath(), tr("Text files (*.txt)"));
|
QDir::currentPath(), tr("Text files (*.txt)"));
|
||||||
@@ -208,26 +123,23 @@ void SceneSwitcher::on_sceneSequenceLoad_clicked()
|
|||||||
|
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
QMessageBox Msgbox;
|
QMessageBox Msgbox;
|
||||||
QString txt =
|
Msgbox.setText(
|
||||||
"Advanced Scene Switcher failed to import settings!\n";
|
"Advanced Scene Switcher failed to import settings!");
|
||||||
txt += "Falling back to old format.";
|
|
||||||
Msgbox.setText(txt);
|
|
||||||
Msgbox.exec();
|
Msgbox.exec();
|
||||||
if (oldSceneRoundTripLoad(&file)) {
|
|
||||||
QString txt =
|
|
||||||
"Advanced Scene Switcher settings imported successfully!\n";
|
|
||||||
txt += "Please resave settings as support for old format will be dropped in next version.";
|
|
||||||
Msgbox.setText(txt);
|
|
||||||
Msgbox.exec();
|
|
||||||
close();
|
|
||||||
} else {
|
|
||||||
Msgbox.setText(
|
|
||||||
"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;
|
QMessageBox Msgbox;
|
||||||
@@ -238,13 +150,16 @@ void SceneSwitcher::on_sceneSequenceLoad_clicked()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SwitcherData::checkSceneSequence(bool &match, OBSWeakSource &scene,
|
void SwitcherData::checkSceneSequence(bool &match, OBSWeakSource &scene,
|
||||||
OBSWeakSource &transition,
|
OBSWeakSource &transition,
|
||||||
std::unique_lock<std::mutex> &lock)
|
std::unique_lock<std::mutex> &lock)
|
||||||
{
|
{
|
||||||
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())
|
||||||
|
continue;
|
||||||
|
|
||||||
if (s.startScene == ws) {
|
if (s.startScene == ws) {
|
||||||
int dur = s.delay * 1000 - interval;
|
int dur = s.delay * 1000 - interval;
|
||||||
if (dur > 0) {
|
if (dur > 0) {
|
||||||
@@ -268,7 +183,10 @@ void SwitcherData::checkSceneSequence(bool &match, OBSWeakSource &scene,
|
|||||||
transition = s.transition;
|
transition = s.transition;
|
||||||
if (verbose)
|
if (verbose)
|
||||||
s.logMatch();
|
s.logMatch();
|
||||||
|
} else if (verbose) {
|
||||||
|
blog(LOG_INFO, "sequence canceled");
|
||||||
}
|
}
|
||||||
|
|
||||||
obs_source_release(currentSource2);
|
obs_source_release(currentSource2);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -277,87 +195,6 @@ void SwitcherData::checkSceneSequence(bool &match, OBSWeakSource &scene,
|
|||||||
obs_weak_source_release(ws);
|
obs_weak_source_release(ws);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_sceneSequences_currentRowChanged(int idx)
|
|
||||||
{
|
|
||||||
if (loading)
|
|
||||||
return;
|
|
||||||
if (idx == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QListWidgetItem *item = ui->sceneSequences->item(idx);
|
|
||||||
|
|
||||||
QString sceneSequence = item->text();
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
for (auto &s : switcher->sceneSequenceSwitches) {
|
|
||||||
if (sceneSequence.compare(s.sceneSequenceStr.c_str()) == 0) {
|
|
||||||
std::string scene1 = GetWeakSourceName(s.startScene);
|
|
||||||
std::string scene2 = GetWeakSourceName(s.scene);
|
|
||||||
std::string transitionName =
|
|
||||||
GetWeakSourceName(s.transition);
|
|
||||||
double delay = s.delay /
|
|
||||||
switcher->sceneSequenceMultiplier;
|
|
||||||
ui->sceneSequenceScenes1->setCurrentText(
|
|
||||||
scene1.c_str());
|
|
||||||
ui->sceneSequenceScenes2->setCurrentText(
|
|
||||||
scene2.c_str());
|
|
||||||
ui->sceneSequenceTransitions->setCurrentText(
|
|
||||||
transitionName.c_str());
|
|
||||||
ui->sceneSequenceSpinBox->setValue(delay);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int SceneSwitcher::SceneSequenceFindByData(const QString &scene1)
|
|
||||||
{
|
|
||||||
QRegExp rx(scene1 + " ->.*");
|
|
||||||
int count = ui->sceneSequences->count();
|
|
||||||
int idx = -1;
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
QListWidgetItem *item = ui->sceneSequences->item(i);
|
|
||||||
QString itemString = item->data(Qt::UserRole).toString();
|
|
||||||
|
|
||||||
if (rx.exactMatch(itemString)) {
|
|
||||||
idx = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_sceneSequenceUp_clicked()
|
|
||||||
{
|
|
||||||
int index = ui->sceneSequences->currentRow();
|
|
||||||
if (index != -1 && index != 0) {
|
|
||||||
ui->sceneSequences->insertItem(
|
|
||||||
index - 1, ui->sceneSequences->takeItem(index));
|
|
||||||
ui->sceneSequences->setCurrentRow(index - 1);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
|
|
||||||
iter_swap(switcher->sceneSequenceSwitches.begin() + index,
|
|
||||||
switcher->sceneSequenceSwitches.begin() + index - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_sceneSequenceDown_clicked()
|
|
||||||
{
|
|
||||||
int index = ui->sceneSequences->currentRow();
|
|
||||||
if (index != -1 && index != ui->sceneSequences->count() - 1) {
|
|
||||||
ui->sceneSequences->insertItem(
|
|
||||||
index + 1, ui->sceneSequences->takeItem(index));
|
|
||||||
ui->sceneSequences->setCurrentRow(index + 1);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
|
|
||||||
iter_swap(switcher->sceneSequenceSwitches.begin() + index,
|
|
||||||
switcher->sceneSequenceSwitches.begin() + index + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SwitcherData::saveSceneSequenceSwitches(obs_data_t *obj)
|
void SwitcherData::saveSceneSequenceSwitches(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
obs_data_array_t *sceneSequenceArray = obs_data_array_create();
|
obs_data_array_t *sceneSequenceArray = obs_data_array_create();
|
||||||
@@ -383,13 +220,14 @@ void SwitcherData::saveSceneSequenceSwitches(obs_data_t *obj)
|
|||||||
obs_data_set_string(array_obj, "transition",
|
obs_data_set_string(array_obj, "transition",
|
||||||
transitionName);
|
transitionName);
|
||||||
obs_data_set_double(array_obj, "delay", s.delay);
|
obs_data_set_double(array_obj, "delay", s.delay);
|
||||||
obs_data_array_push_back(sceneSequenceArray,
|
obs_data_set_int(array_obj, "delayMultiplier",
|
||||||
array_obj);
|
s.delayMultiplier);
|
||||||
obs_source_release(source1);
|
obs_data_array_push_back(sceneSequenceArray, array_obj);
|
||||||
obs_source_release(source2);
|
|
||||||
obs_source_release(transition);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
@@ -414,94 +252,189 @@ void SwitcherData::loadSceneSequenceSwitches(obs_data_t *obj)
|
|||||||
obs_data_get_string(array_obj, "sceneRoundTripScene2");
|
obs_data_get_string(array_obj, "sceneRoundTripScene2");
|
||||||
const char *transition =
|
const char *transition =
|
||||||
obs_data_get_string(array_obj, "transition");
|
obs_data_get_string(array_obj, "transition");
|
||||||
|
double delay = obs_data_get_double(array_obj, "delay");
|
||||||
double delay = 0;
|
int delayMultiplier =
|
||||||
|
obs_data_get_int(array_obj, "delayMultiplier");
|
||||||
// To be removed in future version
|
if (delayMultiplier == 0 ||
|
||||||
// to be compatible with older versions
|
(delayMultiplier != 1 && delayMultiplier % 60 != 0))
|
||||||
if (!obs_data_has_user_value(array_obj, "delay")) {
|
delayMultiplier = 1;
|
||||||
delay = double(obs_data_get_int(array_obj,
|
|
||||||
"sceneRoundTripDelay"));
|
|
||||||
delay = delay * 1000. +
|
|
||||||
double(obs_data_get_int(
|
|
||||||
array_obj, "sceneRoundTripDelayMs"));
|
|
||||||
delay /= 1000.;
|
|
||||||
} else {
|
|
||||||
delay = obs_data_get_double(array_obj, "delay");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string str = MakeSceneSequenceSwitchName(
|
|
||||||
scene1, scene2, transition, delay)
|
|
||||||
.toUtf8()
|
|
||||||
.constData();
|
|
||||||
const char *sceneSequenceStr = str.c_str();
|
|
||||||
|
|
||||||
switcher->sceneSequenceSwitches.emplace_back(
|
switcher->sceneSequenceSwitches.emplace_back(
|
||||||
GetWeakSourceByName(scene1),
|
GetWeakSourceByName(scene1),
|
||||||
GetWeakSourceByName(scene2),
|
GetWeakSourceByName(scene2),
|
||||||
GetWeakTransitionByName(transition), delay,
|
GetWeakTransitionByName(transition), delay,
|
||||||
(strcmp(scene2, previous_scene_name) == 0),
|
delayMultiplier,
|
||||||
sceneSequenceStr);
|
(strcmp(scene2, previous_scene_name) == 0));
|
||||||
|
|
||||||
obs_data_release(array_obj);
|
obs_data_release(array_obj);
|
||||||
}
|
}
|
||||||
obs_data_array_release(sceneSequenceArray);
|
obs_data_array_release(sceneSequenceArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::setupSequenceTab()
|
void AdvSceneSwitcher::setupSequenceTab()
|
||||||
{
|
{
|
||||||
populateSceneSelection(ui->sceneSequenceScenes1, false);
|
|
||||||
populateSceneSelection(ui->sceneSequenceScenes2, true);
|
|
||||||
populateTransitionSelection(ui->sceneSequenceTransitions);
|
|
||||||
|
|
||||||
double smallestDelay = double(switcher->interval) / 1000;
|
|
||||||
for (auto &s : switcher->sceneSequenceSwitches) {
|
for (auto &s : switcher->sceneSequenceSwitches) {
|
||||||
std::string sceneName1 = GetWeakSourceName(s.startScene);
|
QListWidgetItem *item;
|
||||||
std::string sceneName2 = (s.usePreviousScene)
|
item = new QListWidgetItem(ui->sceneSequenceSwitches);
|
||||||
? previous_scene_name
|
ui->sceneSequenceSwitches->addItem(item);
|
||||||
: GetWeakSourceName(s.scene);
|
SequenceWidget *sw = new SequenceWidget(&s);
|
||||||
std::string transitionName = GetWeakSourceName(s.transition);
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
QString text = MakeSceneSequenceSwitchName(
|
ui->sceneSequenceSwitches->setItemWidget(item, sw);
|
||||||
sceneName1.c_str(), sceneName2.c_str(),
|
|
||||||
transitionName.c_str(), s.delay);
|
|
||||||
|
|
||||||
QListWidgetItem *item =
|
|
||||||
new QListWidgetItem(text, ui->sceneSequences);
|
|
||||||
item->setData(Qt::UserRole, text);
|
|
||||||
|
|
||||||
if (s.delay < smallestDelay)
|
|
||||||
smallestDelay = s.delay;
|
|
||||||
}
|
}
|
||||||
(smallestDelay * 1000 < switcher->interval)
|
|
||||||
? ui->intervalWarning->setVisible(true)
|
|
||||||
: ui->intervalWarning->setVisible(false);
|
|
||||||
|
|
||||||
ui->sceneSequenceDelayUnits->addItem("seconds");
|
if (switcher->sceneSequenceSwitches.size() == 0)
|
||||||
ui->sceneSequenceDelayUnits->addItem("minutes");
|
addPulse = PulseWidget(ui->sceneSequenceAdd, QColor(Qt::green));
|
||||||
ui->sceneSequenceDelayUnits->addItem("hours");
|
}
|
||||||
|
|
||||||
switch (switcher->sceneSequenceMultiplier) {
|
bool SceneSequenceSwitch::initialized()
|
||||||
case 1:
|
{
|
||||||
ui->sceneSequenceDelayUnits->setCurrentIndex(0);
|
return SceneSwitcherEntry::initialized() && startScene;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SceneSequenceSwitch::valid()
|
||||||
|
{
|
||||||
|
return !initialized() ||
|
||||||
|
(SceneSwitcherEntry::valid() && WeakSourceValid(startScene));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneSequenceSwitch::logSleep(int dur)
|
||||||
|
{
|
||||||
|
blog(LOG_INFO, "sequence sleep %d", dur);
|
||||||
|
}
|
||||||
|
|
||||||
|
void populateDelayUnits(QComboBox *list)
|
||||||
|
{
|
||||||
|
list->addItem("seconds");
|
||||||
|
list->addItem("minutes");
|
||||||
|
list->addItem("hours");
|
||||||
|
}
|
||||||
|
|
||||||
|
SequenceWidget::SequenceWidget(SceneSequenceSwitch *s) : SwitchWidget(s)
|
||||||
|
{
|
||||||
|
delay = new QDoubleSpinBox();
|
||||||
|
delayUnits = new QComboBox();
|
||||||
|
startScenes = new QComboBox();
|
||||||
|
|
||||||
|
whenLabel = new QLabel("When");
|
||||||
|
switchLabel = new QLabel("is active switch to");
|
||||||
|
afterLabel = new QLabel("after");
|
||||||
|
usingLabel = new QLabel("using");
|
||||||
|
|
||||||
|
QWidget::connect(delay, SIGNAL(valueChanged(double)), this,
|
||||||
|
SLOT(DelayChanged(double)));
|
||||||
|
QWidget::connect(delayUnits, SIGNAL(currentIndexChanged(int)), this,
|
||||||
|
SLOT(DelayUnitsChanged(int)));
|
||||||
|
QWidget::connect(startScenes,
|
||||||
|
SIGNAL(currentTextChanged(const QString &)), this,
|
||||||
|
SLOT(StartSceneChanged(const QString &)));
|
||||||
|
|
||||||
|
delay->setMaximum(99999.000000);
|
||||||
|
AdvSceneSwitcher::populateSceneSelection(startScenes, false);
|
||||||
|
populateDelayUnits(delayUnits);
|
||||||
|
|
||||||
|
if (s) {
|
||||||
|
switch (s->delayMultiplier) {
|
||||||
|
case 1:
|
||||||
|
delayUnits->setCurrentIndex(0);
|
||||||
|
break;
|
||||||
|
case 60:
|
||||||
|
delayUnits->setCurrentIndex(1);
|
||||||
|
break;
|
||||||
|
case 3600:
|
||||||
|
delayUnits->setCurrentIndex(2);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
delayUnits->setCurrentIndex(0);
|
||||||
|
}
|
||||||
|
startScenes->setCurrentText(
|
||||||
|
GetWeakSourceName(s->startScene).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
setStyleSheet("* { background-color: transparent; }");
|
||||||
|
|
||||||
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
|
||||||
|
mainLayout->addWidget(whenLabel);
|
||||||
|
mainLayout->addWidget(startScenes);
|
||||||
|
mainLayout->addWidget(switchLabel);
|
||||||
|
mainLayout->addWidget(scenes);
|
||||||
|
mainLayout->addWidget(afterLabel);
|
||||||
|
mainLayout->addWidget(delay);
|
||||||
|
mainLayout->addWidget(delayUnits);
|
||||||
|
mainLayout->addWidget(usingLabel);
|
||||||
|
mainLayout->addWidget(transitions);
|
||||||
|
mainLayout->addStretch();
|
||||||
|
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
switchData = s;
|
||||||
|
|
||||||
|
loading = false;
|
||||||
|
|
||||||
|
UpdateDelay();
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneSequenceSwitch *SequenceWidget::getSwitchData()
|
||||||
|
{
|
||||||
|
return switchData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SequenceWidget::setSwitchData(SceneSequenceSwitch *s)
|
||||||
|
{
|
||||||
|
switchData = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SequenceWidget::swapSwitchData(SequenceWidget *s1, SequenceWidget *s2)
|
||||||
|
{
|
||||||
|
SwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
SceneSequenceSwitch *t = s1->getSwitchData();
|
||||||
|
s1->setSwitchData(s2->getSwitchData());
|
||||||
|
s2->setSwitchData(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SequenceWidget::UpdateDelay()
|
||||||
|
{
|
||||||
|
if (switchData)
|
||||||
|
delay->setValue(switchData->delay /
|
||||||
|
switchData->delayMultiplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SequenceWidget::DelayChanged(double delay)
|
||||||
|
{
|
||||||
|
if (loading || !switchData)
|
||||||
|
return;
|
||||||
|
switchData->delay = delay * switchData->delayMultiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SequenceWidget::DelayUnitsChanged(int idx)
|
||||||
|
{
|
||||||
|
if (loading || !switchData)
|
||||||
|
return;
|
||||||
|
|
||||||
|
delay_units unit = (delay_units)idx;
|
||||||
|
|
||||||
|
switch (unit) {
|
||||||
|
case SECONDS:
|
||||||
|
switchData->delayMultiplier = 1;
|
||||||
break;
|
break;
|
||||||
case 60:
|
case MINUTES:
|
||||||
ui->sceneSequenceDelayUnits->setCurrentIndex(1);
|
switchData->delayMultiplier = 60;
|
||||||
break;
|
break;
|
||||||
case 3600:
|
case HOURS:
|
||||||
ui->sceneSequenceDelayUnits->setCurrentIndex(2);
|
switchData->delayMultiplier = 60 * 60;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateDelay();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline QString MakeSceneSequenceSwitchName(const QString &scene1,
|
void SequenceWidget::StartSceneChanged(const QString &text)
|
||||||
const QString &scene2,
|
|
||||||
const QString &transition,
|
|
||||||
double delay)
|
|
||||||
{
|
{
|
||||||
return scene1 + QStringLiteral(" -> wait for ") +
|
if (loading || !switchData)
|
||||||
QString::number(delay) + QStringLiteral(" seconds -> ") +
|
return;
|
||||||
scene2 + QStringLiteral(" (using ") + transition +
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
QStringLiteral(" transition)");
|
switchData->startScene = GetWeakSourceByQString(text);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,173 +1,75 @@
|
|||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
static std::vector<std::pair<std::string, timeTrigger>> triggerTable = {
|
static QMetaObject::Connection addPulse;
|
||||||
{"On any day", timeTrigger::ANY_DAY},
|
|
||||||
{"Mondays", timeTrigger::MONDAY},
|
|
||||||
{"Tuesdays", timeTrigger::TUSEDAY},
|
|
||||||
{"Wednesdays", timeTrigger::WEDNESDAY},
|
|
||||||
{"Thursdays", timeTrigger::THURSDAY},
|
|
||||||
{"Fridays", timeTrigger::FRIDAY},
|
|
||||||
{"Saturdays", timeTrigger::SATURDAY},
|
|
||||||
{"Sundays", timeTrigger::SUNDAY},
|
|
||||||
{"Atfer streaming/recording start", timeTrigger::LIVE}};
|
|
||||||
|
|
||||||
void SceneSwitcher::on_timeSwitches_currentRowChanged(int idx)
|
void AdvSceneSwitcher::on_timeAdd_clicked()
|
||||||
{
|
{
|
||||||
if (loading)
|
ui->timeAdd->disconnect(addPulse);
|
||||||
return;
|
|
||||||
if (idx == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QListWidgetItem *item = ui->timeSwitches->item(idx);
|
|
||||||
|
|
||||||
QString timeScenestr = 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->timeSwitches) {
|
switcher->timeSwitches.emplace_back();
|
||||||
if (timeScenestr.compare(s.timeSwitchStr.c_str()) == 0) {
|
|
||||||
QString sceneName = GetWeakSourceName(s.scene).c_str();
|
QListWidgetItem *item;
|
||||||
QString transitionName =
|
item = new QListWidgetItem(ui->timeSwitches);
|
||||||
GetWeakSourceName(s.transition).c_str();
|
ui->timeSwitches->addItem(item);
|
||||||
ui->timeScenes->setCurrentText(sceneName);
|
TimeSwitchWidget *sw =
|
||||||
ui->timeTrigger->setCurrentIndex(s.trigger);
|
new TimeSwitchWidget(&switcher->timeSwitches.back());
|
||||||
ui->timeEdit->setTime(s.time);
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
ui->timeTransitions->setCurrentText(transitionName);
|
ui->timeSwitches->setItemWidget(item, sw);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int SceneSwitcher::timeFindByData(const timeTrigger &trigger, const QTime &time)
|
void AdvSceneSwitcher::on_timeRemove_clicked()
|
||||||
{
|
|
||||||
QRegExp rx(MakeTimeSwitchName(QStringLiteral(".*"),
|
|
||||||
QStringLiteral(".*"), trigger, time));
|
|
||||||
int count = ui->timeSwitches->count();
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
QListWidgetItem *item = ui->timeSwitches->item(i);
|
|
||||||
QString str = item->data(Qt::UserRole).toString();
|
|
||||||
|
|
||||||
if (rx.exactMatch(str))
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_timeAdd_clicked()
|
|
||||||
{
|
|
||||||
QString sceneName = ui->timeScenes->currentText();
|
|
||||||
QString transitionName = ui->timeTransitions->currentText();
|
|
||||||
QTime time = ui->timeEdit->time();
|
|
||||||
|
|
||||||
if (sceneName.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
OBSWeakSource source = GetWeakSourceByQString(sceneName);
|
|
||||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
|
||||||
|
|
||||||
std::string triggerStr = ui->timeTrigger->currentText().toStdString();
|
|
||||||
auto it = std::find_if(
|
|
||||||
triggerTable.begin(), triggerTable.end(),
|
|
||||||
[&triggerStr](
|
|
||||||
const std::pair<std::string, timeTrigger> &element) {
|
|
||||||
return element.first == triggerStr;
|
|
||||||
});
|
|
||||||
timeTrigger trigger = it->second;
|
|
||||||
|
|
||||||
QString text =
|
|
||||||
MakeTimeSwitchName(sceneName, transitionName, trigger, time);
|
|
||||||
QVariant v = QVariant::fromValue(text);
|
|
||||||
|
|
||||||
int idx = timeFindByData(trigger, time);
|
|
||||||
|
|
||||||
if (idx == -1) {
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
switcher->timeSwitches.emplace_back(
|
|
||||||
source, transition, trigger, time,
|
|
||||||
(sceneName == QString(previous_scene_name)),
|
|
||||||
text.toUtf8().constData());
|
|
||||||
|
|
||||||
QListWidgetItem *item =
|
|
||||||
new QListWidgetItem(text, ui->timeSwitches);
|
|
||||||
item->setData(Qt::UserRole, v);
|
|
||||||
} else {
|
|
||||||
QListWidgetItem *item = ui->timeSwitches->item(idx);
|
|
||||||
item->setText(text);
|
|
||||||
item->setData(Qt::UserRole, v);
|
|
||||||
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
for (auto &s : switcher->timeSwitches) {
|
|
||||||
if (s.trigger == trigger && s.time == time) {
|
|
||||||
s.scene = source;
|
|
||||||
s.transition = transition;
|
|
||||||
s.usePreviousScene =
|
|
||||||
(sceneName ==
|
|
||||||
QString(previous_scene_name));
|
|
||||||
s.timeSwitchStr =
|
|
||||||
text.toUtf8().constData();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_timeRemove_clicked()
|
|
||||||
{
|
{
|
||||||
QListWidgetItem *item = ui->timeSwitches->currentItem();
|
QListWidgetItem *item = ui->timeSwitches->currentItem();
|
||||||
if (!item)
|
if (!item)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::string text =
|
|
||||||
item->data(Qt::UserRole).toString().toUtf8().constData();
|
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
int idx = ui->timeSwitches->currentRow();
|
||||||
auto &switches = switcher->timeSwitches;
|
auto &switches = switcher->timeSwitches;
|
||||||
|
switches.erase(switches.begin() + idx);
|
||||||
for (auto it = switches.begin(); it != switches.end(); ++it) {
|
|
||||||
auto &s = *it;
|
|
||||||
|
|
||||||
if (s.timeSwitchStr == text) {
|
|
||||||
switches.erase(it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete item;
|
delete item;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_timeUp_clicked()
|
void AdvSceneSwitcher::on_timeUp_clicked()
|
||||||
{
|
{
|
||||||
int index = ui->timeSwitches->currentRow();
|
int index = ui->timeSwitches->currentRow();
|
||||||
if (index != -1 && index != 0) {
|
if (!listMoveUp(ui->timeSwitches))
|
||||||
ui->timeSwitches->insertItem(index - 1,
|
return;
|
||||||
ui->timeSwitches->takeItem(index));
|
|
||||||
ui->timeSwitches->setCurrentRow(index - 1);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
TimeSwitchWidget *s1 = (TimeSwitchWidget *)ui->timeSwitches->itemWidget(
|
||||||
|
ui->timeSwitches->item(index));
|
||||||
|
TimeSwitchWidget *s2 = (TimeSwitchWidget *)ui->timeSwitches->itemWidget(
|
||||||
|
ui->timeSwitches->item(index - 1));
|
||||||
|
TimeSwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
iter_swap(switcher->timeSwitches.begin() + index,
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switcher->timeSwitches.begin() + index - 1);
|
|
||||||
}
|
std::swap(switcher->timeSwitches[index],
|
||||||
|
switcher->timeSwitches[index - 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_timeDown_clicked()
|
void AdvSceneSwitcher::on_timeDown_clicked()
|
||||||
{
|
{
|
||||||
int index = ui->timeSwitches->currentRow();
|
int index = ui->timeSwitches->currentRow();
|
||||||
if (index != -1 && index != ui->timeSwitches->count() - 1) {
|
|
||||||
ui->timeSwitches->insertItem(index + 1,
|
|
||||||
ui->timeSwitches->takeItem(index));
|
|
||||||
ui->timeSwitches->setCurrentRow(index + 1);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
if (!listMoveDown(ui->timeSwitches))
|
||||||
|
return;
|
||||||
|
|
||||||
iter_swap(switcher->timeSwitches.begin() + index,
|
TimeSwitchWidget *s1 = (TimeSwitchWidget *)ui->timeSwitches->itemWidget(
|
||||||
switcher->timeSwitches.begin() + index + 1);
|
ui->timeSwitches->item(index));
|
||||||
}
|
TimeSwitchWidget *s2 = (TimeSwitchWidget *)ui->timeSwitches->itemWidget(
|
||||||
|
ui->timeSwitches->item(index + 1));
|
||||||
|
TimeSwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
|
||||||
|
std::swap(switcher->timeSwitches[index],
|
||||||
|
switcher->timeSwitches[index + 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool timesAreInInterval(QTime &time1, QTime &time2, int &interval)
|
bool timesAreInInterval(QTime &time1, QTime &time2, int &interval)
|
||||||
@@ -212,6 +114,9 @@ void SwitcherData::checkTimeSwitch(bool &match, OBSWeakSource &scene,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
for (TimeSwitch &s : timeSwitches) {
|
for (TimeSwitch &s : timeSwitches) {
|
||||||
|
if (!s.initialized())
|
||||||
|
continue;
|
||||||
|
|
||||||
if (s.trigger == LIVE)
|
if (s.trigger == LIVE)
|
||||||
match = checkLiveTime(s, liveTime, interval);
|
match = checkLiveTime(s, liveTime, interval);
|
||||||
else
|
else
|
||||||
@@ -282,91 +187,123 @@ void SwitcherData::loadTimeSwitches(obs_data_t *obj)
|
|||||||
QTime time = QTime::fromString(
|
QTime time = QTime::fromString(
|
||||||
obs_data_get_string(array_obj, "time"));
|
obs_data_get_string(array_obj, "time"));
|
||||||
|
|
||||||
std::string timeSwitchStr =
|
|
||||||
MakeTimeSwitchName(scene, transition, trigger, time)
|
|
||||||
.toUtf8()
|
|
||||||
.constData();
|
|
||||||
|
|
||||||
switcher->timeSwitches.emplace_back(
|
switcher->timeSwitches.emplace_back(
|
||||||
GetWeakSourceByName(scene),
|
GetWeakSourceByName(scene),
|
||||||
GetWeakTransitionByName(transition), trigger, time,
|
GetWeakTransitionByName(transition), trigger, time,
|
||||||
(strcmp(scene, previous_scene_name) == 0),
|
(strcmp(scene, previous_scene_name) == 0));
|
||||||
timeSwitchStr);
|
|
||||||
|
|
||||||
obs_data_release(array_obj);
|
obs_data_release(array_obj);
|
||||||
}
|
}
|
||||||
obs_data_array_release(timeArray);
|
obs_data_array_release(timeArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::setupTimeTab()
|
void AdvSceneSwitcher::setupTimeTab()
|
||||||
{
|
{
|
||||||
populateSceneSelection(ui->timeScenes, true);
|
for (auto &s : switcher->timeSwitches) {
|
||||||
populateTransitionSelection(ui->timeTransitions);
|
QListWidgetItem *item;
|
||||||
|
item = new QListWidgetItem(ui->timeSwitches);
|
||||||
for (auto t : triggerTable) {
|
ui->timeSwitches->addItem(item);
|
||||||
ui->timeTrigger->addItem(t.first.c_str());
|
TimeSwitchWidget *sw = new TimeSwitchWidget(&s);
|
||||||
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
|
ui->timeSwitches->setItemWidget(item, sw);
|
||||||
}
|
}
|
||||||
|
|
||||||
// assuming the streaming / recording entry is always last
|
if (switcher->timeSwitches.size() == 0)
|
||||||
ui->timeTrigger->setItemData(
|
addPulse = PulseWidget(ui->timeAdd, QColor(Qt::green));
|
||||||
(int)triggerTable.size() - 1,
|
}
|
||||||
|
|
||||||
|
void populateTriggers(QComboBox *list)
|
||||||
|
{
|
||||||
|
list->addItem("On any day");
|
||||||
|
list->addItem("Mondays");
|
||||||
|
list->addItem("Tuesdays");
|
||||||
|
list->addItem("Wednesdays");
|
||||||
|
list->addItem("Thursdays");
|
||||||
|
list->addItem("Fridays");
|
||||||
|
list->addItem("Saturdays");
|
||||||
|
list->addItem("Sundays");
|
||||||
|
list->addItem("Atfer streaming/recording start");
|
||||||
|
|
||||||
|
list->setItemData(
|
||||||
|
8,
|
||||||
"The time relative to the start of streaming / recording will be used",
|
"The time relative to the start of streaming / recording will be used",
|
||||||
Qt::ToolTipRole);
|
Qt::ToolTipRole);
|
||||||
|
|
||||||
for (auto &s : switcher->timeSwitches) {
|
|
||||||
std::string sceneName = (s.usePreviousScene)
|
|
||||||
? previous_scene_name
|
|
||||||
: GetWeakSourceName(s.scene);
|
|
||||||
std::string transitionName = GetWeakSourceName(s.transition);
|
|
||||||
QString listText = MakeTimeSwitchName(sceneName.c_str(),
|
|
||||||
transitionName.c_str(),
|
|
||||||
s.trigger, s.time);
|
|
||||||
|
|
||||||
QListWidgetItem *item =
|
|
||||||
new QListWidgetItem(listText, ui->timeSwitches);
|
|
||||||
item->setData(Qt::UserRole, listText);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline QString MakeTimeSwitchName(const QString &scene,
|
TimeSwitchWidget::TimeSwitchWidget(TimeSwitch *s) : SwitchWidget(s)
|
||||||
const QString &transition,
|
|
||||||
const timeTrigger &trigger,
|
|
||||||
const QTime &time)
|
|
||||||
{
|
{
|
||||||
QString switchName;
|
triggers = new QComboBox();
|
||||||
|
time = new QTimeEdit();
|
||||||
|
|
||||||
switch (trigger) {
|
atLabel = new QLabel("at");
|
||||||
case ANY_DAY:
|
switchLabel = new QLabel("switch to");
|
||||||
switchName = QStringLiteral("On any weekday");
|
usingLabel = new QLabel("using");
|
||||||
break;
|
|
||||||
case MONDAY:
|
QWidget::connect(triggers, SIGNAL(currentIndexChanged(int)), this,
|
||||||
switchName = QStringLiteral("Mondays");
|
SLOT(TriggerChanged(int)));
|
||||||
break;
|
QWidget::connect(time, SIGNAL(timeChanged(const QTime &)), this,
|
||||||
case TUSEDAY:
|
SLOT(TimeChanged(const QTime &)));
|
||||||
switchName = QStringLiteral("Tusedays");
|
|
||||||
break;
|
populateTriggers(triggers);
|
||||||
case WEDNESDAY:
|
time->setDisplayFormat("HH:mm:ss");
|
||||||
switchName = QStringLiteral("Wednesdays");
|
|
||||||
break;
|
if (s) {
|
||||||
case THURSDAY:
|
triggers->setCurrentIndex(s->trigger);
|
||||||
switchName = QStringLiteral("Thursdays");
|
time->setTime(s->time);
|
||||||
break;
|
|
||||||
case FRIDAY:
|
|
||||||
switchName = QStringLiteral("Fridays");
|
|
||||||
break;
|
|
||||||
case SATURDAY:
|
|
||||||
switchName = QStringLiteral("Saturdays");
|
|
||||||
break;
|
|
||||||
case SUNDAY:
|
|
||||||
switchName = QStringLiteral("Sundays");
|
|
||||||
break;
|
|
||||||
case LIVE:
|
|
||||||
switchName = QStringLiteral(
|
|
||||||
"Relative to starting streaming / recording");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
switchName += QStringLiteral(" at ") + time.toString() +
|
|
||||||
QStringLiteral(" switch to ") + scene +
|
setStyleSheet("* { background-color: transparent; }");
|
||||||
QStringLiteral(" using ") + transition;
|
|
||||||
return switchName;
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
|
||||||
|
mainLayout->addWidget(triggers);
|
||||||
|
mainLayout->addWidget(atLabel);
|
||||||
|
mainLayout->addWidget(time);
|
||||||
|
mainLayout->addWidget(switchLabel);
|
||||||
|
mainLayout->addWidget(scenes);
|
||||||
|
mainLayout->addWidget(usingLabel);
|
||||||
|
mainLayout->addWidget(transitions);
|
||||||
|
mainLayout->addStretch();
|
||||||
|
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
switchData = s;
|
||||||
|
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeSwitch *TimeSwitchWidget::getSwitchData()
|
||||||
|
{
|
||||||
|
return switchData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimeSwitchWidget::setSwitchData(TimeSwitch *s)
|
||||||
|
{
|
||||||
|
switchData = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimeSwitchWidget::swapSwitchData(TimeSwitchWidget *s1,
|
||||||
|
TimeSwitchWidget *s2)
|
||||||
|
{
|
||||||
|
SwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
TimeSwitch *t = s1->getSwitchData();
|
||||||
|
s1->setSwitchData(s2->getSwitchData());
|
||||||
|
s2->setSwitchData(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimeSwitchWidget::TriggerChanged(int index)
|
||||||
|
{
|
||||||
|
if (loading || !switchData)
|
||||||
|
return;
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->trigger = (timeTrigger)index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimeSwitchWidget::TimeChanged(const QTime &time)
|
||||||
|
{
|
||||||
|
if (loading || !switchData)
|
||||||
|
return;
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->time = time;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,274 +1,184 @@
|
|||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
void SceneSwitcher::on_transitionsAdd_clicked()
|
void AdvSceneSwitcher::on_transitionsAdd_clicked()
|
||||||
{
|
{
|
||||||
QString scene1Name = ui->transitionsScene1->currentText();
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
QString scene2Name = ui->transitionsScene2->currentText();
|
switcher->sceneTransitions.emplace_back();
|
||||||
QString transitionName = ui->transitionsTransitions->currentText();
|
|
||||||
|
|
||||||
if (scene1Name.isEmpty() || scene2Name.isEmpty())
|
QListWidgetItem *item;
|
||||||
return;
|
item = new QListWidgetItem(ui->sceneTransitions);
|
||||||
|
ui->sceneTransitions->addItem(item);
|
||||||
if (scene1Name == scene2Name)
|
TransitionSwitchWidget *sw =
|
||||||
return;
|
new TransitionSwitchWidget(&switcher->sceneTransitions.back());
|
||||||
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
OBSWeakSource source1 = GetWeakSourceByQString(scene1Name);
|
ui->sceneTransitions->setItemWidget(item, sw);
|
||||||
OBSWeakSource source2 = GetWeakSourceByQString(scene2Name);
|
|
||||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
|
||||||
|
|
||||||
QString text =
|
|
||||||
MakeSceneTransitionName(scene1Name, scene2Name, transitionName);
|
|
||||||
QVariant v = QVariant::fromValue(text);
|
|
||||||
|
|
||||||
int idx = SceneTransitionsFindByData(scene1Name, scene2Name);
|
|
||||||
|
|
||||||
if (idx == -1) {
|
|
||||||
QListWidgetItem *item =
|
|
||||||
new QListWidgetItem(text, ui->sceneTransitions);
|
|
||||||
item->setData(Qt::UserRole, v);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
switcher->sceneTransitions.emplace_back(
|
|
||||||
source1, source2, transition,
|
|
||||||
text.toUtf8().constData());
|
|
||||||
} else {
|
|
||||||
QListWidgetItem *item = ui->sceneTransitions->item(idx);
|
|
||||||
item->setText(text);
|
|
||||||
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
for (auto &s : switcher->sceneTransitions) {
|
|
||||||
if (s.scene == source1 && s.scene2 == source2) {
|
|
||||||
s.transition = transition;
|
|
||||||
s.sceneTransitionStr =
|
|
||||||
text.toUtf8().constData();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ui->sceneTransitions->sortItems();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::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::string text =
|
|
||||||
item->data(Qt::UserRole).toString().toUtf8().constData();
|
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
int idx = ui->sceneTransitions->currentRow();
|
||||||
auto &switches = switcher->sceneTransitions;
|
auto &switches = switcher->sceneTransitions;
|
||||||
|
switches.erase(switches.begin() + idx);
|
||||||
for (auto it = switches.begin(); it != switches.end(); ++it) {
|
|
||||||
auto &s = *it;
|
|
||||||
|
|
||||||
if (s.sceneTransitionStr == text) {
|
|
||||||
switches.erase(it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete item;
|
delete item;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_defaultTransitionsAdd_clicked()
|
void AdvSceneSwitcher::on_transitionsUp_clicked()
|
||||||
{
|
{
|
||||||
QString sceneName = ui->defaultTransitionsScene->currentText();
|
int index = ui->sceneTransitions->currentRow();
|
||||||
QString transitionName =
|
if (!listMoveUp(ui->sceneTransitions))
|
||||||
ui->defaultTransitionsTransitions->currentText();
|
|
||||||
|
|
||||||
if (sceneName.isEmpty() || transitionName.isEmpty())
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
OBSWeakSource source = GetWeakSourceByQString(sceneName);
|
TransitionSwitchWidget *s1 =
|
||||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
(TransitionSwitchWidget *)ui->sceneTransitions->itemWidget(
|
||||||
|
ui->sceneTransitions->item(index));
|
||||||
|
TransitionSwitchWidget *s2 =
|
||||||
|
(TransitionSwitchWidget *)ui->sceneTransitions->itemWidget(
|
||||||
|
ui->sceneTransitions->item(index - 1));
|
||||||
|
TransitionSwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
QString text =
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
MakeDefaultSceneTransitionName(sceneName, transitionName);
|
|
||||||
QVariant v = QVariant::fromValue(text);
|
|
||||||
|
|
||||||
int idx = DefaultTransitionsFindByData(sceneName);
|
std::swap(switcher->sceneTransitions[index],
|
||||||
|
switcher->sceneTransitions[index - 1]);
|
||||||
if (idx == -1) {
|
|
||||||
QListWidgetItem *item =
|
|
||||||
new QListWidgetItem(text, ui->defaultTransitions);
|
|
||||||
item->setData(Qt::UserRole, v);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
switcher->defaultSceneTransitions.emplace_back(
|
|
||||||
source, transition, text.toUtf8().constData());
|
|
||||||
} else {
|
|
||||||
QListWidgetItem *item = ui->defaultTransitions->item(idx);
|
|
||||||
item->setText(text);
|
|
||||||
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
for (auto &s : switcher->defaultSceneTransitions) {
|
|
||||||
if (s.scene == source) {
|
|
||||||
s.transition = transition;
|
|
||||||
s.sceneTransitionStr =
|
|
||||||
text.toUtf8().constData();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ui->defaultTransitions->sortItems();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_defaultTransitionsRemove_clicked()
|
void AdvSceneSwitcher::on_transitionsDown_clicked()
|
||||||
|
{
|
||||||
|
int index = ui->sceneTransitions->currentRow();
|
||||||
|
|
||||||
|
if (!listMoveDown(ui->sceneTransitions))
|
||||||
|
return;
|
||||||
|
|
||||||
|
TransitionSwitchWidget *s1 =
|
||||||
|
(TransitionSwitchWidget *)ui->sceneTransitions->itemWidget(
|
||||||
|
ui->sceneTransitions->item(index));
|
||||||
|
TransitionSwitchWidget *s2 =
|
||||||
|
(TransitionSwitchWidget *)ui->sceneTransitions->itemWidget(
|
||||||
|
ui->sceneTransitions->item(index + 1));
|
||||||
|
TransitionSwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
|
||||||
|
std::swap(switcher->sceneTransitions[index],
|
||||||
|
switcher->sceneTransitions[index + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_defaultTransitionsAdd_clicked()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switcher->defaultSceneTransitions.emplace_back();
|
||||||
|
|
||||||
|
QListWidgetItem *item;
|
||||||
|
item = new QListWidgetItem(ui->defaultTransitions);
|
||||||
|
ui->defaultTransitions->addItem(item);
|
||||||
|
DefTransitionSwitchWidget *sw = new DefTransitionSwitchWidget(
|
||||||
|
&switcher->defaultSceneTransitions.back());
|
||||||
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
|
ui->defaultTransitions->setItemWidget(item, sw);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_defaultTransitionsRemove_clicked()
|
||||||
{
|
{
|
||||||
QListWidgetItem *item = ui->defaultTransitions->currentItem();
|
QListWidgetItem *item = ui->defaultTransitions->currentItem();
|
||||||
if (!item)
|
if (!item)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::string text =
|
|
||||||
item->data(Qt::UserRole).toString().toUtf8().constData();
|
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
int idx = ui->defaultTransitions->currentRow();
|
||||||
auto &switches = switcher->defaultSceneTransitions;
|
auto &switches = switcher->defaultSceneTransitions;
|
||||||
|
switches.erase(switches.begin() + idx);
|
||||||
for (auto it = switches.begin(); it != switches.end(); ++it) {
|
|
||||||
auto &s = *it;
|
|
||||||
|
|
||||||
if (s.sceneTransitionStr == text) {
|
|
||||||
switches.erase(it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete item;
|
delete item;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitcherData::setDefaultSceneTransitions()
|
void AdvSceneSwitcher::on_defaultTransitionsUp_clicked()
|
||||||
{
|
{
|
||||||
|
int index = ui->defaultTransitions->currentRow();
|
||||||
|
if (!listMoveUp(ui->defaultTransitions))
|
||||||
|
return;
|
||||||
|
|
||||||
|
TransitionSwitchWidget *s1 =
|
||||||
|
(TransitionSwitchWidget *)ui->defaultTransitions->itemWidget(
|
||||||
|
ui->defaultTransitions->item(index));
|
||||||
|
TransitionSwitchWidget *s2 =
|
||||||
|
(TransitionSwitchWidget *)ui->defaultTransitions->itemWidget(
|
||||||
|
ui->defaultTransitions->item(index - 1));
|
||||||
|
TransitionSwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
|
||||||
|
std::swap(switcher->defaultSceneTransitions[index],
|
||||||
|
switcher->defaultSceneTransitions[index - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_defaultTransitionsDown_clicked()
|
||||||
|
{
|
||||||
|
int index = ui->defaultTransitions->currentRow();
|
||||||
|
|
||||||
|
if (!listMoveDown(ui->defaultTransitions))
|
||||||
|
return;
|
||||||
|
|
||||||
|
DefTransitionSwitchWidget *s1 =
|
||||||
|
(DefTransitionSwitchWidget *)ui->defaultTransitions->itemWidget(
|
||||||
|
ui->defaultTransitions->item(index));
|
||||||
|
DefTransitionSwitchWidget *s2 =
|
||||||
|
(DefTransitionSwitchWidget *)ui->defaultTransitions->itemWidget(
|
||||||
|
ui->defaultTransitions->item(index + 1));
|
||||||
|
DefTransitionSwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
|
||||||
|
std::swap(switcher->defaultSceneTransitions[index],
|
||||||
|
switcher->defaultSceneTransitions[index + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitcherData::checkDefaultSceneTransitions(bool &match,
|
||||||
|
OBSWeakSource &transition)
|
||||||
|
{
|
||||||
|
if (checkedDefTransition)
|
||||||
|
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) {
|
||||||
obs_source_t *transition =
|
if (!s.initialized())
|
||||||
obs_weak_source_get_source(s.transition);
|
continue;
|
||||||
//This might cancel the current transition
|
|
||||||
//There is no way to be sure when the previous transition finished
|
match = true;
|
||||||
obs_frontend_set_current_transition(transition);
|
transition = s.transition;
|
||||||
|
|
||||||
if (verbose)
|
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);
|
||||||
|
|
||||||
|
checkedDefTransition = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SceneSwitcher::SceneTransitionsFindByData(const QString &scene1,
|
void SwitcherData::setCurrentDefTransition(OBSWeakSource &transition)
|
||||||
const QString &scene2)
|
|
||||||
{
|
{
|
||||||
QRegExp rx(scene1 + " --- .* --> " + scene2);
|
obs_source_t *transitionSource = obs_weak_source_get_source(transition);
|
||||||
int count = ui->sceneTransitions->count();
|
obs_frontend_set_current_transition(transitionSource);
|
||||||
int idx = -1;
|
obs_source_release(transitionSource);
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
QListWidgetItem *item = ui->sceneTransitions->item(i);
|
|
||||||
QString itemString = item->data(Qt::UserRole).toString();
|
|
||||||
|
|
||||||
if (rx.exactMatch(itemString)) {
|
|
||||||
idx = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return idx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int SceneSwitcher::DefaultTransitionsFindByData(const QString &scene)
|
void AdvSceneSwitcher::on_transitionOverridecheckBox_stateChanged(int state)
|
||||||
{
|
|
||||||
QRegExp rx(scene + " --> .*");
|
|
||||||
int count = ui->defaultTransitions->count();
|
|
||||||
int idx = -1;
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
QListWidgetItem *item = ui->defaultTransitions->item(i);
|
|
||||||
QString itemString = item->data(Qt::UserRole).toString();
|
|
||||||
|
|
||||||
if (rx.exactMatch(itemString)) {
|
|
||||||
idx = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_sceneTransitions_currentRowChanged(int idx)
|
|
||||||
{
|
|
||||||
if (loading)
|
|
||||||
return;
|
|
||||||
if (idx == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QListWidgetItem *item = ui->sceneTransitions->item(idx);
|
|
||||||
|
|
||||||
QString sceneTransition = item->data(Qt::UserRole).toString();
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
for (auto &s : switcher->sceneTransitions) {
|
|
||||||
if (sceneTransition.compare(s.sceneTransitionStr.c_str()) ==
|
|
||||||
0) {
|
|
||||||
std::string scene1 = GetWeakSourceName(s.scene);
|
|
||||||
std::string scene2 = GetWeakSourceName(s.scene2);
|
|
||||||
std::string transitionName =
|
|
||||||
GetWeakSourceName(s.transition);
|
|
||||||
ui->transitionsScene1->setCurrentText(scene1.c_str());
|
|
||||||
ui->transitionsScene2->setCurrentText(scene2.c_str());
|
|
||||||
ui->transitionsTransitions->setCurrentText(
|
|
||||||
transitionName.c_str());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_defaultTransitions_currentRowChanged(int idx)
|
|
||||||
{
|
|
||||||
if (loading)
|
|
||||||
return;
|
|
||||||
if (idx == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QListWidgetItem *item = ui->defaultTransitions->item(idx);
|
|
||||||
|
|
||||||
QString sceneTransition = item->data(Qt::UserRole).toString();
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
for (auto &s : switcher->defaultSceneTransitions) {
|
|
||||||
if (sceneTransition.compare(s.sceneTransitionStr.c_str()) ==
|
|
||||||
0) {
|
|
||||||
std::string scene = GetWeakSourceName(s.scene);
|
|
||||||
std::string transitionName =
|
|
||||||
GetWeakSourceName(s.transition);
|
|
||||||
ui->defaultTransitionsScene->setCurrentText(
|
|
||||||
scene.c_str());
|
|
||||||
ui->defaultTransitionsTransitions->setCurrentText(
|
|
||||||
transitionName.c_str());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_transitionOverridecheckBox_stateChanged(int state)
|
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading)
|
||||||
return;
|
return;
|
||||||
@@ -287,8 +197,13 @@ 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.scene == scene1 && t.scene2 == scene2)
|
if (!t.initialized())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (t.scene == scene1 && t.scene2 == scene2) {
|
||||||
ws = t.transition;
|
ws = t.transition;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
obs_weak_source_addref(ws);
|
obs_weak_source_addref(ws);
|
||||||
}
|
}
|
||||||
@@ -373,11 +288,10 @@ void SwitcherData::saveSceneTransitions(obs_data_t *obj)
|
|||||||
transitionName);
|
transitionName);
|
||||||
obs_data_array_push_back(sceneTransitionsArray,
|
obs_data_array_push_back(sceneTransitionsArray,
|
||||||
array_obj);
|
array_obj);
|
||||||
obs_source_release(source1);
|
|
||||||
obs_source_release(source2);
|
|
||||||
obs_source_release(transition);
|
|
||||||
}
|
}
|
||||||
|
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, "sceneTransitions", sceneTransitionsArray);
|
obs_data_set_array(obj, "sceneTransitions", sceneTransitionsArray);
|
||||||
@@ -399,10 +313,9 @@ void SwitcherData::saveSceneTransitions(obs_data_t *obj)
|
|||||||
transitionName);
|
transitionName);
|
||||||
obs_data_array_push_back(defaultTransitionsArray,
|
obs_data_array_push_back(defaultTransitionsArray,
|
||||||
array_obj);
|
array_obj);
|
||||||
obs_source_release(source);
|
|
||||||
obs_source_release(transition);
|
|
||||||
}
|
}
|
||||||
|
obs_source_release(source);
|
||||||
|
obs_source_release(transition);
|
||||||
obs_data_release(array_obj);
|
obs_data_release(array_obj);
|
||||||
}
|
}
|
||||||
obs_data_set_array(obj, "defaultTransitions", defaultTransitionsArray);
|
obs_data_set_array(obj, "defaultTransitions", defaultTransitionsArray);
|
||||||
@@ -429,16 +342,10 @@ void SwitcherData::loadSceneTransitions(obs_data_t *obj)
|
|||||||
const char *transition =
|
const char *transition =
|
||||||
obs_data_get_string(array_obj, "transition");
|
obs_data_get_string(array_obj, "transition");
|
||||||
|
|
||||||
std::string sceneTransitionsStr =
|
|
||||||
MakeSceneTransitionName(scene1, scene2, transition)
|
|
||||||
.toUtf8()
|
|
||||||
.constData();
|
|
||||||
|
|
||||||
switcher->sceneTransitions.emplace_back(
|
switcher->sceneTransitions.emplace_back(
|
||||||
GetWeakSourceByName(scene1),
|
GetWeakSourceByName(scene1),
|
||||||
GetWeakSourceByName(scene2),
|
GetWeakSourceByName(scene2),
|
||||||
GetWeakTransitionByName(transition),
|
GetWeakTransitionByName(transition));
|
||||||
sceneTransitionsStr);
|
|
||||||
|
|
||||||
obs_data_release(array_obj);
|
obs_data_release(array_obj);
|
||||||
}
|
}
|
||||||
@@ -458,15 +365,9 @@ void SwitcherData::loadSceneTransitions(obs_data_t *obj)
|
|||||||
const char *transition =
|
const char *transition =
|
||||||
obs_data_get_string(array_obj, "transition");
|
obs_data_get_string(array_obj, "transition");
|
||||||
|
|
||||||
std::string sceneTransitionsStr =
|
|
||||||
MakeDefaultSceneTransitionName(scene, transition)
|
|
||||||
.toUtf8()
|
|
||||||
.constData();
|
|
||||||
|
|
||||||
switcher->defaultSceneTransitions.emplace_back(
|
switcher->defaultSceneTransitions.emplace_back(
|
||||||
GetWeakSourceByName(scene),
|
GetWeakSourceByName(scene),
|
||||||
GetWeakTransitionByName(transition),
|
GetWeakTransitionByName(transition));
|
||||||
sceneTransitionsStr);
|
|
||||||
|
|
||||||
obs_data_release(array_obj);
|
obs_data_release(array_obj);
|
||||||
}
|
}
|
||||||
@@ -476,52 +377,147 @@ void SwitcherData::loadSceneTransitions(obs_data_t *obj)
|
|||||||
obs_data_get_bool(obj, "tansitionOverrideOverride");
|
obs_data_get_bool(obj, "tansitionOverrideOverride");
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::setupTransitionsTab()
|
void AdvSceneSwitcher::setupTransitionsTab()
|
||||||
{
|
{
|
||||||
populateSceneSelection(ui->transitionsScene1, false);
|
|
||||||
populateSceneSelection(ui->transitionsScene2, false);
|
|
||||||
populateSceneSelection(ui->defaultTransitionsScene, false);
|
|
||||||
populateTransitionSelection(ui->transitionsTransitions);
|
|
||||||
populateTransitionSelection(ui->defaultTransitionsTransitions);
|
|
||||||
|
|
||||||
for (auto &s : switcher->sceneTransitions) {
|
for (auto &s : switcher->sceneTransitions) {
|
||||||
std::string sceneName1 = GetWeakSourceName(s.scene);
|
QListWidgetItem *item;
|
||||||
std::string sceneName2 = GetWeakSourceName(s.scene2);
|
item = new QListWidgetItem(ui->sceneTransitions);
|
||||||
std::string transitionName = GetWeakSourceName(s.transition);
|
ui->sceneTransitions->addItem(item);
|
||||||
QString text = MakeSceneTransitionName(sceneName1.c_str(),
|
TransitionSwitchWidget *sw = new TransitionSwitchWidget(&s);
|
||||||
sceneName2.c_str(),
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
transitionName.c_str());
|
ui->sceneTransitions->setItemWidget(item, sw);
|
||||||
|
|
||||||
QListWidgetItem *item =
|
|
||||||
new QListWidgetItem(text, ui->sceneTransitions);
|
|
||||||
item->setData(Qt::UserRole, text);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &s : switcher->defaultSceneTransitions) {
|
for (auto &s : switcher->defaultSceneTransitions) {
|
||||||
std::string sceneName = GetWeakSourceName(s.scene);
|
QListWidgetItem *item;
|
||||||
std::string transitionName = GetWeakSourceName(s.transition);
|
item = new QListWidgetItem(ui->defaultTransitions);
|
||||||
QString text = MakeDefaultSceneTransitionName(
|
ui->defaultTransitions->addItem(item);
|
||||||
sceneName.c_str(), transitionName.c_str());
|
DefTransitionSwitchWidget *sw =
|
||||||
|
new DefTransitionSwitchWidget(&s);
|
||||||
QListWidgetItem *item =
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
new QListWidgetItem(text, ui->defaultTransitions);
|
ui->defaultTransitions->setItemWidget(item, sw);
|
||||||
item->setData(Qt::UserRole, text);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->transitionOverridecheckBox->setChecked(
|
ui->transitionOverridecheckBox->setChecked(
|
||||||
switcher->tansitionOverrideOverride);
|
switcher->tansitionOverrideOverride);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline QString MakeSceneTransitionName(const QString &scene1,
|
bool SceneTransition::initialized()
|
||||||
const QString &scene2,
|
|
||||||
const QString &transition)
|
|
||||||
{
|
{
|
||||||
return scene1 + QStringLiteral(" --- ") + transition +
|
return SceneSwitcherEntry::initialized() && scene2;
|
||||||
QStringLiteral(" --> ") + scene2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline QString MakeDefaultSceneTransitionName(const QString &scene,
|
bool SceneTransition::valid()
|
||||||
const QString &transition)
|
|
||||||
{
|
{
|
||||||
return scene + QStringLiteral(" --> ") + transition;
|
return !initialized() ||
|
||||||
|
(SceneSwitcherEntry::valid() && WeakSourceValid(scene2));
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionSwitchWidget::TransitionSwitchWidget(SceneTransition *s)
|
||||||
|
: SwitchWidget(s, false)
|
||||||
|
{
|
||||||
|
scenes2 = new QComboBox();
|
||||||
|
|
||||||
|
switchLabel = new QLabel("Switch from scene");
|
||||||
|
toLabel = new QLabel("to scene");
|
||||||
|
usingLabel = new QLabel("using transition");
|
||||||
|
|
||||||
|
QWidget::connect(scenes2, SIGNAL(currentTextChanged(const QString &)),
|
||||||
|
this, SLOT(Scene2Changed(const QString &)));
|
||||||
|
|
||||||
|
AdvSceneSwitcher::populateSceneSelection(scenes2, false);
|
||||||
|
|
||||||
|
if (s) {
|
||||||
|
scenes2->setCurrentText(GetWeakSourceName(s->scene2).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
setStyleSheet("* { background-color: transparent; }");
|
||||||
|
|
||||||
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
|
||||||
|
mainLayout->addWidget(switchLabel);
|
||||||
|
mainLayout->addWidget(scenes);
|
||||||
|
mainLayout->addWidget(toLabel);
|
||||||
|
mainLayout->addWidget(scenes2);
|
||||||
|
mainLayout->addWidget(usingLabel);
|
||||||
|
mainLayout->addWidget(transitions);
|
||||||
|
mainLayout->addStretch();
|
||||||
|
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
switchData = s;
|
||||||
|
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneTransition *TransitionSwitchWidget::getSwitchData()
|
||||||
|
{
|
||||||
|
return switchData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionSwitchWidget::setSwitchData(SceneTransition *s)
|
||||||
|
{
|
||||||
|
switchData = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionSwitchWidget::swapSwitchData(TransitionSwitchWidget *s1,
|
||||||
|
TransitionSwitchWidget *s2)
|
||||||
|
{
|
||||||
|
SwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
SceneTransition *t = s1->getSwitchData();
|
||||||
|
s1->setSwitchData(s2->getSwitchData());
|
||||||
|
s2->setSwitchData(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionSwitchWidget::Scene2Changed(const QString &text)
|
||||||
|
{
|
||||||
|
if (loading || !switchData)
|
||||||
|
return;
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->scene2 = GetWeakSourceByQString(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
DefTransitionSwitchWidget::DefTransitionSwitchWidget(DefaultSceneTransition *s)
|
||||||
|
: SwitchWidget(s, false)
|
||||||
|
{
|
||||||
|
whenLabel = new QLabel("When scene");
|
||||||
|
switchLabel =
|
||||||
|
new QLabel("is active change default scene transition to ");
|
||||||
|
|
||||||
|
setStyleSheet("* { background-color: transparent; }");
|
||||||
|
|
||||||
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
|
||||||
|
mainLayout->addWidget(whenLabel);
|
||||||
|
mainLayout->addWidget(scenes);
|
||||||
|
mainLayout->addWidget(switchLabel);
|
||||||
|
mainLayout->addWidget(transitions);
|
||||||
|
mainLayout->addStretch();
|
||||||
|
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
switchData = s;
|
||||||
|
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultSceneTransition *DefTransitionSwitchWidget::getSwitchData()
|
||||||
|
{
|
||||||
|
return switchData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefTransitionSwitchWidget::setSwitchData(DefaultSceneTransition *s)
|
||||||
|
{
|
||||||
|
switchData = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefTransitionSwitchWidget::swapSwitchData(DefTransitionSwitchWidget *s1,
|
||||||
|
DefTransitionSwitchWidget *s2)
|
||||||
|
{
|
||||||
|
SwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
DefaultSceneTransition *t = s1->getSwitchData();
|
||||||
|
s1->setSwitchData(s2->getSwitchData());
|
||||||
|
s2->setSwitchData(t);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,166 @@
|
|||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
|
static QMetaObject::Connection addPulse;
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_windowAdd_clicked()
|
||||||
|
{
|
||||||
|
ui->windowAdd->disconnect(addPulse);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switcher->windowSwitches.emplace_back();
|
||||||
|
|
||||||
|
QListWidgetItem *item;
|
||||||
|
item = new QListWidgetItem(ui->windowSwitches);
|
||||||
|
ui->windowSwitches->addItem(item);
|
||||||
|
WindowSwitchWidget *sw =
|
||||||
|
new WindowSwitchWidget(&switcher->windowSwitches.back());
|
||||||
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
|
ui->windowSwitches->setItemWidget(item, sw);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_windowRemove_clicked()
|
||||||
|
{
|
||||||
|
QListWidgetItem *item = ui->windowSwitches->currentItem();
|
||||||
|
if (!item)
|
||||||
|
return;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
int idx = ui->windowSwitches->currentRow();
|
||||||
|
auto &switches = switcher->windowSwitches;
|
||||||
|
switches.erase(switches.begin() + idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete item;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_windowUp_clicked()
|
||||||
|
{
|
||||||
|
int index = ui->windowSwitches->currentRow();
|
||||||
|
if (!listMoveUp(ui->windowSwitches))
|
||||||
|
return;
|
||||||
|
|
||||||
|
WindowSwitchWidget *s1 =
|
||||||
|
(WindowSwitchWidget *)ui->windowSwitches->itemWidget(
|
||||||
|
ui->windowSwitches->item(index));
|
||||||
|
WindowSwitchWidget *s2 =
|
||||||
|
(WindowSwitchWidget *)ui->windowSwitches->itemWidget(
|
||||||
|
ui->windowSwitches->item(index - 1));
|
||||||
|
WindowSwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
|
||||||
|
std::swap(switcher->windowSwitches[index],
|
||||||
|
switcher->windowSwitches[index - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_windowDown_clicked()
|
||||||
|
{
|
||||||
|
int index = ui->windowSwitches->currentRow();
|
||||||
|
|
||||||
|
if (!listMoveDown(ui->windowSwitches))
|
||||||
|
return;
|
||||||
|
|
||||||
|
WindowSwitchWidget *s1 =
|
||||||
|
(WindowSwitchWidget *)ui->windowSwitches->itemWidget(
|
||||||
|
ui->windowSwitches->item(index));
|
||||||
|
WindowSwitchWidget *s2 =
|
||||||
|
(WindowSwitchWidget *)ui->windowSwitches->itemWidget(
|
||||||
|
ui->windowSwitches->item(index + 1));
|
||||||
|
WindowSwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
|
||||||
|
std::swap(switcher->windowSwitches[index],
|
||||||
|
switcher->windowSwitches[index + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_ignoreWindowsAdd_clicked()
|
||||||
|
{
|
||||||
|
QString windowName = ui->ignoreWindowsWindows->currentText();
|
||||||
|
|
||||||
|
if (windowName.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QVariant v = QVariant::fromValue(windowName);
|
||||||
|
|
||||||
|
QList<QListWidgetItem *> items =
|
||||||
|
ui->ignoreWindows->findItems(windowName, Qt::MatchExactly);
|
||||||
|
|
||||||
|
if (items.size() == 0) {
|
||||||
|
QListWidgetItem *item =
|
||||||
|
new QListWidgetItem(windowName, ui->ignoreWindows);
|
||||||
|
item->setData(Qt::UserRole, v);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switcher->ignoreWindowsSwitches.emplace_back(
|
||||||
|
windowName.toUtf8().constData());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_ignoreWindowsRemove_clicked()
|
||||||
|
{
|
||||||
|
QListWidgetItem *item = ui->ignoreWindows->currentItem();
|
||||||
|
if (!item)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QString windowName = item->data(Qt::UserRole).toString();
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
auto &switches = switcher->ignoreWindowsSwitches;
|
||||||
|
|
||||||
|
for (auto it = switches.begin(); it != switches.end(); ++it) {
|
||||||
|
auto &s = *it;
|
||||||
|
|
||||||
|
if (s == windowName.toUtf8().constData()) {
|
||||||
|
switches.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete item;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AdvSceneSwitcher::IgnoreWindowsFindByData(const QString &window)
|
||||||
|
{
|
||||||
|
int count = ui->ignoreWindows->count();
|
||||||
|
int idx = -1;
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
QListWidgetItem *item = ui->ignoreWindows->item(i);
|
||||||
|
QString itemRegion = item->data(Qt::UserRole).toString();
|
||||||
|
|
||||||
|
if (itemRegion == window) {
|
||||||
|
idx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_ignoreWindows_currentRowChanged(int idx)
|
||||||
|
{
|
||||||
|
if (loading)
|
||||||
|
return;
|
||||||
|
if (idx == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QListWidgetItem *item = ui->ignoreWindows->item(idx);
|
||||||
|
|
||||||
|
QString window = item->data(Qt::UserRole).toString();
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
for (auto &s : switcher->ignoreWindowsSwitches) {
|
||||||
|
if (window.compare(s.c_str()) == 0) {
|
||||||
|
ui->ignoreWindowsWindows->setCurrentText(s.c_str());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool isRunning(std::string &title)
|
bool isRunning(std::string &title)
|
||||||
{
|
{
|
||||||
@@ -28,246 +190,6 @@ bool isFocused(std::string &title)
|
|||||||
return (equals || matches);
|
return (equals || matches);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_up_clicked()
|
|
||||||
{
|
|
||||||
int index = ui->switches->currentRow();
|
|
||||||
if (index != -1 && index != 0) {
|
|
||||||
ui->switches->insertItem(index - 1,
|
|
||||||
ui->switches->takeItem(index));
|
|
||||||
ui->switches->setCurrentRow(index - 1);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
|
|
||||||
iter_swap(switcher->windowSwitches.begin() + index,
|
|
||||||
switcher->windowSwitches.begin() + index - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_down_clicked()
|
|
||||||
{
|
|
||||||
int index = ui->switches->currentRow();
|
|
||||||
if (index != -1 && index != ui->switches->count() - 1) {
|
|
||||||
ui->switches->insertItem(index + 1,
|
|
||||||
ui->switches->takeItem(index));
|
|
||||||
ui->switches->setCurrentRow(index + 1);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
|
|
||||||
iter_swap(switcher->windowSwitches.begin() + index,
|
|
||||||
switcher->windowSwitches.begin() + index + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_add_clicked()
|
|
||||||
{
|
|
||||||
QString sceneName = ui->scenes->currentText();
|
|
||||||
QString windowName = ui->windows->currentText();
|
|
||||||
QString transitionName = ui->transitions->currentText();
|
|
||||||
bool fullscreen = ui->fullscreenCheckBox->isChecked();
|
|
||||||
bool maximized = ui->maximizedCheckBox->isChecked();
|
|
||||||
bool focus = ui->focusCheckBox->isChecked();
|
|
||||||
|
|
||||||
if (windowName.isEmpty() || sceneName.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
OBSWeakSource source = GetWeakSourceByQString(sceneName);
|
|
||||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
|
||||||
QVariant v = QVariant::fromValue(windowName);
|
|
||||||
|
|
||||||
QString text = MakeWindowSwitchName(sceneName, windowName,
|
|
||||||
transitionName, fullscreen,
|
|
||||||
maximized, focus);
|
|
||||||
|
|
||||||
int idx = FindByData(windowName);
|
|
||||||
|
|
||||||
if (idx == -1) {
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
switcher->windowSwitches.emplace_back(
|
|
||||||
source, windowName.toUtf8().constData(), transition,
|
|
||||||
fullscreen, maximized, focus);
|
|
||||||
|
|
||||||
QListWidgetItem *item = new QListWidgetItem(text, ui->switches);
|
|
||||||
item->setData(Qt::UserRole, v);
|
|
||||||
} else {
|
|
||||||
QListWidgetItem *item = ui->switches->item(idx);
|
|
||||||
item->setText(text);
|
|
||||||
|
|
||||||
std::string window = windowName.toUtf8().constData();
|
|
||||||
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
for (auto &s : switcher->windowSwitches) {
|
|
||||||
if (s.window == window) {
|
|
||||||
s.scene = source;
|
|
||||||
s.transition = transition;
|
|
||||||
s.fullscreen = fullscreen;
|
|
||||||
s.maximized = maximized;
|
|
||||||
s.focus = focus;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_remove_clicked()
|
|
||||||
{
|
|
||||||
QListWidgetItem *item = ui->switches->currentItem();
|
|
||||||
if (!item)
|
|
||||||
return;
|
|
||||||
|
|
||||||
std::string window =
|
|
||||||
item->data(Qt::UserRole).toString().toUtf8().constData();
|
|
||||||
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
auto &switches = switcher->windowSwitches;
|
|
||||||
|
|
||||||
for (auto it = switches.begin(); it != switches.end(); ++it) {
|
|
||||||
auto &s = *it;
|
|
||||||
|
|
||||||
if (s.window == window) {
|
|
||||||
switches.erase(it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete item;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_ignoreWindowsAdd_clicked()
|
|
||||||
{
|
|
||||||
QString windowName = ui->ignoreWindowsWindows->currentText();
|
|
||||||
|
|
||||||
if (windowName.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
QVariant v = QVariant::fromValue(windowName);
|
|
||||||
|
|
||||||
QList<QListWidgetItem *> items =
|
|
||||||
ui->ignoreWindows->findItems(windowName, Qt::MatchExactly);
|
|
||||||
|
|
||||||
if (items.size() == 0) {
|
|
||||||
QListWidgetItem *item =
|
|
||||||
new QListWidgetItem(windowName, ui->ignoreWindows);
|
|
||||||
item->setData(Qt::UserRole, v);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
switcher->ignoreWindowsSwitches.emplace_back(
|
|
||||||
windowName.toUtf8().constData());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_ignoreWindowsRemove_clicked()
|
|
||||||
{
|
|
||||||
QListWidgetItem *item = ui->ignoreWindows->currentItem();
|
|
||||||
if (!item)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QString windowName = item->data(Qt::UserRole).toString();
|
|
||||||
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
auto &switches = switcher->ignoreWindowsSwitches;
|
|
||||||
|
|
||||||
for (auto it = switches.begin(); it != switches.end(); ++it) {
|
|
||||||
auto &s = *it;
|
|
||||||
|
|
||||||
if (s == windowName.toUtf8().constData()) {
|
|
||||||
switches.erase(it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete item;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SceneSwitcher::FindByData(const QString &window)
|
|
||||||
{
|
|
||||||
int count = ui->switches->count();
|
|
||||||
int idx = -1;
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
QListWidgetItem *item = ui->switches->item(i);
|
|
||||||
QString itemWindow = item->data(Qt::UserRole).toString();
|
|
||||||
|
|
||||||
if (itemWindow == window) {
|
|
||||||
idx = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SceneSwitcher::IgnoreWindowsFindByData(const QString &window)
|
|
||||||
{
|
|
||||||
int count = ui->ignoreWindows->count();
|
|
||||||
int idx = -1;
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
QListWidgetItem *item = ui->ignoreWindows->item(i);
|
|
||||||
QString itemRegion = item->data(Qt::UserRole).toString();
|
|
||||||
|
|
||||||
if (itemRegion == window) {
|
|
||||||
idx = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_switches_currentRowChanged(int idx)
|
|
||||||
{
|
|
||||||
if (loading)
|
|
||||||
return;
|
|
||||||
if (idx == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QListWidgetItem *item = ui->switches->item(idx);
|
|
||||||
|
|
||||||
QString window = item->data(Qt::UserRole).toString();
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
for (auto &s : switcher->windowSwitches) {
|
|
||||||
if (window.compare(s.window.c_str()) == 0) {
|
|
||||||
std::string name = GetWeakSourceName(s.scene);
|
|
||||||
std::string transitionName =
|
|
||||||
GetWeakSourceName(s.transition);
|
|
||||||
ui->scenes->setCurrentText(name.c_str());
|
|
||||||
ui->windows->setCurrentText(window);
|
|
||||||
ui->transitions->setCurrentText(transitionName.c_str());
|
|
||||||
ui->fullscreenCheckBox->setChecked(s.fullscreen);
|
|
||||||
ui->maximizedCheckBox->setChecked(s.maximized);
|
|
||||||
ui->focusCheckBox->setChecked(s.focus);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_ignoreWindows_currentRowChanged(int idx)
|
|
||||||
{
|
|
||||||
if (loading)
|
|
||||||
return;
|
|
||||||
if (idx == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QListWidgetItem *item = ui->ignoreWindows->item(idx);
|
|
||||||
|
|
||||||
QString window = item->data(Qt::UserRole).toString();
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
for (auto &s : switcher->ignoreWindowsSwitches) {
|
|
||||||
if (window.compare(s.c_str()) == 0) {
|
|
||||||
ui->ignoreWindowsWindows->setCurrentText(s.c_str());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SwitcherData::checkWindowTitleSwitch(bool &match, OBSWeakSource &scene,
|
void SwitcherData::checkWindowTitleSwitch(bool &match, OBSWeakSource &scene,
|
||||||
OBSWeakSource &transition)
|
OBSWeakSource &transition)
|
||||||
{
|
{
|
||||||
@@ -293,7 +215,10 @@ void SwitcherData::checkWindowTitleSwitch(bool &match, OBSWeakSource &scene,
|
|||||||
lastTitle = title;
|
lastTitle = title;
|
||||||
|
|
||||||
// Check for match
|
// Check for match
|
||||||
for (WindowSceneSwitch &s : windowSwitches) {
|
for (WindowSwitch &s : windowSwitches) {
|
||||||
|
if (!s.initialized())
|
||||||
|
continue;
|
||||||
|
|
||||||
// True if fullscreen is disabled OR current window is fullscreen
|
// True if fullscreen is disabled OR current window is fullscreen
|
||||||
bool fullscreen = (!s.fullscreen || isFullscreen(s.window));
|
bool fullscreen = (!s.fullscreen || isFullscreen(s.window));
|
||||||
// True if maximized is disabled OR current window is maximized
|
// True if maximized is disabled OR current window is maximized
|
||||||
@@ -324,7 +249,7 @@ void SwitcherData::checkWindowTitleSwitch(bool &match, OBSWeakSource &scene,
|
|||||||
void SwitcherData::saveWindowTitleSwitches(obs_data_t *obj)
|
void SwitcherData::saveWindowTitleSwitches(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
obs_data_array_t *windowTitleArray = obs_data_array_create();
|
obs_data_array_t *windowTitleArray = obs_data_array_create();
|
||||||
for (WindowSceneSwitch &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);
|
obs_source_t *source = obs_weak_source_get_source(s.scene);
|
||||||
@@ -344,9 +269,9 @@ void SwitcherData::saveWindowTitleSwitches(obs_data_t *obj)
|
|||||||
obs_data_set_bool(array_obj, "maximized", s.maximized);
|
obs_data_set_bool(array_obj, "maximized", s.maximized);
|
||||||
obs_data_set_bool(array_obj, "focus", s.focus);
|
obs_data_set_bool(array_obj, "focus", s.focus);
|
||||||
obs_data_array_push_back(windowTitleArray, array_obj);
|
obs_data_array_push_back(windowTitleArray, array_obj);
|
||||||
obs_source_release(source);
|
|
||||||
obs_source_release(transition);
|
|
||||||
}
|
}
|
||||||
|
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);
|
||||||
@@ -420,26 +345,22 @@ void SwitcherData::loadWindowTitleSwitches(obs_data_t *obj)
|
|||||||
obs_data_array_release(ignoreWindowsArray);
|
obs_data_array_release(ignoreWindowsArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::setupTitleTab()
|
void AdvSceneSwitcher::setupTitleTab()
|
||||||
{
|
{
|
||||||
populateSceneSelection(ui->scenes, false);
|
|
||||||
populateTransitionSelection(ui->transitions);
|
|
||||||
populateWindowSelection(ui->windows);
|
|
||||||
populateWindowSelection(ui->ignoreWindowsWindows);
|
|
||||||
|
|
||||||
for (auto &s : switcher->windowSwitches) {
|
for (auto &s : switcher->windowSwitches) {
|
||||||
std::string sceneName = GetWeakSourceName(s.scene);
|
QListWidgetItem *item;
|
||||||
std::string transitionName = GetWeakSourceName(s.transition);
|
item = new QListWidgetItem(ui->windowSwitches);
|
||||||
QString text = MakeWindowSwitchName(sceneName.c_str(),
|
ui->windowSwitches->addItem(item);
|
||||||
s.window.c_str(),
|
WindowSwitchWidget *sw = new WindowSwitchWidget(&s);
|
||||||
transitionName.c_str(),
|
item->setSizeHint(sw->minimumSizeHint());
|
||||||
s.fullscreen, s.maximized,
|
ui->windowSwitches->setItemWidget(item, sw);
|
||||||
s.focus);
|
|
||||||
|
|
||||||
QListWidgetItem *item = new QListWidgetItem(text, ui->switches);
|
|
||||||
item->setData(Qt::UserRole, s.window.c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (switcher->windowSwitches.size() == 0)
|
||||||
|
addPulse = PulseWidget(ui->windowAdd, QColor(Qt::green));
|
||||||
|
|
||||||
|
populateWindowSelection(ui->ignoreWindowsWindows);
|
||||||
|
|
||||||
for (auto &window : switcher->ignoreWindowsSwitches) {
|
for (auto &window : switcher->ignoreWindowsSwitches) {
|
||||||
QString text = QString::fromStdString(window);
|
QString text = QString::fromStdString(window);
|
||||||
|
|
||||||
@@ -447,36 +368,110 @@ void SceneSwitcher::setupTitleTab()
|
|||||||
new QListWidgetItem(text, ui->ignoreWindows);
|
new QListWidgetItem(text, ui->ignoreWindows);
|
||||||
item->setData(Qt::UserRole, text);
|
item->setData(Qt::UserRole, text);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowSwitchWidget::WindowSwitchWidget(WindowSwitch *s) : SwitchWidget(s, false)
|
||||||
|
{
|
||||||
|
windows = new QComboBox();
|
||||||
|
fullscreen = new QCheckBox("if fullscreen");
|
||||||
|
maximized = new QCheckBox("if maximized");
|
||||||
|
focused = new QCheckBox("if focused");
|
||||||
|
|
||||||
|
QWidget::connect(windows, SIGNAL(currentTextChanged(const QString &)),
|
||||||
|
this, SLOT(WindowChanged(const QString &)));
|
||||||
|
QWidget::connect(fullscreen, SIGNAL(stateChanged(int)), this,
|
||||||
|
SLOT(FullscreenChanged(int)));
|
||||||
|
QWidget::connect(maximized, SIGNAL(stateChanged(int)), this,
|
||||||
|
SLOT(MaximizedChanged(int)));
|
||||||
|
QWidget::connect(focused, SIGNAL(stateChanged(int)), this,
|
||||||
|
SLOT(FocusChanged(int)));
|
||||||
|
|
||||||
|
AdvSceneSwitcher::populateWindowSelection(windows);
|
||||||
|
|
||||||
|
windows->setEditable(true);
|
||||||
|
windows->setMaxVisibleItems(20);
|
||||||
#if __APPLE__
|
#if __APPLE__
|
||||||
// TODO:
|
// TODO:
|
||||||
// not implemented on MacOS as I cannot test it
|
// not implemented on MacOS as I cannot test it
|
||||||
ui->maximizedCheckBox->setDisabled(true);
|
maximized->setDisabled(true);
|
||||||
ui->maximizedCheckBox->setVisible(false);
|
maximized->setVisible(false);
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
static inline QString MakeWindowSwitchName(const QString &scene,
|
if (s) {
|
||||||
const QString &value,
|
windows->setCurrentText(s->window.c_str());
|
||||||
const QString &transition,
|
fullscreen->setChecked(s->fullscreen);
|
||||||
bool fullscreen, bool maximized,
|
maximized->setChecked(s->maximized);
|
||||||
bool focus)
|
focused->setChecked(s->focus);
|
||||||
{
|
|
||||||
QString name = QStringLiteral("[") + scene + QStringLiteral(", ") +
|
|
||||||
transition + QStringLiteral("]: ") + value;
|
|
||||||
|
|
||||||
if (fullscreen || maximized || focus) {
|
|
||||||
name += QStringLiteral(" (only if");
|
|
||||||
|
|
||||||
if (fullscreen)
|
|
||||||
name += QStringLiteral(" fullscreen ");
|
|
||||||
if (maximized)
|
|
||||||
name += QStringLiteral(" maximized ");
|
|
||||||
if (focus)
|
|
||||||
name += QStringLiteral(" focused");
|
|
||||||
|
|
||||||
name += QStringLiteral(")");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return name;
|
setStyleSheet("* { background-color: transparent; }");
|
||||||
|
|
||||||
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
|
||||||
|
mainLayout->addWidget(windows);
|
||||||
|
mainLayout->addWidget(scenes);
|
||||||
|
mainLayout->addWidget(transitions);
|
||||||
|
mainLayout->addWidget(scenes);
|
||||||
|
mainLayout->addWidget(fullscreen);
|
||||||
|
mainLayout->addWidget(maximized);
|
||||||
|
mainLayout->addWidget(focused);
|
||||||
|
mainLayout->addStretch();
|
||||||
|
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
switchData = s;
|
||||||
|
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowSwitch *WindowSwitchWidget::getSwitchData()
|
||||||
|
{
|
||||||
|
return switchData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowSwitchWidget::setSwitchData(WindowSwitch *s)
|
||||||
|
{
|
||||||
|
switchData = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowSwitchWidget::swapSwitchData(WindowSwitchWidget *s1,
|
||||||
|
WindowSwitchWidget *s2)
|
||||||
|
{
|
||||||
|
SwitchWidget::swapSwitchData(s1, s2);
|
||||||
|
|
||||||
|
WindowSwitch *t = s1->getSwitchData();
|
||||||
|
s1->setSwitchData(s2->getSwitchData());
|
||||||
|
s2->setSwitchData(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowSwitchWidget::WindowChanged(const QString &text)
|
||||||
|
{
|
||||||
|
if (loading || !switchData)
|
||||||
|
return;
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->window = text.toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowSwitchWidget::FullscreenChanged(int state)
|
||||||
|
{
|
||||||
|
if (loading || !switchData)
|
||||||
|
return;
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->fullscreen = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowSwitchWidget::MaximizedChanged(int state)
|
||||||
|
{
|
||||||
|
if (loading || !switchData)
|
||||||
|
return;
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->maximized = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowSwitchWidget::FocusChanged(int state)
|
||||||
|
{
|
||||||
|
if (loading || !switchData)
|
||||||
|
return;
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->focus = state;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
void SwitcherData::Prune()
|
void SwitcherData::Prune()
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < windowSwitches.size(); i++) {
|
for (size_t i = 0; i < windowSwitches.size(); i++) {
|
||||||
WindowSceneSwitch &s = windowSwitches[i];
|
WindowSwitch &s = windowSwitches[i];
|
||||||
if (!s.valid())
|
if (!s.valid())
|
||||||
windowSwitches.erase(windowSwitches.begin() + i--);
|
windowSwitches.erase(windowSwitches.begin() + i--);
|
||||||
}
|
}
|
||||||
@@ -60,7 +60,7 @@ void SwitcherData::Prune()
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < executableSwitches.size(); i++) {
|
for (size_t i = 0; i < executableSwitches.size(); i++) {
|
||||||
ExecutableSceneSwitch &s = executableSwitches[i];
|
ExecutableSwitch &s = executableSwitches[i];
|
||||||
if (!s.valid())
|
if (!s.valid())
|
||||||
executableSwitches.erase(executableSwitches.begin() +
|
executableSwitches.erase(executableSwitches.begin() +
|
||||||
i--);
|
i--);
|
||||||
|
|||||||
@@ -3,13 +3,16 @@
|
|||||||
#include "../headers/advanced-scene-switcher.hpp"
|
#include "../headers/advanced-scene-switcher.hpp"
|
||||||
#include <TlHelp32.h>
|
#include <TlHelp32.h>
|
||||||
#include <Psapi.h>
|
#include <Psapi.h>
|
||||||
|
#include <locale>
|
||||||
|
#include <codecvt>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
using namespace std;
|
#define MAX_SEARCH 1000
|
||||||
|
|
||||||
static bool GetWindowTitle(HWND window, string &title)
|
static bool GetWindowTitle(HWND window, std::string &title)
|
||||||
{
|
{
|
||||||
size_t len = (size_t)GetWindowTextLengthW(window);
|
size_t len = (size_t)GetWindowTextLengthW(window);
|
||||||
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))
|
||||||
@@ -40,45 +43,67 @@ static bool WindowValid(HWND window)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetWindowList(vector<string> &windows)
|
BOOL CALLBACK GetTitleCB(HWND hwnd, LPARAM lParam)
|
||||||
{
|
{
|
||||||
windows.resize(0);
|
if (!WindowValid(hwnd)) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
HWND window = GetWindow(GetDesktopWindow(), GW_CHILD);
|
std::string title;
|
||||||
|
GetWindowTitle(hwnd, title);
|
||||||
|
if (title.empty())
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
while (window) {
|
std::vector<std::string> &titles =
|
||||||
string title;
|
*reinterpret_cast<std::vector<std::string> *>(lParam);
|
||||||
if (WindowValid(window) && GetWindowTitle(window, title))
|
titles.push_back(title);
|
||||||
windows.emplace_back(title);
|
|
||||||
window = GetNextWindow(window, GW_HWNDNEXT);
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID EnumWindowsWithMetro(__in WNDENUMPROC lpEnumFunc, __in LPARAM lParam)
|
||||||
|
{
|
||||||
|
HWND childWindow = NULL;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (i < MAX_SEARCH &&
|
||||||
|
(childWindow = FindWindowEx(NULL, childWindow, NULL, NULL))) {
|
||||||
|
if (!lpEnumFunc(childWindow, lParam))
|
||||||
|
return;
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overloaded
|
void GetWindowList(std::vector<std::string> &windows)
|
||||||
|
{
|
||||||
|
windows.resize(0);
|
||||||
|
EnumWindowsWithMetro(GetTitleCB, reinterpret_cast<LPARAM>(&windows));
|
||||||
|
}
|
||||||
|
|
||||||
void GetWindowList(QStringList &windows)
|
void GetWindowList(QStringList &windows)
|
||||||
{
|
{
|
||||||
windows.clear();
|
windows.clear();
|
||||||
|
|
||||||
HWND window = GetWindow(GetDesktopWindow(), GW_CHILD);
|
std::vector<std::string> w;
|
||||||
|
GetWindowList(w);
|
||||||
while (window) {
|
for (auto window : w) {
|
||||||
string title;
|
windows << QString::fromStdString(window);
|
||||||
if (WindowValid(window) && GetWindowTitle(window, title))
|
|
||||||
windows << QString::fromStdString(title);
|
|
||||||
window = GetNextWindow(window, GW_HWNDNEXT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add entry for OBS Studio itself, see GetCurrentWindowTitle
|
||||||
|
windows << QString("OBS");
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetCurrentWindowTitle(string &title)
|
void GetCurrentWindowTitle(std::string &title)
|
||||||
{
|
{
|
||||||
HWND window = GetForegroundWindow();
|
HWND window = GetForegroundWindow();
|
||||||
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;
|
||||||
@@ -97,22 +122,26 @@ std::pair<int, int> getCursorPos()
|
|||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HWND getHWNDfromTitle(std::string title)
|
||||||
|
{
|
||||||
|
HWND hwnd = NULL;
|
||||||
|
|
||||||
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||||
|
std::wstring wTitle = converter.from_bytes(title);
|
||||||
|
|
||||||
|
hwnd = FindWindowEx(NULL, NULL, NULL, wTitle.c_str());
|
||||||
|
return hwnd;
|
||||||
|
}
|
||||||
|
|
||||||
bool isMaximized(std::string &title)
|
bool isMaximized(std::string &title)
|
||||||
{
|
{
|
||||||
RECT appBounds;
|
RECT appBounds;
|
||||||
MONITORINFO monitorInfo = {0};
|
MONITORINFO monitorInfo = {0};
|
||||||
|
HWND hwnd = NULL;
|
||||||
|
|
||||||
HWND hwnd = GetWindow(GetDesktopWindow(), GW_CHILD);
|
hwnd = getHWNDfromTitle(title);
|
||||||
while (hwnd) {
|
if (!hwnd)
|
||||||
string wtitle;
|
return false;
|
||||||
if (WindowValid(hwnd) && GetWindowTitle(hwnd, wtitle) &&
|
|
||||||
(wtitle == title ||
|
|
||||||
QString::fromStdString(wtitle).contains(QRegularExpression(
|
|
||||||
QString::fromStdString(title)))))
|
|
||||||
break;
|
|
||||||
|
|
||||||
hwnd = GetNextWindow(hwnd, GW_HWNDNEXT);
|
|
||||||
}
|
|
||||||
|
|
||||||
monitorInfo.cbSize = sizeof(MONITORINFO);
|
monitorInfo.cbSize = sizeof(MONITORINFO);
|
||||||
GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST),
|
GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST),
|
||||||
@@ -138,17 +167,11 @@ bool isFullscreen(std::string &title)
|
|||||||
RECT appBounds;
|
RECT appBounds;
|
||||||
MONITORINFO monitorInfo = {0};
|
MONITORINFO monitorInfo = {0};
|
||||||
|
|
||||||
HWND hwnd = GetWindow(GetDesktopWindow(), GW_CHILD);
|
HWND hwnd = NULL;
|
||||||
while (hwnd) {
|
hwnd = getHWNDfromTitle(title);
|
||||||
string wtitle;
|
|
||||||
if (WindowValid(hwnd) && GetWindowTitle(hwnd, wtitle) &&
|
|
||||||
(wtitle == title ||
|
|
||||||
QString::fromStdString(wtitle).contains(QRegularExpression(
|
|
||||||
QString::fromStdString(title)))))
|
|
||||||
break;
|
|
||||||
|
|
||||||
hwnd = GetNextWindow(hwnd, GW_HWNDNEXT);
|
if (!hwnd)
|
||||||
}
|
return false;
|
||||||
|
|
||||||
monitorInfo.cbSize = sizeof(MONITORINFO);
|
monitorInfo.cbSize = sizeof(MONITORINFO);
|
||||||
GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST),
|
GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST),
|
||||||
|
|||||||
Reference in New Issue
Block a user