Compare commits

..

2 Commits

Author SHA1 Message Date
WarmUpTill
5d568683f7 Update obs-websocket-api.h 2025-07-06 11:06:25 +02:00
WarmUpTill
a26c37021d Fix crash on OBS shutdown 2025-07-06 11:06:22 +02:00
433 changed files with 10701 additions and 38624 deletions

View File

@@ -19,9 +19,14 @@ inputs:
runs: runs:
using: 'composite' using: 'composite'
steps: steps:
- name: Setup cmake
uses: jwlawson/actions-setup-cmake@v1.13
with:
cmake-version: '3.24.x'
- name: Restore cached dependencies - name: Restore cached dependencies
id: restore-cache id: restore-cache
uses: actions/cache@v5 uses: actions/cache@v4
with: with:
path: ${{ env.DEP_DIR }} path: ${{ env.DEP_DIR }}
key: ${{ env.DEP_DIR }}-${{ runner.os }}-${{ inputs.target }} key: ${{ env.DEP_DIR }}-${{ runner.os }}-${{ inputs.target }}

View File

@@ -29,7 +29,6 @@ runs:
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
echo "/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin" >> $GITHUB_PATH echo "/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin" >> $GITHUB_PATH
echo "/home/linuxbrew/.linuxbrew/opt/clang-format@16/bin" >> $GITHUB_PATH echo "/home/linuxbrew/.linuxbrew/opt/clang-format@16/bin" >> $GITHUB_PATH
brew update
brew install --quiet zsh brew install --quiet zsh
echo ::endgroup:: echo ::endgroup::
@@ -53,7 +52,6 @@ runs:
if (( ${changes[(I)(*.c|*.h|*.cpp|*.hpp|*.m|*.mm)]} )) { if (( ${changes[(I)(*.c|*.h|*.cpp|*.hpp|*.m|*.mm)]} )) {
echo ::group::Install clang-format-16 echo ::group::Install clang-format-16
brew update
brew install --quiet obsproject/tools/clang-format@16 brew install --quiet obsproject/tools/clang-format@16
echo ::endgroup:: echo ::endgroup::

View File

@@ -8,7 +8,6 @@ package 'libcurl4-openssl-dev'
package 'libxtst-dev' package 'libxtst-dev'
package 'libxss-dev' package 'libxss-dev'
package 'libopencv-dev' package 'libopencv-dev'
package 'libopencv-contrib-dev'
package 'libtesseract-dev' package 'libtesseract-dev'
package 'libproc2-dev' package 'libproc2-dev'
package 'libusb-1.0-0-dev' package 'libusb-1.0-0-dev'

View File

@@ -1,4 +1,4 @@
package 'cmake', path: 'Cmake\bin', bin: 'cmake' package 'cmake', path: 'Cmake\bin', bin: 'cmake'
package 'innosetup', path: 'Inno Setup 6', bin: 'iscc' package 'innosetup', path: 'Inno Setup 6', bin: 'iscc'
package 'OpenSSL', path: 'OpenSSL', bin: 'openssl', version: '3.6.2' package 'OpenSSL', path: 'OpenSSL', bin: 'openssl'
package 'Microsoft.VisualStudio.Locator', path: 'vswhere', bin: 'vswhere' package 'Microsoft.VisualStudio.Locator', path: 'vswhere', bin: 'vswhere'

View File

@@ -284,56 +284,30 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
case ${host_os} { case ${host_os} {
macos) macos)
local opencv_dir="${project_root}/deps/opencv" local opencv_dir="${project_root}/deps/opencv"
local opencv_contrib_dir="${project_root}/deps/opencv_contrib" local opencv_build_dir="${opencv_dir}/build_${target##*-}"
local opencv_install_x86="${opencv_dir}/install_x86_64"
local opencv_install_arm="${opencv_dir}/install_arm64"
local -a opencv_cmake_args_common=( local -a opencv_cmake_args=(
-DCMAKE_BUILD_TYPE=Release -DCMAKE_BUILD_TYPE=Release
-DBUILD_LIST=core,imgproc,objdetect,xobjdetect,dnn -DBUILD_LIST=core,imgproc,objdetect
-DOPENCV_EXTRA_MODULES_PATH="${opencv_contrib_dir}/modules" -DCMAKE_OSX_ARCHITECTURES=${${target##*-}//universal/x86_64;arm64}
-DCMAKE_OSX_DEPLOYMENT_TARGET=${DEPLOYMENT_TARGET:-10.15} -DCMAKE_OSX_DEPLOYMENT_TARGET=${DEPLOYMENT_TARGET:-10.15}
-DCMAKE_PREFIX_PATH="${advss_dep_path};${_plugin_deps}" -DCMAKE_PREFIX_PATH="${advss_dep_path};${_plugin_deps}"
-DWITH_KLEIDICV=OFF -DCMAKE_INSTALL_PREFIX="${advss_dep_path}"
) )
if [ "${target}" != "macos-x86_64" ]; then
opencv_cmake_args+=(-DWITH_IPP=OFF)
fi
pushd ${opencv_dir} pushd ${opencv_dir}
log_info "Configure OpenCV ..."
cmake -S . -B ${opencv_build_dir} ${opencv_cmake_args}
log_info "Configure OpenCV (x86_64) ..." log_info "Building OpenCV ..."
cmake -S . -B build_x86_64 ${opencv_cmake_args_common} \ cmake --build ${opencv_build_dir} --config Release
-DCMAKE_OSX_ARCHITECTURES=x86_64 \
-DCMAKE_PROJECT_INCLUDE="${SCRIPT_HOME}/opencv-force-processor-x86_64.cmake" \
-DCMAKE_INSTALL_PREFIX="${opencv_install_x86}" \
-DWITH_IPP=OFF
log_info "Building OpenCV (x86_64) ..." log_info "Installing OpenCV ..."
cmake --build build_x86_64 --config Release cmake --install ${opencv_build_dir} --prefix "${advss_dep_path}" --config Release || true
log_info "Installing OpenCV (x86_64) ..."
cmake --install build_x86_64 --prefix "${opencv_install_x86}" --config Release || true
log_info "Configure OpenCV (arm64) ..."
cmake -S . -B build_arm64 ${opencv_cmake_args_common} \
-DCMAKE_OSX_ARCHITECTURES=arm64 \
-DCMAKE_INSTALL_PREFIX="${opencv_install_arm}"
log_info "Building OpenCV (arm64) ..."
cmake --build build_arm64 --config Release
log_info "Installing OpenCV (arm64) ..."
cmake --install build_arm64 --prefix "${opencv_install_arm}" --config Release || true
log_info "Merging OpenCV into universal binaries ..."
cp -R "${opencv_install_arm}/." "${advss_dep_path}"
for arm_lib in ${opencv_install_arm}/lib/**/*.(dylib|a)(.); do
local rel="${arm_lib#${opencv_install_arm}/}"
local x86_lib="${opencv_install_x86}/${rel}"
if [[ -f "${x86_lib}" ]]; then
lipo -create "${x86_lib}" "${arm_lib}" -output "${advss_dep_path}/${rel}"
fi
done
rm -rf "${opencv_install_x86}" "${opencv_install_arm}"
popd popd
local leptonica_dir="${project_root}/deps/leptonica" local leptonica_dir="${project_root}/deps/leptonica"
@@ -345,7 +319,7 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
-DCMAKE_OSX_DEPLOYMENT_TARGET=${DEPLOYMENT_TARGET:-10.15} -DCMAKE_OSX_DEPLOYMENT_TARGET=${DEPLOYMENT_TARGET:-10.15}
-DSW_BUILD=OFF -DSW_BUILD=OFF
-DOPENJPEG_SUPPORT=OFF -DOPENJPEG_SUPPORT=OFF
-DENABLE_WEBP=OFF -DLIBWEBP_SUPPORT=OFF
-DCMAKE_DISABLE_FIND_PACKAGE_GIF=TRUE -DCMAKE_DISABLE_FIND_PACKAGE_GIF=TRUE
-DCMAKE_DISABLE_FIND_PACKAGE_JPEG=TRUE -DCMAKE_DISABLE_FIND_PACKAGE_JPEG=TRUE
-DCMAKE_DISABLE_FIND_PACKAGE_TIFF=TRUE -DCMAKE_DISABLE_FIND_PACKAGE_TIFF=TRUE
@@ -420,11 +394,8 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
popd popd
pushd ${advss_dep_path}
log_info "Prepare openssl ..." log_info "Prepare openssl ..."
rm -rf ${advss_dep_path}/openssl ${advss_dep_path}/openssl_build
mkdir ${advss_dep_path}/openssl_build
pushd ${advss_dep_path}/openssl_build
rm -rf openssl rm -rf openssl
git clone https://github.com/openssl/openssl.git --branch openssl-3.1.2 --depth 1 git clone https://github.com/openssl/openssl.git --branch openssl-3.1.2 --depth 1
mv openssl openssl_x86 mv openssl openssl_x86
@@ -432,27 +403,25 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
log_info "Building openssl x86 ..." log_info "Building openssl x86 ..."
export MACOSX_DEPLOYMENT_TARGET=10.9 export MACOSX_DEPLOYMENT_TARGET=10.9
pushd openssl_x86 cd openssl_x86
./Configure darwin64-x86_64-cc no-shared no-module no-zlib --prefix=${advss_dep_path} ./Configure darwin64-x86_64-cc shared
make -j$(nproc) make
popd
log_info "Building openssl arm ..." log_info "Building openssl arm ..."
export MACOSX_DEPLOYMENT_TARGET=10.15 export MACOSX_DEPLOYMENT_TARGET=10.15
pushd openssl_arm cd ../openssl_arm
./Configure enable-rc5 darwin64-arm64-cc no-shared no-module no-asm no-zlib --prefix=${advss_dep_path} ./Configure enable-rc5 zlib darwin64-arm64-cc no-asm
make -j$(nproc) make
log_info "Install openssl ..."
make install
popd
log_info "Combine arm and x86 openssl binaries ..." log_info "Combine arm and x86 openssl binaries ..."
lipo -create openssl_x86/libcrypto.a openssl_arm/libcrypto.a -output ${advss_dep_path}/lib/libcrypto.a cd ..
lipo -create openssl_x86/libssl.a openssl_arm/libssl.a -output ${advss_dep_path}/lib/libssl.a mkdir openssl-combined
lipo -create openssl_x86/libcrypto.a openssl_arm/libcrypto.a -output openssl-combined/libcrypto.a
lipo -create openssl_x86/libssl.a openssl_arm/libssl.a -output openssl-combined/libssl.a
log_info "Clean up openssl dir ..." log_info "Clean up openssl dir ..."
rm -rf openssl_x86 openssl_arm mv openssl_x86 openssl
rm -rf openssl_arm
popd popd
pushd ${project_root}/deps/libusb pushd ${project_root}/deps/libusb
@@ -470,16 +439,14 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
mkdir ${project_root}/deps/libusb/out_x86 mkdir ${project_root}/deps/libusb/out_x86
./autogen.sh ./autogen.sh
./configure --host=x86_64-apple-darwin --prefix=${advss_dep_path} ./configure --host=x86_64-apple-darwin --prefix=${advss_dep_path}
make -j$(nproc) make && make install
make install
log_info "Configure libusb arm ..." log_info "Configure libusb arm ..."
make clean make clean
rm -r ${project_root}/deps/libusb/out_x86 rm -r ${project_root}/deps/libusb/out_x86
mkdir ${project_root}/deps/libusb/out_x86 mkdir ${project_root}/deps/libusb/out_x86
./configure --host=aarch64-apple-darwin --prefix=${project_root}/deps/libusb/out_x86 ./configure --host=aarch64-apple-darwin --prefix=${project_root}/deps/libusb/out_x86
make -j$(nproc) make && make install
make install
log_info "Building libusb arm ..." log_info "Building libusb arm ..."
make clean make clean
@@ -492,8 +459,7 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
export MACOSX_DEPLOYMENT_TARGET=10.15 export MACOSX_DEPLOYMENT_TARGET=10.15
mkdir ${project_root}/deps/libusb/out_arm mkdir ${project_root}/deps/libusb/out_arm
./configure --host=aarch64-apple-darwin --prefix=${project_root}/deps/libusb/out_arm ./configure --host=aarch64-apple-darwin --prefix=${project_root}/deps/libusb/out_arm
make -j$(nproc) make && make install
make install
log_info "Combine arm and x86 libusb binaries ..." log_info "Combine arm and x86 libusb binaries ..."
lipo -create ${project_root}/deps/libusb/out_x86/lib/libusb-1.0.0.dylib \ lipo -create ${project_root}/deps/libusb/out_x86/lib/libusb-1.0.0.dylib \
@@ -525,8 +491,8 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
-DPAHO_BUILD_SHARED=OFF -DPAHO_BUILD_SHARED=OFF
-DPAHO_BUILD_STATIC=ON -DPAHO_BUILD_STATIC=ON
-DPAHO_WITH_MQTT_C=ON -DPAHO_WITH_MQTT_C=ON
-DPAHO_WITH_SSL=ON -DOPENSSL_ROOT_DIR="${advss_dep_path}"
-DOPENSSL_USE_STATIC_LIBS=ON -DPAHO_WITH_SSL=OFF # TODO: figure out linking issues with openssl
) )
pushd ${mqtt_dir} pushd ${mqtt_dir}

View File

@@ -253,12 +253,12 @@ ${_usage_host:-}"
macos-*) macos-*)
if (( ${+CI} )) typeset -gx NSUnbufferedIO=YES if (( ${+CI} )) typeset -gx NSUnbufferedIO=YES
local openssl_lib_dir="${advss_deps_path}/openssl-combined/"
local openssl_include_dir="${advss_deps_path}/openssl/include"
cmake_args+=( cmake_args+=(
-DCMAKE_PREFIX_PATH="${advss_deps_path}" -DOPENSSL_INCLUDE_DIR="${openssl_include_dir}"
-DOPENSSL_ROOT_DIR="${advss_deps_path}" -DOPENSSL_LIBRARIES="${openssl_lib_dir}/libcrypto.a;${openssl_lib_dir}/libssl.a"
-DOPENSSL_INCLUDE_DIR="${advss_deps_path}/include"
-DOPENSSL_CRYPTO_LIBRARY="${advss_deps_path}/lib/libcrypto.a"
-DOPENSSL_SSL_LIBRARY="${advss_deps_path}/lib/libssl.a"
--preset ${_preset} --preset ${_preset}
) )

View File

@@ -258,9 +258,6 @@ ${_usage_host:-}"
pushd ${project_root} pushd ${project_root}
cmake --build build_${target##*-} --config ${config} -t package ${cmake_args} cmake --build build_${target##*-} --config ${config} -t package ${cmake_args}
# Mark certain deps as optional
build-aux/CI/linux/demote-deps.sh ${project_root}/release/*.deb Recommends '(mqtt)|(opencv)|(tesseract)|(usb)|(x11)|(libobs)'
if [ ! -e ${project_root}/release/${output_name}.deb ]; then if [ ! -e ${project_root}/release/${output_name}.deb ]; then
mv ${project_root}/release/*.deb ${project_root}/release/${output_name}.deb mv ${project_root}/release/*.deb ${project_root}/release/${output_name}.deb
mv ${project_root}/release/*.ddeb ${project_root}/release/${output_name}.ddeb mv ${project_root}/release/*.ddeb ${project_root}/release/${output_name}.ddeb

View File

@@ -106,7 +106,6 @@ function Build {
$ADVSSDepPath = "$(Resolve-Path -Path ${ProjectRoot}/${OutDirName})" $ADVSSDepPath = "$(Resolve-Path -Path ${ProjectRoot}/${OutDirName})"
$OpenCVPath = "${ProjectRoot}/deps/opencv" $OpenCVPath = "${ProjectRoot}/deps/opencv"
$OpenCVContribPath = "${ProjectRoot}/deps/opencv_contrib"
$OpenCVBuildPath = "${OpenCVPath}/build" $OpenCVBuildPath = "${OpenCVPath}/build"
Push-Location -Stack BuildOpenCVTemp Push-Location -Stack BuildOpenCVTemp
@@ -116,8 +115,7 @@ function Build {
"-DCMAKE_BUILD_TYPE=Release" "-DCMAKE_BUILD_TYPE=Release"
"-DCMAKE_PREFIX_PATH:PATH=${OBSDepPath}" "-DCMAKE_PREFIX_PATH:PATH=${OBSDepPath}"
"-DCMAKE_INSTALL_PREFIX:PATH=${ADVSSDepPath}" "-DCMAKE_INSTALL_PREFIX:PATH=${ADVSSDepPath}"
"-DBUILD_LIST=core,imgproc,objdetect,xobjdetect" "-DBUILD_LIST=core,imgproc,objdetect"
"-DOPENCV_EXTRA_MODULES_PATH:PATH=${OpenCVContribPath}/modules"
) )
Log-Information "Configuring OpenCV..." Log-Information "Configuring OpenCV..."
@@ -211,9 +209,7 @@ function Build {
$msbuildExe = vswhere -latest -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe | select-object -first 1 $msbuildExe = vswhere -latest -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe | select-object -first 1
if ($msbuildExe) { if ($msbuildExe) {
$env:CL="/wd5287"
Invoke-External $msbuildExe "${LibusbPath}/msvc/libusb.sln" /property:Configuration=Release /property:Platform=x64 Invoke-External $msbuildExe "${LibusbPath}/msvc/libusb.sln" /property:Configuration=Release /property:Platform=x64
Remove-Item Env:CL
$libusbBuildResultDirectory = "${LibusbPath}/build/v143/x64/Release" $libusbBuildResultDirectory = "${LibusbPath}/build/v143/x64/Release"
if (-not (Test-Path -Path $libusbBuildResultDirectory)) { if (-not (Test-Path -Path $libusbBuildResultDirectory)) {
@@ -236,24 +232,8 @@ function Build {
"-DCMAKE_PREFIX_PATH:PATH=${OBSDepPath}" "-DCMAKE_PREFIX_PATH:PATH=${OBSDepPath}"
"-DCMAKE_INSTALL_PREFIX:PATH=${ADVSSDepPath}" "-DCMAKE_INSTALL_PREFIX:PATH=${ADVSSDepPath}"
"-DPAHO_WITH_MQTT_C=ON" "-DPAHO_WITH_MQTT_C=ON"
"-DPAHO_WITH_SSL=ON"
) )
# Try to find OpenSSL installed via winget
$pf64 = Join-Path $Env:ProgramFiles "OpenSSL-Win64"
$pf = Join-Path $Env:ProgramFiles "OpenSSL"
$possibleDirs = @($pf64, $pf)
$opensslDir = $possibleDirs | Where-Object { Test-Path (Join-Path $_ "include\openssl\ssl.h") } | Select-Object -First 1
if ($opensslDir) {
Write-Host "Detected OpenSSL at: $opensslDir"
$MqttCmakeArgs += "-DOPENSSL_ROOT_DIR=$opensslDir"
$MqttCmakeArgs += "-DOPENSSL_CRYPTO_LIBRARY=$opensslDir\lib\VC\x64\MD\libcrypto.lib"
$MqttCmakeArgs += "-DOPENSSL_SSL_LIBRARY=$opensslDir\lib\VC\x64\MD\libssl.lib"
} else {
Write-Warning "OpenSSL not found - maybe cmake will find it ..."
}
Log-Information "Configuring paho.mqtt.cpp..." Log-Information "Configuring paho.mqtt.cpp..."
Invoke-External cmake -S ${MqttPath} -B ${MqttBuildPath} @MqttCmakeArgs Invoke-External cmake -S ${MqttPath} -B ${MqttBuildPath} @MqttCmakeArgs

View File

@@ -68,53 +68,14 @@ function Package {
Remove-Item @RemoveArgs Remove-Item @RemoveArgs
$ReleasePath = "${ProjectRoot}/release/${Configuration}" Log-Group "Archiving ${ProductName}..."
$NewBinPath = "${ReleasePath}/${ProductName}/bin/64bit" $CompressArgs = @{
$NewDataPath = "${ReleasePath}/${ProductName}/data" Path = (Get-ChildItem -Path "${ProjectRoot}/release/${Configuration}" -Exclude "${OutputName}*.*")
$CIWindowsDir = "${ProjectRoot}/build-aux/CI/windows" CompressionLevel = 'Optimal'
DestinationPath = "${ProjectRoot}/release/${OutputName}.zip"
# --- Recommended zip (new layout, extract to %ProgramData%\obs-studio\) --- Verbose = ($Env:CI -ne $null)
Log-Group "Archiving ${ProductName} (recommended)..."
$RecStaging = "${ProjectRoot}/release/zip-staging-rec"
Remove-Item -Path $RecStaging -Recurse -Force -ErrorAction SilentlyContinue
New-Item -ItemType Directory -Force -Path $RecStaging | Out-Null
Copy-Item -Path "${CIWindowsDir}/README.txt" -Destination "${RecStaging}/README.txt"
if ( Test-Path -Path $NewBinPath ) {
$RecBinPath = "${RecStaging}/${ProductName}/bin/64bit"
New-Item -ItemType Directory -Force -Path $RecBinPath | Out-Null
Copy-Item -Path "${NewBinPath}/*" -Destination $RecBinPath -Recurse -Force
} }
if ( Test-Path -Path $NewDataPath ) { Compress-Archive -Force @CompressArgs
$RecDataPath = "${RecStaging}/${ProductName}/data"
New-Item -ItemType Directory -Force -Path $RecDataPath | Out-Null
Copy-Item -Path "${NewDataPath}/*" -Destination $RecDataPath -Recurse -Force
}
Compress-Archive -Force -Path (Get-ChildItem -Path $RecStaging) `
-CompressionLevel Optimal `
-DestinationPath "${ProjectRoot}/release/${OutputName}.zip"
Remove-Item -Path $RecStaging -Recurse -Force
Log-Group
# --- Legacy zip (old layout, extract to OBS install directory) ---
Log-Group "Archiving ${ProductName} (portable)..."
$PortableStaging = "${ProjectRoot}/release/zip-staging-portable"
Remove-Item -Path $PortableStaging -Recurse -Force -ErrorAction SilentlyContinue
New-Item -ItemType Directory -Force -Path $PortableStaging | Out-Null
Copy-Item -Path "${CIWindowsDir}/README-portable.txt" -Destination "${PortableStaging}/README.txt"
if ( Test-Path -Path $NewBinPath ) {
$PortableBinPath = "${PortableStaging}/obs-plugins/64bit"
New-Item -ItemType Directory -Force -Path $PortableBinPath | Out-Null
Copy-Item -Path "${NewBinPath}/*" -Destination $PortableBinPath -Recurse -Force
}
if ( Test-Path -Path $NewDataPath ) {
$PortableDataPath = "${PortableStaging}/data/obs-plugins/${ProductName}"
New-Item -ItemType Directory -Force -Path $PortableDataPath | Out-Null
Copy-Item -Path "${NewDataPath}/*" -Destination $PortableDataPath -Recurse -Force
}
Compress-Archive -Force -Path (Get-ChildItem -Path $PortableStaging) `
-CompressionLevel Optimal `
-DestinationPath "${ProjectRoot}/release/${OutputName}-portable.zip"
Remove-Item -Path $PortableStaging -Recurse -Force
Log-Group Log-Group
if ( ( $BuildInstaller ) ) { if ( ( $BuildInstaller ) ) {
@@ -128,25 +89,7 @@ function Package {
Log-Information 'Creating InnoSetup installer...' Log-Information 'Creating InnoSetup installer...'
Push-Location -Stack BuildTemp Push-Location -Stack BuildTemp
Ensure-Location -Path "${ProjectRoot}/release" Ensure-Location -Path "${ProjectRoot}/release"
Remove-Item -Path Package -Recurse -Force -ErrorAction SilentlyContinue Copy-Item -Path ${Configuration} -Destination Package -Recurse
# Recommended layout (for %ProgramData%\obs-studio\plugins\)
$PkgRec = "Package/recommended"
New-Item -ItemType Directory -Force -Path $PkgRec | Out-Null
Copy-Item -Path "${Configuration}/*" -Destination $PkgRec -Recurse -Force
# Legacy layout (for OBS installation directory)
if ( Test-Path "${Configuration}/${ProductName}/bin/64bit" ) {
$PkgLegBin = "Package/portable/obs-plugins/64bit"
New-Item -ItemType Directory -Force -Path $PkgLegBin | Out-Null
Copy-Item -Path "${Configuration}/${ProductName}/bin/64bit/*" -Destination $PkgLegBin -Recurse -Force
}
if ( Test-Path "${Configuration}/${ProductName}/data" ) {
$PkgLegData = "Package/portable/data/obs-plugins/${ProductName}"
New-Item -ItemType Directory -Force -Path $PkgLegData | Out-Null
Copy-Item -Path "${Configuration}/${ProductName}/data/*" -Destination $PkgLegData -Recurse -Force
}
Invoke-External iscc ${IsccFile} /O"${ProjectRoot}/release" /F"${OutputName}-Installer" Invoke-External iscc ${IsccFile} /O"${ProjectRoot}/release" /F"${OutputName}-Installer"
Remove-Item -Path Package -Recurse Remove-Item -Path Package -Recurse
Pop-Location -Stack BuildTemp Pop-Location -Stack BuildTemp

View File

@@ -1,7 +0,0 @@
# Injected via CMAKE_PROJECT_INCLUDE after opencv's project() call. Forces
# CMAKE_SYSTEM_PROCESSOR into the cache so that third-party subdirectories
# (mlas) that read the cache directly see x86_64 instead of the arm64 host
# processor on Apple Silicon CI runners.
set(CMAKE_SYSTEM_PROCESSOR
x86_64
CACHE INTERNAL "" FORCE)

View File

@@ -10,6 +10,7 @@ if (( ${+commands[ccache]} )) {
typeset -gx CCACHE_CONFIGPATH="${project_root}/.ccache.conf" typeset -gx CCACHE_CONFIGPATH="${project_root}/.ccache.conf"
ccache --set-config=run_second_cpp=true
ccache --set-config=direct_mode=true ccache --set-config=direct_mode=true
ccache --set-config=inode_cache=true ccache --set-config=inode_cache=true
ccache --set-config=compiler_check=content ccache --set-config=compiler_check=content

View File

@@ -35,21 +35,13 @@ if (( ! (${skips[(Ie)all]} + ${skips[(Ie)deps]}) )) {
sudo apt-get install ${apt_args} gcc-${${target##*-}//_/-}-linux-gnu g++-${${target##*-}//_/-}-linux-gnu sudo apt-get install ${apt_args} gcc-${${target##*-}//_/-}-linux-gnu g++-${${target##*-}//_/-}-linux-gnu
} }
local dist_version sudo add-apt-repository --yes ppa:obsproject/obs-studio
read -r dist_version <<< "$(source /etc/os-release; print "${VERSION_ID}")" sudo apt update
# The OBS PPA may not yet support newer Ubuntu versions. sudo apt-get install ${apt_args} \
# On those, use the native obs-studio packages and install libobs-dev separately, build-essential \
# as it is not bundled in obs-studio itself on newer Ubuntu releases. libgles2-mesa-dev \
local -a obs_packages=(build-essential libgles2-mesa-dev libsimde-dev obs-studio) obs-studio
if is-at-least 26.04 ${dist_version}; then
obs_packages+=(libobs-dev)
else
sudo add-apt-repository --yes ppa:obsproject/obs-studio
sudo apt update
fi
sudo apt-get install ${apt_args} ${obs_packages}
local -a _qt_packages=() local -a _qt_packages=()

View File

@@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
with: with:
submodules: "recursive" submodules: "recursive"
- name: check_libobs_revision - name: check_libobs_revision
@@ -50,7 +50,7 @@ jobs:
mv ../*.deb . mv ../*.deb .
- name: Publish - name: Publish
if: success() if: success()
uses: actions/upload-artifact@v7 uses: actions/upload-artifact@v4
with: with:
name: "obs-scene-switcher.deb" name: "obs-scene-switcher.deb"
path: ${{ github.workspace }}/*.deb path: ${{ github.workspace }}/*.deb

View File

@@ -6,7 +6,7 @@ on:
description: "Project name detected by parsing build spec file" description: "Project name detected by parsing build spec file"
value: ${{ jobs.check-event.outputs.pluginName }} value: ${{ jobs.check-event.outputs.pluginName }}
env: env:
DEP_DIR: .deps/advss-build-dependencies-6 DEP_DIR: .deps/advss-build-dependencies
jobs: jobs:
check-event: check-event:
name: Check GitHub Event Data 🔎 name: Check GitHub Event Data 🔎
@@ -22,7 +22,7 @@ jobs:
commitHash: ${{ steps.setup.outputs.commitHash }} commitHash: ${{ steps.setup.outputs.commitHash }}
pluginName: ${{ steps.setup.outputs.pluginName }} pluginName: ${{ steps.setup.outputs.pluginName }}
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Check Event Data ☑️ - name: Check Event Data ☑️
@@ -75,13 +75,13 @@ jobs:
macos-build: macos-build:
name: Build for macOS 🍏 name: Build for macOS 🍏
runs-on: macos-15 runs-on: macos-14
needs: check-event needs: check-event
defaults: defaults:
run: run:
shell: zsh --no-rcs --errexit --pipefail {0} shell: zsh --no-rcs --errexit --pipefail {0}
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
with: with:
submodules: recursive submodules: recursive
fetch-depth: 0 fetch-depth: 0
@@ -107,11 +107,11 @@ jobs:
print "pluginName=${product_name}" >> $GITHUB_OUTPUT print "pluginName=${product_name}" >> $GITHUB_OUTPUT
print "pluginVersion=${git_tag}" >> $GITHUB_OUTPUT print "pluginVersion=${git_tag}" >> $GITHUB_OUTPUT
print '::group::Enable Xcode 16.1' print '::group::Enable Xcode 15.2'
sudo xcode-select --switch /Applications/Xcode_16.1.0.app/Contents/Developer sudo xcode-select --switch /Applications/Xcode_15.2.app/Contents/Developer
print '::endgroup::' print '::endgroup::'
- uses: actions/cache@v5 - uses: actions/cache@v4
id: ccache-cache id: ccache-cache
with: with:
path: ${{ github.workspace }}/.ccache path: ${{ github.workspace }}/.ccache
@@ -163,13 +163,13 @@ jobs:
codesignPass: ${{ secrets.MACOS_NOTARIZATION_PASSWORD }} codesignPass: ${{ secrets.MACOS_NOTARIZATION_PASSWORD }}
- name: Upload Artifacts 📡 - name: Upload Artifacts 📡
uses: actions/upload-artifact@v7 uses: actions/upload-artifact@v4
with: with:
name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-macos-universal-${{ needs.check-event.outputs.commitHash }} name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-macos-universal-${{ needs.check-event.outputs.commitHash }}
path: ${{ github.workspace }}/release/${{ steps.setup.outputs.pluginName }}-*-macos-universal.* path: ${{ github.workspace }}/release/${{ steps.setup.outputs.pluginName }}-*-macos-universal.*
- name: Upload Debug Symbol Artifacts 🪲 - name: Upload Debug Symbol Artifacts 🪲
uses: actions/upload-artifact@v7 uses: actions/upload-artifact@v4
if: ${{ needs.check-event.outputs.config == 'Release' }} if: ${{ needs.check-event.outputs.config == 'Release' }}
with: with:
name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-macos-universal-${{ needs.check-event.outputs.commitHash }}-dSYMs name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-macos-universal-${{ needs.check-event.outputs.commitHash }}-dSYMs
@@ -183,7 +183,7 @@ jobs:
run: run:
shell: bash shell: bash
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
with: with:
submodules: recursive submodules: recursive
fetch-depth: 0 fetch-depth: 0
@@ -202,7 +202,7 @@ jobs:
echo "pluginName=${product_name}" >> $GITHUB_OUTPUT echo "pluginName=${product_name}" >> $GITHUB_OUTPUT
echo "pluginVersion=${git_tag}" >> $GITHUB_OUTPUT echo "pluginVersion=${git_tag}" >> $GITHUB_OUTPUT
- uses: actions/cache@v5 - uses: actions/cache@v4
id: ccache-cache id: ccache-cache
with: with:
path: ${{ github.workspace }}/.ccache path: ${{ github.workspace }}/.ccache
@@ -210,19 +210,13 @@ jobs:
restore-keys: | restore-keys: |
${{ runner.os }}-ccache-x86_64- ${{ runner.os }}-ccache-x86_64-
- name: Set up Homebrew 🍺 - name: Set up CMake 🏗️
uses: Homebrew/actions/setup-homebrew@main uses: jwlawson/actions-setup-cmake@v1.13
with:
cmake-version: '3.24.x'
- name: Install Vulkan SDK 🌋 - name: Set up Homebrew 🍺
shell: bash uses: Homebrew/actions/setup-homebrew@master
run: |
wget -qO- https://packages.lunarg.com/lunarg-signing-key-pub.asc \
| sudo tee /etc/apt/trusted.gpg.d/lunarg.asc
sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-noble.list \
https://packages.lunarg.com/vulkan/lunarg-vulkan-noble.list
sudo apt-get update -qq
sudo apt-get install -y vulkan-sdk
echo "VULKAN_SDK=/usr" >> "$GITHUB_ENV"
- name: Build Plugin 🧱 - name: Build Plugin 🧱
uses: ./.github/actions/build-plugin uses: ./.github/actions/build-plugin
@@ -244,111 +238,23 @@ jobs:
config: ${{ needs.check-event.outputs.config }} config: ${{ needs.check-event.outputs.config }}
- name: Upload Source Tarball 🗜️ - name: Upload Source Tarball 🗜️
uses: actions/upload-artifact@v7 uses: actions/upload-artifact@v4
with: with:
name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-sources-${{ needs.check-event.outputs.commitHash }} name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-sources-${{ needs.check-event.outputs.commitHash }}
path: ${{ github.workspace }}/release/${{ steps.setup.outputs.pluginName }}-*-source.* path: ${{ github.workspace }}/release/${{ steps.setup.outputs.pluginName }}-*-source.*
- name: Rename artifacts for Ubuntu 24 🏷️
run: |
: Rename artifacts for Ubuntu 24 🏷️
for f in ${{ github.workspace }}/release/*-x86_64-linux-gnu.*; do
[ -e "${f}" ] || continue
mv "${f}" "${f/x86_64-linux-gnu/x86_64-ubuntu24.04-linux-gnu}"
done
- name: Upload Artifacts 📡 - name: Upload Artifacts 📡
uses: actions/upload-artifact@v7 uses: actions/upload-artifact@v4
with: with:
name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-ubuntu-24.04-x86_64-${{ needs.check-event.outputs.commitHash }} name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-ubuntu-24.04-x86_64-${{ needs.check-event.outputs.commitHash }}
path: ${{ github.workspace }}/release/${{ steps.setup.outputs.pluginName }}-*-x86_64*.* path: ${{ github.workspace }}/release/${{ steps.setup.outputs.pluginName }}-*-x86_64*.*
- name: Upload debug symbol artifacts 🪲 - name: Upload debug symbol artifacts 🪲
uses: actions/upload-artifact@v7 uses: actions/upload-artifact@v4
if: ${{ fromJSON(needs.check-event.outputs.package) }} if: ${{ fromJSON(needs.check-event.outputs.package) }}
with: with:
name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-ubuntu-24.04-x86_64-${{ needs.check-event.outputs.commitHash }}-dbgsym name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-ubuntu-24.04-x86_64-${{ needs.check-event.outputs.commitHash }}-dbgsym
path: ${{ github.workspace }}/release/${{ steps.setup.outputs.pluginName }}-*-x86_64*-dbgsym.ddeb path: ${{ github.workspace }}/release/${{ steps.setup.outputs.pluginName }}-*-x86_64*-dbgsym.ddeb
if-no-files-found: ignore
ubuntu-26-build:
name: Build for Ubuntu 26 🐧
runs-on: ubuntu-26.04
needs: check-event
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
fetch-depth: 0
- name: Set Up Environment 🔧
id: setup
run: |
: Set Up Environment 🔧
if [[ "${RUNNER_DEBUG}" ]]; then set -x; fi
git_tag="$(git describe --tags)"
read -r product_name product_version <<< \
"$(jq -r '. | {name, version} | join(" ")' buildspec.json)"
echo "pluginName=${product_name}" >> $GITHUB_OUTPUT
echo "pluginVersion=${git_tag}" >> $GITHUB_OUTPUT
- uses: actions/cache@v5
id: ccache-cache
with:
path: ${{ github.workspace }}/.ccache
key: ${{ runner.os }}-ccache-x86_64-${{ needs.check-event.outputs.config }}
restore-keys: |
${{ runner.os }}-ccache-x86_64-
- name: Set up Homebrew 🍺
uses: Homebrew/actions/setup-homebrew@main
- name: Build Plugin 🧱
uses: ./.github/actions/build-plugin
with:
target: x86_64
config: ${{ needs.check-event.outputs.config }}
- name: Run tests
uses: ./.github/actions/run-tests
with:
target: x86_64
config: ${{ needs.check-event.outputs.config }}
- name: Package Plugin 📀
uses: ./.github/actions/package-plugin
with:
package: ${{ fromJSON(needs.check-event.outputs.package) }}
target: x86_64
config: ${{ needs.check-event.outputs.config }}
- name: Rename artifacts for Ubuntu 26 🏷️
run: |
: Rename artifacts for Ubuntu 26 🏷️
for f in ${{ github.workspace }}/release/*-x86_64-linux-gnu.*; do
[ -e "${f}" ] || continue
mv "${f}" "${f/x86_64-linux-gnu/x86_64-ubuntu26.04-linux-gnu}"
done
- name: Upload Artifacts 📡
uses: actions/upload-artifact@v7
with:
name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-ubuntu-26.04-x86_64-${{ needs.check-event.outputs.commitHash }}
path: ${{ github.workspace }}/release/${{ steps.setup.outputs.pluginName }}-*-x86_64*.*
- name: Upload debug symbol artifacts 🪲
uses: actions/upload-artifact@v7
if: ${{ fromJSON(needs.check-event.outputs.package) }}
with:
name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-ubuntu-26.04-x86_64-${{ needs.check-event.outputs.commitHash }}-dbgsym
path: ${{ github.workspace }}/release/${{ steps.setup.outputs.pluginName }}-*-x86_64*-dbgsym.ddeb
if-no-files-found: ignore
windows-build: windows-build:
name: Build for Windows 🪟 name: Build for Windows 🪟
@@ -358,7 +264,7 @@ jobs:
run: run:
shell: pwsh shell: pwsh
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
with: with:
submodules: recursive submodules: recursive
fetch-depth: 0 fetch-depth: 0
@@ -385,12 +291,6 @@ jobs:
target: x64 target: x64
config: ${{ needs.check-event.outputs.config }} config: ${{ needs.check-event.outputs.config }}
- name: Install Vulkan SDK 🌋
uses: jakoch/install-vulkan-sdk-action@v1
with:
install_runtime: false
cache: true
- name: Build Plugin 🧱 - name: Build Plugin 🧱
uses: ./.github/actions/build-plugin uses: ./.github/actions/build-plugin
with: with:
@@ -411,7 +311,7 @@ jobs:
package: ${{ fromJSON(needs.check-event.outputs.package) }} package: ${{ fromJSON(needs.check-event.outputs.package) }}
- name: Upload Artifacts 📡 - name: Upload Artifacts 📡
uses: actions/upload-artifact@v7 uses: actions/upload-artifact@v4
with: with:
name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-windows-x64-${{ needs.check-event.outputs.commitHash }} name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-windows-x64-${{ needs.check-event.outputs.commitHash }}
path: ${{ github.workspace }}/release/${{ steps.setup.outputs.pluginName }}-*-windows-x64*.* path: ${{ github.workspace }}/release/${{ steps.setup.outputs.pluginName }}-*-windows-x64*.*

View File

@@ -5,7 +5,7 @@ jobs:
clang-format: clang-format:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
- name: clang-format check 🐉 - name: clang-format check 🐉
@@ -17,7 +17,7 @@ jobs:
cmake-format: cmake-format:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
- name: cmake-format check 🎛️ - name: cmake-format check 🎛️

View File

@@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v4
- name: Check locale files - name: Check locale files
run: | run: |

View File

@@ -59,7 +59,7 @@ jobs:
esac esac
- name: Download Build Artifacts 📥 - name: Download Build Artifacts 📥
uses: actions/download-artifact@v8 uses: actions/download-artifact@v4
if: fromJSON(steps.check.outputs.validTag) if: fromJSON(steps.check.outputs.validTag)
id: download id: download
@@ -78,7 +78,6 @@ jobs:
'windows-x64;zip|exe' 'windows-x64;zip|exe'
'macos-universal;tar.xz|pkg' 'macos-universal;tar.xz|pkg'
'ubuntu-24.04-x86_64;tar.xz|deb|ddeb' 'ubuntu-24.04-x86_64;tar.xz|deb|ddeb'
'ubuntu-26.04-x86_64;tar.xz|deb|ddeb'
'sources;tar.xz' 'sources;tar.xz'
) )
@@ -107,7 +106,7 @@ jobs:
- name: Create Release 🛫 - name: Create Release 🛫
if: fromJSON(steps.check.outputs.validTag) if: fromJSON(steps.check.outputs.validTag)
id: create_release id: create_release
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda uses: softprops/action-gh-release@d4e8205d7e959a9107da6396278b2f1f07af0f9b
with: with:
draft: true draft: true
prerelease: ${{ fromJSON(steps.check.outputs.prerelease) }} prerelease: ${{ fromJSON(steps.check.outputs.prerelease) }}

9
.gitmodules vendored
View File

@@ -28,15 +28,12 @@
[submodule "deps/libusb"] [submodule "deps/libusb"]
path = deps/libusb path = deps/libusb
url = https://github.com/libusb/libusb.git url = https://github.com/libusb/libusb.git
[submodule "deps/date"]
path = deps/date
url = https://github.com/HowardHinnant/date.git
[submodule "deps/jsoncons"] [submodule "deps/jsoncons"]
path = deps/jsoncons path = deps/jsoncons
url = https://github.com/danielaparker/jsoncons.git url = https://github.com/danielaparker/jsoncons.git
[submodule "deps/paho.mqtt.cpp"] [submodule "deps/paho.mqtt.cpp"]
path = deps/paho.mqtt.cpp path = deps/paho.mqtt.cpp
url = https://github.com/eclipse-paho/paho.mqtt.cpp.git url = https://github.com/eclipse-paho/paho.mqtt.cpp.git
[submodule "deps/opencv_contrib"]
path = deps/opencv_contrib
url = https://github.com/opencv/opencv_contrib.git
[submodule "deps/whisper.cpp"]
path = deps/whisper.cpp
url = https://github.com/ggml-org/whisper.cpp.git

View File

@@ -6,18 +6,18 @@ You have the option to ...
Both methods require [CMake](https://cmake.org/download/). Both methods require [CMake](https://cmake.org/download/).
The plugin can be compiled for OBS 31 and above, although using the latest version of OBS is recommended to support all features. The plugin can be compiled for OBS 27 and above, although using the latest version of OBS is recommended to support all features.
## Compiling in tree (recommended for development) ## Compiling in tree (recommended for development)
This section assumes that you have a working [OBS Studio development environment](https://obsproject.com/wiki/Building-OBS-Studio). This section assumes that you have a working [OBS Studio development environment](https://obsproject.com/wiki/Building-OBS-Studio).
Add the "SceneSwitcher" source directory to your obs-studio source directory under obs-studio/plugins: Add the "SceneSwitcher" source directory to your obs-studio source directory under obs-studio/UI/frontend-plugins/:
``` ```
cd obs-studio/plugins cd obs-studio/UI/frontend-plugins/
git clone --recursive https://github.com/WarmUpTill/SceneSwitcher.git git clone --recursive https://github.com/WarmUpTill/SceneSwitcher.git
``` ```
Then modify the obs-studio/plugins/CMakeLists.txt and add an entry for the scene switcher: Then modify the obs-studio/UI/frontend-plugins/CMakeLists.txt Example and add an entry for the scene switcher:
``` ```
add_subdirectory(SceneSwitcher) add_subdirectory(SceneSwitcher)
``` ```

View File

@@ -16,14 +16,6 @@ if(BUILD_OUT_OF_TREE)
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/common/bootstrap.cmake" include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/common/bootstrap.cmake"
NO_POLICY_SCOPE) NO_POLICY_SCOPE)
include(compilerconfig) include(compilerconfig)
# OPENSSL_USE_STATIC_LIBS here ensures FindOpenSSL picks up the static libs
# preventing DLL name collisions with other plugins (e.g.NVIDIA AR SDK).
if(OS_WINDOWS)
set(OPENSSL_USE_STATIC_LIBS
ON
CACHE BOOL "Use static OpenSSL" FORCE)
include(cmake/windows/wingetssl.cmake)
endif()
include(defaults) include(defaults)
include(helpers) include(helpers)
endif() endif()
@@ -107,8 +99,6 @@ target_sources(
lib/macro/macro-action-edit.hpp lib/macro/macro-action-edit.hpp
lib/macro/macro-action-factory.cpp lib/macro/macro-action-factory.cpp
lib/macro/macro-action-factory.hpp lib/macro/macro-action-factory.hpp
lib/macro/macro-action-loop.cpp
lib/macro/macro-action-loop.hpp
lib/macro/macro-action-macro.cpp lib/macro/macro-action-macro.cpp
lib/macro/macro-action-macro.hpp lib/macro/macro-action-macro.hpp
lib/macro/macro-action-queue.cpp lib/macro/macro-action-queue.cpp
@@ -133,15 +123,6 @@ target_sources(
lib/macro/macro-condition.hpp lib/macro/macro-condition.hpp
lib/macro/macro-dock.cpp lib/macro/macro-dock.cpp
lib/macro/macro-dock.hpp lib/macro/macro-dock.hpp
lib/macro/macro-dock-settings.hpp
lib/macro/macro-dock-settings.cpp
lib/macro/macro-dock-window.cpp
lib/macro/macro-dock-window.hpp
lib/macro/macro-edit.cpp
lib/macro/macro-edit.hpp
lib/macro/macro-export-builtin-extensions.cpp
lib/macro/macro-export-extensions.cpp
lib/macro/macro-export-extensions.hpp
lib/macro/macro-export-import-dialog.cpp lib/macro/macro-export-import-dialog.cpp
lib/macro/macro-export-import-dialog.hpp lib/macro/macro-export-import-dialog.hpp
lib/macro/macro-helpers.cpp lib/macro/macro-helpers.cpp
@@ -154,27 +135,21 @@ target_sources(
lib/macro/macro-ref.hpp lib/macro/macro-ref.hpp
lib/macro/macro-run-button.cpp lib/macro/macro-run-button.cpp
lib/macro/macro-run-button.hpp lib/macro/macro-run-button.hpp
lib/macro/macro-search.cpp
lib/macro/macro-search.hpp
lib/macro/macro-segment-copy-paste.cpp lib/macro/macro-segment-copy-paste.cpp
lib/macro/macro-segment-copy-paste.hpp lib/macro/macro-segment-copy-paste.hpp
lib/macro/macro-segment-list.cpp lib/macro/macro-segment-list.cpp
lib/macro/macro-segment-list.hpp lib/macro/macro-segment-list.hpp
lib/macro/macro-segment-selection.cpp lib/macro/macro-segment-selection.cpp
lib/macro/macro-segment-selection.hpp lib/macro/macro-segment-selection.hpp
lib/macro/macro-segment-unknown.hpp
lib/macro/macro-segment.cpp lib/macro/macro-segment.cpp
lib/macro/macro-segment.hpp lib/macro/macro-segment.hpp
lib/macro/macro-selection.cpp lib/macro/macro-selection.cpp
lib/macro/macro-selection.hpp lib/macro/macro-selection.hpp
lib/macro/macro-settings.cpp lib/macro/macro-settings.cpp
lib/macro/macro-settings.hpp lib/macro/macro-settings.hpp
lib/macro/macro-signals.cpp
lib/macro/macro-signals.hpp
lib/macro/macro-tab.cpp lib/macro/macro-tab.cpp
lib/macro/macro-tree.cpp lib/macro/macro-tree.cpp
lib/macro/macro-tree.hpp lib/macro/macro-tree.hpp
lib/macro/macro-websocket-trigger.cpp
lib/macro/macro.cpp lib/macro/macro.cpp
lib/macro/macro.hpp) lib/macro/macro.hpp)
@@ -189,12 +164,8 @@ target_sources(
lib/utils/auto-update-tooltip-label.hpp lib/utils/auto-update-tooltip-label.hpp
lib/utils/backup.cpp lib/utils/backup.cpp
lib/utils/backup.hpp lib/utils/backup.hpp
lib/utils/canvas-helpers.cpp
lib/utils/canvas-helpers.hpp
lib/utils/condition-logic.cpp lib/utils/condition-logic.cpp
lib/utils/condition-logic.hpp lib/utils/condition-logic.hpp
lib/utils/crash-handler.cpp
lib/utils/crash-handler.hpp
lib/utils/curl-helper.cpp lib/utils/curl-helper.cpp
lib/utils/curl-helper.hpp lib/utils/curl-helper.hpp
lib/utils/cursor-shape-changer.cpp lib/utils/cursor-shape-changer.cpp
@@ -212,15 +183,6 @@ target_sources(
lib/utils/file-selection.hpp lib/utils/file-selection.hpp
lib/utils/filter-combo-box.cpp lib/utils/filter-combo-box.cpp
lib/utils/filter-combo-box.hpp lib/utils/filter-combo-box.hpp
lib/utils/first-run-wizard.cpp
lib/utils/first-run-wizard.hpp
lib/utils/first-run-wizard-audio.cpp
lib/utils/first-run-wizard-audio.hpp
lib/utils/first-run-wizard-helpers.hpp
lib/utils/first-run-wizard-sequence.cpp
lib/utils/first-run-wizard-sequence.hpp
lib/utils/first-run-wizard-window.cpp
lib/utils/first-run-wizard-window.hpp
lib/utils/help-icon.hpp lib/utils/help-icon.hpp
lib/utils/help-icon.cpp lib/utils/help-icon.cpp
lib/utils/item-selection-helpers.cpp lib/utils/item-selection-helpers.cpp
@@ -255,8 +217,6 @@ target_sources(
lib/utils/priority-helper.hpp lib/utils/priority-helper.hpp
lib/utils/regex-config.cpp lib/utils/regex-config.cpp
lib/utils/regex-config.hpp lib/utils/regex-config.hpp
lib/utils/resizable-widget.cpp
lib/utils/resizable-widget.hpp
lib/utils/resizing-text-edit.cpp lib/utils/resizing-text-edit.cpp
lib/utils/resizing-text-edit.hpp lib/utils/resizing-text-edit.hpp
lib/utils/resource-table.cpp lib/utils/resource-table.cpp
@@ -303,10 +263,6 @@ target_sources(
lib/utils/volume-control.hpp lib/utils/volume-control.hpp
lib/utils/websocket-api.cpp lib/utils/websocket-api.cpp
lib/utils/websocket-api.hpp lib/utils/websocket-api.hpp
lib/variables/variable-color-button.cpp
lib/variables/variable-color-button.hpp
lib/variables/variable-color.cpp
lib/variables/variable-color.hpp
lib/variables/variable-line-edit.cpp lib/variables/variable-line-edit.cpp
lib/variables/variable-line-edit.hpp lib/variables/variable-line-edit.hpp
lib/variables/variable-number.hpp lib/variables/variable-number.hpp
@@ -379,9 +335,6 @@ set_target_properties(${LIB_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden)
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_17) target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_17)
target_compile_features(${LIB_NAME} PUBLIC cxx_std_17) target_compile_features(${LIB_NAME} PUBLIC cxx_std_17)
target_precompile_headers(${LIB_NAME} PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/lib/pch.hpp")
target_include_directories( target_include_directories(
${LIB_NAME} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/deps/obs-websocket/lib" ${LIB_NAME} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/deps/obs-websocket/lib"
"${CMAKE_CURRENT_SOURCE_DIR}/deps/exprtk") "${CMAKE_CURRENT_SOURCE_DIR}/deps/exprtk")
@@ -478,29 +431,14 @@ else()
endif() endif()
if(PROCPS2_INCLUDE_DIR) if(PROCPS2_INCLUDE_DIR)
find_package(PkgConfig REQUIRED) find_package(PkgConfig REQUIRED)
pkg_check_modules(libproc2 IMPORTED_TARGET libproc2<4.0.5 QUIET)
if(libproc2_FOUND)
target_compile_definitions(${LIB_NAME} PRIVATE PROCPS2_USE_INFO)
endif()
pkg_check_modules(libproc2 REQUIRED IMPORTED_TARGET libproc2) pkg_check_modules(libproc2 REQUIRED IMPORTED_TARGET libproc2)
set(PROC_INCLUDE_DIR "${PROCPS2_INCLUDE_DIR}") set(PROC_INCLUDE_DIR "${PROCPS2_INCLUDE_DIR}")
target_compile_definitions(${LIB_NAME} PRIVATE PROCPS2_AVAILABLE) target_compile_definitions(${LIB_NAME} PRIVATE PROCPS2_AVAILABLE)
set(PROCESS_CONDITION_SUPPORTED 1) set(PROCESS_CONDITION_SUPPORTED 1)
# Check if PIDS_VAL takes 4 arguments (old API, pre-4.0.5) or 3 (new API)
include(CheckCSourceCompiles)
set(CMAKE_REQUIRED_INCLUDES "${PROCPS2_INCLUDE_DIR}")
set(CMAKE_REQUIRED_LIBRARIES proc2)
check_c_source_compiles(
"
#include <libproc2/pids.h>
int main(void) {
struct pids_stack *s = 0;
struct pids_info *i = 0;
(void)PIDS_VAL(0, str, s, i);
return 0;
}
"
PROCPS2_PIDS_VAL_TAKES_INFO)
if(PROCPS2_PIDS_VAL_TAKES_INFO)
target_compile_definitions(${LIB_NAME} PRIVATE PROCPS2_USE_INFO)
endif()
endif() endif()
if(NOT DEFINED PROCESS_CONDITION_SUPPORTED) if(NOT DEFINED PROCESS_CONDITION_SUPPORTED)
message( message(
@@ -526,11 +464,7 @@ endif()
# --- End of section --- # --- End of section ---
add_subdirectory(plugins) add_subdirectory(plugins)
add_subdirectory(tests)
option(ADVSS_ENABLE_TESTS "Build advanced-scene-switcher unit tests" OFF)
if(ADVSS_ENABLE_TESTS)
add_subdirectory(tests)
endif()
# --- Install --- # --- Install ---
@@ -559,59 +493,3 @@ else()
set_target_properties_obs(${PROJECT_NAME} PROPERTIES PREFIX "") set_target_properties_obs(${PROJECT_NAME} PROPERTIES PREFIX "")
endif() endif()
endif() endif()
# --- Install third-party dependency licenses ---
#
# Each entry is "display-name:path/to/license/file" relative to deps/. Files are
# silently skipped when a submodule is not checked out.
set(_dep_license_files
"asio:asio/asio/LICENSE_1_0.txt"
"cpp-httplib:cpp-httplib/LICENSE"
"json:json/LICENSE.MIT"
"jsoncons:jsoncons/LICENSE"
"leptonica:leptonica/leptonica-license.txt"
"libremidi:libremidi/LICENSE.md"
"libusb:libusb/COPYING"
"opencv:opencv/LICENSE"
"openvr:openvr/LICENSE"
"paho-mqtt:paho.mqtt.cpp/LICENSE"
"tesseract:tesseract/LICENSE"
"websocketpp:websocketpp/COPYING"
"whisper:whisper.cpp/LICENSE")
if(DEB_INSTALL)
if(NOT DATA_OUT_DIR)
set(DATA_OUT_DIR "/share/obs/obs-plugins/${PROJECT_NAME}")
endif()
set(_license_dest "${CMAKE_INSTALL_PREFIX}/${DATA_OUT_DIR}/licenses")
elseif(OS_MACOS)
# macOS: license files become bundle Resources/licenses/* entries
set(_license_dest "")
else()
# Windows and non-DEB Linux: alongside the plugin's data directory
set(_license_dest "${CMAKE_PROJECT_NAME}/data/licenses")
endif()
foreach(_entry IN LISTS _dep_license_files)
string(REGEX MATCH "^([^:]+):(.+)$" _m "${_entry}")
set(_dep_name "${CMAKE_MATCH_1}")
set(_dep_file "${CMAKE_CURRENT_SOURCE_DIR}/deps/${CMAKE_MATCH_2}")
if(NOT EXISTS "${_dep_file}")
continue()
endif()
if(OS_MACOS)
# Copy to binary dir so we can give the file a clean name
set(_staged "${CMAKE_CURRENT_BINARY_DIR}/licenses/LICENSE-${_dep_name}")
configure_file("${_dep_file}" "${_staged}" COPYONLY)
target_sources(${PROJECT_NAME} PRIVATE "${_staged}")
set_source_files_properties("${_staged}" PROPERTIES MACOSX_PACKAGE_LOCATION
"Resources/licenses")
else()
install(
FILES "${_dep_file}"
DESTINATION "${_license_dest}"
RENAME "LICENSE-${_dep_name}")
endif()
endforeach()

View File

@@ -41,8 +41,7 @@
"description": "Build for macOS 11.0+ (Universal binary) for CI", "description": "Build for macOS 11.0+ (Universal binary) for CI",
"generator": "Xcode", "generator": "Xcode",
"cacheVariables": { "cacheVariables": {
"CMAKE_COMPILE_WARNING_AS_ERROR": true, "CMAKE_COMPILE_WARNING_AS_ERROR": true
"ADVSS_ENABLE_TESTS": true
} }
}, },
{ {
@@ -70,8 +69,7 @@
"displayName": "Windows x64 CI build", "displayName": "Windows x64 CI build",
"description": "Build for Windows x64 on CI", "description": "Build for Windows x64 on CI",
"cacheVariables": { "cacheVariables": {
"CMAKE_COMPILE_WARNING_AS_ERROR": true, "CMAKE_COMPILE_WARNING_AS_ERROR": true
"ADVSS_ENABLE_TESTS": true
} }
}, },
{ {
@@ -99,8 +97,7 @@
"description": "Build for Linux x86_64 on CI", "description": "Build for Linux x86_64 on CI",
"cacheVariables": { "cacheVariables": {
"CMAKE_BUILD_TYPE": "RelWithDebInfo", "CMAKE_BUILD_TYPE": "RelWithDebInfo",
"CMAKE_COMPILE_WARNING_AS_ERROR": true, "CMAKE_COMPILE_WARNING_AS_ERROR": true
"ADVSS_ENABLE_TESTS": true
} }
}, },
{ {
@@ -128,8 +125,7 @@
"description": "Build for Linux aarch64 on CI", "description": "Build for Linux aarch64 on CI",
"cacheVariables": { "cacheVariables": {
"CMAKE_BUILD_TYPE": "RelWithDebInfo", "CMAKE_BUILD_TYPE": "RelWithDebInfo",
"CMAKE_COMPILE_WARNING_AS_ERROR": true, "CMAKE_COMPILE_WARNING_AS_ERROR": true
"ADVSS_ENABLE_TESTS": true
} }
} }
], ],

View File

@@ -14,6 +14,11 @@ On Linux the plugin is available via the **Flatpak** package manager for users w
flatpak install com.obsproject.Studio.Plugin.SceneSwitcher flatpak install com.obsproject.Studio.Plugin.SceneSwitcher
``` ```
The **Snap** package manager offers an OBS Studio installation which is bundled with the plugin:
```
sudo snap install obs-studio
```
More information can be found [here](https://github.com/WarmUpTill/SceneSwitcher/wiki/Installation). More information can be found [here](https://github.com/WarmUpTill/SceneSwitcher/wiki/Installation).
## Contributing ## Contributing

View File

@@ -1,126 +0,0 @@
#!/usr/bin/env bash
# Usage: demote_deps.sh <in.deb> [Recommends|Suggests] [regex]
# Example: demote_deps.sh build/advanced-scene-switcher_1.31.0_amd64.deb Recommends 'opencv'
set -euo pipefail
if [[ $# -lt 1 ]]; then
echo "Usage: $0 <in.deb> [Recommends|Suggests] [regex]" >&2
exit 1
fi
IN_DEB="$1"
DEST_FIELD="${2:-Recommends}" # Recommends or Suggests
MATCH_REGEX="${3:-opencv}" # regex to match packages to demote
echo "Demoting dependencies matching '${MATCH_REGEX}' to ${DEST_FIELD}"
TMPDIR="$(mktemp -d)"
trap 'rm -rf "$TMPDIR"' EXIT
dpkg-deb -R "$IN_DEB" "$TMPDIR"
CONTROL="$TMPDIR/DEBIAN/control"
# Read a field (single line value), handling continuation lines starting with a space.
get_field() {
local key="$1"
awk -v key="$key" '
BEGIN { val=""; collecting=0 }
$0 ~ "^" key ":" {
collecting=1
sub("^" key ":[[:space:]]*", "", $0)
val=$0
next
}
collecting==1 {
if ($0 ~ "^[[:space:]]") {
sub("^[[:space:]]+", "", $0)
val = val " " $0
next
} else {
collecting=0
}
}
END { print val }
' "$CONTROL"
}
# Split a comma-separated list into lines, trimming whitespace
split_csv() {
tr ',' '\n' | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//' | sed '/^$/d'
}
# Join with ", "
join_csv() {
awk 'BEGIN{first=1}{ if(!first) printf(", "); printf("%s",$0); first=0 } END{print ""}'
}
# Deduplicate while preserving order
dedup() {
awk '!seen[$0]++'
}
DEPENDS_VAL="$(get_field Depends)"
EXIST_DEST_VAL="$(get_field "$DEST_FIELD")"
# Separate opencv-matching vs the rest (preserve tokens exactly)
mapfile -t DEPENDS_ARR < <(printf "%s\n" "$DEPENDS_VAL" | split_csv)
declare -a MOVED=()
declare -a KEPT=()
for item in "${DEPENDS_ARR[@]}"; do
# Skip empty just in case
[[ -z "$item" ]] && continue
if [[ "$item" =~ $MATCH_REGEX ]]; then
MOVED+=("$item")
else
KEPT+=("$item")
fi
done
# Merge with existing dest field
if [[ -n "$EXIST_DEST_VAL" ]]; then
mapfile -t EXIST_DEST_ARR < <(printf "%s\n" "$EXIST_DEST_VAL" | split_csv)
MOVED+=("${EXIST_DEST_ARR[@]}")
fi
# De-duplicate
mapfile -t MOVED < <(printf "%s\n" "${MOVED[@]:-}" | sed '/^$/d' | dedup)
mapfile -t KEPT < <(printf "%s\n" "${KEPT[@]:-}" | sed '/^$/d' | dedup)
# Rebuild values
NEW_DEPENDS="$(printf "%s\n" "${KEPT[@]:-}" | join_csv || true)"
NEW_DEST="$(printf "%s\n" "${MOVED[@]:-}" | join_csv || true)"
# Write a cleaned control (remove existing Depends/Recommends/Suggests incl. continuations)
awk '
BEGIN { skip=0 }
{
if ($0 ~ "^(Depends|Recommends|Suggests):") { skip=1; next }
if (skip==1) {
if ($0 ~ "^[[:space:]]") { next } else { skip=0 }
}
print
}
' "$CONTROL" > "$CONTROL.clean"
# Append the rebuilt fields
{
cat "$CONTROL.clean"
if [[ -n "$NEW_DEPENDS" ]]; then
echo "Depends: $NEW_DEPENDS"
fi
if [[ -n "$NEW_DEST" ]]; then
echo "$DEST_FIELD: $NEW_DEST"
fi
} > "$CONTROL.new"
# Clean up empty lines
sed -i '/^[[:space:]]*$/d' "$CONTROL.new"
mv "$CONTROL.new" "$CONTROL"
rm -f "$CONTROL.clean"
# Repack
rm -f "${IN_DEB}"
OUT_DEB="${IN_DEB}"
dpkg-deb -b "$TMPDIR" "$OUT_DEB" >/dev/null
echo "$OUT_DEB"

View File

@@ -1,23 +0,0 @@
Advanced Scene Switcher - Windows Installation (Portable)
==========================================================
For full installation instructions visit:
https://github.com/WarmUpTill/SceneSwitcher/wiki/Installation
This archive uses the portable plugin layout for older OBS versions,
portable OBS installs, and Steam.
Extract the CONTENTS of this archive into your OBS installation directory,
typically:
C:\Program Files\obs-studio\
Merge the data\ and obs-plugins\ folders with the existing ones when prompted.
Steam users: right-click OBS in your library -> Manage -> Browse local files,
then extract the contents of this archive into that directory.
For OBS 28 and newer the recommended archive is preferred:
advanced-scene-switcher-<version>-windows-x64.zip

View File

@@ -1,21 +0,0 @@
Advanced Scene Switcher - Windows Installation
===============================================
For full installation instructions visit:
https://github.com/WarmUpTill/SceneSwitcher/wiki/Installation
This archive uses the recommended plugin layout for OBS 28 and newer.
Extract the CONTENTS of this archive into:
C:\ProgramData\obs-studio\plugins\
Tip: press Win+R and type %ProgramData%\obs-studio\plugins to open that folder.
After extracting, the path should look like:
C:\ProgramData\obs-studio\plugins\advanced-scene-switcher\bin\64bit\advanced-scene-switcher.dll
If the plugin does not appear in OBS, try the portable archive instead:
advanced-scene-switcher-<version>-windows-x64-portable.zip

View File

@@ -1,33 +1,33 @@
{ {
"dependencies": { "dependencies": {
"obs-studio": { "obs-studio": {
"version": "31.1.1", "version": "30.1.2",
"baseUrl": "https://github.com/obsproject/obs-studio/archive/refs/tags", "baseUrl": "https://github.com/obsproject/obs-studio/archive/refs/tags",
"label": "OBS sources", "label": "OBS sources",
"hashes": { "hashes": {
"macos": "39751f067bacc13d44b116c5138491b5f1391f91516d3d590d874edd21292291", "macos": "490bae1c392b3b344b0270afd8cb887da4bc50bd92c0c426e96713c1ccb9701a",
"windows-x64": "2c8427c10b55ac6d68008df2e9a3e82f4647aaad18f105e30d4713c2de678ccf" "windows-x64": "c2dd03fa7fd01fad5beafce8f7156da11f9ed9a588373fd40b44a06f4c03b867"
} }
}, },
"prebuilt": { "prebuilt": {
"version": "2025-07-11", "version": "2024-03-19",
"baseUrl": "https://github.com/obsproject/obs-deps/releases/download", "baseUrl": "https://github.com/obsproject/obs-deps/releases/download",
"label": "Pre-Built obs-deps", "label": "Pre-Built obs-deps",
"hashes": { "hashes": {
"macos": "495687e63383d1a287684b6e2e9bfe246bb8f156fe265926afb1a325af1edd2a", "macos": "2e9bfb55a5e0e4c1086fa1fda4cf268debfead473089df2aaea80e1c7a3ca7ff",
"windows-x64": "c8c642c1070dc31ce9a0f1e4cef5bb992f4bff4882255788b5da12129e85caa7" "windows-x64": "6e86068371526a967e805f6f9903f9407adb683c21820db5f07da8f30d11e998"
} }
}, },
"qt6": { "qt6": {
"version": "2025-07-11", "version": "2024-03-19",
"baseUrl": "https://github.com/obsproject/obs-deps/releases/download", "baseUrl": "https://github.com/obsproject/obs-deps/releases/download",
"label": "Pre-Built Qt6", "label": "Pre-Built Qt6",
"hashes": { "hashes": {
"macos": "d3f5f04b6ea486e032530bdf0187cbda9a54e0a49621a4c8ba984c5023998867", "macos": "694f1e639c017e3b1f456f735330dc5afae287cbea85757101af1368de3142c8",
"windows-x64": "0e76bf0555dd5382838850b748d3dcfab44a1e1058441309ab54e1a65b156d0a" "windows-x64": "72d1df34a0ef7413a681d5fcc88cae81da60adc03dcd23ef17862ab170bcc0dd"
}, },
"debugSymbols": { "debugSymbols": {
"windows-x64": "11b7be92cf66a273299b8f3515c07a5cfb61614b59a4e67f7fc5ecba5e2bdf21" "windows-x64": "fbddd1f659c360f2291911ac5709b67b6f8182e6bca519d24712e4f6fd3cc865"
} }
} }
}, },

View File

@@ -2,7 +2,7 @@
if(BUILD_OUT_OF_TREE) if(BUILD_OUT_OF_TREE)
if(OS_WINDOWS) if(OS_WINDOWS)
set(OBS_PLUGIN_DESTINATION "${CMAKE_PROJECT_NAME}/bin/64bit") set(OBS_PLUGIN_DESTINATION "obs-plugins/64bit")
else() else()
set(OBS_PLUGIN_DESTINATION "${CMAKE_INSTALL_LIBDIR}/obs-plugins") set(OBS_PLUGIN_DESTINATION "${CMAKE_INSTALL_LIBDIR}/obs-plugins")
endif() endif()
@@ -157,9 +157,7 @@ else()
set_target_properties(${target} PROPERTIES INSTALL_RPATH set_target_properties(${target} PROPERTIES INSTALL_RPATH
"$ORIGIN:$ORIGIN/..") "$ORIGIN:$ORIGIN/..")
endif() endif()
get_filename_component(_plugin_dir_name "${CMAKE_CURRENT_SOURCE_DIR}" NAME) message(STATUS "ADVSS: ENABLED PLUGIN ${target}")
set_property(GLOBAL APPEND PROPERTY ADVSS_PLUGINS_ENABLED
${_plugin_dir_name})
endfunction() endfunction()
function(install_advss_plugin_dependency_target target dep) function(install_advss_plugin_dependency_target target dep)
@@ -333,8 +331,6 @@ function(setup_advss_plugin target)
PRIVATE "${ADVSS_SOURCE_DIR}/lib" "${ADVSS_SOURCE_DIR}/lib/legacy" PRIVATE "${ADVSS_SOURCE_DIR}/lib" "${ADVSS_SOURCE_DIR}/lib/legacy"
"${ADVSS_SOURCE_DIR}/lib/macro" "${ADVSS_SOURCE_DIR}/lib/utils" "${ADVSS_SOURCE_DIR}/lib/macro" "${ADVSS_SOURCE_DIR}/lib/utils"
"${ADVSS_SOURCE_DIR}/lib/variables" "${ADVSS_SOURCE_DIR}/forms") "${ADVSS_SOURCE_DIR}/lib/variables" "${ADVSS_SOURCE_DIR}/forms")
target_precompile_headers(${target} PRIVATE "${ADVSS_SOURCE_DIR}/lib/pch.hpp")
endfunction() endfunction()
function(install_advss_plugin_dependency) function(install_advss_plugin_dependency)

View File

@@ -65,16 +65,17 @@ function(_setup_obs_studio)
if(OS_WINDOWS) if(OS_WINDOWS)
set(_cmake_generator "${CMAKE_GENERATOR}") set(_cmake_generator "${CMAKE_GENERATOR}")
set(_cmake_arch set(_cmake_arch "-A ${arch}")
"-A ${arch},version=${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}")
set(_cmake_extra set(_cmake_extra
"-DCMAKE_SYSTEM_VERSION=${CMAKE_SYSTEM_VERSION} -DCMAKE_ENABLE_SCRIPTING=OFF" "-DCMAKE_SYSTEM_VERSION=${CMAKE_SYSTEM_VERSION} -DCMAKE_ENABLE_SCRIPTING=OFF"
) )
set(_cmake_version "2.0.0")
elseif(OS_MACOS) elseif(OS_MACOS)
set(_cmake_generator "Xcode") set(_cmake_generator "Xcode")
set(_cmake_arch "-DCMAKE_OSX_ARCHITECTURES:STRING='arm64;x86_64'") set(_cmake_arch "-DCMAKE_OSX_ARCHITECTURES:STRING='arm64;x86_64'")
set(_cmake_extra set(_cmake_extra
"-DCMAKE_OSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}") "-DCMAKE_OSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}")
set(_cmake_version "3.0.0")
endif() endif()
message(STATUS "Configure ${label} (${arch})") message(STATUS "Configure ${label} (${arch})")
@@ -82,42 +83,32 @@ function(_setup_obs_studio)
COMMAND COMMAND
"${CMAKE_COMMAND}" -S "${dependencies_dir}/${_obs_destination}" -B "${CMAKE_COMMAND}" -S "${dependencies_dir}/${_obs_destination}" -B
"${dependencies_dir}/${_obs_destination}/build_${arch}" -G "${dependencies_dir}/${_obs_destination}/build_${arch}" -G
${_cmake_generator} "${_cmake_arch}" -DOBS_CMAKE_VERSION:STRING=3.0.0 ${_cmake_generator} "${_cmake_arch}"
-DENABLE_PLUGINS:BOOL=OFF -DENABLE_FRONTEND:BOOL=OFF -DOBS_CMAKE_VERSION:STRING=${_cmake_version} -DENABLE_PLUGINS:BOOL=OFF
-DOBS_VERSION_OVERRIDE:STRING=${_obs_version} -DENABLE_UI:BOOL=OFF -DOBS_VERSION_OVERRIDE:STRING=${_obs_version}
"-DCMAKE_PREFIX_PATH='${CMAKE_PREFIX_PATH}'" ${_is_fresh} ${_cmake_extra} "-DCMAKE_PREFIX_PATH='${CMAKE_PREFIX_PATH}'" ${_is_fresh} ${_cmake_extra}
RESULT_VARIABLE _process_result COMMAND_ERROR_IS_FATAL ANY RESULT_VARIABLE _process_result COMMAND_ERROR_IS_FATAL ANY
OUTPUT_QUIET) OUTPUT_QUIET)
message(STATUS "Configure ${label} (${arch}) - done") message(STATUS "Configure ${label} (${arch}) - done")
message(STATUS "Build ${label} (Debug - ${arch})") message(STATUS "Build ${label} (${arch})")
execute_process( execute_process(
COMMAND "${CMAKE_COMMAND}" --build build_${arch} --target obs-frontend-api COMMAND "${CMAKE_COMMAND}" --build build_${arch} --target obs-frontend-api
--config Debug --parallel --config Debug --parallel
WORKING_DIRECTORY "${dependencies_dir}/${_obs_destination}" WORKING_DIRECTORY "${dependencies_dir}/${_obs_destination}"
RESULT_VARIABLE _process_result COMMAND_ERROR_IS_FATAL ANY RESULT_VARIABLE _process_result COMMAND_ERROR_IS_FATAL ANY
OUTPUT_QUIET) OUTPUT_QUIET)
message(STATUS "Build ${label} (Debug - ${arch}) - done") message(STATUS "Build ${label} (${arch}) - done")
message(STATUS "Build ${label} (Release - ${arch})")
execute_process(
COMMAND "${CMAKE_COMMAND}" --build build_${arch} --target obs-frontend-api
--config Release --parallel
WORKING_DIRECTORY "${dependencies_dir}/${_obs_destination}"
RESULT_VARIABLE _process_result COMMAND_ERROR_IS_FATAL ANY
OUTPUT_QUIET)
message(STATUS "Build ${label} (Reelase - ${arch}) - done")
message(STATUS "Install ${label} (${arch})") message(STATUS "Install ${label} (${arch})")
if(OS_WINDOWS)
set(_cmake_extra "--component obs_libraries")
else()
set(_cmake_extra "")
endif()
execute_process( execute_process(
COMMAND "${CMAKE_COMMAND}" --install build_${arch} --component Development COMMAND "${CMAKE_COMMAND}" --install build_${arch} --component Development
--config Debug --prefix "${dependencies_dir}" --config Debug --prefix "${dependencies_dir}" ${_cmake_extra}
WORKING_DIRECTORY "${dependencies_dir}/${_obs_destination}"
RESULT_VARIABLE _process_result COMMAND_ERROR_IS_FATAL ANY
OUTPUT_QUIET)
execute_process(
COMMAND "${CMAKE_COMMAND}" --install build_${arch} --component Development
--config Release --prefix "${dependencies_dir}"
WORKING_DIRECTORY "${dependencies_dir}/${_obs_destination}" WORKING_DIRECTORY "${dependencies_dir}/${_obs_destination}"
RESULT_VARIABLE _process_result COMMAND_ERROR_IS_FATAL ANY RESULT_VARIABLE _process_result COMMAND_ERROR_IS_FATAL ANY
OUTPUT_QUIET) OUTPUT_QUIET)
@@ -180,53 +171,24 @@ function(_check_dependencies)
set(url ${url}/${version}/${file}) set(url ${url}/${version}/${file})
endif() endif()
set(MAX_DOWNLOAD_RETRIES 3)
set(RETRY_DELAY 60) # seconds
if(NOT EXISTS "${dependencies_dir}/${file}") if(NOT EXISTS "${dependencies_dir}/${file}")
message(STATUS "Downloading ${url}") message(STATUS "Downloading ${url}")
file(
DOWNLOAD "${url}" "${dependencies_dir}/${file}"
STATUS download_status
EXPECTED_HASH SHA256=${hash})
set(download_success FALSE) list(GET download_status 0 error_code)
list(GET download_status 1 error_message)
foreach(i RANGE 1 ${MAX_DOWNLOAD_RETRIES}) if(error_code GREATER 0)
message(STATUS "Attempt ${i}/${MAX_DOWNLOAD_RETRIES} for ${url}") message(STATUS "Downloading ${url} - Failure")
file(DOWNLOAD "${url}" "${dependencies_dir}/${file}"
STATUS download_status)
list(GET download_status 0 error_code)
list(GET download_status 1 error_message)
if(error_code EQUAL 0)
file(SHA256 "${dependencies_dir}/${file}" actual_hash)
if(NOT actual_hash STREQUAL hash)
set(error_code 1)
set(error_message
"hash mismatch (expected ${hash}, got ${actual_hash})")
endif()
endif()
if(error_code EQUAL 0)
message(STATUS "Downloading ${url} - success on attempt ${i}")
set(download_success TRUE)
break()
else()
message(WARNING "Download failed (attempt ${i}): ${error_message}")
file(REMOVE "${dependencies_dir}/${file}")
if(NOT i EQUAL MAX_DOWNLOAD_RETRIES)
message(STATUS "Retrying in ${RETRY_DELAY} seconds...")
execute_process(COMMAND ${CMAKE_COMMAND} -E sleep ${RETRY_DELAY})
endif()
endif()
endforeach()
if(NOT download_success)
message( message(
FATAL_ERROR FATAL_ERROR
"Unable to download ${url} after ${MAX_DOWNLOAD_RETRIES} attempts") "Unable to download ${url}, failed with error: ${error_message}")
file(REMOVE "${dependencies_dir}/${file}")
else()
message(STATUS "Downloading ${url} - done")
endif() endif()
message(STATUS "Downloading ${url} - done")
endif() endif()
if(NOT EXISTS "${dependencies_dir}/${destination}") if(NOT EXISTS "${dependencies_dir}/${destination}")

View File

@@ -64,7 +64,7 @@ function(_git_find_closest_git_dir _start_dir _git_dir_var)
while(NOT EXISTS "${git_dir}") while(NOT EXISTS "${git_dir}")
# .git dir not found, search parent directories # .git dir not found, search parent directories
set(git_previous_parent "${cur_dir}") set(git_previous_parent "${cur_dir}")
get_filename_component(cur_dir "${cur_dir}" DIRECTORY) get_filename_component(cur_dir ${cur_dir} DIRECTORY)
if(cur_dir STREQUAL git_previous_parent) if(cur_dir STREQUAL git_previous_parent)
# We have reached the root directory, we are not in git # We have reached the root directory, we are not in git
set(${_git_dir_var} set(${_git_dir_var}

View File

@@ -18,11 +18,8 @@ set(CPACK_PACKAGE_FILE_NAME
"${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_C_LIBRARY_ARCHITECTURE}" "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_C_LIBRARY_ARCHITECTURE}"
) )
set(CPACK_GENERATOR set(CPACK_GENERATOR "DEB")
"DEB"
CACHE STRING "CPack generator to use")
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
set(CPACK_DEBIAN_PACKAGE_DEPENDS "obs-studio")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "${PLUGIN_EMAIL}") set(CPACK_DEBIAN_PACKAGE_MAINTAINER "${PLUGIN_EMAIL}")
set(CPACK_SET_DESTDIR ON) set(CPACK_SET_DESTDIR ON)
@@ -49,19 +46,6 @@ set(CPACK_SOURCE_PACKAGE_FILE_NAME
set(CPACK_ARCHIVE_THREADS 0) set(CPACK_ARCHIVE_THREADS 0)
include(CPack) include(CPack)
# CPack.cmake has a side effect that leaves binary packaging variables in the
# state intended for source packaging when it finishes. Specifically it sets
# CPACK_GENERATOR to CPACK_SOURCE_GENERATOR ("TXZ"), sets
# CPACK_INSTALLED_DIRECTORIES to the source root (which would cause CPackDeb to
# scan the entire source tree, including ccache object files that lack a Build
# ID), and clears CPACK_INSTALL_CMAKE_PROJECTS (preventing the cmake install
# mechanism from being used). In some cmake versions these overrides happen
# before CPackConfig.cmake is written. Reset all three so that binary DEB
# packaging works correctly regardless of cmake version.
set(CPACK_GENERATOR "DEB")
set(CPACK_INSTALLED_DIRECTORIES "")
set(CPACK_INSTALL_CMAKE_PROJECTS
"${CMAKE_BINARY_DIR};${CMAKE_PROJECT_NAME};ALL;/")
find_package(libobs QUIET) find_package(libobs QUIET)

View File

@@ -6,11 +6,7 @@ include(buildspec_common)
# _check_dependencies_windows: Set up Windows slice for _check_dependencies # _check_dependencies_windows: Set up Windows slice for _check_dependencies
function(_check_dependencies_windows) function(_check_dependencies_windows)
if(CMAKE_GENERATOR_PLATFORM) set(arch ${CMAKE_GENERATOR_PLATFORM})
set(arch ${CMAKE_GENERATOR_PLATFORM})
else()
set(arch x64)
endif()
set(platform windows-${arch}) set(platform windows-${arch})
set(dependencies_dir "${CMAKE_CURRENT_SOURCE_DIR}/.deps") set(dependencies_dir "${CMAKE_CURRENT_SOURCE_DIR}/.deps")

View File

@@ -6,9 +6,3 @@ include_guard(GLOBAL)
set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL TRUE) set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL TRUE)
include(buildspec) include(buildspec)
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX
"$ENV{ALLUSERSPROFILE}/obs-studio/plugins"
CACHE STRING "Default plugin installation directory" FORCE)
endif()

View File

@@ -30,13 +30,13 @@ function(set_target_properties_plugin target)
install( install(
TARGETS ${target} TARGETS ${target}
RUNTIME DESTINATION "${target}/bin/64bit" RUNTIME DESTINATION bin/64bit
LIBRARY DESTINATION "${target}/bin/64bit") LIBRARY DESTINATION obs-plugins/64bit)
install( install(
FILES "$<TARGET_PDB_FILE:${target}>" FILES "$<TARGET_PDB_FILE:${target}>"
CONFIGURATIONS RelWithDebInfo Debug Release CONFIGURATIONS RelWithDebInfo Debug Release
DESTINATION "${target}/bin/64bit" DESTINATION obs-plugins/64bit
OPTIONAL) OPTIONAL)
if(OBS_BUILD_DIR) if(OBS_BUILD_DIR)
@@ -44,11 +44,11 @@ function(set_target_properties_plugin target)
TARGET ${target} TARGET ${target}
POST_BUILD POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E make_directory COMMAND "${CMAKE_COMMAND}" -E make_directory
"${OBS_BUILD_DIR}/plugins/${target}/bin/64bit" "${OBS_BUILD_DIR}/obs-plugins/64bit"
COMMAND COMMAND
"${CMAKE_COMMAND}" -E copy_if_different "$<TARGET_FILE:${target}>" "${CMAKE_COMMAND}" -E copy_if_different "$<TARGET_FILE:${target}>"
"$<$<CONFIG:Debug,RelWithDebInfo,Release>:$<TARGET_PDB_FILE:${target}>>" "$<$<CONFIG:Debug,RelWithDebInfo,Release>:$<TARGET_PDB_FILE:${target}>>"
"${OBS_BUILD_DIR}/plugins/${target}/bin/64bit" "${OBS_BUILD_DIR}/obs-plugins/64bit"
COMMENT "Copy ${target} to obs-studio directory ${OBS_BUILD_DIR}" COMMENT "Copy ${target} to obs-studio directory ${OBS_BUILD_DIR}"
VERBATIM) VERBATIM)
endif() endif()
@@ -105,7 +105,7 @@ function(target_install_resources target)
install( install(
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/data/" DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/data/"
DESTINATION "${target}/data" DESTINATION data/obs-plugins/${target}
USE_SOURCE_PERMISSIONS) USE_SOURCE_PERMISSIONS)
if(OBS_BUILD_DIR) if(OBS_BUILD_DIR)
@@ -113,11 +113,11 @@ function(target_install_resources target)
TARGET ${target} TARGET ${target}
POST_BUILD POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E make_directory COMMAND "${CMAKE_COMMAND}" -E make_directory
"${OBS_BUILD_DIR}/plugins/${target}/data" "${OBS_BUILD_DIR}/data/obs-plugins/${target}"
COMMAND COMMAND
"${CMAKE_COMMAND}" -E copy_directory "${CMAKE_COMMAND}" -E copy_directory
"${CMAKE_CURRENT_SOURCE_DIR}/data" "${CMAKE_CURRENT_SOURCE_DIR}/data"
"${OBS_BUILD_DIR}/plugins/${target}/data" "${OBS_BUILD_DIR}/data/obs-plugins/${target}"
COMMENT "Copy ${target} resources to data directory" COMMENT "Copy ${target} resources to data directory"
VERBATIM) VERBATIM)
endif() endif()
@@ -133,7 +133,7 @@ function(target_add_resource target resource)
install( install(
FILES "${resource}" FILES "${resource}"
DESTINATION "${target}/data" DESTINATION data/obs-plugins/${target}
COMPONENT Runtime) COMPONENT Runtime)
if(OBS_BUILD_DIR) if(OBS_BUILD_DIR)
@@ -141,9 +141,9 @@ function(target_add_resource target resource)
TARGET ${target} TARGET ${target}
POST_BUILD POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E make_directory COMMAND "${CMAKE_COMMAND}" -E make_directory
"${OBS_BUILD_DIR}/plugins/${target}/data" "${OBS_BUILD_DIR}/data/obs-plugins/${target}"
COMMAND "${CMAKE_COMMAND}" -E copy "${resource}" COMMAND "${CMAKE_COMMAND}" -E copy "${resource}"
"${OBS_BUILD_DIR}/plugins/${target}/data" "${OBS_BUILD_DIR}/data/obs-plugins/${target}"
COMMENT "Copy ${target} resource ${resource} to library directory" COMMENT "Copy ${target} resource ${resource} to library directory"
VERBATIM) VERBATIM)
endif() endif()

View File

@@ -2,13 +2,12 @@
#define MyAppVersion "@CMAKE_PROJECT_VERSION@" #define MyAppVersion "@CMAKE_PROJECT_VERSION@"
#define MyAppPublisher "@PLUGIN_AUTHOR@" #define MyAppPublisher "@PLUGIN_AUTHOR@"
#define MyAppURL "@PLUGIN_WEBSITE@" #define MyAppURL "@PLUGIN_WEBSITE@"
#define MyAppId "@UUID_APP@"
[Setup] [Setup]
; NOTE: The value of AppId uniquely identifies this application. ; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications. ; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{{#MyAppId}} AppId={{@UUID_APP@}
AppName={#MyAppName} AppName={#MyAppName}
AppVersion={#MyAppVersion} AppVersion={#MyAppVersion}
AppPublisher={#MyAppPublisher} AppPublisher={#MyAppPublisher}
@@ -21,19 +20,14 @@ OutputBaseFilename={#MyAppName}-{#MyAppVersion}-Windows-Installer
Compression=lzma Compression=lzma
SolidCompression=yes SolidCompression=yes
DirExistsWarning=no DirExistsWarning=no
UsePreviousAppDir=no
SetupIconFile=installer.ico SetupIconFile=installer.ico
UninstallDisplayIcon={code:GetUninstallIconPath} UninstallDisplayIcon={app}\data\obs-plugins\advanced-scene-switcher\res\images\logo.ico
DisableDirPage=no
[Languages] [Languages]
Name: "english"; MessagesFile: "compiler:Default.isl" Name: "english"; MessagesFile: "compiler:Default.isl"
[Files] [Files]
; Recommended layout - used when installing to %ProgramData%\obs-studio\plugins\ Source: "..\release\Package\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "..\release\Package\recommended\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; Check: IsRecommendedLayout
; Legacy layout - used when installing to the OBS installation directory
Source: "..\release\Package\portable\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; Check: IsLegacyLayout
Source: "..\LICENSE"; Flags: dontcopy Source: "..\LICENSE"; Flags: dontcopy
; NOTE: Don't use "Flags: ignoreversion" on any shared system files ; NOTE: Don't use "Flags: ignoreversion" on any shared system files
@@ -56,64 +50,17 @@ begin
); );
end; end;
// Returns true when the selected install directory is under %ProgramData%, // credit where it's due :
// meaning the recommended plugin layout should be used. // following function come from https://github.com/Xaymar/obs-studio_amf-encoder-plugin/blob/master/%23Resources/Installer.in.iss#L45
function IsRecommendedLayout(): Boolean;
begin
Result := Pos(LowerCase(ExpandConstant('{commonappdata}')),
LowerCase(WizardDirValue())) = 1;
end;
function IsLegacyLayout(): Boolean;
begin
Result := not IsRecommendedLayout();
end;
function GetUninstallIconPath(Param: string): string;
begin
if IsRecommendedLayout() then
Result := ExpandConstant('{app}\advanced-scene-switcher\data\res\images\logo.ico')
else
Result := ExpandConstant('{app}\data\obs-plugins\advanced-scene-switcher\res\images\logo.ico');
end;
function GetDirName(Value: string): string; function GetDirName(Value: string): string;
var var
PrevPath: string; InstallPath: string;
UninstallKey: string;
begin begin
Result := ExpandConstant('{commonappdata}\obs-studio\plugins'); // initialize default path, which will be returned when the following registry
UninstallKey := 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' + '{' + '{#MyAppId}' + '}_is1'; // key queries fail due to missing keys or for some different reason
if RegQueryStringValue(HKLM, UninstallKey, 'InstallLocation', PrevPath) and (PrevPath <> '') then Result := '{autopf}\obs-studio';
Result := PrevPath; // query the first registry value; if this succeeds, return the obtained value
if RegQueryStringValue(HKLM32, 'SOFTWARE\OBS Studio', '', InstallPath) then
Result := InstallPath
end; end;
// Remove files placed by the portable installer (obs-plugins/64bit and
// data/obs-plugins layout) so the plugin is not loaded twice by OBS.
// Only runs when upgrading from a portable location to the recommended one.
procedure RemoveLegacyFiles();
var
OldInstallPath: string;
UninstallKey: string;
begin
if not IsRecommendedLayout() then
Exit;
UninstallKey := 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' + '{' + '{#MyAppId}' + '}_is1';
if not RegQueryStringValue(HKLM, UninstallKey, 'InstallLocation', OldInstallPath) then
Exit;
// Skip if the previous install was already in the recommended location
if Pos(LowerCase(ExpandConstant('{commonappdata}')), LowerCase(OldInstallPath)) = 1 then
Exit;
DeleteFile(OldInstallPath + '\obs-plugins\64bit\advanced-scene-switcher.dll');
DeleteFile(OldInstallPath + '\obs-plugins\64bit\advanced-scene-switcher.pdb');
DeleteFile(OldInstallPath + '\obs-plugins\64bit\advanced-scene-switcher-lib.dll');
DeleteFile(OldInstallPath + '\obs-plugins\64bit\advanced-scene-switcher-lib.pdb');
DelTree(OldInstallPath + '\obs-plugins\64bit\advanced-scene-switcher-plugins', True, True, True);
DelTree(OldInstallPath + '\data\obs-plugins\advanced-scene-switcher', True, True, True);
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssInstall then
RemoveLegacyFiles();
end;

View File

@@ -1,86 +0,0 @@
# ---------------------------------------------------------------------------
# Detects OpenSSL installed via winget or other common Windows locations,
# without requiring the user to manually set OPENSSL_ROOT_DIR.
# ---------------------------------------------------------------------------
if(WIN32 AND (NOT OpenSSL_FOUND))
set(_openssl_roots
"$ENV{ProgramFiles}/OpenSSL-Win64" "$ENV{ProgramFiles}/OpenSSL"
"$ENV{ProgramW6432}/OpenSSL-Win64")
set(_openssl_lib_suffixes "lib/VC/x64/MD" "lib/VC/x64/MDd" "lib/VC/x64/MT"
"lib/VC/x64/MTd" "lib")
# Determine which configuration we're building
if(CMAKE_BUILD_TYPE MATCHES "Debug")
set(_is_debug TRUE)
else()
set(_is_debug FALSE)
endif()
# Determine which runtime we use Default to /MD (shared CRT)
set(_crt_kind "MD")
if(MSVC)
if(CMAKE_MSVC_RUNTIME_LIBRARY MATCHES "MultiThreaded")
if(CMAKE_MSVC_RUNTIME_LIBRARY MATCHES "Debug")
set(_crt_kind "MTd")
else()
set(_crt_kind "MT")
endif()
else()
if(_is_debug)
set(_crt_kind "MDd")
else()
set(_crt_kind "MD")
endif()
endif()
endif()
message(STATUS "Looking for OpenSSL built with CRT variant: ${_crt_kind}")
# Try to find the root and corresponding lib path
if(OPENSSL_USE_STATIC_LIBS)
set(_crypto_lib_name "libcrypto_static.lib")
set(_ssl_lib_name "libssl_static.lib")
else()
set(_crypto_lib_name "libcrypto.lib")
set(_ssl_lib_name "libssl.lib")
endif()
foreach(_root ${_openssl_roots})
if(EXISTS "${_root}/include/openssl/ssl.h")
foreach(_suffix ${_openssl_lib_suffixes})
if(_suffix MATCHES "${_crt_kind}$"
AND EXISTS "${_root}/${_suffix}/${_crypto_lib_name}")
set(OPENSSL_ROOT_DIR
"${_root}"
CACHE PATH "Path to OpenSSL root")
set(OPENSSL_CRYPTO_LIBRARY
"${_root}/${_suffix}/${_crypto_lib_name}"
CACHE FILEPATH "OpenSSL crypto lib")
set(OPENSSL_SSL_LIBRARY
"${_root}/${_suffix}/${_ssl_lib_name}"
CACHE FILEPATH "OpenSSL ssl lib")
set(OPENSSL_INCLUDE_DIR
"${_root}/include"
CACHE PATH "OpenSSL include dir")
set(OpenSSL_FOUND
TRUE
CACHE BOOL "Whether OpenSSL was found")
message(STATUS "Found OpenSSL at: ${_root}/${_suffix}")
return()
endif()
endforeach()
endif()
if(OpenSSL_FOUND)
break()
endif()
endforeach()
if(NOT OpenSSL_FOUND)
message(WARNING "Could not auto-detect OpenSSL under Program Files. "
"Might have to set OPENSSL_ROOT_DIR manually.")
endif()
endif()

View File

@@ -12,7 +12,7 @@ AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Aktiviere den Szenenwe
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Aktiviere den Szenenwechsler nicht" AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Aktiviere den Szenenwechsler nicht"
AdvSceneSwitcher.generalTab.status.start="Start" AdvSceneSwitcher.generalTab.status.start="Start"
AdvSceneSwitcher.generalTab.status.stop="Stop" AdvSceneSwitcher.generalTab.status.stop="Stop"
AdvSceneSwitcher.generalTab.status.autoStart.startup="Starte auotmatischen den Szenenwechsler beim:" AdvSceneSwitcher.generalTab.status.autoStart="Starte auotmatischen den Szenenwechsler beim:"
AdvSceneSwitcher.generalTab.status.autoStart.never="Niemals" AdvSceneSwitcher.generalTab.status.autoStart.never="Niemals"
AdvSceneSwitcher.generalTab.status.autoStart.recording="Aufnehmen" AdvSceneSwitcher.generalTab.status.autoStart.recording="Aufnehmen"
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Streamen" AdvSceneSwitcher.generalTab.status.autoStart.streaming="Streamen"
@@ -76,6 +76,7 @@ AdvSceneSwitcher.macroTab.name="Name:"
AdvSceneSwitcher.macroTab.run="Makro ausführen" AdvSceneSwitcher.macroTab.run="Makro ausführen"
AdvSceneSwitcher.macroTab.runFail="Ausführen von \"%1\" fehlgeschlagen!\nEntweder ist eine der Aktionen fehlgeschlagen oder das Makro wird bereits ausgeführt.\nSoll die aktuelle Ausführung gestoppt werden?" AdvSceneSwitcher.macroTab.runFail="Ausführen von \"%1\" fehlgeschlagen!\nEntweder ist eine der Aktionen fehlgeschlagen oder das Makro wird bereits ausgeführt.\nSoll die aktuelle Ausführung gestoppt werden?"
AdvSceneSwitcher.macroTab.runInParallel="Parallel zu anderen Makros ausführen" AdvSceneSwitcher.macroTab.runInParallel="Parallel zu anderen Makros ausführen"
AdvSceneSwitcher.macroTab.onChange="Nur bei Änderung ausführen"
AdvSceneSwitcher.macroTab.defaultname="Makro %1" AdvSceneSwitcher.macroTab.defaultname="Makro %1"
AdvSceneSwitcher.macroTab.defaultGroupName="Gruppe %1" AdvSceneSwitcher.macroTab.defaultGroupName="Gruppe %1"
AdvSceneSwitcher.macroTab.removeGroupPopup.text="Sicher, dass \"%1\" und alle zugehörigen Elemente gelöscht werden?" AdvSceneSwitcher.macroTab.removeGroupPopup.text="Sicher, dass \"%1\" und alle zugehörigen Elemente gelöscht werden?"
@@ -99,6 +100,7 @@ AdvSceneSwitcher.macroList.deleted="gelöscht"
AdvSceneSwitcher.macroList.duplicate="\"%1\" ist bereits ausgewählt!" AdvSceneSwitcher.macroList.duplicate="\"%1\" ist bereits ausgewählt!"
; Macro Logic ; Macro Logic
AdvSceneSwitcher.logic.none="Eintrag ignorieren"
AdvSceneSwitcher.logic.and="Und" AdvSceneSwitcher.logic.and="Und"
AdvSceneSwitcher.logic.or="Oder" AdvSceneSwitcher.logic.or="Oder"
AdvSceneSwitcher.logic.andNot="Und nicht" AdvSceneSwitcher.logic.andNot="Und nicht"
@@ -144,7 +146,11 @@ AdvSceneSwitcher.condition.file="Datei"
AdvSceneSwitcher.condition.file.type.match="entspricht" AdvSceneSwitcher.condition.file.type.match="entspricht"
AdvSceneSwitcher.condition.file.type.contentChange="Inhalt geändert" AdvSceneSwitcher.condition.file.type.contentChange="Inhalt geändert"
AdvSceneSwitcher.condition.file.type.dateChange="Änderungsdatum geändert" AdvSceneSwitcher.condition.file.type.dateChange="Änderungsdatum geändert"
AdvSceneSwitcher.condition.file.layout="{{filePath}}{{conditions}}{{regex}}" AdvSceneSwitcher.condition.file.remote="Entfernte Datei"
AdvSceneSwitcher.condition.file.local="Lokale Datei"
AdvSceneSwitcher.condition.file.entry.line1="{{fileType}}{{filePath}}{{conditions}}{{useRegex}}"
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFileContent}}"
AdvSceneSwitcher.condition.media="Medien" AdvSceneSwitcher.condition.media="Medien"
AdvSceneSwitcher.condition.media.source="Quelle" AdvSceneSwitcher.condition.media.source="Quelle"
AdvSceneSwitcher.condition.media.anyOnScene="Beliebige Medienquelle in" AdvSceneSwitcher.condition.media.anyOnScene="Beliebige Medienquelle in"
@@ -210,8 +216,8 @@ AdvSceneSwitcher.condition.record.state.start="Aufnahme läuft"
AdvSceneSwitcher.condition.record.state.pause="Aufnahme pausiert" AdvSceneSwitcher.condition.record.state.pause="Aufnahme pausiert"
AdvSceneSwitcher.condition.record.state.stop="Aufnahme gestoppt" AdvSceneSwitcher.condition.record.state.stop="Aufnahme gestoppt"
AdvSceneSwitcher.condition.process="Prozess" AdvSceneSwitcher.condition.process="Prozess"
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}läuft{{focused}}und ist fokusiert" AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}läuft{{focused}}und ist fokusiert"
AdvSceneSwitcher.condition.process.layout.focus="Aktueller Vordergrundprozess: {{focusProcess}}" AdvSceneSwitcher.condition.process.entry.focus="Aktueller Vordergrundprozess: {{focusProcess}}"
AdvSceneSwitcher.condition.idle="Leerlauf" AdvSceneSwitcher.condition.idle="Leerlauf"
AdvSceneSwitcher.condition.idle.entry="Keine Tastatur- oder Mauseingaben für {{duration}}" AdvSceneSwitcher.condition.idle.entry="Keine Tastatur- oder Mauseingaben für {{duration}}"
AdvSceneSwitcher.condition.pluginState="Plugin-Status" AdvSceneSwitcher.condition.pluginState="Plugin-Status"
@@ -285,14 +291,14 @@ AdvSceneSwitcher.condition.replay.state.started="Replay Buffer gestartet"
AdvSceneSwitcher.condition.replay.state.saved="Replay Buffer gespeichert" AdvSceneSwitcher.condition.replay.state.saved="Replay Buffer gespeichert"
AdvSceneSwitcher.condition.replay.entry="{{state}}" AdvSceneSwitcher.condition.replay.entry="{{state}}"
AdvSceneSwitcher.condition.date="Datum" AdvSceneSwitcher.condition.date="Datum"
AdvSceneSwitcher.day.any="Beliebiger Tag" AdvSceneSwitcher.condition.date.anyDay="Beliebiger Tag"
AdvSceneSwitcher.day.monday="Montag" AdvSceneSwitcher.condition.date.monday="Montag"
AdvSceneSwitcher.day.tuesday="Dienstag" AdvSceneSwitcher.condition.date.tuesday="Dienstag"
AdvSceneSwitcher.day.wednesday="Mittwoch" AdvSceneSwitcher.condition.date.wednesday="Mittwoch"
AdvSceneSwitcher.day.thursday="Donnerstag" AdvSceneSwitcher.condition.date.thursday="Donnerstag"
AdvSceneSwitcher.day.friday="Freitag" AdvSceneSwitcher.condition.date.friday="Freitag"
AdvSceneSwitcher.day.saturday="Samstag" AdvSceneSwitcher.condition.date.saturday="Samstag"
AdvSceneSwitcher.day.sunday="Sonntag" AdvSceneSwitcher.condition.date.sunday="Sonntag"
AdvSceneSwitcher.condition.date.state.at="Am" AdvSceneSwitcher.condition.date.state.at="Am"
AdvSceneSwitcher.condition.date.state.after="Nach" AdvSceneSwitcher.condition.date.state.after="Nach"
AdvSceneSwitcher.condition.date.state.before="Vor" AdvSceneSwitcher.condition.date.state.before="Vor"
@@ -303,13 +309,12 @@ AdvSceneSwitcher.condition.date.ignoreDate="Wenn diese Option nicht aktiviert is
AdvSceneSwitcher.condition.date.ignoreTime="Wenn diese Option nicht aktiviert ist, wird die Zeitkomponente ignoriert" AdvSceneSwitcher.condition.date.ignoreTime="Wenn diese Option nicht aktiviert ist, wird die Zeitkomponente ignoriert"
AdvSceneSwitcher.condition.date.showAdvancedSettings="Erweiterte Einstellungen anzeigen" AdvSceneSwitcher.condition.date.showAdvancedSettings="Erweiterte Einstellungen anzeigen"
AdvSceneSwitcher.condition.date.showSimpleSettings="Einfache Einstellungen anzeigen" AdvSceneSwitcher.condition.date.showSimpleSettings="Einfache Einstellungen anzeigen"
AdvSceneSwitcher.condition.date.layout.simple.day="Am{{dayOfWeek}}" AdvSceneSwitcher.condition.date.entry.simple="Am {{dayOfWeek}} {{weekCondition}} {{ignoreWeekTime}}{{weekTime}}"
AdvSceneSwitcher.condition.date.layout.simple.time="{{ignoreWeekTime}}{{weekCondition}}{{weekTime}}" AdvSceneSwitcher.condition.date.entry.advanced="{{condition}} {{ignoreDate}}{{date}} {{ignoreTime}}{{time}} {{separator}} {{date2}} {{time2}}"
AdvSceneSwitcher.condition.date.layout.advanced="{{condition}} {{ignoreDate}}{{date}} {{ignoreTime}}{{time}} {{separator}} {{date2}} {{time2}}" AdvSceneSwitcher.condition.date.entry.repeat="{{repeat}} Wiederholen alle {{duration}} bei Datumsübereinstimmung"
AdvSceneSwitcher.condition.date.layout.repeat="{{repeat}} Wiederholen alle {{duration}} bei Datumsübereinstimmung" AdvSceneSwitcher.condition.date.entry.pattern="Aktuelles Datum \"{{currentDate}}\" entspricht dem Muster {{pattern}}"
AdvSceneSwitcher.condition.date.layout.pattern="Aktuelles Datum \"{{currentDate}}\" entspricht dem Muster {{pattern}}" AdvSceneSwitcher.condition.date.entry.nextMatchDate="Nächster Treffer bei: %1"
AdvSceneSwitcher.condition.date.layout.nextMatchDate="Nächster Treffer bei: %1" AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}} Bei Wiederholung ausgewähltes Datum auf Wiederholungsdatum aktualisieren"
AdvSceneSwitcher.condition.date.layout.updateOnRepeat="{{updateOnRepeat}} Bei Wiederholung ausgewähltes Datum auf Wiederholungsdatum aktualisieren"
AdvSceneSwitcher.condition.sceneTransform="Szenenelement transformieren" AdvSceneSwitcher.condition.sceneTransform="Szenenelement transformieren"
AdvSceneSwitcher.condition.sceneTransform.getTransform="Transformation erhalten" AdvSceneSwitcher.condition.sceneTransform.getTransform="Transformation erhalten"
AdvSceneSwitcher.condition.sceneTransform.condition.match="entspricht Transformation" AdvSceneSwitcher.condition.sceneTransform.condition.match="entspricht Transformation"
@@ -378,12 +383,14 @@ AdvSceneSwitcher.condition.variable.type.greaterThanVariable="ist größer als d
; Macro Actions ; Macro Actions
AdvSceneSwitcher.action.scene="Szene wechseln" AdvSceneSwitcher.action.scene="Szene wechseln"
AdvSceneSwitcher.action.scene.entry="Wechsle{{sceneTypes}}Szene zu{{scenes}}mittels{{transitions}}mit einer Dauer von{{duration}}Sekunden"
AdvSceneSwitcher.action.scene.entry.noDuration="Wechsle{{sceneTypes}}Szene zu{{scenes}}mittels{{transitions}}"
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Warten, bis der Übergang zur Zielszene abgeschlossen ist" AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Warten, bis der Übergang zur Zielszene abgeschlossen ist"
AdvSceneSwitcher.action.wait="Warten" AdvSceneSwitcher.action.wait="Warten"
AdvSceneSwitcher.action.wait.type.fixed="fixe" AdvSceneSwitcher.action.wait.type.fixed="fixe"
AdvSceneSwitcher.action.wait.type.random="zufällig" AdvSceneSwitcher.action.wait.type.random="zufällig"
AdvSceneSwitcher.action.wait.layout.fixed="Warte für {{waitType}} Dauer von {{duration}}" AdvSceneSwitcher.action.wait.entry.fixed="Warte für {{waitType}} Dauer von {{duration}}"
AdvSceneSwitcher.action.wait.layout.random="Warte für {{waitType}} Dauer von {{duration}} bis {{duration2}}" AdvSceneSwitcher.action.wait.entry.random="Warte für {{waitType}} Dauer von {{duration}} bis {{duration2}}"
AdvSceneSwitcher.action.audio="Audio" AdvSceneSwitcher.action.audio="Audio"
AdvSceneSwitcher.action.audio.type.mute="Stummgeschaltet" AdvSceneSwitcher.action.audio.type.mute="Stummgeschaltet"
AdvSceneSwitcher.action.audio.type.unmute="Nicht stummgeschaltet" AdvSceneSwitcher.action.audio.type.unmute="Nicht stummgeschaltet"
@@ -407,6 +414,7 @@ AdvSceneSwitcher.action.recording.type.unpause="Aufnahme nicht mehr pausieren"
AdvSceneSwitcher.action.recording.type.split="Aufnahme-Datei teilen" AdvSceneSwitcher.action.recording.type.split="Aufnahme-Datei teilen"
AdvSceneSwitcher.action.recording.pause.hint="Bitte beachten, dass je nach Aufnahmeeinstellung die Aufnahme möglicherweise nicht unterbrochen werden kann" AdvSceneSwitcher.action.recording.pause.hint="Bitte beachten, dass je nach Aufnahmeeinstellung die Aufnahme möglicherweise nicht unterbrochen werden kann"
AdvSceneSwitcher.action.recording.split.hint="Vergewissern, dass die automatische Dateiaufteilung in den OBS-Einstellungen aktiviert ist!" AdvSceneSwitcher.action.recording.split.hint="Vergewissern, dass die automatische Dateiaufteilung in den OBS-Einstellungen aktiviert ist!"
AdvSceneSwitcher.action.recording.entry="{{actions}}{{recordFolder}}{{recordFileFormat}}{{pauseHint}}{{splitHint}}"
AdvSceneSwitcher.action.replay="Replay Buffer" AdvSceneSwitcher.action.replay="Replay Buffer"
AdvSceneSwitcher.action.replay.saveWarn="Warnung: Ein zu häufiges Speichern kann dazu führen, dass der Replay Buffer nicht gespeichert wird!" AdvSceneSwitcher.action.replay.saveWarn="Warnung: Ein zu häufiges Speichern kann dazu führen, dass der Replay Buffer nicht gespeichert wird!"
AdvSceneSwitcher.action.replay.type.stop="Replay Buffer stoppen" AdvSceneSwitcher.action.replay.type.stop="Replay Buffer stoppen"
@@ -415,6 +423,7 @@ AdvSceneSwitcher.action.replay.type.save="Replay Buffer speichern"
AdvSceneSwitcher.action.streaming="Stream" AdvSceneSwitcher.action.streaming="Stream"
AdvSceneSwitcher.action.streaming.type.stop="Stream stoppen" AdvSceneSwitcher.action.streaming.type.stop="Stream stoppen"
AdvSceneSwitcher.action.streaming.type.start="Stream starten" AdvSceneSwitcher.action.streaming.type.start="Stream starten"
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
AdvSceneSwitcher.action.run="Ausführen" AdvSceneSwitcher.action.run="Ausführen"
AdvSceneSwitcher.action.sceneVisibility="Sichtbarkeit von Szenenelementen" AdvSceneSwitcher.action.sceneVisibility="Sichtbarkeit von Szenenelementen"
AdvSceneSwitcher.action.sceneVisibility.type.show="Anzeigen" AdvSceneSwitcher.action.sceneVisibility.type.show="Anzeigen"
@@ -422,7 +431,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.hide="Verstecken"
AdvSceneSwitcher.action.sceneVisibility.type.toggle="Umschalten" AdvSceneSwitcher.action.sceneVisibility.type.toggle="Umschalten"
AdvSceneSwitcher.action.sceneVisibility.type.source="Quelle" AdvSceneSwitcher.action.sceneVisibility.type.source="Quelle"
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Beliebig" AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Beliebig"
AdvSceneSwitcher.action.sceneVisibility.layout="Auf{{scenes}}{{actions}}{{sources}}" AdvSceneSwitcher.action.sceneVisibility.entry="Auf{{scenes}}{{actions}}{{sources}}"
AdvSceneSwitcher.action.filter="Filter" AdvSceneSwitcher.action.filter="Filter"
AdvSceneSwitcher.action.filter.type.enable="Aktivieren" AdvSceneSwitcher.action.filter.type.enable="Aktivieren"
AdvSceneSwitcher.action.filter.type.disable="Deaktivieren" AdvSceneSwitcher.action.filter.type.disable="Deaktivieren"
@@ -450,14 +459,14 @@ AdvSceneSwitcher.action.macro="Makro"
AdvSceneSwitcher.action.macro.type.pause="Pausieren" AdvSceneSwitcher.action.macro.type.pause="Pausieren"
AdvSceneSwitcher.action.macro.type.unpause="Nicht mehr pausieren" AdvSceneSwitcher.action.macro.type.unpause="Nicht mehr pausieren"
AdvSceneSwitcher.action.macro.type.resetCounter="Zähler zurücksetzen" AdvSceneSwitcher.action.macro.type.resetCounter="Zähler zurücksetzen"
AdvSceneSwitcher.action.macro.type.runActions="Aktionen ausführen" AdvSceneSwitcher.action.macro.type.run="Aktionen ausführen"
AdvSceneSwitcher.action.macro.type.stop="Aktionen stoppen" AdvSceneSwitcher.action.macro.type.stop="Aktionen stoppen"
AdvSceneSwitcher.action.pluginState="Plugin-Status" AdvSceneSwitcher.action.pluginState="Plugin-Status"
AdvSceneSwitcher.action.pluginState.type.stop="Erweiterten Automatischen Szenenwechsler stoppen" AdvSceneSwitcher.action.pluginState.type.stop="Erweiterten Automatischen Szenenwechsler stoppen"
AdvSceneSwitcher.action.pluginState.type.noMatch="Ändern des Nichtübereinstimmungsverhaltens:" AdvSceneSwitcher.action.pluginState.type.noMatch="Ändern des Nichtübereinstimmungsverhaltens:"
AdvSceneSwitcher.action.pluginState.type.import="Einstellungen importieren aus" AdvSceneSwitcher.action.pluginState.type.import="Einstellungen importieren aus"
AdvSceneSwitcher.action.pluginState.importWarning="Hinweis: Die Aktion wird ignoriert, solange das Einstellungsfenster geöffnet ist." AdvSceneSwitcher.action.pluginState.importWarning="Hinweis: Die Aktion wird ignoriert, solange das Einstellungsfenster geöffnet ist."
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}" AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
AdvSceneSwitcher.action.virtualCamera="Virtuelle Kamera" AdvSceneSwitcher.action.virtualCamera="Virtuelle Kamera"
AdvSceneSwitcher.action.virtualCamera.type.stop="Virtuelle Kamera stoppen" AdvSceneSwitcher.action.virtualCamera.type.stop="Virtuelle Kamera stoppen"
AdvSceneSwitcher.action.virtualCamera.type.start="Virtuelle Kamera starten" AdvSceneSwitcher.action.virtualCamera.type.start="Virtuelle Kamera starten"
@@ -498,9 +507,9 @@ AdvSceneSwitcher.action.transition.type.scene="Szenenübergang"
AdvSceneSwitcher.action.transition.type.sceneOverride="Szenenübergang überschreiben" AdvSceneSwitcher.action.transition.type.sceneOverride="Szenenübergang überschreiben"
AdvSceneSwitcher.action.transition.type.sourceShow="Übergang der Quelle anzeigen" AdvSceneSwitcher.action.transition.type.sourceShow="Übergang der Quelle anzeigen"
AdvSceneSwitcher.action.transition.type.sourceHide="Übergang der Quelle verstecken" AdvSceneSwitcher.action.transition.type.sourceHide="Übergang der Quelle verstecken"
AdvSceneSwitcher.action.transition.layout.type="Anpassen {{type}}{{scenes}}{{sources}}" AdvSceneSwitcher.action.transition.entry.line1="Anpassen {{type}}{{scenes}}{{sources}}"
AdvSceneSwitcher.action.transition.layout.transition="{{setTransition}}Übergangstyp festlegen auf {{transitions}}" AdvSceneSwitcher.action.transition.entry.line2="{{setTransition}}Übergangstyp festlegen auf {{transitions}}"
AdvSceneSwitcher.action.transition.layout.duration="{{setDuration}}Übergangsdauer festlegen auf {{duration}}Sekunden" AdvSceneSwitcher.action.transition.entry.line3="{{setDuration}}Übergangsdauer festlegen auf {{duration}}Sekunden"
AdvSceneSwitcher.action.timer="Timer" AdvSceneSwitcher.action.timer="Timer"
AdvSceneSwitcher.action.timer.type.pause="Pausieren" AdvSceneSwitcher.action.timer.type.pause="Pausieren"
AdvSceneSwitcher.action.timer.type.continue="Fortsetzen" AdvSceneSwitcher.action.timer.type.continue="Fortsetzen"
@@ -827,6 +836,8 @@ AdvSceneSwitcher.status.inactive="Inaktiv"
AdvSceneSwitcher.running="Plugin läuft" AdvSceneSwitcher.running="Plugin läuft"
AdvSceneSwitcher.stopped="Plugin gestoppt" AdvSceneSwitcher.stopped="Plugin gestoppt"
AdvSceneSwitcher.firstBootMessage="<html><head/><body><p>Dies scheint das erste Mal zu sein, dass der Erweiterte Szenenwechsler gestartet wurde.<br>Bitte schaue ins <a href=\"https://github.com/WarmUpTill/SceneSwitcher/wiki\"><span style=\" text-decoration: underline; color:#268bd2;\">Wiki</span></a> für eine Liste von Anleitungen und Beispielen.<br>Nicht zögern und Fragen im <a href=\"https://obsproject.com/forum/threads/advanced-scene-switcher.48264\"><span style=\" text-decoration: underline; color:#268bd2;\">Thread</span></a> des Plugins im OBS-Forum stellen!!</p></body></html>"
AdvSceneSwitcher.deprecatedTabWarning="Die Entwicklung für dieses Tab wurde gestoppt!\nBitte stattdessen zur Verwendung des Makros-Tab übergehen.\nDieser Hinweis kann im Allgemein-Tab deaktiviert werden." AdvSceneSwitcher.deprecatedTabWarning="Die Entwicklung für dieses Tab wurde gestoppt!\nBitte stattdessen zur Verwendung des Makros-Tab übergehen.\nDieser Hinweis kann im Allgemein-Tab deaktiviert werden."
AdvSceneSwitcher.unit.milliseconds="Millisekunden" AdvSceneSwitcher.unit.milliseconds="Millisekunden"

File diff suppressed because it is too large Load Diff

View File

@@ -12,7 +12,7 @@ AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Siempre iniciar el sel
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="No iniciar el selector de escenas" AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="No iniciar el selector de escenas"
AdvSceneSwitcher.generalTab.status.start="Iniciar" AdvSceneSwitcher.generalTab.status.start="Iniciar"
AdvSceneSwitcher.generalTab.status.stop="Detener" AdvSceneSwitcher.generalTab.status.stop="Detener"
AdvSceneSwitcher.generalTab.status.autoStart.startup="Iniciar automáticamente el selector de escenas cuando:" AdvSceneSwitcher.generalTab.status.autoStart="Iniciar automáticamente el selector de escenas cuando:"
AdvSceneSwitcher.generalTab.status.autoStart.never="Nunca" AdvSceneSwitcher.generalTab.status.autoStart.never="Nunca"
AdvSceneSwitcher.generalTab.status.autoStart.recording="Grabando" AdvSceneSwitcher.generalTab.status.autoStart.recording="Grabando"
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Emitiendo" AdvSceneSwitcher.generalTab.status.autoStart.streaming="Emitiendo"
@@ -72,6 +72,7 @@ AdvSceneSwitcher.macroTab.add="Agregar nueva macro"
AdvSceneSwitcher.macroTab.name="Nombre:" AdvSceneSwitcher.macroTab.name="Nombre:"
AdvSceneSwitcher.macroTab.run="Ejecutar macro" AdvSceneSwitcher.macroTab.run="Ejecutar macro"
AdvSceneSwitcher.macroTab.runInParallel="Ejecutar macro en paralelo a otras macros" AdvSceneSwitcher.macroTab.runInParallel="Ejecutar macro en paralelo a otras macros"
AdvSceneSwitcher.macroTab.onChange="Realizar acciones solo en el cambio de condición"
AdvSceneSwitcher.macroTab.defaultname="Macro %1" AdvSceneSwitcher.macroTab.defaultname="Macro %1"
AdvSceneSwitcher.macroTab.copy="Crear copia" AdvSceneSwitcher.macroTab.copy="Crear copia"
AdvSceneSwitcher.macroTab.expandAll="Expandir todo" AdvSceneSwitcher.macroTab.expandAll="Expandir todo"
@@ -83,6 +84,7 @@ AdvSceneSwitcher.macroTab.highlightTrueConditions="Resaltar condiciones de la ma
AdvSceneSwitcher.macroTab.highlightPerformedActions="Resaltar acciones realizadas recientemente de la macro seleccionada actualmente" AdvSceneSwitcher.macroTab.highlightPerformedActions="Resaltar acciones realizadas recientemente de la macro seleccionada actualmente"
; Lógica de macros ; Lógica de macros
AdvSceneSwitcher.logic.none="Omitir entrada"
AdvSceneSwitcher.logic.and="Y" AdvSceneSwitcher.logic.and="Y"
AdvSceneSwitcher.logic.or="O" AdvSceneSwitcher.logic.or="O"
AdvSceneSwitcher.logic.andNot="Y no" AdvSceneSwitcher.logic.andNot="Y no"
@@ -116,7 +118,9 @@ AdvSceneSwitcher.condition.scene.currentSceneTransitionBehaviour="Durante la tra
AdvSceneSwitcher.condition.scene.previousSceneTransitionBehaviour="Durante la transición, verifique la escena de origen de la transición" AdvSceneSwitcher.condition.scene.previousSceneTransitionBehaviour="Durante la transición, verifique la escena de origen de la transición"
AdvSceneSwitcher.condition.window="Ventana" AdvSceneSwitcher.condition.window="Ventana"
AdvSceneSwitcher.condition.file="Archivo" AdvSceneSwitcher.condition.file="Archivo"
AdvSceneSwitcher.condition.file.layout="Contenido de{{filePath}}{{conditions}}{{regex}}" AdvSceneSwitcher.condition.file.entry.line1="Contenido de{{fileType}}{{filePath}}{{conditions}}{{useRegex}}"
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFileContent}}"
AdvSceneSwitcher.condition.media="Medios" AdvSceneSwitcher.condition.media="Medios"
AdvSceneSwitcher.condition.media.anyOnScene="Cualquier fuente multimedia activada" AdvSceneSwitcher.condition.media.anyOnScene="Cualquier fuente multimedia activada"
AdvSceneSwitcher.condition.media.allOnScene="Todas las fuentes de medios activadas" AdvSceneSwitcher.condition.media.allOnScene="Todas las fuentes de medios activadas"
@@ -172,7 +176,7 @@ AdvSceneSwitcher.condition.record.state.start="Grabación en ejecución"
AdvSceneSwitcher.condition.record.state.pause="Grabación en pausa" AdvSceneSwitcher.condition.record.state.pause="Grabación en pausa"
AdvSceneSwitcher.condition.record.state.stop="Grabación detenida" AdvSceneSwitcher.condition.record.state.stop="Grabación detenida"
AdvSceneSwitcher.condition.process="Proceso" AdvSceneSwitcher.condition.process="Proceso"
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}se está ejecutando{{focused}}y está enfocado" AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}se está ejecutando{{focused}}y está enfocado"
AdvSceneSwitcher.condition.idle="Inactivo" AdvSceneSwitcher.condition.idle="Inactivo"
AdvSceneSwitcher.condition.idle.entry="No hay entradas de teclado o ratón durante {{duration}}" AdvSceneSwitcher.condition.idle.entry="No hay entradas de teclado o ratón durante {{duration}}"
AdvSceneSwitcher.condition.pluginState="Estado del complemento" AdvSceneSwitcher.condition.pluginState="Estado del complemento"
@@ -237,14 +241,14 @@ AdvSceneSwitcher.condition.replay.state.started="Búfer de reproducción iniciad
AdvSceneSwitcher.condition.replay.state.saved="Búfer de reproducción guardado" AdvSceneSwitcher.condition.replay.state.saved="Búfer de reproducción guardado"
AdvSceneSwitcher.condition.replay.entry="{{state}}" AdvSceneSwitcher.condition.replay.entry="{{state}}"
AdvSceneSwitcher.condition.date="Fecha" AdvSceneSwitcher.condition.date="Fecha"
AdvSceneSwitcher.day.any="Cualquier día" AdvSceneSwitcher.condition.date.anyDay="Cualquier día"
AdvSceneSwitcher.day.monday="Lunes" AdvSceneSwitcher.condition.date.monday="Lunes"
AdvSceneSwitcher.day.tuesday="Martes" AdvSceneSwitcher.condition.date.tuesday="Martes"
AdvSceneSwitcher.day.wednesday="Miércoles" AdvSceneSwitcher.condition.date.wednesday="Miércoles"
AdvSceneSwitcher.day.thursday="Jueves" AdvSceneSwitcher.condition.date.thursday="Jueves"
AdvSceneSwitcher.day.friday="Viernes" AdvSceneSwitcher.condition.date.friday="Viernes"
AdvSceneSwitcher.day.saturday="Sábado" AdvSceneSwitcher.condition.date.saturday="Sábado"
AdvSceneSwitcher.day.sunday="Domingo" AdvSceneSwitcher.condition.date.sunday="Domingo"
AdvSceneSwitcher.condition.date.state.at="A las" AdvSceneSwitcher.condition.date.state.at="A las"
AdvSceneSwitcher.condition.date.state.after="Después" AdvSceneSwitcher.condition.date.state.after="Después"
AdvSceneSwitcher.condition.date.state.before="Antes" AdvSceneSwitcher.condition.date.state.before="Antes"
@@ -254,12 +258,11 @@ AdvSceneSwitcher.condition.date.ignoreDate="Si no se marca, se ignorará el comp
AdvSceneSwitcher.condition.date.ignoreTime="Si no se marca, se ignorará el componente de tiempo" AdvSceneSwitcher.condition.date.ignoreTime="Si no se marca, se ignorará el componente de tiempo"
AdvSceneSwitcher.condition.date.showAdvancedSettings="Mostrar configuración avanzada" AdvSceneSwitcher.condition.date.showAdvancedSettings="Mostrar configuración avanzada"
AdvSceneSwitcher.condition.date.showSimpleSettings="Mostrar configuración simple" AdvSceneSwitcher.condition.date.showSimpleSettings="Mostrar configuración simple"
AdvSceneSwitcher.condition.date.layout.simple.day="El{{dayOfWeek}}" AdvSceneSwitcher.condition.date.entry.simple="El {{dayOfWeek}} {{weekCondition}} {{ignoreWeekTime}}{{weekTime}}"
AdvSceneSwitcher.condition.date.layout.simple.time="{{ignoreWeekTime}}{{weekCondition}}{{weekTime}}" AdvSceneSwitcher.condition.date.entry.advanced="{{condition}} {{ignoreDate}}{{date}} {{ignoreTime}}{{time}} {{separator}} {{date2}} {{time2}}"
AdvSceneSwitcher.condition.date.layout.advanced="{{condition}} {{ignoreDate}}{{date}} {{ignoreTime}}{{time}} {{separator}} {{date2}} {{time2}}" AdvSceneSwitcher.condition.date.entry.repeat="{{repeat}} Repetir cada {{duration}} en la coincidencia de fechas"
AdvSceneSwitcher.condition.date.layout.repeat="{{repeat}} Repetir cada {{duration}} en la coincidencia de fechas" AdvSceneSwitcher.condition.date.entry.nextMatchDate="Próxima coincidencia en: %1"
AdvSceneSwitcher.condition.date.layout.nextMatchDate="Próxima coincidencia en: %1" AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}} Al repetir actualizar la fecha seleccionada para repetir la fecha"
AdvSceneSwitcher.condition.date.layout.updateOnRepeat="{{updateOnRepeat}} Al repetir actualizar la fecha seleccionada para repetir la fecha"
AdvSceneSwitcher.condition.sceneTransform="Transformar elemento de escena" AdvSceneSwitcher.condition.sceneTransform="Transformar elemento de escena"
AdvSceneSwitcher.condition.sceneTransform.getTransform="Obtener transformación" AdvSceneSwitcher.condition.sceneTransform.getTransform="Obtener transformación"
AdvSceneSwitcher.condition.sceneTransform.condition.match="coincide con la transformación" AdvSceneSwitcher.condition.sceneTransform.condition.match="coincide con la transformación"
@@ -308,12 +311,13 @@ AdvSceneSwitcher.condition.stats.entry="{{stats}} esta {{condition}} {{value}}"
; Macro Actions ; Macro Actions
AdvSceneSwitcher.action.scene="Cambiar escena" AdvSceneSwitcher.action.scene="Cambiar escena"
AdvSceneSwitcher.action.scene.entry="Cambiar a la{{sceneTypes}}escena{{scenes}}usando{{transitions}}con una duración de{{duration}} segundos"
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Espere hasta que se complete la transición a la escena de destino" AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Espere hasta que se complete la transición a la escena de destino"
AdvSceneSwitcher.action.wait="Esperar" AdvSceneSwitcher.action.wait="Esperar"
AdvSceneSwitcher.action.wait.type.fixed="fijo" AdvSceneSwitcher.action.wait.type.fixed="fijo"
AdvSceneSwitcher.action.wait.type.random="aleatorio" AdvSceneSwitcher.action.wait.type.random="aleatorio"
AdvSceneSwitcher.action.wait.layout.fixed="Espere {{waitType}} de {{duration}}" AdvSceneSwitcher.action.wait.entry.fixed="Espere {{waitType}} de {{duration}}"
AdvSceneSwitcher.action.wait.layout.random="Espere {{waitType}} de {{duration}} a {{duration2}}" AdvSceneSwitcher.action.wait.entry.random="Espere {{waitType}} de {{duration}} a {{duration2}}"
AdvSceneSwitcher.action.audio="Audio" AdvSceneSwitcher.action.audio="Audio"
AdvSceneSwitcher.action.audio.type.mute="Silencio" AdvSceneSwitcher.action.audio.type.mute="Silencio"
AdvSceneSwitcher.action.audio.type.unmute="Activar silencio" AdvSceneSwitcher.action.audio.type.unmute="Activar silencio"
@@ -331,6 +335,7 @@ AdvSceneSwitcher.action.recording.type.start="Iniciar grabación"
AdvSceneSwitcher.action.recording.type.pause="Pausar grabación" AdvSceneSwitcher.action.recording.type.pause="Pausar grabación"
AdvSceneSwitcher.action.recording.type.unpause="Reanudar grabación" AdvSceneSwitcher.action.recording.type.unpause="Reanudar grabación"
AdvSceneSwitcher.action.recording.pause.hint="Tenga en cuenta que, dependiendo de la configuración de grabación, es posible que no pueda pausar la grabación" AdvSceneSwitcher.action.recording.pause.hint="Tenga en cuenta que, dependiendo de la configuración de grabación, es posible que no pueda pausar la grabación"
AdvSceneSwitcher.action.recording.entry="{{actions}}{{recordFolder}}{{recordFileFormat}}{{pauseHint}}{{splitHint}}"
AdvSceneSwitcher.action.replay="Búfer de reproducción" AdvSceneSwitcher.action.replay="Búfer de reproducción"
AdvSceneSwitcher.action.replay.saveWarn="Advertencia: ¡Guardar con demasiada frecuencia puede hacer que el búfer de reproducción no se guarde realmente!" AdvSceneSwitcher.action.replay.saveWarn="Advertencia: ¡Guardar con demasiada frecuencia puede hacer que el búfer de reproducción no se guarde realmente!"
AdvSceneSwitcher.action.replay.type.stop="Detener el búfer de reproducción" AdvSceneSwitcher.action.replay.type.stop="Detener el búfer de reproducción"
@@ -339,13 +344,14 @@ AdvSceneSwitcher.action.replay.type.save="Guardar búfer de reproducción"
AdvSceneSwitcher.action.streaming="Transmisión" AdvSceneSwitcher.action.streaming="Transmisión"
AdvSceneSwitcher.action.streaming.type.stop="Detener transmisión" AdvSceneSwitcher.action.streaming.type.stop="Detener transmisión"
AdvSceneSwitcher.action.streaming.type.start="Iniciar transmisión" AdvSceneSwitcher.action.streaming.type.start="Iniciar transmisión"
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
AdvSceneSwitcher.action.run="Ejecutar" AdvSceneSwitcher.action.run="Ejecutar"
AdvSceneSwitcher.action.sceneVisibility="Visibilidad del elemento de escena" AdvSceneSwitcher.action.sceneVisibility="Visibilidad del elemento de escena"
AdvSceneSwitcher.action.sceneVisibility.type.show="Mostrar" AdvSceneSwitcher.action.sceneVisibility.type.show="Mostrar"
AdvSceneSwitcher.action.sceneVisibility.type.hide="Ocultar" AdvSceneSwitcher.action.sceneVisibility.type.hide="Ocultar"
AdvSceneSwitcher.action.sceneVisibility.type.source="Fuente" AdvSceneSwitcher.action.sceneVisibility.type.source="Fuente"
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Cualquiera" AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Cualquiera"
AdvSceneSwitcher.action.sceneVisibility.layout="En{{scenes}}{{actions}}{{sources}}" AdvSceneSwitcher.action.sceneVisibility.entry="En{{scenes}}{{actions}}{{sources}}"
AdvSceneSwitcher.action.filter="Filtro" AdvSceneSwitcher.action.filter="Filtro"
AdvSceneSwitcher.action.filter.type.enable="Habilitar" AdvSceneSwitcher.action.filter.type.enable="Habilitar"
AdvSceneSwitcher.action.filter.type.disable="Deshabilitar" AdvSceneSwitcher.action.filter.type.disable="Deshabilitar"
@@ -370,14 +376,14 @@ AdvSceneSwitcher.action.macro="Macro"
AdvSceneSwitcher.action.macro.type.pause="Pausa" AdvSceneSwitcher.action.macro.type.pause="Pausa"
AdvSceneSwitcher.action.macro.type.unpause="Reanudar" AdvSceneSwitcher.action.macro.type.unpause="Reanudar"
AdvSceneSwitcher.action.macro.type.resetCounter="Reiniciar contador" AdvSceneSwitcher.action.macro.type.resetCounter="Reiniciar contador"
AdvSceneSwitcher.action.macro.type.runActions="Ejecutar" AdvSceneSwitcher.action.macro.type.run="Ejecutar"
AdvSceneSwitcher.action.macro.type.stop="Detener" AdvSceneSwitcher.action.macro.type.stop="Detener"
AdvSceneSwitcher.action.pluginState="Estado del complemento" AdvSceneSwitcher.action.pluginState="Estado del complemento"
AdvSceneSwitcher.action.pluginState.type.stop="Detener el complemento Advanced Scene Switcher" AdvSceneSwitcher.action.pluginState.type.stop="Detener el complemento Advanced Scene Switcher"
AdvSceneSwitcher.action.pluginState.type.noMatch="Cambiar el comportamiento de no coincidencia:" AdvSceneSwitcher.action.pluginState.type.noMatch="Cambiar el comportamiento de no coincidencia:"
AdvSceneSwitcher.action.pluginState.type.import="Importar configuración desde" AdvSceneSwitcher.action.pluginState.type.import="Importar configuración desde"
AdvSceneSwitcher.action.pluginState.importWarning="Nota: la acción se ignorará mientras se abra la ventana de configuración." AdvSceneSwitcher.action.pluginState.importWarning="Nota: la acción se ignorará mientras se abra la ventana de configuración."
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}" AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
AdvSceneSwitcher.action.virtualCamera="Cámara virtual" AdvSceneSwitcher.action.virtualCamera="Cámara virtual"
AdvSceneSwitcher.action.virtualCamera.type.stop="Detener cámara virtual" AdvSceneSwitcher.action.virtualCamera.type.stop="Detener cámara virtual"
AdvSceneSwitcher.action.virtualCamera.type.start="Iniciar cámara virtual" AdvSceneSwitcher.action.virtualCamera.type.start="Iniciar cámara virtual"
@@ -418,9 +424,9 @@ AdvSceneSwitcher.action.transition.type.scene="transición de escena"
AdvSceneSwitcher.action.transition.type.sceneOverride="anulación de transición de escena" AdvSceneSwitcher.action.transition.type.sceneOverride="anulación de transición de escena"
AdvSceneSwitcher.action.transition.type.sourceShow="transición del programa de origen" AdvSceneSwitcher.action.transition.type.sourceShow="transición del programa de origen"
AdvSceneSwitcher.action.transition.type.sourceHide="fuente ocultar transición" AdvSceneSwitcher.action.transition.type.sourceHide="fuente ocultar transición"
AdvSceneSwitcher.action.transition.layout.type="Modificar {{type}}{{scenes}}{{sources}}" AdvSceneSwitcher.action.transition.entry.line1="Modificar {{type}}{{scenes}}{{sources}}"
AdvSceneSwitcher.action.transition.layout.transition="{{setTransition}}Establecer el tipo de transición en {{transitions}}" AdvSceneSwitcher.action.transition.entry.line2="{{setTransition}}Establecer el tipo de transición en {{transitions}}"
AdvSceneSwitcher.action.transition.layout.duration="{{setDuration}}Establecer la duración de la transición en {{duration}}segundos" AdvSceneSwitcher.action.transition.entry.line3="{{setDuration}}Establecer la duración de la transición en {{duration}}segundos"
AdvSceneSwitcher.action.timer="Temporizador" AdvSceneSwitcher.action.timer="Temporizador"
AdvSceneSwitcher.action.timer.type.pause="Pausa" AdvSceneSwitcher.action.timer.type.pause="Pausa"
AdvSceneSwitcher.action.timer.type.continue="Continuar" AdvSceneSwitcher.action.timer.type.continue="Continuar"
@@ -675,6 +681,8 @@ AdvSceneSwitcher.status.inactive="Inactivo"
AdvSceneSwitcher.running="Iniciar complemento" AdvSceneSwitcher.running="Iniciar complemento"
AdvSceneSwitcher.stopped="Complemento de detención" AdvSceneSwitcher.stopped="Complemento de detención"
AdvSceneSwitcher.firstBootMessage="<html><head/><body><p>Esta parece ser la primera vez que se inicia el conmutador de escena avanzado.<br>Por favor, eche un vistazo a <a href=\"https:/ /github.com/WarmUpTill/SceneSwitcher/wiki\"><span style=\" text-decoration: underline; color:#268bd2;\">Wiki</span></a> para obtener una lista de guías y ejemplos.<br>No dude en hacer preguntas en el complemento <a href=\"https://obsproject.com /forum/threads/advanced-scene-switcher.48264\"><span style=\" text-decoration: underline; color:#268bd2;\">hilo</span></a> en los foros de OBS!</p></body></html>"
AdvSceneSwitcher.deprecatedTabWarning="¡Se detuvo el desarrollo de esta pestaña!\nConsidere cambiar a macros en su lugar.\nEsta sugerencia se puede desactivar en la pestaña General". AdvSceneSwitcher.deprecatedTabWarning="¡Se detuvo el desarrollo de esta pestaña!\nConsidere cambiar a macros en su lugar.\nEsta sugerencia se puede desactivar en la pestaña General".
AdvSceneSwitcher.unit.milliseconds="milisegundos" AdvSceneSwitcher.unit.milliseconds="milisegundos"

View File

@@ -12,7 +12,7 @@ AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Toujours démarrer le
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Ne pas démarrer le sélecteur de scène" AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Ne pas démarrer le sélecteur de scène"
AdvSceneSwitcher.generalTab.status.start="Démarrer" AdvSceneSwitcher.generalTab.status.start="Démarrer"
AdvSceneSwitcher.generalTab.status.stop="Arrêter" AdvSceneSwitcher.generalTab.status.stop="Arrêter"
AdvSceneSwitcher.generalTab.status.autoStart.startup="Démarrer automatiquement le sélecteur de scène lorsque :" AdvSceneSwitcher.generalTab.status.autoStart="Démarrer automatiquement le sélecteur de scène lorsque :"
AdvSceneSwitcher.generalTab.status.autoStart.never="Jamais" AdvSceneSwitcher.generalTab.status.autoStart.never="Jamais"
AdvSceneSwitcher.generalTab.status.autoStart.recording="Enregistrement" AdvSceneSwitcher.generalTab.status.autoStart.recording="Enregistrement"
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Diffusion en continu" AdvSceneSwitcher.generalTab.status.autoStart.streaming="Diffusion en continu"
@@ -78,6 +78,7 @@ AdvSceneSwitcher.macroTab.add="Ajouter une nouvelle macro"
AdvSceneSwitcher.macroTab.name="Nom :" AdvSceneSwitcher.macroTab.name="Nom :"
AdvSceneSwitcher.macroTab.run="Exécuter la macro" AdvSceneSwitcher.macroTab.run="Exécuter la macro"
AdvSceneSwitcher.macroTab.runInParallel="Exécuter la macro en parallèle avec d'autres macros" AdvSceneSwitcher.macroTab.runInParallel="Exécuter la macro en parallèle avec d'autres macros"
AdvSceneSwitcher.macroTab.onChange="Exécuter des actions uniquement en cas de changement de condition"
AdvSceneSwitcher.macroTab.defaultname="Macro %1" AdvSceneSwitcher.macroTab.defaultname="Macro %1"
AdvSceneSwitcher.macroTab.defaultGroupName="Groupe %1" AdvSceneSwitcher.macroTab.defaultGroupName="Groupe %1"
AdvSceneSwitcher.macroTab.removeSingleMacroPopup.text="Êtes-vous sûr de vouloir supprimer \"%1\" ?" AdvSceneSwitcher.macroTab.removeSingleMacroPopup.text="Êtes-vous sûr de vouloir supprimer \"%1\" ?"
@@ -131,6 +132,7 @@ AdvSceneSwitcher.macroList.deleted="supprimé"
AdvSceneSwitcher.macroList.duplicate="\"%1\" est déjà sélectionné !" AdvSceneSwitcher.macroList.duplicate="\"%1\" est déjà sélectionné !"
; Macro Logic ; Macro Logic
AdvSceneSwitcher.logic.none="Ignorer l'entrée"
AdvSceneSwitcher.logic.and="Et" AdvSceneSwitcher.logic.and="Et"
AdvSceneSwitcher.logic.or="Ou" AdvSceneSwitcher.logic.or="Ou"
AdvSceneSwitcher.logic.andNot="Et pas" AdvSceneSwitcher.logic.andNot="Et pas"
@@ -186,6 +188,8 @@ AdvSceneSwitcher.condition.file="Fichier"
AdvSceneSwitcher.condition.file.type.match="correspond à" AdvSceneSwitcher.condition.file.type.match="correspond à"
AdvSceneSwitcher.condition.file.type.contentChange="a changé de contenu" AdvSceneSwitcher.condition.file.type.contentChange="a changé de contenu"
AdvSceneSwitcher.condition.file.type.dateChange="a changé de date de modification" AdvSceneSwitcher.condition.file.type.dateChange="a changé de date de modification"
AdvSceneSwitcher.condition.file.remote="Fichier distant"
AdvSceneSwitcher.condition.file.local="Fichier local"
AdvSceneSwitcher.condition.media="Média" AdvSceneSwitcher.condition.media="Média"
AdvSceneSwitcher.condition.media.source="Source" AdvSceneSwitcher.condition.media.source="Source"
AdvSceneSwitcher.condition.media.anyOnScene="Toute source média sur la scène" AdvSceneSwitcher.condition.media.anyOnScene="Toute source média sur la scène"
@@ -257,10 +261,10 @@ AdvSceneSwitcher.condition.video.layout.modelPath="Données du modèle (classifi
AdvSceneSwitcher.condition.video.layout.minNeighbor="Nombre minimum de voisins :{{minNeighbors}}" AdvSceneSwitcher.condition.video.layout.minNeighbor="Nombre minimum de voisins :{{minNeighbors}}"
AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}Réduire la charge CPU en effectuant la vérification uniquement toutes les{{throttleCount}}millisecondes" AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}Réduire la charge CPU en effectuant la vérification uniquement toutes les{{throttleCount}}millisecondes"
AdvSceneSwitcher.condition.video.layout.checkAreaEnable="Effectuer la vérification uniquement dans la zone" AdvSceneSwitcher.condition.video.layout.checkAreaEnable="Effectuer la vérification uniquement dans la zone"
AdvSceneSwitcher.condition.video.layout.ocrColorPick="Vérifier la couleur du texte :{{color}}" AdvSceneSwitcher.condition.video.layout.ocrColorPick="Vérifier la couleur du texte :{{textColor}}{{selectColor}}"
AdvSceneSwitcher.condition.video.layout.ocrTextType="Vérifier le type de texte :{{textType}}" AdvSceneSwitcher.condition.video.layout.ocrTextType="Vérifier le type de texte :{{textType}}"
AdvSceneSwitcher.condition.video.layout.ocrLanguage="Vérifier la langue :{{languageCode}}" AdvSceneSwitcher.condition.video.layout.ocrLanguage="Vérifier la langue :{{languageCode}}"
AdvSceneSwitcher.condition.video.layout.color="Vérifier la couleur :{{color}}" AdvSceneSwitcher.condition.video.layout.color="Vérifier la couleur :{{color}}{{selectColor}}"
AdvSceneSwitcher.condition.video.minSize="Taille minimale :" AdvSceneSwitcher.condition.video.minSize="Taille minimale :"
AdvSceneSwitcher.condition.video.maxSize="Taille maximale :" AdvSceneSwitcher.condition.video.maxSize="Taille maximale :"
AdvSceneSwitcher.condition.video.selectArea="Sélectionner la zone" AdvSceneSwitcher.condition.video.selectArea="Sélectionner la zone"
@@ -278,8 +282,8 @@ AdvSceneSwitcher.condition.record.state.start="Enregistrement en cours"
AdvSceneSwitcher.condition.record.state.pause="Enregistrement en pause" AdvSceneSwitcher.condition.record.state.pause="Enregistrement en pause"
AdvSceneSwitcher.condition.record.state.stop="Arrêt de l'enregistrement" AdvSceneSwitcher.condition.record.state.stop="Arrêt de l'enregistrement"
AdvSceneSwitcher.condition.process="Processus" AdvSceneSwitcher.condition.process="Processus"
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}en cours d'exécution{{focused}}et est au premier plan" AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}en cours d'exécution{{focused}}et est au premier plan"
AdvSceneSwitcher.condition.process.layout.focus="Processus au premier plan actuel :{{focusProcess}}" AdvSceneSwitcher.condition.process.entry.focus="Processus au premier plan actuel :{{focusProcess}}"
AdvSceneSwitcher.condition.idle="Inactif" AdvSceneSwitcher.condition.idle="Inactif"
AdvSceneSwitcher.condition.idle.entry="Aucune entrée de clavier ou de souris pendant{{duration}}" AdvSceneSwitcher.condition.idle.entry="Aucune entrée de clavier ou de souris pendant{{duration}}"
AdvSceneSwitcher.condition.pluginState="État du plugin" AdvSceneSwitcher.condition.pluginState="État du plugin"
@@ -352,14 +356,14 @@ AdvSceneSwitcher.condition.replay.state.stopped="Tampon de répétition arrêté
AdvSceneSwitcher.condition.replay.state.started="Tampon de répétition démarré" AdvSceneSwitcher.condition.replay.state.started="Tampon de répétition démarré"
AdvSceneSwitcher.condition.replay.state.saved="Tampon de répétition enregistré" AdvSceneSwitcher.condition.replay.state.saved="Tampon de répétition enregistré"
AdvSceneSwitcher.condition.date="Date" AdvSceneSwitcher.condition.date="Date"
AdvSceneSwitcher.day.any="N'importe quel jour" AdvSceneSwitcher.condition.date.anyDay="N'importe quel jour"
AdvSceneSwitcher.day.monday="Lundi" AdvSceneSwitcher.condition.date.monday="Lundi"
AdvSceneSwitcher.day.tuesday="Mardi" AdvSceneSwitcher.condition.date.tuesday="Mardi"
AdvSceneSwitcher.day.wednesday="Mercredi" AdvSceneSwitcher.condition.date.wednesday="Mercredi"
AdvSceneSwitcher.day.thursday="Jeudi" AdvSceneSwitcher.condition.date.thursday="Jeudi"
AdvSceneSwitcher.day.friday="Vendredi" AdvSceneSwitcher.condition.date.friday="Vendredi"
AdvSceneSwitcher.day.saturday="Samedi" AdvSceneSwitcher.condition.date.saturday="Samedi"
AdvSceneSwitcher.day.sunday="Dimanche" AdvSceneSwitcher.condition.date.sunday="Dimanche"
AdvSceneSwitcher.condition.date.state.at="À" AdvSceneSwitcher.condition.date.state.at="À"
AdvSceneSwitcher.condition.date.state.after="Après" AdvSceneSwitcher.condition.date.state.after="Après"
AdvSceneSwitcher.condition.date.state.before="Avant" AdvSceneSwitcher.condition.date.state.before="Avant"
@@ -370,12 +374,11 @@ AdvSceneSwitcher.condition.date.ignoreDate="Si non cochée, la composante date s
AdvSceneSwitcher.condition.date.ignoreTime="Si non cochée, la composante heure sera ignorée" AdvSceneSwitcher.condition.date.ignoreTime="Si non cochée, la composante heure sera ignorée"
AdvSceneSwitcher.condition.date.showAdvancedSettings="Afficher les paramètres avancés" AdvSceneSwitcher.condition.date.showAdvancedSettings="Afficher les paramètres avancés"
AdvSceneSwitcher.condition.date.showSimpleSettings="Afficher les paramètres simples" AdvSceneSwitcher.condition.date.showSimpleSettings="Afficher les paramètres simples"
AdvSceneSwitcher.condition.date.layout.simple.day="Le{{dayOfWeek}}" AdvSceneSwitcher.condition.date.entry.simple="Le{{dayOfWeek}}{{weekCondition}}{{ignoreWeekTime}}{{weekTime}}"
AdvSceneSwitcher.condition.date.layout.simple.time="{{ignoreWeekTime}}{{weekCondition}}{{weekTime}}" AdvSceneSwitcher.condition.date.entry.repeat="{{repeat}}Répéter toutes les{{duration}}lorsque la date correspond"
AdvSceneSwitcher.condition.date.layout.repeat="{{repeat}}Répéter toutes les{{duration}}lorsque la date correspond" AdvSceneSwitcher.condition.date.entry.pattern="La date actuelle \"{{currentDate}}\" correspond au motif{{pattern}}"
AdvSceneSwitcher.condition.date.layout.pattern="La date actuelle \"{{currentDate}}\" correspond au motif{{pattern}}" AdvSceneSwitcher.condition.date.entry.nextMatchDate="Prochaine correspondance à : %1"
AdvSceneSwitcher.condition.date.layout.nextMatchDate="Prochaine correspondance à : %1" AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}}À la répétition, mettre à jour la date sélectionnée pour la date de répétition"
AdvSceneSwitcher.condition.date.layout.updateOnRepeat="{{updateOnRepeat}}À la répétition, mettre à jour la date sélectionnée pour la date de répétition"
AdvSceneSwitcher.condition.sceneTransform="Transformation de l'élément de la scène" AdvSceneSwitcher.condition.sceneTransform="Transformation de l'élément de la scène"
AdvSceneSwitcher.condition.sceneTransform.getTransform="Obtenir la transformation" AdvSceneSwitcher.condition.sceneTransform.getTransform="Obtenir la transformation"
AdvSceneSwitcher.condition.sceneTransform.condition.match="correspond à la transformation" AdvSceneSwitcher.condition.sceneTransform.condition.match="correspond à la transformation"
@@ -456,12 +459,14 @@ AdvSceneSwitcher.condition.slideshow.updateInterval.tooltip="Les informations su
AdvSceneSwitcher.action.scene="Changer de scène" AdvSceneSwitcher.action.scene="Changer de scène"
AdvSceneSwitcher.action.scene.type.program="Programme" AdvSceneSwitcher.action.scene.type.program="Programme"
AdvSceneSwitcher.action.scene.type.preview="Aperçu" AdvSceneSwitcher.action.scene.type.preview="Aperçu"
AdvSceneSwitcher.action.scene.entry="Changer la scène{{sceneTypes}}{{scenes}}en utilisant{{transitions}}avec une durée de{{duration}}secondes"
AdvSceneSwitcher.action.scene.entry.noDuration="Changer la scène{{sceneTypes}}{{scenes}}en utilisant{{transitions}}"
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Attendre que la transition vers la scène cible soit terminée" AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Attendre que la transition vers la scène cible soit terminée"
AdvSceneSwitcher.action.wait="Attendre" AdvSceneSwitcher.action.wait="Attendre"
AdvSceneSwitcher.action.wait.type.fixed="fixe" AdvSceneSwitcher.action.wait.type.fixed="fixe"
AdvSceneSwitcher.action.wait.type.random="aléatoire" AdvSceneSwitcher.action.wait.type.random="aléatoire"
AdvSceneSwitcher.action.wait.layout.fixed="Attendre pour{{waitType}}une durée de{{duration}}" AdvSceneSwitcher.action.wait.entry.fixed="Attendre pour{{waitType}}une durée de{{duration}}"
AdvSceneSwitcher.action.wait.layout.random="Attendre pour{{waitType}}une durée de{{duration}}à{{duration2}}" AdvSceneSwitcher.action.wait.entry.random="Attendre pour{{waitType}}une durée de{{duration}}à{{duration2}}"
AdvSceneSwitcher.action.audio="Audio" AdvSceneSwitcher.action.audio="Audio"
AdvSceneSwitcher.action.audio.type.mute="Muet" AdvSceneSwitcher.action.audio.type.mute="Muet"
AdvSceneSwitcher.action.audio.type.unmute="Activer le son" AdvSceneSwitcher.action.audio.type.unmute="Activer le son"
@@ -507,7 +512,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.hide="Masquer"
AdvSceneSwitcher.action.sceneVisibility.type.toggle="Basculer" AdvSceneSwitcher.action.sceneVisibility.type.toggle="Basculer"
AdvSceneSwitcher.action.sceneVisibility.type.source="Source" AdvSceneSwitcher.action.sceneVisibility.type.source="Source"
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="N'importe" AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="N'importe"
AdvSceneSwitcher.action.sceneVisibility.layout="Sur{{scenes}}{{actions}}{{sources}}" AdvSceneSwitcher.action.sceneVisibility.entry="Sur{{scenes}}{{actions}}{{sources}}"
AdvSceneSwitcher.action.filter="Filtre" AdvSceneSwitcher.action.filter="Filtre"
AdvSceneSwitcher.action.filter.type.enable="Activer" AdvSceneSwitcher.action.filter.type.enable="Activer"
AdvSceneSwitcher.action.filter.type.disable="Désactiver" AdvSceneSwitcher.action.filter.type.disable="Désactiver"
@@ -550,7 +555,7 @@ AdvSceneSwitcher.action.macro="Macro"
AdvSceneSwitcher.action.macro.type.pause="Pause" AdvSceneSwitcher.action.macro.type.pause="Pause"
AdvSceneSwitcher.action.macro.type.unpause="Reprendre" AdvSceneSwitcher.action.macro.type.unpause="Reprendre"
AdvSceneSwitcher.action.macro.type.resetCounter="Réinitialiser le compteur" AdvSceneSwitcher.action.macro.type.resetCounter="Réinitialiser le compteur"
AdvSceneSwitcher.action.macro.type.runActions="Exécuter les actions" AdvSceneSwitcher.action.macro.type.run="Exécuter les actions"
AdvSceneSwitcher.action.macro.type.stop="Arrêter les actions" AdvSceneSwitcher.action.macro.type.stop="Arrêter les actions"
AdvSceneSwitcher.action.macro.type.disableAction="Désactiver l'action" AdvSceneSwitcher.action.macro.type.disableAction="Désactiver l'action"
AdvSceneSwitcher.action.macro.type.enableAction="Activer l'action" AdvSceneSwitcher.action.macro.type.enableAction="Activer l'action"
@@ -619,9 +624,9 @@ AdvSceneSwitcher.action.transition.type.scene="Transition de scène"
AdvSceneSwitcher.action.transition.type.sceneOverride="Remplacement de la transition de scène" AdvSceneSwitcher.action.transition.type.sceneOverride="Remplacement de la transition de scène"
AdvSceneSwitcher.action.transition.type.sourceShow="Transition d'affichage de la source" AdvSceneSwitcher.action.transition.type.sourceShow="Transition d'affichage de la source"
AdvSceneSwitcher.action.transition.type.sourceHide="Transition de masquage de la source" AdvSceneSwitcher.action.transition.type.sourceHide="Transition de masquage de la source"
AdvSceneSwitcher.action.transition.layout.type="Modifier{{type}}{{scenes}}{{sources}}" AdvSceneSwitcher.action.transition.entry.line1="Modifier{{type}}{{scenes}}{{sources}}"
AdvSceneSwitcher.action.transition.layout.transition="{{setTransition}}Définir le type de transition sur{{transitions}}" AdvSceneSwitcher.action.transition.entry.line2="{{setTransition}}Définir le type de transition sur{{transitions}}"
AdvSceneSwitcher.action.transition.layout.duration="{{setDuration}}Définir la durée de la transition à{{duration}}secondes" AdvSceneSwitcher.action.transition.entry.line3="{{setDuration}}Définir la durée de la transition à{{duration}}secondes"
AdvSceneSwitcher.action.timer="Minuterie" AdvSceneSwitcher.action.timer="Minuterie"
AdvSceneSwitcher.action.timer.type.pause="Mettre en pause" AdvSceneSwitcher.action.timer.type.pause="Mettre en pause"
AdvSceneSwitcher.action.timer.type.continue="Continuer" AdvSceneSwitcher.action.timer.type.continue="Continuer"
@@ -698,8 +703,8 @@ AdvSceneSwitcher.action.variable.invalidSelection="Sélection invalide !"
AdvSceneSwitcher.action.variable.actionNoVariableSupport="La récupération de valeurs de variables à partir d'actions %1 n'est pas prise en charge !" AdvSceneSwitcher.action.variable.actionNoVariableSupport="La récupération de valeurs de variables à partir d'actions %1 n'est pas prise en charge !"
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="La récupération de valeurs de variables à partir de conditions %1 n'est pas prise en charge !" AdvSceneSwitcher.action.variable.conditionNoVariableSupport="La récupération de valeurs de variables à partir de conditions %1 n'est pas prise en charge !"
AdvSceneSwitcher.action.variable.currentSegmentValue="Valeur actuelle :" AdvSceneSwitcher.action.variable.currentSegmentValue="Valeur actuelle :"
AdvSceneSwitcher.action.variable.layout.substringIndex="Début de la sous-chaîne :{{subStringStart}}Taille de la sous-chaîne :{{subStringSize}}{{subStringRegex}}" AdvSceneSwitcher.action.variable.layout.substringIndex="Début de la sous-chaîne :{{subStringStart}}Taille de la sous-chaîne :{{subStringSize}}"
AdvSceneSwitcher.action.variable.layout.substringRegex="Attribuer la valeur du match{{regexMatchIdx}}en utilisant une expression régulière:{{subStringRegex}}" AdvSceneSwitcher.action.variable.layout.substringRegex="Attribuer la valeur du match{{regexMatchIdx}}en utilisant une expression régulière :"
AdvSceneSwitcher.action.variable.layout.userInput.customPrompt="{{useCustomPrompt}}Utiliser un message personnalisé{{inputPrompt}}" AdvSceneSwitcher.action.variable.layout.userInput.customPrompt="{{useCustomPrompt}}Utiliser un message personnalisé{{inputPrompt}}"
AdvSceneSwitcher.action.variable.layout.userInput.placeholder="{{useInputPlaceholder}}Remplir avec un indicateur de position{{inputPlaceholder}}" AdvSceneSwitcher.action.variable.layout.userInput.placeholder="{{useInputPlaceholder}}Remplir avec un indicateur de position{{inputPlaceholder}}"
AdvSceneSwitcher.action.projector="Projecteur" AdvSceneSwitcher.action.projector="Projecteur"
@@ -1102,15 +1107,15 @@ AdvSceneSwitcher.sceneItemSelection.configure="Configurer le type de sélection
AdvSceneSwitcher.sceneItemSelection.type.sourceName="Nom de la source" AdvSceneSwitcher.sceneItemSelection.type.sourceName="Nom de la source"
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable="Nom de la variable" AdvSceneSwitcher.sceneItemSelection.type.sourceVariable="Nom de la variable"
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern="Le nom de la source correspond au motif" AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern="Le nom de la source correspond au motif"
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.layout="{{nameConflictIndex}}correspondant à{{pattern}}{{regex}}" AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.entry="{{nameConflictIndex}}correspondant à{{pattern}}{{regex}}"
AdvSceneSwitcher.sceneItemSelection.type.sourceType="Sources de type" AdvSceneSwitcher.sceneItemSelection.type.sourceType="Sources de type"
AdvSceneSwitcher.sceneItemSelection.type.sourceType.layout="{{nameConflictIndex}}Type de source{{sourceTypes}}" AdvSceneSwitcher.sceneItemSelection.type.sourceType.entry="{{nameConflictIndex}}Type de source{{sourceTypes}}"
AdvSceneSwitcher.sceneItemSelection.type.index="Source avec index" AdvSceneSwitcher.sceneItemSelection.type.index="Source avec index"
AdvSceneSwitcher.sceneItemSelection.type.index.layout="{{index}}source" AdvSceneSwitcher.sceneItemSelection.type.index.entry="{{index}}source"
AdvSceneSwitcher.sceneItemSelection.type.indexRange="Sources dans la plage d'index" AdvSceneSwitcher.sceneItemSelection.type.indexRange="Sources dans la plage d'index"
AdvSceneSwitcher.sceneItemSelection.type.indexRange.layout="Sources de{{index}}à{{indexEnd}}" AdvSceneSwitcher.sceneItemSelection.type.indexRange.entry="Sources de{{index}}à{{indexEnd}}"
AdvSceneSwitcher.sceneItemSelection.type.all="Toutes les sources" AdvSceneSwitcher.sceneItemSelection.type.all="Toutes les sources"
AdvSceneSwitcher.sceneItemSelection.type.all.layout="Toutes les sources" AdvSceneSwitcher.sceneItemSelection.type.all.entry="Toutes les sources"
AdvSceneSwitcher.sceneItemSelection.all="Tout" AdvSceneSwitcher.sceneItemSelection.all="Tout"
AdvSceneSwitcher.sceneItemSelection.any="N'importe lequel" AdvSceneSwitcher.sceneItemSelection.any="N'importe lequel"
@@ -1119,6 +1124,8 @@ AdvSceneSwitcher.status.inactive="Inactif"
AdvSceneSwitcher.running="Plugin en cours d'exécution" AdvSceneSwitcher.running="Plugin en cours d'exécution"
AdvSceneSwitcher.stopped="Plugin arrêté" AdvSceneSwitcher.stopped="Plugin arrêté"
AdvSceneSwitcher.firstBootMessage="<html><head/><body><p>Il semble que ce soit la première fois que l'Advanced Scene Switcher est démarré.<br>Veuillez consulter le <a href=\"https://github.com/WarmUpTill/SceneSwitcher/wiki\"><span style=\" text-decoration: underline; color:#268bd2;\">Wiki</span></a> pour obtenir une liste de guides et d'exemples.<br>N'hésitez pas à poser des questions dans le <a href=\"https://obsproject.com/forum/threads/advanced-scene-switcher.48264\"><span style=\" text-decoration: underline; color:#268bd2;\">fil de discussion</span></a> du plugin sur les forums OBS !</p></body></html>"
AdvSceneSwitcher.deprecatedTabWarning="Le développement de cet onglet est terminé !\nVeuillez envisager de passer à l'utilisation des Macros à la place.\nCette astuce peut être désactivée dans l'onglet Général." AdvSceneSwitcher.deprecatedTabWarning="Le développement de cet onglet est terminé !\nVeuillez envisager de passer à l'utilisation des Macros à la place.\nCette astuce peut être désactivée dans l'onglet Général."
AdvSceneSwitcher.unit.milliseconds="millisecondes" AdvSceneSwitcher.unit.milliseconds="millisecondes"

File diff suppressed because it is too large Load Diff

View File

@@ -12,7 +12,7 @@ AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Sempre iniciar o switc
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Não iniciar o switcher de cenas" AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Não iniciar o switcher de cenas"
AdvSceneSwitcher.generalTab.status.start="Iniciar" AdvSceneSwitcher.generalTab.status.start="Iniciar"
AdvSceneSwitcher.generalTab.status.stop="Parar" AdvSceneSwitcher.generalTab.status.stop="Parar"
AdvSceneSwitcher.generalTab.status.autoStart.startup="Iniciar automaticamente o switcher de cenas quando:" AdvSceneSwitcher.generalTab.status.autoStart="Iniciar automaticamente o switcher de cenas quando:"
AdvSceneSwitcher.generalTab.status.autoStart.never="Nunca" AdvSceneSwitcher.generalTab.status.autoStart.never="Nunca"
AdvSceneSwitcher.generalTab.status.autoStart.recording="Gravando" AdvSceneSwitcher.generalTab.status.autoStart.recording="Gravando"
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Transmitindo" AdvSceneSwitcher.generalTab.status.autoStart.streaming="Transmitindo"
@@ -147,6 +147,7 @@ AdvSceneSwitcher.macroTab.run.tooltip="Execute todas as ações da macro indepen
AdvSceneSwitcher.macroTab.runElse="Executar macro (alternativa)" AdvSceneSwitcher.macroTab.runElse="Executar macro (alternativa)"
AdvSceneSwitcher.macroTab.runFail="Falha ao executar \"%1\"!\nUma das ações falhou ou a macro já está em execução.\nDeseja interrompê-la?" AdvSceneSwitcher.macroTab.runFail="Falha ao executar \"%1\"!\nUma das ações falhou ou a macro já está em execução.\nDeseja interrompê-la?"
AdvSceneSwitcher.macroTab.runInParallel="Executar macro em paralelo com outras macros" AdvSceneSwitcher.macroTab.runInParallel="Executar macro em paralelo com outras macros"
AdvSceneSwitcher.macroTab.onChange="Executar ações apenas quando houver mudança na condição"
AdvSceneSwitcher.macroTab.defaultname="Macro %1" AdvSceneSwitcher.macroTab.defaultname="Macro %1"
AdvSceneSwitcher.macroTab.defaultGroupName="Grupo %1" AdvSceneSwitcher.macroTab.defaultGroupName="Grupo %1"
AdvSceneSwitcher.macroTab.macroNameExists="O nome \"%1\" já está em uso por uma macro." AdvSceneSwitcher.macroTab.macroNameExists="O nome \"%1\" já está em uso por uma macro."
@@ -239,6 +240,7 @@ AdvSceneSwitcher.macroList.deleted="excluída"
AdvSceneSwitcher.macroList.duplicate="\"%1\" já está selecionada!" AdvSceneSwitcher.macroList.duplicate="\"%1\" já está selecionada!"
; Macro Logic ; Macro Logic
AdvSceneSwitcher.logic.none="Ignorar entrada"
AdvSceneSwitcher.logic.and="E" AdvSceneSwitcher.logic.and="E"
AdvSceneSwitcher.logic.or="Ou" AdvSceneSwitcher.logic.or="Ou"
AdvSceneSwitcher.logic.andNot="E não" AdvSceneSwitcher.logic.andNot="E não"
@@ -294,6 +296,11 @@ AdvSceneSwitcher.condition.file="Arquivo"
AdvSceneSwitcher.condition.file.type.match="corresponde" AdvSceneSwitcher.condition.file.type.match="corresponde"
AdvSceneSwitcher.condition.file.type.contentChange="conteúdo mudou" AdvSceneSwitcher.condition.file.type.contentChange="conteúdo mudou"
AdvSceneSwitcher.condition.file.type.dateChange="data de modificação mudou" AdvSceneSwitcher.condition.file.type.dateChange="data de modificação mudou"
AdvSceneSwitcher.condition.file.remote="Arquivo remoto"
AdvSceneSwitcher.condition.file.local="Arquivo local"
AdvSceneSwitcher.condition.file.entry.line1="{{fileType}}{{filePath}}{{conditions}}{{useRegex}}"
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFileContent}}"
AdvSceneSwitcher.condition.media="Mídia" AdvSceneSwitcher.condition.media="Mídia"
AdvSceneSwitcher.condition.media.checkType.state="Estado corresponde" AdvSceneSwitcher.condition.media.checkType.state="Estado corresponde"
AdvSceneSwitcher.condition.media.checkType.time="Restrição de tempo corresponde" AdvSceneSwitcher.condition.media.checkType.time="Restrição de tempo corresponde"
@@ -371,10 +378,10 @@ AdvSceneSwitcher.condition.video.layout.minNeighbor="Vizinhos mínimos:{{minNeig
AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}Reduzir carga de CPU realizando a verificação apenas a cada {{throttleCount}} milissegundos" AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}Reduzir carga de CPU realizando a verificação apenas a cada {{throttleCount}} milissegundos"
AdvSceneSwitcher.condition.video.layout.checkAreaEnable="Realizar verificação apenas na área" AdvSceneSwitcher.condition.video.layout.checkAreaEnable="Realizar verificação apenas na área"
AdvSceneSwitcher.condition.video.layout.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}" AdvSceneSwitcher.condition.video.layout.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
AdvSceneSwitcher.condition.video.layout.ocrColorPick="Verificar cor do texto:{{color}}" AdvSceneSwitcher.condition.video.layout.ocrColorPick="Verificar cor do texto:{{textColor}}{{selectColor}}"
AdvSceneSwitcher.condition.video.layout.ocrTextType="Verificar tipo de texto:{{textType}}" AdvSceneSwitcher.condition.video.layout.ocrTextType="Verificar tipo de texto:{{textType}}"
AdvSceneSwitcher.condition.video.layout.ocrLanguage="Verificar idioma:{{languageCode}}" AdvSceneSwitcher.condition.video.layout.ocrLanguage="Verificar idioma:{{languageCode}}"
AdvSceneSwitcher.condition.video.layout.color="Verificar cor:{{color}}" AdvSceneSwitcher.condition.video.layout.color="Verificar cor:{{color}}{{selectColor}}"
AdvSceneSwitcher.condition.video.minSize="Tamanho mínimo:" AdvSceneSwitcher.condition.video.minSize="Tamanho mínimo:"
AdvSceneSwitcher.condition.video.maxSize="Tamanho máximo:" AdvSceneSwitcher.condition.video.maxSize="Tamanho máximo:"
AdvSceneSwitcher.condition.video.selectArea="Selecionar área" AdvSceneSwitcher.condition.video.selectArea="Selecionar área"
@@ -394,8 +401,8 @@ AdvSceneSwitcher.condition.record.state.stop="Gravação parada"
AdvSceneSwitcher.condition.record.state.duration="Duração da gravação é maior que" AdvSceneSwitcher.condition.record.state.duration="Duração da gravação é maior que"
AdvSceneSwitcher.condition.record.entry="{{condition}}{{duration}}" AdvSceneSwitcher.condition.record.entry="{{condition}}{{duration}}"
AdvSceneSwitcher.condition.process="Processo" AdvSceneSwitcher.condition.process="Processo"
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}está em execução{{focused}}e está em foco" AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}está em execução{{focused}}e está em foco"
AdvSceneSwitcher.condition.process.layout.focus="Processo atual em primeiro plano:{{focusProcess}}" AdvSceneSwitcher.condition.process.entry.focus="Processo atual em primeiro plano:{{focusProcess}}"
AdvSceneSwitcher.condition.idle="Inativo" AdvSceneSwitcher.condition.idle="Inativo"
AdvSceneSwitcher.condition.idle.entry="Sem entradas de teclado ou mouse por {{duration}}" AdvSceneSwitcher.condition.idle.entry="Sem entradas de teclado ou mouse por {{duration}}"
AdvSceneSwitcher.condition.pluginState="Estado do plugin" AdvSceneSwitcher.condition.pluginState="Estado do plugin"
@@ -495,14 +502,14 @@ AdvSceneSwitcher.condition.replay.state.started="Buffer de replay iniciado"
AdvSceneSwitcher.condition.replay.state.saved="Buffer de replay salvo" AdvSceneSwitcher.condition.replay.state.saved="Buffer de replay salvo"
AdvSceneSwitcher.condition.replay.entry="{{state}}" AdvSceneSwitcher.condition.replay.entry="{{state}}"
AdvSceneSwitcher.condition.date="Data" AdvSceneSwitcher.condition.date="Data"
AdvSceneSwitcher.day.any="Qualquer dia" AdvSceneSwitcher.condition.date.anyDay="Qualquer dia"
AdvSceneSwitcher.day.monday="Segunda-feira" AdvSceneSwitcher.condition.date.monday="Segunda-feira"
AdvSceneSwitcher.day.tuesday="Terça-feira" AdvSceneSwitcher.condition.date.tuesday="Terça-feira"
AdvSceneSwitcher.day.wednesday="Quarta-feira" AdvSceneSwitcher.condition.date.wednesday="Quarta-feira"
AdvSceneSwitcher.day.thursday="Quinta-feira" AdvSceneSwitcher.condition.date.thursday="Quinta-feira"
AdvSceneSwitcher.day.friday="Sexta-feira" AdvSceneSwitcher.condition.date.friday="Sexta-feira"
AdvSceneSwitcher.day.saturday="Sábado" AdvSceneSwitcher.condition.date.saturday="Sábado"
AdvSceneSwitcher.day.sunday="Domingo" AdvSceneSwitcher.condition.date.sunday="Domingo"
AdvSceneSwitcher.condition.date.state.at="Às" AdvSceneSwitcher.condition.date.state.at="Às"
AdvSceneSwitcher.condition.date.state.after="Após" AdvSceneSwitcher.condition.date.state.after="Após"
AdvSceneSwitcher.condition.date.state.before="Antes" AdvSceneSwitcher.condition.date.state.before="Antes"
@@ -513,13 +520,12 @@ AdvSceneSwitcher.condition.date.ignoreDate="Se desmarcado, o componente de data
AdvSceneSwitcher.condition.date.ignoreTime="Se desmarcado, o componente de tempo será ignorado" AdvSceneSwitcher.condition.date.ignoreTime="Se desmarcado, o componente de tempo será ignorado"
AdvSceneSwitcher.condition.date.showAdvancedSettings="Mostrar configurações avançadas" AdvSceneSwitcher.condition.date.showAdvancedSettings="Mostrar configurações avançadas"
AdvSceneSwitcher.condition.date.showSimpleSettings="Mostrar configurações simples" AdvSceneSwitcher.condition.date.showSimpleSettings="Mostrar configurações simples"
AdvSceneSwitcher.condition.date.layout.simple.day="Em{{dayOfWeek}}" AdvSceneSwitcher.condition.date.entry.simple="Em{{dayOfWeek}}{{weekCondition}}{{ignoreWeekTime}}{{weekTime}}"
AdvSceneSwitcher.condition.date.layout.simple.time="{{ignoreWeekTime}}{{weekCondition}}{{weekTime}}" AdvSceneSwitcher.condition.date.entry.advanced="{{condition}}{{ignoreDate}}{{date}}{{ignoreTime}}{{time}}{{separator}}{{date2}}{{time2}}"
AdvSceneSwitcher.condition.date.layout.advanced="{{condition}}{{ignoreDate}}{{date}}{{ignoreTime}}{{time}}{{separator}}{{date2}}{{time2}}" AdvSceneSwitcher.condition.date.entry.repeat="{{repeat}}Repetir a cada{{duration}}em correspondência de data"
AdvSceneSwitcher.condition.date.layout.repeat="{{repeat}}Repetir a cada{{duration}}em correspondência de data" AdvSceneSwitcher.condition.date.entry.pattern="Data atual \"{{currentDate}}\" corresponde ao padrão{{pattern}}"
AdvSceneSwitcher.condition.date.layout.pattern="Data atual \"{{currentDate}}\" corresponde ao padrão{{pattern}}" AdvSceneSwitcher.condition.date.entry.nextMatchDate="Próxima correspondência em: %1"
AdvSceneSwitcher.condition.date.layout.nextMatchDate="Próxima correspondência em: %1" AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}}Ao repetir, atualize a data selecionada para a data de repetição"
AdvSceneSwitcher.condition.date.layout.updateOnRepeat="{{updateOnRepeat}}Ao repetir, atualize a data selecionada para a data de repetição"
AdvSceneSwitcher.condition.sceneTransform="Transformação do item de cena" AdvSceneSwitcher.condition.sceneTransform="Transformação do item de cena"
AdvSceneSwitcher.condition.sceneTransform.getTransform="Obter transformação" AdvSceneSwitcher.condition.sceneTransform.getTransform="Obter transformação"
AdvSceneSwitcher.condition.sceneTransform.getCurrentValue="Obter valor atual" AdvSceneSwitcher.condition.sceneTransform.getCurrentValue="Obter valor atual"
@@ -714,12 +720,15 @@ AdvSceneSwitcher.condition.noDevicesFoundWarning="Nenhum dispositivo USB detecta
AdvSceneSwitcher.action.scene="Trocar cena" AdvSceneSwitcher.action.scene="Trocar cena"
AdvSceneSwitcher.action.scene.type.program="Programa" AdvSceneSwitcher.action.scene.type.program="Programa"
AdvSceneSwitcher.action.scene.type.preview="Pré-visualização" AdvSceneSwitcher.action.scene.type.preview="Pré-visualização"
AdvSceneSwitcher.action.scene.entry="Trocar{{sceneTypes}}cena para{{scenes}}usando{{transitions}}com duração de{{duration}}segundos"
AdvSceneSwitcher.action.scene.entry.noDuration="Trocar{{sceneTypes}}cena para{{scenes}}usando{{transitions}}"
AdvSceneSwitcher.action.scene.entry.preview="Trocar{{sceneTypes}}cena para{{scenes}}"
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Aguardar até que a transição para a cena de destino seja concluída" AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Aguardar até que a transição para a cena de destino seja concluída"
AdvSceneSwitcher.action.wait="Aguardar" AdvSceneSwitcher.action.wait="Aguardar"
AdvSceneSwitcher.action.wait.type.fixed="fixo" AdvSceneSwitcher.action.wait.type.fixed="fixo"
AdvSceneSwitcher.action.wait.type.random="aleatório" AdvSceneSwitcher.action.wait.type.random="aleatório"
AdvSceneSwitcher.action.wait.layout.fixed="Aguardando por{{waitType}}duração de{{duration}}" AdvSceneSwitcher.action.wait.entry.fixed="Aguardando por{{waitType}}duração de{{duration}}"
AdvSceneSwitcher.action.wait.layout.random="Aguardando por{{waitType}}duração de{{duration}}para{{duration2}}" AdvSceneSwitcher.action.wait.entry.random="Aguardando por{{waitType}}duração de{{duration}}para{{duration2}}"
AdvSceneSwitcher.action.audio="Áudio" AdvSceneSwitcher.action.audio="Áudio"
AdvSceneSwitcher.action.audio.type.mute="Silenciar" AdvSceneSwitcher.action.audio.type.mute="Silenciar"
AdvSceneSwitcher.action.audio.type.unmute="Ativar som" AdvSceneSwitcher.action.audio.type.unmute="Ativar som"
@@ -748,6 +757,7 @@ AdvSceneSwitcher.action.recording.type.changeOutputFolder="Alterar pasta de saí
AdvSceneSwitcher.action.recording.type.changeOutputFileFormat="Alterar formatação do nome do arquivo" AdvSceneSwitcher.action.recording.type.changeOutputFileFormat="Alterar formatação do nome do arquivo"
AdvSceneSwitcher.action.recording.pause.hint="Observe que dependendo das suas configurações de gravação, você pode não conseguir pausar a gravação" AdvSceneSwitcher.action.recording.pause.hint="Observe que dependendo das suas configurações de gravação, você pode não conseguir pausar a gravação"
AdvSceneSwitcher.action.recording.split.hint="Certifique-se de habilitar a divisão automática de arquivos nas configurações do OBS primeiro!" AdvSceneSwitcher.action.recording.split.hint="Certifique-se de habilitar a divisão automática de arquivos nas configurações do OBS primeiro!"
AdvSceneSwitcher.action.recording.entry="{{actions}}{{recordFolder}}{{recordFileFormat}}{{pauseHint}}{{splitHint}}"
AdvSceneSwitcher.action.replay="Buffer de replay" AdvSceneSwitcher.action.replay="Buffer de replay"
AdvSceneSwitcher.action.replay.saveWarn="Aviso: Salvar com muita frequência pode resultar em o buffer de replay não ser realmente salvo!" AdvSceneSwitcher.action.replay.saveWarn="Aviso: Salvar com muita frequência pode resultar em o buffer de replay não ser realmente salvo!"
AdvSceneSwitcher.action.replay.durationWarn="Aviso: Alterar o tempo máximo de replay só se aplicará na próxima vez que o buffer de replay for iniciado!" AdvSceneSwitcher.action.replay.durationWarn="Aviso: Alterar o tempo máximo de replay só se aplicará na próxima vez que o buffer de replay for iniciado!"
@@ -764,6 +774,7 @@ AdvSceneSwitcher.action.streaming.type.server="Definir URL do servidor"
AdvSceneSwitcher.action.streaming.type.streamKey="Definir chave de transmissão" AdvSceneSwitcher.action.streaming.type.streamKey="Definir chave de transmissão"
AdvSceneSwitcher.action.streaming.type.username="Definir nome de usuário" AdvSceneSwitcher.action.streaming.type.username="Definir nome de usuário"
AdvSceneSwitcher.action.streaming.type.password="Definir senha" AdvSceneSwitcher.action.streaming.type.password="Definir senha"
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
AdvSceneSwitcher.action.run="Executar" AdvSceneSwitcher.action.run="Executar"
AdvSceneSwitcher.action.run.wait.entry="{{wait}}Aguardar a saída do processo ou no máximo {{timeout}}{{waitHelp}}" AdvSceneSwitcher.action.run.wait.entry="{{wait}}Aguardar a saída do processo ou no máximo {{timeout}}{{waitHelp}}"
AdvSceneSwitcher.action.run.wait.help.tooltip="Observe que as propriedades da macro não funcionarão se você deixar isso desmarcado, pois o processo é iniciado de forma independente do restante da lógica e não há controle sobre ele." AdvSceneSwitcher.action.run.wait.help.tooltip="Observe que as propriedades da macro não funcionarão se você deixar isso desmarcado, pois o processo é iniciado de forma independente do restante da lógica e não há controle sobre ele."
@@ -773,7 +784,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.hide="Ocultar"
AdvSceneSwitcher.action.sceneVisibility.type.toggle="Alternar" AdvSceneSwitcher.action.sceneVisibility.type.toggle="Alternar"
AdvSceneSwitcher.action.sceneVisibility.type.source="Fonte" AdvSceneSwitcher.action.sceneVisibility.type.source="Fonte"
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Qualquer" AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Qualquer"
AdvSceneSwitcher.action.sceneVisibility.layout="Em{{scenes}}{{actions}}{{sources}}" AdvSceneSwitcher.action.sceneVisibility.entry="Em{{scenes}}{{actions}}{{sources}}"
AdvSceneSwitcher.action.filter="Filtro" AdvSceneSwitcher.action.filter="Filtro"
AdvSceneSwitcher.action.filter.type.enable="Habilitar" AdvSceneSwitcher.action.filter.type.enable="Habilitar"
AdvSceneSwitcher.action.filter.type.disable="Desabilitar" AdvSceneSwitcher.action.filter.type.disable="Desabilitar"
@@ -838,7 +849,7 @@ AdvSceneSwitcher.action.macro="Macro"
AdvSceneSwitcher.action.macro.type.pause="Pausar" AdvSceneSwitcher.action.macro.type.pause="Pausar"
AdvSceneSwitcher.action.macro.type.unpause="Retomar" AdvSceneSwitcher.action.macro.type.unpause="Retomar"
AdvSceneSwitcher.action.macro.type.resetCounter="Reiniciar contador" AdvSceneSwitcher.action.macro.type.resetCounter="Reiniciar contador"
AdvSceneSwitcher.action.macro.type.runActions="Executar macro" AdvSceneSwitcher.action.macro.type.run="Executar macro"
AdvSceneSwitcher.action.macro.type.run.conditions.ignore="Não considerar o estado da condição" AdvSceneSwitcher.action.macro.type.run.conditions.ignore="Não considerar o estado da condição"
AdvSceneSwitcher.action.macro.type.run.conditions.true="Apenas se as condições forem verdadeiras" AdvSceneSwitcher.action.macro.type.run.conditions.true="Apenas se as condições forem verdadeiras"
AdvSceneSwitcher.action.macro.type.run.conditions.false="Apenas se as condições forem falsas" AdvSceneSwitcher.action.macro.type.run.conditions.false="Apenas se as condições forem falsas"
@@ -853,9 +864,9 @@ AdvSceneSwitcher.action.macro.type.stop="Parar ações"
AdvSceneSwitcher.action.macro.type.disableAction="Desabilitar ação" AdvSceneSwitcher.action.macro.type.disableAction="Desabilitar ação"
AdvSceneSwitcher.action.macro.type.enableAction="Habilitar ação" AdvSceneSwitcher.action.macro.type.enableAction="Habilitar ação"
AdvSceneSwitcher.action.macro.type.toggleAction="Alternar ação" AdvSceneSwitcher.action.macro.type.toggleAction="Alternar ação"
AdvSceneSwitcher.action.macro.layout.run="{{actions}}{{actionSections}}de{{macros}}" AdvSceneSwitcher.action.macro.entry.run="{{actions}}{{actionTypes}}de{{macros}}"
AdvSceneSwitcher.action.macro.layout.run.condition="{{conditionBehaviors}}de{{conditionMacros}}" AdvSceneSwitcher.action.macro.entry.run.condition="{{conditionBehaviors}}de{{conditionMacros}}"
AdvSceneSwitcher.action.macro.layout.other="{{actions}}{{macros}}" AdvSceneSwitcher.action.macro.entry.other="{{actions}}{{actionIndex}}{{macros}}"
AdvSceneSwitcher.action.pluginState="Estado do plugin" AdvSceneSwitcher.action.pluginState="Estado do plugin"
AdvSceneSwitcher.action.pluginState.type.stop="Parar o plugin Advanced Scene Switcher" AdvSceneSwitcher.action.pluginState.type.stop="Parar o plugin Advanced Scene Switcher"
AdvSceneSwitcher.action.pluginState.type.noMatch="Alterar o comportamento em caso de não correspondência:" AdvSceneSwitcher.action.pluginState.type.noMatch="Alterar o comportamento em caso de não correspondência:"
@@ -863,7 +874,7 @@ AdvSceneSwitcher.action.pluginState.type.import="Importar configurações de"
AdvSceneSwitcher.action.pluginState.importWarning="Nota: Ação será ignorada enquanto a janela de configurações estiver aberta." AdvSceneSwitcher.action.pluginState.importWarning="Nota: Ação será ignorada enquanto a janela de configurações estiver aberta."
AdvSceneSwitcher.action.pluginState.type.terminate="Desligar OBS" AdvSceneSwitcher.action.pluginState.type.terminate="Desligar OBS"
AdvSceneSwitcher.action.pluginState.terminateConfirm="O OBS será desligado automaticamente em 10 segundos!\nDeseja continuar com o desligamento do OBS?" AdvSceneSwitcher.action.pluginState.terminateConfirm="O OBS será desligado automaticamente em 10 segundos!\nDeseja continuar com o desligamento do OBS?"
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}" AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
AdvSceneSwitcher.action.virtualCamera="Câmera virtual" AdvSceneSwitcher.action.virtualCamera="Câmera virtual"
AdvSceneSwitcher.action.virtualCamera.type.stop="Parar câmera virtual" AdvSceneSwitcher.action.virtualCamera.type.stop="Parar câmera virtual"
AdvSceneSwitcher.action.virtualCamera.type.start="Iniciar câmera virtual" AdvSceneSwitcher.action.virtualCamera.type.start="Iniciar câmera virtual"
@@ -925,9 +936,9 @@ AdvSceneSwitcher.action.transition.type.scene="transição de cena"
AdvSceneSwitcher.action.transition.type.sceneOverride="substituição de transição de cena" AdvSceneSwitcher.action.transition.type.sceneOverride="substituição de transição de cena"
AdvSceneSwitcher.action.transition.type.sourceShow="transição de exibição de fonte" AdvSceneSwitcher.action.transition.type.sourceShow="transição de exibição de fonte"
AdvSceneSwitcher.action.transition.type.sourceHide="transição de ocultação de fonte" AdvSceneSwitcher.action.transition.type.sourceHide="transição de ocultação de fonte"
AdvSceneSwitcher.action.transition.layout.type="Modificar{{type}}{{scenes}}{{sources}}" AdvSceneSwitcher.action.transition.entry.line1="Modificar{{type}}{{scenes}}{{sources}}"
AdvSceneSwitcher.action.transition.layout.transition="{{setTransition}}Definir tipo de transição para{{transitions}}" AdvSceneSwitcher.action.transition.entry.line2="{{setTransition}}Definir tipo de transição para{{transitions}}"
AdvSceneSwitcher.action.transition.layout.duration="{{setDuration}}Definir duração da transição para{{duration}}segundos" AdvSceneSwitcher.action.transition.entry.line3="{{setDuration}}Definir duração da transição para{{duration}}segundos"
AdvSceneSwitcher.action.timer="Temporizador" AdvSceneSwitcher.action.timer="Temporizador"
AdvSceneSwitcher.action.timer.type.pause="Pausar" AdvSceneSwitcher.action.timer.type.pause="Pausar"
AdvSceneSwitcher.action.timer.type.continue="Continuar" AdvSceneSwitcher.action.timer.type.continue="Continuar"
@@ -1022,8 +1033,8 @@ AdvSceneSwitcher.action.variable.conditionNoVariableSupport="Obter valores de va
AdvSceneSwitcher.action.variable.currentSegmentValue="Valor atual:" AdvSceneSwitcher.action.variable.currentSegmentValue="Valor atual:"
AdvSceneSwitcher.action.variable.layout.pad="{{actions}}de{{variables}}para comprimento{{stringLength}}adicionando{{paddingCharSelection}}ao{{direction}}" AdvSceneSwitcher.action.variable.layout.pad="{{actions}}de{{variables}}para comprimento{{stringLength}}adicionando{{paddingCharSelection}}ao{{direction}}"
AdvSceneSwitcher.action.variable.layout.truncate="{{actions}}de{{variables}}para comprimento{{stringLength}}removendo caracteres da{{direction}}" AdvSceneSwitcher.action.variable.layout.truncate="{{actions}}de{{variables}}para comprimento{{stringLength}}removendo caracteres da{{direction}}"
AdvSceneSwitcher.action.variable.layout.substringIndex="Início da substring:{{subStringStart}}Tamanho da substring:{{subStringSize}}{{subStringRegex}}" AdvSceneSwitcher.action.variable.layout.substringIndex="Início da substring:{{subStringStart}}Tamanho da substring:{{subStringSize}}"
AdvSceneSwitcher.action.variable.layout.substringRegex="Atribuir valor do{{regexMatchIdx}}correspondência usando expressão regular:{{subStringRegex}}" AdvSceneSwitcher.action.variable.layout.substringRegex="Atribuir valor do{{regexMatchIdx}}correspondência usando expressão regular:"
AdvSceneSwitcher.action.variable.layout.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}" AdvSceneSwitcher.action.variable.layout.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
AdvSceneSwitcher.action.variable.layout.userInput.customPrompt="{{useCustomPrompt}}Usar prompt personalizado{{inputPrompt}}" AdvSceneSwitcher.action.variable.layout.userInput.customPrompt="{{useCustomPrompt}}Usar prompt personalizado{{inputPrompt}}"
AdvSceneSwitcher.action.variable.layout.userInput.placeholder="{{useInputPlaceholder}}Preencher com placeholder{{inputPlaceholder}}" AdvSceneSwitcher.action.variable.layout.userInput.placeholder="{{useInputPlaceholder}}Preencher com placeholder{{inputPlaceholder}}"
@@ -1057,8 +1068,8 @@ AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.enable="Habilitar modo apenas
AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.disable="Desabilitar modo apenas emotes no chat" AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.disable="Desabilitar modo apenas emotes no chat"
AdvSceneSwitcher.action.twitch.type.chat.sendMessage="Enviar mensagem de chat" AdvSceneSwitcher.action.twitch.type.chat.sendMessage="Enviar mensagem de chat"
AdvSceneSwitcher.action.twitch.categorySelectionDisabled="Não é possível selecionar categoria sem selecionar uma conta Twitch primeiro!" AdvSceneSwitcher.action.twitch.categorySelectionDisabled="Não é possível selecionar categoria sem selecionar uma conta Twitch primeiro!"
AdvSceneSwitcher.action.twitch.layout.default="Em{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}{{pointsReward}}{{nonModDelayDuration}}" AdvSceneSwitcher.action.twitch.entry.default="Em{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}{{pointsReward}}"
AdvSceneSwitcher.action.twitch.layout.chat="Usando conta{{account}}{{actions}}em{{channel}}" AdvSceneSwitcher.action.twitch.entry.chat="Usando conta{{account}}{{actions}}em{{channel}}"
AdvSceneSwitcher.action.twitch.title.title="Digite o título" AdvSceneSwitcher.action.twitch.title.title="Digite o título"
AdvSceneSwitcher.action.twitch.marker.description="Descreva o marcador" AdvSceneSwitcher.action.twitch.marker.description="Descreva o marcador"
AdvSceneSwitcher.action.twitch.clip.hasDelay="Adicionar um leve atraso antes de capturar o clipe" AdvSceneSwitcher.action.twitch.clip.hasDelay="Adicionar um leve atraso antes de capturar o clipe"
@@ -1840,19 +1851,19 @@ AdvSceneSwitcher.setting.transform.width="Largura"
AdvSceneSwitcher.sceneItemSelection.configure="Configurar tipo de seleção de item de cena" AdvSceneSwitcher.sceneItemSelection.configure="Configurar tipo de seleção de item de cena"
AdvSceneSwitcher.sceneItemSelection.type.sourceName="Nome da fonte" AdvSceneSwitcher.sceneItemSelection.type.sourceName="Nome da fonte"
AdvSceneSwitcher.sceneItemSelection.type.sourceName.layout="{{nameConflictIndex}}{{sourceName}}" AdvSceneSwitcher.sceneItemSelection.type.sourceName.entry="{{nameConflictIndex}}{{sourceName}}"
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable="Nome da variável" AdvSceneSwitcher.sceneItemSelection.type.sourceVariable="Nome da variável"
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable.layout="{{nameConflictIndex}}{{variable}}" AdvSceneSwitcher.sceneItemSelection.type.sourceVariable.entry="{{nameConflictIndex}}{{variable}}"
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern="Nome da fonte corresponde ao padrão" AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern="Nome da fonte corresponde ao padrão"
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.layout="{{nameConflictIndex}}correspondendo{{pattern}}{{regex}}" AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.entry="{{nameConflictIndex}}correspondendo{{pattern}}{{regex}}"
AdvSceneSwitcher.sceneItemSelection.type.sourceType="Fontes do tipo" AdvSceneSwitcher.sceneItemSelection.type.sourceType="Fontes do tipo"
AdvSceneSwitcher.sceneItemSelection.type.sourceType.layout="Tipo de fonte{{nameConflictIndex}}{{sourceTypes}}" AdvSceneSwitcher.sceneItemSelection.type.sourceType.entry="Tipo de fonte{{nameConflictIndex}}{{sourceTypes}}"
AdvSceneSwitcher.sceneItemSelection.type.index="Fonte com índice" AdvSceneSwitcher.sceneItemSelection.type.index="Fonte com índice"
AdvSceneSwitcher.sceneItemSelection.type.index.layout="{{index}}fonte" AdvSceneSwitcher.sceneItemSelection.type.index.entry="{{index}}fonte"
AdvSceneSwitcher.sceneItemSelection.type.indexRange="Fontes no intervalo de índices" AdvSceneSwitcher.sceneItemSelection.type.indexRange="Fontes no intervalo de índices"
AdvSceneSwitcher.sceneItemSelection.type.indexRange.layout="Fontes de{{index}}para{{indexEnd}}" AdvSceneSwitcher.sceneItemSelection.type.indexRange.entry="Fontes de{{index}}para{{indexEnd}}"
AdvSceneSwitcher.sceneItemSelection.type.all="Todas as fontes" AdvSceneSwitcher.sceneItemSelection.type.all="Todas as fontes"
AdvSceneSwitcher.sceneItemSelection.type.all.layout="Todas as fontes" AdvSceneSwitcher.sceneItemSelection.type.all.entry="Todas as fontes"
AdvSceneSwitcher.sceneItemSelection.all="Todas" AdvSceneSwitcher.sceneItemSelection.all="Todas"
AdvSceneSwitcher.sceneItemSelection.any="Qualquer" AdvSceneSwitcher.sceneItemSelection.any="Qualquer"
@@ -1863,6 +1874,8 @@ AdvSceneSwitcher.status.inactive="Inativo"
AdvSceneSwitcher.running="Plugin em execução" AdvSceneSwitcher.running="Plugin em execução"
AdvSceneSwitcher.stopped="Plugin parado" AdvSceneSwitcher.stopped="Plugin parado"
AdvSceneSwitcher.firstBootMessage="<html><head/><body><p>Parece que esta é a primeira vez que o Advanced Scene Switcher está sendo iniciado.<br>Por favor, consulte o <a href=\"https://github.com/WarmUpTill/SceneSwitcher/wiki\"><span style=\" text-decoration: underline; color:#268bd2;\">Wiki</span></a> para uma lista de guias e exemplos.<br>Não hesite em fazer perguntas no <a href=\"https://obsproject.com/forum/threads/advanced-scene-switcher.48264\"><span style=\" text-decoration: underline; color:#268bd2;\">tópico</span></a> do plugin nos fóruns do OBS!</p></body></html>"
AdvSceneSwitcher.deprecatedTabWarning="Desenvolvimento para esta aba interrompido!\nPor favor, considere a transição para o uso de Macros em vez disso.\nEsta dica pode ser desativada na aba Geral." AdvSceneSwitcher.deprecatedTabWarning="Desenvolvimento para esta aba interrompido!\nPor favor, considere a transição para o uso de Macros em vez disso.\nEsta dica pode ser desativada na aba Geral."
AdvSceneSwitcher.unit.milliseconds="milissegundos" AdvSceneSwitcher.unit.milliseconds="milissegundos"

View File

@@ -12,7 +12,7 @@ AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Всегда запу
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Не запускать переключатель сцен" AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Не запускать переключатель сцен"
AdvSceneSwitcher.generalTab.status.start="Старт" AdvSceneSwitcher.generalTab.status.start="Старт"
AdvSceneSwitcher.generalTab.status.stop="Стоп" AdvSceneSwitcher.generalTab.status.stop="Стоп"
AdvSceneSwitcher.generalTab.status.autoStart.startup="Автоматически запускать переключатель сцен, когда:" AdvSceneSwitcher.generalTab.status.autoStart="Автоматически запускать переключатель сцен, когда:"
AdvSceneSwitcher.generalTab.status.autoStart.never="Никогда" AdvSceneSwitcher.generalTab.status.autoStart.never="Никогда"
AdvSceneSwitcher.generalTab.status.autoStart.recording="Запись" AdvSceneSwitcher.generalTab.status.autoStart.recording="Запись"
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Вещание" AdvSceneSwitcher.generalTab.status.autoStart.streaming="Вещание"
@@ -70,6 +70,7 @@ AdvSceneSwitcher.macroTab.name="Имя:"
AdvSceneSwitcher.macroTab.defaultname="Макрос %1" AdvSceneSwitcher.macroTab.defaultname="Макрос %1"
AdvSceneSwitcher.macroTab.copy="Создать копию" AdvSceneSwitcher.macroTab.copy="Создать копию"
; Macro Logic ; Macro Logic
AdvSceneSwitcher.logic.none="Игнорировать вход"
AdvSceneSwitcher.logic.and="И" AdvSceneSwitcher.logic.and="И"
AdvSceneSwitcher.logic.or="Или" AdvSceneSwitcher.logic.or="Или"
AdvSceneSwitcher.logic.andNot="И не" AdvSceneSwitcher.logic.andNot="И не"
@@ -84,6 +85,8 @@ AdvSceneSwitcher.condition.scene.type.current="Текущий"
AdvSceneSwitcher.condition.scene.type.previous="Предыдущий" AdvSceneSwitcher.condition.scene.type.previous="Предыдущий"
AdvSceneSwitcher.condition.window="Окно" AdvSceneSwitcher.condition.window="Окно"
AdvSceneSwitcher.condition.file="Файл" AdvSceneSwitcher.condition.file="Файл"
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFileContent}}"
AdvSceneSwitcher.condition.media="Медиа" AdvSceneSwitcher.condition.media="Медиа"
AdvSceneSwitcher.condition.video="Видео" AdvSceneSwitcher.condition.video="Видео"
AdvSceneSwitcher.condition.video.condition.match="точно соответствует" AdvSceneSwitcher.condition.video.condition.match="точно соответствует"
@@ -102,7 +105,7 @@ AdvSceneSwitcher.condition.record.state.start="Запись запущена"
AdvSceneSwitcher.condition.record.state.pause="Запись приостановлена" AdvSceneSwitcher.condition.record.state.pause="Запись приостановлена"
AdvSceneSwitcher.condition.record.state.stop="Запись остановлена" AdvSceneSwitcher.condition.record.state.stop="Запись остановлена"
AdvSceneSwitcher.condition.process="Процесс" AdvSceneSwitcher.condition.process="Процесс"
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}запущен{{focused}}и сфокусирован" AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}запущен{{focused}}и сфокусирован"
AdvSceneSwitcher.condition.idle="Простой" AdvSceneSwitcher.condition.idle="Простой"
AdvSceneSwitcher.condition.idle.entry="Не было ни клавиатуры, ни мыши в течении{{duration}}" AdvSceneSwitcher.condition.idle.entry="Не было ни клавиатуры, ни мыши в течении{{duration}}"
AdvSceneSwitcher.condition.pluginState="Состояние плагина" AdvSceneSwitcher.condition.pluginState="Состояние плагина"
@@ -111,11 +114,12 @@ AdvSceneSwitcher.condition.pluginState.entry="{{condition}}"
; Macro Actions ; Macro Actions
AdvSceneSwitcher.action.scene="Переключить сцену" AdvSceneSwitcher.action.scene="Переключить сцену"
AdvSceneSwitcher.action.scene.entry="Перейти к сцене{{sceneTypes}}{{scenes}}используя{{transitions}}с продолжительностью{{duration}}секунд"
AdvSceneSwitcher.action.wait="Подождать" AdvSceneSwitcher.action.wait="Подождать"
AdvSceneSwitcher.action.wait.type.fixed="фиксированный" AdvSceneSwitcher.action.wait.type.fixed="фиксированный"
AdvSceneSwitcher.action.wait.type.random="случайный" AdvSceneSwitcher.action.wait.type.random="случайный"
AdvSceneSwitcher.action.wait.layout.fixed="Ожидать {{waitType}} в течении {{duration}}" AdvSceneSwitcher.action.wait.entry.fixed="Ожидать {{waitType}} в течении {{duration}}"
AdvSceneSwitcher.action.wait.layout.random="Ожидание {{waitType}} длительностью от {{duration}} до {{duration2}}" AdvSceneSwitcher.action.wait.entry.random="Ожидание {{waitType}} длительностью от {{duration}} до {{duration2}}"
AdvSceneSwitcher.action.audio="Аудио" AdvSceneSwitcher.action.audio="Аудио"
AdvSceneSwitcher.action.audio.type.mute="Замьютить" AdvSceneSwitcher.action.audio.type.mute="Замьютить"
AdvSceneSwitcher.action.audio.type.unmute="Размьютить" AdvSceneSwitcher.action.audio.type.unmute="Размьютить"
@@ -127,6 +131,7 @@ AdvSceneSwitcher.action.recording.type.start="Начать запись"
AdvSceneSwitcher.action.recording.type.pause="Пауза записи" AdvSceneSwitcher.action.recording.type.pause="Пауза записи"
AdvSceneSwitcher.action.recording.type.unpause="Снять запись с паузы" AdvSceneSwitcher.action.recording.type.unpause="Снять запись с паузы"
AdvSceneSwitcher.action.recording.pause.hint="Обратите внимание, что в зависимости от настроек записи вы можете не иметь возможности приостановить запись" AdvSceneSwitcher.action.recording.pause.hint="Обратите внимание, что в зависимости от настроек записи вы можете не иметь возможности приостановить запись"
AdvSceneSwitcher.action.recording.entry="{{actions}}{{recordFolder}}{{recordFileFormat}}{{pauseHint}}{{splitHint}}"
AdvSceneSwitcher.action.replay="Буфер воспроизведения" AdvSceneSwitcher.action.replay="Буфер воспроизведения"
AdvSceneSwitcher.action.replay.type.stop="Остановить буфер воспроизведения" AdvSceneSwitcher.action.replay.type.stop="Остановить буфер воспроизведения"
AdvSceneSwitcher.action.replay.type.start="Начать воспроизведение буфера" AdvSceneSwitcher.action.replay.type.start="Начать воспроизведение буфера"
@@ -134,6 +139,7 @@ AdvSceneSwitcher.action.replay.type.save="Сохранить буфер восп
AdvSceneSwitcher.action.streaming="Потоковое вещание" AdvSceneSwitcher.action.streaming="Потоковое вещание"
AdvSceneSwitcher.action.streaming.type.stop="Остановить потоковое вещание" AdvSceneSwitcher.action.streaming.type.stop="Остановить потоковое вещание"
AdvSceneSwitcher.action.streaming.type.start="Начать потоковое вещание" AdvSceneSwitcher.action.streaming.type.start="Начать потоковое вещание"
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
AdvSceneSwitcher.action.run="Запустить" AdvSceneSwitcher.action.run="Запустить"

View File

@@ -12,7 +12,7 @@ AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Her zaman sahne deği
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Sahne değiştiriciyi başlatma" AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Sahne değiştiriciyi başlatma"
AdvSceneSwitcher.generalTab.status.start="Başlat" AdvSceneSwitcher.generalTab.status.start="Başlat"
AdvSceneSwitcher.generalTab.status.stop="Durdur" AdvSceneSwitcher.generalTab.status.stop="Durdur"
AdvSceneSwitcher.generalTab.status.autoStart.startup="Aşağıdaki durumlarda sahne değiştiriciyi otomatik olarak başlatın:" AdvSceneSwitcher.generalTab.status.autoStart="Aşağıdaki durumlarda sahne değiştiriciyi otomatik olarak başlatın:"
AdvSceneSwitcher.generalTab.status.autoStart.never="Asla" AdvSceneSwitcher.generalTab.status.autoStart.never="Asla"
AdvSceneSwitcher.generalTab.status.autoStart.recording="Kayıt" AdvSceneSwitcher.generalTab.status.autoStart.recording="Kayıt"
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Yayın" AdvSceneSwitcher.generalTab.status.autoStart.streaming="Yayın"
@@ -72,12 +72,14 @@ AdvSceneSwitcher.macroTab.add="Yeni Makro ekle"
AdvSceneSwitcher.macroTab.name="İsim:" AdvSceneSwitcher.macroTab.name="İsim:"
AdvSceneSwitcher.macroTab.run="Makro Çalıştırma" AdvSceneSwitcher.macroTab.run="Makro Çalıştırma"
AdvSceneSwitcher.macroTab.runInParallel="Makroyu diğer makrolara paralel olarak çalıştırın" AdvSceneSwitcher.macroTab.runInParallel="Makroyu diğer makrolara paralel olarak çalıştırın"
AdvSceneSwitcher.macroTab.onChange="Eylemleri yalnızca koşul değişikliğinde gerçekleştirin"
AdvSceneSwitcher.macroTab.defaultname="Makro %1" AdvSceneSwitcher.macroTab.defaultname="Makro %1"
AdvSceneSwitcher.macroTab.copy="Kopya oluştur" AdvSceneSwitcher.macroTab.copy="Kopya oluştur"
AdvSceneSwitcher.macroTab.expandAll="Hepsini Genişlet" AdvSceneSwitcher.macroTab.expandAll="Hepsini Genişlet"
AdvSceneSwitcher.macroTab.collapseAll="Hepsini Küçült" AdvSceneSwitcher.macroTab.collapseAll="Hepsini Küçült"
; Macro Logic ; Macro Logic
AdvSceneSwitcher.logic.none="Girişi yoksay"
AdvSceneSwitcher.logic.and="Ve" AdvSceneSwitcher.logic.and="Ve"
AdvSceneSwitcher.logic.or="Ya da" AdvSceneSwitcher.logic.or="Ya da"
AdvSceneSwitcher.logic.andNot="ve değil" AdvSceneSwitcher.logic.andNot="ve değil"
@@ -106,7 +108,9 @@ AdvSceneSwitcher.condition.scene.type.notChanged="Sahne değişmedi"
AdvSceneSwitcher.condition.scene.currentSceneTransitionBehaviour="Geçiş hedefi sahnesi için geçiş kontrolü sırasında" AdvSceneSwitcher.condition.scene.currentSceneTransitionBehaviour="Geçiş hedefi sahnesi için geçiş kontrolü sırasında"
AdvSceneSwitcher.condition.window="Pencere" AdvSceneSwitcher.condition.window="Pencere"
AdvSceneSwitcher.condition.file="Dosya" AdvSceneSwitcher.condition.file="Dosya"
AdvSceneSwitcher.condition.file.layout="İçerik{{filePath}}{{conditions}}{{regex}}" AdvSceneSwitcher.condition.file.entry.line1="İçerik{{fileType}}{{filePath}}{{conditions}}{{useRegex}}"
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFileContent}}"
AdvSceneSwitcher.condition.media="Medya" AdvSceneSwitcher.condition.media="Medya"
AdvSceneSwitcher.condition.media.anyOnScene="Herhangi bir medya kaynağı" AdvSceneSwitcher.condition.media.anyOnScene="Herhangi bir medya kaynağı"
AdvSceneSwitcher.condition.media.allOnScene="Tüm medya kaynakları " AdvSceneSwitcher.condition.media.allOnScene="Tüm medya kaynakları "
@@ -149,7 +153,7 @@ AdvSceneSwitcher.condition.record.state.start="Kayıt Çalışıyor"
AdvSceneSwitcher.condition.record.state.pause="Kayıt durakladı" AdvSceneSwitcher.condition.record.state.pause="Kayıt durakladı"
AdvSceneSwitcher.condition.record.state.stop="Kayıt durdu" AdvSceneSwitcher.condition.record.state.stop="Kayıt durdu"
AdvSceneSwitcher.condition.process="İşlem" AdvSceneSwitcher.condition.process="İşlem"
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}çalışıyor{{focused}}ve odaklandı" AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}çalışıyor{{focused}}ve odaklandı"
AdvSceneSwitcher.condition.idle="Boşta" AdvSceneSwitcher.condition.idle="Boşta"
AdvSceneSwitcher.condition.idle.entry="...için klavye veya fare girişi yok {{duration}}" AdvSceneSwitcher.condition.idle.entry="...için klavye veya fare girişi yok {{duration}}"
AdvSceneSwitcher.condition.pluginState="Eklenti durumu" AdvSceneSwitcher.condition.pluginState="Eklenti durumu"
@@ -245,12 +249,13 @@ AdvSceneSwitcher.condition.openvr.entry.line3="HMD mevcut {{xPos}} x {{yPos}} x
; Macro Actions ; Macro Actions
AdvSceneSwitcher.action.scene="Sahne Degistirici" AdvSceneSwitcher.action.scene="Sahne Degistirici"
AdvSceneSwitcher.action.scene.entry="Sahneyi{{sceneTypes}}{{scenes}}kullanarak{{transitions}}süresi olan{{duration}}saniye"
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Hedef sahneye geçiş tamamlanana kadar bekleyin" AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Hedef sahneye geçiş tamamlanana kadar bekleyin"
AdvSceneSwitcher.action.wait="Bekle" AdvSceneSwitcher.action.wait="Bekle"
AdvSceneSwitcher.action.wait.type.fixed="sabit" AdvSceneSwitcher.action.wait.type.fixed="sabit"
AdvSceneSwitcher.action.wait.type.random="rastgele" AdvSceneSwitcher.action.wait.type.random="rastgele"
AdvSceneSwitcher.action.wait.layout.fixed="Şunu bekle {{waitType}} süre {{duration}}" AdvSceneSwitcher.action.wait.entry.fixed="Şunu bekle {{waitType}} süre {{duration}}"
AdvSceneSwitcher.action.wait.layout.random="Şunu bekle {{waitType}} bu aralıktan {{duration}} buna {{duration2}}" AdvSceneSwitcher.action.wait.entry.random="Şunu bekle {{waitType}} bu aralıktan {{duration}} buna {{duration2}}"
AdvSceneSwitcher.action.audio="Ses" AdvSceneSwitcher.action.audio="Ses"
AdvSceneSwitcher.action.audio.type.mute="Sessiz" AdvSceneSwitcher.action.audio.type.mute="Sessiz"
AdvSceneSwitcher.action.audio.type.unmute="Ses açmak" AdvSceneSwitcher.action.audio.type.unmute="Ses açmak"
@@ -262,6 +267,7 @@ AdvSceneSwitcher.action.recording.type.start="Kayıt Başlat"
AdvSceneSwitcher.action.recording.type.pause="Kayıt Duraklat" AdvSceneSwitcher.action.recording.type.pause="Kayıt Duraklat"
AdvSceneSwitcher.action.recording.type.unpause="Kayıt Duraklatma" AdvSceneSwitcher.action.recording.type.unpause="Kayıt Duraklatma"
AdvSceneSwitcher.action.recording.pause.hint="Kayıt ayarlarınıza bağlı olarak kaydı duraklatamayabileceğinizi unutmayın." AdvSceneSwitcher.action.recording.pause.hint="Kayıt ayarlarınıza bağlı olarak kaydı duraklatamayabileceğinizi unutmayın."
AdvSceneSwitcher.action.recording.entry="{{actions}}{{recordFolder}}{{recordFileFormat}}{{pauseHint}}{{splitHint}}"
AdvSceneSwitcher.action.replay="Tekrar arabelleği" AdvSceneSwitcher.action.replay="Tekrar arabelleği"
AdvSceneSwitcher.action.replay.type.stop="Tekrar arabelleğini durdur" AdvSceneSwitcher.action.replay.type.stop="Tekrar arabelleğini durdur"
AdvSceneSwitcher.action.replay.type.start="Tekrar arabelleğini başlat" AdvSceneSwitcher.action.replay.type.start="Tekrar arabelleğini başlat"
@@ -269,13 +275,14 @@ AdvSceneSwitcher.action.replay.type.save="Tekrar arabelleğini kaydet"
AdvSceneSwitcher.action.streaming="Yayın" AdvSceneSwitcher.action.streaming="Yayın"
AdvSceneSwitcher.action.streaming.type.stop="Yayın durdur" AdvSceneSwitcher.action.streaming.type.stop="Yayın durdur"
AdvSceneSwitcher.action.streaming.type.start="Yayın başlat" AdvSceneSwitcher.action.streaming.type.start="Yayın başlat"
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
AdvSceneSwitcher.action.run="Çalıştır" AdvSceneSwitcher.action.run="Çalıştır"
AdvSceneSwitcher.action.sceneVisibility="Sahne öğesi görünürlüğü" AdvSceneSwitcher.action.sceneVisibility="Sahne öğesi görünürlüğü"
AdvSceneSwitcher.action.sceneVisibility.type.show="Göster" AdvSceneSwitcher.action.sceneVisibility.type.show="Göster"
AdvSceneSwitcher.action.sceneVisibility.type.hide="Gizle" AdvSceneSwitcher.action.sceneVisibility.type.hide="Gizle"
AdvSceneSwitcher.action.sceneVisibility.type.source="Kayıt" AdvSceneSwitcher.action.sceneVisibility.type.source="Kayıt"
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Herhangi" AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Herhangi"
AdvSceneSwitcher.action.sceneVisibility.layout="Açık{{scenes}}{{actions}}{{sources}}" AdvSceneSwitcher.action.sceneVisibility.entry="Açık{{scenes}}{{actions}}{{sources}}"
AdvSceneSwitcher.action.filter="Filtrele" AdvSceneSwitcher.action.filter="Filtrele"
AdvSceneSwitcher.action.filter.type.enable="Etkin" AdvSceneSwitcher.action.filter.type.enable="Etkin"
AdvSceneSwitcher.action.filter.type.disable="Etkisiz" AdvSceneSwitcher.action.filter.type.disable="Etkisiz"
@@ -299,13 +306,13 @@ AdvSceneSwitcher.action.macro="Makro"
AdvSceneSwitcher.action.macro.type.pause="Duraklat" AdvSceneSwitcher.action.macro.type.pause="Duraklat"
AdvSceneSwitcher.action.macro.type.unpause="Duraklatma" AdvSceneSwitcher.action.macro.type.unpause="Duraklatma"
AdvSceneSwitcher.action.macro.type.resetCounter="Sayacı sıfırla" AdvSceneSwitcher.action.macro.type.resetCounter="Sayacı sıfırla"
AdvSceneSwitcher.action.macro.type.runActions="Çalıştır" AdvSceneSwitcher.action.macro.type.run="Çalıştır"
AdvSceneSwitcher.action.pluginState="Eklenti durumu" AdvSceneSwitcher.action.pluginState="Eklenti durumu"
AdvSceneSwitcher.action.pluginState.type.stop="Advanced Scene Switcher eklentisini durdurun" AdvSceneSwitcher.action.pluginState.type.stop="Advanced Scene Switcher eklentisini durdurun"
AdvSceneSwitcher.action.pluginState.type.noMatch="Eşleşmeme davranışını değiştirin:" AdvSceneSwitcher.action.pluginState.type.noMatch="Eşleşmeme davranışını değiştirin:"
AdvSceneSwitcher.action.pluginState.type.import="Ayarları şuradan içe aktar:" AdvSceneSwitcher.action.pluginState.type.import="Ayarları şuradan içe aktar:"
AdvSceneSwitcher.action.pluginState.importWarning="Not: Ayarlar penceresi açılırken eylem göz ardı edilecektir." AdvSceneSwitcher.action.pluginState.importWarning="Not: Ayarlar penceresi açılırken eylem göz ardı edilecektir."
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}" AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
AdvSceneSwitcher.action.virtualCamera="Sanal Kamera" AdvSceneSwitcher.action.virtualCamera="Sanal Kamera"
AdvSceneSwitcher.action.virtualCamera.type.stop="Sanal Kamerayı Durdur" AdvSceneSwitcher.action.virtualCamera.type.stop="Sanal Kamerayı Durdur"
AdvSceneSwitcher.action.virtualCamera.type.start="Sanal Kamerayı Başlat" AdvSceneSwitcher.action.virtualCamera.type.start="Sanal Kamerayı Başlat"
@@ -336,8 +343,8 @@ AdvSceneSwitcher.action.file.type.write="Yaz"
AdvSceneSwitcher.action.file.type.append="Ekle" AdvSceneSwitcher.action.file.type.append="Ekle"
AdvSceneSwitcher.action.file.entry="{{actions}} {{filePath}}:" AdvSceneSwitcher.action.file.entry="{{actions}} {{filePath}}:"
AdvSceneSwitcher.action.transition="Geçiş" AdvSceneSwitcher.action.transition="Geçiş"
AdvSceneSwitcher.action.transition.layout.transition="{{setTransition}}Geçiş türünü ayarla {{transitions}}" AdvSceneSwitcher.action.transition.entry.line2="{{setTransition}}Geçiş türünü ayarla {{transitions}}"
AdvSceneSwitcher.action.transition.layout.duration="{{setDuration}}Geçiş süresini şuna ayarla: {{duration}}saniyeler" AdvSceneSwitcher.action.transition.entry.line3="{{setDuration}}Geçiş süresini şuna ayarla: {{duration}}saniyeler"
AdvSceneSwitcher.action.timer="Zamanlayıcı" AdvSceneSwitcher.action.timer="Zamanlayıcı"
AdvSceneSwitcher.action.timer.type.pause="Duraklat" AdvSceneSwitcher.action.timer.type.pause="Duraklat"
AdvSceneSwitcher.action.timer.type.continue="Devam et" AdvSceneSwitcher.action.timer.type.continue="Devam et"
@@ -581,6 +588,8 @@ AdvSceneSwitcher.status.inactive="İnaktif"
AdvSceneSwitcher.running="Eklenti çalışıyor" AdvSceneSwitcher.running="Eklenti çalışıyor"
AdvSceneSwitcher.stopped="Eklenti durdu" AdvSceneSwitcher.stopped="Eklenti durdu"
AdvSceneSwitcher.firstBootMessage="<html><head/><body><p>Gelişmiş Sahne Değiştirici ilk kez başlatılıyor gibi görünüyor.<br>Lütfen <a href=\"https://github.com/ adresine bir göz atın. WarmUpTill/SceneSwitcher/wiki\"><span style=\" text-decoration: underline; color:#268bd2;\">Wiki</span></a> için kılavuzlar ve örnekler listesi.<br>Yapmayın. eklentinin <a href=\"https://obsproject.com/forum/threads/advanced-scene-switcher.48264\"><span style=\" text-decoration: underline; color:# sayfasında soru sormaktan çekinmeyin OBS forumlarında 268bd2;\">konu</span></a>!</p></body></html>"
AdvSceneSwitcher.unit.milliseconds="millisaniye" AdvSceneSwitcher.unit.milliseconds="millisaniye"
AdvSceneSwitcher.unit.seconds="saniye" AdvSceneSwitcher.unit.seconds="saniye"
AdvSceneSwitcher.unit.minutes="dakika" AdvSceneSwitcher.unit.minutes="dakika"

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg fill="#fefefe" xmlns="http://www.w3.org/2000/svg"
width="800px" height="800px" viewBox="0 0 52 52" enable-background="new 0 0 52 52" xml:space="preserve">
<path d="M42.6,17.8c2.4,0,7.2-2,7.2-8.4c0-6.4-4.6-6.8-6.1-6.8c-2.8,0-5.6,2-8.1,6.3c-2.5,4.4-5.3,9.1-5.3,9.1
l-0.1,0c-0.6-3.1-1.1-5.6-1.3-6.7c-0.5-2.7-3.6-8.4-9.9-8.4c-6.4,0-12.2,3.7-12.2,3.7l0,0C5.8,7.3,5.1,8.5,5.1,9.9
c0,2.1,1.7,3.9,3.9,3.9c0.6,0,1.2-0.2,1.7-0.4l0,0c0,0,4.8-2.7,5.9,0c0.3,0.8,0.6,1.7,0.9,2.7c1.2,4.2,2.4,9.1,3.3,13.5l-4.2,6
c0,0-4.7-1.7-7.1-1.7s-7.2,2-7.2,8.4s4.6,6.8,6.1,6.8c2.8,0,5.6-2,8.1-6.3c2.5-4.4,5.3-9.1,5.3-9.1c0.8,4,1.5,7.1,1.9,8.5
c1.6,4.5,5.3,7.2,10.1,7.2c0,0,5,0,10.9-3.3c1.4-0.6,2.4-2,2.4-3.6c0-2.1-1.7-3.9-3.9-3.9c-0.6,0-1.2,0.2-1.7,0.4l0,0
c0,0-4.2,2.4-5.6,0.5c-1-2-1.9-4.6-2.6-7.8c-0.6-2.8-1.3-6.2-2-9.5l4.3-6.2C35.5,16.1,40.2,17.8,42.6,17.8z"/>
</svg>

Before

Width:  |  Height:  |  Size: 973 B

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg fill="#202020" xmlns="http://www.w3.org/2000/svg"
width="800px" height="800px" viewBox="0 0 52 52" enable-background="new 0 0 52 52" xml:space="preserve">
<path d="M42.6,17.8c2.4,0,7.2-2,7.2-8.4c0-6.4-4.6-6.8-6.1-6.8c-2.8,0-5.6,2-8.1,6.3c-2.5,4.4-5.3,9.1-5.3,9.1
l-0.1,0c-0.6-3.1-1.1-5.6-1.3-6.7c-0.5-2.7-3.6-8.4-9.9-8.4c-6.4,0-12.2,3.7-12.2,3.7l0,0C5.8,7.3,5.1,8.5,5.1,9.9
c0,2.1,1.7,3.9,3.9,3.9c0.6,0,1.2-0.2,1.7-0.4l0,0c0,0,4.8-2.7,5.9,0c0.3,0.8,0.6,1.7,0.9,2.7c1.2,4.2,2.4,9.1,3.3,13.5l-4.2,6
c0,0-4.7-1.7-7.1-1.7s-7.2,2-7.2,8.4s4.6,6.8,6.1,6.8c2.8,0,5.6-2,8.1-6.3c2.5-4.4,5.3-9.1,5.3-9.1c0.8,4,1.5,7.1,1.9,8.5
c1.6,4.5,5.3,7.2,10.1,7.2c0,0,5,0,10.9-3.3c1.4-0.6,2.4-2,2.4-3.6c0-2.1-1.7-3.9-3.9-3.9c-0.6,0-1.2,0.2-1.7,0.4l0,0
c0,0-4.2,2.4-5.6,0.5c-1-2-1.9-4.6-2.6-7.8c-0.6-2.8-1.3-6.2-2-9.5l4.3-6.2C35.5,16.1,40.2,17.8,42.6,17.8z"/>
</svg>

Before

Width:  |  Height:  |  Size: 973 B

Binary file not shown.

1
deps/date vendored Submodule

Submodule deps/date added at 5bdb7e6f31

2
deps/json vendored

Submodule deps/json updated: 55f93686c0...bc889afb4c

2
deps/leptonica vendored

2
deps/libusb vendored

View File

@@ -22,7 +22,7 @@ with this program. If not, see <https://www.gnu.org/licenses/>
#include <obs.h> #include <obs.h>
#define OBS_WEBSOCKET_API_VERSION 2 #define OBS_WEBSOCKET_API_VERSION 3
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -31,6 +31,8 @@ extern "C" {
typedef void *obs_websocket_vendor; typedef void *obs_websocket_vendor;
typedef void (*obs_websocket_request_callback_function)(obs_data_t *, typedef void (*obs_websocket_request_callback_function)(obs_data_t *,
obs_data_t *, void *); obs_data_t *, void *);
typedef void (*obs_websocket_event_callback_function)(uint64_t, const char *,
const char *, void *);
struct obs_websocket_request_response { struct obs_websocket_request_response {
unsigned int status_code; unsigned int status_code;
@@ -45,6 +47,11 @@ struct obs_websocket_request_callback {
void *priv_data; void *priv_data;
}; };
struct obs_websocket_event_callback {
obs_websocket_event_callback_function callback;
void *priv_data;
};
static proc_handler_t *_ph; static proc_handler_t *_ph;
/* ==================== INTERNAL API FUNCTIONS ==================== */ /* ==================== INTERNAL API FUNCTIONS ==================== */
@@ -123,7 +130,6 @@ obs_websocket_call_request(const char *request_type, obs_data_t *request_data
request_data_string = obs_data_get_json(request_data); request_data_string = obs_data_get_json(request_data);
calldata_t cd = {0, 0, 0, 0}; calldata_t cd = {0, 0, 0, 0};
calldata_set_string(&cd, "request_type", request_type); calldata_set_string(&cd, "request_type", request_type);
calldata_set_string(&cd, "request_data", request_data_string); calldata_set_string(&cd, "request_data", request_data_string);
@@ -152,6 +158,48 @@ static inline void obs_websocket_request_response_free(
bfree(response); bfree(response);
} }
// Register an event handler to receive obs-websocket events
static inline bool obs_websocket_register_event_callback(
obs_websocket_event_callback_function event_callback, void *priv_data)
{
if (!obs_websocket_ensure_ph())
return false;
struct obs_websocket_event_callback cb = {event_callback, priv_data};
calldata_t cd = {0, 0, 0, 0};
calldata_set_ptr(&cd, "callback", &cb);
proc_handler_call(_ph, "register_event_callback", &cd);
bool ret = calldata_bool(&cd, "success");
calldata_free(&cd);
return ret;
}
// Unregister an existing event handler
static inline bool obs_websocket_unregister_event_callback(
obs_websocket_event_callback_function event_callback, void *priv_data)
{
if (!obs_websocket_ensure_ph())
return false;
struct obs_websocket_event_callback cb = {event_callback, priv_data};
calldata_t cd = {0, 0, 0, 0};
calldata_set_ptr(&cd, "callback", &cb);
proc_handler_call(_ph, "unregister_event_callback", &cd);
bool ret = calldata_bool(&cd, "success");
calldata_free(&cd);
return ret;
}
/* ==================== VENDOR API FUNCTIONS ==================== */ /* ==================== VENDOR API FUNCTIONS ==================== */
// ALWAYS CALL ONLY VIA `obs_module_post_load()` CALLBACK! // ALWAYS CALL ONLY VIA `obs_module_post_load()` CALLBACK!
@@ -163,7 +211,6 @@ obs_websocket_register_vendor(const char *vendor_name)
return NULL; return NULL;
calldata_t cd = {0, 0, 0, 0}; calldata_t cd = {0, 0, 0, 0};
calldata_set_string(&cd, "name", vendor_name); calldata_set_string(&cd, "name", vendor_name);
proc_handler_call(_ph, "vendor_register", &cd); proc_handler_call(_ph, "vendor_register", &cd);
@@ -179,11 +226,10 @@ static inline bool obs_websocket_vendor_register_request(
obs_websocket_request_callback_function request_callback, obs_websocket_request_callback_function request_callback,
void *priv_data) void *priv_data)
{ {
calldata_t cd = {0, 0, 0, 0};
struct obs_websocket_request_callback cb = {request_callback, struct obs_websocket_request_callback cb = {request_callback,
priv_data}; priv_data};
calldata_t cd = {0, 0, 0, 0};
calldata_set_string(&cd, "type", request_type); calldata_set_string(&cd, "type", request_type);
calldata_set_ptr(&cd, "callback", &cb); calldata_set_ptr(&cd, "callback", &cb);
@@ -200,7 +246,6 @@ obs_websocket_vendor_unregister_request(obs_websocket_vendor vendor,
const char *request_type) const char *request_type)
{ {
calldata_t cd = {0, 0, 0, 0}; calldata_t cd = {0, 0, 0, 0};
calldata_set_string(&cd, "type", request_type); calldata_set_string(&cd, "type", request_type);
bool success = obs_websocket_vendor_run_simple_proc( bool success = obs_websocket_vendor_run_simple_proc(
@@ -217,7 +262,6 @@ static inline bool obs_websocket_vendor_emit_event(obs_websocket_vendor vendor,
obs_data_t *event_data) obs_data_t *event_data)
{ {
calldata_t cd = {0, 0, 0, 0}; calldata_t cd = {0, 0, 0, 0};
calldata_set_string(&cd, "type", event_name); calldata_set_string(&cd, "type", event_name);
calldata_set_ptr(&cd, "data", (void *)event_data); calldata_set_ptr(&cd, "data", (void *)event_data);

2
deps/opencv vendored

1
deps/opencv_contrib vendored

Submodule deps/opencv_contrib deleted from 755e50675d

1
deps/whisper.cpp vendored

Submodule deps/whisper.cpp deleted from 306c88f4d1

File diff suppressed because it is too large Load Diff

View File

@@ -1,388 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MacroEdit</class>
<widget class="QWidget" name="MacroEdit">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QSplitter" name="macroActionConditionSplitter">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QWidget" name="macroConditions" native="true">
<layout class="QVBoxLayout" name="macroConditionsLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="advss::MacroSegmentList" name="conditionsList">
<property name="minimumSize">
<size>
<width>0</width>
<height>1</height>
</size>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="conditionControlsLayout">
<property name="leftMargin">
<number>9</number>
</property>
<item>
<widget class="QToolButton" name="conditionAdd">
<property name="toolTip">
<string>AdvSceneSwitcher.macroTab.tooltip.conditionAddButton</string>
</property>
<property name="themeID" stdset="0">
<string notr="true">addIconSmall</string>
</property>
<property name="class" stdset="0">
<string notr="true">icon-plus</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="conditionRemove">
<property name="toolTip">
<string>AdvSceneSwitcher.macroTab.tooltip.conditionRemoveButton</string>
</property>
<property name="themeID" stdset="0">
<string notr="true">removeIconSmall</string>
</property>
<property name="class" stdset="0">
<string notr="true">icon-trash</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="conditionTop">
<property name="toolTip">
<string>AdvSceneSwitcher.macroTab.tooltip.conditionTopButton</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="conditionUp">
<property name="toolTip">
<string>AdvSceneSwitcher.macroTab.tooltip.conditionUpButton</string>
</property>
<property name="text">
<string/>
</property>
<property name="themeID" stdset="0">
<string notr="true">upArrowIconSmall</string>
</property>
<property name="class" stdset="0">
<string notr="true">icon-up</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="conditionDown">
<property name="toolTip">
<string>AdvSceneSwitcher.macroTab.tooltip.conditionDownButton</string>
</property>
<property name="themeID" stdset="0">
<string notr="true">downArrowIconSmall</string>
</property>
<property name="class" stdset="0">
<string notr="true">icon-down</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="conditionBottom">
<property name="toolTip">
<string>AdvSceneSwitcher.macroTab.tooltip.conditionBottomButton</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QSplitter" name="macroElseActionSplitter">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QWidget" name="macroActions" native="true">
<layout class="QVBoxLayout" name="macroActionsLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="advss::MacroSegmentList" name="actionsList">
<property name="minimumSize">
<size>
<width>0</width>
<height>1</height>
</size>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="actionControlsLayout">
<property name="leftMargin">
<number>9</number>
</property>
<item>
<widget class="QToolButton" name="actionAdd">
<property name="toolTip">
<string>AdvSceneSwitcher.macroTab.tooltip.actionAddButton</string>
</property>
<property name="themeID" stdset="0">
<string notr="true">addIconSmall</string>
</property>
<property name="class" stdset="0">
<string notr="true">icon-plus</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="actionRemove">
<property name="toolTip">
<string>AdvSceneSwitcher.macroTab.tooltip.actionRemoveButton</string>
</property>
<property name="themeID" stdset="0">
<string notr="true">removeIconSmall</string>
</property>
<property name="class" stdset="0">
<string notr="true">icon-trash</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="actionTop">
<property name="toolTip">
<string>AdvSceneSwitcher.macroTab.tooltip.actionTopButton</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="actionUp">
<property name="toolTip">
<string>AdvSceneSwitcher.macroTab.tooltip.actionUpButton</string>
</property>
<property name="themeID" stdset="0">
<string notr="true">upArrowIconSmall</string>
</property>
<property name="class" stdset="0">
<string notr="true">icon-up</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="actionDown">
<property name="toolTip">
<string>AdvSceneSwitcher.macroTab.tooltip.actionDownButton</string>
</property>
<property name="themeID" stdset="0">
<string notr="true">downArrowIconSmall</string>
</property>
<property name="class" stdset="0">
<string notr="true">icon-down</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="actionBottom">
<property name="toolTip">
<string>AdvSceneSwitcher.macroTab.tooltip.actionBottomButton</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_14">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="toggleElseActions">
<property name="toolTip">
<string>AdvSceneSwitcher.macroTab.tooltip.toggleShowElseSection</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="macroElseActions" native="true">
<layout class="QVBoxLayout" name="macroElseActionsLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="advss::MacroSegmentList" name="elseActionsList">
<property name="minimumSize">
<size>
<width>0</width>
<height>1</height>
</size>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="elseActionControlsLayout">
<property name="leftMargin">
<number>9</number>
</property>
<item>
<widget class="QToolButton" name="elseActionAdd">
<property name="toolTip">
<string>AdvSceneSwitcher.macroTab.tooltip.elseActionAddButton</string>
</property>
<property name="themeID" stdset="0">
<string notr="true">addIconSmall</string>
</property>
<property name="class" stdset="0">
<string notr="true">icon-plus</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="elseActionRemove">
<property name="toolTip">
<string>AdvSceneSwitcher.macroTab.tooltip.elseActionRemoveButton</string>
</property>
<property name="themeID" stdset="0">
<string notr="true">removeIconSmall</string>
</property>
<property name="class" stdset="0">
<string notr="true">icon-trash</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="elseActionTop">
<property name="toolTip">
<string>AdvSceneSwitcher.macroTab.tooltip.elseActionTopButton</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="elseActionUp">
<property name="toolTip">
<string>AdvSceneSwitcher.macroTab.tooltip.elseActionUpButton</string>
</property>
<property name="themeID" stdset="0">
<string notr="true">upArrowIconSmall</string>
</property>
<property name="class" stdset="0">
<string notr="true">icon-up</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="elseActionDown">
<property name="toolTip">
<string>AdvSceneSwitcher.macroTab.tooltip.elseActionDownButton</string>
</property>
<property name="themeID" stdset="0">
<string notr="true">downArrowIconSmall</string>
</property>
<property name="class" stdset="0">
<string notr="true">icon-down</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="elseActionBottom">
<property name="toolTip">
<string>AdvSceneSwitcher.macroTab.tooltip.elseActionBottomButton</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>advss::MacroSegmentList</class>
<extends>QScrollArea</extends>
<header>macro-segment-list.hpp</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>conditionsList</tabstop>
<tabstop>conditionAdd</tabstop>
<tabstop>conditionRemove</tabstop>
<tabstop>conditionTop</tabstop>
<tabstop>conditionUp</tabstop>
<tabstop>conditionDown</tabstop>
<tabstop>conditionBottom</tabstop>
<tabstop>actionsList</tabstop>
<tabstop>actionAdd</tabstop>
<tabstop>actionRemove</tabstop>
<tabstop>actionTop</tabstop>
<tabstop>actionUp</tabstop>
<tabstop>actionDown</tabstop>
<tabstop>actionBottom</tabstop>
<tabstop>toggleElseActions</tabstop>
<tabstop>elseActionsList</tabstop>
<tabstop>elseActionAdd</tabstop>
<tabstop>elseActionRemove</tabstop>
<tabstop>elseActionTop</tabstop>
<tabstop>elseActionUp</tabstop>
<tabstop>elseActionDown</tabstop>
<tabstop>elseActionBottom</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@@ -1,6 +1,5 @@
#include "advanced-scene-switcher.hpp" #include "advanced-scene-switcher.hpp"
#include "backup.hpp" #include "backup.hpp"
#include "crash-handler.hpp"
#include "log-helper.hpp" #include "log-helper.hpp"
#include "macro-helpers.hpp" #include "macro-helpers.hpp"
#include "obs-module-helper.hpp" #include "obs-module-helper.hpp"
@@ -19,10 +18,8 @@
#include <obs-frontend-api.h> #include <obs-frontend-api.h>
#include <QAction> #include <QAction>
#include <QDirIterator> #include <QDirIterator>
#include <QInputDialog>
#include <QLibrary> #include <QLibrary>
#include <QMainWindow> #include <QMainWindow>
#include <QMessageBox>
#include <QTextStream> #include <QTextStream>
#include <regex> #include <regex>
@@ -43,12 +40,9 @@ AdvSceneSwitcher::AdvSceneSwitcher(QWidget *parent)
{ {
switcher->settingsWindowOpened = true; switcher->settingsWindowOpened = true;
ui->setupUi(this); ui->setupUi(this);
{ std::lock_guard<std::mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(switcher->m); switcher->Prune();
switcher->Prune(); LoadUI();
LoadUI();
}
CheckFirstTimeSetup();
} }
AdvSceneSwitcher::~AdvSceneSwitcher() AdvSceneSwitcher::~AdvSceneSwitcher()
@@ -144,6 +138,7 @@ void AdvSceneSwitcher::LoadUI()
SetTabOrder(ui->tabWidget); SetTabOrder(ui->tabWidget);
SetCurrentTab(ui->tabWidget); SetCurrentTab(ui->tabWidget);
RestoreWindowGeo(); RestoreWindowGeo();
CheckFirstTimeSetup();
loading = false; loading = false;
} }
@@ -151,7 +146,16 @@ void AdvSceneSwitcher::LoadUI()
bool AdvSceneSwitcher::eventFilter(QObject *obj, QEvent *event) bool AdvSceneSwitcher::eventFilter(QObject *obj, QEvent *event)
{ {
auto eventType = event->type(); auto eventType = event->type();
if (eventType == QEvent::KeyPress) { if (obj == ui->macroElseActions && eventType == QEvent::Resize) {
QResizeEvent *resizeEvent = static_cast<QResizeEvent *>(event);
if (resizeEvent->size().height() == 0) {
SetElseActionsStateToHidden();
return QDialog::eventFilter(obj, event);
}
SetElseActionsStateToVisible();
} else if (eventType == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event); QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
auto pressedKey = keyEvent->key(); auto pressedKey = keyEvent->key();
@@ -196,21 +200,25 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
switcher->m.lock(); switcher->m.lock();
if (switcher->VersionChanged(data, g_GIT_SHA1)) { if (switcher->VersionChanged(data, g_GIT_SHA1)) {
AskForBackup(data); auto json = obs_data_get_json(data);
static QString jsonQString = json ? json : "";
std::thread t([]() {
obs_queue_task(
OBS_TASK_UI,
[](void *) {
AskForBackup(jsonQString);
},
nullptr, false);
});
t.detach();
} }
switcher->LoadSettings(data); switcher->LoadSettings(data);
switcher->m.unlock(); switcher->m.unlock();
if (switcher->stop) { if (!switcher->stop) {
return; switcher->Start();
} }
if (ShouldSkipPluginStartOnUncleanShutdown()) {
return;
}
switcher->Start();
} }
} }
@@ -326,7 +334,8 @@ void SwitcherData::SetPreconditions()
{ {
// Window title // Window title
lastTitle = currentTitle; lastTitle = currentTitle;
auto title = GetCurrentWindowTitle(); std::string title;
GetCurrentWindowTitle(title);
for (auto &window : ignoreWindowsSwitches) { for (auto &window : ignoreWindowsSwitches) {
bool equals = (title == window); bool equals = (title == window);
bool matches = false; bool matches = false;
@@ -346,7 +355,7 @@ void SwitcherData::SetPreconditions()
currentTitle = title; currentTitle = title;
// Process name // Process name
currentForegroundProcess = GetForegroundProcessName(); GetForegroundProcessName(currentForegroundProcess);
// Macro // Macro
InvalidateMacroTempVarValues(); InvalidateMacroTempVarValues();
@@ -421,7 +430,7 @@ bool SwitcherData::CheckForMatch(OBSWeakSource &scene,
static void ResetMacros() static void ResetMacros()
{ {
for (auto &m : GetTopLevelMacros()) { for (auto &m : GetMacros()) {
ResetMacroRunCount(m.get()); ResetMacroRunCount(m.get());
ResetMacroConditionTimers(m.get()); ResetMacroConditionTimers(m.get());
} }
@@ -461,13 +470,12 @@ void SwitcherData::Stop()
SetMacroAbortWait(true); SetMacroAbortWait(true);
GetMacroWaitCV().notify_all(); GetMacroWaitCV().notify_all();
GetMacroTransitionCV().notify_all(); GetMacroTransitionCV().notify_all();
SignalStopAllMacros(); StopAllMacros();
StopAndClearAllActionQueues(); StopAndClearAllActionQueues();
CloseAllInputDialogs(); CloseAllInputDialogs();
th->wait(); th->wait();
delete th; delete th;
th = nullptr; th = nullptr;
WaitForAllMacros();
RunStopSteps(); RunStopSteps();
} }
@@ -511,8 +519,6 @@ bool SwitcherData::AnySceneTransitionStarted()
******************************************************************************/ ******************************************************************************/
extern "C" EXPORT void FreeSceneSwitcher() extern "C" EXPORT void FreeSceneSwitcher()
{ {
switcher->Stop();
PlatformCleanup(); PlatformCleanup();
RunPluginCleanupSteps(); RunPluginCleanupSteps();
@@ -541,7 +547,6 @@ static void handleSceneChange()
} }
switcher->checkDefaultSceneTransitions(); switcher->checkDefaultSceneTransitions();
switcher->CheckAutoStart();
} }
static void setLiveTime() static void setLiveTime()
@@ -556,28 +561,18 @@ static void resetLiveTime()
static void checkAutoStartRecording() static void checkAutoStartRecording()
{ {
if (switcher->obsIsShuttingDown) {
return;
}
if (switcher->autoStartEvent == SwitcherData::AutoStart::RECORDING || if (switcher->autoStartEvent == SwitcherData::AutoStart::RECORDING ||
switcher->autoStartEvent == switcher->autoStartEvent ==
SwitcherData::AutoStart::RECORINDG_OR_STREAMING) { SwitcherData::AutoStart::RECORINDG_OR_STREAMING)
switcher->Start(); switcher->Start();
}
} }
static void checkAutoStartStreaming() static void checkAutoStartStreaming()
{ {
if (switcher->obsIsShuttingDown) {
return;
}
if (switcher->autoStartEvent == SwitcherData::AutoStart::STREAMING || if (switcher->autoStartEvent == SwitcherData::AutoStart::STREAMING ||
switcher->autoStartEvent == switcher->autoStartEvent ==
SwitcherData::AutoStart::RECORINDG_OR_STREAMING) { SwitcherData::AutoStart::RECORINDG_OR_STREAMING)
switcher->Start(); switcher->Start();
}
} }
static void handleTransitionEnd() static void handleTransitionEnd()
@@ -613,7 +608,7 @@ static void handleSceneCollectionChanging()
AdvSceneSwitcher::window->close(); AdvSceneSwitcher::window->close();
} }
if (!switcher->stop) { if (!switcher->stop) {
switcher->sceneCollectionStop = true; switcher->sceneColletionStop = true;
switcher->Stop(); switcher->Stop();
} }
} }
@@ -634,20 +629,13 @@ static void handleSceneCollectionCleanup()
return; return;
} }
// OBS_FRONTEND_EVENT_SCENE_COLLECTION_CLEANUP is also called on
// shutdown.
// Here we also don't want to clear the settings.
if (switcher->obsIsShuttingDown) {
return;
}
SaveSceneSwitcher(nullptr, false, nullptr); SaveSceneSwitcher(nullptr, false, nullptr);
} }
// Note to future self: // Note to future self:
// be careful using switcher->m here as there is potential for deadlocks when using // be careful using switcher->m here as there is potential for deadlocks when using
// frontend functions such as obs_frontend_set_current_scene() // frontend functions such as obs_frontend_set_current_scene()
static void OBSEvent(enum obs_frontend_event event, void *) static void OBSEvent(enum obs_frontend_event event, void *switcher)
{ {
if (!switcher) { if (!switcher) {
return; return;
@@ -721,54 +709,19 @@ static void LoadPlugins()
} }
} }
static bool settingsPasswordIsCorrect(QWidget *parent)
{
bool ok;
QString input = QInputDialog::getText(
parent,
obs_module_text(
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.title"),
obs_module_text(
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.passwordLabel"),
QLineEdit::Password, QString(), &ok);
if (!ok) {
return false;
}
if (input.toStdString() == switcher->settingsLockPassword) {
return true;
}
QMessageBox::warning(
parent,
obs_module_text(
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.title"),
obs_module_text(
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.wrongPassword"));
return false;
}
void OpenSettingsWindow() void OpenSettingsWindow()
{ {
if (switcher->settingsWindowOpened) { if (switcher->settingsWindowOpened) {
AdvSceneSwitcher::window->show(); AdvSceneSwitcher::window->show();
AdvSceneSwitcher::window->raise(); AdvSceneSwitcher::window->raise();
AdvSceneSwitcher::window->activateWindow(); AdvSceneSwitcher::window->activateWindow();
return; } else {
AdvSceneSwitcher::window =
new AdvSceneSwitcher(static_cast<QMainWindow *>(
obs_frontend_get_main_window()));
AdvSceneSwitcher::window->setAttribute(Qt::WA_DeleteOnClose);
AdvSceneSwitcher::window->show();
} }
auto parent =
static_cast<QMainWindow *>(obs_frontend_get_main_window());
if (switcher->settingsLockEnabled &&
!switcher->settingsLockPassword.empty() &&
!settingsPasswordIsCorrect(parent)) {
return;
}
AdvSceneSwitcher::window = new AdvSceneSwitcher(parent);
AdvSceneSwitcher::window->setAttribute(Qt::WA_DeleteOnClose);
AdvSceneSwitcher::window->show();
} }
void AdvSceneSwitcher::HighlightMacroSettingsButton(bool enable) void AdvSceneSwitcher::HighlightMacroSettingsButton(bool enable)
@@ -791,21 +744,6 @@ void AdvSceneSwitcher::HighlightMacroSettingsButton(bool enable)
highlight = HighlightWidget(ui->macroSettings, Qt::green); highlight = HighlightWidget(ui->macroSettings, Qt::green);
} }
void AdvSceneSwitcher::HighlightAction(int idx, QColor color) const
{
ui->macroEdit->HighlightAction(idx, color);
}
void AdvSceneSwitcher::HighlightElseAction(int idx, QColor color) const
{
ui->macroEdit->HighlightElseAction(idx, color);
}
void AdvSceneSwitcher::HighlightCondition(int idx, QColor color) const
{
ui->macroEdit->HighlightCondition(idx, color);
}
void HighlightMacroSettingsButton(bool enable) void HighlightMacroSettingsButton(bool enable)
{ {
auto window = GetSettingsWindow(); auto window = GetSettingsWindow();
@@ -816,6 +754,8 @@ void HighlightMacroSettingsButton(bool enable)
enable); enable);
} }
void SetupActionQueues();
extern "C" EXPORT void InitSceneSwitcher(obs_module_t *module, extern "C" EXPORT void InitSceneSwitcher(obs_module_t *module,
translateFunc translate) translateFunc translate)
{ {
@@ -827,11 +767,12 @@ extern "C" EXPORT void InitSceneSwitcher(obs_module_t *module,
PlatformInit(); PlatformInit();
LoadPlugins(); LoadPlugins();
SetupDock(); SetupDock();
SetupActionQueues();
RunPluginInitSteps(); RunPluginInitSteps();
obs_frontend_add_save_callback(SaveSceneSwitcher, nullptr); obs_frontend_add_save_callback(SaveSceneSwitcher, nullptr);
obs_frontend_add_event_callback(OBSEvent, nullptr); obs_frontend_add_event_callback(OBSEvent, switcher);
QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction( QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction(
obs_module_text("AdvSceneSwitcher.pluginName")); obs_module_text("AdvSceneSwitcher.pluginName"));

View File

@@ -1,4 +1,7 @@
#pragma once #pragma once
#include "macro-segment-list.hpp"
#include "condition-logic.hpp"
#include "log-helper.hpp"
#include <ui_advanced-scene-switcher.h> #include <ui_advanced-scene-switcher.h>
@@ -42,6 +45,7 @@ protected:
/* --- Begin of general tab section --- */ /* --- Begin of general tab section --- */
public: public:
void SetupGeneralTab(); void SetupGeneralTab();
void UpdateNonMatchingScene(const QString &name);
void SetDeprecationWarnings(); void SetDeprecationWarnings();
public slots: public slots:
@@ -54,6 +58,7 @@ public slots:
void on_startupBehavior_currentIndexChanged(int index); void on_startupBehavior_currentIndexChanged(int index);
void on_logLevel_currentIndexChanged(int index); void on_logLevel_currentIndexChanged(int index);
void on_autoStartEvent_currentIndexChanged(int index); void on_autoStartEvent_currentIndexChanged(int index);
void on_noMatchSwitchScene_currentTextChanged(const QString &text);
void on_checkInterval_valueChanged(int value); void on_checkInterval_valueChanged(int value);
void on_tabWidget_currentChanged(int index); void on_tabWidget_currentChanged(int index);
void on_exportSettings_clicked(); void on_exportSettings_clicked();
@@ -62,21 +67,18 @@ public slots:
void on_showTrayNotifications_stateChanged(int state); void on_showTrayNotifications_stateChanged(int state);
void on_uiHintsDisable_stateChanged(int state); void on_uiHintsDisable_stateChanged(int state);
void on_disableComboBoxFilter_stateChanged(int state); void on_disableComboBoxFilter_stateChanged(int state);
void on_disableMacroWidgetCache_stateChanged(int state);
void on_warnPluginLoadFailure_stateChanged(int state); void on_warnPluginLoadFailure_stateChanged(int state);
void on_suppressCrashRecoveryDialog_stateChanged(int state);
void on_hideLegacyTabs_stateChanged(int state); void on_hideLegacyTabs_stateChanged(int state);
void on_settingsLock_stateChanged(int state);
void on_priorityUp_clicked(); void on_priorityUp_clicked();
void on_priorityDown_clicked(); void on_priorityDown_clicked();
void on_threadPriority_currentTextChanged(const QString &text); void on_threadPriority_currentTextChanged(const QString &text);
void on_openSetupWizard_clicked();
/* --- End of legacy tab section --- */ /* --- End of legacy tab section --- */
/* --- Begin of macro tab section --- */ /* --- Begin of macro tab section --- */
public: public:
void SetupMacroTab(); void SetupMacroTab();
bool MacroTabIsInFocus();
bool AddNewMacro(std::shared_ptr<Macro> &res, std::string &name, bool AddNewMacro(std::shared_ptr<Macro> &res, std::string &name,
std::string format = ""); std::string format = "");
void RemoveMacro(std::shared_ptr<Macro> &); void RemoveMacro(std::shared_ptr<Macro> &);
@@ -84,6 +86,7 @@ public:
void RenameMacro(std::shared_ptr<Macro> &, const QString &name); void RenameMacro(std::shared_ptr<Macro> &, const QString &name);
std::shared_ptr<Macro> GetSelectedMacro() const; std::shared_ptr<Macro> GetSelectedMacro() const;
std::vector<std::shared_ptr<Macro>> GetSelectedMacros() const; std::vector<std::shared_ptr<Macro>> GetSelectedMacros() const;
void SetEditMacro(Macro &m);
void SetMacroEditAreaDisabled(bool) const; void SetMacroEditAreaDisabled(bool) const;
void HighlightAction(int idx, QColor color = QColor(Qt::green)) const; void HighlightAction(int idx, QColor color = QColor(Qt::green)) const;
void HighlightElseAction(int idx, void HighlightElseAction(int idx,
@@ -107,20 +110,107 @@ public slots:
void on_macroDown_clicked() const; void on_macroDown_clicked() const;
void on_macroName_editingFinished(); void on_macroName_editingFinished();
void on_runMacroInParallel_stateChanged(int value) const; void on_runMacroInParallel_stateChanged(int value) const;
void on_actionTriggerMode_currentIndexChanged(int index) const; void on_runMacroOnChange_stateChanged(int value) const;
void on_conditionAdd_clicked();
void on_conditionRemove_clicked();
void on_conditionTop_clicked();
void on_conditionUp_clicked();
void on_conditionDown_clicked();
void on_conditionBottom_clicked();
void on_actionAdd_clicked();
void on_actionRemove_clicked();
void on_actionTop_clicked();
void on_actionUp_clicked();
void on_actionDown_clicked();
void on_actionBottom_clicked();
void on_toggleElseActions_clicked() const;
void on_elseActionAdd_clicked();
void on_elseActionRemove_clicked();
void on_elseActionTop_clicked();
void on_elseActionUp_clicked();
void on_elseActionDown_clicked();
void on_elseActionBottom_clicked();
void MacroSelectionAboutToChange() const;
void MacroSelectionChanged(); void MacroSelectionChanged();
void UpMacroSegementHotkey();
void DownMacroSegementHotkey();
void DeleteMacroSegementHotkey();
void ShowMacroContextMenu(const QPoint &); void ShowMacroContextMenu(const QPoint &);
void ShowMacroActionsContextMenu(const QPoint &);
void ShowMacroElseActionsContextMenu(const QPoint &);
void ShowMacroConditionsContextMenu(const QPoint &);
void CopyMacro(); void CopyMacro();
void RenameSelectedMacro(); void RenameSelectedMacro();
void ExportMacros() const; void ExportMacros() const;
void ImportMacros(); void ImportMacros();
void PauseSelectedMacros(); void ExpandAllActions() const;
void UnpauseSelectedMacros(); void ExpandAllElseActions() const;
void ExpandAllConditions() const;
void CollapseAllActions() const;
void CollapseAllElseActions() const;
void CollapseAllConditions() const;
void MinimizeActions() const;
void MaximizeActions() const;
void MinimizeElseActions() const;
void MaximizeElseActions() const;
void MinimizeConditions() const;
void MaximizeConditions() const;
void SetElseActionsStateToHidden() const;
void SetElseActionsStateToVisible() const;
void MacroActionSelectionChanged(int idx);
void MacroActionReorder(int to, int target);
void AddMacroAction(Macro *macro, int idx, const std::string &id,
obs_data_t *data);
void AddMacroAction(int idx);
void RemoveMacroAction(int idx);
void MoveMacroActionUp(int idx);
void MoveMacroActionDown(int idx);
void MacroElseActionSelectionChanged(int idx);
void MacroElseActionReorder(int to, int target);
void AddMacroElseAction(Macro *macro, int idx, const std::string &id,
obs_data_t *data);
void AddMacroElseAction(int idx);
void RemoveMacroElseAction(int idx);
void SwapElseActions(Macro *m, int pos1, int pos2);
void MoveMacroElseActionUp(int idx);
void MoveMacroElseActionDown(int idx);
void MacroConditionSelectionChanged(int idx);
void MacroConditionReorder(int to, int target);
void AddMacroCondition(int idx);
void AddMacroCondition(Macro *macro, int idx, const std::string &id,
obs_data_t *data, Logic::Type logic);
void RemoveMacroCondition(int idx);
void MoveMacroConditionUp(int idx);
void MoveMacroConditionDown(int idx);
void HighlightControls() const;
void HighlightOnChange() const; void HighlightOnChange() const;
void on_macroSettings_clicked(); void on_macroSettings_clicked();
void CopyMacroSegment();
void PasteMacroSegment();
signals:
void MacroAdded(const QString &name);
void MacroRemoved(const QString &name);
void MacroRenamed(const QString &oldName, const QString &newName);
void MacroSegmentOrderChanged();
void SegmentTempVarsChanged(MacroSegment *);
void HighlightMacrosChanged(bool value);
void ConnectionAdded(const QString &);
void ConnectionRenamed(const QString &oldName, const QString &newName);
void ConnectionRemoved(const QString &);
private: private:
enum class MacroSection { CONDITIONS, ACTIONS, ELSE_ACTIONS };
void SetupMacroSegmentSelection(MacroSection type, int idx);
bool ResolveMacroImportNameConflict(std::shared_ptr<Macro> &); bool ResolveMacroImportNameConflict(std::shared_ptr<Macro> &);
bool MacroTabIsInFocus();
MacroSection lastInteracted = MacroSection::CONDITIONS;
int currentConditionIdx = -1;
int currentActionIdx = -1;
int currentElseActionIdx = -1;
/* --- End of macro tab section --- */ /* --- End of macro tab section --- */

View File

@@ -1,28 +1,22 @@
#include "advanced-scene-switcher.hpp" #include "advanced-scene-switcher.hpp"
#include "crash-handler.hpp"
#include "file-selection.hpp" #include "file-selection.hpp"
#include "filter-combo-box.hpp" #include "filter-combo-box.hpp"
#include "first-run-wizard.hpp"
#include "layout-helpers.hpp" #include "layout-helpers.hpp"
#include "macro-helpers.hpp"
#include "macro-search.hpp"
#include "macro-settings.hpp"
#include "macro.hpp" #include "macro.hpp"
#include "path-helpers.hpp" #include "path-helpers.hpp"
#include "selection-helpers.hpp"
#include "source-helpers.hpp" #include "source-helpers.hpp"
#include "splitter-helpers.hpp" #include "splitter-helpers.hpp"
#include "status-control.hpp" #include "status-control.hpp"
#include "switcher-data.hpp" #include "switcher-data.hpp"
#include "tab-helpers.hpp" #include "tab-helpers.hpp"
#include "ui-helpers.hpp" #include "ui-helpers.hpp"
#include "utility.hpp"
#include "variable.hpp" #include "variable.hpp"
#include "version.h" #include "version.h"
#include <obs-frontend-api.h> #include <obs-frontend-api.h>
#include <QFileDialog> #include <QFileDialog>
#include <QInputDialog>
#include <QMessageBox>
namespace advss { namespace advss {
@@ -31,6 +25,15 @@ void AdvSceneSwitcher::reject()
close(); close();
} }
void AdvSceneSwitcher::UpdateNonMatchingScene(const QString &name)
{
OBSSourceAutoRelease scene =
obs_get_source_by_name(name.toUtf8().constData());
OBSWeakSourceAutoRelease ws = obs_source_get_weak_source(scene);
switcher->nonMatchingScene = ws;
}
void AdvSceneSwitcher::on_noMatchDontSwitch_clicked() void AdvSceneSwitcher::on_noMatchDontSwitch_clicked()
{ {
if (loading) { if (loading) {
@@ -52,6 +55,7 @@ void AdvSceneSwitcher::on_noMatchSwitch_clicked()
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->switchIfNotMatching = NoMatchBehavior::SWITCH; switcher->switchIfNotMatching = NoMatchBehavior::SWITCH;
ui->noMatchSwitchScene->setEnabled(true); ui->noMatchSwitchScene->setEnabled(true);
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
ui->randomDisabledWarning->setVisible(true); ui->randomDisabledWarning->setVisible(true);
} }
@@ -127,6 +131,17 @@ void AdvSceneSwitcher::on_autoStartEvent_currentIndexChanged(int index)
switcher->autoStartEvent = static_cast<SwitcherData::AutoStart>(index); switcher->autoStartEvent = static_cast<SwitcherData::AutoStart>(index);
} }
void AdvSceneSwitcher::on_noMatchSwitchScene_currentTextChanged(
const QString &text)
{
if (loading) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
UpdateNonMatchingScene(text);
}
void AdvSceneSwitcher::on_checkInterval_valueChanged(int value) void AdvSceneSwitcher::on_checkInterval_valueChanged(int value)
{ {
if (loading) { if (loading) {
@@ -148,7 +163,7 @@ void AdvSceneSwitcher::closeEvent(QCloseEvent *)
switcher->windowSize = this->size(); switcher->windowSize = this->size();
switcher->macroListMacroEditSplitterPosition = switcher->macroListMacroEditSplitterPosition =
ui->macroListMacroEditSplitter->sizes(); ui->macroListMacroEditSplitter->sizes();
ui->macroEdit->SetMacro(nullptr); // Trigger saving of splitter states MacroSelectionAboutToChange(); // Trigger saving of splitter states
obs_frontend_save(); obs_frontend_save();
} }
@@ -190,6 +205,16 @@ void AdvSceneSwitcher::on_disableComboBoxFilter_stateChanged(int state)
FilterComboBox::SetFilterBehaviourEnabled(!state); FilterComboBox::SetFilterBehaviourEnabled(!state);
} }
void AdvSceneSwitcher::on_disableMacroWidgetCache_stateChanged(int state)
{
if (loading) {
return;
}
switcher->disableMacroWidgetCache = state;
MacroSegmentList::SetCachingEnabled(!state);
}
void AdvSceneSwitcher::on_warnPluginLoadFailure_stateChanged(int state) void AdvSceneSwitcher::on_warnPluginLoadFailure_stateChanged(int state)
{ {
if (loading) { if (loading) {
@@ -199,15 +224,6 @@ void AdvSceneSwitcher::on_warnPluginLoadFailure_stateChanged(int state)
switcher->warnPluginLoadFailure = state; switcher->warnPluginLoadFailure = state;
} }
void AdvSceneSwitcher::on_suppressCrashRecoveryDialog_stateChanged(int state)
{
if (loading) {
return;
}
SetSuppressCrashDialog(state);
}
static bool isLegacyTab(const QString &name) static bool isLegacyTab(const QString &name)
{ {
return name == obs_module_text( return name == obs_module_text(
@@ -247,64 +263,6 @@ void AdvSceneSwitcher::on_hideLegacyTabs_stateChanged(int state)
ui->priorityBox->setVisible(!switcher->hideLegacyTabs); ui->priorityBox->setVisible(!switcher->hideLegacyTabs);
} }
void AdvSceneSwitcher::on_settingsLock_stateChanged(int state)
{
if (loading) {
return;
}
if (!state) {
switcher->settingsLockEnabled = false;
switcher->settingsLockPassword = "";
return;
}
bool ok;
QString newPassword = QInputDialog::getText(
this,
obs_module_text(
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.title"),
obs_module_text(
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.newPasswordLabel"),
QLineEdit::Password, QString(), &ok);
const auto disablePassword = [this]() {
QSignalBlocker blocker(ui->settingsLock);
ui->settingsLock->setChecked(false);
ui->settingsLock->setCheckState(Qt::Unchecked);
switcher->settingsLockEnabled = false;
switcher->settingsLockPassword = "";
};
if (!ok || newPassword.isEmpty()) {
disablePassword();
return;
}
QString confirm = QInputDialog::getText(
this,
obs_module_text(
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.title"),
obs_module_text(
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.confirmPasswordLabel"),
QLineEdit::Password, QString(), &ok);
if (!ok || newPassword != confirm) {
if (ok) {
QMessageBox::warning(
this,
obs_module_text(
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.title"),
obs_module_text(
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.passwordMismatch"));
}
disablePassword();
return;
}
switcher->settingsLockEnabled = true;
switcher->settingsLockPassword = newPassword.toStdString();
}
void AdvSceneSwitcher::SetDeprecationWarnings() void AdvSceneSwitcher::SetDeprecationWarnings()
{ {
QString toolTip = QString toolTip =
@@ -432,50 +390,14 @@ void AdvSceneSwitcher::RestoreWindowGeo()
} }
} }
static void renameMacroIfNecessary(const std::shared_ptr<Macro> &macro)
{
if (!GetMacroByName(macro->Name().c_str())) {
return;
}
auto name = macro->Name();
int i = 2;
while (GetMacroByName((name + " " + std::to_string(i)).c_str())) {
i++;
}
macro->SetName(name + " " + std::to_string(i));
}
void AdvSceneSwitcher::CheckFirstTimeSetup() void AdvSceneSwitcher::CheckFirstTimeSetup()
{ {
if (!IsFirstRun() || !GetTopLevelMacros().empty()) { if (switcher->firstBoot && !switcher->disableHints) {
return; switcher->firstBoot = false;
DisplayMessage(
obs_module_text("AdvSceneSwitcher.firstBootMessage"));
switcher->Start();
} }
bool wasSkipped = false;
auto macro = wiz::FirstRunWizard::ShowWizard(this, &wasSkipped);
if (macro) {
renameMacroIfNecessary(macro);
QTimer::singleShot(0, this,
[this, macro]() { ui->macros->Add(macro); });
}
if (wasSkipped) {
ui->alwaysShowFeatureTabs->setChecked(true);
}
switcher->Start();
}
void AdvSceneSwitcher::on_openSetupWizard_clicked()
{
auto macro = wiz::FirstRunWizard::ShowWizard(this);
if (!macro) {
return;
}
renameMacroIfNecessary(macro);
ui->macros->Add(macro);
ui->tabWidget->setCurrentWidget(ui->macroTab);
} }
void AdvSceneSwitcher::on_tabWidget_currentChanged(int) void AdvSceneSwitcher::on_tabWidget_currentChanged(int)
@@ -529,13 +451,16 @@ void SwitcherData::LoadSettings(obs_data_t *obj)
} }
// New post load steps to be declared during load // New post load steps to be declared during load
ClearPostLoadSteps(); postLoadSteps.clear();
// Needs to be loaded before any entries which might rely on scene group // Needs to be loaded before any entries which might rely on scene group
// selections to be available. // selections to be available.
loadSceneGroups(obj); loadSceneGroups(obj);
LoadVariables(obj);
RunLoadSteps(obj); for (const auto &func : loadSteps) {
func(obj);
}
LoadMacros(obj); LoadMacros(obj);
LoadGlobalMacroSettings(obj); LoadGlobalMacroSettings(obj);
@@ -556,7 +481,7 @@ void SwitcherData::LoadSettings(obs_data_t *obj)
LoadHotkeys(obj); LoadHotkeys(obj);
LoadUISettings(obj); LoadUISettings(obj);
RunAndClearPostLoadSteps(); RunPostLoadSteps();
// Reset on startup and scene collection change // Reset on startup and scene collection change
ResetLastOpenedTab(); ResetLastOpenedTab();
@@ -572,6 +497,7 @@ void SwitcherData::SaveSettings(obs_data_t *obj)
saveSceneGroups(obj); saveSceneGroups(obj);
SaveMacros(obj); SaveMacros(obj);
SaveGlobalMacroSettings(obj); SaveGlobalMacroSettings(obj);
SaveVariables(obj);
saveWindowTitleSwitches(obj); saveWindowTitleSwitches(obj);
saveScreenRegionSwitches(obj); saveScreenRegionSwitches(obj);
savePauseSwitches(obj); savePauseSwitches(obj);
@@ -590,16 +516,18 @@ void SwitcherData::SaveSettings(obs_data_t *obj)
SaveUISettings(obj); SaveUISettings(obj);
SaveVersion(obj, g_GIT_SHA1); SaveVersion(obj, g_GIT_SHA1);
RunSaveSteps(obj); for (const auto &func : saveSteps) {
func(obj);
}
} }
void SwitcherData::SaveGeneralSettings(obs_data_t *obj) void SwitcherData::SaveGeneralSettings(obs_data_t *obj)
{ {
obs_data_set_int(obj, "interval", interval); obs_data_set_int(obj, "interval", interval);
OBSDataAutoRelease noMatchScene = obs_data_create(); std::string nonMatchingSceneName = GetWeakSourceName(nonMatchingScene);
nonMatchingScene.Save(noMatchScene); obs_data_set_string(obj, "non_matching_scene",
obs_data_set_obj(obj, "noMatchScene", noMatchScene); nonMatchingSceneName.c_str());
obs_data_set_int(obj, "switch_if_not_matching", obs_data_set_int(obj, "switch_if_not_matching",
static_cast<int>(switchIfNotMatching)); static_cast<int>(switchIfNotMatching));
noMatchDelay.Save(obj, "noMatchDelay"); noMatchDelay.Save(obj, "noMatchDelay");
@@ -607,18 +535,13 @@ void SwitcherData::SaveGeneralSettings(obs_data_t *obj)
cooldown.Save(obj, "cooldown"); cooldown.Save(obj, "cooldown");
obs_data_set_bool(obj, "enableCooldown", enableCooldown); obs_data_set_bool(obj, "enableCooldown", enableCooldown);
obs_data_set_bool(obj, "active", sceneCollectionStop ? true : !stop); obs_data_set_bool(obj, "active", sceneColletionStop ? true : !stop);
sceneCollectionStop = false; sceneColletionStop = false;
obs_data_set_int(obj, "startup_behavior", obs_data_set_int(obj, "startup_behavior",
static_cast<int>(startupBehavior)); static_cast<int>(startupBehavior));
OBSDataAutoRelease autoStart = obs_data_create(); obs_data_set_int(obj, "autoStartEvent",
obs_data_set_int(autoStart, "event", static_cast<int>(autoStartEvent)); static_cast<int>(autoStartEvent));
obs_data_set_bool(autoStart, "useAutoStartScene", useAutoStartScene);
autoStartScene.Save(autoStart);
autoStartSceneName.Save(autoStart, "name");
autoStartSceneRegex.Save(autoStart);
obs_data_set_obj(obj, "autoStart", autoStart);
SaveLogLevel(obj); SaveLogLevel(obj);
@@ -627,11 +550,10 @@ void SwitcherData::SaveGeneralSettings(obs_data_t *obj)
obs_data_set_bool(obj, "disableHints", disableHints); obs_data_set_bool(obj, "disableHints", disableHints);
obs_data_set_bool(obj, "disableFilterComboboxFilter", obs_data_set_bool(obj, "disableFilterComboboxFilter",
disableFilterComboboxFilter); disableFilterComboboxFilter);
obs_data_set_bool(obj, "disableMacroWidgetCache",
disableMacroWidgetCache);
obs_data_set_bool(obj, "warnPluginLoadFailure", warnPluginLoadFailure); obs_data_set_bool(obj, "warnPluginLoadFailure", warnPluginLoadFailure);
obs_data_set_bool(obj, "hideLegacyTabs", hideLegacyTabs); obs_data_set_bool(obj, "hideLegacyTabs", hideLegacyTabs);
obs_data_set_bool(obj, "settingsLockEnabled", settingsLockEnabled);
obs_data_set_string(obj, "settingsLockPassword",
settingsLockPassword.c_str());
SaveFunctionPriorities(obj, functionNamesByPriority); SaveFunctionPriorities(obj, functionNamesByPriority);
@@ -654,14 +576,9 @@ void SwitcherData::LoadGeneralSettings(obs_data_t *obj)
static_cast<int>(NoMatchBehavior::NO_SWITCH)); static_cast<int>(NoMatchBehavior::NO_SWITCH));
switchIfNotMatching = static_cast<NoMatchBehavior>( switchIfNotMatching = static_cast<NoMatchBehavior>(
obs_data_get_int(obj, "switch_if_not_matching")); obs_data_get_int(obj, "switch_if_not_matching"));
std::string nonMatchingSceneName =
if (obs_data_has_user_value(obj, "noMatchScene")) { obs_data_get_string(obj, "non_matching_scene");
OBSDataAutoRelease noMatchScene = nonMatchingScene = GetWeakSourceByName(nonMatchingSceneName.c_str());
obs_data_get_obj(obj, "noMatchScene");
nonMatchingScene.Load(noMatchScene);
} else {
nonMatchingScene.Load(obj, "non_matching_scene");
}
noMatchDelay.Load(obj, "noMatchDelay"); noMatchDelay.Load(obj, "noMatchDelay");
cooldown.Load(obj, "cooldown"); cooldown.Load(obj, "cooldown");
@@ -682,15 +599,8 @@ void SwitcherData::LoadGeneralSettings(obs_data_t *obj)
stop = true; stop = true;
} }
OBSDataAutoRelease autoStart = obs_data_get_obj(obj, "autoStart"); autoStartEvent =
autoStartEvent = static_cast<AutoStart>( static_cast<AutoStart>(obs_data_get_int(obj, "autoStartEvent"));
obs_data_has_user_value(obj, "autoStart")
? obs_data_get_int(autoStart, "event")
: obs_data_get_int(obj, "autoStartEvent"));
useAutoStartScene = obs_data_get_bool(autoStart, "useAutoStartScene");
autoStartScene.Load(autoStart);
autoStartSceneName.Load(autoStart, "name");
autoStartSceneRegex.Load(autoStart);
LoadLogLevel(obj); LoadLogLevel(obj);
@@ -699,12 +609,12 @@ void SwitcherData::LoadGeneralSettings(obs_data_t *obj)
disableHints = obs_data_get_bool(obj, "disableHints"); disableHints = obs_data_get_bool(obj, "disableHints");
disableFilterComboboxFilter = disableFilterComboboxFilter =
obs_data_get_bool(obj, "disableFilterComboboxFilter"); obs_data_get_bool(obj, "disableFilterComboboxFilter");
disableMacroWidgetCache =
obs_data_get_bool(obj, "disableMacroWidgetCache");
obs_data_set_default_bool(obj, "warnPluginLoadFailure", true); obs_data_set_default_bool(obj, "warnPluginLoadFailure", true);
warnPluginLoadFailure = obs_data_get_bool(obj, "warnPluginLoadFailure"); warnPluginLoadFailure = obs_data_get_bool(obj, "warnPluginLoadFailure");
obs_data_set_default_bool(obj, "hideLegacyTabs", true); obs_data_set_default_bool(obj, "hideLegacyTabs", true);
hideLegacyTabs = obs_data_get_bool(obj, "hideLegacyTabs"); hideLegacyTabs = obs_data_get_bool(obj, "hideLegacyTabs");
settingsLockEnabled = obs_data_get_bool(obj, "settingsLockEnabled");
settingsLockPassword = obs_data_get_string(obj, "settingsLockPassword");
SetDefaultFunctionPriorities(obj); SetDefaultFunctionPriorities(obj);
LoadFunctionPriorities(obj, functionNamesByPriority); LoadFunctionPriorities(obj, functionNamesByPriority);
@@ -770,10 +680,10 @@ void SwitcherData::CheckNoMatchSwitch(bool &match, OBSWeakSource &scene,
return; return;
} }
auto noMatchScene = nonMatchingScene.GetScene(false); if (switchIfNotMatching == NoMatchBehavior::SWITCH &&
if (switchIfNotMatching == NoMatchBehavior::SWITCH && noMatchScene) { nonMatchingScene) {
match = true; match = true;
scene = noMatchScene; scene = nonMatchingScene;
transition = nullptr; transition = nullptr;
} }
if (switchIfNotMatching == NoMatchBehavior::RANDOM_SWITCH) { if (switchIfNotMatching == NoMatchBehavior::RANDOM_SWITCH) {
@@ -781,27 +691,6 @@ void SwitcherData::CheckNoMatchSwitch(bool &match, OBSWeakSource &scene,
} }
} }
void SwitcherData::CheckAutoStart()
{
if (!useAutoStartScene) {
return;
}
bool shouldStartPlugin = false;
if (autoStartSceneRegex.Enabled()) {
const auto currentSceneName = GetWeakSourceName(currentScene);
shouldStartPlugin = autoStartSceneRegex.Matches(
currentSceneName, autoStartSceneName);
} else {
shouldStartPlugin = autoStartScene.GetScene(false) ==
currentScene;
}
if (shouldStartPlugin) {
Start();
}
}
void SwitcherData::checkSwitchCooldown(bool &match) void SwitcherData::checkSwitchCooldown(bool &match)
{ {
if (!match || !enableCooldown) { if (!match || !enableCooldown) {
@@ -944,7 +833,7 @@ static void setupGeneralTabInactiveWarning(QTabWidget *tabs)
inactiveTimer->start(); inactiveTimer->start();
} }
void AdvSceneSwitcher::SetCheckIntervalTooLowVisibility() const void advss::AdvSceneSwitcher::SetCheckIntervalTooLowVisibility() const
{ {
auto macro = GetMacroWithInvalidConditionInterval(); auto macro = GetMacroWithInvalidConditionInterval();
if (!macro) { if (!macro) {
@@ -968,6 +857,8 @@ void AdvSceneSwitcher::SetCheckIntervalTooLowVisibility() const
void AdvSceneSwitcher::SetupGeneralTab() void AdvSceneSwitcher::SetupGeneralTab()
{ {
PopulateSceneSelection(ui->noMatchSwitchScene, false);
if (switcher->switchIfNotMatching == NoMatchBehavior::SWITCH) { if (switcher->switchIfNotMatching == NoMatchBehavior::SWITCH) {
ui->noMatchSwitch->setChecked(true); ui->noMatchSwitch->setChecked(true);
ui->noMatchSwitchScene->setEnabled(true); ui->noMatchSwitchScene->setEnabled(true);
@@ -979,17 +870,8 @@ void AdvSceneSwitcher::SetupGeneralTab()
ui->noMatchRandomSwitch->setChecked(true); ui->noMatchRandomSwitch->setChecked(true);
ui->noMatchSwitchScene->setEnabled(false); ui->noMatchSwitchScene->setEnabled(false);
} }
ui->noMatchSwitchScene->SetScene(switcher->nonMatchingScene); ui->noMatchSwitchScene->setCurrentText(
ui->noMatchSwitchScene->LockToMainCanvas(); GetWeakSourceName(switcher->nonMatchingScene).c_str());
connect(ui->noMatchSwitchScene, &SceneSelectionWidget::SceneChanged,
this, [this](const SceneSelection &scene) {
if (loading) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switcher->nonMatchingScene = scene;
});
DurationSelection *noMatchDelay = new DurationSelection(); DurationSelection *noMatchDelay = new DurationSelection();
noMatchDelay->SetDuration(switcher->noMatchDelay); noMatchDelay->SetDuration(switcher->noMatchDelay);
@@ -1024,10 +906,11 @@ void AdvSceneSwitcher::SetupGeneralTab()
switcher->disableFilterComboboxFilter); switcher->disableFilterComboboxFilter);
FilterComboBox::SetFilterBehaviourEnabled( FilterComboBox::SetFilterBehaviourEnabled(
!switcher->disableFilterComboboxFilter); !switcher->disableFilterComboboxFilter);
ui->disableMacroWidgetCache->setChecked(
switcher->disableMacroWidgetCache);
MacroSegmentList::SetCachingEnabled(!switcher->disableMacroWidgetCache);
ui->warnPluginLoadFailure->setChecked(switcher->warnPluginLoadFailure); ui->warnPluginLoadFailure->setChecked(switcher->warnPluginLoadFailure);
ui->suppressCrashRecoveryDialog->setChecked(GetSuppressCrashDialog());
ui->hideLegacyTabs->setChecked(switcher->hideLegacyTabs); ui->hideLegacyTabs->setChecked(switcher->hideLegacyTabs);
ui->settingsLock->setChecked(switcher->settingsLockEnabled);
populatePriorityFunctionList(ui->priorityList); populatePriorityFunctionList(ui->priorityList);
populateThreadPriorityList(ui->threadPriority); populateThreadPriorityList(ui->threadPriority);
@@ -1039,88 +922,6 @@ void AdvSceneSwitcher::SetupGeneralTab()
populateAutoStartEventSelection(ui->autoStartEvent); populateAutoStartEventSelection(ui->autoStartEvent);
ui->autoStartEvent->setCurrentIndex( ui->autoStartEvent->setCurrentIndex(
static_cast<int>(switcher->autoStartEvent)); static_cast<int>(switcher->autoStartEvent));
ui->autoStartSceneEnable->setChecked(switcher->useAutoStartScene);
ui->autoStartScene->SetScene(switcher->autoStartScene);
ui->autoStartScene->LockToMainCanvas();
ui->autoStartSceneName->setText(switcher->autoStartSceneName);
ui->autoStartSceneNameRegex->SetRegexConfig(
switcher->autoStartSceneRegex);
const auto setupAutoStartSceneLayoutVisibility = [this](bool useRegex) {
ui->autoStartSceneName->setVisible(useRegex);
ui->autoStartScene->setVisible(!useRegex);
if (useRegex) {
RemoveStretchIfPresent(ui->autoStartSceneLayout);
} else {
AddStretchIfNecessary(ui->autoStartSceneLayout);
}
};
setupAutoStartSceneLayoutVisibility(
switcher->autoStartSceneRegex.Enabled());
const auto setupAutoStartSceneWidgetState =
[this](bool useAutoStartScene) {
ui->autoStartScene->setEnabled(useAutoStartScene);
ui->autoStartSceneName->setEnabled(useAutoStartScene);
ui->autoStartSceneNameRegex->setEnabled(
useAutoStartScene);
};
setupAutoStartSceneWidgetState(switcher->useAutoStartScene);
connect(ui->autoStartSceneEnable, &QCheckBox::stateChanged, this,
[this, setupAutoStartSceneWidgetState](int enabled) {
if (loading) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switcher->useAutoStartScene = enabled;
setupAutoStartSceneWidgetState(enabled);
});
connect(ui->autoStartScene, &SceneSelectionWidget::SceneChanged, this,
[this](const SceneSelection &scene) {
if (loading) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switcher->autoStartScene = scene;
switcher->CheckAutoStart();
});
connect(ui->autoStartSceneName, &VariableLineEdit::editingFinished,
this, [this]() {
if (loading) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switcher->autoStartSceneName =
ui->autoStartSceneName->text().toStdString();
switcher->CheckAutoStart();
});
connect(ui->autoStartSceneNameRegex,
&RegexConfigWidget::RegexConfigChanged, this,
[this, setupAutoStartSceneLayoutVisibility](
const RegexConfig &regex) {
if (loading) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switcher->autoStartSceneRegex = regex;
setupAutoStartSceneLayoutVisibility(regex.Enabled());
switcher->CheckAutoStart();
});
ui->alwaysShowMacroSearch->setChecked(
GetMacroSearchSettings().showAlways);
connect(ui->alwaysShowMacroSearch, &QCheckBox::stateChanged, this,
[this](int enabled) {
GetMacroSearchSettings().showAlways = enabled;
if (loading) {
return;
}
CheckMacroSearchVisibility();
});
// Set up status control // Set up status control
auto statusControl = new StatusControl(this, true); auto statusControl = new StatusControl(this, true);
@@ -1141,8 +942,6 @@ void AdvSceneSwitcher::SetupGeneralTab()
setTabOrder(ui->importSettings, ui->cooldownTime); setTabOrder(ui->importSettings, ui->cooldownTime);
setTabOrder(ui->cooldownTime, ui->noMatchDontSwitch); setTabOrder(ui->cooldownTime, ui->noMatchDontSwitch);
SetupShowAllTabsCheckBox(ui->alwaysShowFeatureTabs, ui->tabWidget);
MinimizeSizeOfColumn(ui->statusLayout, 0); MinimizeSizeOfColumn(ui->statusLayout, 0);
setWindowTitle(windowTitle() + " - " + g_GIT_TAG); setWindowTitle(windowTitle() + " - " + g_GIT_TAG);
} }

View File

@@ -92,11 +92,12 @@ bool SwitcherData::checkExeSwitch(OBSWeakSource &scene,
} }
std::string title = switcher->currentTitle; std::string title = switcher->currentTitle;
QStringList runningProcesses;
bool ignored = false; bool ignored = false;
bool match = false; bool match = false;
// Check for match // Check for match
const auto runningProcesses = GetProcessList(); GetProcessList(runningProcesses);
for (ExecutableSwitch &s : executableSwitches) { for (ExecutableSwitch &s : executableSwitches) {
if (!s.initialized()) { if (!s.initialized()) {
continue; continue;

View File

@@ -178,19 +178,47 @@ void AdvSceneSwitcher::on_ignoreWindows_currentRowChanged(int idx)
} }
} }
static bool windowInfoMatchesSwitch(const WindowInfo &info, void checkWindowTitleSwitchDirect(WindowSwitch &s,
const WindowSwitch &s) std::string &currentWindowTitle, bool &match,
OBSWeakSource &scene,
OBSWeakSource &transition)
{ {
if (s.focus && !info.focused) { bool focus = (!s.focus || s.window == currentWindowTitle);
return false; bool fullscreen = (!s.fullscreen || IsFullscreen(s.window));
bool max = (!s.maximized || IsMaximized(s.window));
if (focus && fullscreen && max) {
match = true;
scene = s.getScene();
transition = s.transition;
} }
if (s.fullscreen && !info.fullscreen) { }
return false;
void checkWindowTitleSwitchRegex(WindowSwitch &s,
std::string &currentWindowTitle,
std::vector<std::string> windowList,
bool &match, OBSWeakSource &scene,
OBSWeakSource &transition)
{
for (auto &window : windowList) {
try {
std::regex expr(s.window);
if (!std::regex_match(window, expr)) {
continue;
}
} catch (const std::regex_error &) {
}
bool focus = (!s.focus || window == currentWindowTitle);
bool fullscreen = (!s.fullscreen || IsFullscreen(window));
bool max = (!s.maximized || IsMaximized(window));
if (focus && fullscreen && max) {
match = true;
scene = s.getScene();
transition = s.transition;
}
} }
if (s.maximized && !info.maximized) {
return false;
}
return true;
} }
bool SwitcherData::checkWindowTitleSwitch(OBSWeakSource &scene, bool SwitcherData::checkWindowTitleSwitch(OBSWeakSource &scene,
@@ -200,37 +228,24 @@ bool SwitcherData::checkWindowTitleSwitch(OBSWeakSource &scene,
return false; return false;
} }
std::string currentWindowTitle = switcher->currentTitle;
bool match = false; bool match = false;
std::vector<std::string> windowList;
WindowQueryOptions options; GetWindowList(windowList);
options.focus = true;
options.fullscreen = true;
options.maximized = true;
const auto windows = GetWindows(options);
for (WindowSwitch &s : windowSwitches) { for (WindowSwitch &s : windowSwitches) {
if (!s.initialized()) { if (!s.initialized()) {
continue; continue;
} }
for (const auto &info : windows) { if (std::find(windowList.begin(), windowList.end(), s.window) !=
bool titleMatch = false; windowList.end()) {
try { checkWindowTitleSwitchDirect(s, currentWindowTitle,
std::regex expr(s.window); match, scene, transition);
titleMatch = info.title == s.window || } else {
std::regex_match(info.title, expr); checkWindowTitleSwitchRegex(s, currentWindowTitle,
} catch (const std::regex_error &) { windowList, match, scene,
titleMatch = info.title == s.window; transition);
}
if (!titleMatch || !windowInfoMatchesSwitch(info, s)) {
continue;
}
match = true;
scene = s.getScene();
transition = s.transition;
break;
} }
if (match) { if (match) {

View File

@@ -32,9 +32,6 @@
#endif #endif
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <climits>
#include <dirent.h>
#include <unistd.h>
#include "kwin-helpers.h" #include "kwin-helpers.h"
namespace advss { namespace advss {
@@ -236,89 +233,28 @@ std::string getWindowName(Window window)
return windowTitle; return windowTitle;
} }
std::vector<WindowInfo> GetWindows(const WindowQueryOptions &options) void GetWindowList(std::vector<std::string> &windows)
{ {
const std::string foregroundTitle = GetCurrentWindowTitle(); windows.resize(0);
const auto topLevel = getTopLevelWindows(); for (auto window : getTopLevelWindows()) {
auto display = disp();
std::vector<WindowInfo> result;
result.reserve(topLevel.size());
for (auto window : topLevel) {
auto name = getWindowName(window); auto name = getWindowName(window);
if (name.empty()) { if (name.empty()) {
continue; continue;
} }
windows.emplace_back(name);
WindowInfo info;
info.title = name;
if (options.focus) {
info.focused = (name == foregroundTitle);
}
if (options.fullscreen || options.maximized) {
QStringList states = getStates(window);
if (options.fullscreen) {
info.fullscreen = states.contains(
"_NET_WM_STATE_FULLSCREEN");
}
if (options.maximized) {
info.maximized =
states.contains(
"_NET_WM_STATE_MAXIMIZED_VERT") &&
states.contains(
"_NET_WM_STATE_MAXIMIZED_HORZ");
}
}
if (options.geometry && display) {
XWindowAttributes attrs;
if (XGetWindowAttributes(display, window, &attrs)) {
int x = 0;
int y = 0;
Window child;
XTranslateCoordinates(
display, window,
DefaultRootWindow(display), 0, 0, &x,
&y, &child);
info.x = x;
info.y = y;
info.width = attrs.width;
info.height = attrs.height;
}
}
// windowClass and text not implemented on Linux
result.emplace_back(std::move(info));
} }
}
// When KWin compat is active, native Wayland windows are not tracked by void GetWindowList(QStringList &windows)
// X11 and therefore do not appear in the list above. Merge in any window {
// reported by KWin that is not already present (matched by title) so that windows.clear();
// title and focus conditions work for native Wayland windows. for (auto window : getTopLevelWindows()) {
if (KWin) { auto name = getWindowName(window);
for (const auto &[pid, title] : if (name.empty()) {
FocusNotifier::getWindowList()) { continue;
bool found = false;
for (const auto &info : result) {
if (info.title == title) {
found = true;
break;
}
}
if (!found) {
WindowInfo waylandWindow;
waylandWindow.title = title;
waylandWindow.focused =
(title == foregroundTitle);
result.emplace_back(std::move(waylandWindow));
}
} }
windows << QString::fromStdString(name);
} }
return result;
} }
int getActiveWindow(Window *&window) int getActiveWindow(Window *&window)
@@ -342,24 +278,91 @@ int getActiveWindow(Window *&window)
&bytes, (uint8_t **)&window); &bytes, (uint8_t **)&window);
} }
std::string GetCurrentWindowTitle() void GetCurrentWindowTitle(std::string &title)
{ {
if (KWin) { if (KWin) {
return FocusNotifier::getActiveWindowTitle(); title = FocusNotifier::getActiveWindowTitle();
return;
} }
Window *data = 0; Window *data = 0;
if (getActiveWindow(data) != Success || !data) { if (getActiveWindow(data) != Success || !data) {
return {}; return;
} }
if (!data[0]) { if (!data[0]) {
XFree(data); XFree(data);
return {}; return;
} }
auto name = getWindowName(data[0]); auto name = getWindowName(data[0]);
XFree(data); XFree(data);
return name;
if (name.empty()) {
return;
}
title = name;
}
bool windowStatesAreSet(const std::string &windowTitle,
std::vector<QString> &expectedStates)
{
if (!ewmhIsSupported()) {
return false;
}
std::vector<Window> windows = getTopLevelWindows();
for (auto &window : windows) {
auto name = getWindowName(window);
if (name.empty()) {
continue;
}
bool equals = windowTitle == name;
bool matches = QString::fromStdString(name).contains(
QRegularExpression(
QString::fromStdString(windowTitle)));
if (!(equals || matches)) {
continue;
}
QStringList states = getStates(window);
if (states.isEmpty()) {
if (expectedStates.empty()) {
return true;
}
return false;
}
for (const auto &state : expectedStates) {
if (!states.contains(state)) {
return false;
}
}
return true;
}
return false;
}
bool IsMaximized(const std::string &title)
{
std::vector<QString> states;
states.emplace_back("_NET_WM_STATE_MAXIMIZED_VERT");
states.emplace_back("_NET_WM_STATE_MAXIMIZED_HORZ");
return windowStatesAreSet(title, states);
}
bool IsFullscreen(const std::string &title)
{
std::vector<QString> states;
states.emplace_back("_NET_WM_STATE_FULLSCREEN");
return windowStatesAreSet(title, states);
}
std::optional<std::string> GetTextInWindow(const std::string &)
{
// Not implemented
return {};
} }
static void getProcessListProcps(QStringList &processes) static void getProcessListProcps(QStringList &processes)
@@ -406,17 +409,16 @@ static void getProcessListProcps2(QStringList &processes)
#endif #endif
} }
QStringList GetProcessList() void GetProcessList(QStringList &processes)
{ {
QStringList processes; processes.clear();
if (libprocpsSupported) { if (libprocpsSupported) {
getProcessListProcps(processes); getProcessListProcps(processes);
return processes; return;
} }
if (libprocps2Supported) { if (libprocps2Supported) {
getProcessListProcps2(processes); getProcessListProcps2(processes);
} }
return processes;
} }
long getForegroundProcessPid() long getForegroundProcessPid()
@@ -467,83 +469,24 @@ std::string getProcNameFromPid(long pid)
return name; return name;
} }
std::string GetForegroundProcessName() void GetForegroundProcessName(QString &proc)
{ {
std::string temp;
GetForegroundProcessName(temp);
proc = QString::fromStdString(temp);
}
void GetForegroundProcessName(std::string &proc)
{
proc.resize(0);
auto pid = getForegroundProcessPid(); auto pid = getForegroundProcessPid();
return getProcNameFromPid(pid); proc = getProcNameFromPid(pid);
}
static std::string getProcessPathFromPid(long pid)
{
std::string linkPath = "/proc/" + std::to_string(pid) + "/exe";
char buf[PATH_MAX];
ssize_t len = readlink(linkPath.c_str(), buf, sizeof(buf) - 1);
if (len <= 0) {
return {};
}
buf[len] = '\0';
return buf;
}
std::string GetForegroundProcessPath()
{
auto pid = getForegroundProcessPid();
if (pid <= 0) {
return {};
}
return getProcessPathFromPid(pid);
}
QStringList GetProcessPathsFromName(const QString &name)
{
QStringList paths;
const std::string nameStr = name.toStdString();
DIR *procDir = opendir("/proc");
if (!procDir) {
return paths;
}
struct dirent *entry;
while ((entry = readdir(procDir)) != nullptr) {
bool isPid = (entry->d_name[0] != '\0');
for (const char *c = entry->d_name; *c; c++) {
if (!isdigit(*c)) {
isPid = false;
break;
}
}
if (!isPid) {
continue;
}
std::string pid = entry->d_name;
std::string commPath = "/proc/" + pid + "/comm";
std::ifstream commFile(commPath);
if (!commFile) {
continue;
}
std::string comm;
std::getline(commFile, comm);
if (comm != nameStr) {
continue;
}
std::string path = getProcessPathFromPid(std::stol(pid));
if (path.empty()) {
continue;
}
QString qPath = QString::fromStdString(path);
if (!paths.contains(qPath)) {
paths.append(qPath);
}
}
closedir(procDir);
return paths;
} }
bool IsInFocus(const QString &executable) bool IsInFocus(const QString &executable)
{ {
const auto current = GetForegroundProcessName(); std::string current;
GetForegroundProcessName(current);
// True if executable switch equals current window // True if executable switch equals current window
bool equals = (executable.toStdString() == current); bool equals = (executable.toStdString() == current);

View File

@@ -12,82 +12,35 @@
namespace advss { namespace advss {
std::mutex FocusNotifier::_mutex;
int FocusNotifier::activePID = -1; int FocusNotifier::activePID = -1;
std::string FocusNotifier::activeTitle = {}; std::string FocusNotifier::activeTitle = {};
std::map<std::string, std::pair<int, std::string>> FocusNotifier::_windows;
int FocusNotifier::getActiveWindowPID() int FocusNotifier::getActiveWindowPID()
{ {
std::lock_guard<std::mutex> lock(_mutex);
return activePID; return activePID;
} }
std::string FocusNotifier::getActiveWindowTitle() std::string FocusNotifier::getActiveWindowTitle()
{ {
std::lock_guard<std::mutex> lock(_mutex);
return activeTitle; return activeTitle;
} }
std::vector<std::pair<int, std::string>> FocusNotifier::getWindowList()
{
std::lock_guard<std::mutex> lock(_mutex);
std::vector<std::pair<int, std::string>> result;
result.reserve(_windows.size());
for (const auto &entry : _windows) {
result.emplace_back(entry.second);
}
return result;
}
void FocusNotifier::focusChanged(const int pid) void FocusNotifier::focusChanged(const int pid)
{ {
std::lock_guard<std::mutex> lock(_mutex);
activePID = pid; activePID = pid;
} }
void FocusNotifier::focusTitle(const QString &title) void FocusNotifier::focusTitle(const QString &title)
{ {
std::lock_guard<std::mutex> lock(_mutex);
activeTitle = title.toStdString(); activeTitle = title.toStdString();
} }
void FocusNotifier::focusUpdate(const int pid, const QString &title)
{
std::lock_guard<std::mutex> lock(_mutex);
activePID = pid;
activeTitle = title.toStdString();
}
void FocusNotifier::windowAdded(const QString &id, const int pid,
const QString &title)
{
std::lock_guard<std::mutex> lock(_mutex);
_windows[id.toStdString()] = {pid, title.toStdString()};
}
void FocusNotifier::windowRemoved(const QString &id)
{
std::lock_guard<std::mutex> lock(_mutex);
_windows.erase(id.toStdString());
}
void FocusNotifier::windowTitleChanged(const QString &id, const QString &title)
{
std::lock_guard<std::mutex> lock(_mutex);
auto it = _windows.find(id.toStdString());
if (it != _windows.end()) {
it->second.second = title.toStdString();
}
}
bool isKWinAvailable() bool isKWinAvailable()
{ {
const QDBusConnectionInterface *interface = const QDBusConnectionInterface *interface =
QDBusConnection::sessionBus().interface(); QDBusConnection::sessionBus().interface();
if (!interface) { if (!interface)
return false; return false;
}
const QStringList services = const QStringList services =
interface->registeredServiceNames().value(); interface->registeredServiceNames().value();
@@ -100,32 +53,25 @@ bool startKWinScript(QString &scriptObjectPath)
"/tmp/AdvancedSceneSwitcher/KWinFocusNotifier.js"; "/tmp/AdvancedSceneSwitcher/KWinFocusNotifier.js";
const QString script = const QString script =
R"(var adss = "com.github.AdvancedSceneSwitcher"; R"(workspace.windowActivated.connect(function(client) {
var adssPath = "/com/github/AdvancedSceneSwitcher"; if (!client) return;
if (!client.pid) return;
if (!client.caption) return;
function trackWindow(window) { callDBus(
var id = window.internalId.toString(); "com.github.AdvancedSceneSwitcher",
callDBus(adss, adssPath, adss, "windowAdded", id, window.pid, window.caption); "/com/github/AdvancedSceneSwitcher",
window.captionChanged.connect(function() { "com.github.AdvancedSceneSwitcher",
callDBus(adss, adssPath, adss, "windowTitleChanged", id, window.caption); "focusChanged",
}); client.pid
} );
callDBus(
var windows = workspace.windowList(); "com.github.AdvancedSceneSwitcher",
for (var i = 0; i < windows.length; i++) { "/com/github/AdvancedSceneSwitcher",
trackWindow(windows[i]); "com.github.AdvancedSceneSwitcher",
} "focusTitle",
client.caption
workspace.windowAdded.connect(trackWindow); );
workspace.windowRemoved.connect(function(window) {
callDBus(adss, adssPath, adss, "windowRemoved", window.internalId.toString());
});
workspace.windowActivated.connect(function(client) {
callDBus(adss, adssPath, adss, "focusUpdate",
client ? client.pid : 0,
client ? client.caption : "");
}))"; }))";
if (const QDir dir; !dir.mkpath(QFileInfo(scriptPath).absolutePath())) { if (const QDir dir; !dir.mkpath(QFileInfo(scriptPath).absolutePath())) {

View File

@@ -2,11 +2,7 @@
#include <QObject> #include <QObject>
#include <QString> #include <QString>
#include <map>
#include <mutex>
#include <string> #include <string>
#include <utility>
#include <vector>
namespace advss { namespace advss {
@@ -14,27 +10,18 @@ class FocusNotifier final : public QObject {
Q_OBJECT Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "com.github.AdvancedSceneSwitcher") Q_CLASSINFO("D-Bus Interface", "com.github.AdvancedSceneSwitcher")
static std::mutex _mutex;
static int activePID; static int activePID;
static std::string activeTitle; static std::string activeTitle;
// Maps KWin internal window ID to {pid, title}
static std::map<std::string, std::pair<int, std::string>> _windows;
public: public:
using QObject::QObject; using QObject::QObject;
static int getActiveWindowPID(); static int getActiveWindowPID();
static std::string getActiveWindowTitle(); static std::string getActiveWindowTitle();
static std::vector<std::pair<int, std::string>> getWindowList();
public slots: public slots:
void focusChanged(const int pid); void focusChanged(const int pid);
void focusTitle(const QString &title); void focusTitle(const QString &title);
void focusUpdate(const int pid, const QString &title);
void windowAdded(const QString &id, const int pid,
const QString &title);
void windowRemoved(const QString &id);
void windowTitleChanged(const QString &id, const QString &title);
}; };
bool isKWinAvailable(); bool isKWinAvailable();

View File

@@ -28,7 +28,8 @@ static inline void populateActionSelection(QComboBox *list)
} }
MacroActionEdit::MacroActionEdit(QWidget *parent, MacroActionEdit::MacroActionEdit(QWidget *parent,
std::shared_ptr<MacroAction> *entryData) std::shared_ptr<MacroAction> *entryData,
const std::string &id)
: MacroSegmentEdit(parent), : MacroSegmentEdit(parent),
_actionSelection(new FilterComboBox()), _actionSelection(new FilterComboBox()),
_enable(new SwitchButton()), _enable(new SwitchButton()),
@@ -49,12 +50,10 @@ MacroActionEdit::MacroActionEdit(QWidget *parent,
_section->AddHeaderWidget(_enable); _section->AddHeaderWidget(_enable);
_section->AddHeaderWidget(_actionSelection); _section->AddHeaderWidget(_actionSelection);
_section->AddHeaderWidget(_headerInfo); _section->AddHeaderWidget(_headerInfo);
_section->AddHeaderWidget(_varMappingToggle);
auto actionLayout = new QVBoxLayout; auto actionLayout = new QVBoxLayout;
actionLayout->setContentsMargins({7, 7, 7, 7}); actionLayout->setContentsMargins({7, 7, 7, 7});
actionLayout->addWidget(_section); actionLayout->addWidget(_section);
actionLayout->addWidget(_outputMappings);
_contentLayout->addLayout(actionLayout); _contentLayout->addLayout(actionLayout);
auto mainLayout = new QHBoxLayout; auto mainLayout = new QHBoxLayout;
@@ -63,6 +62,7 @@ MacroActionEdit::MacroActionEdit(QWidget *parent,
mainLayout->addWidget(_frame); mainLayout->addWidget(_frame);
setLayout(mainLayout); setLayout(mainLayout);
_entryData = entryData;
SetupWidgets(true); SetupWidgets(true);
actionStateTimer->start(300); actionStateTimer->start(300);
@@ -91,10 +91,7 @@ void MacroActionEdit::SetupWidgets(bool basicSetup)
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData); auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)), QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
this, SLOT(HeaderInfoChanged(const QString &))); this, SLOT(HeaderInfoChanged(const QString &)));
QWidget::connect(widget, SIGNAL(ShowVariableMappings(bool)), this,
SLOT(ShowVariableMappings(bool)));
_section->SetContent(widget, (*_entryData)->GetCollapsed()); _section->SetContent(widget, (*_entryData)->GetCollapsed());
SetupVarMappings((*_entryData).get());
SetFocusPolicyOfWidgets(); SetFocusPolicyOfWidgets();
_allWidgetsAreSetup = true; _allWidgetsAreSetup = true;
@@ -120,15 +117,12 @@ void MacroActionEdit::ActionSelectionChanged(const QString &text)
*_entryData = MacroActionFactory::Create(id, macro); *_entryData = MacroActionFactory::Create(id, macro);
(*_entryData)->SetIndex(idx); (*_entryData)->SetIndex(idx);
(*_entryData)->PostLoad(); (*_entryData)->PostLoad();
RunAndClearPostLoadSteps(); RunPostLoadSteps();
} }
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData); auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)), QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
this, SLOT(HeaderInfoChanged(const QString &))); this, SLOT(HeaderInfoChanged(const QString &)));
QWidget::connect(widget, SIGNAL(ShowVariableMappings(bool)), this,
SLOT(ShowVariableMappings(bool)));
_section->SetContent(widget); _section->SetContent(widget);
SetupVarMappings((*_entryData).get());
SetFocusPolicyOfWidgets(); SetFocusPolicyOfWidgets();
} }
@@ -164,9 +158,473 @@ std::shared_ptr<MacroSegment> MacroActionEdit::Data() const
return *_entryData; return *_entryData;
} }
void MacroActionEdit::FocusTypeSelection() void AdvSceneSwitcher::AddMacroAction(Macro *macro, int idx,
const std::string &id, obs_data_t *data)
{ {
_actionSelection->setFocus(); if (idx < 0 || idx > (int)macro->Actions().size()) {
assert(false);
return;
}
{
auto lock = LockContext();
macro->Actions().emplace(macro->Actions().begin() + idx,
MacroActionFactory::Create(id, macro));
if (data) {
macro->Actions().at(idx)->Load(data);
}
macro->Actions().at(idx)->PostLoad();
RunPostLoadSteps();
macro->UpdateActionIndices();
ui->actionsList->Insert(
idx,
new MacroActionEdit(this, &macro->Actions()[idx], id));
SetActionData(*macro);
}
HighlightAction(idx);
ui->actionsList->SetHelpMsgVisible(false);
emit(MacroSegmentOrderChanged());
}
void AdvSceneSwitcher::AddMacroAction(int idx)
{
auto macro = GetSelectedMacro();
if (!macro) {
return;
}
if (idx < 0 || idx > (int)macro->Actions().size()) {
assert(false);
return;
}
std::string id;
if (idx - 1 >= 0) {
id = macro->Actions().at(idx - 1)->GetId();
} else {
id = MacroAction::GetDefaultID();
}
OBSDataAutoRelease data;
if (idx - 1 >= 0) {
data = obs_data_create();
macro->Actions().at(idx - 1)->Save(data);
}
AddMacroAction(macro.get(), idx, id, data);
}
void AdvSceneSwitcher::on_actionAdd_clicked()
{
auto macro = GetSelectedMacro();
if (!macro) {
return;
}
if (currentActionIdx == -1) {
AddMacroAction((int)macro->Actions().size());
} else {
AddMacroAction(currentActionIdx + 1);
}
if (currentActionIdx != -1) {
MacroActionSelectionChanged(currentActionIdx + 1);
}
}
void AdvSceneSwitcher::RemoveMacroAction(int idx)
{
auto macro = GetSelectedMacro();
if (!macro) {
return;
}
if (idx < 0 || idx >= (int)macro->Actions().size()) {
return;
}
{
auto lock = LockContext();
ui->actionsList->Remove(idx);
macro->Actions().erase(macro->Actions().begin() + idx);
SetMacroAbortWait(true);
GetMacroWaitCV().notify_all();
macro->UpdateActionIndices();
SetActionData(*macro);
}
MacroActionSelectionChanged(-1);
lastInteracted = MacroSection::ACTIONS;
emit(MacroSegmentOrderChanged());
}
void AdvSceneSwitcher::on_actionRemove_clicked()
{
if (currentActionIdx == -1) {
auto macro = GetSelectedMacro();
if (!macro) {
return;
}
RemoveMacroAction((int)macro->Actions().size() - 1);
} else {
RemoveMacroAction(currentActionIdx);
}
MacroActionSelectionChanged(-1);
}
void AdvSceneSwitcher::on_actionTop_clicked()
{
if (currentActionIdx == -1) {
return;
}
MacroActionReorder(0, currentActionIdx);
MacroActionSelectionChanged(0);
}
void AdvSceneSwitcher::on_actionUp_clicked()
{
if (currentActionIdx == -1 || currentActionIdx == 0) {
return;
}
MoveMacroActionUp(currentActionIdx);
MacroActionSelectionChanged(currentActionIdx - 1);
}
void AdvSceneSwitcher::on_actionDown_clicked()
{
if (currentActionIdx == -1 ||
currentActionIdx == ui->actionsList->ContentLayout()->count() - 1) {
return;
}
MoveMacroActionDown(currentActionIdx);
MacroActionSelectionChanged(currentActionIdx + 1);
}
void AdvSceneSwitcher::on_actionBottom_clicked()
{
if (currentActionIdx == -1) {
return;
}
const int newIdx = ui->actionsList->ContentLayout()->count() - 1;
MacroActionReorder(newIdx, currentActionIdx);
MacroActionSelectionChanged(newIdx);
}
void AdvSceneSwitcher::on_elseActionAdd_clicked()
{
auto macro = GetSelectedMacro();
if (!macro) {
return;
}
if (currentElseActionIdx == -1) {
AddMacroElseAction((int)macro->ElseActions().size());
} else {
AddMacroElseAction(currentElseActionIdx + 1);
}
if (currentElseActionIdx != -1) {
MacroElseActionSelectionChanged(currentElseActionIdx + 1);
}
}
void AdvSceneSwitcher::on_elseActionRemove_clicked()
{
if (currentElseActionIdx == -1) {
auto macro = GetSelectedMacro();
if (!macro) {
return;
}
RemoveMacroElseAction((int)macro->ElseActions().size() - 1);
} else {
RemoveMacroElseAction(currentElseActionIdx);
}
MacroElseActionSelectionChanged(-1);
}
void AdvSceneSwitcher::on_elseActionTop_clicked()
{
if (currentElseActionIdx == -1) {
return;
}
MacroElseActionReorder(0, currentElseActionIdx);
MacroElseActionSelectionChanged(0);
}
void AdvSceneSwitcher::on_elseActionUp_clicked()
{
if (currentElseActionIdx == -1 || currentElseActionIdx == 0) {
return;
}
MoveMacroElseActionUp(currentElseActionIdx);
MacroElseActionSelectionChanged(currentElseActionIdx - 1);
}
void AdvSceneSwitcher::on_elseActionDown_clicked()
{
if (currentElseActionIdx == -1 ||
currentElseActionIdx ==
ui->elseActionsList->ContentLayout()->count() - 1) {
return;
}
MoveMacroElseActionDown(currentElseActionIdx);
MacroElseActionSelectionChanged(currentElseActionIdx + 1);
}
void AdvSceneSwitcher::on_elseActionBottom_clicked()
{
if (currentElseActionIdx == -1) {
return;
}
const int newIdx = ui->elseActionsList->ContentLayout()->count() - 1;
MacroElseActionReorder(newIdx, currentElseActionIdx);
MacroElseActionSelectionChanged(newIdx);
}
void AdvSceneSwitcher::SwapActions(Macro *m, int pos1, int pos2)
{
if (pos1 == pos2) {
return;
}
if (pos1 > pos2) {
std::swap(pos1, pos2);
}
auto lock = LockContext();
iter_swap(m->Actions().begin() + pos1, m->Actions().begin() + pos2);
m->UpdateActionIndices();
auto widget1 = static_cast<MacroActionEdit *>(
ui->actionsList->ContentLayout()->takeAt(pos1)->widget());
auto widget2 = static_cast<MacroActionEdit *>(
ui->actionsList->ContentLayout()->takeAt(pos2 - 1)->widget());
ui->actionsList->Insert(pos1, widget2);
ui->actionsList->Insert(pos2, widget1);
SetActionData(*m);
emit(MacroSegmentOrderChanged());
}
void AdvSceneSwitcher::MoveMacroActionUp(int idx)
{
auto macro = GetSelectedMacro();
if (!macro) {
return;
}
if (idx < 1 || idx >= (int)macro->Actions().size()) {
return;
}
SwapActions(macro.get(), idx, idx - 1);
HighlightAction(idx - 1);
}
void AdvSceneSwitcher::MoveMacroActionDown(int idx)
{
auto macro = GetSelectedMacro();
if (!macro) {
return;
}
if (idx < 0 || idx >= (int)macro->Actions().size() - 1) {
return;
}
SwapActions(macro.get(), idx, idx + 1);
HighlightAction(idx + 1);
}
void AdvSceneSwitcher::MacroElseActionSelectionChanged(int idx)
{
SetupMacroSegmentSelection(MacroSection::ELSE_ACTIONS, idx);
}
void AdvSceneSwitcher::MacroElseActionReorder(int to, int from)
{
auto macro = GetSelectedMacro();
if (!macro) {
return;
}
if (to == from || from < 0 || from > (int)macro->ElseActions().size() ||
to < 0 || to > (int)macro->ElseActions().size()) {
return;
}
{
auto lock = LockContext();
auto action = macro->ElseActions().at(from);
macro->ElseActions().erase(macro->ElseActions().begin() + from);
macro->ElseActions().insert(macro->ElseActions().begin() + to,
action);
macro->UpdateElseActionIndices();
ui->elseActionsList->ContentLayout()->insertItem(
to, ui->elseActionsList->ContentLayout()->takeAt(from));
SetElseActionData(*macro);
}
HighlightElseAction(to);
emit(MacroSegmentOrderChanged());
}
void AdvSceneSwitcher::AddMacroElseAction(Macro *macro, int idx,
const std::string &id,
obs_data_t *data)
{
if (idx < 0 || idx > (int)macro->ElseActions().size()) {
assert(false);
return;
}
{
auto lock = LockContext();
macro->ElseActions().emplace(macro->ElseActions().begin() + idx,
MacroActionFactory::Create(id,
macro));
if (data) {
macro->ElseActions().at(idx)->Load(data);
}
macro->ElseActions().at(idx)->PostLoad();
RunPostLoadSteps();
macro->UpdateElseActionIndices();
ui->elseActionsList->Insert(
idx, new MacroActionEdit(
this, &macro->ElseActions()[idx], id));
SetElseActionData(*macro);
}
HighlightElseAction(idx);
ui->elseActionsList->SetHelpMsgVisible(false);
emit(MacroSegmentOrderChanged());
}
void AdvSceneSwitcher::AddMacroElseAction(int idx)
{
auto macro = GetSelectedMacro();
if (!macro) {
return;
}
if (idx < 0 || idx > (int)macro->ElseActions().size()) {
assert(false);
return;
}
std::string id;
if (idx - 1 >= 0) {
id = macro->ElseActions().at(idx - 1)->GetId();
} else {
id = MacroAction::GetDefaultID();
}
OBSDataAutoRelease data;
if (idx - 1 >= 0) {
data = obs_data_create();
macro->ElseActions().at(idx - 1)->Save(data);
}
AddMacroElseAction(macro.get(), idx, id, data);
}
void AdvSceneSwitcher::RemoveMacroElseAction(int idx)
{
auto macro = GetSelectedMacro();
if (!macro) {
return;
}
if (idx < 0 || idx >= (int)macro->ElseActions().size()) {
return;
}
{
auto lock = LockContext();
ui->elseActionsList->Remove(idx);
macro->ElseActions().erase(macro->ElseActions().begin() + idx);
SetMacroAbortWait(true);
GetMacroWaitCV().notify_all();
macro->UpdateElseActionIndices();
SetElseActionData(*macro);
}
MacroElseActionSelectionChanged(-1);
lastInteracted = MacroSection::ELSE_ACTIONS;
emit(MacroSegmentOrderChanged());
}
void AdvSceneSwitcher::SwapElseActions(Macro *m, int pos1, int pos2)
{
if (pos1 == pos2) {
return;
}
if (pos1 > pos2) {
std::swap(pos1, pos2);
}
auto lock = LockContext();
iter_swap(m->ElseActions().begin() + pos1,
m->ElseActions().begin() + pos2);
m->UpdateElseActionIndices();
auto widget1 = static_cast<MacroActionEdit *>(
ui->elseActionsList->ContentLayout()->takeAt(pos1)->widget());
auto widget2 = static_cast<MacroActionEdit *>(
ui->elseActionsList->ContentLayout()
->takeAt(pos2 - 1)
->widget());
ui->elseActionsList->Insert(pos1, widget2);
ui->elseActionsList->Insert(pos2, widget1);
SetElseActionData(*m);
emit(MacroSegmentOrderChanged());
}
void AdvSceneSwitcher::MoveMacroElseActionUp(int idx)
{
auto macro = GetSelectedMacro();
if (!macro) {
return;
}
if (idx < 1 || idx >= (int)macro->ElseActions().size()) {
return;
}
SwapElseActions(macro.get(), idx, idx - 1);
HighlightElseAction(idx - 1);
}
void AdvSceneSwitcher::MoveMacroElseActionDown(int idx)
{
auto macro = GetSelectedMacro();
if (!macro) {
return;
}
if (idx < 0 || idx >= (int)macro->ElseActions().size() - 1) {
return;
}
SwapElseActions(macro.get(), idx, idx + 1);
HighlightElseAction(idx + 1);
}
void AdvSceneSwitcher::MacroActionSelectionChanged(int idx)
{
SetupMacroSegmentSelection(MacroSection::ACTIONS, idx);
}
void AdvSceneSwitcher::MacroActionReorder(int to, int from)
{
auto macro = GetSelectedMacro();
if (!macro) {
return;
}
if (to == from || from < 0 || from > (int)macro->Actions().size() ||
to < 0 || to > (int)macro->Actions().size()) {
return;
}
{
auto lock = LockContext();
auto action = macro->Actions().at(from);
macro->Actions().erase(macro->Actions().begin() + from);
macro->Actions().insert(macro->Actions().begin() + to, action);
macro->UpdateActionIndices();
ui->actionsList->ContentLayout()->insertItem(
to, ui->actionsList->ContentLayout()->takeAt(from));
SetActionData(*macro);
}
HighlightAction(to);
emit(MacroSegmentOrderChanged());
} }
} // namespace advss } // namespace advss

View File

@@ -13,11 +13,12 @@ class MacroActionEdit : public MacroSegmentEdit {
Q_OBJECT Q_OBJECT
public: public:
MacroActionEdit(QWidget *parent = nullptr, MacroActionEdit(
std::shared_ptr<MacroAction> * = nullptr); QWidget *parent = nullptr,
std::shared_ptr<MacroAction> * = nullptr,
const std::string &id = MacroAction::GetDefaultID().data());
void SetupWidgets(bool basicSetup = false); void SetupWidgets(bool basicSetup = false);
void SetEntryData(std::shared_ptr<MacroAction> *); void SetEntryData(std::shared_ptr<MacroAction> *);
void FocusTypeSelection() override;
private slots: private slots:
void ActionSelectionChanged(const QString &text); void ActionSelectionChanged(const QString &text);

View File

@@ -1,11 +1,25 @@
#include "macro-action-factory.hpp" #include "macro-action-factory.hpp"
#include "macro-segment-unknown.hpp"
#include <mutex> #include <mutex>
namespace advss { namespace advss {
using MacroActionUnknown = MacroSegmentUnknown<MacroAction>; namespace {
class MacroActionUnknown : public MacroAction {
public:
MacroActionUnknown(Macro *m) : MacroAction(m) {}
std::shared_ptr<MacroAction> Copy() const
{
return std::make_shared<MacroActionUnknown>(GetMacro());
}
bool PerformAction() { return true; };
bool Save(obs_data_t *obj) const { return MacroAction::Save(obj); };
bool Load(obs_data_t *obj) { return MacroAction::Load(obj); };
std::string GetId() const { return "unknown"; }
};
} // namespace
static std::recursive_mutex mutex; static std::recursive_mutex mutex;
@@ -35,10 +49,9 @@ bool MacroActionFactory::Deregister(const std::string &id)
return true; return true;
} }
static std::shared_ptr<MacroAction> createUnknownAction(Macro *m, static std::shared_ptr<MacroAction> createUnknownAction(Macro *m)
const std::string &id)
{ {
return std::make_shared<MacroActionUnknown>(m, id); return std::make_shared<MacroActionUnknown>(m);
} }
std::shared_ptr<MacroAction> MacroActionFactory::Create(const std::string &id, std::shared_ptr<MacroAction> MacroActionFactory::Create(const std::string &id,
@@ -49,7 +62,12 @@ std::shared_ptr<MacroAction> MacroActionFactory::Create(const std::string &id,
return it->second._create(m); return it->second._create(m);
} }
return createUnknownAction(m, id); return createUnknownAction(m);
}
static QWidget *createUnknownActionWidget()
{
return new QLabel(obs_module_text("AdvSceneSwitcher.action.unknown"));
} }
QWidget *MacroActionFactory::CreateWidget(const std::string &id, QWidget *MacroActionFactory::CreateWidget(const std::string &id,
@@ -61,7 +79,7 @@ QWidget *MacroActionFactory::CreateWidget(const std::string &id,
return it->second._createWidget(parent, action); return it->second._createWidget(parent, action);
} }
return CreateUnknownSegmentWidget(true); return createUnknownActionWidget();
} }
std::string MacroActionFactory::GetActionName(const std::string &id) std::string MacroActionFactory::GetActionName(const std::string &id)

View File

@@ -1,196 +0,0 @@
#include "macro-action-loop.hpp"
#include "layout-helpers.hpp"
#include "macro-action-factory.hpp"
#include "macro.hpp"
namespace advss {
const std::string MacroActionLoop::id = "loop";
bool MacroActionLoop::_registered = MacroActionFactory::Register(
MacroActionLoop::id,
{MacroActionLoop::Create, MacroActionLoopEdit::Create,
"AdvSceneSwitcher.action.loop"});
bool MacroActionLoop::PerformAction()
{
int iterations = 0;
const int maxIterations = _maxIterations;
Macro *parentMacro = GetMacro();
if (maxIterations <= 0) {
blog(LOG_WARNING,
"loop action has invalid max iterations value of %d",
maxIterations);
return true;
}
while (_loopMacro->CheckConditions()) {
if (iterations >= maxIterations) {
blog(LOG_WARNING,
"loop action reached iteration limit of %d",
maxIterations);
break;
}
ablog(LOG_INFO, "loop iteration %d", iterations);
if (!_loopMacro->PerformActions(true, false, true)) {
break;
}
++iterations;
if (parentMacro && parentMacro->GetStop()) {
break;
}
}
ablog(LOG_INFO, "loop completed after %d iteration(s)", iterations);
SetTempVarValue("count", std::to_string(iterations));
return true;
}
void MacroActionLoop::LogAction() const
{
ablog(LOG_INFO, "running loop (max %d iterations)",
_maxIterations.GetValue());
}
bool MacroActionLoop::Save(obs_data_t *obj) const
{
MacroAction::Save(obj);
_maxIterations.Save(obj, "maxIterations");
OBSDataAutoRelease loopMacroData = obs_data_create();
_loopMacro->Save(loopMacroData);
obs_data_set_obj(obj, "loopMacro", loopMacroData);
obs_data_set_int(obj, "customWidgetHeight", _customWidgetHeight);
return true;
}
bool MacroActionLoop::Load(obs_data_t *obj)
{
MacroAction::Load(obj);
_maxIterations.Load(obj, "maxIterations");
if (obs_data_has_user_value(obj, "loopMacro")) {
OBSDataAutoRelease loopMacroData =
obs_data_get_obj(obj, "loopMacro");
_loopMacro = std::make_shared<Macro>();
_loopMacro->Load(loopMacroData);
}
_customWidgetHeight = obs_data_get_int(obj, "customWidgetHeight");
return true;
}
bool MacroActionLoop::PostLoad()
{
MacroAction::PostLoad();
_loopMacro->PostLoad();
_loopMacro->SetActionTriggerMode(Macro::ActionTriggerMode::ALWAYS);
return true;
}
std::shared_ptr<MacroAction> MacroActionLoop::Create(Macro *m)
{
return std::make_shared<MacroActionLoop>(m);
}
std::shared_ptr<MacroAction> MacroActionLoop::Copy() const
{
auto copy = std::make_shared<MacroActionLoop>(*this);
OBSDataAutoRelease data = obs_data_create();
_loopMacro->Save(data);
copy->_loopMacro = std::make_shared<Macro>();
copy->_loopMacro->Load(data);
copy->_loopMacro->PostLoad();
return copy;
}
void MacroActionLoop::ResolveVariablesToFixedValues()
{
_maxIterations.ResolveVariables();
for (auto &action : _loopMacro->Actions()) {
action->ResolveVariablesToFixedValues();
}
}
void MacroActionLoop::SetupTempVars()
{
MacroAction::SetupTempVars();
AddTempvar("count",
obs_module_text("AdvSceneSwitcher.tempVar.loop.count"),
obs_module_text(
"AdvSceneSwitcher.tempVar.loop.count.description"));
}
MacroActionLoopEdit::MacroActionLoopEdit(
QWidget *parent, std::shared_ptr<MacroActionLoop> entryData)
: ResizableWidget(parent),
_macroEdit(new MacroEdit(
this, QStringList()
<< "AdvSceneSwitcher.action.loop.conditionHelp"
<< "AdvSceneSwitcher.action.loop.actionHelp"
<< "")),
_maxIterations(new VariableSpinBox())
{
_maxIterations->setMinimum(1);
_maxIterations->setMaximum(10000000);
QWidget::connect(
_maxIterations,
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
this, SLOT(MaxIterationsChanged(const NumberVariable<int> &)));
auto controlsLayout = new QHBoxLayout();
controlsLayout->addWidget(new QLabel(
obs_module_text("AdvSceneSwitcher.action.loop.maxIterations")));
controlsLayout->addWidget(_maxIterations);
controlsLayout->addStretch();
auto layout = new QVBoxLayout();
layout->addLayout(controlsLayout);
layout->addWidget(_macroEdit);
setLayout(layout);
_macroEdit->HideElseSection();
_entryData = entryData;
UpdateEntryData();
_loading = false;
}
MacroActionLoopEdit::~MacroActionLoopEdit()
{
if (!_entryData) {
return;
}
_entryData->_customWidgetHeight = GetCustomHeight();
_macroEdit->SetMacro({});
}
void MacroActionLoopEdit::UpdateEntryData()
{
if (!_entryData) {
return;
}
_maxIterations->SetValue(_entryData->_maxIterations);
_macroEdit->SetMacro(_entryData->_loopMacro);
if (_macroEdit->IsEmpty()) {
_macroEdit->ShowAllMacroSections();
_entryData->_customWidgetHeight = 600;
}
SetResizingEnabled(true);
SetCustomHeight(_entryData->_customWidgetHeight);
adjustSize();
updateGeometry();
}
void MacroActionLoopEdit::MaxIterationsChanged(const NumberVariable<int> &value)
{
GUARD_LOADING_AND_LOCK();
_entryData->_maxIterations = value;
}
} // namespace advss

View File

@@ -1,64 +0,0 @@
#pragma once
#include "macro-action-edit.hpp"
#include "macro-edit.hpp"
#include "resizable-widget.hpp"
#include "variable-spinbox.hpp"
#include <QLabel>
#include <QVBoxLayout>
namespace advss {
class MacroActionLoop : public MacroAction {
public:
MacroActionLoop(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction() const;
bool Save(obs_data_t *obj) const;
bool Load(obs_data_t *obj);
bool PostLoad();
std::string GetId() const { return id; }
static std::shared_ptr<MacroAction> Create(Macro *m);
std::shared_ptr<MacroAction> Copy() const;
void ResolveVariablesToFixedValues();
std::shared_ptr<Macro> _loopMacro = std::make_shared<Macro>();
IntVariable _maxIterations = 100;
int _customWidgetHeight = 0;
private:
void SetupTempVars();
static bool _registered;
static const std::string id;
};
class MacroActionLoopEdit : public ResizableWidget {
Q_OBJECT
public:
MacroActionLoopEdit(
QWidget *parent,
std::shared_ptr<MacroActionLoop> entryData = nullptr);
~MacroActionLoopEdit();
void UpdateEntryData();
static QWidget *Create(QWidget *parent,
std::shared_ptr<MacroAction> action)
{
return new MacroActionLoopEdit(
parent,
std::dynamic_pointer_cast<MacroActionLoop>(action));
}
private slots:
void MaxIterationsChanged(const NumberVariable<int> &value);
private:
MacroEdit *_macroEdit;
VariableSpinBox *_maxIterations;
std::shared_ptr<MacroActionLoop> _entryData;
bool _loading = true;
};
} // namespace advss

View File

@@ -1,14 +1,8 @@
#include "macro-action-macro.hpp" #include "macro-action-macro.hpp"
#include "condition-logic.hpp"
#include "help-icon.hpp" #include "help-icon.hpp"
#include "layout-helpers.hpp" #include "layout-helpers.hpp"
#include "macro-action-factory.hpp"
#include "macro-helpers.hpp"
#include "macro.hpp" #include "macro.hpp"
#include <chrono>
namespace advss { namespace advss {
const std::string MacroActionMacro::id = "macro"; const std::string MacroActionMacro::id = "macro";
@@ -18,165 +12,54 @@ bool MacroActionMacro::_registered = MacroActionFactory::Register(
{MacroActionMacro::Create, MacroActionMacroEdit::Create, {MacroActionMacro::Create, MacroActionMacroEdit::Create,
"AdvSceneSwitcher.action.macro"}); "AdvSceneSwitcher.action.macro"});
void MacroActionMacro::AdjustActionState(Macro *macro) const
{
const auto &macroActions = _useElseSection ? macro->ElseActions()
: macro->Actions();
std::vector<std::shared_ptr<MacroAction>> actionsToModify;
switch (_actionSelectionType) {
case SelectionType::INDEX: {
const bool isValidAction =
(_useElseSection &&
IsValidElseActionIndex(macro, _actionIndex - 1)) ||
(!_useElseSection &&
IsValidActionIndex(macro, _actionIndex - 1));
if (isValidAction) {
actionsToModify.emplace_back(
macroActions.at(_actionIndex - 1));
}
break;
}
case SelectionType::LABEL:
for (const auto &action : macroActions) {
if (!action->GetUseCustomLabel()) {
continue;
}
const auto label = action->GetCustomLabel();
if (_regex.Enabled()) {
if (_regex.Matches(label, _label)) {
actionsToModify.emplace_back(action);
}
continue;
}
if (label == std::string(_label)) {
actionsToModify.emplace_back(action);
}
}
break;
case SelectionType::ID:
for (const auto &action : macroActions) {
if (action->GetId() == _actionId) {
actionsToModify.emplace_back(action);
}
}
break;
default:
break;
}
for (const auto &action : actionsToModify) {
switch (_action) {
case Action::DISABLE_ACTION:
action->SetEnabled(false);
break;
case Action::ENABLE_ACTION:
action->SetEnabled(true);
break;
case Action::TOGGLE_ACTION:
action->SetEnabled(!action->Enabled());
break;
default:
break;
}
}
}
bool MacroActionMacro::PerformAction() bool MacroActionMacro::PerformAction()
{ {
if (_action == Action::NESTED_MACRO) {
const bool conditionsMatched = _nestedMacro->CheckConditions();
return _nestedMacro->PerformActions(conditionsMatched);
}
auto macro = _macro.GetMacro(); auto macro = _macro.GetMacro();
if (!macro) { if (!macro) {
return true; return true;
} }
const auto performActionForMacro = [this](Macro *macro) { switch (_action) {
switch (_action) { case Action::PAUSE:
case Action::PAUSE: macro->SetPaused();
macro->SetPaused(); break;
break; case Action::UNPAUSE:
case Action::UNPAUSE: macro->SetPaused(false);
macro->SetPaused(false); break;
break; case Action::TOGGLE_PAUSE:
case Action::TOGGLE_PAUSE: macro->SetPaused(!macro->Paused());
macro->SetPaused(!macro->Paused()); break;
break; case Action::RESET_COUNTER:
case Action::RESET_COUNTER: macro->ResetRunCount();
macro->ResetRunCount(); break;
break; case Action::RUN:
case Action::RUN_ACTIONS: RunActions(macro.get());
RunActions(macro); break;
break; case Action::STOP:
case Action::STOP: macro->Stop();
macro->Stop(); break;
break; case Action::DISABLE_ACTION:
case Action::DISABLE_ACTION: if (IsValidMacroSegmentIndex(macro.get(), _actionIndex - 1,
case Action::ENABLE_ACTION: false)) {
case Action::TOGGLE_ACTION: macro->Actions().at(_actionIndex - 1)->SetEnabled(false);
AdjustActionState(macro);
break;
case Action::RUN_MACRO: {
if (_runOptions.skipWhenPaused && macro->Paused()) {
break;
}
const bool conditionsMatched =
macro->CheckConditions(true);
macro->PerformActions(conditionsMatched, false, true);
break;
} }
case Action::GET_INFO: { break;
SetTempVarValue( case Action::ENABLE_ACTION:
"conditionCount", if (IsValidMacroSegmentIndex(macro.get(), _actionIndex - 1,
std::to_string(macro->Conditions().size())); false)) {
SetTempVarValue( macro->Actions().at(_actionIndex - 1)->SetEnabled(true);
"actionCount",
std::to_string(macro->Actions().size()));
SetTempVarValue(
"elseActionCount",
std::to_string(macro->ElseActions().size()));
SetTempVarValue("paused",
macro->Paused() ? "true" : "false");
SetTempVarValue("runCount",
std::to_string(macro->RunCount()));
const auto lastRun = macro->GetLastExecutionTime();
const bool hasRun =
lastRun.time_since_epoch().count() != 0;
const auto secondsSinceLastRun =
hasRun ? std::chrono::duration_cast<
std::chrono::seconds>(
std::chrono::
high_resolution_clock::
now() -
lastRun)
.count()
: -1;
SetTempVarValue("secondsSinceLastRun",
std::to_string(secondsSinceLastRun));
break;
} }
default: break;
break; case Action::TOGGLE_ACTION:
if (IsValidMacroSegmentIndex(macro.get(), _actionIndex - 1,
false)) {
auto action = macro->Actions().at(_actionIndex - 1);
action->SetEnabled(!action->Enabled());
} }
}; break;
default:
if (!IsGroupMacro(macro.get())) { break;
performActionForMacro(macro.get());
return true;
} }
auto macros = GetGroupMacroEntries(macro.get());
for (const auto &macro : macros) {
performActionForMacro(macro.get());
}
return true; return true;
} }
@@ -197,7 +80,7 @@ void MacroActionMacro::LogAction() const
ablog(LOG_INFO, "reset counter for \"%s\"", ablog(LOG_INFO, "reset counter for \"%s\"",
macro->Name().c_str()); macro->Name().c_str());
break; break;
case Action::RUN_ACTIONS: case Action::RUN:
ablog(LOG_INFO, "run nested macro \"%s\"", ablog(LOG_INFO, "run nested macro \"%s\"",
macro->Name().c_str()); macro->Name().c_str());
break; break;
@@ -216,15 +99,6 @@ void MacroActionMacro::LogAction() const
ablog(LOG_INFO, "toggled action %d of macro \"%s\"", ablog(LOG_INFO, "toggled action %d of macro \"%s\"",
_actionIndex.GetValue(), macro->Name().c_str()); _actionIndex.GetValue(), macro->Name().c_str());
break; break;
case Action::NESTED_MACRO:
ablog(LOG_INFO, "run nested macro");
break;
case Action::GET_INFO:
ablog(LOG_INFO, "get info for \"%s\"", macro->Name().c_str());
break;
case Action::RUN_MACRO:
ablog(LOG_INFO, "run macro \"%s\"", macro->Name().c_str());
break;
default: default:
break; break;
} }
@@ -233,45 +107,21 @@ void MacroActionMacro::LogAction() const
bool MacroActionMacro::Save(obs_data_t *obj) const bool MacroActionMacro::Save(obs_data_t *obj) const
{ {
MacroAction::Save(obj); MacroAction::Save(obj);
obs_data_set_int(obj, "action", static_cast<int>(_action));
_macro.Save(obj); _macro.Save(obj);
obs_data_set_int(obj, "actionSelectionType",
static_cast<int>(_actionSelectionType));
_actionIndex.Save(obj, "actionIndex"); _actionIndex.Save(obj, "actionIndex");
_label.Save(obj, "label"); obs_data_set_int(obj, "action", static_cast<int>(_action));
obs_data_set_string(obj, "actionId", _actionId.c_str());
_regex.Save(obj);
_runOptions.Save(obj); _runOptions.Save(obj);
OBSDataAutoRelease nestedMacroData = obs_data_create();
_nestedMacro->Save(nestedMacroData);
obs_data_set_obj(obj, "nestedMacro", nestedMacroData);
obs_data_set_int(obj, "customWidgetHeight", _customWidgetHeight);
return true; return true;
} }
bool MacroActionMacro::Load(obs_data_t *obj) bool MacroActionMacro::Load(obs_data_t *obj)
{ {
MacroAction::Load(obj); MacroAction::Load(obj);
SetAction(static_cast<MacroActionMacro::Action>(
obs_data_get_int(obj, "action")));
_macro.Load(obj); _macro.Load(obj);
_actionSelectionType = static_cast<SelectionType>(
obs_data_get_int(obj, "actionSelectionType"));
_actionIndex.Load(obj, "actionIndex"); _actionIndex.Load(obj, "actionIndex");
_label.Load(obj, "label"); _action = static_cast<MacroActionMacro::Action>(
_actionId = obs_data_get_string(obj, "actionId"); obs_data_get_int(obj, "action"));
_regex.Load(obj);
_runOptions.Load(obj); _runOptions.Load(obj);
if (obs_data_has_user_value(obj, "nestedMacro")) {
OBSDataAutoRelease nestedMacroData =
obs_data_get_obj(obj, "nestedMacro");
_nestedMacro = std::make_shared<Macro>();
_nestedMacro->Load(nestedMacroData);
}
_customWidgetHeight = obs_data_get_int(obj, "customWidgetHeight");
return true; return true;
} }
@@ -280,7 +130,6 @@ bool MacroActionMacro::PostLoad()
MacroRefAction::PostLoad(); MacroRefAction::PostLoad();
MacroAction::PostLoad(); MacroAction::PostLoad();
_runOptions.macro.PostLoad(); _runOptions.macro.PostLoad();
_nestedMacro->PostLoad();
return true; return true;
} }
@@ -296,32 +145,12 @@ std::shared_ptr<MacroAction> MacroActionMacro::Create(Macro *m)
std::shared_ptr<MacroAction> MacroActionMacro::Copy() const std::shared_ptr<MacroAction> MacroActionMacro::Copy() const
{ {
auto copy = std::make_shared<MacroActionMacro>(*this); return std::make_shared<MacroActionMacro>(*this);
// Create a new nested macro
OBSDataAutoRelease data = obs_data_create();
_nestedMacro->Save(data);
copy->_nestedMacro = std::make_shared<Macro>();
copy->_nestedMacro->Load(data);
copy->_nestedMacro->PostLoad();
return copy;
} }
void MacroActionMacro::ResolveVariablesToFixedValues() void MacroActionMacro::ResolveVariablesToFixedValues()
{ {
_actionIndex.ResolveVariables(); _actionIndex.ResolveVariables();
_label.ResolveVariables();
if (_action == Action::NESTED_MACRO) {
for (auto &action : _nestedMacro->Actions()) {
action->ResolveVariablesToFixedValues();
}
for (auto &action : _nestedMacro->ElseActions()) {
action->ResolveVariablesToFixedValues();
}
}
} }
static void runActionsHelper(Macro *macro, bool runElseActions, bool setInputs, static void runActionsHelper(Macro *macro, bool runElseActions, bool setInputs,
@@ -363,56 +192,6 @@ void MacroActionMacro::RunActions(Macro *actionMacro) const
} }
} }
void MacroActionMacro::SetAction(Action action)
{
_action = action;
SetupTempVars();
}
void MacroActionMacro::SetupTempVars()
{
MacroAction::SetupTempVars();
if (_action != Action::GET_INFO) {
return;
}
AddTempvar(
"conditionCount",
obs_module_text(
"AdvSceneSwitcher.tempVar.macro.info.conditionCount"),
obs_module_text(
"AdvSceneSwitcher.tempVar.macro.info.conditionCount.description"));
AddTempvar(
"actionCount",
obs_module_text(
"AdvSceneSwitcher.tempVar.macro.info.actionCount"),
obs_module_text(
"AdvSceneSwitcher.tempVar.macro.info.actionCount.description"));
AddTempvar(
"elseActionCount",
obs_module_text(
"AdvSceneSwitcher.tempVar.macro.info.elseActionCount"),
obs_module_text(
"AdvSceneSwitcher.tempVar.macro.info.elseActionCount.description"));
AddTempvar(
"paused",
obs_module_text("AdvSceneSwitcher.tempVar.macro.info.paused"),
obs_module_text(
"AdvSceneSwitcher.tempVar.macro.info.paused.description"));
AddTempvar(
"runCount",
obs_module_text("AdvSceneSwitcher.tempVar.macro.info.runCount"),
obs_module_text(
"AdvSceneSwitcher.tempVar.macro.info.runCount.description"));
AddTempvar(
"secondsSinceLastRun",
obs_module_text(
"AdvSceneSwitcher.tempVar.macro.info.secondsSinceLastRun"),
obs_module_text(
"AdvSceneSwitcher.tempVar.macro.info.secondsSinceLastRun.description"));
}
static void populateActionSelection(QComboBox *list) static void populateActionSelection(QComboBox *list)
{ {
static const std::vector<std::pair<MacroActionMacro::Action, std::string>> static const std::vector<std::pair<MacroActionMacro::Action, std::string>>
@@ -425,12 +204,8 @@ static void populateActionSelection(QComboBox *list)
"AdvSceneSwitcher.action.macro.type.togglePause"}, "AdvSceneSwitcher.action.macro.type.togglePause"},
{MacroActionMacro::Action::RESET_COUNTER, {MacroActionMacro::Action::RESET_COUNTER,
"AdvSceneSwitcher.action.macro.type.resetCounter"}, "AdvSceneSwitcher.action.macro.type.resetCounter"},
{MacroActionMacro::Action::NESTED_MACRO, {MacroActionMacro::Action::RUN,
"AdvSceneSwitcher.action.macro.type.nestedMacro"}, "AdvSceneSwitcher.action.macro.type.run"},
{MacroActionMacro::Action::RUN_ACTIONS,
"AdvSceneSwitcher.action.macro.type.runActions"},
{MacroActionMacro::Action::RUN_MACRO,
"AdvSceneSwitcher.action.macro.type.runMacro"},
{MacroActionMacro::Action::STOP, {MacroActionMacro::Action::STOP,
"AdvSceneSwitcher.action.macro.type.stop"}, "AdvSceneSwitcher.action.macro.type.stop"},
{MacroActionMacro::Action::DISABLE_ACTION, {MacroActionMacro::Action::DISABLE_ACTION,
@@ -439,8 +214,6 @@ static void populateActionSelection(QComboBox *list)
"AdvSceneSwitcher.action.macro.type.enableAction"}, "AdvSceneSwitcher.action.macro.type.enableAction"},
{MacroActionMacro::Action::TOGGLE_ACTION, {MacroActionMacro::Action::TOGGLE_ACTION,
"AdvSceneSwitcher.action.macro.type.toggleAction"}, "AdvSceneSwitcher.action.macro.type.toggleAction"},
{MacroActionMacro::Action::GET_INFO,
"AdvSceneSwitcher.action.macro.type.getInfo"},
}; };
for (const auto &[value, name] : actions) { for (const auto &[value, name] : actions) {
@@ -459,7 +232,7 @@ static void populateConditionBehaviorSelection(QComboBox *list)
"AdvSceneSwitcher.action.macro.type.run.conditions.false")); "AdvSceneSwitcher.action.macro.type.run.conditions.false"));
} }
static void populateActionSectionSelection(QComboBox *list) static void populateActionTypeSelection(QComboBox *list)
{ {
list->addItem(obs_module_text( list->addItem(obs_module_text(
"AdvSceneSwitcher.action.macro.type.run.actionType.regular")); "AdvSceneSwitcher.action.macro.type.run.actionType.regular"));
@@ -467,99 +240,49 @@ static void populateActionSectionSelection(QComboBox *list)
"AdvSceneSwitcher.action.macro.type.run.actionType.else")); "AdvSceneSwitcher.action.macro.type.run.actionType.else"));
} }
static void populateActionTypes(QComboBox *list)
{
for (const auto &[id, info] : MacroActionFactory::GetActionTypes()) {
list->addItem(obs_module_text(info._name.c_str()),
QString::fromStdString(id));
}
}
static void populateActionSelectionTypes(QComboBox *list)
{
list->addItem(
obs_module_text(
"AdvSceneSwitcher.action.macro.actionSelectionType.index"),
static_cast<int>(MacroActionMacro::SelectionType::INDEX));
list->addItem(
obs_module_text(
"AdvSceneSwitcher.action.macro.actionSelectionType.label"),
static_cast<int>(MacroActionMacro::SelectionType::LABEL));
list->addItem(
obs_module_text(
"AdvSceneSwitcher.action.macro.actionSelectionType.id"),
static_cast<int>(MacroActionMacro::SelectionType::ID));
}
MacroActionMacroEdit::MacroActionMacroEdit( MacroActionMacroEdit::MacroActionMacroEdit(
QWidget *parent, std::shared_ptr<MacroActionMacro> entryData) QWidget *parent, std::shared_ptr<MacroActionMacro> entryData)
: ResizableWidget(parent), : QWidget(parent),
_actions(new QComboBox()),
_macros(new MacroSelection(parent)), _macros(new MacroSelection(parent)),
_actionSelectionType(new QComboBox(this)),
_actionIndex(new MacroSegmentSelection( _actionIndex(new MacroSegmentSelection(
this, MacroSegmentSelection::Type::ACTION)), this, MacroSegmentSelection::Type::ACTION)),
_label(new VariableLineEdit(this)), _actions(new QComboBox()),
_actionTypes(new FilterComboBox(this)),
_regex(new RegexConfigWidget(this)),
_conditionMacros(new MacroSelection(parent)), _conditionMacros(new MacroSelection(parent)),
_conditionBehaviors(new QComboBox()), _conditionBehaviors(new QComboBox()),
_reevaluateConditionState(new QCheckBox( _reevaluateConditionState(new QCheckBox(
obs_module_text("AdvSceneSwitcher.action.macro.type.run." obs_module_text("AdvSceneSwitcher.action.macro.type.run."
"updateConditionMatchState"))), "updateConditionMatchState"))),
_actionSections(new QComboBox(this)), _actionTypes(new QComboBox()),
_skipWhenPaused(new QCheckBox(obs_module_text( _skipWhenPaused(new QCheckBox(obs_module_text(
"AdvSceneSwitcher.action.macro.type.run.skipWhenPaused"))), "AdvSceneSwitcher.action.macro.type.run.skipWhenPaused"))),
_noConditionsWarning(new QLabel(obs_module_text(
"AdvSceneSwitcher.action.macro.type.runMacro.noConditionsWarning"))),
_runMacroHelp(new HelpIcon(obs_module_text(
"AdvSceneSwitcher.action.macro.type.runMacro.help"))),
_setInputs(new QCheckBox(obs_module_text( _setInputs(new QCheckBox(obs_module_text(
"AdvSceneSwitcher.action.macro.type.run.setInputs"))), "AdvSceneSwitcher.action.macro.type.run.setInputs"))),
_inputs(new MacroInputEdit()), _inputs(new MacroInputEdit()),
_entryLayout(new QHBoxLayout()), _entryLayout(new QHBoxLayout()),
_conditionLayout(new QHBoxLayout()), _conditionLayout(new QHBoxLayout()),
_reevaluateConditionStateLayout(new QHBoxLayout()), _reevaluateConditionStateLayout(new QHBoxLayout()),
_setInputsLayout(new QHBoxLayout()), _setInputsLayout(new QHBoxLayout())
_nestedMacro(new MacroEdit(
this,
QStringList()
<< "AdvSceneSwitcher.action.macro.type.nestedMacro.conditionHelp"
<< "AdvSceneSwitcher.action.macro.type.nestedMacro.actionHelp"
<< "AdvSceneSwitcher.action.macro.type.nestedMacro.elseActionHelp"))
{ {
populateActionSelection(_actions); populateActionSelection(_actions);
populateConditionBehaviorSelection(_conditionBehaviors); populateConditionBehaviorSelection(_conditionBehaviors);
populateActionSectionSelection(_actionSections); populateActionTypeSelection(_actionTypes);
populateActionSelectionTypes(_actionSelectionType);
populateActionTypes(_actionTypes);
_conditionMacros->HideSelectedMacro(); _conditionMacros->HideSelectedMacro();
_conditionMacros->HideGroups();
QWidget::connect(_macros, SIGNAL(currentTextChanged(const QString &)), QWidget::connect(_macros, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(MacroChanged(const QString &))); this, SLOT(MacroChanged(const QString &)));
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this, QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
SLOT(ActionChanged(int))); SLOT(ActionChanged(int)));
QWidget::connect(_actionSelectionType, SIGNAL(currentIndexChanged(int)),
this, SLOT(ActionSelectionTypeChanged(int)));
QWidget::connect(_actionIndex, QWidget::connect(_actionIndex,
SIGNAL(SelectionChanged(const IntVariable &)), this, SIGNAL(SelectionChanged(const IntVariable &)), this,
SLOT(ActionIndexChanged(const IntVariable &))); SLOT(ActionIndexChanged(const IntVariable &)));
QWidget::connect(_label, SIGNAL(editingFinished()), this,
SLOT(LabelChanged()));
QWidget::connect(_actionTypes, SIGNAL(currentIndexChanged(int)), this,
SLOT(ActionTypeChanged(int)));
QWidget::connect(_regex,
SIGNAL(RegexConfigChanged(const RegexConfig &)), this,
SLOT(RegexChanged(const RegexConfig &)));
QWidget::connect(_conditionMacros, QWidget::connect(_conditionMacros,
SIGNAL(currentTextChanged(const QString &)), this, SIGNAL(currentTextChanged(const QString &)), this,
SLOT(ConditionMacroChanged(const QString &))); SLOT(ConditionMacroChanged(const QString &)));
QWidget::connect(_conditionBehaviors, SIGNAL(currentIndexChanged(int)), QWidget::connect(_conditionBehaviors, SIGNAL(currentIndexChanged(int)),
this, SLOT(ConditionBehaviorChanged(int))); this, SLOT(ConditionBehaviorChanged(int)));
QWidget::connect(_actionSections, SIGNAL(currentIndexChanged(int)), QWidget::connect(_actionTypes, SIGNAL(currentIndexChanged(int)), this,
this, SLOT(ActionSectionChanged(int))); SLOT(ActionTypeChanged(int)));
QWidget::connect(_skipWhenPaused, SIGNAL(stateChanged(int)), this, QWidget::connect(_skipWhenPaused, SIGNAL(stateChanged(int)), this,
SLOT(SkipWhenPausedChanged(int))); SLOT(SkipWhenPausedChanged(int)));
QWidget::connect(_setInputs, SIGNAL(stateChanged(int)), this, QWidget::connect(_setInputs, SIGNAL(stateChanged(int)), this,
@@ -587,8 +310,6 @@ MacroActionMacroEdit::MacroActionMacroEdit(
layout->addLayout(_setInputsLayout); layout->addLayout(_setInputsLayout);
layout->addWidget(_inputs); layout->addWidget(_inputs);
layout->addWidget(_skipWhenPaused); layout->addWidget(_skipWhenPaused);
layout->addWidget(_noConditionsWarning);
layout->addWidget(_nestedMacro);
setLayout(layout); setLayout(layout);
_entryData = entryData; _entryData = entryData;
UpdateEntryData(); UpdateEntryData();
@@ -600,12 +321,6 @@ void HighlightMacroSettingsButton(bool enable);
MacroActionMacroEdit::~MacroActionMacroEdit() MacroActionMacroEdit::~MacroActionMacroEdit()
{ {
HighlightMacroSettingsButton(false); HighlightMacroSettingsButton(false);
if (!_entryData) {
return;
}
_entryData->_customWidgetHeight = GetCustomHeight();
_nestedMacro->SetMacro({}); // Save splitter states
} }
void MacroActionMacroEdit::UpdateEntryData() void MacroActionMacroEdit::UpdateEntryData()
@@ -613,42 +328,24 @@ void MacroActionMacroEdit::UpdateEntryData()
if (!_entryData) { if (!_entryData) {
return; return;
} }
_actions->setCurrentIndex( _actions->setCurrentIndex(
_actions->findData(static_cast<int>(_entryData->GetAction()))); _actions->findData(static_cast<int>(_entryData->_action)));
_actionSelectionType->setCurrentIndex(_actionSelectionType->findData(
static_cast<int>(_entryData->_actionSelectionType)));
_actionIndex->SetValue(_entryData->_actionIndex); _actionIndex->SetValue(_entryData->_actionIndex);
_actionIndex->SetMacro(_entryData->_macro.GetMacro()); _actionIndex->SetMacro(_entryData->_macro.GetMacro());
_label->setText(_entryData->_label);
_actionTypes->setCurrentIndex(_actionTypes->findData(
QString::fromStdString(_entryData->_actionId)));
_regex->SetRegexConfig(_entryData->_regex);
_macros->SetCurrentMacro(_entryData->_macro); _macros->SetCurrentMacro(_entryData->_macro);
_conditionMacros->SetCurrentMacro(_entryData->_runOptions.macro); _conditionMacros->SetCurrentMacro(_entryData->_runOptions.macro);
_conditionBehaviors->setCurrentIndex( _conditionBehaviors->setCurrentIndex(
static_cast<int>(_entryData->_runOptions.logic)); static_cast<int>(_entryData->_runOptions.logic));
_reevaluateConditionState->setChecked( _reevaluateConditionState->setChecked(
_entryData->_runOptions.reevaluateConditionState); _entryData->_runOptions.reevaluateConditionState);
_actionSections->setCurrentIndex( _actionTypes->setCurrentIndex(
_entryData->_runOptions.runElseActions ? 1 : 0); _entryData->_runOptions.runElseActions ? 1 : 0);
_skipWhenPaused->setChecked(_entryData->_runOptions.skipWhenPaused); _skipWhenPaused->setChecked(_entryData->_runOptions.skipWhenPaused);
_setInputs->setChecked(_entryData->_runOptions.setInputs); _setInputs->setChecked(_entryData->_runOptions.setInputs);
SetupMacroInput(_entryData->_macro.GetMacro().get()); SetupMacroInput(_entryData->_macro.GetMacro().get());
const auto &macro = _entryData->_nestedMacro;
_nestedMacro->SetMacro(macro);
SetWidgetVisibility(); SetWidgetVisibility();
} }
QWidget *MacroActionMacroEdit::Create(QWidget *parent,
std::shared_ptr<MacroAction> action)
{
return new MacroActionMacroEdit(
parent, std::dynamic_pointer_cast<MacroActionMacro>(action));
}
void MacroActionMacroEdit::MacroChanged(const QString &text) void MacroActionMacroEdit::MacroChanged(const QString &text)
{ {
GUARD_LOADING_AND_LOCK(); GUARD_LOADING_AND_LOCK();
@@ -664,17 +361,8 @@ void MacroActionMacroEdit::MacroChanged(const QString &text)
void MacroActionMacroEdit::ActionChanged(int idx) void MacroActionMacroEdit::ActionChanged(int idx)
{ {
GUARD_LOADING_AND_LOCK(); GUARD_LOADING_AND_LOCK();
_entryData->SetAction(static_cast<MacroActionMacro::Action>( _entryData->_action = static_cast<MacroActionMacro::Action>(
_actions->itemData(idx).toInt())); _actions->itemData(idx).toInt());
SetWidgetVisibility();
}
void MacroActionMacroEdit::ActionSelectionTypeChanged(int idx)
{
GUARD_LOADING_AND_LOCK();
_entryData->_actionSelectionType =
static_cast<MacroActionMacro::SelectionType>(
_actionSelectionType->itemData(idx).toInt());
SetWidgetVisibility(); SetWidgetVisibility();
} }
@@ -684,25 +372,6 @@ void MacroActionMacroEdit::ActionIndexChanged(const IntVariable &value)
_entryData->_actionIndex = value; _entryData->_actionIndex = value;
} }
void MacroActionMacroEdit::LabelChanged()
{
GUARD_LOADING_AND_LOCK();
_entryData->_label = _label->text().toStdString();
}
void MacroActionMacroEdit::ActionTypeChanged(int idx)
{
GUARD_LOADING_AND_LOCK();
_entryData->_actionId =
_actionTypes->itemData(idx).toString().toStdString();
}
void MacroActionMacroEdit::RegexChanged(const RegexConfig &regex)
{
GUARD_LOADING_AND_LOCK();
_entryData->_regex = regex;
}
void MacroActionMacroEdit::ConditionMacroChanged(const QString &text) void MacroActionMacroEdit::ConditionMacroChanged(const QString &text)
{ {
GUARD_LOADING_AND_LOCK(); GUARD_LOADING_AND_LOCK();
@@ -724,13 +393,10 @@ void MacroActionMacroEdit::ReevaluateConditionStateChanged(int value)
SetWidgetVisibility(); SetWidgetVisibility();
} }
void MacroActionMacroEdit::ActionSectionChanged(int useElse) void MacroActionMacroEdit::ActionTypeChanged(int value)
{ {
GUARD_LOADING_AND_LOCK(); GUARD_LOADING_AND_LOCK();
_entryData->_runOptions.runElseActions = useElse; _entryData->_runOptions.runElseActions = value;
_entryData->_useElseSection = useElse;
_actionIndex->SetType(useElse ? MacroSegmentSelection::Type::ELSE_ACTION
: MacroSegmentSelection::Type::ACTION);
} }
void MacroActionMacroEdit::SkipWhenPausedChanged(int value) void MacroActionMacroEdit::SkipWhenPausedChanged(int value)
@@ -757,14 +423,9 @@ void MacroActionMacroEdit::InputsChanged(const StringList &inputs)
void MacroActionMacroEdit::SetWidgetVisibility() void MacroActionMacroEdit::SetWidgetVisibility()
{ {
_entryLayout->removeWidget(_actions); _entryLayout->removeWidget(_actions);
_entryLayout->removeWidget(_runMacroHelp);
_entryLayout->removeWidget(_actionIndex); _entryLayout->removeWidget(_actionIndex);
_entryLayout->removeWidget(_macros); _entryLayout->removeWidget(_macros);
_entryLayout->removeWidget(_actionSections);
_entryLayout->removeWidget(_label);
_entryLayout->removeWidget(_regex);
_entryLayout->removeWidget(_actionTypes); _entryLayout->removeWidget(_actionTypes);
_entryLayout->removeWidget(_actionSelectionType);
_conditionLayout->removeWidget(_conditionBehaviors); _conditionLayout->removeWidget(_conditionBehaviors);
_conditionLayout->removeWidget(_conditionMacros); _conditionLayout->removeWidget(_conditionMacros);
@@ -773,47 +434,20 @@ void MacroActionMacroEdit::SetWidgetVisibility()
const std::unordered_map<std::string, QWidget *> placeholders = { const std::unordered_map<std::string, QWidget *> placeholders = {
{"{{actions}}", _actions}, {"{{actions}}", _actions},
{"{{runMacroHelp}}", _runMacroHelp},
{"{{actionIndex}}", _actionIndex}, {"{{actionIndex}}", _actionIndex},
{"{{macros}}", _macros}, {"{{macros}}", _macros},
{"{{actionSections}}", _actionSections}, {"{{actionTypes}}", _actionTypes},
{"{{conditionBehaviors}}", _conditionBehaviors}, {"{{conditionBehaviors}}", _conditionBehaviors},
{"{{conditionMacros}}", _conditionMacros}, {"{{conditionMacros}}", _conditionMacros},
{"{{actionSelectionType}}", _actionSelectionType},
{"{{label}}", _label},
{"{{regex}}", _regex},
{"{{actionTypes}}", _actionTypes},
}; };
const auto action = _entryData->GetAction(); PlaceWidgets(
const char *layoutText = ""; obs_module_text(
switch (action) { _entryData->_action == MacroActionMacro::Action::RUN
case MacroActionMacro::Action::PAUSE: ? "AdvSceneSwitcher.action.macro.entry.run"
case MacroActionMacro::Action::UNPAUSE: : "AdvSceneSwitcher.action.macro.entry.other"),
case MacroActionMacro::Action::TOGGLE_PAUSE: _entryLayout, placeholders);
case MacroActionMacro::Action::RESET_COUNTER:
case MacroActionMacro::Action::STOP:
case MacroActionMacro::Action::NESTED_MACRO:
case MacroActionMacro::Action::GET_INFO:
layoutText = "AdvSceneSwitcher.action.macro.layout.other";
break;
case MacroActionMacro::Action::RUN_MACRO:
layoutText = "AdvSceneSwitcher.action.macro.layout.runMacro";
break;
case MacroActionMacro::Action::RUN_ACTIONS:
layoutText = "AdvSceneSwitcher.action.macro.layout.run";
break;
case MacroActionMacro::Action::DISABLE_ACTION:
case MacroActionMacro::Action::ENABLE_ACTION:
case MacroActionMacro::Action::TOGGLE_ACTION:
layoutText = "AdvSceneSwitcher.action.macro.layout.actionState";
break;
default:
break;
}
PlaceWidgets(obs_module_text(layoutText), _entryLayout, placeholders);
if (_entryData->_runOptions.logic == if (_entryData->_runOptions.logic ==
MacroActionMacro::RunOptions::Logic::IGNORE_CONDITIONS) { MacroActionMacro::RunOptions::Logic::IGNORE_CONDITIONS) {
@@ -822,82 +456,47 @@ void MacroActionMacroEdit::SetWidgetVisibility()
} else { } else {
PlaceWidgets( PlaceWidgets(
obs_module_text( obs_module_text(
"AdvSceneSwitcher.action.macro.layout.run.condition"), "AdvSceneSwitcher.action.macro.entry.run.condition"),
_conditionLayout, placeholders); _conditionLayout, placeholders);
} }
if (action == MacroActionMacro::Action::RUN_ACTIONS || if (_entryData->_action == MacroActionMacro::Action::RUN ||
action == MacroActionMacro::Action::STOP || _entryData->_action == MacroActionMacro::Action::STOP) {
action == MacroActionMacro::Action::RUN_MACRO) {
_macros->HideSelectedMacro(); _macros->HideSelectedMacro();
} else { } else {
_macros->ShowAllMacros(); _macros->ShowAllMacros();
} }
const auto actionSelectionType = _entryData->_actionSelectionType;
const bool isModifyingActionState = const bool isModifyingActionState =
action == MacroActionMacro::Action::DISABLE_ACTION || _entryData->_action ==
action == MacroActionMacro::Action::ENABLE_ACTION || MacroActionMacro::Action::DISABLE_ACTION ||
action == MacroActionMacro::Action::TOGGLE_ACTION; _entryData->_action ==
_actionSelectionType->setVisible(isModifyingActionState); MacroActionMacro::Action::ENABLE_ACTION ||
_actionIndex->setVisible( _entryData->_action == MacroActionMacro::Action::TOGGLE_ACTION;
isModifyingActionState && _actionIndex->setVisible(isModifyingActionState);
actionSelectionType == MacroActionMacro::SelectionType::INDEX);
_label->setVisible(isModifyingActionState &&
actionSelectionType ==
MacroActionMacro::SelectionType::LABEL);
_regex->setVisible(isModifyingActionState &&
actionSelectionType ==
MacroActionMacro::SelectionType::LABEL);
_actionTypes->setVisible(isModifyingActionState &&
actionSelectionType ==
MacroActionMacro::SelectionType::ID);
SetLayoutVisible(_conditionLayout, SetLayoutVisible(_conditionLayout,
action == MacroActionMacro::Action::RUN_ACTIONS); _entryData->_action == MacroActionMacro::Action::RUN);
const bool needsAdditionalConditionWidgets = const bool needsAdditionalConditionWidgets =
action == MacroActionMacro::Action::RUN_ACTIONS && _entryData->_action == MacroActionMacro::Action::RUN &&
_entryData->_runOptions.logic != _entryData->_runOptions.logic !=
MacroActionMacro::RunOptions::Logic::IGNORE_CONDITIONS; MacroActionMacro::RunOptions::Logic::IGNORE_CONDITIONS;
_conditionMacros->setVisible(needsAdditionalConditionWidgets); _conditionMacros->setVisible(needsAdditionalConditionWidgets);
SetLayoutVisible(_reevaluateConditionStateLayout, SetLayoutVisible(_reevaluateConditionStateLayout,
needsAdditionalConditionWidgets); needsAdditionalConditionWidgets);
SetLayoutVisible(_setInputsLayout, SetLayoutVisible(_setInputsLayout,
action == MacroActionMacro::Action::RUN_ACTIONS); _entryData->_action == MacroActionMacro::Action::RUN);
_inputs->setVisible(action == MacroActionMacro::Action::RUN_ACTIONS && _inputs->setVisible(_entryData->_action ==
MacroActionMacro::Action::RUN &&
_entryData->_runOptions.setInputs); _entryData->_runOptions.setInputs);
HighlightMacroSettingsButton( HighlightMacroSettingsButton(_entryData->_action ==
action == MacroActionMacro::Action::RUN_ACTIONS && MacroActionMacro::Action::RUN &&
_entryData->_runOptions.setInputs && _entryData->_runOptions.setInputs &&
!_inputs->HasInputsToSet()); !_inputs->HasInputsToSet());
_actionSections->setVisible( _actionTypes->setVisible(_entryData->_action ==
action == MacroActionMacro::Action::RUN_ACTIONS || MacroActionMacro::Action::RUN);
isModifyingActionState); _skipWhenPaused->setVisible(_entryData->_action ==
_skipWhenPaused->setVisible( MacroActionMacro::Action::RUN);
action == MacroActionMacro::Action::RUN_ACTIONS ||
action == MacroActionMacro::Action::RUN_MACRO);
if (action == MacroActionMacro::Action::RUN_MACRO) {
auto macro = _entryData->_macro.GetMacro();
_noConditionsWarning->setVisible(!macro ||
macro->Conditions().empty());
} else {
_noConditionsWarning->setVisible(false);
}
_runMacroHelp->setVisible(action ==
MacroActionMacro::Action::RUN_MACRO);
_nestedMacro->setVisible(action ==
MacroActionMacro::Action::NESTED_MACRO);
_macros->setVisible(action != MacroActionMacro::Action::NESTED_MACRO);
SetResizingEnabled(action == MacroActionMacro::Action::NESTED_MACRO);
if (_nestedMacro->IsEmpty()) {
_nestedMacro->ShowAllMacroSections();
// TODO: find a better solution than setting a fixed height
_entryData->_customWidgetHeight = 600;
}
SetCustomHeight(_entryData->_customWidgetHeight);
adjustSize(); adjustSize();
updateGeometry(); updateGeometry();

View File

@@ -1,17 +1,11 @@
#pragma once #pragma once
#include "macro-action-edit.hpp" #include "macro-action-edit.hpp"
#include "macro.hpp"
#include "macro-edit.hpp"
#include "macro-input.hpp" #include "macro-input.hpp"
#include "macro-selection.hpp" #include "macro-selection.hpp"
#include "macro-segment-selection.hpp" #include "macro-segment-selection.hpp"
#include "regex-config.hpp"
#include "resizable-widget.hpp"
#include "variable-line-edit.hpp"
#include <QCheckBox> #include <QCheckBox>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QLabel>
namespace advss { namespace advss {
@@ -50,44 +44,25 @@ public:
PAUSE, PAUSE,
UNPAUSE, UNPAUSE,
RESET_COUNTER, RESET_COUNTER,
RUN_ACTIONS, RUN,
STOP, STOP,
DISABLE_ACTION, DISABLE_ACTION,
ENABLE_ACTION, ENABLE_ACTION,
TOGGLE_ACTION, TOGGLE_ACTION,
TOGGLE_PAUSE, TOGGLE_PAUSE,
NESTED_MACRO,
GET_INFO,
RUN_MACRO,
}; };
Action _action = Action::RUN;
void SetAction(Action);
Action GetAction() const { return _action; }
enum class SelectionType { INDEX, LABEL, ID };
SelectionType _actionSelectionType = SelectionType::INDEX;
bool _useElseSection = false;
IntVariable _actionIndex = 1; IntVariable _actionIndex = 1;
StringVariable _label = "Custom label";
std::string _actionId;
RegexConfig _regex;
RunOptions _runOptions = {}; RunOptions _runOptions = {};
std::shared_ptr<Macro> _nestedMacro = std::make_shared<Macro>();
int _customWidgetHeight = 0;
private: private:
void SetupTempVars();
void RunActions(Macro *actionMacro) const; void RunActions(Macro *actionMacro) const;
void AdjustActionState(Macro *) const;
Action _action = Action::NESTED_MACRO;
static bool _registered; static bool _registered;
static const std::string id; static const std::string id;
}; };
class MacroActionMacroEdit final : public ResizableWidget { class MacroActionMacroEdit final : public QWidget {
Q_OBJECT Q_OBJECT
public: public:
@@ -96,20 +71,22 @@ public:
std::shared_ptr<MacroActionMacro> entryData = nullptr); std::shared_ptr<MacroActionMacro> entryData = nullptr);
~MacroActionMacroEdit(); ~MacroActionMacroEdit();
void UpdateEntryData(); void UpdateEntryData();
static QWidget *Create(QWidget *, std::shared_ptr<MacroAction>); static QWidget *Create(QWidget *parent,
std::shared_ptr<MacroAction> action)
{
return new MacroActionMacroEdit(
parent,
std::dynamic_pointer_cast<MacroActionMacro>(action));
}
private slots: private slots:
void MacroChanged(const QString &text); void MacroChanged(const QString &text);
void ActionChanged(int value); void ActionChanged(int value);
void ActionSelectionTypeChanged(int value);
void ActionIndexChanged(const IntVariable &value); void ActionIndexChanged(const IntVariable &value);
void LabelChanged();
void ActionTypeChanged(int value);
void RegexChanged(const RegexConfig &);
void ConditionMacroChanged(const QString &text); void ConditionMacroChanged(const QString &text);
void ConditionBehaviorChanged(int value); void ConditionBehaviorChanged(int value);
void ReevaluateConditionStateChanged(int value); void ReevaluateConditionStateChanged(int value);
void ActionSectionChanged(int value); void ActionTypeChanged(int value);
void SkipWhenPausedChanged(int value); void SkipWhenPausedChanged(int value);
void SetInputsChanged(int value); void SetInputsChanged(int value);
void InputsChanged(const StringList &); void InputsChanged(const StringList &);
@@ -121,27 +98,20 @@ private:
void SetWidgetVisibility(); void SetWidgetVisibility();
void SetupMacroInput(Macro *) const; void SetupMacroInput(Macro *) const;
QComboBox *_actions;
MacroSelection *_macros; MacroSelection *_macros;
QComboBox *_actionSelectionType;
MacroSegmentSelection *_actionIndex; MacroSegmentSelection *_actionIndex;
VariableLineEdit *_label; QComboBox *_actions;
FilterComboBox *_actionTypes;
RegexConfigWidget *_regex;
MacroSelection *_conditionMacros; MacroSelection *_conditionMacros;
QComboBox *_conditionBehaviors; QComboBox *_conditionBehaviors;
QCheckBox *_reevaluateConditionState; QCheckBox *_reevaluateConditionState;
QComboBox *_actionSections; QComboBox *_actionTypes;
QCheckBox *_skipWhenPaused; QCheckBox *_skipWhenPaused;
QLabel *_noConditionsWarning;
HelpIcon *_runMacroHelp;
QCheckBox *_setInputs; QCheckBox *_setInputs;
MacroInputEdit *_inputs; MacroInputEdit *_inputs;
QHBoxLayout *_entryLayout; QHBoxLayout *_entryLayout;
QHBoxLayout *_conditionLayout; QHBoxLayout *_conditionLayout;
QHBoxLayout *_reevaluateConditionStateLayout; QHBoxLayout *_reevaluateConditionStateLayout;
QHBoxLayout *_setInputsLayout; QHBoxLayout *_setInputsLayout;
MacroEdit *_nestedMacro;
std::shared_ptr<MacroActionMacro> _entryData; std::shared_ptr<MacroActionMacro> _entryData;
bool _loading = true; bool _loading = true;

View File

@@ -1,10 +1,9 @@
#include "macro-action-variable.hpp" #include "macro-action-variable.hpp"
#include "help-icon.hpp" #include "advanced-scene-switcher.hpp"
#include "json-helpers.hpp" #include "json-helpers.hpp"
#include "layout-helpers.hpp" #include "layout-helpers.hpp"
#include "macro-condition-edit.hpp"
#include "macro-signals.hpp"
#include "math-helpers.hpp" #include "math-helpers.hpp"
#include "macro-condition-edit.hpp"
#include "macro.hpp" #include "macro.hpp"
#include "non-modal-dialog.hpp" #include "non-modal-dialog.hpp"
#include "source-helpers.hpp" #include "source-helpers.hpp"
@@ -17,15 +16,6 @@ namespace advss {
const std::string MacroActionVariable::id = "variable"; const std::string MacroActionVariable::id = "variable";
std::vector<TempVariableRef> MacroActionVariable::GetTempVarRefs() const
{
auto refs = MacroSegment::GetTempVarRefs();
if (_tempVar.HasValidID()) {
refs.push_back(_tempVar);
}
return refs;
}
bool MacroActionVariable::_registered = MacroActionFactory::Register( bool MacroActionVariable::_registered = MacroActionFactory::Register(
MacroActionVariable::id, MacroActionVariable::id,
{MacroActionVariable::Create, MacroActionVariableEdit::Create, {MacroActionVariable::Create, MacroActionVariableEdit::Create,
@@ -228,43 +218,6 @@ void MacroActionVariable::GenerateRandomNumber(Variable *var)
} }
} }
void MacroActionVariable::PickRandomValue(Variable *var)
{
static std::random_device rd;
static std::mt19937 gen(rd());
static const uint8_t maxIter = 255;
if (_randomValues.isEmpty()) {
return;
}
if (_randomValues.size() == 1) {
const auto &value = _randomValues.at(0);
var->SetValue(value);
_lastRandomValue = value;
}
std::uniform_int_distribution<int> dis(0, _randomValues.size() - 1);
StringVariable value = _randomValues.at(dis(gen));
uint8_t iter = 0;
for (; !_allowRepeatValues && iter < maxIter &&
_lastRandomValue.has_value() &&
std::string(value) == _lastRandomValue.value();
iter++) {
value = _randomValues.at(dis(gen));
}
if (iter == maxIter) {
blog(LOG_INFO,
"giving up picking non-repeat random value after %d tries",
maxIter);
}
var->SetValue(value);
_lastRandomValue = value;
}
struct AskForInputParams { struct AskForInputParams {
AskForInputParams(const QString &prompt_, const QString &placeholder_) AskForInputParams(const QString &prompt_, const QString &placeholder_)
: prompt(prompt_), : prompt(prompt_),
@@ -332,14 +285,6 @@ bool MacroActionVariable::PerformAction()
case Action::APPEND: case Action::APPEND:
apppend(*var, _strValue); apppend(*var, _strValue);
break; break;
case Action::COPY_VAR: {
auto var2 = _variable2.lock();
if (!var2) {
return true;
}
var->SetValue(var2->Value());
break;
}
case Action::APPEND_VAR: { case Action::APPEND_VAR: {
auto var2 = _variable2.lock(); auto var2 = _variable2.lock();
if (!var2) { if (!var2) {
@@ -447,19 +392,7 @@ bool MacroActionVariable::PerformAction()
if (!value.has_value()) { if (!value.has_value()) {
return true; return true;
} }
var->SetValue(*value);
if (!_jsonQueryExtractSingle) {
var->SetValue(*value);
return true;
}
auto extracted = ExtractSingleJsonArrayElement(*value);
if (extracted.has_value()) {
var->SetValue(*extracted);
} else {
var->SetValue(*value);
}
return true; return true;
} }
case Action::ARRAY_JSON: { case Action::ARRAY_JSON: {
@@ -516,9 +449,6 @@ bool MacroActionVariable::PerformAction()
case Action::RANDOM_NUMBER: case Action::RANDOM_NUMBER:
GenerateRandomNumber(var.get()); GenerateRandomNumber(var.get());
return true; return true;
case Action::RANDOM_LIST_VALUE:
PickRandomValue(var.get());
return true;
} }
return true; return true;
@@ -550,7 +480,7 @@ bool MacroActionVariable::Save(obs_data_t *obj) const
_inputPlaceholder.Save(obj, "inputPlaceholder"); _inputPlaceholder.Save(obj, "inputPlaceholder");
_envVariableName.Save(obj, "environmentVariableName"); _envVariableName.Save(obj, "environmentVariableName");
_scene.Save(obj); _scene.Save(obj);
_tempVar.Save(obj, GetMacro()); _tempVar.Save(obj);
_sceneItemIndex.Save(obj, "sceneItemIndex"); _sceneItemIndex.Save(obj, "sceneItemIndex");
obs_data_set_int(obj, "direction", static_cast<int>(_direction)); obs_data_set_int(obj, "direction", static_cast<int>(_direction));
_stringLength.Save(obj, "stringLength"); _stringLength.Save(obj, "stringLength");
@@ -559,12 +489,8 @@ bool MacroActionVariable::Save(obs_data_t *obj) const
_randomNumberStart.Save(obj, "randomNumberStart"); _randomNumberStart.Save(obj, "randomNumberStart");
_randomNumberEnd.Save(obj, "randomNumberEnd"); _randomNumberEnd.Save(obj, "randomNumberEnd");
obs_data_set_bool(obj, "generateInteger", _generateInteger); obs_data_set_bool(obj, "generateInteger", _generateInteger);
_randomValues.Save(obj, "randomValues", "value");
obs_data_set_bool(obj, "allowRepeatValues", _allowRepeatValues);
_jsonQuery.Save(obj, "jsonQuery"); _jsonQuery.Save(obj, "jsonQuery");
_jsonIndex.Save(obj, "jsonIndex"); _jsonIndex.Save(obj, "jsonIndex");
obs_data_set_bool(obj, "jsonQueryExtractSingle",
_jsonQueryExtractSingle);
obs_data_set_int(obj, "version", 1); obs_data_set_int(obj, "version", 1);
@@ -621,12 +547,8 @@ bool MacroActionVariable::Load(obs_data_t *obj)
_randomNumberStart.Load(obj, "randomNumberStart"); _randomNumberStart.Load(obj, "randomNumberStart");
_randomNumberEnd.Load(obj, "randomNumberEnd"); _randomNumberEnd.Load(obj, "randomNumberEnd");
_generateInteger = obs_data_get_bool(obj, "generateInteger"); _generateInteger = obs_data_get_bool(obj, "generateInteger");
_randomValues.Load(obj, "randomValues", "value");
_allowRepeatValues = obs_data_get_bool(obj, "allowRepeatValues");
_jsonQuery.Load(obj, "jsonQuery"); _jsonQuery.Load(obj, "jsonQuery");
_jsonIndex.Load(obj, "jsonIndex"); _jsonIndex.Load(obj, "jsonIndex");
_jsonQueryExtractSingle =
obs_data_get_bool(obj, "jsonQueryExtractSingle");
return true; return true;
} }
@@ -747,8 +669,6 @@ static inline void populateActionSelection(QComboBox *list)
actions = { actions = {
{MacroActionVariable::Action::SET_VALUE, {MacroActionVariable::Action::SET_VALUE,
"AdvSceneSwitcher.action.variable.type.set"}, "AdvSceneSwitcher.action.variable.type.set"},
{MacroActionVariable::Action::COPY_VAR,
"AdvSceneSwitcher.action.variable.type.copy"},
{MacroActionVariable::Action::APPEND, {MacroActionVariable::Action::APPEND,
"AdvSceneSwitcher.action.variable.type.append"}, "AdvSceneSwitcher.action.variable.type.append"},
{MacroActionVariable::Action::PAD, {MacroActionVariable::Action::PAD,
@@ -793,8 +713,6 @@ static inline void populateActionSelection(QComboBox *list)
"AdvSceneSwitcher.action.variable.type.roundToInt"}, "AdvSceneSwitcher.action.variable.type.roundToInt"},
{MacroActionVariable::Action::RANDOM_NUMBER, {MacroActionVariable::Action::RANDOM_NUMBER,
"AdvSceneSwitcher.action.variable.type.randomNumber"}, "AdvSceneSwitcher.action.variable.type.randomNumber"},
{MacroActionVariable::Action::RANDOM_LIST_VALUE,
"AdvSceneSwitcher.action.variable.type.randomListValue"},
{true, ""}, // Separator {true, ""}, // Separator
{MacroActionVariable::Action::USER_INPUT, {MacroActionVariable::Action::USER_INPUT,
@@ -872,10 +790,11 @@ MacroActionVariableEdit::MacroActionVariableEdit(
_segmentValueStatus(new QLabel()), _segmentValueStatus(new QLabel()),
_segmentValue(new ResizingPlainTextEdit(this, 10, 1, 1)), _segmentValue(new ResizingPlainTextEdit(this, 10, 1, 1)),
_substringLayout(new QVBoxLayout()), _substringLayout(new QVBoxLayout()),
_subStringControlsLayout(new QHBoxLayout()), _subStringIndexEntryLayout(new QHBoxLayout()),
_subStringRegexEntryLayout(new QHBoxLayout()),
_subStringStart(new VariableSpinBox(this)), _subStringStart(new VariableSpinBox(this)),
_subStringSize(new VariableSpinBox(this)), _subStringSize(new VariableSpinBox(this)),
_subStringRegex(new RegexConfigWidget(parent)), _substringRegex(new RegexConfigWidget(parent)),
_regexPattern(new ResizingPlainTextEdit(this, 10, 1, 1)), _regexPattern(new ResizingPlainTextEdit(this, 10, 1, 1)),
_regexMatchIdx(new VariableSpinBox(this)), _regexMatchIdx(new VariableSpinBox(this)),
_findReplaceLayout(new QHBoxLayout()), _findReplaceLayout(new QHBoxLayout()),
@@ -907,28 +826,10 @@ MacroActionVariableEdit::MacroActionVariableEdit(
obs_module_text( obs_module_text(
"AdvSceneSwitcher.action.variable.generateInteger"), "AdvSceneSwitcher.action.variable.generateInteger"),
this)), this)),
_randomNumberLayout(new QVBoxLayout()), _randomLayout(new QVBoxLayout()),
_randomValues(new StringListEdit(this)),
_allowRepeatValues(new QCheckBox(
obs_module_text(
"AdvSceneSwitcher.action.variable.type.allowRepeat"),
this)),
_randomValueLayout(new QVBoxLayout()),
_jsonQuery(new VariableLineEdit(this)), _jsonQuery(new VariableLineEdit(this)),
_jsonQueryHelp(new HelpIcon( _jsonQueryHelp(new QLabel(this)),
obs_module_text(
"AdvSceneSwitcher.action.variable.type.queryJson.info"),
this)),
_jsonIndex(new VariableSpinBox(this)), _jsonIndex(new VariableSpinBox(this)),
_jsonExtractSingle(new QCheckBox(
obs_module_text(
"AdvSceneSwitcher.action.variable.type.queryJson.extractSingle"),
this)),
_jsonExtractSingleHelp(new HelpIcon(
obs_module_text(
"AdvSceneSwitcher.action.variable.type.queryJson.extractSingle.info"),
this)),
_jsonQueryLayout(new QVBoxLayout()),
_entryLayout(new QHBoxLayout()) _entryLayout(new QHBoxLayout())
{ {
_numValue->setMinimum(-9999999999); _numValue->setMinimum(-9999999999);
@@ -958,13 +859,15 @@ MacroActionVariableEdit::MacroActionVariableEdit(
_randomNumberStart->setMaximum(9999999999); _randomNumberStart->setMaximum(9999999999);
_randomNumberEnd->setMinimum(-9999999999); _randomNumberEnd->setMinimum(-9999999999);
_randomNumberEnd->setMaximum(9999999999); _randomNumberEnd->setMaximum(9999999999);
_randomValues->SetMaxStringSize(99999999); const QString path = GetThemeTypeName() == "Light"
? ":/res/images/help.svg"
: ":/res/images/help_light.svg";
const QIcon icon(path);
const QPixmap pixmap = icon.pixmap(QSize(16, 16));
_jsonQueryHelp->setPixmap(pixmap);
_jsonQueryHelp->setToolTip(obs_module_text(
"AdvSceneSwitcher.action.variable.type.queryJson.info"));
_jsonIndex->setMaximum(999); _jsonIndex->setMaximum(999);
auto jsonExtractSingleLayout = new QHBoxLayout();
jsonExtractSingleLayout->addWidget(_jsonExtractSingle);
jsonExtractSingleLayout->addWidget(_jsonExtractSingleHelp);
jsonExtractSingleLayout->addStretch();
_jsonQueryLayout->addLayout(jsonExtractSingleLayout);
QWidget::connect(_variables, SIGNAL(SelectionChanged(const QString &)), QWidget::connect(_variables, SIGNAL(SelectionChanged(const QString &)),
this, SLOT(VariableChanged(const QString &))); this, SLOT(VariableChanged(const QString &)));
@@ -981,8 +884,7 @@ MacroActionVariableEdit::MacroActionVariableEdit(
QWidget::connect(_segmentIdx, QWidget::connect(_segmentIdx,
SIGNAL(SelectionChanged(const IntVariable &)), this, SIGNAL(SelectionChanged(const IntVariable &)), this,
SLOT(SegmentIndexChanged(const IntVariable &))); SLOT(SegmentIndexChanged(const IntVariable &)));
QWidget::connect(MacroSignalManager::Instance(), QWidget::connect(window(), SIGNAL(MacroSegmentOrderChanged()), this,
SIGNAL(SegmentOrderChanged()), this,
SLOT(MacroSegmentOrderChanged())); SLOT(MacroSegmentOrderChanged()));
QWidget::connect( QWidget::connect(
_subStringStart, _subStringStart,
@@ -992,7 +894,7 @@ MacroActionVariableEdit::MacroActionVariableEdit(
_subStringSize, _subStringSize,
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)), SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
this, SLOT(SubStringSizeChanged(const NumberVariable<int> &))); this, SLOT(SubStringSizeChanged(const NumberVariable<int> &)));
QWidget::connect(_subStringRegex, QWidget::connect(_substringRegex,
SIGNAL(RegexConfigChanged(const RegexConfig &)), this, SIGNAL(RegexConfigChanged(const RegexConfig &)), this,
SLOT(SubStringRegexChanged(const RegexConfig &))); SLOT(SubStringRegexChanged(const RegexConfig &)));
QWidget::connect(_regexPattern, SIGNAL(textChanged()), this, QWidget::connect(_regexPattern, SIGNAL(textChanged()), this,
@@ -1052,19 +954,12 @@ MacroActionVariableEdit::MacroActionVariableEdit(
SLOT(RandomNumberEndChanged(const NumberVariable<double> &))); SLOT(RandomNumberEndChanged(const NumberVariable<double> &)));
QWidget::connect(_generateInteger, SIGNAL(stateChanged(int)), this, QWidget::connect(_generateInteger, SIGNAL(stateChanged(int)), this,
SLOT(GenerateIntegerChanged(int))); SLOT(GenerateIntegerChanged(int)));
QWidget::connect(_randomValues,
SIGNAL(StringListChanged(const StringList &)), this,
SLOT(RandomValueListChanged(const StringList &)));
QWidget::connect(_allowRepeatValues, SIGNAL(stateChanged(int)), this,
SLOT(AllowRepeatValuesChanged(int)));
QWidget::connect(_jsonQuery, SIGNAL(editingFinished()), this, QWidget::connect(_jsonQuery, SIGNAL(editingFinished()), this,
SLOT(JsonQueryChanged())); SLOT(JsonQueryChanged()));
QWidget::connect( QWidget::connect(
_jsonIndex, _jsonIndex,
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)), SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
this, SLOT(JsonIndexChanged(const NumberVariable<int> &))); this, SLOT(JsonIndexChanged(const NumberVariable<int> &)));
QWidget::connect(_jsonExtractSingle, SIGNAL(stateChanged(int)), this,
SLOT(JsonQueryExtractSingleChanged(int)));
const std::unordered_map<std::string, QWidget *> widgetPlaceholders = { const std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{variables}}", _variables}, {"{{variables}}", _variables},
@@ -1073,6 +968,9 @@ MacroActionVariableEdit::MacroActionVariableEdit(
{"{{strValue}}", _strValue}, {"{{strValue}}", _strValue},
{"{{numValue}}", _numValue}, {"{{numValue}}", _numValue},
{"{{segmentIndex}}", _segmentIdx}, {"{{segmentIndex}}", _segmentIdx},
{"{{subStringStart}}", _subStringStart},
{"{{subStringSize}}", _subStringSize},
{"{{regexMatchIdx}}", _regexMatchIdx},
{"{{findRegex}}", _findRegex}, {"{{findRegex}}", _findRegex},
{"{{findStr}}", _findStr}, {"{{findStr}}", _findStr},
{"{{replaceStr}}", _replaceStr}, {"{{replaceStr}}", _replaceStr},
@@ -1104,7 +1002,12 @@ MacroActionVariableEdit::MacroActionVariableEdit(
PlaceWidgets( PlaceWidgets(
obs_module_text( obs_module_text(
"AdvSceneSwitcher.action.variable.layout.substringIndex"), "AdvSceneSwitcher.action.variable.layout.substringIndex"),
_subStringControlsLayout, widgetPlaceholders); _subStringIndexEntryLayout, widgetPlaceholders);
PlaceWidgets(
obs_module_text(
"AdvSceneSwitcher.action.variable.layout.substringRegex"),
_subStringRegexEntryLayout, widgetPlaceholders);
PlaceWidgets( PlaceWidgets(
obs_module_text( obs_module_text(
@@ -1125,23 +1028,20 @@ MacroActionVariableEdit::MacroActionVariableEdit(
obs_module_text( obs_module_text(
"AdvSceneSwitcher.action.variable.layout.randomNumber"), "AdvSceneSwitcher.action.variable.layout.randomNumber"),
randomLayout, widgetPlaceholders); randomLayout, widgetPlaceholders);
_randomNumberLayout->addLayout(randomLayout); _randomLayout->addLayout(randomLayout);
_randomNumberLayout->addWidget(_generateInteger); _randomLayout->addWidget(_generateInteger);
_randomValueLayout->addWidget(_randomValues);
_randomValueLayout->addWidget(_allowRepeatValues);
auto regexConfigLayout = new QHBoxLayout; auto regexConfigLayout = new QHBoxLayout;
regexConfigLayout->addWidget(_subStringRegex); regexConfigLayout->addWidget(_substringRegex);
regexConfigLayout->addStretch(); regexConfigLayout->addStretch();
_substringLayout->addLayout(_subStringControlsLayout); _substringLayout->addLayout(_subStringIndexEntryLayout);
_substringLayout->addLayout(_subStringRegexEntryLayout);
_substringLayout->addWidget(_regexPattern); _substringLayout->addWidget(_regexPattern);
_substringLayout->addLayout(regexConfigLayout); _substringLayout->addLayout(regexConfigLayout);
auto layout = new QVBoxLayout; auto layout = new QVBoxLayout;
layout->addLayout(_entryLayout); layout->addLayout(_entryLayout);
layout->addLayout(_jsonQueryLayout);
layout->addLayout(_substringLayout); layout->addLayout(_substringLayout);
layout->addWidget(_segmentValueStatus); layout->addWidget(_segmentValueStatus);
layout->addWidget(_segmentValue); layout->addWidget(_segmentValue);
@@ -1149,8 +1049,7 @@ MacroActionVariableEdit::MacroActionVariableEdit(
layout->addWidget(_mathExpressionResult); layout->addWidget(_mathExpressionResult);
layout->addLayout(_promptLayout); layout->addLayout(_promptLayout);
layout->addLayout(_placeholderLayout); layout->addLayout(_placeholderLayout);
layout->addLayout(_randomNumberLayout); layout->addLayout(_randomLayout);
layout->addLayout(_randomValueLayout);
setLayout(layout); setLayout(layout);
_entryData = entryData; _entryData = entryData;
@@ -1184,7 +1083,7 @@ void MacroActionVariableEdit::UpdateEntryData()
: MacroSegmentSelection::Type::ACTION); : MacroSegmentSelection::Type::ACTION);
_subStringStart->SetValue(_entryData->_subStringStart); _subStringStart->SetValue(_entryData->_subStringStart);
_subStringSize->SetValue(_entryData->_subStringSize); _subStringSize->SetValue(_entryData->_subStringSize);
_subStringRegex->SetRegexConfig(_entryData->_subStringRegex); _substringRegex->SetRegexConfig(_entryData->_subStringRegex);
_findRegex->SetRegexConfig(_entryData->_findRegex); _findRegex->SetRegexConfig(_entryData->_findRegex);
_regexPattern->setPlainText( _regexPattern->setPlainText(
QString::fromStdString(_entryData->_regexPattern)); QString::fromStdString(_entryData->_regexPattern));
@@ -1209,11 +1108,8 @@ void MacroActionVariableEdit::UpdateEntryData()
_randomNumberStart->SetValue(_entryData->_randomNumberStart); _randomNumberStart->SetValue(_entryData->_randomNumberStart);
_randomNumberEnd->SetValue(_entryData->_randomNumberEnd); _randomNumberEnd->SetValue(_entryData->_randomNumberEnd);
_generateInteger->setChecked(_entryData->_generateInteger); _generateInteger->setChecked(_entryData->_generateInteger);
_allowRepeatValues->setChecked(_entryData->_allowRepeatValues);
_randomValues->SetStringList(_entryData->_randomValues);
_jsonQuery->setText(_entryData->_jsonQuery); _jsonQuery->setText(_entryData->_jsonQuery);
_jsonIndex->SetValue(_entryData->_jsonIndex); _jsonIndex->SetValue(_entryData->_jsonIndex);
_jsonExtractSingle->setChecked(_entryData->_jsonQueryExtractSingle);
SetWidgetVisibility(); SetWidgetVisibility();
} }
@@ -1493,7 +1389,6 @@ void MacroActionVariableEdit::SelectionChanged(const TempVariableRef &var)
{ {
GUARD_LOADING_AND_LOCK(); GUARD_LOADING_AND_LOCK();
_entryData->_tempVar = var; _entryData->_tempVar = var;
IncrementTempVarInUseGeneration();
SetWidgetVisibility(); SetWidgetVisibility();
} }
@@ -1555,18 +1450,6 @@ void MacroActionVariableEdit::GenerateIntegerChanged(int value)
_entryData->_generateInteger = value; _entryData->_generateInteger = value;
} }
void MacroActionVariableEdit::RandomValueListChanged(const StringList &values)
{
GUARD_LOADING_AND_LOCK();
_entryData->_randomValues = values;
}
void MacroActionVariableEdit::AllowRepeatValuesChanged(int value)
{
GUARD_LOADING_AND_LOCK();
_entryData->_allowRepeatValues = value;
}
void MacroActionVariableEdit::JsonQueryChanged() void MacroActionVariableEdit::JsonQueryChanged()
{ {
GUARD_LOADING_AND_LOCK(); GUARD_LOADING_AND_LOCK();
@@ -1579,12 +1462,6 @@ void MacroActionVariableEdit::JsonIndexChanged(const NumberVariable<int> &value)
_entryData->_jsonIndex = value; _entryData->_jsonIndex = value;
} }
void MacroActionVariableEdit::JsonQueryExtractSingleChanged(int value)
{
GUARD_LOADING_AND_LOCK();
_entryData->_jsonQueryExtractSingle = value;
}
void MacroActionVariableEdit::SetWidgetVisibility() void MacroActionVariableEdit::SetWidgetVisibility()
{ {
if (!_entryData) { if (!_entryData) {
@@ -1611,20 +1488,8 @@ void MacroActionVariableEdit::SetWidgetVisibility()
{"{{jsonQuery}}", _jsonQuery}, {"{{jsonQuery}}", _jsonQuery},
{"{{jsonQueryHelp}}", _jsonQueryHelp}, {"{{jsonQueryHelp}}", _jsonQueryHelp},
{"{{jsonIndex}}", _jsonIndex}, {"{{jsonIndex}}", _jsonIndex},
{"{{subStringRegex}}", _subStringRegex},
{"{{subStringStart}}", _subStringStart},
{"{{subStringSize}}", _subStringSize},
{"{{regexMatchIdx}}", _regexMatchIdx},
}; };
for (const auto &[_, widget] : widgetPlaceholders) {
_entryLayout->removeWidget(widget);
_subStringControlsLayout->removeWidget(widget);
}
ClearLayout(_entryLayout);
ClearLayout(_subStringControlsLayout);
const char *layoutString = ""; const char *layoutString = "";
if (_entryData->_action == MacroActionVariable::Action::PAD) { if (_entryData->_action == MacroActionVariable::Action::PAD) {
layoutString = obs_module_text( layoutString = obs_module_text(
@@ -1633,15 +1498,16 @@ void MacroActionVariableEdit::SetWidgetVisibility()
MacroActionVariable::Action::TRUNCATE) { MacroActionVariable::Action::TRUNCATE) {
layoutString = obs_module_text( layoutString = obs_module_text(
"AdvSceneSwitcher.action.variable.layout.truncate"); "AdvSceneSwitcher.action.variable.layout.truncate");
} else if (_entryData->_action ==
MacroActionVariable::Action::COPY_VAR) {
layoutString = obs_module_text(
"AdvSceneSwitcher.action.variable.layout.copy");
} else { } else {
layoutString = obs_module_text( layoutString = obs_module_text(
"AdvSceneSwitcher.action.variable.layout.other"); "AdvSceneSwitcher.action.variable.layout.other");
} }
for (const auto &[_, widget] : widgetPlaceholders) {
_entryLayout->removeWidget(widget);
}
ClearLayout(_entryLayout);
PlaceWidgets(layoutString, _entryLayout, widgetPlaceholders); PlaceWidgets(layoutString, _entryLayout, widgetPlaceholders);
if (_entryData->_action == MacroActionVariable::Action::SET_VALUE || if (_entryData->_action == MacroActionVariable::Action::SET_VALUE ||
@@ -1658,7 +1524,6 @@ void MacroActionVariableEdit::SetWidgetVisibility()
} }
_variables2->setVisible( _variables2->setVisible(
_entryData->_action == MacroActionVariable::Action::COPY_VAR ||
_entryData->_action == _entryData->_action ==
MacroActionVariable::Action::APPEND_VAR || MacroActionVariable::Action::APPEND_VAR ||
_entryData->_action == _entryData->_action ==
@@ -1688,25 +1553,15 @@ void MacroActionVariableEdit::SetWidgetVisibility()
MacroActionVariable::Action::SET_ACTION_VALUE || MacroActionVariable::Action::SET_ACTION_VALUE ||
_entryData->_action == _entryData->_action ==
MacroActionVariable::Action::SET_CONDITION_VALUE); MacroActionVariable::Action::SET_CONDITION_VALUE);
bool showRegex = _entryData->_subStringRegex.Enabled();
layoutString =
showRegex
? "AdvSceneSwitcher.action.variable.layout.substringRegex"
: "AdvSceneSwitcher.action.variable.layout.substringIndex";
PlaceWidgets(obs_module_text(layoutString), _subStringControlsLayout,
widgetPlaceholders);
_subStringStart->setVisible(!showRegex);
_subStringSize->setVisible(!showRegex);
_regexMatchIdx->setVisible(showRegex);
SetLayoutVisible(_substringLayout, SetLayoutVisible(_substringLayout,
_entryData->_action == _entryData->_action ==
MacroActionVariable::Action::SUBSTRING); MacroActionVariable::Action::SUBSTRING);
_regexPattern->setVisible( if (_entryData->_action == MacroActionVariable::Action::SUBSTRING) {
showRegex && bool showRegex = _entryData->_subStringRegex.Enabled();
_entryData->_action == MacroActionVariable::Action::SUBSTRING); SetLayoutVisible(_subStringIndexEntryLayout, !showRegex);
SetLayoutVisible(_subStringRegexEntryLayout, showRegex);
_regexPattern->setVisible(showRegex);
}
SetLayoutVisible(_findReplaceLayout, SetLayoutVisible(_findReplaceLayout,
_entryData->_action == _entryData->_action ==
MacroActionVariable::Action::FIND_AND_REPLACE); MacroActionVariable::Action::FIND_AND_REPLACE);
@@ -1771,22 +1626,15 @@ void MacroActionVariableEdit::SetWidgetVisibility()
MacroActionVariable::Action::PAD); MacroActionVariable::Action::PAD);
_caseType->setVisible(_entryData->_action == _caseType->setVisible(_entryData->_action ==
MacroActionVariable::Action::CHANGE_CASE); MacroActionVariable::Action::CHANGE_CASE);
SetLayoutVisible(_randomNumberLayout, SetLayoutVisible(_randomLayout,
_entryData->_action == _entryData->_action ==
MacroActionVariable::Action::RANDOM_NUMBER); MacroActionVariable::Action::RANDOM_NUMBER);
SetLayoutVisible(
_randomValueLayout,
_entryData->_action ==
MacroActionVariable::Action::RANDOM_LIST_VALUE);
_jsonQuery->setVisible(_entryData->_action == _jsonQuery->setVisible(_entryData->_action ==
MacroActionVariable::Action::QUERY_JSON); MacroActionVariable::Action::QUERY_JSON);
_jsonQueryHelp->setVisible(_entryData->_action == _jsonQueryHelp->setVisible(_entryData->_action ==
MacroActionVariable::Action::QUERY_JSON); MacroActionVariable::Action::QUERY_JSON);
_jsonIndex->setVisible(_entryData->_action == _jsonIndex->setVisible(_entryData->_action ==
MacroActionVariable::Action::ARRAY_JSON); MacroActionVariable::Action::ARRAY_JSON);
SetLayoutVisible(_jsonQueryLayout,
_entryData->_action ==
MacroActionVariable::Action::QUERY_JSON);
adjustSize(); adjustSize();
updateGeometry(); updateGeometry();

View File

@@ -6,7 +6,6 @@
#include "resizing-text-edit.hpp" #include "resizing-text-edit.hpp"
#include "scene-selection.hpp" #include "scene-selection.hpp"
#include "single-char-selection.hpp" #include "single-char-selection.hpp"
#include "string-list.hpp"
#include "variable-line-edit.hpp" #include "variable-line-edit.hpp"
#include "variable-text-edit.hpp" #include "variable-text-edit.hpp"
#include "variable-spinbox.hpp" #include "variable-spinbox.hpp"
@@ -23,7 +22,6 @@ public:
bool PostLoad(); bool PostLoad();
std::string GetShortDesc() const; std::string GetShortDesc() const;
std::string GetId() const { return id; }; std::string GetId() const { return id; };
std::vector<TempVariableRef> GetTempVarRefs() const;
static std::shared_ptr<MacroAction> Create(Macro *m); static std::shared_ptr<MacroAction> Create(Macro *m);
std::shared_ptr<MacroAction> Copy() const; std::shared_ptr<MacroAction> Copy() const;
void SetSegmentIndexValue(int); void SetSegmentIndexValue(int);
@@ -57,8 +55,6 @@ public:
RANDOM_NUMBER, RANDOM_NUMBER,
QUERY_JSON, QUERY_JSON,
ARRAY_JSON, ARRAY_JSON,
COPY_VAR,
RANDOM_LIST_VALUE,
}; };
Action _action = Action::SET_VALUE; Action _action = Action::SET_VALUE;
@@ -110,13 +106,8 @@ public:
DoubleVariable _randomNumberEnd = 100; DoubleVariable _randomNumberEnd = 100;
bool _generateInteger = true; bool _generateInteger = true;
StringList _randomValues = {"value1", "value2", "value3"};
bool _allowRepeatValues = true;
std::optional<std::string> _lastRandomValue;
StringVariable _jsonQuery = "$.some.nested.value"; StringVariable _jsonQuery = "$.some.nested.value";
IntVariable _jsonIndex = 0; IntVariable _jsonIndex = 0;
bool _jsonQueryExtractSingle = true;
private: private:
void DecrementCurrentSegmentVariableRef(); void DecrementCurrentSegmentVariableRef();
@@ -127,7 +118,6 @@ private:
void HandleCaseChange(Variable *); void HandleCaseChange(Variable *);
void SetToSceneItemName(Variable *); void SetToSceneItemName(Variable *);
void GenerateRandomNumber(Variable *); void GenerateRandomNumber(Variable *);
void PickRandomValue(Variable *);
std::weak_ptr<MacroSegment> _macroSegment; std::weak_ptr<MacroSegment> _macroSegment;
int _segmentIdxLoadValue = -1; int _segmentIdxLoadValue = -1;
@@ -184,11 +174,8 @@ private slots:
void RandomNumberStartChanged(const NumberVariable<double> &); void RandomNumberStartChanged(const NumberVariable<double> &);
void RandomNumberEndChanged(const NumberVariable<double> &); void RandomNumberEndChanged(const NumberVariable<double> &);
void GenerateIntegerChanged(int); void GenerateIntegerChanged(int);
void RandomValueListChanged(const StringList &);
void AllowRepeatValuesChanged(int);
void JsonQueryChanged(); void JsonQueryChanged();
void JsonIndexChanged(const NumberVariable<int> &); void JsonIndexChanged(const NumberVariable<int> &);
void JsonQueryExtractSingleChanged(int);
signals: signals:
void HeaderInfoChanged(const QString &); void HeaderInfoChanged(const QString &);
@@ -206,10 +193,11 @@ private:
QLabel *_segmentValueStatus; QLabel *_segmentValueStatus;
ResizingPlainTextEdit *_segmentValue; ResizingPlainTextEdit *_segmentValue;
QVBoxLayout *_substringLayout; QVBoxLayout *_substringLayout;
QHBoxLayout *_subStringControlsLayout; QHBoxLayout *_subStringIndexEntryLayout;
QHBoxLayout *_subStringRegexEntryLayout;
VariableSpinBox *_subStringStart; VariableSpinBox *_subStringStart;
VariableSpinBox *_subStringSize; VariableSpinBox *_subStringSize;
RegexConfigWidget *_subStringRegex; RegexConfigWidget *_substringRegex;
ResizingPlainTextEdit *_regexPattern; ResizingPlainTextEdit *_regexPattern;
VariableSpinBox *_regexMatchIdx; VariableSpinBox *_regexMatchIdx;
QHBoxLayout *_findReplaceLayout; QHBoxLayout *_findReplaceLayout;
@@ -236,16 +224,10 @@ private:
VariableDoubleSpinBox *_randomNumberStart; VariableDoubleSpinBox *_randomNumberStart;
VariableDoubleSpinBox *_randomNumberEnd; VariableDoubleSpinBox *_randomNumberEnd;
QCheckBox *_generateInteger; QCheckBox *_generateInteger;
QVBoxLayout *_randomNumberLayout; QVBoxLayout *_randomLayout;
StringListEdit *_randomValues;
QCheckBox *_allowRepeatValues;
QVBoxLayout *_randomValueLayout;
VariableLineEdit *_jsonQuery; VariableLineEdit *_jsonQuery;
HelpIcon *_jsonQueryHelp; QLabel *_jsonQueryHelp;
VariableSpinBox *_jsonIndex; VariableSpinBox *_jsonIndex;
QCheckBox *_jsonExtractSingle;
HelpIcon *_jsonExtractSingleHelp;
QVBoxLayout *_jsonQueryLayout;
QHBoxLayout *_entryLayout; QHBoxLayout *_entryLayout;
std::shared_ptr<MacroActionVariable> _entryData; std::shared_ptr<MacroActionVariable> _entryData;

View File

@@ -1,14 +1,10 @@
#include "macro-condition-edit.hpp" #include "macro-condition-edit.hpp"
#include "advanced-scene-switcher.hpp" #include "advanced-scene-switcher.hpp"
#include "condition-logic.hpp"
#include "macro-settings.hpp" #include "macro-settings.hpp"
#include "macro-signals.hpp"
#include "macro.hpp" #include "macro.hpp"
#include "path-helpers.hpp" #include "path-helpers.hpp"
#include "plugin-state-helpers.hpp" #include "plugin-state-helpers.hpp"
#include "section.hpp" #include "section.hpp"
#include "switch-button.hpp"
#include "ui-helpers.hpp" #include "ui-helpers.hpp"
#include "utility.hpp" #include "utility.hpp"
@@ -104,17 +100,14 @@ void DurationModifierEdit::Collapse(bool collapse)
MacroConditionEdit::MacroConditionEdit( MacroConditionEdit::MacroConditionEdit(
QWidget *parent, std::shared_ptr<MacroCondition> *entryData, QWidget *parent, std::shared_ptr<MacroCondition> *entryData,
bool isRootCondition) const std::string &id, bool isRootCondition)
: MacroSegmentEdit(parent), : MacroSegmentEdit(parent),
_enable(new SwitchButton()),
_logicSelection(new QComboBox()), _logicSelection(new QComboBox()),
_conditionSelection(new FilterComboBox()), _conditionSelection(new FilterComboBox()),
_dur(new DurationModifierEdit()), _dur(new DurationModifierEdit()),
_entryData(entryData), _entryData(entryData),
_isRoot(isRootCondition) _isRoot(isRootCondition)
{ {
QWidget::connect(_enable, SIGNAL(checked(bool)), this,
SLOT(ConditionEnableChanged(bool)));
QWidget::connect(_logicSelection, SIGNAL(currentIndexChanged(int)), QWidget::connect(_logicSelection, SIGNAL(currentIndexChanged(int)),
this, SLOT(LogicSelectionChanged(int))); this, SLOT(LogicSelectionChanged(int)));
QWidget::connect(_conditionSelection, QWidget::connect(_conditionSelection,
@@ -129,17 +122,14 @@ MacroConditionEdit::MacroConditionEdit(
Logic::PopulateLogicTypeSelection(_logicSelection, isRootCondition); Logic::PopulateLogicTypeSelection(_logicSelection, isRootCondition);
populateConditionSelection(_conditionSelection); populateConditionSelection(_conditionSelection);
_section->AddHeaderWidget(_enable);
_section->AddHeaderWidget(_logicSelection); _section->AddHeaderWidget(_logicSelection);
_section->AddHeaderWidget(_conditionSelection); _section->AddHeaderWidget(_conditionSelection);
_section->AddHeaderWidget(_headerInfo); _section->AddHeaderWidget(_headerInfo);
_section->AddHeaderWidget(_dur); _section->AddHeaderWidget(_dur);
_section->AddHeaderWidget(_varMappingToggle);
QVBoxLayout *conditionLayout = new QVBoxLayout; QVBoxLayout *conditionLayout = new QVBoxLayout;
conditionLayout->setContentsMargins({7, 7, 7, 7}); conditionLayout->setContentsMargins({7, 7, 7, 7});
conditionLayout->addWidget(_section); conditionLayout->addWidget(_section);
conditionLayout->addWidget(_outputMappings);
_contentLayout->addLayout(conditionLayout); _contentLayout->addLayout(conditionLayout);
QHBoxLayout *mainLayout = new QHBoxLayout; QHBoxLayout *mainLayout = new QHBoxLayout;
@@ -162,17 +152,8 @@ void MacroConditionEdit::LogicSelectionChanged(int idx)
const auto logic = static_cast<Logic::Type>( const auto logic = static_cast<Logic::Type>(
_logicSelection->itemData(idx).toInt()); _logicSelection->itemData(idx).toInt());
(*_entryData)->SetLogicType(logic); (*_entryData)->SetLogicType(logic);
}
void MacroConditionEdit::ConditionEnableChanged(bool value) SetEnableAppearance(logic != Logic::Type::NONE);
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
(*_entryData)->SetEnabled(value);
SetDisableEffect(!value);
} }
bool MacroConditionEdit::IsRootNode() const bool MacroConditionEdit::IsRootNode() const
@@ -185,9 +166,7 @@ void MacroConditionEdit::SetLogicSelection()
const auto logic = (*_entryData)->GetLogicType(); const auto logic = (*_entryData)->GetLogicType();
_logicSelection->setCurrentIndex( _logicSelection->setCurrentIndex(
_logicSelection->findData(static_cast<int>(logic))); _logicSelection->findData(static_cast<int>(logic)));
const bool enabled = (*_entryData)->Enabled(); SetEnableAppearance(logic != Logic::Type::NONE);
_enable->setChecked(enabled);
SetEnableAppearance(enabled);
} }
void MacroConditionEdit::SetRootNode(bool root) void MacroConditionEdit::SetRootNode(bool root)
@@ -225,10 +204,7 @@ void MacroConditionEdit::SetupWidgets(bool basicSetup)
MacroConditionFactory::CreateWidget(id, this, *_entryData); MacroConditionFactory::CreateWidget(id, this, *_entryData);
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)), QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
this, SLOT(HeaderInfoChanged(const QString &))); this, SLOT(HeaderInfoChanged(const QString &)));
QWidget::connect(widget, SIGNAL(ShowVariableMappings(bool)), this,
SLOT(ShowVariableMappings(bool)));
_section->SetContent(widget, (*_entryData)->GetCollapsed()); _section->SetContent(widget, (*_entryData)->GetCollapsed());
SetupVarMappings((*_entryData).get());
SetFocusPolicyOfWidgets(); SetFocusPolicyOfWidgets();
_allWidgetsAreSetup = true; _allWidgetsAreSetup = true;
@@ -258,28 +234,20 @@ void MacroConditionEdit::ConditionSelectionChanged(const QString &text)
{ {
auto lock = LockContext(); auto lock = LockContext();
auto logic = (*_entryData)->GetLogicType(); auto logic = (*_entryData)->GetLogicType();
const bool enabled = (*_entryData)->Enabled();
_entryData->reset(); _entryData->reset();
*_entryData = MacroConditionFactory::Create(id, macro); *_entryData = MacroConditionFactory::Create(id, macro);
(*_entryData)->SetIndex(idx); (*_entryData)->SetIndex(idx);
(*_entryData)->SetLogicType(logic); (*_entryData)->SetLogicType(logic);
(*_entryData)->SetEnabled(enabled);
(*_entryData)->PostLoad(); (*_entryData)->PostLoad();
RunAndClearPostLoadSteps(); RunPostLoadSteps();
} }
auto widget = auto widget =
MacroConditionFactory::CreateWidget(id, this, *_entryData); MacroConditionFactory::CreateWidget(id, this, *_entryData);
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)), QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
this, SLOT(HeaderInfoChanged(const QString &))); this, SLOT(HeaderInfoChanged(const QString &)));
QWidget::connect(widget, SIGNAL(ShowVariableMappings(bool)), this,
SLOT(ShowVariableMappings(bool)));
_section->SetContent(widget); _section->SetContent(widget);
SetupVarMappings((*_entryData).get());
_dur->setVisible(MacroConditionFactory::UsesDurationModifier(id)); _dur->setVisible(MacroConditionFactory::UsesDurationModifier(id));
SetFocusPolicyOfWidgets(); SetFocusPolicyOfWidgets();
emit MacroSignalManager::Instance()->ConditionTypeCreated(
QString::fromStdString(id));
} }
void MacroConditionEdit::DurationChanged(const Duration &seconds) void MacroConditionEdit::DurationChanged(const Duration &seconds)
@@ -307,9 +275,289 @@ std::shared_ptr<MacroSegment> MacroConditionEdit::Data() const
return *_entryData; return *_entryData;
} }
void MacroConditionEdit::FocusTypeSelection() void AdvSceneSwitcher::AddMacroCondition(int idx)
{ {
_conditionSelection->setFocus(); auto macro = GetSelectedMacro();
if (!macro) {
return;
}
if (idx < 0 || idx > (int)macro->Conditions().size()) {
assert(false);
return;
}
std::string id;
Logic::Type logic;
if (idx >= 1) {
id = macro->Conditions().at(idx - 1)->GetId();
if (idx == 1) {
logic = Logic::Type::OR;
} else {
logic = macro->Conditions().at(idx - 1)->GetLogicType();
}
} else {
id = MacroCondition::GetDefaultID();
logic = Logic::Type::ROOT_NONE;
}
OBSDataAutoRelease data;
if (idx - 1 >= 0) {
data = obs_data_create();
macro->Conditions().at(idx - 1)->Save(data);
}
AddMacroCondition(macro.get(), idx, id, data.Get(), logic);
}
void AdvSceneSwitcher::AddMacroCondition(Macro *macro, int idx,
const std::string &id,
obs_data_t *data, Logic::Type logic)
{
if (idx < 0 || idx > (int)macro->Conditions().size()) {
assert(false);
return;
}
{
auto lock = LockContext();
auto cond = macro->Conditions().emplace(
macro->Conditions().begin() + idx,
MacroConditionFactory::Create(id, macro));
if (data) {
macro->Conditions().at(idx)->Load(data);
}
macro->Conditions().at(idx)->PostLoad();
RunPostLoadSteps();
(*cond)->SetLogicType(logic);
macro->UpdateConditionIndices();
ui->conditionsList->Insert(
idx,
new MacroConditionEdit(this, &macro->Conditions()[idx],
id, idx == 0));
SetConditionData(*macro);
}
HighlightCondition(idx);
ui->conditionsList->SetHelpMsgVisible(false);
emit(MacroSegmentOrderChanged());
}
void AdvSceneSwitcher::on_conditionAdd_clicked()
{
auto macro = GetSelectedMacro();
if (!macro) {
return;
}
if (currentConditionIdx == -1) {
AddMacroCondition((int)macro->Conditions().size());
} else {
AddMacroCondition(currentConditionIdx + 1);
}
if (currentConditionIdx != -1) {
MacroConditionSelectionChanged(currentConditionIdx + 1);
}
}
void AdvSceneSwitcher::RemoveMacroCondition(int idx)
{
auto macro = GetSelectedMacro();
if (!macro) {
return;
}
if (idx < 0 || idx >= (int)macro->Conditions().size()) {
return;
}
{
auto lock = LockContext();
ui->conditionsList->Remove(idx);
macro->Conditions().erase(macro->Conditions().begin() + idx);
macro->UpdateConditionIndices();
if (idx == 0 && macro->Conditions().size() > 0) {
auto newRoot = macro->Conditions().at(0);
newRoot->SetLogicType(Logic::Type::ROOT_NONE);
static_cast<MacroConditionEdit *>(
ui->conditionsList->WidgetAt(0))
->SetRootNode(true);
}
SetConditionData(*macro);
}
MacroConditionSelectionChanged(-1);
lastInteracted = MacroSection::CONDITIONS;
emit(MacroSegmentOrderChanged());
}
void AdvSceneSwitcher::on_conditionRemove_clicked()
{
if (currentConditionIdx == -1) {
auto macro = GetSelectedMacro();
if (!macro) {
return;
}
RemoveMacroCondition((int)macro->Conditions().size() - 1);
} else {
RemoveMacroCondition(currentConditionIdx);
}
MacroConditionSelectionChanged(-1);
}
void AdvSceneSwitcher::on_conditionTop_clicked()
{
if (currentConditionIdx == -1) {
return;
}
MacroConditionReorder(0, currentConditionIdx);
MacroConditionSelectionChanged(0);
}
void AdvSceneSwitcher::on_conditionUp_clicked()
{
if (currentConditionIdx == -1 || currentConditionIdx == 0) {
return;
}
MoveMacroConditionUp(currentConditionIdx);
MacroConditionSelectionChanged(currentConditionIdx - 1);
}
void AdvSceneSwitcher::on_conditionDown_clicked()
{
if (currentConditionIdx == -1 ||
currentConditionIdx ==
ui->conditionsList->ContentLayout()->count() - 1) {
return;
}
MoveMacroConditionDown(currentConditionIdx);
MacroConditionSelectionChanged(currentConditionIdx + 1);
}
void AdvSceneSwitcher::on_conditionBottom_clicked()
{
if (currentConditionIdx == -1) {
return;
}
const int newIdx = ui->conditionsList->ContentLayout()->count() - 1;
MacroConditionReorder(newIdx, currentConditionIdx);
MacroConditionSelectionChanged(newIdx);
}
void AdvSceneSwitcher::SwapConditions(Macro *m, int pos1, int pos2)
{
if (pos1 == pos2) {
return;
}
if (pos1 > pos2) {
std::swap(pos1, pos2);
}
bool root = pos1 == 0;
auto lock = LockContext();
iter_swap(m->Conditions().begin() + pos1,
m->Conditions().begin() + pos2);
m->UpdateConditionIndices();
auto c1 = m->Conditions().begin() + pos1;
auto c2 = m->Conditions().begin() + pos2;
if (root) {
auto logic1 = (*c1)->GetLogicType();
auto logic2 = (*c2)->GetLogicType();
(*c1)->SetLogicType(logic2);
(*c2)->SetLogicType(logic1);
}
auto widget1 = static_cast<MacroConditionEdit *>(
ui->conditionsList->ContentLayout()->takeAt(pos1)->widget());
auto widget2 = static_cast<MacroConditionEdit *>(
ui->conditionsList->ContentLayout()->takeAt(pos2 - 1)->widget());
ui->conditionsList->Insert(pos1, widget2);
ui->conditionsList->Insert(pos2, widget1);
SetConditionData(*m);
widget2->SetRootNode(root);
widget1->SetRootNode(false);
emit(MacroSegmentOrderChanged());
}
void AdvSceneSwitcher::MoveMacroConditionUp(int idx)
{
auto macro = GetSelectedMacro();
if (!macro) {
return;
}
if (idx < 1 || idx >= (int)macro->Conditions().size()) {
return;
}
SwapConditions(macro.get(), idx, idx - 1);
HighlightCondition(idx - 1);
}
void AdvSceneSwitcher::MoveMacroConditionDown(int idx)
{
auto macro = GetSelectedMacro();
if (!macro) {
return;
}
if (idx < 0 || idx >= (int)macro->Conditions().size() - 1) {
return;
}
SwapConditions(macro.get(), idx, idx + 1);
HighlightCondition(idx + 1);
}
void AdvSceneSwitcher::MacroConditionSelectionChanged(int idx)
{
SetupMacroSegmentSelection(MacroSection::CONDITIONS, idx);
}
void AdvSceneSwitcher::MacroConditionReorder(int to, int from)
{
auto macro = GetSelectedMacro();
if (!macro) {
return;
}
if (to == from || from < 0 || from > (int)macro->Conditions().size() ||
to < 0 || to > (int)macro->Conditions().size()) {
return;
}
{
auto lock = LockContext();
auto condition = macro->Conditions().at(from);
if (to == 0) {
condition->SetLogicType(Logic::Type::ROOT_NONE);
static_cast<MacroConditionEdit *>(
ui->conditionsList->WidgetAt(from))
->SetRootNode(true);
macro->Conditions().at(0)->SetLogicType(
Logic::Type::AND);
static_cast<MacroConditionEdit *>(
ui->conditionsList->WidgetAt(0))
->SetRootNode(false);
}
if (from == 0) {
condition->SetLogicType(Logic::Type::AND);
static_cast<MacroConditionEdit *>(
ui->conditionsList->WidgetAt(from))
->SetRootNode(false);
macro->Conditions().at(1)->SetLogicType(
Logic::Type::ROOT_NONE);
static_cast<MacroConditionEdit *>(
ui->conditionsList->WidgetAt(1))
->SetRootNode(true);
}
macro->Conditions().erase(macro->Conditions().begin() + from);
macro->Conditions().insert(macro->Conditions().begin() + to,
condition);
macro->UpdateConditionIndices();
ui->conditionsList->ContentLayout()->insertItem(
to, ui->conditionsList->ContentLayout()->takeAt(from));
SetConditionData(*macro);
}
HighlightCondition(to);
emit(MacroSegmentOrderChanged());
} }
} // namespace advss } // namespace advss

View File

@@ -8,8 +8,6 @@
namespace advss { namespace advss {
class SwitchButton;
class DurationModifierEdit : public QWidget { class DurationModifierEdit : public QWidget {
Q_OBJECT Q_OBJECT
public: public:
@@ -36,27 +34,26 @@ class MacroConditionEdit : public MacroSegmentEdit {
Q_OBJECT Q_OBJECT
public: public:
MacroConditionEdit(QWidget *parent = nullptr, MacroConditionEdit(
std::shared_ptr<MacroCondition> * = nullptr, QWidget *parent = nullptr,
bool root = true); std::shared_ptr<MacroCondition> * = nullptr,
const std::string &id = MacroCondition::GetDefaultID().data(),
bool root = true);
bool IsRootNode() const; bool IsRootNode() const;
void SetRootNode(bool); void SetRootNode(bool);
void SetupWidgets(bool basicSetup = false); void SetupWidgets(bool basicSetup = false);
void SetEntryData(std::shared_ptr<MacroCondition> *); void SetEntryData(std::shared_ptr<MacroCondition> *);
void FocusTypeSelection() override;
private slots: private slots:
void LogicSelectionChanged(int idx); void LogicSelectionChanged(int idx);
void ConditionSelectionChanged(const QString &text); void ConditionSelectionChanged(const QString &text);
void DurationChanged(const Duration &value); void DurationChanged(const Duration &value);
void DurationModifierChanged(DurationModifier::Type m); void DurationModifierChanged(DurationModifier::Type m);
void ConditionEnableChanged(bool);
private: private:
void SetLogicSelection(); void SetLogicSelection();
std::shared_ptr<MacroSegment> Data() const; std::shared_ptr<MacroSegment> Data() const;
SwitchButton *_enable;
QComboBox *_logicSelection; QComboBox *_logicSelection;
FilterComboBox *_conditionSelection; FilterComboBox *_conditionSelection;
DurationModifierEdit *_dur; DurationModifierEdit *_dur;

View File

@@ -1,11 +1,21 @@
#include "macro-condition-factory.hpp" #include "macro-condition-factory.hpp"
#include "macro-segment-unknown.hpp"
#include <mutex> #include <mutex>
namespace advss { namespace advss {
using MacroConditionUnknown = MacroSegmentUnknown<MacroCondition>; namespace {
class MacroConditionUnknown : public MacroCondition {
public:
MacroConditionUnknown(Macro *m) : MacroCondition(m) {}
bool CheckCondition() { return false; }
bool Save(obs_data_t *obj) const { return MacroCondition::Save(obj); };
bool Load(obs_data_t *obj) { return MacroCondition::Load(obj); };
std::string GetId() const { return "unknown"; }
};
} // namespace
static std::recursive_mutex mutex; static std::recursive_mutex mutex;
@@ -36,10 +46,9 @@ bool MacroConditionFactory::Deregister(const std::string &id)
return true; return true;
} }
static std::shared_ptr<MacroCondition> static std::shared_ptr<MacroCondition> createUnknownCondition(Macro *m)
createUnknownCondition(Macro *m, const std::string &id)
{ {
return std::make_shared<MacroConditionUnknown>(m, id); return std::make_shared<MacroConditionUnknown>(m);
} }
std::shared_ptr<MacroCondition> std::shared_ptr<MacroCondition>
@@ -49,7 +58,13 @@ MacroConditionFactory::Create(const std::string &id, Macro *m)
if (auto it = GetMap().find(id); it != GetMap().end()) { if (auto it = GetMap().find(id); it != GetMap().end()) {
return it->second._create(m); return it->second._create(m);
} }
return createUnknownCondition(m, id); return createUnknownCondition(m);
}
static QWidget *createUnknownConditionWidget()
{
return new QLabel(
obs_module_text("AdvSceneSwitcher.condition.unknown"));
} }
QWidget * QWidget *
@@ -60,7 +75,7 @@ MacroConditionFactory::CreateWidget(const std::string &id, QWidget *parent,
if (auto it = GetMap().find(id); it != GetMap().end()) { if (auto it = GetMap().find(id); it != GetMap().end()) {
return it->second._createWidget(parent, cond); return it->second._createWidget(parent, cond);
} }
return CreateUnknownSegmentWidget(false); return createUnknownConditionWidget();
} }
std::string MacroConditionFactory::GetConditionName(const std::string &id) std::string MacroConditionFactory::GetConditionName(const std::string &id)

View File

@@ -1,10 +1,6 @@
#include "macro-condition-macro.hpp" #include "macro-condition-macro.hpp"
#include "layout-helpers.hpp" #include "layout-helpers.hpp"
#include "macro-action-edit.hpp" #include "macro-action-edit.hpp"
#include "macro-helpers.hpp"
#include "macro-ref.hpp"
#include "macro-signals.hpp"
#include "macro.hpp" #include "macro.hpp"
namespace advss { namespace advss {
@@ -30,8 +26,6 @@ const static std::map<MacroConditionMacro::Type, std::string>
"AdvSceneSwitcher.condition.macro.type.actionEnabled"}, "AdvSceneSwitcher.condition.macro.type.actionEnabled"},
{MacroConditionMacro::Type::PAUSED, {MacroConditionMacro::Type::PAUSED,
"AdvSceneSwitcher.condition.macro.type.paused"}, "AdvSceneSwitcher.condition.macro.type.paused"},
{MacroConditionMacro::Type::ACTIONS_PERFORMED,
"AdvSceneSwitcher.condition.macro.type.actionsPerformed"},
}; };
const static std::map<MacroConditionMacro::CounterCondition, std::string> const static std::map<MacroConditionMacro::CounterCondition, std::string>
@@ -105,7 +99,7 @@ bool MacroConditionMacro::CheckActionStateCondition()
if (!macro) { if (!macro) {
return false; return false;
} }
if (!IsValidActionIndex(macro.get(), _actionIndex - 1)) { if (!IsValidMacroSegmentIndex(macro.get(), _actionIndex - 1, false)) {
return false; return false;
} }
if (_type == Type::ACTION_DISABLED) { if (_type == Type::ACTION_DISABLED) {
@@ -127,16 +121,6 @@ bool MacroConditionMacro::CheckPauseState()
return macro->Paused(); return macro->Paused();
} }
bool MacroConditionMacro::CheckActionsPerformed()
{
auto macro = _macro.GetMacro();
if (!macro) {
return false;
}
return macro->WasExecutedSince(macro->LastConditionCheckTime());
}
bool MacroConditionMacro::CheckCountCondition() bool MacroConditionMacro::CheckCountCondition()
{ {
auto macro = _macro.GetMacro(); auto macro = _macro.GetMacro();
@@ -174,8 +158,6 @@ bool MacroConditionMacro::CheckCondition()
return CheckActionStateCondition(); return CheckActionStateCondition();
case Type::PAUSED: case Type::PAUSED:
return CheckPauseState(); return CheckPauseState();
case Type::ACTIONS_PERFORMED:
return CheckActionsPerformed();
default: default:
break; break;
} }
@@ -318,7 +300,6 @@ MacroConditionMacroEdit::MacroConditionMacroEdit(
_actionIndex(new MacroSegmentSelection( _actionIndex(new MacroSegmentSelection(
this, MacroSegmentSelection::Type::ACTION)) this, MacroSegmentSelection::Type::ACTION))
{ {
_macros->HideGroups();
_count->setMaximum(10000000); _count->setMaximum(10000000);
populateTypeSelection(_types); populateTypeSelection(_types);
populateCounterConditionSelection(_counterConditions); populateCounterConditionSelection(_counterConditions);
@@ -326,8 +307,7 @@ MacroConditionMacroEdit::MacroConditionMacroEdit(
QWidget::connect(_macros, SIGNAL(currentTextChanged(const QString &)), QWidget::connect(_macros, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(MacroChanged(const QString &))); this, SLOT(MacroChanged(const QString &)));
QWidget::connect(MacroSignalManager::Instance(), QWidget::connect(parent, SIGNAL(MacroRemoved(const QString &)), this,
SIGNAL(Remove(const QString &)), this,
SLOT(MacroRemove(const QString &))); SLOT(MacroRemove(const QString &)));
QWidget::connect(_types, SIGNAL(currentIndexChanged(int)), this, QWidget::connect(_types, SIGNAL(currentIndexChanged(int)), this,
SLOT(TypeChanged(int))); SLOT(TypeChanged(int)));
@@ -434,9 +414,6 @@ void MacroConditionMacroEdit::SetupWidgets()
case MacroConditionMacro::Type::PAUSED: case MacroConditionMacro::Type::PAUSED:
SetupPauseWidgets(); SetupPauseWidgets();
break; break;
case MacroConditionMacro::Type::ACTIONS_PERFORMED:
SetupActionsPerformedWidgets();
break;
default: default:
break; break;
} }
@@ -495,14 +472,6 @@ void MacroConditionMacroEdit::SetupPauseWidgets()
_settingsLine1, {{"{{macros}}", _macros}}); _settingsLine1, {{"{{macros}}", _macros}});
} }
void MacroConditionMacroEdit::SetupActionsPerformedWidgets()
{
PlaceWidgets(
obs_module_text(
"AdvSceneSwitcher.condition.macro.actionsPerformed.entry"),
_settingsLine1, {{"{{macros}}", _macros}});
}
void MacroConditionMacroEdit::SetWidgetVisibility() void MacroConditionMacroEdit::SetWidgetVisibility()
{ {
_macros->setVisible( _macros->setVisible(
@@ -512,9 +481,7 @@ void MacroConditionMacroEdit::SetWidgetVisibility()
MacroConditionMacro::Type::ACTION_DISABLED || MacroConditionMacro::Type::ACTION_DISABLED ||
_entryData->GetType() == _entryData->GetType() ==
MacroConditionMacro::Type::ACTION_ENABLED || MacroConditionMacro::Type::ACTION_ENABLED ||
_entryData->GetType() == MacroConditionMacro::Type::PAUSED || _entryData->GetType() == MacroConditionMacro::Type::PAUSED);
_entryData->GetType() ==
MacroConditionMacro::Type::ACTIONS_PERFORMED);
_counterConditions->setVisible(_entryData->GetType() == _counterConditions->setVisible(_entryData->GetType() ==
MacroConditionMacro::Type::COUNT); MacroConditionMacro::Type::COUNT);
_count->setVisible(_entryData->GetType() == _count->setVisible(_entryData->GetType() ==

View File

@@ -39,7 +39,6 @@ public:
ACTION_DISABLED, ACTION_DISABLED,
ACTION_ENABLED, ACTION_ENABLED,
PAUSED, PAUSED,
ACTIONS_PERFORMED,
}; };
void SetType(Type); void SetType(Type);
Type GetType() const { return _type; } Type GetType() const { return _type; }
@@ -67,7 +66,6 @@ private:
bool CheckMultiStateCondition(); bool CheckMultiStateCondition();
bool CheckActionStateCondition(); bool CheckActionStateCondition();
bool CheckPauseState(); bool CheckPauseState();
bool CheckActionsPerformed();
void SetupTempVars(); void SetupTempVars();
@@ -136,7 +134,6 @@ private:
void SetupCountWidgets(); void SetupCountWidgets();
void SetupActionStateWidgets(bool enable); void SetupActionStateWidgets(bool enable);
void SetupPauseWidgets(); void SetupPauseWidgets();
void SetupActionsPerformedWidgets();
void SetWidgetVisibility(); void SetWidgetVisibility();
bool _loading = true; bool _loading = true;
}; };

View File

@@ -6,15 +6,6 @@ namespace advss {
const std::string MacroConditionTempVar::id = "temp_var"; const std::string MacroConditionTempVar::id = "temp_var";
std::vector<TempVariableRef> MacroConditionTempVar::GetTempVarRefs() const
{
auto refs = MacroSegment::GetTempVarRefs();
if (_tempVar.HasValidID()) {
refs.push_back(_tempVar);
}
return refs;
}
bool MacroConditionTempVar::_registered = MacroConditionFactory::Register( bool MacroConditionTempVar::_registered = MacroConditionFactory::Register(
MacroConditionTempVar::id, MacroConditionTempVar::id,
{MacroConditionTempVar::Create, MacroConditionTempVarEdit::Create, {MacroConditionTempVar::Create, MacroConditionTempVarEdit::Create,
@@ -163,7 +154,7 @@ bool MacroConditionTempVar::CheckCondition()
bool MacroConditionTempVar::Save(obs_data_t *obj) const bool MacroConditionTempVar::Save(obs_data_t *obj) const
{ {
MacroCondition::Save(obj); MacroCondition::Save(obj);
_tempVar.Save(obj, GetMacro()); _tempVar.Save(obj);
obs_data_set_string(obj, "variableName", obs_data_set_string(obj, "variableName",
GetWeakVariableName(_variable2).c_str()); GetWeakVariableName(_variable2).c_str());
_strValue.Save(obj, "strValue"); _strValue.Save(obj, "strValue");
@@ -275,7 +266,6 @@ void MacroConditionTempVarEdit::VariableChanged(const TempVariableRef &var)
{ {
GUARD_LOADING_AND_LOCK(); GUARD_LOADING_AND_LOCK();
_entryData->_tempVar = var; _entryData->_tempVar = var;
IncrementTempVarInUseGeneration();
} }
void MacroConditionTempVarEdit::Variable2Changed(const QString &text) void MacroConditionTempVarEdit::Variable2Changed(const QString &text)

View File

@@ -20,7 +20,6 @@ public:
bool Load(obs_data_t *obj); bool Load(obs_data_t *obj);
std::string GetShortDesc() const; std::string GetShortDesc() const;
std::string GetId() const { return id; }; std::string GetId() const { return id; };
std::vector<TempVariableRef> GetTempVarRefs() const;
static std::shared_ptr<MacroCondition> Create(Macro *m) static std::shared_ptr<MacroCondition> Create(Macro *m)
{ {
return std::make_shared<MacroConditionTempVar>(m); return std::make_shared<MacroConditionTempVar>(m);

View File

@@ -1,7 +1,5 @@
#include "macro-condition.hpp" #include "macro-condition.hpp"
#include "condition-logic.hpp"
namespace advss { namespace advss {
MacroCondition::MacroCondition(Macro *m, bool supportsVariableValue) MacroCondition::MacroCondition(Macro *m, bool supportsVariableValue)
@@ -9,17 +7,6 @@ MacroCondition::MacroCondition(Macro *m, bool supportsVariableValue)
{ {
} }
bool MacroCondition::EvaluateCondition()
{
bool newValue = CheckCondition();
_changed = _previousValue.has_value() && (*_previousValue != newValue);
const bool negate = _logic.IsNegationType(GetLogicType());
_risingEdge = _changed &&
((!negate && newValue) || (negate && !newValue));
_previousValue = newValue;
return newValue;
}
bool MacroCondition::Save(obs_data_t *obj) const bool MacroCondition::Save(obs_data_t *obj) const
{ {
MacroSegment::Save(obj); MacroSegment::Save(obj);
@@ -33,10 +20,6 @@ bool MacroCondition::Load(obs_data_t *obj)
{ {
MacroSegment::Load(obj); MacroSegment::Load(obj);
_logic.Load(obj, "logic"); _logic.Load(obj, "logic");
if (_logic.GetType() == Logic::Type::NONE) {
SetEnabled(false);
_logic.SetType(Logic::Type::AND);
}
_durationModifier.Load(obj); _durationModifier.Load(obj);
return true; return true;
} }
@@ -56,8 +39,7 @@ void MacroCondition::ValidateLogicSelection(bool isRootCondition,
return; return;
} }
_logic.SetType(Logic::Type::AND); _logic.SetType(Logic::Type::NONE);
SetEnabled(false);
blog(LOG_WARNING, blog(LOG_WARNING,
"setting invalid logic selection to 'ignore' for macro %s", "setting invalid logic selection to 'ignore' for macro %s",
context); context);

View File

@@ -4,19 +4,13 @@
#include "duration-modifier.hpp" #include "duration-modifier.hpp"
#include "macro-ref.hpp" #include "macro-ref.hpp"
#include <optional>
namespace advss { namespace advss {
class EXPORT MacroCondition : public MacroSegment { class EXPORT MacroCondition : public MacroSegment {
public: public:
MacroCondition(Macro *m, bool supportsVariableValue = false); MacroCondition(Macro *m, bool supportsVariableValue = false);
virtual ~MacroCondition() = default; virtual ~MacroCondition() = default;
virtual bool CheckCondition() = 0;
bool EvaluateCondition();
bool HasChanged() const { return _changed; }
bool IsRisingEdge() const { return _risingEdge; }
virtual bool Save(obs_data_t *obj) const = 0; virtual bool Save(obs_data_t *obj) const = 0;
virtual bool Load(obs_data_t *obj) = 0; virtual bool Load(obs_data_t *obj) = 0;
@@ -34,15 +28,9 @@ public:
static std::string_view GetDefaultID(); static std::string_view GetDefaultID();
protected:
virtual bool CheckCondition() = 0;
private: private:
Logic _logic = Logic(Logic::Type::ROOT_NONE); Logic _logic = Logic(Logic::Type::ROOT_NONE);
DurationModifier _durationModifier; DurationModifier _durationModifier;
std::optional<bool> _previousValue;
bool _changed = false;
bool _risingEdge = false;
}; };
class EXPORT MacroRefCondition : virtual public MacroCondition { class EXPORT MacroRefCondition : virtual public MacroCondition {

View File

@@ -1,397 +0,0 @@
#include "macro-dock-settings.hpp"
#include "macro-dock-window.hpp"
#include "macro-dock.hpp"
#include "macro-helpers.hpp"
#include "macro.hpp"
#include "plugin-state-helpers.hpp"
#include "variable-string.hpp"
#include <obs-frontend-api.h>
#include <util/platform.h>
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(30, 0, 0)
#include <QDockWidget>
namespace {
struct DockMapEntry {
QAction *action = nullptr;
QWidget *dock = nullptr;
};
} // namespace
static std::unordered_map<const char *, DockMapEntry> dockIds;
static std::mutex dockMutex;
static bool obs_frontend_add_dock_by_id(const char *id, const char *title,
QWidget *widget)
{
std::lock_guard<std::mutex> lock(dockMutex);
if (dockIds.count(id) > 0) {
return false;
}
widget->setObjectName(id);
auto dock = new QDockWidget();
dock->setWindowTitle(title);
dock->setWidget(widget);
dock->setFloating(true);
dock->setVisible(false);
dock->setFeatures(QDockWidget::DockWidgetClosable |
QDockWidget::DockWidgetMovable |
QDockWidget::DockWidgetFloatable);
auto action = static_cast<QAction *>(obs_frontend_add_dock(dock));
if (!action) {
return false;
}
dockIds[id] = {action, dock};
return true;
}
static void obs_frontend_remove_dock(const char *id)
{
std::lock_guard<std::mutex> lock(dockMutex);
auto it = dockIds.find(id);
if (it == dockIds.end()) {
return;
}
it->second.action->deleteLater();
it->second.dock->deleteLater();
dockIds.erase(it);
}
#endif
namespace advss {
MacroDockSettings::MacroDockSettings(Macro *macro) : _macro(macro) {}
MacroDockSettings::~MacroDockSettings()
{
// Keep the dock widgets in case of shutdown so they can be restored by
// OBS on startup
if (!OBSIsShuttingDown()) {
RemoveDock();
}
}
void MacroDockSettings::Save(obs_data_t *obj, bool saveForCopy) const
{
OBSDataAutoRelease dockSettings = obs_data_create();
obs_data_set_bool(dockSettings, "register", _registerDock);
obs_data_set_bool(dockSettings, "standaloneDock", _standaloneDock);
obs_data_set_string(dockSettings, "dockWindow", _dockWindow.c_str());
obs_data_set_bool(dockSettings, "hasRunButton", _hasRunButton);
obs_data_set_bool(dockSettings, "hasPauseButton", _hasPauseButton);
obs_data_set_bool(dockSettings, "hasStatusLabel", _hasStatusLabel);
obs_data_set_bool(dockSettings, "highlightIfConditionsTrue",
_highlight);
_runButtonText.Save(dockSettings, "runButtonText");
_pauseButtonText.Save(dockSettings, "pauseButtonText");
_unpauseButtonText.Save(dockSettings, "unpauseButtonText");
_conditionsTrueStatusText.Save(dockSettings,
"conditionsTrueStatusText");
_conditionsFalseStatusText.Save(dockSettings,
"conditionsFalseStatusText");
if (saveForCopy) {
auto uuid = GenerateId();
obs_data_set_string(dockSettings, "dockId", uuid.c_str());
} else {
obs_data_set_string(dockSettings, "dockId", _id.c_str());
}
obs_data_set_int(dockSettings, "version", 1);
obs_data_set_obj(obj, "dockSettings", dockSettings);
}
void MacroDockSettings::Load(obs_data_t *obj)
{
OBSDataAutoRelease dockSettings = obs_data_get_obj(obj, "dockSettings");
if (!dockSettings) {
// TODO: Remove this fallback
_hasRunButton = obs_data_get_bool(obj, "dockHasRunButton");
_hasPauseButton = obs_data_get_bool(obj, "dockHasPauseButton");
_registerDock = obs_data_get_bool(obj, "registerDock");
ResetDockIfEnabled();
return;
}
_macroName = _macro->Name();
if (!obs_data_has_user_value(dockSettings, "version")) {
assert(_macro);
_id = std::string("ADVSS-") + _macroName;
} else {
_id = obs_data_get_string(dockSettings, "dockId");
}
_registerDock = obs_data_get_bool(dockSettings, "register");
// TODO: remove these default settings in a future version
obs_data_set_default_bool(dockSettings, "standaloneDock", true);
obs_data_set_default_string(dockSettings, "dockWindow", "Dock");
obs_data_set_default_string(
dockSettings, "runButtonText",
obs_module_text("AdvSceneSwitcher.macroDock.run"));
obs_data_set_default_string(
dockSettings, "pauseButtonText",
obs_module_text("AdvSceneSwitcher.macroDock.pause"));
obs_data_set_default_string(
dockSettings, "unpauseButtonText",
obs_module_text("AdvSceneSwitcher.macroDock.unpause"));
_standaloneDock = obs_data_get_bool(dockSettings, "standaloneDock");
_dockWindow = obs_data_get_string(dockSettings, "dockWindow");
_runButtonText.Load(dockSettings, "runButtonText");
_pauseButtonText.Load(dockSettings, "pauseButtonText");
_unpauseButtonText.Load(dockSettings, "unpauseButtonText");
_conditionsTrueStatusText.Load(dockSettings,
"conditionsTrueStatusText");
_conditionsFalseStatusText.Load(dockSettings,
"conditionsFalseStatusText");
if (_registerDock) {
_hasRunButton = obs_data_get_bool(dockSettings, "hasRunButton");
_hasPauseButton =
obs_data_get_bool(dockSettings, "hasPauseButton");
_hasStatusLabel =
obs_data_get_bool(dockSettings, "hasStatusLabel");
_highlight = obs_data_get_bool(dockSettings,
"highlightIfConditionsTrue");
}
ResetDockIfEnabled();
}
void MacroDockSettings::EnableDock(bool enable)
{
// Only apply "on change" to avoid recreation of the dock widget
if (_registerDock == enable) {
return;
}
RemoveDock();
if (!enable) {
_registerDock = enable;
return;
}
assert(_macro);
_macroName = _macro->Name();
_dock = new MacroDock(GetWeakMacroByName(_macroName.c_str()),
_runButtonText, _pauseButtonText,
_unpauseButtonText, _conditionsTrueStatusText,
_conditionsFalseStatusText, _highlight);
if (!_standaloneDock) {
auto window = GetDockWindowByName(_dockWindow);
if (!window) {
return;
}
window->AddMacroDock(_dock, QString::fromStdString(_macroName));
_registerDock = enable;
return;
}
if (!obs_frontend_add_dock_by_id(_id.c_str(), _macroName.c_str(),
_dock)) {
blog(LOG_INFO, "failed to add macro dock for macro %s",
_macroName.c_str());
_dock->deleteLater();
_dock = nullptr;
_registerDock = false;
return;
}
_registerDock = enable;
}
void MacroDockSettings::SetIsStandaloneDock(bool value)
{
if (_standaloneDock == value) {
return;
}
RemoveDock();
_standaloneDock = value;
ResetDockIfEnabled();
}
void MacroDockSettings::SetDockWindowName(const std::string &name)
{
if (_dockWindow == name) {
return;
}
RemoveDock();
_dockWindow = name;
ResetDockIfEnabled();
}
void MacroDockSettings::SetHasRunButton(bool value)
{
_hasRunButton = value;
if (!_dock) {
return;
}
_dock->ShowRunButton(value);
}
void MacroDockSettings::SetHasPauseButton(bool value)
{
_hasPauseButton = value;
if (!_dock) {
return;
}
_dock->ShowPauseButton(value);
}
void MacroDockSettings::SetHasStatusLabel(bool value)
{
_hasStatusLabel = value;
if (!_dock) {
return;
}
_dock->ShowStatusLabel(value);
}
void MacroDockSettings::SetHighlightEnable(bool value)
{
_highlight = value;
if (!_dock) {
return;
}
_dock->EnableHighlight(value);
}
void MacroDockSettings::SetRunButtonText(const std::string &text)
{
_runButtonText = text;
if (!_dock) {
return;
}
_dock->SetRunButtonText(text);
}
void MacroDockSettings::SetPauseButtonText(const std::string &text)
{
_pauseButtonText = text;
if (!_dock) {
return;
}
_dock->SetPauseButtonText(text);
}
void MacroDockSettings::SetUnpauseButtonText(const std::string &text)
{
_unpauseButtonText = text;
if (!_dock) {
return;
}
_dock->SetUnpauseButtonText(text);
}
void MacroDockSettings::SetConditionsTrueStatusText(const std::string &text)
{
_conditionsTrueStatusText = text;
if (!_dock) {
return;
}
_dock->SetConditionsTrueText(text);
}
StringVariable MacroDockSettings::ConditionsTrueStatusText() const
{
return _conditionsTrueStatusText;
}
void MacroDockSettings::SetConditionsFalseStatusText(const std::string &text)
{
_conditionsFalseStatusText = text;
if (!_dock) {
return;
}
_dock->SetConditionsFalseText(text);
}
StringVariable MacroDockSettings::ConditionsFalseStatusText() const
{
return _conditionsFalseStatusText;
}
void MacroDockSettings::HandleMacroNameChange()
{
const auto newName = _macro->Name();
if (!_standaloneDock) {
auto window = GetDockWindowByName(_dockWindow);
if (!window) {
return;
}
window->RenameMacro(_macroName, newName);
_macroName = newName;
return;
}
if (_macroName != newName) {
RemoveDock();
_id = GenerateId();
_macroName = newName;
}
ResetDockIfEnabled();
}
void MacroDockSettings::ResetDockIfEnabled()
{
if (_registerDock) {
_registerDock = false;
EnableDock(true);
}
}
void MacroDockSettings::RemoveDock()
{
if (_standaloneDock) {
obs_frontend_remove_dock(_id.c_str());
_dock = nullptr;
return;
}
auto window = GetDockWindowByName(_dockWindow);
if (window) {
window->RemoveMacroDock(_dock);
}
if (_dock) {
_dock = nullptr;
}
}
std::string MacroDockSettings::GenerateId()
{
#if LIBOBS_API_VER > MAKE_SEMANTIC_VERSION(30, 0, 0)
auto uuid = os_generate_uuid();
auto id = std::string("advss-macro-dock-") + std::string(uuid);
bfree(uuid);
return id;
#else
static std::atomic_int16_t idCounter = 0;
return std::to_string(++idCounter);
#endif
}
} // namespace advss

View File

@@ -1,76 +0,0 @@
#pragma once
#include "obs-module-helper.hpp"
#include "variable-string.hpp"
namespace advss {
class Macro;
class MacroDock;
class MacroDockSettings {
public:
MacroDockSettings(Macro *macro);
~MacroDockSettings();
void Save(obs_data_t *obj, bool saveForCopy) const;
void Load(obs_data_t *obj);
void EnableDock(bool);
bool DockEnabled() const { return _registerDock; }
bool IsStandaloneDock() const { return _standaloneDock; }
void SetIsStandaloneDock(bool value);
std::string DockWindowName() const { return _dockWindow; }
void SetDockWindowName(const std::string &name);
void SetHasRunButton(bool value);
bool HasRunButton() const { return _hasRunButton; }
void SetHasPauseButton(bool value);
bool HasPauseButton() const { return _hasPauseButton; }
void SetHasStatusLabel(bool value);
bool HasStatusLabel() const { return _hasStatusLabel; }
void SetHighlightEnable(bool value);
bool HighlightEnabled() const { return _highlight; }
StringVariable RunButtonText() const { return _runButtonText; }
void SetRunButtonText(const std::string &text);
StringVariable PauseButtonText() const { return _pauseButtonText; }
void SetPauseButtonText(const std::string &text);
StringVariable UnpauseButtonText() const { return _unpauseButtonText; }
void SetUnpauseButtonText(const std::string &text);
void SetConditionsTrueStatusText(const std::string &text);
StringVariable ConditionsTrueStatusText() const;
void SetConditionsFalseStatusText(const std::string &text);
StringVariable ConditionsFalseStatusText() const;
void HandleMacroNameChange();
private:
void ResetDockIfEnabled();
void RemoveDock();
static std::string GenerateId();
bool _registerDock = false;
bool _standaloneDock = true;
std::string _dockWindow = "Dock";
bool _hasRunButton = true;
bool _hasPauseButton = true;
bool _hasStatusLabel = false;
bool _highlight = false;
StringVariable _runButtonText =
obs_module_text("AdvSceneSwitcher.macroDock.run");
StringVariable _pauseButtonText =
obs_module_text("AdvSceneSwitcher.macroDock.pause");
StringVariable _unpauseButtonText =
obs_module_text("AdvSceneSwitcher.macroDock.unpause");
StringVariable _conditionsTrueStatusText =
obs_module_text("AdvSceneSwitcher.macroDock.statusLabel.true");
StringVariable _conditionsFalseStatusText =
obs_module_text("AdvSceneSwitcher.macroDock.statusLabel.false");
std::string _id = GenerateId();
std::string _macroName = "";
Macro *_macro = nullptr;
MacroDock *_dock = nullptr;
};
} // namespace advss

View File

@@ -1,170 +0,0 @@
#include "macro-dock-window.hpp"
#include "log-helper.hpp"
#include "plugin-state-helpers.hpp"
#include <obs-frontend-api.h>
#include <QDockWidget>
#include <QLayout>
#include <mutex>
namespace advss {
static std::unordered_map<std::string, MacroDockWindow *> windows;
static std::unordered_map<std::string, QByteArray> windowGeometries;
static std::mutex mutex;
static void saveDocks(obs_data_t *obj)
{
std::lock_guard<std::mutex> lock(mutex);
OBSDataAutoRelease data = obs_data_create();
OBSDataArrayAutoRelease array = obs_data_array_create();
for (const auto &[name, window] : windows) {
OBSDataAutoRelease dockData = obs_data_create();
obs_data_set_string(dockData, "name", name.c_str());
obs_data_set_string(dockData, "geometry",
window->GetWindow()
->saveState()
.toBase64()
.toStdString()
.c_str());
obs_data_array_push_back(array, dockData);
}
obs_data_set_array(data, "docks", array);
obs_data_set_obj(obj, "dockWindows", data);
}
static void restoreDockGeometry()
{
std::lock_guard<std::mutex> lock(mutex);
for (const auto &[name, dock] : windows) {
const auto it = windowGeometries.find(name);
if (it == windowGeometries.end()) {
continue;
}
dock->GetWindow()->restoreState(it->second);
}
}
static void loadDocks(obs_data_t *obj)
{
std::lock_guard<std::mutex> lock(mutex);
windowGeometries.clear();
OBSDataAutoRelease data = obs_data_get_obj(obj, "dockWindows");
OBSDataArrayAutoRelease array = obs_data_get_array(data, "docks");
auto size = obs_data_array_count(array);
for (size_t i = 0; i < size; ++i) {
OBSDataAutoRelease dockData = obs_data_array_item(array, i);
const auto name = obs_data_get_string(dockData, "name");
const auto geometry = QByteArray::fromBase64(
obs_data_get_string(dockData, "geometry"));
windowGeometries[name] = geometry;
}
AddPostLoadStep(restoreDockGeometry);
}
[[maybe_unused]] static bool _ = []() {
AddPluginInitStep([]() {
AddSaveStep(saveDocks);
AddLoadStep(loadDocks);
});
return true;
}();
MacroDockWindow::MacroDockWindow(const std::string &name)
: QFrame(),
_name(name),
_window(new QMainWindow())
{
setFrameShape(QFrame::StyledPanel);
setFrameShadow(QFrame::Sunken);
_window->setDockNestingEnabled(true);
auto layout = new QVBoxLayout;
layout->addWidget(_window);
setLayout(layout);
}
QWidget *MacroDockWindow::AddMacroDock(QWidget *widget, const QString &title)
{
auto dock = new QDockWidget();
dock->setWindowTitle(title);
dock->setWidget(widget);
dock->setVisible(true);
dock->setFeatures(QDockWidget::DockWidgetMovable);
dock->setObjectName(title);
_window->addDockWidget(Qt::RightDockWidgetArea, dock);
return dock;
}
void MacroDockWindow::RenameMacro(const std::string &oldName,
const std::string &newName)
{
auto docks = _window->findChildren<QDockWidget *>();
for (const auto dock : docks) {
if (dock->windowTitle() == QString::fromStdString(oldName)) {
dock->setWindowTitle(QString::fromStdString(newName));
break;
}
}
}
void MacroDockWindow::RemoveMacroDock(QWidget *widget)
{
bool removedDock = false;
auto docks = _window->findChildren<QDockWidget *>();
for (const auto dock : docks) {
if (dock->widget() == widget) {
_window->removeDockWidget(dock);
dock->deleteLater();
removedDock = true;
break;
}
}
if (OBSIsShuttingDown()) {
return;
}
const bool shouldRemoveDockWindow = docks.isEmpty() ||
(removedDock && docks.count() == 1);
if (!shouldRemoveDockWindow) {
return;
}
std::lock_guard<std::mutex> lock(mutex);
auto it = windows.find(_name);
if (it != windows.end()) {
windows.erase(it);
}
const auto id = "advss-dock-window-" + _name;
obs_frontend_remove_dock(id.c_str());
}
QMainWindow *MacroDockWindow::GetWindow() const
{
return _window;
}
MacroDockWindow *GetDockWindowByName(const std::string &name)
{
std::lock_guard<std::mutex> lock(mutex);
auto it = windows.find(name);
if (it != windows.end()) {
return it->second;
}
auto window = new MacroDockWindow(name);
const auto id = "advss-dock-window-" + name;
if (!obs_frontend_add_dock_by_id(id.c_str(), name.c_str(), window)) {
blog(LOG_INFO, "failed to add macro dock window '%s'",
id.c_str());
return nullptr;
}
windows[name] = window;
return window;
}
} // namespace advss

View File

@@ -1,29 +0,0 @@
#pragma once
#include <QFrame>
#include <QMainWindow>
#include <QWidget>
#include <string>
#include <vector>
namespace advss {
class MacroDockWindow : public QFrame {
Q_OBJECT
public:
MacroDockWindow(const std::string &name);
QWidget *AddMacroDock(QWidget *, const QString &title);
void RenameMacro(const std::string &oldName,
const std::string &newName);
void RemoveMacroDock(QWidget *);
QMainWindow *GetWindow() const;
private:
std::string _name;
QMainWindow *_window;
};
MacroDockWindow *GetDockWindowByName(const std::string &name);
} // namespace advss

View File

@@ -30,10 +30,9 @@ MacroDock::MacroDock(std::weak_ptr<Macro> m,
auto macro = _macro.lock(); auto macro = _macro.lock();
if (macro) { if (macro) {
const auto &settings = macro->GetDockSettings(); _run->setVisible(macro->DockHasRunButton());
_run->setVisible(settings.HasRunButton()); _pauseToggle->setVisible(macro->DockHasPauseButton());
_pauseToggle->setVisible(settings.HasPauseButton()); _statusText->setVisible(macro->DockHasStatusLabel());
_statusText->setVisible(settings.HasStatusLabel());
} }
QWidget::connect(_run, SIGNAL(clicked()), this, SLOT(RunClicked())); QWidget::connect(_run, SIGNAL(clicked()), this, SLOT(RunClicked()));
@@ -110,7 +109,7 @@ void MacroDock::RunClicked()
return; return;
} }
auto ret = macro->PerformActions(true, true, true); auto ret = macro->PerformActions(true);
if (!ret) { if (!ret) {
QString err = QString err =
obs_module_text("AdvSceneSwitcher.macroTab.runFail"); obs_module_text("AdvSceneSwitcher.macroTab.runFail");

File diff suppressed because it is too large Load Diff

View File

@@ -1,144 +0,0 @@
#pragma once
#include "condition-logic.hpp"
#include <ui_macro-edit.h>
namespace advss {
class Macro;
class MacroSegment;
class MacroEdit : public QWidget {
Q_OBJECT
public:
MacroEdit(QWidget *parent, QStringList helpMsg = {});
void SetMacro(const std::shared_ptr<Macro> &);
std::shared_ptr<Macro> GetMacro() const;
void ClearSegmentWidgetCacheFor(Macro *) const;
void SetControlsDisabled(bool disable) const;
void HighlightAction(int idx, QColor color = QColor(Qt::green)) const;
void HighlightElseAction(int idx,
QColor color = QColor(Qt::green)) const;
void HighlightCondition(int idx,
QColor color = QColor(Qt::green)) const;
void ResetConditionHighlights();
void ResetActionHighlights();
void SetActionData(Macro &m) const;
void SetElseActionData(Macro &m) const;
void SetConditionData(Macro &m) const;
void SwapActions(Macro *m, int pos1, int pos2);
void SwapElseActions(Macro *m, int pos1, int pos2);
void SwapConditions(Macro *m, int pos1, int pos2);
void CopyMacroSegment();
void PasteMacroSegment();
bool IsEmpty() const;
void ShowAllMacroSections();
void HideElseSection() const;
private slots:
void on_conditionAdd_clicked();
void on_conditionRemove_clicked();
void on_conditionTop_clicked();
void on_conditionUp_clicked();
void on_conditionDown_clicked();
void on_conditionBottom_clicked();
void on_actionAdd_clicked();
void on_actionRemove_clicked();
void on_actionTop_clicked();
void on_actionUp_clicked();
void on_actionDown_clicked();
void on_actionBottom_clicked();
void on_toggleElseActions_clicked() const;
void on_elseActionAdd_clicked();
void on_elseActionRemove_clicked();
void on_elseActionTop_clicked();
void on_elseActionUp_clicked();
void on_elseActionDown_clicked();
void on_elseActionBottom_clicked();
void UpMacroSegmentHotkey();
void DownMacroSegmentHotkey();
void DeleteMacroSegmentHotkey();
void ShowMacroActionsContextMenu(const QPoint &);
void ShowMacroElseActionsContextMenu(const QPoint &);
void ShowMacroConditionsContextMenu(const QPoint &);
void ExpandAllActions() const;
void ExpandAllElseActions() const;
void ExpandAllConditions() const;
void CollapseAllActions() const;
void CollapseAllElseActions() const;
void CollapseAllConditions() const;
void MinimizeActions() const;
void MaximizeActions() const;
void MinimizeElseActions() const;
void MaximizeElseActions() const;
void MinimizeConditions() const;
void MaximizeConditions() const;
void SetElseActionsStateToHidden() const;
void SetElseActionsStateToVisible() const;
void MacroActionSelectionChanged(int idx);
void MacroActionReorder(int to, int target);
void AddMacroAction(Macro *macro, int idx, const std::string &id,
obs_data_t *data);
void AddMacroAction(int idx);
void RemoveMacroAction(int idx);
void MoveMacroActionUp(int idx);
void MoveMacroActionDown(int idx);
void MacroElseActionSelectionChanged(int idx);
void MacroElseActionReorder(int to, int target);
void AddMacroElseAction(Macro *macro, int idx, const std::string &id,
obs_data_t *data);
void AddMacroElseAction(int idx);
void RemoveMacroElseAction(int idx);
void MoveMacroElseActionUp(int idx);
void MoveMacroElseActionDown(int idx);
void MacroConditionSelectionChanged(int idx);
void MacroConditionReorder(int to, int target);
void AddMacroCondition(int idx);
void AddMacroCondition(Macro *macro, int idx, const std::string &id,
obs_data_t *data, Logic::Type logic);
void RemoveMacroCondition(int idx);
void MoveMacroConditionUp(int idx);
void MoveMacroConditionDown(int idx);
void HighlightControls() const;
signals:
void MacroAdded(const QString &name);
void MacroRemoved(const QString &name);
void MacroRenamed(const QString &oldName, const QString &newName);
void MacroSegmentOrderChanged();
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
private:
enum class MacroSection { CONDITIONS, ACTIONS, ELSE_ACTIONS };
void PopulateMacroActions(Macro &m, uint32_t afterIdx = 0);
void PopulateMacroElseActions(Macro &m, uint32_t afterIdx = 0);
void PopulateMacroConditions(Macro &m, uint32_t afterIdx = 0);
void ScrollAndFocusNewSegment(MacroSegmentList *list, int newIdx,
int *currentIdx);
void SetupMacroSegmentSelection(MacroSection type, int idx);
void
SetupContextMenu(const QPoint &pos,
const std::function<void(MacroEdit *, int)> &remove,
const std::function<void(MacroEdit *)> &expand,
const std::function<void(MacroEdit *)> &collapse,
const std::function<void(MacroEdit *)> &maximize,
const std::function<void(MacroEdit *)> &minimize,
MacroSegmentList *list);
void RunSegmentHighlightChecks();
bool ElseSectionIsVisible() const;
MacroSection lastInteracted = MacroSection::CONDITIONS;
int currentConditionIdx = -1;
int currentActionIdx = -1;
int currentElseActionIdx = -1;
std::shared_ptr<Macro> _currentMacro;
std::unique_ptr<Ui_MacroEdit> ui;
};
} // namespace advss

View File

@@ -1,89 +0,0 @@
#include "macro-export-extensions.hpp"
#include "action-queue.hpp"
#include "variable.hpp"
#include <obs.hpp>
namespace advss {
static bool setup();
static bool setupDone = setup();
static bool setup()
{
// --- Variables ---
AddMacroExportExtension(
{"AdvSceneSwitcher.macroTab.export.variables", "variables",
[](obs_data_t *data, const QStringList &selectedIds) {
if (selectedIds.isEmpty()) {
SaveVariables(data);
return;
}
OBSDataArrayAutoRelease array =
obs_data_array_create();
for (const auto &v : GetVariables()) {
const QString name =
QString::fromStdString(v->Name());
if (!selectedIds.contains(name)) {
continue;
}
OBSDataAutoRelease item = obs_data_create();
v->Save(item);
obs_data_array_push_back(array, item);
}
obs_data_set_array(data, "variables", array);
},
[](obs_data_t *data, const QStringList &) {
ImportVariables(data);
},
[]() -> QList<QPair<QString, QString>> {
QList<QPair<QString, QString>> items;
for (const auto &v : GetVariables()) {
const QString name =
QString::fromStdString(v->Name());
items.append({name, name});
}
return items;
}});
// --- Action Queues ---
AddMacroExportExtension(
{"AdvSceneSwitcher.macroTab.export.actionQueues",
"actionQueues",
[](obs_data_t *data, const QStringList &selectedIds) {
if (selectedIds.isEmpty()) {
SaveActionQueues(data);
return;
}
OBSDataArrayAutoRelease array =
obs_data_array_create();
for (const auto &q : GetActionQueues()) {
const QString name =
QString::fromStdString(q->Name());
if (!selectedIds.contains(name)) {
continue;
}
OBSDataAutoRelease item = obs_data_create();
q->Save(item);
obs_data_array_push_back(array, item);
}
obs_data_set_array(data, "actionQueues", array);
},
[](obs_data_t *data, const QStringList &) {
ImportQueues(data);
},
[]() -> QList<QPair<QString, QString>> {
QList<QPair<QString, QString>> items;
for (const auto &q : GetActionQueues()) {
const QString name =
QString::fromStdString(q->Name());
items.append({name, name});
}
return items;
}});
return true;
}
} // namespace advss

View File

@@ -1,17 +0,0 @@
#include "macro-export-extensions.hpp"
namespace advss {
static std::vector<MacroExportExtension> extensions;
void AddMacroExportExtension(const MacroExportExtension &ext)
{
extensions.emplace_back(ext);
}
const std::vector<MacroExportExtension> &GetMacroExportExtensions()
{
return extensions;
}
} // namespace advss

View File

@@ -1,41 +0,0 @@
#pragma once
#include "export-symbol-helper.hpp"
#include <functional>
#include <obs-data.h>
#include <QList>
#include <QPair>
#include <QString>
#include <vector>
namespace advss {
struct MacroExportExtension {
const char *displayNameKey;
const char *jsonKey;
// Export callback.
// Write content into 'data'. 'selectedIds' contains the item IDs the
// user explicitly checked; if empty (no per-item widget provided) save
// everything.
std::function<void(obs_data_t *data, const QStringList &selectedIds)>
save;
// Import callback.
// Read content from 'data'. 'selectedIds' contains the item IDs the
// user explicitly checked; if empty import every item found in 'data'.
std::function<void(obs_data_t *data, const QStringList &selectedIds)>
load;
// Optional: enumerate items available for export as (id, displayName)
// pairs. When nullptr the extension appears as a single all-or-nothing
// checkbox in the export dialog.
std::function<QList<QPair<QString, QString>>()> getExportItems =
nullptr;
};
EXPORT void AddMacroExportExtension(const MacroExportExtension &ext);
const std::vector<MacroExportExtension> &GetMacroExportExtensions();
} // namespace advss

View File

@@ -1,183 +1,22 @@
#include "macro-export-import-dialog.hpp" #include "macro-export-import-dialog.hpp"
#include "macro-export-extensions.hpp"
#include "obs-module-helper.hpp" #include "obs-module-helper.hpp"
#include "section.hpp"
#include <obs.hpp> #include <obs.hpp>
#include <QDialogButtonBox>
#include <QLabel>
#include <QLayout> #include <QLayout>
#include <QScrollArea> #include <QLabel>
#include <QSplitter> #include <QDialogButtonBox>
#include <algorithm>
#include <numeric>
namespace advss { namespace advss {
static bool usePlainText = false; static bool usePlainText = false;
// --------------------------------------------------------------------------- MacroExportImportDialog::MacroExportImportDialog(Type type)
// Compress / decompress helpers
// ---------------------------------------------------------------------------
static QString compressMacroString(const QString &input)
{
QByteArray inputData = input.toUtf8();
auto compressedData = qCompress(inputData);
QByteArray encodedData = compressedData.toBase64();
return QString::fromUtf8(encodedData);
}
static QString decompressMacroString(const QString &input)
{
QByteArray encodedData = input.toUtf8();
QByteArray compressedData = QByteArray::fromBase64(encodedData);
auto outputData = qUncompress(compressedData);
return QString::fromUtf8(outputData);
}
static bool isValidData(const QString &json)
{
OBSDataAutoRelease data =
obs_data_create_from_json(json.toStdString().c_str());
return !!data;
}
// ---------------------------------------------------------------------------
// Extension section
// ---------------------------------------------------------------------------
QWidget *MacroExportImportDialog::BuildExtensionWidget()
{
auto wrapper = new QWidget(this);
auto wrapperLayout = new QVBoxLayout(wrapper);
wrapperLayout->setContentsMargins(0, 0, 0, 0);
wrapperLayout->setSpacing(4);
wrapperLayout->addWidget(new QLabel(obs_module_text(
"AdvSceneSwitcher.macroTab.export.additionalContent")));
auto outerContent = new QWidget();
auto outerLayout = new QVBoxLayout(outerContent);
outerLayout->setContentsMargins(4, 4, 4, 4);
outerLayout->setSpacing(4);
const auto &extensions = GetMacroExportExtensions();
std::vector<int> order(extensions.size());
std::iota(order.begin(), order.end(), 0);
std::sort(order.begin(), order.end(), [&](int a, int b) {
return QString::localeAwareCompare(
obs_module_text(extensions[a].displayNameKey),
obs_module_text(extensions[b].displayNameKey)) <
0;
});
for (int extIdx : order) {
const auto &ext = extensions[extIdx];
ExtensionUI ui;
// Simple all-or-nothing checkbox (no sub-items).
if (!ext.getExportItems) {
ui.mainCheck = new QCheckBox(
obs_module_text(ext.displayNameKey),
outerContent);
ui.mainCheck->setChecked(false);
connect(ui.mainCheck, &QCheckBox::stateChanged, this,
&MacroExportImportDialog::UpdateExportString);
outerLayout->addWidget(ui.mainCheck);
_extensionUIs.append(std::move(ui));
_extensionOrder.push_back(extIdx);
continue;
}
// Extensions with per-item selection get their own inner
// Section: the main checkbox sits in the header (next to the
// toggle arrow) and the per-item checkboxes live in the
// collapsible content area.
auto items = ext.getExportItems();
if (items.isEmpty()) {
continue;
}
std::sort(items.begin(), items.end(),
[](const QPair<QString, QString> &a,
const QPair<QString, QString> &b) {
return QString::localeAwareCompare(
a.second, b.second) < 0;
});
auto innerSection = new Section(200, outerContent);
ui.mainCheck =
new QCheckBox(obs_module_text(ext.displayNameKey));
ui.mainCheck->setChecked(false);
innerSection->AddHeaderWidget(ui.mainCheck);
auto subWidget = new QWidget();
auto subLayout = new QVBoxLayout(subWidget);
subLayout->setContentsMargins(4, 2, 4, 2);
subLayout->setSpacing(2);
for (const auto &[id, displayName] : items) {
auto cb = new QCheckBox(displayName, subWidget);
cb->setChecked(false);
subLayout->addWidget(cb);
ui.itemChecks.append({id, cb});
connect(cb, &QCheckBox::stateChanged, this,
&MacroExportImportDialog::UpdateExportString);
}
// Main checkbox toggles all sub-items.
// Capture uiIdx (position in _extensionUIs after append).
const int uiIdx = _extensionUIs.size();
connect(ui.mainCheck, &QCheckBox::stateChanged, this,
[this, uiIdx](int state) {
if (state == Qt::PartiallyChecked)
return;
const bool checked = (state == Qt::Checked);
if (uiIdx < _extensionUIs.size()) {
for (auto &[id, cb] :
_extensionUIs[uiIdx].itemChecks) {
QSignalBlocker b(cb);
cb->setChecked(checked);
}
}
UpdateExportString();
});
innerSection->SetContent(subWidget, true);
outerLayout->addWidget(innerSection);
_extensionUIs.append(std::move(ui));
_extensionOrder.push_back(extIdx);
}
outerLayout->addStretch();
auto scrollArea = new QScrollArea(wrapper);
scrollArea->setWidget(outerContent);
scrollArea->setWidgetResizable(true);
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
scrollArea->setFrameShape(QFrame::NoFrame);
wrapperLayout->addWidget(scrollArea);
return wrapper;
}
// ---------------------------------------------------------------------------
// Constructor
// ---------------------------------------------------------------------------
MacroExportImportDialog::MacroExportImportDialog(Type type,
const QString &baseJson)
: QDialog(nullptr), : QDialog(nullptr),
_baseJson(baseJson),
_importExportString(new QPlainTextEdit(this)), _importExportString(new QPlainTextEdit(this)),
_usePlainText(new QCheckBox(obs_module_text( _usePlainText(new QCheckBox(obs_module_text(
"AdvSceneSwitcher.macroTab.export.usePlainText"))) "AdvSceneSwitcher.macroTab.export.usePlainText")))
{ {
_importExportString->setReadOnly(type == Type::EXPORT_MACRO); _importExportString->setReadOnly(type == Type::EXPORT_MACRO);
auto label = new QLabel(obs_module_text( auto label = new QLabel(obs_module_text(
type == Type::EXPORT_MACRO type == Type::EXPORT_MACRO
? "AdvSceneSwitcher.macroTab.export.info" ? "AdvSceneSwitcher.macroTab.export.info"
@@ -200,90 +39,40 @@ MacroExportImportDialog::MacroExportImportDialog(Type type,
connect(_usePlainText, &QCheckBox::stateChanged, this, connect(_usePlainText, &QCheckBox::stateChanged, this,
&MacroExportImportDialog::UsePlainTextChanged); &MacroExportImportDialog::UsePlainTextChanged);
auto layout = new QVBoxLayout(this); auto layout = new QVBoxLayout;
layout->addWidget(label);
if (type == Type::EXPORT_MACRO && !GetMacroExportExtensions().empty()) { layout->addWidget(_importExportString);
auto splitter = new QSplitter(Qt::Vertical, this); layout->addWidget(_usePlainText);
splitter->setChildrenCollapsible(false);
splitter->addWidget(BuildExtensionWidget());
auto textWidget = new QWidget(splitter);
auto textLayout = new QVBoxLayout(textWidget);
textLayout->setContentsMargins(0, 0, 0, 0);
textLayout->addWidget(label);
textLayout->addWidget(_importExportString);
textLayout->addWidget(_usePlainText);
splitter->addWidget(textWidget);
layout->addWidget(splitter);
} else {
layout->addWidget(label);
layout->addWidget(_importExportString);
layout->addWidget(_usePlainText);
}
layout->addWidget(buttons); layout->addWidget(buttons);
setLayout(layout); setLayout(layout);
setWindowTitle(obs_module_text("AdvSceneSwitcher.windowTitle")); setWindowTitle(obs_module_text("AdvSceneSwitcher.windowTitle"));
if (type == Type::EXPORT_MACRO) {
RefreshExportText();
}
} }
// --------------------------------------------------------------------------- QString compressMacroString(const QString &input)
// Export string helpers
// ---------------------------------------------------------------------------
QString MacroExportImportDialog::BuildExportJson() const
{ {
OBSDataAutoRelease data = QByteArray inputData = input.toUtf8();
obs_data_create_from_json(_baseJson.toStdString().c_str()); auto compressedData = qCompress(inputData);
if (!data) { QByteArray encodedData = compressedData.toBase64();
return _baseJson; return QString::fromUtf8(encodedData);
}
const auto &extensions = GetMacroExportExtensions();
for (int i = 0; i < (int)_extensionUIs.size(); ++i) {
const auto &ui = _extensionUIs[i];
QStringList selectedIds;
if (ui.itemChecks.isEmpty()) {
if (!ui.mainCheck->isChecked()) {
continue;
}
} else {
for (const auto &[id, cb] : ui.itemChecks) {
if (cb->isChecked()) {
selectedIds << id;
}
}
if (selectedIds.isEmpty()) {
continue;
}
}
extensions[_extensionOrder[i]].save(data, selectedIds);
}
const char *json = obs_data_get_json(data);
return json ? QString::fromUtf8(json) : QString{};
} }
void MacroExportImportDialog::RefreshExportText() QString decompressMacroString(const QString &input)
{ {
const QString json = BuildExportJson(); QByteArray encodedData = input.toUtf8();
if (usePlainText) { QByteArray compressedData = QByteArray::fromBase64(encodedData);
_importExportString->setPlainText(json); auto outputData = qUncompress(compressedData);
} else { return QString::fromUtf8(outputData);
_importExportString->setPlainText(compressMacroString(json));
}
} }
void MacroExportImportDialog::UpdateExportString() void MacroExportImportDialog::ExportMacros(const QString &json)
{ {
RefreshExportText(); MacroExportImportDialog dialog(
MacroExportImportDialog::Type::EXPORT_MACRO);
dialog._importExportString->setPlainText(compressMacroString(json));
dialog.adjustSize();
dialog.updateGeometry();
dialog.exec();
} }
void MacroExportImportDialog::UsePlainTextChanged(int value) void MacroExportImportDialog::UsePlainTextChanged(int value)
@@ -301,45 +90,26 @@ void MacroExportImportDialog::UsePlainTextChanged(int value)
usePlainText = value; usePlainText = value;
} }
// --------------------------------------------------------------------------- static bool isValidData(const QString &json)
// Static entry points
// ---------------------------------------------------------------------------
void MacroExportImportDialog::ExportMacros(obs_data_t *macroData)
{ {
const char *rawJson = obs_data_get_json(macroData); OBSDataAutoRelease data =
const QString baseJson = rawJson ? QString::fromUtf8(rawJson) obs_data_create_from_json(json.toStdString().c_str());
: QString{}; return !!data;
MacroExportImportDialog dialog(Type::EXPORT_MACRO, baseJson);
dialog.adjustSize();
dialog.updateGeometry();
dialog.exec();
} }
bool MacroExportImportDialog::ImportMacros(QString &json) bool MacroExportImportDialog::ImportMacros(QString &json)
{ {
MacroExportImportDialog dialog(Type::IMPORT_MACRO); MacroExportImportDialog dialog(
if (dialog.exec() != QDialog::Accepted) { MacroExportImportDialog::Type::IMPORT_MACRO);
return false; if (dialog.exec() == QDialog::Accepted) {
} json = decompressMacroString(
dialog._importExportString->toPlainText());
json = decompressMacroString(dialog._importExportString->toPlainText()); if (!isValidData(json)) { // Fallback to support raw json format
if (!isValidData(json)) { json = dialog._importExportString->toPlainText();
// Fallback: support raw (uncompressed) JSON pasted directly.
json = dialog._importExportString->toPlainText();
}
// Invoke all extension load callbacks.
OBSDataAutoRelease data =
obs_data_create_from_json(json.toStdString().c_str());
if (data) {
for (const auto &ext : GetMacroExportExtensions()) {
ext.load(data, {});
} }
return true;
} }
return false;
return true;
} }
} // namespace advss } // namespace advss

View File

@@ -1,47 +1,25 @@
#pragma once #pragma once
#include <QCheckBox> #include <QCheckBox>
#include <QDialog> #include <QDialog>
#include <QList>
#include <QPlainTextEdit> #include <QPlainTextEdit>
#include <obs-data.h>
#include <vector>
namespace advss { namespace advss {
class MacroExportImportDialog : public QDialog { class MacroExportImportDialog : public QDialog {
Q_OBJECT Q_OBJECT
public: public:
enum class Type { EXPORT_MACRO, IMPORT_MACRO }; enum class Type { EXPORT_MACRO, IMPORT_MACRO };
MacroExportImportDialog(Type type);
static void ExportMacros(obs_data_t *macroData); static void ExportMacros(const QString &json);
static bool ImportMacros(QString &json); static bool ImportMacros(QString &json);
private slots: private slots:
void UsePlainTextChanged(int); void UsePlainTextChanged(int);
void UpdateExportString();
private: private:
explicit MacroExportImportDialog(Type type,
const QString &baseJson = {});
// Per-extension widgets
struct ExtensionUI {
QCheckBox *mainCheck = nullptr;
// (itemId, checkbox) pairs - empty when no per-item selection.
QList<QPair<QString, QCheckBox *>> itemChecks;
};
QWidget *BuildExtensionWidget();
QString BuildExportJson() const;
void RefreshExportText();
QString _baseJson;
QPlainTextEdit *_importExportString; QPlainTextEdit *_importExportString;
QCheckBox *_usePlainText; QCheckBox *_usePlainText;
QList<ExtensionUI> _extensionUIs;
std::vector<int> _extensionOrder;
}; };
} // namespace advss } // namespace advss

View File

@@ -1,6 +1,5 @@
#include "macro-helpers.hpp" #include "macro-helpers.hpp"
#include "macro.hpp" #include "macro.hpp"
#include "macro-action-macro.hpp"
#include "plugin-state-helpers.hpp" #include "plugin-state-helpers.hpp"
namespace advss { namespace advss {
@@ -9,87 +8,6 @@ static std::atomic_bool abortMacroWait = {false};
static std::atomic_bool macroSceneSwitched = {false}; static std::atomic_bool macroSceneSwitched = {false};
static std::atomic_int shutdownConditionCount = {0}; static std::atomic_int shutdownConditionCount = {0};
static void appendNestedMacros(std::deque<std::shared_ptr<Macro>> &macros,
Macro *macro)
{
if (!macro) {
return;
}
const auto iterate = [&macros](const std::deque<
std::shared_ptr<MacroAction>> &actions) {
for (const auto &action : actions) {
const auto nestedMacroAction =
dynamic_cast<MacroActionMacro *>(action.get());
if (!nestedMacroAction) {
continue;
}
macros.push_back(nestedMacroAction->_nestedMacro);
appendNestedMacros(
macros, nestedMacroAction->_nestedMacro.get());
}
};
iterate(macro->Actions());
iterate(macro->ElseActions());
}
std::deque<std::shared_ptr<Macro>> &GetTopLevelMacros()
{
static std::deque<std::shared_ptr<Macro>> macros;
return macros;
}
std::deque<std::shared_ptr<Macro>> &GetTemporaryMacros()
{
static std::deque<std::shared_ptr<Macro>> tempMacros;
return tempMacros;
}
std::deque<std::shared_ptr<Macro>> GetAllMacros()
{
auto macros = GetTopLevelMacros();
for (const auto &topLevelMacro : macros) {
appendNestedMacros(macros, topLevelMacro.get());
}
const auto &tempMacros = GetTemporaryMacros();
macros.insert(macros.end(), tempMacros.begin(), tempMacros.end());
for (const auto &tempMacro : tempMacros) {
appendNestedMacros(macros, tempMacro.get());
}
return macros;
}
Macro *GetMacroByName(const char *name)
{
for (const auto &m : GetTopLevelMacros()) {
if (m->Name() == name) {
return m.get();
}
}
return nullptr;
}
Macro *GetMacroByQString(const QString &name)
{
return GetMacroByName(name.toUtf8().constData());
}
std::weak_ptr<Macro> GetWeakMacroByName(const char *name)
{
for (const auto &m : GetTopLevelMacros()) {
if (m->Name() == name) {
return m;
}
}
return {};
}
std::optional<std::deque<std::shared_ptr<MacroAction>>> std::optional<std::deque<std::shared_ptr<MacroAction>>>
GetMacroActions(Macro *macro) GetMacroActions(Macro *macro)
{ {
@@ -99,15 +17,6 @@ GetMacroActions(Macro *macro)
return macro->Actions(); return macro->Actions();
} }
std::optional<std::deque<std::shared_ptr<MacroAction>>>
GetMacroElseActions(Macro *macro)
{
if (!macro) {
return {};
}
return macro->ElseActions();
}
std::optional<std::deque<std::shared_ptr<MacroCondition>>> std::optional<std::deque<std::shared_ptr<MacroCondition>>>
GetMacroConditions(Macro *macro) GetMacroConditions(Macro *macro)
{ {
@@ -117,32 +26,9 @@ GetMacroConditions(Macro *macro)
return macro->Conditions(); return macro->Conditions();
} }
bool IsGroupMacro(Macro *macro) std::string_view GetSceneSwitchActionId()
{ {
return macro && macro->IsGroup(); return MacroAction::GetDefaultID();
}
std::vector<std::shared_ptr<Macro>> GetGroupMacroEntries(Macro *macro)
{
if (!macro || !macro->IsGroup()) {
return {};
}
std::vector<std::shared_ptr<Macro>> entries;
entries.reserve(macro->GroupSize());
const auto &macros = GetTopLevelMacros();
for (auto it = macros.begin(); it < macros.end(); it++) {
if ((*it)->Name() != macro->Name()) {
continue;
}
for (uint32_t i = 1; i <= macro->GroupSize(); i++) {
entries.emplace_back(*std::next(it, i));
}
break;
}
return entries;
} }
std::condition_variable &GetMacroWaitCV() std::condition_variable &GetMacroWaitCV()
@@ -214,20 +100,6 @@ bool MacroIsPaused(const Macro *macro)
return macro ? macro->Paused() : true; return macro ? macro->Paused() : true;
} }
void SetMacroPaused(Macro *macro, bool paused)
{
if (macro) {
macro->SetPaused(paused);
}
}
void StopMacro(Macro *macro)
{
if (macro) {
macro->Stop();
}
}
bool MacroWasPausedSince( bool MacroWasPausedSince(
const Macro *macro, const Macro *macro,
const std::chrono::high_resolution_clock::time_point &time) const std::chrono::high_resolution_clock::time_point &time)
@@ -251,20 +123,9 @@ void AddMacroHelperThread(Macro *macro, std::thread &&newThread)
macro->AddHelperThread(std::move(newThread)); macro->AddHelperThread(std::move(newThread));
} }
bool RunMacroActions(Macro *macro, bool forceParallel, bool ignorePause) bool RunMacroActions(Macro *macro)
{ {
return macro && macro->PerformActions(true, forceParallel, ignorePause); return macro && macro->PerformActions(true);
}
bool RunMacroElseActions(Macro *macro, bool forceParallel, bool ignorePause)
{
return macro &&
macro->PerformActions(false, forceParallel, ignorePause);
}
bool CheckMacroConditions(Macro *macro, bool ignorePause)
{
return macro && macro->CheckConditions(ignorePause);
} }
void ResetMacroConditionTimers(Macro *macro) void ResetMacroConditionTimers(Macro *macro)
@@ -283,42 +144,20 @@ void ResetMacroRunCount(Macro *macro)
macro->ResetRunCount(); macro->ResetRunCount();
} }
bool IsValidActionIndex(const Macro *m, const int idx) bool IsValidMacroSegmentIndex(const Macro *m, const int idx, bool isCondition)
{ {
if (!m || idx < 0) { if (!m || idx < 0) {
return false; return false;
} }
if (isCondition) {
if (idx >= (int)m->Actions().size()) { if (idx >= (int)m->Conditions().size()) {
return false; return false;
}
} else {
if (idx >= (int)m->Actions().size()) {
return false;
}
} }
return true;
}
bool IsValidElseActionIndex(const Macro *m, const int idx)
{
if (!m || idx < 0) {
return false;
}
if (idx >= (int)m->ElseActions().size()) {
return false;
}
return true;
}
bool IsValidConditionIndex(const Macro *m, const int idx)
{
if (!m || idx < 0) {
return false;
}
if (idx >= (int)m->Conditions().size()) {
return false;
}
return true; return true;
} }

View File

@@ -1,13 +1,12 @@
#pragma once #pragma once
#include "export-symbol-helper.hpp" #include "export-symbol-helper.hpp"
#include <QString>
#include <atomic> #include <atomic>
#include <chrono> #include <chrono>
#include <condition_variable> #include <condition_variable>
#include <deque> #include <deque>
#include <optional> #include <optional>
#include <string_view>
#include <thread> #include <thread>
struct obs_data; struct obs_data;
@@ -19,25 +18,16 @@ class Macro;
class MacroAction; class MacroAction;
class MacroCondition; class MacroCondition;
static const int macro_func = 10; EXPORT std::deque<std::shared_ptr<Macro>> &GetMacros();
EXPORT std::deque<std::shared_ptr<Macro>> &GetTopLevelMacros();
std::deque<std::shared_ptr<Macro>> &GetTemporaryMacros();
EXPORT std::deque<std::shared_ptr<Macro>> GetAllMacros();
Macro *GetMacroByName(const char *name);
Macro *GetMacroByQString(const QString &name);
std::weak_ptr<Macro> GetWeakMacroByName(const char *name);
EXPORT std::optional<std::deque<std::shared_ptr<MacroAction>>> EXPORT std::optional<std::deque<std::shared_ptr<MacroAction>>>
GetMacroActions(Macro *); GetMacroActions(Macro *);
EXPORT std::optional<std::deque<std::shared_ptr<MacroAction>>>
GetMacroElseActions(Macro *);
EXPORT std::optional<std::deque<std::shared_ptr<MacroCondition>>> EXPORT std::optional<std::deque<std::shared_ptr<MacroCondition>>>
GetMacroConditions(Macro *); GetMacroConditions(Macro *);
EXPORT bool IsGroupMacro(Macro *); std::string_view GetSceneSwitchActionId();
EXPORT std::vector<std::shared_ptr<Macro>> GetGroupMacroEntries(Macro *);
constexpr auto macro_func = 10;
EXPORT std::condition_variable &GetMacroWaitCV(); EXPORT std::condition_variable &GetMacroWaitCV();
EXPORT std::condition_variable &GetMacroTransitionCV(); EXPORT std::condition_variable &GetMacroTransitionCV();
@@ -58,8 +48,6 @@ LastMacroConditionCheckTime(const Macro *);
EXPORT bool MacroIsStopped(const Macro *); EXPORT bool MacroIsStopped(const Macro *);
EXPORT bool MacroIsPaused(const Macro *); EXPORT bool MacroIsPaused(const Macro *);
EXPORT void SetMacroPaused(Macro *, bool paused);
EXPORT void StopMacro(Macro *);
EXPORT bool EXPORT bool
MacroWasPausedSince(const Macro *, MacroWasPausedSince(const Macro *,
const std::chrono::high_resolution_clock::time_point &); const std::chrono::high_resolution_clock::time_point &);
@@ -68,16 +56,10 @@ EXPORT bool MacroWasCheckedSinceLastStart(const Macro *);
EXPORT void AddMacroHelperThread(Macro *, std::thread &&); EXPORT void AddMacroHelperThread(Macro *, std::thread &&);
EXPORT bool CheckMacros(); EXPORT bool CheckMacros();
EXPORT bool CheckMacroConditions(Macro *, bool ignorePause = false);
EXPORT bool RunMacroActions(Macro *, bool forceParallel = false, EXPORT bool RunMacroActions(Macro *);
bool ignorePause = false);
EXPORT bool RunMacroElseActions(Macro *, bool forceParallel = false,
bool ignorePause = false);
EXPORT bool RunMacros(); EXPORT bool RunMacros();
void StopAllMacros();
void SignalStopAllMacros();
void WaitForAllMacros();
EXPORT void LoadMacros(obs_data_t *obj); EXPORT void LoadMacros(obs_data_t *obj);
EXPORT void SaveMacros(obs_data_t *obj); EXPORT void SaveMacros(obs_data_t *obj);
@@ -86,8 +68,6 @@ EXPORT void InvalidateMacroTempVarValues();
EXPORT void ResetMacroConditionTimers(Macro *); EXPORT void ResetMacroConditionTimers(Macro *);
EXPORT void ResetMacroRunCount(Macro *); EXPORT void ResetMacroRunCount(Macro *);
bool IsValidActionIndex(const Macro *m, const int idx); bool IsValidMacroSegmentIndex(const Macro *m, const int idx, bool isCondition);
bool IsValidElseActionIndex(const Macro *m, const int idx);
bool IsValidConditionIndex(const Macro *m, const int idx);
} // namespace advss } // namespace advss

View File

@@ -1,7 +1,6 @@
#include "macro-list.hpp" #include "macro-list.hpp"
#include "macro-helpers.hpp" #include "macro-helpers.hpp"
#include "macro-selection.hpp" #include "macro-selection.hpp"
#include "macro-signals.hpp"
#include "obs-module-helper.hpp" #include "obs-module-helper.hpp"
#include "ui-helpers.hpp" #include "ui-helpers.hpp"
@@ -11,11 +10,11 @@ MacroList::MacroList(QWidget *parent, bool allowDuplicates, bool reorder)
: ListEditor(parent, reorder), : ListEditor(parent, reorder),
_allowDuplicates(allowDuplicates) _allowDuplicates(allowDuplicates)
{ {
QWidget::connect(MacroSignalManager::Instance(), QWidget::connect(window(),
SIGNAL(Rename(const QString &, const QString &)), this, SIGNAL(MacroRenamed(const QString &, const QString &)),
this,
SLOT(MacroRename(const QString &, const QString &))); SLOT(MacroRename(const QString &, const QString &)));
QWidget::connect(MacroSignalManager::Instance(), QWidget::connect(window(), SIGNAL(MacroRemoved(const QString &)), this,
SIGNAL(Remove(const QString &)), this,
SLOT(MacroRemove(const QString &))); SLOT(MacroRemove(const QString &)));
UpdateListSize(); UpdateListSize();
} }

View File

@@ -1,8 +1,5 @@
#include "macro-ref.hpp" #include "macro-ref.hpp"
#include "macro-helpers.hpp"
#include "macro.hpp" #include "macro.hpp"
#include "plugin-state-helpers.hpp"
namespace advss { namespace advss {
@@ -22,7 +19,6 @@ void MacroRef::Load(obs_data_t *obj)
auto name = obs_data_get_string(obj, "macro"); auto name = obs_data_get_string(obj, "macro");
_postLoadName = name; _postLoadName = name;
_macro = GetWeakMacroByName(name); _macro = GetWeakMacroByName(name);
AddPostLoadStep([this]() { MacroRef::PostLoad(); });
} }
void MacroRef::PostLoad() void MacroRef::PostLoad()
@@ -75,11 +71,11 @@ void LoadMacroList(obs_data_t *obj, std::vector<MacroRef> &macros,
{ {
obs_data_array_t *array = obs_data_get_array(obj, name.c_str()); obs_data_array_t *array = obs_data_get_array(obj, name.c_str());
size_t count = obs_data_array_count(array); size_t count = obs_data_array_count(array);
macros.reserve(macros.size() + count);
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
obs_data_t *array_obj = obs_data_array_item(array, i); obs_data_t *array_obj = obs_data_array_item(array, i);
macros.emplace_back(); MacroRef ref;
macros.back().Load(array_obj); ref.Load(array_obj);
macros.push_back(ref);
obs_data_release(array_obj); obs_data_release(array_obj);
} }
obs_data_array_release(array); obs_data_array_release(array);

Some files were not shown because too many files have changed in this diff Show More