Compare commits

..

No commits in common. "master" and "1.28.0-beta1" have entirely different histories.

442 changed files with 14965 additions and 39821 deletions

View File

@ -6,6 +6,15 @@
"autosort": true
},
"additional_commands": {
"find_qt": {
"flags": [],
"kwargs": {
"COMPONENTS": "+",
"COMPONENTS_WIN": "+",
"COMPONENTS_MACOS": "+",
"COMPONENTS_LINUX": "+"
}
},
"set_target_properties_obs": {
"pargs": 1,
"flags": [],

View File

@ -20,7 +20,6 @@ body:
- macOS 13
- macOS 12
- macOS 11
- Ubuntu 24.04
- Ubuntu 23.10
- Ubuntu 22.04
- Other

View File

@ -2,7 +2,7 @@
# https://github.com/obsproject/.github/tree/master/.github/ISSUE_TEMPLATE
name: Feature request
description: Suggest an idea for this project
description: Suggest an idea for this projectReport a bug or crash
body:
- type: markdown
id: md_welcome

View File

@ -22,7 +22,7 @@ runs:
- name: Setup cmake
uses: jwlawson/actions-setup-cmake@v1.13
with:
cmake-version: '3.x.x'
cmake-version: '3.24.x'
- name: Restore cached dependencies
id: restore-cache

View File

@ -9,10 +9,5 @@ package 'libxtst-dev'
package 'libxss-dev'
package 'libopencv-dev'
package 'libtesseract-dev'
package 'libproc2-dev'
package 'libusb-1.0-0-dev'
package 'libpaho-mqttpp-dev'
package 'libpaho-mqtt-dev'
package 'libpaho-mqtt-dev'
package 'libasound2-dev'
package 'libpipewire-0.3-dev'
package 'libprocps-dev'
package 'libusb-1.0-0-dev'

View File

@ -394,11 +394,8 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
popd
pushd ${advss_dep_path}
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
git clone https://github.com/openssl/openssl.git --branch openssl-3.1.2 --depth 1
mv openssl openssl_x86
@ -406,27 +403,25 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
log_info "Building openssl x86 ..."
export MACOSX_DEPLOYMENT_TARGET=10.9
pushd openssl_x86
./Configure darwin64-x86_64-cc no-shared no-module no-zlib --prefix=${advss_dep_path}
make -j$(nproc)
popd
cd openssl_x86
./Configure darwin64-x86_64-cc shared
make
log_info "Building openssl arm ..."
export MACOSX_DEPLOYMENT_TARGET=10.15
pushd openssl_arm
./Configure enable-rc5 darwin64-arm64-cc no-shared no-module no-asm no-zlib --prefix=${advss_dep_path}
make -j$(nproc)
log_info "Install openssl ..."
make install
popd
cd ../openssl_arm
./Configure enable-rc5 zlib darwin64-arm64-cc no-asm
make
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
lipo -create openssl_x86/libssl.a openssl_arm/libssl.a -output ${advss_dep_path}/lib/libssl.a
cd ..
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 ..."
rm -rf openssl_x86 openssl_arm
mv openssl_x86 openssl
rm -rf openssl_arm
popd
pushd ${project_root}/deps/libusb
@ -444,16 +439,14 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
mkdir ${project_root}/deps/libusb/out_x86
./autogen.sh
./configure --host=x86_64-apple-darwin --prefix=${advss_dep_path}
make -j$(nproc)
make install
make && make install
log_info "Configure libusb arm ..."
make clean
rm -r ${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
make -j$(nproc)
make install
make && make install
log_info "Building libusb arm ..."
make clean
@ -466,8 +459,7 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
export MACOSX_DEPLOYMENT_TARGET=10.15
mkdir ${project_root}/deps/libusb/out_arm
./configure --host=aarch64-apple-darwin --prefix=${project_root}/deps/libusb/out_arm
make -j$(nproc)
make install
make && make install
log_info "Combine arm and x86 libusb binaries ..."
lipo -create ${project_root}/deps/libusb/out_x86/lib/libusb-1.0.0.dylib \
@ -486,36 +478,14 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
unset MACOSX_DEPLOYMENT_TARGET
popd
local mqtt_dir="${project_root}/deps/paho.mqtt.cpp"
local mqtt_build_dir="${mqtt_dir}/build_${target##*-}"
local -a mqtt_cmake_args=(
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_OSX_ARCHITECTURES=${${target##*-}//universal/x86_64;arm64}
-DCMAKE_OSX_DEPLOYMENT_TARGET=${DEPLOYMENT_TARGET:-10.15}
-DCMAKE_PREFIX_PATH="${advss_dep_path};${_plugin_deps}"
-DCMAKE_INSTALL_PREFIX="${advss_dep_path}"
-DPAHO_BUILD_SHARED=OFF
-DPAHO_BUILD_STATIC=ON
-DPAHO_WITH_MQTT_C=ON
-DPAHO_WITH_SSL=ON
-DOPENSSL_USE_STATIC_LIBS=ON
)
pushd ${mqtt_dir}
log_info "Configure paho.mqtt.cpp ..."
cmake -S . -B ${mqtt_build_dir} ${mqtt_cmake_args}
log_info "Building paho.mqtt.cpp ..."
cmake --build ${mqtt_build_dir} --config Release
log_info "Installing paho.mqtt.cpp ..."
cmake --install ${mqtt_build_dir} --prefix "${advss_dep_path}" --config Release
popd
;;
linux)
# Nothing to do for now
# Hacky workaround to support libproc2 with Ubuntu 22 build environment
local lsb_version=$(lsb_release -r | cut -f 2 || true)
if [[ "${lsb_version}" == '22.04' ]] {
sudo apt install ${project_root}/build-aux/CI/linux/ubuntu22/libproc2-0_4.0.2-3_amd64.deb
sudo apt install ${project_root}/build-aux/CI/linux/ubuntu22/libproc2-dev_4.0.2-3_amd64.deb
}
;;
}
}

View File

@ -253,8 +253,12 @@ ${_usage_host:-}"
macos-*)
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+=(
-DCMAKE_PREFIX_PATH="${advss_deps_path}"
-DOPENSSL_INCLUDE_DIR="${openssl_include_dir}"
-DOPENSSL_LIBRARIES="${openssl_lib_dir}/libcrypto.a;${openssl_lib_dir}/libssl.a"
--preset ${_preset}
)

View File

@ -258,9 +258,6 @@ ${_usage_host:-}"
pushd ${project_root}
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)'
if [ ! -e ${project_root}/release/${output_name}.deb ]; then
mv ${project_root}/release/*.deb ${project_root}/release/${output_name}.deb
mv ${project_root}/release/*.ddeb ${project_root}/release/${output_name}.ddeb

View File

@ -209,9 +209,7 @@ function Build {
$msbuildExe = vswhere -latest -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe | select-object -first 1
if ($msbuildExe) {
$env:CL="/wd5287"
Invoke-External $msbuildExe "${LibusbPath}/msvc/libusb.sln" /property:Configuration=Release /property:Platform=x64
Remove-Item Env:CL
$libusbBuildResultDirectory = "${LibusbPath}/build/v143/x64/Release"
if (-not (Test-Path -Path $libusbBuildResultDirectory)) {
@ -221,53 +219,6 @@ function Build {
} else {
Log-Information "Failed to locate msbuild.exe - skipping libusb build"
}
Push-Location -Stack BuildMqttTemp
Ensure-Location $ProjectRoot
$MqttPath = "${ProjectRoot}/deps/paho.mqtt.cpp"
$MqttBuildPath = "${MqttPath}/build"
# Explicitly disable PkgConfig and tiff as it will lead build errors
$MqttCmakeArgs = @(
"-DCMAKE_BUILD_TYPE=${Configuration}"
"-DCMAKE_PREFIX_PATH:PATH=${OBSDepPath}"
"-DCMAKE_INSTALL_PREFIX:PATH=${ADVSSDepPath}"
"-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..."
Invoke-External cmake -S ${MqttPath} -B ${MqttBuildPath} @MqttCmakeArgs
$MqttCmakeArgs = @(
'--config', "${Configuration}"
)
if ( $VerbosePreference -eq 'Continue' ) {
$MqttCmakeArgs += ('--verbose')
}
Log-Information "Building paho.mqtt.cpp..."
Invoke-External cmake --build "${MqttBuildPath}" @MqttCmakeArgs
Log-Information "Install paho.mqtt.cpp..."
Invoke-External cmake --install "${MqttBuildPath}" --prefix "${ADVSSDepPath}" @MqttCmakeArgs
}
Build

View File

@ -18,7 +18,5 @@ if (( ! ${+commands[brew]} )) {
}
brew bundle --file ${SCRIPT_HOME}/.Brewfile
# Workaround to make sure locally built openssl is picked up by cmake
brew uninstall --ignore-dependencies openssl@3 || true
rehash || true
rehash
log_group

View File

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

View File

@ -41,7 +41,6 @@ if (( ! (${skips[(Ie)all]} + ${skips[(Ie)deps]}) )) {
sudo apt-get install ${apt_args} \
build-essential \
libgles2-mesa-dev \
libsimde-dev \
obs-studio
local -a _qt_packages=()

0
.github/test vendored Normal file
View File

View File

@ -43,7 +43,7 @@ jobs:
# devscripts and libobs-dev are needed but they were already installed
# from check_libobs_revision and install_frontend_header sections.
sudo apt update
sudo apt install build-essential cmake debhelper libcurl4-openssl-dev libxss-dev libxtst-dev qt6-base-dev libopencv-dev libproc2-dev
sudo apt install cmake debhelper libcurl4-openssl-dev libxss-dev libxtst-dev qtbase5-dev libopencv-dev libprocps-dev
- name: build
run: |
debuild --no-lintian --no-sign

View File

@ -6,11 +6,11 @@ on:
description: "Project name detected by parsing build spec file"
value: ${{ jobs.check-event.outputs.pluginName }}
env:
DEP_DIR: .deps/advss-build-dependencies-3
DEP_DIR: .deps/advss-build-dependencies
jobs:
check-event:
name: Check GitHub Event Data 🔎
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
defaults:
run:
shell: bash
@ -75,7 +75,7 @@ jobs:
macos-build:
name: Build for macOS 🍏
runs-on: macos-15
runs-on: macos-14
needs: check-event
defaults:
run:
@ -107,8 +107,8 @@ jobs:
print "pluginName=${product_name}" >> $GITHUB_OUTPUT
print "pluginVersion=${git_tag}" >> $GITHUB_OUTPUT
print '::group::Enable Xcode 16.1'
sudo xcode-select --switch /Applications/Xcode_16.1.0.app/Contents/Developer
print '::group::Enable Xcode 15.2'
sudo xcode-select --switch /Applications/Xcode_15.2.app/Contents/Developer
print '::endgroup::'
- uses: actions/cache@v4
@ -177,7 +177,7 @@ jobs:
ubuntu-build:
name: Build for Ubuntu 🐧
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
needs: check-event
defaults:
run:
@ -210,11 +210,6 @@ jobs:
restore-keys: |
${{ runner.os }}-ccache-x86_64-
- name: Set up CMake 🏗️
uses: jwlawson/actions-setup-cmake@v1.13
with:
cmake-version: '3.x.x'
- name: Set up Homebrew 🍺
uses: Homebrew/actions/setup-homebrew@master
@ -246,14 +241,14 @@ jobs:
- name: Upload Artifacts 📡
uses: actions/upload-artifact@v4
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-22.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@v4
if: ${{ fromJSON(needs.check-event.outputs.package) }}
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-22.04-x86_64-${{ needs.check-event.outputs.commitHash }}-dbgsym
path: ${{ github.workspace }}/release/${{ steps.setup.outputs.pluginName }}-*-x86_64*-dbgsym.ddeb
windows-build:

View File

@ -3,7 +3,7 @@ on:
workflow_call:
jobs:
clang-format:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
with:
@ -15,7 +15,7 @@ jobs:
failCondition: error
cmake-format:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
with:

View File

@ -31,7 +31,7 @@ jobs:
create-release:
name: Create Release 🛫
if: github.ref_type == 'tag'
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
needs: build-project
defaults:
run:
@ -77,7 +77,7 @@ jobs:
variants=(
'windows-x64;zip|exe'
'macos-universal;tar.xz|pkg'
'ubuntu-24.04-x86_64;tar.xz|deb|ddeb'
'ubuntu-22.04-x86_64;tar.xz|deb|ddeb'
'sources;tar.xz'
)

9
.gitmodules vendored
View File

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

View File

@ -6,18 +6,18 @@ You have the option to ...
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)
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
```
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)
```

View File

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.21...3.26)
cmake_minimum_required(VERSION 3.16...3.26)
project(advanced-scene-switcher VERSION 1.0.0)
@ -20,12 +20,6 @@ if(BUILD_OUT_OF_TREE)
include(helpers)
endif()
# OBS 31 no longer defines find_qt so check if we need to include it for in-tree
# builds
if(NOT COMMAND find_qt)
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/common/helpers_common.cmake")
endif()
set(LIB_NAME "${PROJECT_NAME}-lib")
add_library(${PROJECT_NAME} MODULE)
add_library(${LIB_NAME} SHARED)
@ -33,16 +27,6 @@ add_library(${LIB_NAME} SHARED)
include(cmake/common/get_git_revision_description.cmake)
get_git_head_revision(GIT_REFSPEC GIT_SHA1)
git_describe(GIT_TAG)
# Helper for OpenSSL
if(OS_WINDOWS)
include(cmake/windows/wingetssl.cmake)
endif()
if(${GIT_TAG} STREQUAL "GIT-NOTFOUND")
set(GIT_TAG ${PROJECT_VERSION})
endif()
message(STATUS "${PROJECT_NAME} version: ${GIT_TAG}")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/common/version.cpp.in"
"${CMAKE_CURRENT_BINARY_DIR}/lib/version.cpp" @ONLY)
@ -108,6 +92,8 @@ target_sources(
lib/macro/macro-action-macro.hpp
lib/macro/macro-action-queue.cpp
lib/macro/macro-action-queue.hpp
lib/macro/macro-action-script.cpp
lib/macro/macro-action-script.hpp
lib/macro/macro-action-variable.cpp
lib/macro/macro-action-variable.hpp
lib/macro/macro-action.cpp
@ -120,6 +106,8 @@ target_sources(
lib/macro/macro-condition-macro.hpp
lib/macro/macro-condition-queue.cpp
lib/macro/macro-condition-queue.hpp
lib/macro/macro-condition-script.cpp
lib/macro/macro-condition-script.hpp
lib/macro/macro-condition-tempvar.cpp
lib/macro/macro-condition-tempvar.hpp
lib/macro/macro-condition-variable.cpp
@ -128,12 +116,6 @@ target_sources(
lib/macro/macro-condition.hpp
lib/macro/macro-dock.cpp
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-import-dialog.cpp
lib/macro/macro-export-import-dialog.hpp
lib/macro/macro-helpers.cpp
@ -146,27 +128,25 @@ target_sources(
lib/macro/macro-ref.hpp
lib/macro/macro-run-button.cpp
lib/macro/macro-run-button.hpp
lib/macro/macro-search.cpp
lib/macro/macro-search.hpp
lib/macro/macro-script-handler.cpp
lib/macro/macro-script-handler.hpp
lib/macro/macro-segment-copy-paste.cpp
lib/macro/macro-segment-copy-paste.hpp
lib/macro/macro-segment-list.cpp
lib/macro/macro-segment-list.hpp
lib/macro/macro-segment-script.cpp
lib/macro/macro-segment-script.hpp
lib/macro/macro-segment-selection.cpp
lib/macro/macro-segment-selection.hpp
lib/macro/macro-segment-unknown.hpp
lib/macro/macro-segment.cpp
lib/macro/macro-segment.hpp
lib/macro/macro-selection.cpp
lib/macro/macro-selection.hpp
lib/macro/macro-settings.cpp
lib/macro/macro-settings.hpp
lib/macro/macro-signals.cpp
lib/macro/macro-signals.hpp
lib/macro/macro-tab.cpp
lib/macro/macro-tree.cpp
lib/macro/macro-tree.hpp
lib/macro/macro-websocket-trigger.cpp
lib/macro/macro.cpp
lib/macro/macro.hpp)
@ -177,16 +157,10 @@ target_sources(
lib/queue/action-queue.hpp
lib/queue/action-queue-tab.cpp
lib/queue/action-queue-tab.hpp
lib/utils/auto-update-tooltip-label.cpp
lib/utils/auto-update-tooltip-label.hpp
lib/utils/backup.cpp
lib/utils/backup.hpp
lib/utils/canvas-helpers.cpp
lib/utils/canvas-helpers.hpp
lib/utils/condition-logic.cpp
lib/utils/condition-logic.hpp
lib/utils/crash-handler.cpp
lib/utils/crash-handler.hpp
lib/utils/curl-helper.cpp
lib/utils/curl-helper.hpp
lib/utils/cursor-shape-changer.cpp
@ -204,14 +178,10 @@ target_sources(
lib/utils/file-selection.hpp
lib/utils/filter-combo-box.cpp
lib/utils/filter-combo-box.hpp
lib/utils/first-run-wizard.cpp
lib/utils/first-run-wizard.hpp
lib/utils/help-icon.hpp
lib/utils/help-icon.cpp
lib/utils/item-selection-helpers.cpp
lib/utils/item-selection-helpers.hpp
lib/utils/json-helpers.cpp
lib/utils/json-helpers.hpp
lib/utils/layout-helpers.cpp
lib/utils/layout-helpers.hpp
lib/utils/list-controls.cpp
@ -238,14 +208,17 @@ target_sources(
lib/utils/plugin-state-helpers.hpp
lib/utils/priority-helper.cpp
lib/utils/priority-helper.hpp
lib/utils/properties-view.cpp
lib/utils/properties-view.hpp
lib/utils/properties-view.moc.hpp
lib/utils/regex-config.cpp
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.hpp
lib/utils/resource-table.cpp
lib/utils/resource-table.hpp
lib/utils/resource-table-hotkey-handler.cpp
lib/utils/resource-table-hotkey-handler.hpp
lib/utils/scene-selection.cpp
lib/utils/scene-selection.hpp
lib/utils/scene-switch-helpers.cpp
@ -314,16 +287,9 @@ include(cmake/common/advss_helpers.cmake)
setup_obs_lib_dependency(${LIB_NAME})
setup_obs_lib_dependency(${PROJECT_NAME})
find_package(Qt6 REQUIRED COMPONENTS Widgets Core)
target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Core Qt6::Widgets)
target_link_libraries(${LIB_NAME} PRIVATE Qt6::Core Qt6::Widgets)
# Ignore QCheckBox::stateChanged deprecation warning until minimum supported Qt
# version is at least Qt 6.7, which introduces QCheckBox::checkStateChanged
if(Qt6_VERSION VERSION_GREATER "6.0.0")
target_compile_definitions(${LIB_NAME} PRIVATE QT_NO_DEPRECATED_WARNINGS)
endif()
find_qt(COMPONENTS Widgets Core)
target_link_libraries(${PROJECT_NAME} PRIVATE Qt::Core Qt::Widgets)
target_link_libraries(${LIB_NAME} PRIVATE Qt::Core Qt::Widgets)
target_compile_options(
${PROJECT_NAME}
PRIVATE
@ -372,21 +338,6 @@ else()
endif()
target_link_libraries(${LIB_NAME} PUBLIC nlohmann_json::nlohmann_json)
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/deps/jsoncons/CMakeLists.txt")
# Don't build jsoncons unit tests as they are causing compilation issues and
# won't be executed either way
if(OS_MACOS)
cmake_policy(SET CMP0077 NEW)
endif()
set(JSONCONS_BUILD_TESTS
OFF
CACHE BOOL "" FORCE)
add_subdirectory(deps/jsoncons EXCLUDE_FROM_ALL)
target_link_libraries(${LIB_NAME} PRIVATE jsoncons)
target_compile_definitions(${LIB_NAME} PRIVATE JSONPATH_SUPPORT=1)
endif()
find_package(CURL QUIET)
find_package(Libcurl QUIET)
if(CURL_FOUND)
@ -440,7 +391,6 @@ else()
set_target_properties(${LIB_NAME} PROPERTIES PREFIX "")
set_target_properties(${LIB_NAME} PROPERTIES SOVERSION 1)
find_package(Qt6 REQUIRED COMPONENTS DBus)
find_package(X11 REQUIRED COMPONENTS Xss)
target_include_directories(${LIB_NAME} PRIVATE "${X11_INCLUDE_DIR}"
"${X11_Xss_INCLUDE_PATH}")
@ -455,30 +405,10 @@ else()
set(PROCESS_CONDITION_SUPPORTED 1)
endif()
if(PROCPS2_INCLUDE_DIR)
find_package(PkgConfig REQUIRED)
pkg_check_modules(libproc2 REQUIRED IMPORTED_TARGET libproc2)
message(STATUS "${PROJECT_NAME} using libproc2")
set(PROC_INCLUDE_DIR "${PROCPS2_INCLUDE_DIR}")
target_compile_definitions(${LIB_NAME} PRIVATE PROCPS2_AVAILABLE)
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()
if(NOT DEFINED PROCESS_CONDITION_SUPPORTED)
message(
@ -487,11 +417,7 @@ else()
)
endif()
target_include_directories(${LIB_NAME} PRIVATE "${PROC_INCLUDE_DIR}")
target_sources(${LIB_NAME} PRIVATE lib/linux/advanced-scene-switcher-nix.cpp
lib/linux/kwin-helpers.cpp)
# Don't include irrelevant folders into sources archive
list(APPEND CPACK_SOURCE_IGNORE_FILES "\\.deps/.*")
target_sources(${LIB_NAME} PRIVATE lib/linux/advanced-scene-switcher-nix.cpp)
endif()
if(NOT OS_WINDOWS)

View File

@ -19,8 +19,6 @@ The **Snap** package manager offers an OBS Studio installation which is bundled
sudo snap install obs-studio
```
More information can be found [here](https://github.com/WarmUpTill/SceneSwitcher/wiki/Installation).
## Contributing
- If you wish to contribute code to the project, have a look at this [section](BUILDING.md) describing how to compile the plugin.

View File

@ -7,7 +7,7 @@ Build-Depends: cmake,
libcurl4-openssl-dev,
libobs-dev,
libxtst-dev,
qt6-base-dev,
qtbase5-dev,
libxss-dev,
libopencv-dev
Standards-Version: 4.6.0

View File

@ -3,7 +3,7 @@
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
export QT_SELECT = qt6
export QT_SELECT = qt5
%:
dh $@

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

View File

@ -283,14 +283,8 @@ endfunction()
function(setup_advss_plugin target)
setup_obs_lib_dependency(${target})
find_package(Qt6 REQUIRED COMPONENTS Widgets Core)
target_link_libraries(${target} PRIVATE Qt6::Core Qt6::Widgets)
# Ignore QCheckBox::stateChanged deprecation warning until minimum supported
# Qt version is at least Qt 6.7, which introduces QCheckBox::checkStateChanged
if(Qt6_VERSION VERSION_GREATER "6.7.0")
target_compile_definitions(${target} PRIVATE QT_NO_DEPRECATED_WARNINGS)
endif()
find_qt(COMPONENTS Widgets Core)
target_link_libraries(${target} PRIVATE Qt::Core Qt::Widgets)
set_target_properties(
${target}

View File

@ -65,16 +65,17 @@ function(_setup_obs_studio)
if(OS_WINDOWS)
set(_cmake_generator "${CMAKE_GENERATOR}")
set(_cmake_arch
"-A ${arch},version=${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}")
set(_cmake_arch "-A ${arch}")
set(_cmake_extra
"-DCMAKE_SYSTEM_VERSION=${CMAKE_SYSTEM_VERSION} -DCMAKE_ENABLE_SCRIPTING=OFF"
)
set(_cmake_version "2.0.0")
elseif(OS_MACOS)
set(_cmake_generator "Xcode")
set(_cmake_arch "-DCMAKE_OSX_ARCHITECTURES:STRING='arm64;x86_64'")
set(_cmake_extra
"-DCMAKE_OSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}")
set(_cmake_version "3.0.0")
endif()
message(STATUS "Configure ${label} (${arch})")
@ -82,42 +83,32 @@ function(_setup_obs_studio)
COMMAND
"${CMAKE_COMMAND}" -S "${dependencies_dir}/${_obs_destination}" -B
"${dependencies_dir}/${_obs_destination}/build_${arch}" -G
${_cmake_generator} "${_cmake_arch}" -DOBS_CMAKE_VERSION:STRING=3.0.0
-DENABLE_PLUGINS:BOOL=OFF -DENABLE_FRONTEND:BOOL=OFF
-DOBS_VERSION_OVERRIDE:STRING=${_obs_version}
${_cmake_generator} "${_cmake_arch}"
-DOBS_CMAKE_VERSION:STRING=${_cmake_version} -DENABLE_PLUGINS:BOOL=OFF
-DENABLE_UI:BOOL=OFF -DOBS_VERSION_OVERRIDE:STRING=${_obs_version}
"-DCMAKE_PREFIX_PATH='${CMAKE_PREFIX_PATH}'" ${_is_fresh} ${_cmake_extra}
RESULT_VARIABLE _process_result COMMAND_ERROR_IS_FATAL ANY
OUTPUT_QUIET)
message(STATUS "Configure ${label} (${arch}) - done")
message(STATUS "Build ${label} (Debug - ${arch})")
message(STATUS "Build ${label} (${arch})")
execute_process(
COMMAND "${CMAKE_COMMAND}" --build build_${arch} --target obs-frontend-api
--config Debug --parallel
WORKING_DIRECTORY "${dependencies_dir}/${_obs_destination}"
RESULT_VARIABLE _process_result COMMAND_ERROR_IS_FATAL ANY
OUTPUT_QUIET)
message(STATUS "Build ${label} (Debug - ${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 "Build ${label} (${arch}) - done")
message(STATUS "Install ${label} (${arch})")
if(OS_WINDOWS)
set(_cmake_extra "--component obs_libraries")
else()
set(_cmake_extra "")
endif()
execute_process(
COMMAND "${CMAKE_COMMAND}" --install build_${arch} --component Development
--config Debug --prefix "${dependencies_dir}"
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}"
--config Debug --prefix "${dependencies_dir}" ${_cmake_extra}
WORKING_DIRECTORY "${dependencies_dir}/${_obs_destination}"
RESULT_VARIABLE _process_result COMMAND_ERROR_IS_FATAL ANY
OUTPUT_QUIET)
@ -180,46 +171,24 @@ function(_check_dependencies)
set(url ${url}/${version}/${file})
endif()
set(MAX_DOWNLOAD_RETRIES 3)
set(RETRY_DELAY 60) # seconds
if(NOT EXISTS "${dependencies_dir}/${file}")
message(STATUS "Downloading ${url}")
file(
DOWNLOAD "${url}" "${dependencies_dir}/${file}"
STATUS download_status
EXPECTED_HASH SHA256=${hash})
set(download_success FALSE)
foreach(i RANGE 1 ${MAX_DOWNLOAD_RETRIES})
message(STATUS "Attempt ${i}/${MAX_DOWNLOAD_RETRIES} for ${url}")
file(
DOWNLOAD "${url}" "${dependencies_dir}/${file}"
STATUS download_status
EXPECTED_HASH SHA256=${hash})
list(GET download_status 0 error_code)
list(GET download_status 1 error_message)
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)
list(GET download_status 0 error_code)
list(GET download_status 1 error_message)
if(error_code GREATER 0)
message(STATUS "Downloading ${url} - Failure")
message(
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()
message(STATUS "Downloading ${url} - done")
endif()
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}")
# .git dir not found, search parent directories
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)
# We have reached the root directory, we are not in git
set(${_git_dir_var}

View File

@ -17,6 +17,85 @@ if(NOT QT_VERSION)
set_property(CACHE QT_VERSION PROPERTY STRINGS AUTO 5 6)
endif()
# find_qt: Macro to find best possible Qt version for use with the project:
macro(find_qt)
set(multiValueArgs COMPONENTS COMPONENTS_WIN COMPONENTS_MAC COMPONENTS_LINUX)
cmake_parse_arguments(find_qt "" "${oneValueArgs}" "${multiValueArgs}"
${ARGN})
# Do not use versionless targets in the first step to avoid Qt::Core being
# clobbered by later opportunistic find_package runs
set(QT_NO_CREATE_VERSIONLESS_TARGETS TRUE)
message(DEBUG "Start Qt version discovery...")
# Loop until _QT_VERSION is set or FATAL_ERROR aborts script execution early
while(NOT _QT_VERSION)
message(DEBUG "QT_VERSION set to ${QT_VERSION}")
if(QT_VERSION STREQUAL AUTO AND NOT qt_test_version)
set(qt_test_version 6)
elseif(NOT QT_VERSION STREQUAL AUTO)
set(qt_test_version ${QT_VERSION})
endif()
message(DEBUG "Attempting to find Qt${qt_test_version}")
find_package(
Qt${qt_test_version}
COMPONENTS Core
QUIET)
if(TARGET Qt${qt_test_version}::Core)
set(_QT_VERSION
${qt_test_version}
CACHE INTERNAL "")
message(STATUS "Qt version found: ${_QT_VERSION}")
unset(qt_test_version)
break()
elseif(QT_VERSION STREQUAL AUTO)
if(qt_test_version EQUAL 6)
message(WARNING "Qt6 was not found, falling back to Qt5")
set(qt_test_version 5)
continue()
endif()
endif()
message(FATAL_ERROR "Neither Qt6 nor Qt5 found.")
endwhile()
# Enable versionless targets for the remaining Qt components
set(QT_NO_CREATE_VERSIONLESS_TARGETS FALSE)
set(qt_components ${find_qt_COMPONENTS})
if(OS_WINDOWS)
list(APPEND qt_components ${find_qt_COMPONENTS_WIN})
elseif(OS_MACOS)
list(APPEND qt_components ${find_qt_COMPONENTS_MAC})
else()
list(APPEND qt_components ${find_qt_COMPONENTS_LINUX})
endif()
message(DEBUG "Trying to find Qt components ${qt_components}...")
find_package(Qt${_QT_VERSION} REQUIRED ${qt_components})
list(APPEND qt_components Core)
if("Gui" IN_LIST find_qt_COMPONENTS_LINUX)
list(APPEND qt_components "GuiPrivate")
endif()
# Check for versionless targets of each requested component and create if
# necessary
foreach(component IN LISTS qt_components)
message(DEBUG "Checking for target Qt::${component}")
if(NOT TARGET Qt::${component} AND TARGET Qt${_QT_VERSION}::${component})
add_library(Qt::${component} INTERFACE IMPORTED)
set_target_properties(
Qt::${component} PROPERTIES INTERFACE_LINK_LIBRARIES
Qt${_QT_VERSION}::${component})
endif()
set_property(TARGET Qt::${component} PROPERTY INTERFACE_COMPILE_FEATURES "")
endforeach()
endmacro()
# check_uuid: Helper function to check for valid UUID
function(check_uuid uuid_string return_value)
set(valid_uuid TRUE)

View File

@ -80,8 +80,6 @@ function(set_target_properties_plugin target)
configure_file(cmake/windows/resources/installer-Windows.iss.in
"${CMAKE_CURRENT_BINARY_DIR}/installer-Windows.generated.iss")
configure_file(data/res/images/logo.ico
"${CMAKE_CURRENT_BINARY_DIR}/installer.ico" COPYONLY)
configure_file(cmake/windows/resources/resource.rc.in
"${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.rc")

View File

@ -20,9 +20,6 @@ OutputBaseFilename={#MyAppName}-{#MyAppVersion}-Windows-Installer
Compression=lzma
SolidCompression=yes
DirExistsWarning=no
SetupIconFile=installer.ico
UninstallDisplayIcon={app}\data\obs-plugins\advanced-scene-switcher\res\images\logo.ico
DisableDirPage=no
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"

View File

@ -1,78 +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
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}/libcrypto.lib")
set(OPENSSL_ROOT_DIR
"${_root}"
CACHE PATH "Path to OpenSSL root")
set(OPENSSL_CRYPTO_LIBRARY
"${_root}/${_suffix}/libcrypto.lib"
CACHE FILEPATH "OpenSSL crypto lib")
set(OPENSSL_SSL_LIBRARY
"${_root}/${_suffix}/libssl.lib"
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.start="Start"
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.recording="Aufnehmen"
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Streamen"
@ -26,6 +26,7 @@ AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchToRandom="Wechsle zu
AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchTo="Wechsle zu:"
AdvSceneSwitcher.generalTab.generalBehavior.cooldown="Nach Ausführen von Aktionen überspringe das Ausführen von Aktionen für"
AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint="In diesem Zeitraum werden potentielle erfüllte Bedingungen ignoriert!"
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Ausführliches Logging"
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="Fensterposition und -größe speichern"
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="Benachrichtigungen im System-Tray anzeigen"
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="Deaktiviere UI Tipps"
@ -40,7 +41,7 @@ AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="Exportieren"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Importieren"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Exportiere Erweiterter Automatischer Szenenwechsler Einstellungen zu Datei ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Exportiere Erweiterter Automatischer Szenenwechsler Einstellungen von Datei ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Text Dateien (*.txt *.json)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Text Dateien (*.txt)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="Importieren der Einstellungen ist fehlgeschlagen"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Einstellungen wurden erfolgreich importiert"
AdvSceneSwitcher.generalTab.priority.fileContent="Datei Inhalt"
@ -76,6 +77,7 @@ AdvSceneSwitcher.macroTab.name="Name:"
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.runInParallel="Parallel zu anderen Makros ausführen"
AdvSceneSwitcher.macroTab.onChange="Nur bei Änderung ausführen"
AdvSceneSwitcher.macroTab.defaultname="Makro %1"
AdvSceneSwitcher.macroTab.defaultGroupName="Gruppe %1"
AdvSceneSwitcher.macroTab.removeGroupPopup.text="Sicher, dass \"%1\" und alle zugehörigen Elemente gelöscht werden?"
@ -193,12 +195,12 @@ AdvSceneSwitcher.condition.video.modelLoadFail="Modelldaten konnten nicht gelade
AdvSceneSwitcher.condition.video.type.main="OBS's Haupt-Ausgabe"
AdvSceneSwitcher.condition.video.type.source="Quelle"
AdvSceneSwitcher.condition.video.type.scene="Szene"
AdvSceneSwitcher.condition.video.layout="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.layout.modelPath="Modelldaten (Haar-Kaskaden-Klassifikator): {{modelDataPath}}"
AdvSceneSwitcher.condition.video.layout.minNeighbor="Minimale Anzahl von Nachbarn: {{minNeighbors}}"
AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}Reduzieren Sie die CPU-Belastung, indem Sie die Prüfung nur alle {{throttleCount}} Millisekunden"
AdvSceneSwitcher.condition.video.layout.checkAreaEnable="Kontrolle nur im Bereich durchführen"
AdvSceneSwitcher.condition.video.layout.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.entry.modelPath="Modelldaten (Haar-Kaskaden-Klassifikator): {{modelDataPath}}"
AdvSceneSwitcher.condition.video.entry.minNeighbor="Minimale Anzahl von Nachbarn: {{minNeighbors}}"
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}Reduzieren Sie die CPU-Belastung, indem Sie die Prüfung nur alle {{throttleCount}} Millisekunden"
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="Kontrolle nur im Bereich durchführen"
AdvSceneSwitcher.condition.video.entry.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
AdvSceneSwitcher.condition.video.minSize="Minimale Größe:"
AdvSceneSwitcher.condition.video.maxSize="Maximale Größe:"
AdvSceneSwitcher.condition.video.selectArea="Bereich auswählen"
@ -210,6 +212,7 @@ AdvSceneSwitcher.condition.stream.state.start="Stream läuft"
AdvSceneSwitcher.condition.stream.state.stop="Stream gestoppt"
AdvSceneSwitcher.condition.stream.state.starting="Stream wird gestartet"
AdvSceneSwitcher.condition.stream.state.stopping="Stream wird gestoppt"
AdvSceneSwitcher.condition.stream.entry="{{streamState}}{{keyFrameInterval}}"
AdvSceneSwitcher.condition.record="Aufnahme"
AdvSceneSwitcher.condition.record.state.start="Aufnahme läuft"
AdvSceneSwitcher.condition.record.state.pause="Aufnahme pausiert"
@ -290,14 +293,14 @@ AdvSceneSwitcher.condition.replay.state.started="Replay Buffer gestartet"
AdvSceneSwitcher.condition.replay.state.saved="Replay Buffer gespeichert"
AdvSceneSwitcher.condition.replay.entry="{{state}}"
AdvSceneSwitcher.condition.date="Datum"
AdvSceneSwitcher.day.any="Beliebiger Tag"
AdvSceneSwitcher.day.monday="Montag"
AdvSceneSwitcher.day.tuesday="Dienstag"
AdvSceneSwitcher.day.wednesday="Mittwoch"
AdvSceneSwitcher.day.thursday="Donnerstag"
AdvSceneSwitcher.day.friday="Freitag"
AdvSceneSwitcher.day.saturday="Samstag"
AdvSceneSwitcher.day.sunday="Sonntag"
AdvSceneSwitcher.condition.date.anyDay="Beliebiger Tag"
AdvSceneSwitcher.condition.date.monday="Montag"
AdvSceneSwitcher.condition.date.tuesday="Dienstag"
AdvSceneSwitcher.condition.date.wednesday="Mittwoch"
AdvSceneSwitcher.condition.date.thursday="Donnerstag"
AdvSceneSwitcher.condition.date.friday="Freitag"
AdvSceneSwitcher.condition.date.saturday="Samstag"
AdvSceneSwitcher.condition.date.sunday="Sonntag"
AdvSceneSwitcher.condition.date.state.at="Am"
AdvSceneSwitcher.condition.date.state.after="Nach"
AdvSceneSwitcher.condition.date.state.before="Vor"
@ -308,13 +311,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.showAdvancedSettings="Erweiterte Einstellungen anzeigen"
AdvSceneSwitcher.condition.date.showSimpleSettings="Einfache Einstellungen anzeigen"
AdvSceneSwitcher.condition.date.layout.simple.day="Am{{dayOfWeek}}"
AdvSceneSwitcher.condition.date.layout.simple.time="{{ignoreWeekTime}}{{weekCondition}}{{weekTime}}"
AdvSceneSwitcher.condition.date.layout.advanced="{{condition}} {{ignoreDate}}{{date}} {{ignoreTime}}{{time}} {{separator}} {{date2}} {{time2}}"
AdvSceneSwitcher.condition.date.layout.repeat="{{repeat}} Wiederholen alle {{duration}} bei Datumsübereinstimmung"
AdvSceneSwitcher.condition.date.layout.pattern="Aktuelles Datum \"{{currentDate}}\" entspricht dem Muster {{pattern}}"
AdvSceneSwitcher.condition.date.layout.nextMatchDate="Nächster Treffer bei: %1"
AdvSceneSwitcher.condition.date.layout.updateOnRepeat="{{updateOnRepeat}} Bei Wiederholung ausgewähltes Datum auf Wiederholungsdatum aktualisieren"
AdvSceneSwitcher.condition.date.entry.simple="Am {{dayOfWeek}} {{weekCondition}} {{ignoreWeekTime}}{{weekTime}}"
AdvSceneSwitcher.condition.date.entry.advanced="{{condition}} {{ignoreDate}}{{date}} {{ignoreTime}}{{time}} {{separator}} {{date2}} {{time2}}"
AdvSceneSwitcher.condition.date.entry.repeat="{{repeat}} Wiederholen alle {{duration}} bei Datumsübereinstimmung"
AdvSceneSwitcher.condition.date.entry.pattern="Aktuelles Datum \"{{currentDate}}\" entspricht dem Muster {{pattern}}"
AdvSceneSwitcher.condition.date.entry.nextMatchDate="Nächster Treffer bei: %1"
AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}} Bei Wiederholung ausgewähltes Datum auf Wiederholungsdatum aktualisieren"
AdvSceneSwitcher.condition.sceneTransform="Szenenelement transformieren"
AdvSceneSwitcher.condition.sceneTransform.getTransform="Transformation erhalten"
AdvSceneSwitcher.condition.sceneTransform.condition.match="entspricht Transformation"
@ -383,6 +385,8 @@ AdvSceneSwitcher.condition.variable.type.greaterThanVariable="ist größer als d
; Macro Actions
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.wait="Warten"
AdvSceneSwitcher.action.wait.type.fixed="fixe"
@ -429,7 +433,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.hide="Verstecken"
AdvSceneSwitcher.action.sceneVisibility.type.toggle="Umschalten"
AdvSceneSwitcher.action.sceneVisibility.type.source="Quelle"
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.type.enable="Aktivieren"
AdvSceneSwitcher.action.filter.type.disable="Deaktivieren"
@ -464,7 +468,7 @@ AdvSceneSwitcher.action.pluginState.type.stop="Erweiterten Automatischen Szenenw
AdvSceneSwitcher.action.pluginState.type.noMatch="Ändern des Nichtübereinstimmungsverhaltens:"
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.entry="{{actions}}{{values}}{{scenes}}{{settings}}"
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
AdvSceneSwitcher.action.virtualCamera="Virtuelle Kamera"
AdvSceneSwitcher.action.virtualCamera.type.stop="Virtuelle Kamera stoppen"
AdvSceneSwitcher.action.virtualCamera.type.start="Virtuelle Kamera starten"
@ -486,7 +490,7 @@ AdvSceneSwitcher.action.sceneOrder.type.moveDown="Nach unten verschieben"
AdvSceneSwitcher.action.sceneOrder.type.moveTop="An erste Stelle verschieben"
AdvSceneSwitcher.action.sceneOrder.type.moveBottom="An letzte Stelle verschieben"
AdvSceneSwitcher.action.sceneOrder.type.movePosition="An Position verschieben"
AdvSceneSwitcher.action.sceneOrder.entry="Auf{{scenes}}{{actions}}{{sources}}{{sources2}}{{position}}"
AdvSceneSwitcher.action.sceneOrder.entry="Auf{{scenes}}{{actions}}{{sources}}{{position}}"
AdvSceneSwitcher.action.sceneTransform="Szenenelement transformieren"
AdvSceneSwitcher.action.sceneTransform.getTransform="Transformation erhalten"
AdvSceneSwitcher.action.sceneTransform.entry="Auf{{scenes}}{{action}}{{rotation}}{{sources}}{{settingSelection}}{{singleSettingValue}}"
@ -523,6 +527,7 @@ AdvSceneSwitcher.action.screenshot.save.default="Standard"
AdvSceneSwitcher.action.screenshot.save.custom="Benutzerdefiniert"
AdvSceneSwitcher.action.screenshot.type.source="Quelle"
AdvSceneSwitcher.action.screenshot.type.scene="Szene"
AdvSceneSwitcher.action.screenshot.mainOutput="OBS's Haupt-Ausgabe"
AdvSceneSwitcher.action.screenshot.blackscreenNote="Quellen oder Szenen, die nicht immer gerendert werden, können dazu führen, dass einige Teile der Screenshots leer bleiben."
AdvSceneSwitcher.action.screenshot.entry="Screenshot{{targetType}}{{sources}}{{scenes}}und speichere in{{saveType}}{{variables}}Pfad"
AdvSceneSwitcher.action.profile="Profil"
@ -750,9 +755,9 @@ AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Starte/Stoppe den Erweite
AdvSceneSwitcher.hotkey.macro.pause="Pausiere Makro %1"
AdvSceneSwitcher.hotkey.macro.unpause="Makro %1 nicht mehr pausieren"
AdvSceneSwitcher.hotkey.macro.togglePause="Pause von Makro %1 togglen"
AdvSceneSwitcher.hotkey.macro.segment.up="Makro-Segmentauswahl nach oben verschieben"
AdvSceneSwitcher.hotkey.macro.segment.down="Makro-Segmentauswahl nach unten verschieben"
AdvSceneSwitcher.hotkey.macro.segment.remove="Ausgewähltes Makro-Segment entfernen"
AdvSceneSwitcher.hotkey.upMacroSegmentHotkey="Makro-Segmentauswahl nach oben verschieben"
AdvSceneSwitcher.hotkey.downMacroSegmentHotkey="Makro-Segmentauswahl nach unten verschieben"
AdvSceneSwitcher.hotkey.removeMacroSegmentHotkey="Ausgewähltes Makro-Segment entfernen"
AdvSceneSwitcher.askBackup="Neue Version des Erweiterten Automatischen Szenenwechslers wurde erkannt.\nSoll ein Backup der alten Einstellungen angelegt werden?"
AdvSceneSwitcher.askForMacro="Makro auswählen {{macroSelection}}"
@ -834,6 +839,8 @@ AdvSceneSwitcher.status.inactive="Inaktiv"
AdvSceneSwitcher.running="Plugin läuft"
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.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.start="Iniciar"
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.recording="Grabando"
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Emitiendo"
@ -25,6 +25,7 @@ AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.dontSwitch="No cambiar"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchToRandom="Cambiar a una escena aleatoria"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchTo="Cambiar a:"
AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint="¡Durante este tiempo, se ignorarán las posibles coincidencias!"
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Habilitar el registro detallado"
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="Guardar la posición y el tamaño de la ventana"
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="Mostrar notificaciones del sistema"
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="Deshabilitar sugerencias de interfaz de usuario"
@ -38,7 +39,7 @@ AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="Exportar"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Importar"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Exportar los ajustes para Advanced Scene Switcher ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Importar los ajustes para Advanced Scene Switcher ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Archivos de texto (*.txt *.json)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Archivos de texto (*.txt)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="La importacion la configuracion de escenas fallo"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Configuración de escenas importada correctamente"
AdvSceneSwitcher.generalTab.priority.fileContent="Contenido del archivo"
@ -72,6 +73,7 @@ AdvSceneSwitcher.macroTab.add="Agregar nueva macro"
AdvSceneSwitcher.macroTab.name="Nombre:"
AdvSceneSwitcher.macroTab.run="Ejecutar macro"
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.copy="Crear copia"
AdvSceneSwitcher.macroTab.expandAll="Expandir todo"
@ -153,12 +155,12 @@ AdvSceneSwitcher.condition.video.patternMatchSuccess="El patrón está resaltado
AdvSceneSwitcher.condition.video.objectMatchFail="¡No se encontró el objeto!"
AdvSceneSwitcher.condition.video.objectMatchSuccess="El objeto está resaltado en rojo"
AdvSceneSwitcher.condition.video.modelLoadFail="¡No se pudieron cargar los datos del modelo!"
AdvSceneSwitcher.condition.video.layout="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.layout.modelPath="Datos del modelo (haar cascade classifier): {{modelDataPath}}"
AdvSceneSwitcher.condition.video.layout.minNeighbor="Mínimo de vecinos: {{minNeighbors}}"
AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}Reduzca la carga de la CPU realizando una comprobación solo cada {{throttleCount}} milisegundos"
AdvSceneSwitcher.condition.video.layout.checkAreaEnable="Realizar comprobación solo en el área"
AdvSceneSwitcher.condition.video.layout.checkArea="{{checkAreaEnable}}Realizar comprobación solo en el área {{checkArea}} {{selectArea}}"
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.entry.modelPath="Datos del modelo (haar cascade classifier): {{modelDataPath}}"
AdvSceneSwitcher.condition.video.entry.minNeighbor="Mínimo de vecinos: {{minNeighbors}}"
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}Reduzca la carga de la CPU realizando una comprobación solo cada {{throttleCount}} milisegundos"
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="Realizar comprobación solo en el área"
AdvSceneSwitcher.condition.video.entry.checkArea="{{checkAreaEnable}}Realizar comprobación solo en el área {{checkArea}} {{selectArea}}"
AdvSceneSwitcher.condition.video.minSize="Tamaño mínimo:"
AdvSceneSwitcher.condition.video.maxSize="Tamaño máximo:"
AdvSceneSwitcher.condition.video.selectArea="Seleccionar área"
@ -170,6 +172,7 @@ AdvSceneSwitcher.condition.stream.state.start="Transmisión en ejecución"
AdvSceneSwitcher.condition.stream.state.stop="Transmisión detenida"
AdvSceneSwitcher.condition.stream.state.starting="Inicio de transmisión"
AdvSceneSwitcher.condition.stream.state.stopping="Detener transmisión"
AdvSceneSwitcher.condition.stream.entry="{{streamState}}{{keyFrameInterval}}"
AdvSceneSwitcher.condition.record="Grabación"
AdvSceneSwitcher.condition.record.state.start="Grabación en ejecución"
AdvSceneSwitcher.condition.record.state.pause="Grabación en pausa"
@ -240,14 +243,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.entry="{{state}}"
AdvSceneSwitcher.condition.date="Fecha"
AdvSceneSwitcher.day.any="Cualquier día"
AdvSceneSwitcher.day.monday="Lunes"
AdvSceneSwitcher.day.tuesday="Martes"
AdvSceneSwitcher.day.wednesday="Miércoles"
AdvSceneSwitcher.day.thursday="Jueves"
AdvSceneSwitcher.day.friday="Viernes"
AdvSceneSwitcher.day.saturday="Sábado"
AdvSceneSwitcher.day.sunday="Domingo"
AdvSceneSwitcher.condition.date.anyDay="Cualquier día"
AdvSceneSwitcher.condition.date.monday="Lunes"
AdvSceneSwitcher.condition.date.tuesday="Martes"
AdvSceneSwitcher.condition.date.wednesday="Miércoles"
AdvSceneSwitcher.condition.date.thursday="Jueves"
AdvSceneSwitcher.condition.date.friday="Viernes"
AdvSceneSwitcher.condition.date.saturday="Sábado"
AdvSceneSwitcher.condition.date.sunday="Domingo"
AdvSceneSwitcher.condition.date.state.at="A las"
AdvSceneSwitcher.condition.date.state.after="Después"
AdvSceneSwitcher.condition.date.state.before="Antes"
@ -257,12 +260,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.showAdvancedSettings="Mostrar configuración avanzada"
AdvSceneSwitcher.condition.date.showSimpleSettings="Mostrar configuración simple"
AdvSceneSwitcher.condition.date.layout.simple.day="El{{dayOfWeek}}"
AdvSceneSwitcher.condition.date.layout.simple.time="{{ignoreWeekTime}}{{weekCondition}}{{weekTime}}"
AdvSceneSwitcher.condition.date.layout.advanced="{{condition}} {{ignoreDate}}{{date}} {{ignoreTime}}{{time}} {{separator}} {{date2}} {{time2}}"
AdvSceneSwitcher.condition.date.layout.repeat="{{repeat}} Repetir cada {{duration}} en la coincidencia de fechas"
AdvSceneSwitcher.condition.date.layout.nextMatchDate="Próxima coincidencia en: %1"
AdvSceneSwitcher.condition.date.layout.updateOnRepeat="{{updateOnRepeat}} Al repetir actualizar la fecha seleccionada para repetir la fecha"
AdvSceneSwitcher.condition.date.entry.simple="El {{dayOfWeek}} {{weekCondition}} {{ignoreWeekTime}}{{weekTime}}"
AdvSceneSwitcher.condition.date.entry.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.entry.nextMatchDate="Próxima coincidencia en: %1"
AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}} Al repetir actualizar la fecha seleccionada para repetir la fecha"
AdvSceneSwitcher.condition.sceneTransform="Transformar elemento de escena"
AdvSceneSwitcher.condition.sceneTransform.getTransform="Obtener transformación"
AdvSceneSwitcher.condition.sceneTransform.condition.match="coincide con la transformación"
@ -311,6 +313,7 @@ AdvSceneSwitcher.condition.stats.entry="{{stats}} esta {{condition}} {{value}}"
; Macro Actions
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.wait="Esperar"
AdvSceneSwitcher.action.wait.type.fixed="fijo"
@ -350,7 +353,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.show="Mostrar"
AdvSceneSwitcher.action.sceneVisibility.type.hide="Ocultar"
AdvSceneSwitcher.action.sceneVisibility.type.source="Fuente"
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.type.enable="Habilitar"
AdvSceneSwitcher.action.filter.type.disable="Deshabilitar"
@ -382,7 +385,7 @@ AdvSceneSwitcher.action.pluginState.type.stop="Detener el complemento Advanced S
AdvSceneSwitcher.action.pluginState.type.noMatch="Cambiar el comportamiento de no coincidencia:"
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.entry="{{actions}}{{values}}{{scenes}}{{settings}}"
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
AdvSceneSwitcher.action.virtualCamera="Cámara virtual"
AdvSceneSwitcher.action.virtualCamera.type.stop="Detener cámara virtual"
AdvSceneSwitcher.action.virtualCamera.type.start="Iniciar cámara virtual"
@ -404,7 +407,7 @@ AdvSceneSwitcher.action.sceneOrder.type.moveDown="Mover hacia abajo"
AdvSceneSwitcher.action.sceneOrder.type.moveTop="Mover al principio"
AdvSceneSwitcher.action.sceneOrder.type.moveBottom="Mover al final"
AdvSceneSwitcher.action.sceneOrder.type.movePosition="Mover a la posición"
AdvSceneSwitcher.action.sceneOrder.entry="En{{scenes}}{{actions}}{{sources}}{{sources2}}{{position}}"
AdvSceneSwitcher.action.sceneOrder.entry="En{{scenes}}{{actions}}{{sources}}{{position}}"
AdvSceneSwitcher.action.sceneTransform="Transformar elemento de escena"
AdvSceneSwitcher.action.sceneTransform.getTransform="Obtener transformación"
AdvSceneSwitcher.action.sceneTransform.entry="En{{scenes}}{{action}}{{rotation}}{{sources}}{{settingSelection}}{{singleSettingValue}}"
@ -436,6 +439,7 @@ AdvSceneSwitcher.action.random="Aleatorio"
AdvSceneSwitcher.action.random.entry="Ejecute aleatoriamente cualquiera de las siguientes macros (las macros en pausa se ignoran)"
AdvSceneSwitcher.action.systray="Notificación de la bandeja del sistema"
AdvSceneSwitcher.action.screenshot="Captura de pantalla"
AdvSceneSwitcher.action.screenshot.mainOutput="Salida principal de OBS"
AdvSceneSwitcher.action.profile="Perfil"
AdvSceneSwitcher.action.profile.entry="Cambiar perfil activo a {{profiles}}"
AdvSceneSwitcher.action.sceneCollection="Colección de escenas"
@ -639,9 +643,9 @@ AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Alternar inicio / detenci
AdvSceneSwitcher.hotkey.macro.pause="Pausar macro %1"
AdvSceneSwitcher.hotkey.macro.unpause="Despausar macro %1"
AdvSceneSwitcher.hotkey.macro.togglePause="Alternar pausa de macro %1"
AdvSceneSwitcher.hotkey.macro.segment.up="Mover selección de segmento de macro hacia arriba"
AdvSceneSwitcher.hotkey.macro.segment.down="Mover selección de segmento de macro hacia abajo"
AdvSceneSwitcher.hotkey.macro.segment.remove="Eliminar segmento de macro seleccionado"
AdvSceneSwitcher.hotkey.upMacroSegmentHotkey="Mover selección de segmento de macro hacia arriba"
AdvSceneSwitcher.hotkey.downMacroSegmentHotkey="Mover selección de segmento de macro hacia abajo"
AdvSceneSwitcher.hotkey.removeMacroSegmentHotkey="Eliminar segmento de macro seleccionado"
AdvSceneSwitcher.askBackup="Se detectó una nueva versión de Advanced Scene Switcher.\n¿Crear una copia de seguridad de la configuración anterior?"
AdvSceneSwitcher.askForMacro="Select macro {{macroSelection}}"
@ -680,6 +684,8 @@ AdvSceneSwitcher.status.inactive="Inactivo"
AdvSceneSwitcher.running="Iniciar complemento"
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.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.start="Démarrer"
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.recording="Enregistrement"
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Diffusion en continu"
@ -26,6 +26,7 @@ AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchToRandom="Basculer v
AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchTo="Basculer vers :"
AdvSceneSwitcher.generalTab.generalBehavior.cooldown="Après avoir effectué des actions, sauter l'exécution d'actions pendant"
AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint="Pendant cette période, les correspondances potentielles seront ignorées !"
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Activer les journaux détaillés"
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="Enregistrer la position et la taille de la fenêtre"
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="Afficher les notifications dans la zone de notification système"
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="Désactiver les indications de l'interface utilisateur"
@ -43,7 +44,7 @@ AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="Exporter"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Importer"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Exporter les paramètres d'Advanced Scene Switcher vers un fichier ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Importer les paramètres d'Advanced Scene Switcher depuis un fichier ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Fichiers texte (*.txt *.json)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Fichiers texte (*.txt)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="L'importation des paramètres d'Advanced Scene Switcher a échoué"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Les paramètres d'Advanced Scene Switcher ont été importés avec succès"
AdvSceneSwitcher.generalTab.priority.fileContent="Contenu du fichier"
@ -78,6 +79,7 @@ AdvSceneSwitcher.macroTab.add="Ajouter une nouvelle macro"
AdvSceneSwitcher.macroTab.name="Nom :"
AdvSceneSwitcher.macroTab.run="Exécuter la macro"
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.defaultGroupName="Groupe %1"
AdvSceneSwitcher.macroTab.removeSingleMacroPopup.text="Êtes-vous sûr de vouloir supprimer \"%1\" ?"
@ -256,14 +258,14 @@ AdvSceneSwitcher.condition.video.colorDeviationThresholdDescription="À quel poi
AdvSceneSwitcher.condition.video.type.main="Sortie principale d'OBS"
AdvSceneSwitcher.condition.video.type.source="Source"
AdvSceneSwitcher.condition.video.type.scene="Scène"
AdvSceneSwitcher.condition.video.layout.modelPath="Données du modèle (classificateur de cascade de Haar) :{{modelDataPath}}"
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.checkAreaEnable="Effectuer la vérification uniquement dans la zone"
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.ocrLanguage="Vérifier la langue :{{languageCode}}"
AdvSceneSwitcher.condition.video.layout.color="Vérifier la couleur :{{color}}{{selectColor}}"
AdvSceneSwitcher.condition.video.entry.modelPath="Données du modèle (classificateur de cascade de Haar) :{{modelDataPath}}"
AdvSceneSwitcher.condition.video.entry.minNeighbor="Nombre minimum de voisins :{{minNeighbors}}"
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}Réduire la charge CPU en effectuant la vérification uniquement toutes les{{throttleCount}}millisecondes"
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="Effectuer la vérification uniquement dans la zone"
AdvSceneSwitcher.condition.video.entry.orcColorPick="Vérifier la couleur du texte :{{textColor}}{{selectColor}}"
AdvSceneSwitcher.condition.video.entry.orcTextType="Vérifier le type de texte :{{textType}}"
AdvSceneSwitcher.condition.video.entry.orcLanguage="Vérifier la langue :{{languageCode}}"
AdvSceneSwitcher.condition.video.entry.color="Vérifier la couleur :{{color}}{{selectColor}}"
AdvSceneSwitcher.condition.video.minSize="Taille minimale :"
AdvSceneSwitcher.condition.video.maxSize="Taille maximale :"
AdvSceneSwitcher.condition.video.selectArea="Sélectionner la zone"
@ -355,14 +357,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.saved="Tampon de répétition enregistré"
AdvSceneSwitcher.condition.date="Date"
AdvSceneSwitcher.day.any="N'importe quel jour"
AdvSceneSwitcher.day.monday="Lundi"
AdvSceneSwitcher.day.tuesday="Mardi"
AdvSceneSwitcher.day.wednesday="Mercredi"
AdvSceneSwitcher.day.thursday="Jeudi"
AdvSceneSwitcher.day.friday="Vendredi"
AdvSceneSwitcher.day.saturday="Samedi"
AdvSceneSwitcher.day.sunday="Dimanche"
AdvSceneSwitcher.condition.date.anyDay="N'importe quel jour"
AdvSceneSwitcher.condition.date.monday="Lundi"
AdvSceneSwitcher.condition.date.tuesday="Mardi"
AdvSceneSwitcher.condition.date.wednesday="Mercredi"
AdvSceneSwitcher.condition.date.thursday="Jeudi"
AdvSceneSwitcher.condition.date.friday="Vendredi"
AdvSceneSwitcher.condition.date.saturday="Samedi"
AdvSceneSwitcher.condition.date.sunday="Dimanche"
AdvSceneSwitcher.condition.date.state.at="À"
AdvSceneSwitcher.condition.date.state.after="Après"
AdvSceneSwitcher.condition.date.state.before="Avant"
@ -373,12 +375,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.showAdvancedSettings="Afficher les paramètres avancés"
AdvSceneSwitcher.condition.date.showSimpleSettings="Afficher les paramètres simples"
AdvSceneSwitcher.condition.date.layout.simple.day="Le{{dayOfWeek}}"
AdvSceneSwitcher.condition.date.layout.simple.time="{{ignoreWeekTime}}{{weekCondition}}{{weekTime}}"
AdvSceneSwitcher.condition.date.layout.repeat="{{repeat}}Répéter toutes les{{duration}}lorsque la date correspond"
AdvSceneSwitcher.condition.date.layout.pattern="La date actuelle \"{{currentDate}}\" correspond au motif{{pattern}}"
AdvSceneSwitcher.condition.date.layout.nextMatchDate="Prochaine correspondance à : %1"
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.date.entry.simple="Le{{dayOfWeek}}{{weekCondition}}{{ignoreWeekTime}}{{weekTime}}"
AdvSceneSwitcher.condition.date.entry.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.entry.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.sceneTransform="Transformation de l'élément de la scène"
AdvSceneSwitcher.condition.sceneTransform.getTransform="Obtenir la transformation"
AdvSceneSwitcher.condition.sceneTransform.condition.match="correspond à la transformation"
@ -459,6 +460,8 @@ AdvSceneSwitcher.condition.slideshow.updateInterval.tooltip="Les informations su
AdvSceneSwitcher.action.scene="Changer de scène"
AdvSceneSwitcher.action.scene.type.program="Programme"
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.wait="Attendre"
AdvSceneSwitcher.action.wait.type.fixed="fixe"
@ -510,7 +513,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.hide="Masquer"
AdvSceneSwitcher.action.sceneVisibility.type.toggle="Basculer"
AdvSceneSwitcher.action.sceneVisibility.type.source="Source"
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.type.enable="Activer"
AdvSceneSwitcher.action.filter.type.disable="Désactiver"
@ -594,7 +597,7 @@ AdvSceneSwitcher.action.sceneOrder.type.moveDown="Déplacer vers le bas"
AdvSceneSwitcher.action.sceneOrder.type.moveTop="Déplacer en haut"
AdvSceneSwitcher.action.sceneOrder.type.moveBottom="Déplacer en bas"
AdvSceneSwitcher.action.sceneOrder.type.movePosition="Déplacer à la position"
AdvSceneSwitcher.action.sceneOrder.entry="Sur{{scenes}}{{actions}}{{sources}}{{sources2}}{{position}}"
AdvSceneSwitcher.action.sceneOrder.entry="Sur{{scenes}}{{actions}}{{sources}}{{position}}"
AdvSceneSwitcher.action.sceneTransform="Transformation de l'élément de la scène"
AdvSceneSwitcher.action.sceneTransform.type.manual="Transform"
AdvSceneSwitcher.action.sceneTransform.type.reset="Réinitialiser la transformation"
@ -644,6 +647,7 @@ AdvSceneSwitcher.action.screenshot.save.default="Par défaut"
AdvSceneSwitcher.action.screenshot.save.custom="Personnalisé"
AdvSceneSwitcher.action.screenshot.type.source="Source"
AdvSceneSwitcher.action.screenshot.type.scene="Scène"
AdvSceneSwitcher.action.screenshot.mainOutput="Sortie principale d'OBS"
AdvSceneSwitcher.action.screenshot.blackscreenNote="Les sources ou les scènes qui ne sont pas toujours rendues peuvent entraîner des parties de captures d'écran vides."
AdvSceneSwitcher.action.screenshot.entry="Capturer{{targetType}}{{sources}}{{scenes}}et enregistrer à l'emplacement{{saveType}}{{variables}}"
AdvSceneSwitcher.action.profile="Profil"
@ -701,10 +705,10 @@ 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.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.layout.substringIndex="Début de la sous-chaîne :{{subStringStart}}Taille de la sous-chaîne :{{subStringSize}}{{subStringRegex}}"
AdvSceneSwitcher.action.variable.layout.substringRegex="Attribuer la valeur du match{{regexMatchIdx}}en utilisant une expression régulière:{{subStringRegex}}"
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.entry.substringIndex="Début de la sous-chaîne :{{subStringStart}}Taille de la sous-chaîne :{{subStringSize}}"
AdvSceneSwitcher.action.variable.entry.substringRegex="Attribuer la valeur du match{{regexMatchIdx}}en utilisant une expression régulière :"
AdvSceneSwitcher.action.variable.entry.userInput.customPrompt="{{useCustomPrompt}}Utiliser un message personnalisé{{inputPrompt}}"
AdvSceneSwitcher.action.variable.entry.userInput.placeholder="{{useInputPlaceholder}}Remplir avec un indicateur de position{{inputPlaceholder}}"
AdvSceneSwitcher.action.projector="Projecteur"
AdvSceneSwitcher.action.projector.type.source="Source"
AdvSceneSwitcher.action.projector.type.scene="Scène"
@ -714,6 +718,8 @@ AdvSceneSwitcher.action.projector.type.multiview="Multivue"
AdvSceneSwitcher.action.projector.display="Affichage"
AdvSceneSwitcher.action.projector.windowed="Fenêtré"
AdvSceneSwitcher.action.projector.fullscreen="Plein écran"
AdvSceneSwitcher.action.projector.entry="Ouvrir le projecteur{{windowTypes}}de{{types}}{{scenes}}{{sources}}"
AdvSceneSwitcher.action.projector.entry.monitor="sur{{monitors}}"
AdvSceneSwitcher.action.midi="MIDI"
AdvSceneSwitcher.action.midi.entry="Envoyer un message à{{device}}:"
AdvSceneSwitcher.action.midi.entry.listen="Définir la sélection de messages MIDI sur les messages entrants de{{listenDevices}}:{{listenButton}}"
@ -918,9 +924,9 @@ AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Basculer le démarrage/ar
AdvSceneSwitcher.hotkey.macro.pause="Mettre en pause la macro %1"
AdvSceneSwitcher.hotkey.macro.unpause="Reprendre la macro %1"
AdvSceneSwitcher.hotkey.macro.togglePause="Basculer la pause de la macro %1"
AdvSceneSwitcher.hotkey.macro.segment.up="Déplacer la sélection du segment de macro vers le haut"
AdvSceneSwitcher.hotkey.macro.segment.down="Déplacer la sélection du segment de macro vers le bas"
AdvSceneSwitcher.hotkey.macro.segment.remove="Supprimer le segment de macro sélectionné"
AdvSceneSwitcher.hotkey.upMacroSegmentHotkey="Déplacer la sélection du segment de macro vers le haut"
AdvSceneSwitcher.hotkey.downMacroSegmentHotkey="Déplacer la sélection du segment de macro vers le bas"
AdvSceneSwitcher.hotkey.removeMacroSegmentHotkey="Supprimer le segment de macro sélectionné"
AdvSceneSwitcher.askBackup="Une nouvelle version du commutateur de scènes avancé a été détectée.\nSouhaitez-vous créer une sauvegarde des anciens paramètres ?"
AdvSceneSwitcher.askForMacro="Sélectionnez la macro{{macroSelection}}"
@ -1105,15 +1111,15 @@ AdvSceneSwitcher.sceneItemSelection.configure="Configurer le type de sélection
AdvSceneSwitcher.sceneItemSelection.type.sourceName="Nom de la source"
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable="Nom de la variable"
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.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.layout="{{index}}source"
AdvSceneSwitcher.sceneItemSelection.type.index.entry="{{index}}source"
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.layout="Toutes les sources"
AdvSceneSwitcher.sceneItemSelection.type.all.entry="Toutes les sources"
AdvSceneSwitcher.sceneItemSelection.all="Tout"
AdvSceneSwitcher.sceneItemSelection.any="N'importe lequel"
@ -1122,6 +1128,8 @@ AdvSceneSwitcher.status.inactive="Inactif"
AdvSceneSwitcher.running="Plugin en cours d'exécution"
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.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.start="Iniciar"
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.recording="Gravando"
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Transmitindo"
@ -30,6 +30,7 @@ AdvSceneSwitcher.generalTab.generalBehavior.logLevel="Nível de log:"
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.default="Padrão"
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.logAction="Registrar ações executadas"
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.verbose="Registro detalhado"
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Ativar registro detalhado"
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="Salvar posição e tamanho da janela"
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="Mostrar notificações na área de notificação"
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="Desativar dicas de interface"
@ -48,7 +49,7 @@ AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="Exportar"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Importar"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Exportar configurações do Advanced Scene Switcher para arquivo ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Importar configurações do Advanced Scene Switcher de arquivo ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Arquivos de texto (*.txt *.json)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Arquivos de texto (*.txt)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="O Advanced Scene Switcher falhou ao importar configurações"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Configurações do Advanced Scene Switcher importadas com sucesso"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportSensitiveDataWarning="Aviso:\nOs dados exportados podem conter informações sensíveis!"
@ -147,6 +148,7 @@ AdvSceneSwitcher.macroTab.run.tooltip="Execute todas as ações da macro indepen
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.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.defaultGroupName="Grupo %1"
AdvSceneSwitcher.macroTab.macroNameExists="O nome \"%1\" já está em uso por uma macro."
@ -371,16 +373,16 @@ AdvSceneSwitcher.condition.video.colorDeviationThresholdDescription="Quão semel
AdvSceneSwitcher.condition.video.type.main="Saída principal do OBS"
AdvSceneSwitcher.condition.video.type.source="Fonte"
AdvSceneSwitcher.condition.video.type.scene="Cena"
AdvSceneSwitcher.condition.video.layout="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.layout.modelPath="Dados do modelo (classificador em cascata haar):{{modelDataPath}}"
AdvSceneSwitcher.condition.video.layout.minNeighbor="Vizinhos mínimos:{{minNeighbors}}"
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.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
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.ocrLanguage="Verificar idioma:{{languageCode}}"
AdvSceneSwitcher.condition.video.layout.color="Verificar cor:{{color}}{{selectColor}}"
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.entry.modelPath="Dados do modelo (classificador em cascata haar):{{modelDataPath}}"
AdvSceneSwitcher.condition.video.entry.minNeighbor="Vizinhos mínimos:{{minNeighbors}}"
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}Reduzir carga de CPU realizando a verificação apenas a cada {{throttleCount}} milissegundos"
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="Realizar verificação apenas na área"
AdvSceneSwitcher.condition.video.entry.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
AdvSceneSwitcher.condition.video.entry.orcColorPick="Verificar cor do texto:{{textColor}}{{selectColor}}"
AdvSceneSwitcher.condition.video.entry.orcTextType="Verificar tipo de texto:{{textType}}"
AdvSceneSwitcher.condition.video.entry.orcLanguage="Verificar idioma:{{languageCode}}"
AdvSceneSwitcher.condition.video.entry.color="Verificar cor:{{color}}{{selectColor}}"
AdvSceneSwitcher.condition.video.minSize="Tamanho mínimo:"
AdvSceneSwitcher.condition.video.maxSize="Tamanho máximo:"
AdvSceneSwitcher.condition.video.selectArea="Selecionar área"
@ -393,6 +395,7 @@ AdvSceneSwitcher.condition.stream.state.stop="Streaming parado"
AdvSceneSwitcher.condition.stream.state.starting="Iniciando o streaming"
AdvSceneSwitcher.condition.stream.state.stopping="Parando o streaming"
AdvSceneSwitcher.condition.stream.state.keyFrameInterval="Intervalo de keyframe igual a"
AdvSceneSwitcher.condition.stream.entry="{{streamState}}{{keyFrameInterval}}"
AdvSceneSwitcher.condition.record="Gravação"
AdvSceneSwitcher.condition.record.state.start="Gravação em execução"
AdvSceneSwitcher.condition.record.state.pause="Gravação pausada"
@ -501,14 +504,14 @@ AdvSceneSwitcher.condition.replay.state.started="Buffer de replay iniciado"
AdvSceneSwitcher.condition.replay.state.saved="Buffer de replay salvo"
AdvSceneSwitcher.condition.replay.entry="{{state}}"
AdvSceneSwitcher.condition.date="Data"
AdvSceneSwitcher.day.any="Qualquer dia"
AdvSceneSwitcher.day.monday="Segunda-feira"
AdvSceneSwitcher.day.tuesday="Terça-feira"
AdvSceneSwitcher.day.wednesday="Quarta-feira"
AdvSceneSwitcher.day.thursday="Quinta-feira"
AdvSceneSwitcher.day.friday="Sexta-feira"
AdvSceneSwitcher.day.saturday="Sábado"
AdvSceneSwitcher.day.sunday="Domingo"
AdvSceneSwitcher.condition.date.anyDay="Qualquer dia"
AdvSceneSwitcher.condition.date.monday="Segunda-feira"
AdvSceneSwitcher.condition.date.tuesday="Terça-feira"
AdvSceneSwitcher.condition.date.wednesday="Quarta-feira"
AdvSceneSwitcher.condition.date.thursday="Quinta-feira"
AdvSceneSwitcher.condition.date.friday="Sexta-feira"
AdvSceneSwitcher.condition.date.saturday="Sábado"
AdvSceneSwitcher.condition.date.sunday="Domingo"
AdvSceneSwitcher.condition.date.state.at="Às"
AdvSceneSwitcher.condition.date.state.after="Após"
AdvSceneSwitcher.condition.date.state.before="Antes"
@ -519,13 +522,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.showAdvancedSettings="Mostrar configurações avançadas"
AdvSceneSwitcher.condition.date.showSimpleSettings="Mostrar configurações simples"
AdvSceneSwitcher.condition.date.layout.simple.day="Em{{dayOfWeek}}"
AdvSceneSwitcher.condition.date.layout.simple.time="{{ignoreWeekTime}}{{weekCondition}}{{weekTime}}"
AdvSceneSwitcher.condition.date.layout.advanced="{{condition}}{{ignoreDate}}{{date}}{{ignoreTime}}{{time}}{{separator}}{{date2}}{{time2}}"
AdvSceneSwitcher.condition.date.layout.repeat="{{repeat}}Repetir a cada{{duration}}em correspondência de data"
AdvSceneSwitcher.condition.date.layout.pattern="Data atual \"{{currentDate}}\" corresponde ao padrão{{pattern}}"
AdvSceneSwitcher.condition.date.layout.nextMatchDate="Próxima correspondência em: %1"
AdvSceneSwitcher.condition.date.layout.updateOnRepeat="{{updateOnRepeat}}Ao repetir, atualize a data selecionada para a data de repetição"
AdvSceneSwitcher.condition.date.entry.simple="Em{{dayOfWeek}}{{weekCondition}}{{ignoreWeekTime}}{{weekTime}}"
AdvSceneSwitcher.condition.date.entry.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.entry.pattern="Data atual \"{{currentDate}}\" corresponde ao padrão{{pattern}}"
AdvSceneSwitcher.condition.date.entry.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.sceneTransform="Transformação do item de cena"
AdvSceneSwitcher.condition.sceneTransform.getTransform="Obter transformação"
AdvSceneSwitcher.condition.sceneTransform.getCurrentValue="Obter valor atual"
@ -720,6 +722,9 @@ AdvSceneSwitcher.condition.noDevicesFoundWarning="Nenhum dispositivo USB detecta
AdvSceneSwitcher.action.scene="Trocar cena"
AdvSceneSwitcher.action.scene.type.program="Programa"
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.wait="Aguardar"
AdvSceneSwitcher.action.wait.type.fixed="fixo"
@ -781,7 +786,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.hide="Ocultar"
AdvSceneSwitcher.action.sceneVisibility.type.toggle="Alternar"
AdvSceneSwitcher.action.sceneVisibility.type.source="Fonte"
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.type.enable="Habilitar"
AdvSceneSwitcher.action.filter.type.disable="Desabilitar"
@ -861,9 +866,9 @@ AdvSceneSwitcher.action.macro.type.stop="Parar ações"
AdvSceneSwitcher.action.macro.type.disableAction="Desabilitar ação"
AdvSceneSwitcher.action.macro.type.enableAction="Habilitar ação"
AdvSceneSwitcher.action.macro.type.toggleAction="Alternar ação"
AdvSceneSwitcher.action.macro.layout.run="{{actions}}{{actionSections}}de{{macros}}"
AdvSceneSwitcher.action.macro.layout.run.condition="{{conditionBehaviors}}de{{conditionMacros}}"
AdvSceneSwitcher.action.macro.layout.other="{{actions}}{{macros}}"
AdvSceneSwitcher.action.macro.entry.run="{{actions}}{{actionTypes}}de{{macros}}"
AdvSceneSwitcher.action.macro.entry.run.condition="{{conditionBehaviors}}de{{conditionMacros}}"
AdvSceneSwitcher.action.macro.entry.other="{{actions}}{{actionIndex}}{{macros}}"
AdvSceneSwitcher.action.pluginState="Estado do plugin"
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:"
@ -871,7 +876,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.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.entry="{{actions}}{{values}}{{scenes}}{{settings}}"
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
AdvSceneSwitcher.action.virtualCamera="Câmera virtual"
AdvSceneSwitcher.action.virtualCamera.type.stop="Parar câmera virtual"
AdvSceneSwitcher.action.virtualCamera.type.start="Iniciar câmera virtual"
@ -902,7 +907,7 @@ AdvSceneSwitcher.action.sceneOrder.type.moveDown="Mover para baixo"
AdvSceneSwitcher.action.sceneOrder.type.moveTop="Mover para o topo"
AdvSceneSwitcher.action.sceneOrder.type.moveBottom="Mover para o fundo"
AdvSceneSwitcher.action.sceneOrder.type.movePosition="Mover para posição"
AdvSceneSwitcher.action.sceneOrder.entry="Em{{scenes}}{{actions}}{{sources}}{{sources2}}{{position}}"
AdvSceneSwitcher.action.sceneOrder.entry="Em{{scenes}}{{actions}}{{sources}}{{position}}"
AdvSceneSwitcher.action.sceneTransform="Transformação de item de cena"
AdvSceneSwitcher.action.sceneTransform.type.manual="Definir string de transformação"
AdvSceneSwitcher.action.sceneTransform.type.setSingleSetting="Definir configuração de transformação"
@ -956,6 +961,7 @@ AdvSceneSwitcher.action.screenshot.save.default="Padrão"
AdvSceneSwitcher.action.screenshot.save.custom="Personalizado"
AdvSceneSwitcher.action.screenshot.type.source="Fonte"
AdvSceneSwitcher.action.screenshot.type.scene="Cena"
AdvSceneSwitcher.action.screenshot.mainOutput="Saída principal do OBS"
AdvSceneSwitcher.action.screenshot.blackscreenNote="Fontes ou cenas, que nem sempre são renderizadas, podem resultar em algumas partes das capturas de tela permanecendo em branco."
AdvSceneSwitcher.action.screenshot.entry="Captura de tela{{targetType}}{{sources}}{{scenes}}e salvar em{{saveType}}{{variables}}localização"
AdvSceneSwitcher.action.profile="Perfil"
@ -1008,7 +1014,7 @@ AdvSceneSwitcher.action.variable.type.askForValue="Obter entrada do usuário"
AdvSceneSwitcher.action.variable.type.environmentVariable="Definir valor da variável de ambiente"
AdvSceneSwitcher.action.variable.type.sceneItemCount="Definir para contagem de itens de cena"
AdvSceneSwitcher.action.variable.type.stringLength="Definir comprimento da string"
AdvSceneSwitcher.action.variable.type.extractJsonField="Extrair campo json com nome"
AdvSceneSwitcher.action.variable.type.extractJson="Extrair campo json com nome"
AdvSceneSwitcher.action.variable.type.setToTempvar="Definir para propriedade da macro"
AdvSceneSwitcher.action.variable.type.setToTempvar.help="Este tipo de ação permite extrair valores de segmentos da macro atual e atribuir esses valores à variável selecionada.\nPor exemplo, você pode obter o nome da cena atual de uma condição de cena e atribuir esse nome a uma variável."
AdvSceneSwitcher.action.variable.type.sceneItemName="Definir para nome do item de cena no índice"
@ -1028,13 +1034,13 @@ AdvSceneSwitcher.action.variable.invalidSelection="Seleção inválida!"
AdvSceneSwitcher.action.variable.actionNoVariableSupport="Obter valores de variáveis das ações %1 não é suportado!"
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="Obter valores de variáveis das condições %1 não é suportado!"
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.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.substringRegex="Atribuir valor do{{regexMatchIdx}}correspondência usando expressão regular:{{subStringRegex}}"
AdvSceneSwitcher.action.variable.layout.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
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.entry.pad="{{actions}}de{{variables}}para comprimento{{stringLength}}adicionando{{paddingCharSelection}}ao{{direction}}"
AdvSceneSwitcher.action.variable.entry.truncate="{{actions}}de{{variables}}para comprimento{{stringLength}}removendo caracteres da{{direction}}"
AdvSceneSwitcher.action.variable.entry.substringIndex="Início da substring:{{subStringStart}}Tamanho da substring:{{subStringSize}}"
AdvSceneSwitcher.action.variable.entry.substringRegex="Atribuir valor do{{regexMatchIdx}}correspondência usando expressão regular:"
AdvSceneSwitcher.action.variable.entry.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
AdvSceneSwitcher.action.variable.entry.userInput.customPrompt="{{useCustomPrompt}}Usar prompt personalizado{{inputPrompt}}"
AdvSceneSwitcher.action.variable.entry.userInput.placeholder="{{useInputPlaceholder}}Preencher com placeholder{{inputPlaceholder}}"
AdvSceneSwitcher.action.projector="Projetor"
AdvSceneSwitcher.action.projector.type.source="Fonte"
AdvSceneSwitcher.action.projector.type.scene="Cena"
@ -1044,6 +1050,8 @@ AdvSceneSwitcher.action.projector.type.multiview="Multivisão"
AdvSceneSwitcher.action.projector.display="Exibição"
AdvSceneSwitcher.action.projector.windowed="Janela"
AdvSceneSwitcher.action.projector.fullscreen="Tela cheia"
AdvSceneSwitcher.action.projector.entry="Abrir{{windowTypes}}projetor de{{types}}{{scenes}}{{sources}}"
AdvSceneSwitcher.action.projector.entry.monitor="em{{monitors}}"
AdvSceneSwitcher.action.midi="MIDI"
AdvSceneSwitcher.action.midi.entry="Enviar mensagem para{{device}}:"
AdvSceneSwitcher.action.midi.entry.listen="Definir seleção de mensagem MIDI para mensagens recebidas em{{listenDevices}}:{{listenButton}}"
@ -1063,10 +1071,10 @@ AdvSceneSwitcher.action.twitch.type.clip.create="Criar clipe da transmissão"
AdvSceneSwitcher.action.twitch.type.chat.announcement.send="Enviar anúncio de chat"
AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.enable="Habilitar 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.sendChatMessage="Enviar mensagem de chat"
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.layout.chat="Usando conta{{account}}{{actions}}em{{channel}}"
AdvSceneSwitcher.action.twitch.entry.default="Em{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}"
AdvSceneSwitcher.action.twitch.entry.chat="Usando conta{{account}}{{actions}}em{{channel}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}"
AdvSceneSwitcher.action.twitch.title.title="Digite o título"
AdvSceneSwitcher.action.twitch.marker.description="Descreva o marcador"
AdvSceneSwitcher.action.twitch.clip.hasDelay="Adicionar um leve atraso antes de capturar o clipe"
@ -1108,9 +1116,9 @@ AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Alternar Iniciar/Parar pa
AdvSceneSwitcher.hotkey.macro.pause="Pausar macro %1"
AdvSceneSwitcher.hotkey.macro.unpause="Retomar macro %1"
AdvSceneSwitcher.hotkey.macro.togglePause="Alternar pausa da macro %1"
AdvSceneSwitcher.hotkey.macro.segment.up="Mover seleção de segmento de macro para cima"
AdvSceneSwitcher.hotkey.macro.segment.down="Mover seleção de segmento de macro para baixo"
AdvSceneSwitcher.hotkey.macro.segment.remove="Remover segmento de macro selecionado"
AdvSceneSwitcher.hotkey.upMacroSegmentHotkey="Mover seleção de segmento de macro para cima"
AdvSceneSwitcher.hotkey.downMacroSegmentHotkey="Mover seleção de segmento de macro para baixo"
AdvSceneSwitcher.hotkey.removeMacroSegmentHotkey="Remover segmento de macro selecionado"
AdvSceneSwitcher.askBackup="Detectada uma nova versão do Advanced Scene Switcher.\nDeve ser criado um backup das configurações antigas?"
AdvSceneSwitcher.askForMacro="Selecionar macro{{macroSelection}}"
@ -1848,19 +1856,19 @@ AdvSceneSwitcher.setting.transform.width="Largura"
AdvSceneSwitcher.sceneItemSelection.configure="Configurar tipo de seleção de item de cena"
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.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.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.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.layout="{{index}}fonte"
AdvSceneSwitcher.sceneItemSelection.type.index.entry="{{index}}fonte"
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.layout="Todas as fontes"
AdvSceneSwitcher.sceneItemSelection.type.all.entry="Todas as fontes"
AdvSceneSwitcher.sceneItemSelection.all="Todas"
AdvSceneSwitcher.sceneItemSelection.any="Qualquer"
@ -1871,6 +1879,8 @@ AdvSceneSwitcher.status.inactive="Inativo"
AdvSceneSwitcher.running="Plugin em execução"
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.unit.milliseconds="milissegundos"

View File

@ -12,7 +12,7 @@ AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Всегда запу
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Не запускать переключатель сцен"
AdvSceneSwitcher.generalTab.status.start="Старт"
AdvSceneSwitcher.generalTab.status.stop="Стоп"
AdvSceneSwitcher.generalTab.status.autoStart.startup="Автоматически запускать переключатель сцен, когда:"
AdvSceneSwitcher.generalTab.status.autoStart="Автоматически запускать переключатель сцен, когда:"
AdvSceneSwitcher.generalTab.status.autoStart.never="Никогда"
AdvSceneSwitcher.generalTab.status.autoStart.recording="Запись"
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Вещание"
@ -25,6 +25,7 @@ AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.dontSwitch="Не пере
AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchToRandom="Переключиться на любую сцену на вкладке Random"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchTo="Переключиться на:"
AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint="В течение этого времени потенциальные совпадения будут игнорироваться!"
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Включить ведение подробного журнала"
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="Сохранять положение и размер окна"
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="Отключить подсказки пользовательского интерфейса"
AdvSceneSwitcher.generalTab.priority="Приоритет"
@ -36,7 +37,7 @@ AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="Экспорт"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Импорт"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Экспортировать настройки расширенного переключателя сцен в файл ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Импортировать настройки Advanced Scene Switcher из файла ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Текстовые файлы (*.txt *.json)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Текстовые файлы (*.txt)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="Advanced Scene Switcher не удалось импортировать настройки"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Настройки Advanced Scene Switcher импортированы успешно"
AdvSceneSwitcher.generalTab.priority.fileContent="Содержание файла"
@ -114,6 +115,7 @@ AdvSceneSwitcher.condition.pluginState.entry="{{condition}}"
; Macro Actions
AdvSceneSwitcher.action.scene="Переключить сцену"
AdvSceneSwitcher.action.scene.entry="Перейти к сцене{{sceneTypes}}{{scenes}}используя{{transitions}}с продолжительностью{{duration}}секунд"
AdvSceneSwitcher.action.wait="Подождать"
AdvSceneSwitcher.action.wait.type.fixed="фиксированный"
AdvSceneSwitcher.action.wait.type.random="случайный"

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.start="Başlat"
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.recording="Kayıt"
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Yayın"
@ -26,6 +26,7 @@ AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchToRandom="Rastgele s
AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchTo="Değiştirmek:"
AdvSceneSwitcher.generalTab.generalBehavior.cooldown="Bir eşleşmeden sonra aşağıdakiler için işlem yapmayın:"
AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint="Bu süre zarfında olası eşleşmeler göz ardı edilecektir!"
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Ayrıntılı günlük kaydını etkinleştir"
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="Pencere konumunu ve boyutunu kaydet"
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="Sistem tepsisi bildirimlerini göster"
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="UI ipuçlarını devre dışı bırak"
@ -38,7 +39,7 @@ AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="Dışa Aktar"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="İçe Aktar"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Gelişmiş Sahne Değiştirici ayarlarını dosyaya aktar ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Gelişmiş Sahne Değiştirici ayarlarını dosyadan içe aktar ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Text dosyası (*.txt *.json)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Text dosyası (*.txt)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="Gelişmiş Sahne Değiştirici ayarları dosyadan içe aktarmakta başarısız oldu"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Gelişmiş Sahne Değiştirici ayarları başarılı bir şekilde dosyadan içe aktarıldı"
AdvSceneSwitcher.generalTab.priority.fileContent="Dosya İçeriği"
@ -72,6 +73,7 @@ AdvSceneSwitcher.macroTab.add="Yeni Makro ekle"
AdvSceneSwitcher.macroTab.name="İsim:"
AdvSceneSwitcher.macroTab.run="Makro Çalıştırma"
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.copy="Kopya oluştur"
AdvSceneSwitcher.macroTab.expandAll="Hepsini Genişlet"
@ -138,15 +140,16 @@ AdvSceneSwitcher.condition.video.screenshotFail="Kaynağın ekran görüntüsü
AdvSceneSwitcher.condition.video.patternMatchFail="Desen bulunamadı!"
AdvSceneSwitcher.condition.video.objectMatchFail="Nesne bulunamadı!"
AdvSceneSwitcher.condition.video.modelLoadFail="Model verileri yüklenemedi!"
AdvSceneSwitcher.condition.video.layout="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.layout.modelPath="Model verileri (haar kademeli sınıflandırıcı):{{modelDataPath}}"
AdvSceneSwitcher.condition.video.layout.minNeighbor="Minimum komşular: {{minNeighbors}}"
AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}} Yalnızca her seferinde kontrol gerçekleştirerek CPU yükünü azaltın {{throttleCount}} millisaniyeler"
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.entry.modelPath="Model verileri (haar kademeli sınıflandırıcı):{{modelDataPath}}"
AdvSceneSwitcher.condition.video.entry.minNeighbor="Minimum komşular: {{minNeighbors}}"
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}} Yalnızca her seferinde kontrol gerçekleştirerek CPU yükünü azaltın {{throttleCount}} millisaniyeler"
AdvSceneSwitcher.condition.stream="Yayınlama"
AdvSceneSwitcher.condition.stream.state.start="Yayın çalışıyor"
AdvSceneSwitcher.condition.stream.state.stop="Yayın durdu"
AdvSceneSwitcher.condition.stream.state.starting="Yayın başlıyor"
AdvSceneSwitcher.condition.stream.state.stopping="Yayın duruyor"
AdvSceneSwitcher.condition.stream.entry="{{streamState}}{{keyFrameInterval}}"
AdvSceneSwitcher.condition.record="Kayıt"
AdvSceneSwitcher.condition.record.state.start="Kayıt Çalışıyor"
AdvSceneSwitcher.condition.record.state.pause="Kayıt durakladı"
@ -248,6 +251,7 @@ AdvSceneSwitcher.condition.openvr.entry.line3="HMD mevcut {{xPos}} x {{yPos}} x
; Macro Actions
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.wait="Bekle"
AdvSceneSwitcher.action.wait.type.fixed="sabit"
@ -280,7 +284,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.show="Göster"
AdvSceneSwitcher.action.sceneVisibility.type.hide="Gizle"
AdvSceneSwitcher.action.sceneVisibility.type.source="Kayıt"
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.type.enable="Etkin"
AdvSceneSwitcher.action.filter.type.disable="Etkisiz"
@ -310,7 +314,7 @@ AdvSceneSwitcher.action.pluginState.type.stop="Advanced Scene Switcher eklentisi
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.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.type.stop="Sanal Kamerayı Durdur"
AdvSceneSwitcher.action.virtualCamera.type.start="Sanal Kamerayı Başlat"
@ -332,7 +336,7 @@ AdvSceneSwitcher.action.sceneOrder.type.moveDown="Aşağı indir"
AdvSceneSwitcher.action.sceneOrder.type.moveTop="En üste taşı"
AdvSceneSwitcher.action.sceneOrder.type.moveBottom="Aşağıya taşı"
AdvSceneSwitcher.action.sceneOrder.type.movePosition="Konuma taşı"
AdvSceneSwitcher.action.sceneOrder.entry="Açık{{scenes}}{{actions}}{{sources}}{{sources2}}{{position}}"
AdvSceneSwitcher.action.sceneOrder.entry="Açık{{scenes}}{{actions}}{{sources}}{{position}}"
AdvSceneSwitcher.action.sceneTransform="Sahne öğesi dönüşümü"
AdvSceneSwitcher.action.sceneTransform.getTransform="Dönüşümü al"
AdvSceneSwitcher.action.sceneTransform.entry="Açık{{scenes}}{{action}}{{rotation}}{{sources}}{{settingSelection}}{{singleSettingValue}}"
@ -353,6 +357,7 @@ AdvSceneSwitcher.action.random="Rastgele"
AdvSceneSwitcher.action.random.entry="Aşağıdaki makrolardan herhangi birini rastgele çalıştırın (duraklatılmış makrolar yoksayılır)"
AdvSceneSwitcher.action.systray="Sistem tepsisi bildirimi"
AdvSceneSwitcher.action.screenshot="Ekran görüntüsü"
AdvSceneSwitcher.action.screenshot.mainOutput="OBS'nin ana çıkışı"
AdvSceneSwitcher.action.profile="Profil"
AdvSceneSwitcher.action.profile.entry="Aktif profili şununla değiştir: {{profiles}}"
AdvSceneSwitcher.action.sceneCollection="Sahne koleksiyonu"
@ -586,6 +591,8 @@ AdvSceneSwitcher.status.inactive="İnaktif"
AdvSceneSwitcher.running="Eklenti çalışıyor"
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.seconds="saniye"
AdvSceneSwitcher.unit.minutes="dakika"

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

1
deps/date vendored

@ -1 +0,0 @@
Subproject commit 5bdb7e6f31fac909c090a46dbd9fea27b6e609a4

12844
deps/exprtk/exprtk.hpp vendored

File diff suppressed because it is too large Load Diff

2
deps/json vendored

@ -1 +1 @@
Subproject commit 55f93686c01528224f448c19128836e7df245f72
Subproject commit bc889afb4c5bf1c0d8ee29ef35eaaf4c8bef8a5d

1
deps/jsoncons vendored

@ -1 +0,0 @@
Subproject commit 64b9da1e9f15eeff4ec9d6bc856538db542118f2

2
deps/libremidi vendored

@ -1 +1 @@
Subproject commit 73e6ea40de1a1ee35f16022e70fecfb45ae4061d
Subproject commit d6d6557b5bd138a56b7ea68dfcb92a0f9ff70a5b

2
deps/libusb vendored

@ -1 +1 @@
Subproject commit 15a7ebb4d426c5ce196684347d2b7cafad862626
Subproject commit d52e355daa09f17ce64819122cb067b8a2ee0d4b

1
deps/paho.mqtt.cpp vendored

@ -1 +0,0 @@
Subproject commit 165476b1dc248b3f4480f05646086326e1d7d82e

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,6 @@
#include "advanced-scene-switcher.hpp"
#include "backup.hpp"
#include "crash-handler.hpp"
#include "curl-helper.hpp"
#include "log-helper.hpp"
#include "macro-helpers.hpp"
#include "obs-module-helper.hpp"
@ -19,15 +19,10 @@
#include <obs-frontend-api.h>
#include <QAction>
#include <QDirIterator>
#include <QLibrary>
#include <QMainWindow>
#include <QTextStream>
#include <regex>
#ifdef _WIN32
#include <Windows.h>
#endif
namespace advss {
AdvSceneSwitcher *AdvSceneSwitcher::window = nullptr;
@ -147,7 +142,16 @@ void AdvSceneSwitcher::LoadUI()
bool AdvSceneSwitcher::eventFilter(QObject *obj, QEvent *event)
{
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);
auto pressedKey = keyEvent->key();
@ -192,21 +196,25 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
switcher->m.lock();
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->m.unlock();
if (switcher->stop) {
return;
if (!switcher->stop) {
switcher->Start();
}
if (ShouldSkipPluginStartOnUncleanShutdown()) {
return;
}
switcher->Start();
}
}
@ -299,7 +307,7 @@ void SwitcherData::Thread()
}
}
RunIntervalResetSteps();
ResetForNextInterval();
if (match) {
if (macroMatch) {
@ -349,6 +357,14 @@ void SwitcherData::SetPreconditions()
InvalidateMacroTempVarValues();
}
void SwitcherData::ResetForNextInterval()
{
// Plugin reset functions
for (const auto &func : resetIntervalSteps) {
func();
}
}
bool SwitcherData::CheckForMatch(OBSWeakSource &scene,
OBSWeakSource &transition, int &linger,
bool &setPrevSceneAfterLinger,
@ -418,7 +434,7 @@ bool SwitcherData::CheckForMatch(OBSWeakSource &scene,
static void ResetMacros()
{
for (auto &m : GetTopLevelMacros()) {
for (auto &m : GetMacros()) {
ResetMacroRunCount(m.get());
ResetMacroConditionTimers(m.get());
}
@ -429,7 +445,7 @@ void AutoStartActionQueues();
void SwitcherData::Start()
{
if (!(th && th->isRunning())) {
RunIntervalResetSteps();
ResetForNextInterval();
ResetMacros();
AutoStartActionQueues();
@ -437,7 +453,10 @@ void SwitcherData::Start()
th = new SwitcherThread();
th->start((QThread::Priority)threadPriority);
RunStartSteps();
// Will be overwritten quickly but might be useful
writeToStatusFile("Advanced Scene Switcher running");
SendWebsocketVendorEvent("AdvancedSceneSwitcherStarted",
nullptr);
}
if (showSystemTrayNotifications) {
@ -464,7 +483,11 @@ void SwitcherData::Stop()
th->wait();
delete th;
th = nullptr;
RunStopSteps();
writeToStatusFile("Advanced Scene Switcher stopped");
if (!obsIsShuttingDown) {
SendWebsocketVendorEvent("AdvancedSceneSwitcherStopped",
nullptr);
}
}
if (showSystemTrayNotifications) {
@ -535,7 +558,6 @@ static void handleSceneChange()
}
switcher->checkDefaultSceneTransitions();
switcher->CheckAutoStart();
}
static void setLiveTime()
@ -550,28 +572,18 @@ static void resetLiveTime()
static void checkAutoStartRecording()
{
if (switcher->obsIsShuttingDown) {
return;
}
if (switcher->autoStartEvent == SwitcherData::AutoStart::RECORDING ||
switcher->autoStartEvent ==
SwitcherData::AutoStart::RECORINDG_OR_STREAMING) {
SwitcherData::AutoStart::RECORINDG_OR_STREAMING)
switcher->Start();
}
}
static void checkAutoStartStreaming()
{
if (switcher->obsIsShuttingDown) {
return;
}
if (switcher->autoStartEvent == SwitcherData::AutoStart::STREAMING ||
switcher->autoStartEvent ==
SwitcherData::AutoStart::RECORINDG_OR_STREAMING) {
SwitcherData::AutoStart::RECORINDG_OR_STREAMING)
switcher->Start();
}
}
static void handleTransitionEnd()
@ -607,7 +619,7 @@ static void handleSceneCollectionChanging()
AdvSceneSwitcher::window->close();
}
if (!switcher->stop) {
switcher->sceneCollectionStop = true;
switcher->sceneColletionStop = true;
switcher->Stop();
}
}
@ -723,7 +735,7 @@ void OpenSettingsWindow()
}
}
void AdvSceneSwitcher::HighlightMacroSettingsButton(bool enable)
void AdvSceneSwitcher::HighligthMacroSettingsButton(bool enable)
{
static QObject *highlight = nullptr;
if ((highlight && enable) || (!highlight && !enable)) {
@ -743,28 +755,13 @@ void AdvSceneSwitcher::HighlightMacroSettingsButton(bool enable)
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 HighligthMacroSettingsButton(bool enable)
{
auto window = GetSettingsWindow();
if (!window) {
return;
}
static_cast<AdvSceneSwitcher *>(window)->HighlightMacroSettingsButton(
static_cast<AdvSceneSwitcher *>(window)->HighligthMacroSettingsButton(
enable);
}

View File

@ -11,7 +11,6 @@ namespace advss {
class MacroActionEdit;
class MacroConditionEdit;
class MacroSegment;
class Duration;
class SequenceWidget;
struct SceneGroup;
@ -45,6 +44,7 @@ protected:
/* --- Begin of general tab section --- */
public:
void SetupGeneralTab();
void UpdateNonMatchingScene(const QString &name);
void SetDeprecationWarnings();
public slots:
@ -57,6 +57,7 @@ public slots:
void on_startupBehavior_currentIndexChanged(int index);
void on_logLevel_currentIndexChanged(int index);
void on_autoStartEvent_currentIndexChanged(int index);
void on_noMatchSwitchScene_currentTextChanged(const QString &text);
void on_checkInterval_valueChanged(int value);
void on_tabWidget_currentChanged(int index);
void on_exportSettings_clicked();
@ -70,56 +71,142 @@ public slots:
void on_priorityUp_clicked();
void on_priorityDown_clicked();
void on_threadPriority_currentTextChanged(const QString &text);
void on_openSetupWizard_clicked();
/* --- End of legacy tab section --- */
/* --- Begin of macro tab section --- */
public:
void SetupMacroTab();
bool MacroTabIsInFocus();
bool AddNewMacro(std::shared_ptr<Macro> &res, std::string &name,
std::string format = "");
void RemoveMacro(std::shared_ptr<Macro> &);
void RemoveSelectedMacros();
void RenameMacro(std::shared_ptr<Macro> &, const QString &name);
std::shared_ptr<Macro> GetSelectedMacro() const;
std::vector<std::shared_ptr<Macro>> GetSelectedMacros() const;
void SetMacroEditAreaDisabled(bool) 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;
std::shared_ptr<Macro> GetSelectedMacro();
std::vector<std::shared_ptr<Macro>> GetSelectedMacros();
void SetEditMacro(Macro &m);
void SetMacroEditAreaDisabled(bool);
void HighlightAction(int idx, QColor color = QColor(Qt::green));
void HighlightElseAction(int idx, QColor color = QColor(Qt::green));
void HighlightCondition(int idx, QColor color = QColor(Qt::green));
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 SetActionData(Macro &m) const;
void SetElseActionData(Macro &m) const;
void SetConditionData(Macro &m) const;
void SetActionData(Macro &m);
void SetElseActionData(Macro &m);
void SetConditionData(Macro &m);
void SwapActions(Macro *m, int pos1, int pos2);
void SwapConditions(Macro *m, int pos1, int pos2);
void HighlightMacroSettingsButton(bool enable = true);
void HighligthMacroSettingsButton(bool enable = true);
public slots:
void on_macroAdd_clicked();
void on_macroRemove_clicked();
void on_macroUp_clicked() const;
void on_macroDown_clicked() const;
void on_macroUp_clicked();
void on_macroDown_clicked();
void on_macroName_editingFinished();
void on_runMacroInParallel_stateChanged(int value) const;
void on_actionTriggerMode_currentIndexChanged(int index) const;
void on_runMacroInParallel_stateChanged(int value);
void on_runMacroOnChange_stateChanged(int value);
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();
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();
void MacroSelectionChanged();
void UpMacroSegementHotkey();
void DownMacroSegementHotkey();
void DeleteMacroSegementHotkey();
void ShowMacroContextMenu(const QPoint &);
void ShowMacroActionsContextMenu(const QPoint &);
void ShowMacroElseActionsContextMenu(const QPoint &);
void ShowMacroConditionsContextMenu(const QPoint &);
void CopyMacro();
void RenameSelectedMacro();
void ExportMacros() const;
void ExportMacros();
void ImportMacros();
void HighlightOnChange() const;
void ExpandAllActions();
void ExpandAllElseActions();
void ExpandAllConditions();
void CollapseAllActions();
void CollapseAllElseActions();
void CollapseAllConditions();
void MinimizeActions();
void MaximizeActions();
void MinimizeElseActions();
void MaximizeElseActions();
void MinimizeConditions();
void MaximizeConditions();
void SetElseActionsStateToHidden();
void SetElseActionsStateToVisible();
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();
void HighlightOnChange();
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();
void HighlightMacrosChanged(bool value);
void ConnectionAdded(const QString &);
void ConnectionRenamed(const QString &oldName, const QString &newName);
void ConnectionRemoved(const QString &);
private:
enum class MacroSection { CONDITIONS, ACTIONS, ELSE_ACTIONS };
void SetupMacroSegmentSelection(MacroSection type, int idx);
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 --- */
@ -299,6 +386,6 @@ private:
};
void OpenSettingsWindow();
void HighlightMacroSettingsButton(bool enable);
void HighligthMacroSettingsButton(bool enable);
} // namespace advss

View File

@ -1,18 +1,17 @@
#include "advanced-scene-switcher.hpp"
#include "file-selection.hpp"
#include "filter-combo-box.hpp"
#include "first-run-wizard.hpp"
#include "layout-helpers.hpp"
#include "macro.hpp"
#include "macro-search.hpp"
#include "macro-settings.hpp"
#include "path-helpers.hpp"
#include "selection-helpers.hpp"
#include "source-helpers.hpp"
#include "splitter-helpers.hpp"
#include "status-control.hpp"
#include "switcher-data.hpp"
#include "tab-helpers.hpp"
#include "ui-helpers.hpp"
#include "utility.hpp"
#include "variable.hpp"
#include "version.h"
@ -26,6 +25,15 @@ void AdvSceneSwitcher::reject()
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()
{
if (loading) {
@ -47,6 +55,7 @@ void AdvSceneSwitcher::on_noMatchSwitch_clicked()
std::lock_guard<std::mutex> lock(switcher->m);
switcher->switchIfNotMatching = NoMatchBehavior::SWITCH;
ui->noMatchSwitchScene->setEnabled(true);
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
ui->randomDisabledWarning->setVisible(true);
}
@ -104,12 +113,12 @@ void AdvSceneSwitcher::on_startupBehavior_currentIndexChanged(int index)
static_cast<SwitcherData::StartupBehavior>(index);
}
void AdvSceneSwitcher::on_logLevel_currentIndexChanged(int idx)
void AdvSceneSwitcher::on_logLevel_currentIndexChanged(int value)
{
if (loading) {
return;
}
SetLogLevel(static_cast<LogLevel>(ui->logLevel->itemData(idx).toInt()));
switcher->logLevel = static_cast<SwitcherData::LogLevel>(value);
}
void AdvSceneSwitcher::on_autoStartEvent_currentIndexChanged(int index)
@ -122,6 +131,17 @@ void AdvSceneSwitcher::on_autoStartEvent_currentIndexChanged(int 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)
{
if (loading) {
@ -143,7 +163,7 @@ void AdvSceneSwitcher::closeEvent(QCloseEvent *)
switcher->windowSize = this->size();
switcher->macroListMacroEditSplitterPosition =
ui->macroListMacroEditSplitter->sizes();
ui->macroEdit->SetMacro(nullptr); // Trigger saving of splitter states
MacroSelectionAboutToChange(); // Trigger saving of splitter states
obs_frontend_save();
}
@ -255,15 +275,12 @@ static bool containsSensitiveData(obs_data_t *data)
obs_data_get_array(data, "twitchConnections");
OBSDataArrayAutoRelease websocketConnections =
obs_data_get_array(data, "websocketConnections");
OBSDataArrayAutoRelease mqttConnections =
obs_data_get_array(data, "mqttConnections");
auto isNotEmpty = [](obs_data_array *array) {
return obs_data_array_count(array) > 0;
};
return isNotEmpty(twitchTokens) || isNotEmpty(websocketConnections) ||
isNotEmpty(mqttConnections);
return isNotEmpty(twitchTokens) || isNotEmpty(websocketConnections);
}
void AdvSceneSwitcher::on_exportSettings_clicked()
@ -327,10 +344,6 @@ void AdvSceneSwitcher::on_importSettings_clicked()
return;
}
// We have to make sure to that no macro is currently being edited while
// the new settings are loaded
ui->macros->clearSelection();
std::lock_guard<std::mutex> lock(switcher->m);
switcher->LoadSettings(obj);
switcher->lastImportPath = path.toStdString();
@ -360,46 +373,13 @@ 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()
{
if (!IsFirstRun() || !GetTopLevelMacros().empty()) {
return;
if (switcher->firstBoot && !switcher->disableHints) {
switcher->firstBoot = false;
DisplayMessage(
obs_module_text("AdvSceneSwitcher.firstBootMessage"));
}
auto macro = FirstRunWizard::ShowWizard(this);
if (macro) {
renameMacroIfNecessary(macro);
QTimer::singleShot(0, this,
[this, macro]() { ui->macros->Add(macro); });
}
switcher->Start();
}
void AdvSceneSwitcher::on_openSetupWizard_clicked()
{
auto macro = FirstRunWizard::ShowWizard(this);
if (!macro) {
return;
}
renameMacroIfNecessary(macro);
ui->macros->Add(macro);
ui->tabWidget->setCurrentWidget(ui->macroTab);
}
void AdvSceneSwitcher::on_tabWidget_currentChanged(int)
@ -453,14 +433,16 @@ void SwitcherData::LoadSettings(obs_data_t *obj)
}
// 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
// selections to be available.
loadSceneGroups(obj);
LoadVariables(obj);
RunLoadSteps(obj);
for (const auto &func : loadSteps) {
func(obj);
}
LoadMacros(obj);
LoadGlobalMacroSettings(obj);
@ -481,7 +463,7 @@ void SwitcherData::LoadSettings(obs_data_t *obj)
LoadHotkeys(obj);
LoadUISettings(obj);
RunAndClearPostLoadSteps();
RunPostLoadSteps();
// Reset on startup and scene collection change
ResetLastOpenedTab();
@ -516,16 +498,18 @@ void SwitcherData::SaveSettings(obs_data_t *obj)
SaveUISettings(obj);
SaveVersion(obj, g_GIT_SHA1);
RunSaveSteps(obj);
for (const auto &func : saveSteps) {
func(obj);
}
}
void SwitcherData::SaveGeneralSettings(obs_data_t *obj)
{
obs_data_set_int(obj, "interval", interval);
OBSDataAutoRelease noMatchScene = obs_data_create();
nonMatchingScene.Save(noMatchScene);
obs_data_set_obj(obj, "noMatchScene", noMatchScene);
std::string nonMatchingSceneName = GetWeakSourceName(nonMatchingScene);
obs_data_set_string(obj, "non_matching_scene",
nonMatchingSceneName.c_str());
obs_data_set_int(obj, "switch_if_not_matching",
static_cast<int>(switchIfNotMatching));
noMatchDelay.Save(obj, "noMatchDelay");
@ -533,21 +517,16 @@ void SwitcherData::SaveGeneralSettings(obs_data_t *obj)
cooldown.Save(obj, "cooldown");
obs_data_set_bool(obj, "enableCooldown", enableCooldown);
obs_data_set_bool(obj, "active", sceneCollectionStop ? true : !stop);
sceneCollectionStop = false;
obs_data_set_bool(obj, "active", sceneColletionStop ? true : !stop);
sceneColletionStop = false;
obs_data_set_int(obj, "startup_behavior",
static_cast<int>(startupBehavior));
OBSDataAutoRelease autoStart = obs_data_create();
obs_data_set_int(autoStart, "event", 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);
obs_data_set_int(obj, "autoStartEvent",
static_cast<int>(autoStartEvent));
obs_data_set_int(obj, "logLevel", static_cast<int>(logLevel));
obs_data_set_int(obj, "logLevelVersion", 1);
obs_data_set_bool(obj, "showSystemTrayNotifications",
showSystemTrayNotifications);
obs_data_set_bool(obj, "disableHints", disableHints);
@ -577,14 +556,9 @@ void SwitcherData::LoadGeneralSettings(obs_data_t *obj)
static_cast<int>(NoMatchBehavior::NO_SWITCH));
switchIfNotMatching = static_cast<NoMatchBehavior>(
obs_data_get_int(obj, "switch_if_not_matching"));
if (obs_data_has_user_value(obj, "noMatchScene")) {
OBSDataAutoRelease noMatchScene =
obs_data_get_obj(obj, "noMatchScene");
nonMatchingScene.Load(noMatchScene);
} else {
nonMatchingScene.Load(obj, "non_matching_scene");
}
std::string nonMatchingSceneName =
obs_data_get_string(obj, "non_matching_scene");
nonMatchingScene = GetWeakSourceByName(nonMatchingSceneName.c_str());
noMatchDelay.Load(obj, "noMatchDelay");
cooldown.Load(obj, "cooldown");
@ -605,17 +579,28 @@ void SwitcherData::LoadGeneralSettings(obs_data_t *obj)
stop = true;
}
OBSDataAutoRelease autoStart = obs_data_get_obj(obj, "autoStart");
autoStartEvent = static_cast<AutoStart>(
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);
autoStartEvent =
static_cast<AutoStart>(obs_data_get_int(obj, "autoStartEvent"));
LoadLogLevel(obj);
logLevel = static_cast<LogLevel>(obs_data_get_int(obj, "logLevel"));
if (obs_data_get_int(obj, "logLevelVersion") < 1) {
enum OldLogLevel { DEFAULT, LOG_ACTION, VERBOSE };
OldLogLevel oldLogLevel = static_cast<OldLogLevel>(
obs_data_get_int(obj, "logLevel"));
switch (oldLogLevel) {
case DEFAULT:
logLevel = LogLevel::DEFAULT;
break;
case LOG_ACTION:
logLevel = LogLevel::LOG_ACTION;
break;
case VERBOSE:
logLevel = LogLevel::VERBOSE;
break;
default:
break;
}
}
showSystemTrayNotifications =
obs_data_get_bool(obj, "showSystemTrayNotifications");
@ -691,10 +676,10 @@ void SwitcherData::CheckNoMatchSwitch(bool &match, OBSWeakSource &scene,
return;
}
auto noMatchScene = nonMatchingScene.GetScene(false);
if (switchIfNotMatching == NoMatchBehavior::SWITCH && noMatchScene) {
if (switchIfNotMatching == NoMatchBehavior::SWITCH &&
nonMatchingScene) {
match = true;
scene = noMatchScene;
scene = nonMatchingScene;
transition = nullptr;
}
if (switchIfNotMatching == NoMatchBehavior::RANDOM_SWITCH) {
@ -702,27 +687,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)
{
if (!match || !enableCooldown) {
@ -865,7 +829,7 @@ static void setupGeneralTabInactiveWarning(QTabWidget *tabs)
inactiveTimer->start();
}
void AdvSceneSwitcher::SetCheckIntervalTooLowVisibility() const
void advss::AdvSceneSwitcher::SetCheckIntervalTooLowVisibility() const
{
auto macro = GetMacroWithInvalidConditionInterval();
if (!macro) {
@ -889,6 +853,8 @@ void AdvSceneSwitcher::SetCheckIntervalTooLowVisibility() const
void AdvSceneSwitcher::SetupGeneralTab()
{
PopulateSceneSelection(ui->noMatchSwitchScene, false);
if (switcher->switchIfNotMatching == NoMatchBehavior::SWITCH) {
ui->noMatchSwitch->setChecked(true);
ui->noMatchSwitchScene->setEnabled(true);
@ -900,17 +866,8 @@ void AdvSceneSwitcher::SetupGeneralTab()
ui->noMatchRandomSwitch->setChecked(true);
ui->noMatchSwitchScene->setEnabled(false);
}
ui->noMatchSwitchScene->SetScene(switcher->nonMatchingScene);
ui->noMatchSwitchScene->LockToMainCanvas();
connect(ui->noMatchSwitchScene, &SceneSelectionWidget::SceneChanged,
this, [this](const SceneSelection &scene) {
if (loading) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switcher->nonMatchingScene = scene;
});
ui->noMatchSwitchScene->setCurrentText(
GetWeakSourceName(switcher->nonMatchingScene).c_str());
DurationSelection *noMatchDelay = new DurationSelection();
noMatchDelay->SetDuration(switcher->noMatchDelay);
@ -933,9 +890,7 @@ void AdvSceneSwitcher::SetupGeneralTab()
SIGNAL(DurationChanged(const Duration &)), this,
SLOT(CooldownDurationChanged(const Duration &)));
PopulateLogLevelSelection(ui->logLevel);
ui->logLevel->setCurrentIndex(
ui->logLevel->findData(static_cast<int>(GetLogLevel())));
ui->logLevel->setCurrentIndex(static_cast<int>(switcher->logLevel));
ui->saveWindowGeo->setChecked(switcher->saveWindowGeo);
ui->showTrayNotifications->setChecked(
@ -958,88 +913,6 @@ void AdvSceneSwitcher::SetupGeneralTab()
populateAutoStartEventSelection(ui->autoStartEvent);
ui->autoStartEvent->setCurrentIndex(
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
auto statusControl = new StatusControl(this, true);
@ -1060,8 +933,6 @@ void AdvSceneSwitcher::SetupGeneralTab()
setTabOrder(ui->importSettings, ui->cooldownTime);
setTabOrder(ui->cooldownTime, ui->noMatchDontSwitch);
SetupShowAllTabsCheckBox(ui->alwaysShowFeatureTabs, ui->tabWidget);
MinimizeSizeOfColumn(ui->statusLayout, 0);
setWindowTitle(windowTitle() + " - " + g_GIT_TAG);
}

View File

@ -259,8 +259,7 @@ void AudioSwitch::setVolumeLevel(void *data, const float *,
}
}
static obs_volmeter_t *addVolmeterToSource(AudioSwitch *entry,
obs_weak_source *source)
obs_volmeter_t *AddVolmeterToSource(AudioSwitch *entry, obs_weak_source *source)
{
obs_volmeter_t *volmeter = obs_volmeter_create(OBS_FADER_LOG);
obs_volmeter_add_callback(volmeter, AudioSwitch::setVolumeLevel, entry);
@ -280,7 +279,7 @@ void AudioSwitch::resetVolmeter()
obs_volmeter_remove_callback(volmeter, setVolumeLevel, this);
obs_volmeter_destroy(volmeter);
volmeter = addVolmeterToSource(this, audioSource);
volmeter = AddVolmeterToSource(this, audioSource);
}
bool AudioSwitch::initialized()
@ -319,7 +318,7 @@ void AudioSwitch::load(obs_data_t *obj)
duration.Load(obj, "duration");
ignoreInactiveSource = obs_data_get_bool(obj, "ignoreInactiveSource");
volmeter = addVolmeterToSource(this, audioSource);
volmeter = AddVolmeterToSource(this, audioSource);
}
void AudioSwitchFallback::save(obs_data_t *obj)
@ -350,7 +349,7 @@ AudioSwitch::AudioSwitch(const AudioSwitch &other)
condition(other.condition),
duration(other.duration)
{
volmeter = addVolmeterToSource(this, other.audioSource);
volmeter = AddVolmeterToSource(this, other.audioSource);
}
AudioSwitch::AudioSwitch(AudioSwitch &&other) noexcept

View File

@ -21,29 +21,6 @@ bool FileSwitch::pause = false;
static QObject *addPulse = nullptr;
static std::hash<std::string> strHash;
static void writeToStatusFile(const QString &msg)
{
if (!GetSwitcher() || !GetSwitcher()->fileIO.writeEnabled ||
GetSwitcher()->fileIO.writePath.empty()) {
return;
}
QFile file(QString::fromStdString(GetSwitcher()->fileIO.writePath));
if (file.open(QIODevice::ReadWrite)) {
QTextStream stream(&file);
stream << msg << Qt::endl;
}
file.close();
}
static bool _ = []() {
AddStartStep(
[]() { writeToStatusFile("Advanced Scene Switcher running"); });
AddStopStep(
[]() { writeToStatusFile("Advanced Scene Switcher stopped"); });
return true;
}();
void AdvSceneSwitcher::on_browseButton_clicked()
{
QString path = QFileDialog::getOpenFileName(
@ -136,6 +113,24 @@ void SwitcherData::writeSceneInfoToFile()
}
}
void SwitcherData::writeToStatusFile(const QString &msg)
{
if (!fileIO.writeEnabled || fileIO.writePath.empty()) {
return;
}
QFile file(QString::fromStdString(fileIO.writePath));
if (file.open(QIODevice::ReadWrite)) {
QTextStream stream(&file);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
stream << msg << "\n";
#else
stream << msg << Qt::endl;
#endif
}
file.close();
}
bool SwitcherData::checkSwitchInfoFromFile(OBSWeakSource &scene,
OBSWeakSource &transition)
{

View File

@ -32,7 +32,6 @@
#endif
#include <fstream>
#include <sstream>
#include "kwin-helpers.h"
namespace advss {
@ -45,10 +44,6 @@ static XScreenSaverAllocInfoFunc allocSSFunc = nullptr;
static XScreenSaverQueryInfoFunc querySSFunc = nullptr;
bool canGetIdleTime = false;
static bool KWin = false;
static FocusNotifier notifier;
static QString KWinScriptObjectPath;
static QLibrary *libprocps = nullptr;
#ifdef PROCPS_AVAILABLE
typedef PROCTAB *(*openproc_func)(int flags);
@ -280,11 +275,6 @@ int getActiveWindow(Window *&window)
void GetCurrentWindowTitle(std::string &title)
{
if (KWin) {
title = FocusNotifier::getActiveWindowTitle();
return;
}
Window *data = 0;
if (getActiveWindow(data) != Success || !data) {
return;
@ -296,7 +286,6 @@ void GetCurrentWindowTitle(std::string &title)
auto name = getWindowName(data[0]);
XFree(data);
if (name.empty()) {
return;
}
@ -395,11 +384,7 @@ static void getProcessListProcps2(QStringList &processes)
return;
}
while ((stack = procps_pids_get_(info, PIDS_FETCH_TASKS_ONLY))) {
#ifdef PROCPS2_USE_INFO
auto cmd = PIDS_VAL(0, str, stack, info);
#else
auto cmd = PIDS_VAL(0, str, stack);
#endif
QString procName(cmd);
if (!procName.isEmpty() && !processes.contains(procName)) {
processes << procName;
@ -423,10 +408,6 @@ void GetProcessList(QStringList &processes)
long getForegroundProcessPid()
{
if (KWin) {
return FocusNotifier::getActiveWindowPID();
}
Window *window;
if (getActiveWindow(window) != Success || !window || !*window) {
return -1;
@ -452,7 +433,6 @@ long getForegroundProcessPid()
pid = *((long *)prop);
XFree(prop);
return pid;
}
@ -566,11 +546,6 @@ static void initProc2()
#endif
}
int ignoreXerror(Display *d, XErrorEvent *e)
{
return 0;
}
void PlatformInit()
{
auto display = disp();
@ -578,21 +553,9 @@ void PlatformInit()
return;
}
KWin = isKWinAvailable();
if (!(KWin && startKWinScript(KWinScriptObjectPath) &&
registerKWinDBusListener(&notifier))) {
// something bad happened while trying to initialize
// the KWin script/dbus so disable it
KWin = false;
blog(LOG_INFO, "not using KWin compat");
} else {
blog(LOG_INFO, "using KWin compat");
}
initXss();
initProcps();
initProc2();
XSetErrorHandler(ignoreXerror);
}
static void cleanupHelper(QLibrary *lib)
@ -609,9 +572,6 @@ void PlatformCleanup()
cleanupHelper(libprocps);
cleanupHelper(libproc2);
cleanupDisplay();
XSetErrorHandler(NULL);
if (KWin && !KWinScriptObjectPath.isEmpty())
stopKWinScript(KWinScriptObjectPath);
}
} // namespace advss

View File

@ -1,166 +0,0 @@
#include "kwin-helpers.h"
#include "log-helper.hpp"
#include <QDir>
#include <QFile>
#include <QFileDevice>
#include <QTextStream>
#include <QtDBus/QDBusConnectionInterface>
#include <QtDBus/QDBusInterface>
#include <QtDBus/QDBusReply>
namespace advss {
int FocusNotifier::activePID = -1;
std::string FocusNotifier::activeTitle = {};
int FocusNotifier::getActiveWindowPID()
{
return activePID;
}
std::string FocusNotifier::getActiveWindowTitle()
{
return activeTitle;
}
void FocusNotifier::focusChanged(const int pid)
{
activePID = pid;
}
void FocusNotifier::focusTitle(const QString &title)
{
activeTitle = title.toStdString();
}
bool isKWinAvailable()
{
const QDBusConnectionInterface *interface =
QDBusConnection::sessionBus().interface();
if (!interface)
return false;
const QStringList services =
interface->registeredServiceNames().value();
return services.contains("org.kde.KWin");
}
bool startKWinScript(QString &scriptObjectPath)
{
const QString scriptPath =
"/tmp/AdvancedSceneSwitcher/KWinFocusNotifier.js";
const QString script =
R"(workspace.windowActivated.connect(function(client) {
if (!client) return;
if (!client.pid) return;
if (!client.caption) return;
callDBus(
"com.github.AdvancedSceneSwitcher",
"/com/github/AdvancedSceneSwitcher",
"com.github.AdvancedSceneSwitcher",
"focusChanged",
client.pid
);
callDBus(
"com.github.AdvancedSceneSwitcher",
"/com/github/AdvancedSceneSwitcher",
"com.github.AdvancedSceneSwitcher",
"focusTitle",
client.caption
);
}))";
if (const QDir dir; !dir.mkpath(QFileInfo(scriptPath).absolutePath())) {
blog(LOG_ERROR, "error creating /tmp/AdvancedSceneSwitcher");
return false;
}
QFile scriptFile(scriptPath);
if (!scriptFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
blog(LOG_ERROR,
"error opening KWinFocusNotifier.js for writing");
return false;
}
scriptFile.setPermissions(QFileDevice::ReadOwner |
QFileDevice::WriteOwner);
QTextStream outputStream(&scriptFile);
outputStream << script;
scriptFile.close();
const QDBusConnection bus = QDBusConnection::sessionBus();
QDBusInterface scriptingIface("org.kde.KWin", "/Scripting",
"org.kde.kwin.Scripting", bus);
if (!scriptingIface.isValid()) {
return false;
}
const QDBusReply<bool> scriptRunningReply =
scriptingIface.call("isScriptLoaded", scriptPath);
if (scriptRunningReply.isValid() && scriptRunningReply.value()) {
// script already registered and running, don't do it again
// this will leave the script running since we do not have
// a valid script id anymore, but at the very least this prevents
// it from running multiple times
return true;
}
const QDBusReply<int> scriptIdReply =
scriptingIface.call("loadScript", scriptPath);
if (!scriptIdReply.isValid()) {
return false;
}
const int scriptId = scriptIdReply.value();
scriptObjectPath =
QString("/Scripting/Script%1").arg(QString::number(scriptId));
QDBusInterface scriptRunner("org.kde.KWin", scriptObjectPath,
"org.kde.kwin.Script", bus);
if (!scriptRunner.isValid()) {
return false;
}
const QDBusReply<void> runReply = scriptRunner.call("run");
return runReply.isValid();
}
bool stopKWinScript(const QString &scriptObjectPath)
{
QDBusInterface scriptRunner("org.kde.KWin", scriptObjectPath,
"org.kde.kwin.Script",
QDBusConnection::sessionBus());
if (!scriptRunner.isValid()) {
return false;
}
const QDBusReply<void> stopReply = scriptRunner.call("stop");
return stopReply.isValid();
}
bool registerKWinDBusListener(FocusNotifier *notifier)
{
static const QString serviceName = "com.github.AdvancedSceneSwitcher";
static const QString objectPath = "/com/github/AdvancedSceneSwitcher";
auto bus = QDBusConnection::sessionBus();
if (bus.objectRegisteredAt(objectPath)) {
// already registered?
return true;
}
if (!bus.registerService(serviceName)) {
return false;
}
if (!bus.registerObject(objectPath, notifier,
QDBusConnection::ExportAllSlots)) {
return false;
}
return true;
}
} // namespace advss

View File

@ -1,33 +0,0 @@
#pragma once
#include <QObject>
#include <QString>
#include <string>
namespace advss {
class FocusNotifier final : public QObject {
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "com.github.AdvancedSceneSwitcher")
static int activePID;
static std::string activeTitle;
public:
using QObject::QObject;
static int getActiveWindowPID();
static std::string getActiveWindowTitle();
public slots:
void focusChanged(const int pid);
void focusTitle(const QString &title);
};
bool isKWinAvailable();
bool startKWinScript(QString &scriptObjectPath);
bool stopKWinScript(const QString &scriptObjectPath);
bool registerKWinDBusListener(FocusNotifier *notifier);
void printDBusError();
} // namespace advss

View File

@ -7,6 +7,8 @@
#include "section.hpp"
#include "switch-button.hpp"
#include <QGraphicsOpacityEffect>
namespace advss {
static inline void populateActionSelection(QComboBox *list)
@ -15,9 +17,6 @@ static inline void populateActionSelection(QComboBox *list)
QString entry(obs_module_text(action._name.c_str()));
if (list->findText(entry) == -1) {
list->addItem(entry);
qobject_cast<QListView *>(list->view())
->setRowHidden(list->count() - 1,
action._hidden);
} else {
blog(LOG_WARNING,
"did not insert duplicate action entry with name \"%s\"",
@ -28,20 +27,19 @@ static inline void populateActionSelection(QComboBox *list)
}
MacroActionEdit::MacroActionEdit(QWidget *parent,
std::shared_ptr<MacroAction> *entryData)
std::shared_ptr<MacroAction> *entryData,
const std::string &id)
: MacroSegmentEdit(parent),
_actionSelection(new FilterComboBox()),
_enable(new SwitchButton()),
_entryData(entryData)
{
auto actionStateTimer = new QTimer(this);
QWidget::connect(_actionSelection,
SIGNAL(currentTextChanged(const QString &)), this,
SLOT(ActionSelectionChanged(const QString &)));
QWidget::connect(_enable, SIGNAL(checked(bool)), this,
SLOT(ActionEnableChanged(bool)));
QWidget::connect(actionStateTimer, SIGNAL(timeout()), this,
QWidget::connect(&_actionStateTimer, SIGNAL(timeout()), this,
SLOT(UpdateActionState()));
populateActionSelection(_actionSelection);
@ -62,40 +60,12 @@ MacroActionEdit::MacroActionEdit(QWidget *parent,
setLayout(mainLayout);
_entryData = entryData;
SetupWidgets(true);
UpdateEntryData(id);
actionStateTimer->start(300);
_actionStateTimer.start(300);
_loading = false;
}
void MacroActionEdit::SetupWidgets(bool basicSetup)
{
if (_allWidgetsAreSetup) {
return;
}
const auto id = (*_entryData)->GetId();
_actionSelection->setCurrentText(
obs_module_text(MacroActionFactory::GetActionName(id).c_str()));
const bool enabled = (*_entryData)->Enabled();
_enable->setChecked(enabled);
SetDisableEffect(!enabled);
HeaderInfoChanged(
QString::fromStdString((*_entryData)->GetShortDesc()));
if (basicSetup) {
return;
}
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
this, SLOT(HeaderInfoChanged(const QString &)));
_section->SetContent(widget, (*_entryData)->GetCollapsed());
SetFocusPolicyOfWidgets();
_allWidgetsAreSetup = true;
}
void MacroActionEdit::ActionSelectionChanged(const QString &text)
{
if (_loading || !_entryData) {
@ -116,7 +86,7 @@ void MacroActionEdit::ActionSelectionChanged(const QString &text)
*_entryData = MacroActionFactory::Create(id, macro);
(*_entryData)->SetIndex(idx);
(*_entryData)->PostLoad();
RunAndClearPostLoadSteps();
RunPostLoadSteps();
}
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
@ -125,11 +95,38 @@ void MacroActionEdit::ActionSelectionChanged(const QString &text)
SetFocusPolicyOfWidgets();
}
void MacroActionEdit::UpdateEntryData(const std::string &id)
{
_actionSelection->setCurrentText(
obs_module_text(MacroActionFactory::GetActionName(id).c_str()));
const bool enabled = (*_entryData)->Enabled();
_enable->setChecked(enabled);
SetDisableEffect(!enabled);
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
this, SLOT(HeaderInfoChanged(const QString &)));
HeaderInfoChanged(
QString::fromStdString((*_entryData)->GetShortDesc()));
_section->SetContent(widget, (*_entryData)->GetCollapsed());
SetFocusPolicyOfWidgets();
}
void MacroActionEdit::SetEntryData(std::shared_ptr<MacroAction> *data)
{
_entryData = data;
}
void MacroActionEdit::SetDisableEffect(bool value)
{
if (value) {
auto effect = new QGraphicsOpacityEffect(this);
effect->setOpacity(0.5);
_section->setGraphicsEffect(effect);
} else {
_section->setGraphicsEffect(nullptr);
}
}
void MacroActionEdit::ActionEnableChanged(bool value)
{
if (_loading || !_entryData) {
@ -147,9 +144,13 @@ void MacroActionEdit::UpdateActionState()
return;
}
const bool enabled = (*_entryData)->Enabled();
SetEnableAppearance(enabled);
_enable->setChecked(enabled);
SetEnableAppearance((*_entryData)->Enabled());
}
void MacroActionEdit::SetEnableAppearance(bool value)
{
_enable->setChecked(value);
SetDisableEffect(!value);
}
std::shared_ptr<MacroSegment> MacroActionEdit::Data() const
@ -157,4 +158,473 @@ std::shared_ptr<MacroSegment> MacroActionEdit::Data() const
return *_entryData;
}
void AdvSceneSwitcher::AddMacroAction(Macro *macro, int idx,
const std::string &id, obs_data_t *data)
{
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

View File

@ -13,9 +13,11 @@ class MacroActionEdit : public MacroSegmentEdit {
Q_OBJECT
public:
MacroActionEdit(QWidget *parent = nullptr,
std::shared_ptr<MacroAction> * = nullptr);
void SetupWidgets(bool basicSetup = false);
MacroActionEdit(
QWidget *parent = nullptr,
std::shared_ptr<MacroAction> * = nullptr,
const std::string &id = MacroAction::GetDefaultID().data());
void UpdateEntryData(const std::string &id);
void SetEntryData(std::shared_ptr<MacroAction> *);
private slots:
@ -25,11 +27,14 @@ private slots:
private:
std::shared_ptr<MacroSegment> Data() const;
void SetDisableEffect(bool);
void SetEnableAppearance(bool);
FilterComboBox *_actionSelection;
SwitchButton *_enable;
std::shared_ptr<MacroAction> *_entryData;
QTimer _actionStateTimer;
bool _loading = true;
};

View File

@ -1,11 +1,25 @@
#include "macro-action-factory.hpp"
#include "macro-segment-unknown.hpp"
#include <mutex>
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;
@ -35,10 +49,9 @@ bool MacroActionFactory::Deregister(const std::string &id)
return true;
}
static std::shared_ptr<MacroAction> createUnknownAction(Macro *m,
const std::string &id)
static std::shared_ptr<MacroAction> createUnknownAction(Macro *m)
{
return std::make_shared<MacroActionUnknown>(m, id);
return std::make_shared<MacroActionUnknown>(m);
}
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 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,
@ -61,7 +79,7 @@ QWidget *MacroActionFactory::CreateWidget(const std::string &id,
return it->second._createWidget(parent, action);
}
return CreateUnknownSegmentWidget(true);
return createUnknownActionWidget();
}
std::string MacroActionFactory::GetActionName(const std::string &id)

View File

@ -12,7 +12,6 @@ struct MacroActionInfo {
std::function<std::shared_ptr<MacroAction>(Macro *m)> _create = nullptr;
CreateActionWidget _createWidget = nullptr;
std::string _name;
bool _hidden = false;
};
class MacroActionFactory {
@ -20,7 +19,7 @@ public:
MacroActionFactory() = delete;
EXPORT static bool Register(const std::string &id, MacroActionInfo);
EXPORT static bool Deregister(const std::string &id);
static bool Deregister(const std::string &id);
static std::shared_ptr<MacroAction> Create(const std::string &id,
Macro *m);
static QWidget *CreateWidget(const std::string &id, QWidget *parent,

View File

@ -2,7 +2,6 @@
#include "help-icon.hpp"
#include "layout-helpers.hpp"
#include "macro.hpp"
#include "macro-action-factory.hpp"
namespace advss {
@ -13,126 +12,70 @@ bool MacroActionMacro::_registered = MacroActionFactory::Register(
{MacroActionMacro::Create, MacroActionMacroEdit::Create,
"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;
}
}
}
const static std::map<MacroActionMacro::Action, std::string> actionTypes = {
{MacroActionMacro::Action::PAUSE,
"AdvSceneSwitcher.action.macro.type.pause"},
{MacroActionMacro::Action::UNPAUSE,
"AdvSceneSwitcher.action.macro.type.unpause"},
{MacroActionMacro::Action::RESET_COUNTER,
"AdvSceneSwitcher.action.macro.type.resetCounter"},
{MacroActionMacro::Action::RUN,
"AdvSceneSwitcher.action.macro.type.run"},
{MacroActionMacro::Action::STOP,
"AdvSceneSwitcher.action.macro.type.stop"},
{MacroActionMacro::Action::DISABLE_ACTION,
"AdvSceneSwitcher.action.macro.type.disableAction"},
{MacroActionMacro::Action::ENABLE_ACTION,
"AdvSceneSwitcher.action.macro.type.enableAction"},
{MacroActionMacro::Action::TOGGLE_ACTION,
"AdvSceneSwitcher.action.macro.type.toggleAction"},
};
bool MacroActionMacro::PerformAction()
{
if (_action == Action::NESTED_MACRO) {
const bool conditionsMatched = _nestedMacro->CheckConditions();
return _nestedMacro->PerformActions(conditionsMatched);
}
auto macro = _macro.GetMacro();
if (!macro) {
return true;
}
const auto performActionForMacro = [this](Macro *macro) {
switch (_action) {
case Action::PAUSE:
macro->SetPaused();
break;
case Action::UNPAUSE:
macro->SetPaused(false);
break;
case Action::TOGGLE_PAUSE:
macro->SetPaused(!macro->Paused());
break;
case Action::RESET_COUNTER:
macro->ResetRunCount();
break;
case Action::RUN_ACTIONS:
RunActions(macro);
break;
case Action::STOP:
macro->Stop();
break;
case Action::DISABLE_ACTION:
case Action::ENABLE_ACTION:
case Action::TOGGLE_ACTION:
AdjustActionState(macro);
break;
default:
break;
switch (_action) {
case Action::PAUSE:
macro->SetPaused();
break;
case Action::UNPAUSE:
macro->SetPaused(false);
break;
case Action::RESET_COUNTER:
macro->ResetRunCount();
break;
case Action::RUN:
RunActions(macro.get());
break;
case Action::STOP:
macro->Stop();
break;
case Action::DISABLE_ACTION:
if (IsValidMacroSegmentIndex(macro.get(), _actionIndex - 1,
false)) {
macro->Actions().at(_actionIndex - 1)->SetEnabled(false);
}
};
if (!IsGroupMacro(macro.get())) {
performActionForMacro(macro.get());
return true;
break;
case Action::ENABLE_ACTION:
if (IsValidMacroSegmentIndex(macro.get(), _actionIndex - 1,
false)) {
macro->Actions().at(_actionIndex - 1)->SetEnabled(true);
}
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:
break;
}
auto macros = GetGroupMacroEntries(macro.get());
for (const auto &macro : macros) {
performActionForMacro(macro.get());
}
return true;
}
@ -153,7 +96,7 @@ void MacroActionMacro::LogAction() const
ablog(LOG_INFO, "reset counter for \"%s\"",
macro->Name().c_str());
break;
case Action::RUN_ACTIONS:
case Action::RUN:
ablog(LOG_INFO, "run nested macro \"%s\"",
macro->Name().c_str());
break;
@ -172,9 +115,6 @@ void MacroActionMacro::LogAction() const
ablog(LOG_INFO, "toggled action %d of macro \"%s\"",
_actionIndex.GetValue(), macro->Name().c_str());
break;
case Action::NESTED_MACRO:
ablog(LOG_INFO, "run nested macro");
break;
default:
break;
}
@ -183,44 +123,21 @@ void MacroActionMacro::LogAction() const
bool MacroActionMacro::Save(obs_data_t *obj) const
{
MacroAction::Save(obj);
obs_data_set_int(obj, "action", static_cast<int>(_action));
_macro.Save(obj);
obs_data_set_int(obj, "actionSelectionType",
static_cast<int>(_actionSelectionType));
_actionIndex.Save(obj, "actionIndex");
_label.Save(obj, "label");
obs_data_set_string(obj, "actionId", _actionId.c_str());
_regex.Save(obj);
obs_data_set_int(obj, "action", static_cast<int>(_action));
_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;
}
bool MacroActionMacro::Load(obs_data_t *obj)
{
MacroAction::Load(obj);
_macro.Load(obj);
_actionIndex.Load(obj, "actionIndex");
_action = static_cast<MacroActionMacro::Action>(
obs_data_get_int(obj, "action"));
_macro.Load(obj);
_actionSelectionType = static_cast<SelectionType>(
obs_data_get_int(obj, "actionSelectionType"));
_actionIndex.Load(obj, "actionIndex");
_label.Load(obj, "label");
_actionId = obs_data_get_string(obj, "actionId");
_regex.Load(obj);
_runOptions.Load(obj);
if (obs_data_has_user_value(obj, "nestedMacro")) {
OBSDataAutoRelease nestedMacroData =
obs_data_get_obj(obj, "nestedMacro");
_nestedMacro->Load(nestedMacroData);
}
_customWidgetHeight = obs_data_get_int(obj, "customWidgetHeight");
return true;
}
@ -229,7 +146,6 @@ bool MacroActionMacro::PostLoad()
MacroRefAction::PostLoad();
MacroAction::PostLoad();
_runOptions.macro.PostLoad();
_nestedMacro->PostLoad();
return true;
}
@ -245,23 +161,12 @@ std::shared_ptr<MacroAction> MacroActionMacro::Create(Macro *m)
std::shared_ptr<MacroAction> MacroActionMacro::Copy() const
{
auto copy = 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;
return std::make_shared<MacroActionMacro>(*this);
}
void MacroActionMacro::ResolveVariablesToFixedValues()
{
_actionIndex.ResolveVariables();
_label.ResolveVariables();
}
static void runActionsHelper(Macro *macro, bool runElseActions, bool setInputs,
@ -305,33 +210,8 @@ void MacroActionMacro::RunActions(Macro *actionMacro) const
static void populateActionSelection(QComboBox *list)
{
static const std::vector<std::pair<MacroActionMacro::Action, std::string>>
actions = {
{MacroActionMacro::Action::PAUSE,
"AdvSceneSwitcher.action.macro.type.pause"},
{MacroActionMacro::Action::UNPAUSE,
"AdvSceneSwitcher.action.macro.type.unpause"},
{MacroActionMacro::Action::TOGGLE_PAUSE,
"AdvSceneSwitcher.action.macro.type.togglePause"},
{MacroActionMacro::Action::RESET_COUNTER,
"AdvSceneSwitcher.action.macro.type.resetCounter"},
{MacroActionMacro::Action::NESTED_MACRO,
"AdvSceneSwitcher.action.macro.type.nestedMacro"},
{MacroActionMacro::Action::RUN_ACTIONS,
"AdvSceneSwitcher.action.macro.type.run"},
{MacroActionMacro::Action::STOP,
"AdvSceneSwitcher.action.macro.type.stop"},
{MacroActionMacro::Action::DISABLE_ACTION,
"AdvSceneSwitcher.action.macro.type.disableAction"},
{MacroActionMacro::Action::ENABLE_ACTION,
"AdvSceneSwitcher.action.macro.type.enableAction"},
{MacroActionMacro::Action::TOGGLE_ACTION,
"AdvSceneSwitcher.action.macro.type.toggleAction"},
};
for (const auto &[value, name] : actions) {
list->addItem(obs_module_text(name.c_str()),
static_cast<int>(value));
for (const auto &[_, name] : actionTypes) {
list->addItem(obs_module_text(name.c_str()));
}
}
@ -345,7 +225,7 @@ static void populateConditionBehaviorSelection(QComboBox *list)
"AdvSceneSwitcher.action.macro.type.run.conditions.false"));
}
static void populateActionSectionSelection(QComboBox *list)
static void populateActionTypeSelection(QComboBox *list)
{
list->addItem(obs_module_text(
"AdvSceneSwitcher.action.macro.type.run.actionType.regular"));
@ -353,47 +233,19 @@ static void populateActionSectionSelection(QComboBox *list)
"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(
QWidget *parent, std::shared_ptr<MacroActionMacro> entryData)
: ResizableWidget(parent),
_actions(new QComboBox()),
: QWidget(parent),
_macros(new MacroSelection(parent)),
_actionSelectionType(new QComboBox(this)),
_actionIndex(new MacroSegmentSelection(
this, MacroSegmentSelection::Type::ACTION)),
_label(new VariableLineEdit(this)),
_actionTypes(new FilterComboBox(this)),
_regex(new RegexConfigWidget(this)),
_actions(new QComboBox()),
_conditionMacros(new MacroSelection(parent)),
_conditionBehaviors(new QComboBox()),
_reevaluateConditionState(new QCheckBox(
obs_module_text("AdvSceneSwitcher.action.macro.type.run."
"updateConditionMatchState"))),
_actionSections(new QComboBox(this)),
_actionTypes(new QComboBox()),
_skipWhenPaused(new QCheckBox(obs_module_text(
"AdvSceneSwitcher.action.macro.type.run.skipWhenPaused"))),
_setInputs(new QCheckBox(obs_module_text(
@ -402,46 +254,28 @@ MacroActionMacroEdit::MacroActionMacroEdit(
_entryLayout(new QHBoxLayout()),
_conditionLayout(new QHBoxLayout()),
_reevaluateConditionStateLayout(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"))
_setInputsLayout(new QHBoxLayout())
{
populateActionSelection(_actions);
populateConditionBehaviorSelection(_conditionBehaviors);
populateActionSectionSelection(_actionSections);
populateActionSelectionTypes(_actionSelectionType);
populateActionTypes(_actionTypes);
populateActionTypeSelection(_actionTypes);
_conditionMacros->HideSelectedMacro();
_conditionMacros->HideGroups();
QWidget::connect(_macros, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(MacroChanged(const QString &)));
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
SLOT(ActionChanged(int)));
QWidget::connect(_actionSelectionType, SIGNAL(currentIndexChanged(int)),
this, SLOT(ActionSelectionTypeChanged(int)));
QWidget::connect(_actionIndex,
SIGNAL(SelectionChanged(const IntVariable &)), this,
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,
SIGNAL(currentTextChanged(const QString &)), this,
SLOT(ConditionMacroChanged(const QString &)));
QWidget::connect(_conditionBehaviors, SIGNAL(currentIndexChanged(int)),
this, SLOT(ConditionBehaviorChanged(int)));
QWidget::connect(_actionSections, SIGNAL(currentIndexChanged(int)),
this, SLOT(ActionSectionChanged(int)));
QWidget::connect(_actionTypes, SIGNAL(currentIndexChanged(int)), this,
SLOT(ActionTypeChanged(int)));
QWidget::connect(_skipWhenPaused, SIGNAL(stateChanged(int)), this,
SLOT(SkipWhenPausedChanged(int)));
QWidget::connect(_setInputs, SIGNAL(stateChanged(int)), this,
@ -469,24 +303,17 @@ MacroActionMacroEdit::MacroActionMacroEdit(
layout->addLayout(_setInputsLayout);
layout->addWidget(_inputs);
layout->addWidget(_skipWhenPaused);
layout->addWidget(_nestedMacro);
setLayout(layout);
_entryData = entryData;
UpdateEntryData();
_loading = false;
}
void HighlightMacroSettingsButton(bool enable);
void HighligthMacroSettingsButton(bool enable);
MacroActionMacroEdit::~MacroActionMacroEdit()
{
HighlightMacroSettingsButton(false);
if (!_entryData) {
return;
}
_entryData->_customWidgetHeight = GetCustomHeight();
_nestedMacro->SetMacro({}); // Save splitter states
HighligthMacroSettingsButton(false);
}
void MacroActionMacroEdit::UpdateEntryData()
@ -494,42 +321,23 @@ void MacroActionMacroEdit::UpdateEntryData()
if (!_entryData) {
return;
}
_actions->setCurrentIndex(
_actions->findData(static_cast<int>(_entryData->_action)));
_actionSelectionType->setCurrentIndex(_actionSelectionType->findData(
static_cast<int>(_entryData->_actionSelectionType)));
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
_actionIndex->SetValue(_entryData->_actionIndex);
_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);
_conditionMacros->SetCurrentMacro(_entryData->_runOptions.macro);
_conditionBehaviors->setCurrentIndex(
static_cast<int>(_entryData->_runOptions.logic));
_reevaluateConditionState->setChecked(
_entryData->_runOptions.reevaluateConditionState);
_actionSections->setCurrentIndex(
_actionTypes->setCurrentIndex(
_entryData->_runOptions.runElseActions ? 1 : 0);
_skipWhenPaused->setChecked(_entryData->_runOptions.skipWhenPaused);
_setInputs->setChecked(_entryData->_runOptions.setInputs);
SetupMacroInput(_entryData->_macro.GetMacro().get());
const auto &macro = _entryData->_nestedMacro;
_nestedMacro->SetMacro(macro);
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)
{
GUARD_LOADING_AND_LOCK();
@ -542,20 +350,10 @@ void MacroActionMacroEdit::MacroChanged(const QString &text)
SetWidgetVisibility();
}
void MacroActionMacroEdit::ActionChanged(int idx)
void MacroActionMacroEdit::ActionChanged(int value)
{
GUARD_LOADING_AND_LOCK();
_entryData->_action = static_cast<MacroActionMacro::Action>(
_actions->itemData(idx).toInt());
SetWidgetVisibility();
}
void MacroActionMacroEdit::ActionSelectionTypeChanged(int idx)
{
GUARD_LOADING_AND_LOCK();
_entryData->_actionSelectionType =
static_cast<MacroActionMacro::SelectionType>(
_actionSelectionType->itemData(idx).toInt());
_entryData->_action = static_cast<MacroActionMacro::Action>(value);
SetWidgetVisibility();
}
@ -565,25 +363,6 @@ void MacroActionMacroEdit::ActionIndexChanged(const IntVariable &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)
{
GUARD_LOADING_AND_LOCK();
@ -605,13 +384,10 @@ void MacroActionMacroEdit::ReevaluateConditionStateChanged(int value)
SetWidgetVisibility();
}
void MacroActionMacroEdit::ActionSectionChanged(int useElse)
void MacroActionMacroEdit::ActionTypeChanged(int value)
{
GUARD_LOADING_AND_LOCK();
_entryData->_runOptions.runElseActions = useElse;
_entryData->_useElseSection = useElse;
_actionIndex->SetType(useElse ? MacroSegmentSelection::Type::ELSE_ACTION
: MacroSegmentSelection::Type::ACTION);
_entryData->_runOptions.runElseActions = value;
}
void MacroActionMacroEdit::SkipWhenPausedChanged(int value)
@ -640,11 +416,7 @@ void MacroActionMacroEdit::SetWidgetVisibility()
_entryLayout->removeWidget(_actions);
_entryLayout->removeWidget(_actionIndex);
_entryLayout->removeWidget(_macros);
_entryLayout->removeWidget(_actionSections);
_entryLayout->removeWidget(_label);
_entryLayout->removeWidget(_regex);
_entryLayout->removeWidget(_actionTypes);
_entryLayout->removeWidget(_actionSelectionType);
_conditionLayout->removeWidget(_conditionBehaviors);
_conditionLayout->removeWidget(_conditionMacros);
@ -655,40 +427,18 @@ void MacroActionMacroEdit::SetWidgetVisibility()
{"{{actions}}", _actions},
{"{{actionIndex}}", _actionIndex},
{"{{macros}}", _macros},
{"{{actionSections}}", _actionSections},
{"{{actionTypes}}", _actionTypes},
{"{{conditionBehaviors}}", _conditionBehaviors},
{"{{conditionMacros}}", _conditionMacros},
{"{{actionSelectionType}}", _actionSelectionType},
{"{{label}}", _label},
{"{{regex}}", _regex},
{"{{actionTypes}}", _actionTypes},
};
const auto action = _entryData->_action;
const char *layoutText = "";
switch (action) {
case MacroActionMacro::Action::PAUSE:
case MacroActionMacro::Action::UNPAUSE:
case MacroActionMacro::Action::TOGGLE_PAUSE:
case MacroActionMacro::Action::RESET_COUNTER:
case MacroActionMacro::Action::STOP:
case MacroActionMacro::Action::NESTED_MACRO:
layoutText = "AdvSceneSwitcher.action.macro.layout.other";
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);
PlaceWidgets(
obs_module_text(
_entryData->_action == MacroActionMacro::Action::RUN
? "AdvSceneSwitcher.action.macro.entry.run"
: "AdvSceneSwitcher.action.macro.entry.other"),
_entryLayout, placeholders);
if (_entryData->_runOptions.logic ==
MacroActionMacro::RunOptions::Logic::IGNORE_CONDITIONS) {
@ -697,70 +447,47 @@ void MacroActionMacroEdit::SetWidgetVisibility()
} else {
PlaceWidgets(
obs_module_text(
"AdvSceneSwitcher.action.macro.layout.run.condition"),
"AdvSceneSwitcher.action.macro.entry.run.condition"),
_conditionLayout, placeholders);
}
if (action == MacroActionMacro::Action::RUN_ACTIONS ||
action == MacroActionMacro::Action::STOP) {
if (_entryData->_action == MacroActionMacro::Action::RUN ||
_entryData->_action == MacroActionMacro::Action::STOP) {
_macros->HideSelectedMacro();
} else {
_macros->ShowAllMacros();
}
const auto actionSelectionType = _entryData->_actionSelectionType;
const bool isModifyingActionState =
action == MacroActionMacro::Action::DISABLE_ACTION ||
action == MacroActionMacro::Action::ENABLE_ACTION ||
action == MacroActionMacro::Action::TOGGLE_ACTION;
_actionSelectionType->setVisible(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);
_entryData->_action ==
MacroActionMacro::Action::DISABLE_ACTION ||
_entryData->_action ==
MacroActionMacro::Action::ENABLE_ACTION ||
_entryData->_action == MacroActionMacro::Action::TOGGLE_ACTION;
_actionIndex->setVisible(isModifyingActionState);
SetLayoutVisible(_conditionLayout,
action == MacroActionMacro::Action::RUN_ACTIONS);
_entryData->_action == MacroActionMacro::Action::RUN);
const bool needsAdditionalConditionWidgets =
action == MacroActionMacro::Action::RUN_ACTIONS &&
_entryData->_action == MacroActionMacro::Action::RUN &&
_entryData->_runOptions.logic !=
MacroActionMacro::RunOptions::Logic::IGNORE_CONDITIONS;
_conditionMacros->setVisible(needsAdditionalConditionWidgets);
SetLayoutVisible(_reevaluateConditionStateLayout,
needsAdditionalConditionWidgets);
SetLayoutVisible(_setInputsLayout,
action == MacroActionMacro::Action::RUN_ACTIONS);
_inputs->setVisible(action == MacroActionMacro::Action::RUN_ACTIONS &&
_entryData->_action == MacroActionMacro::Action::RUN);
_inputs->setVisible(_entryData->_action ==
MacroActionMacro::Action::RUN &&
_entryData->_runOptions.setInputs);
HighlightMacroSettingsButton(
action == MacroActionMacro::Action::RUN_ACTIONS &&
_entryData->_runOptions.setInputs &&
!_inputs->HasInputsToSet());
_actionSections->setVisible(
action == MacroActionMacro::Action::RUN_ACTIONS ||
isModifyingActionState);
_skipWhenPaused->setVisible(action ==
MacroActionMacro::Action::RUN_ACTIONS);
_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);
HighligthMacroSettingsButton(_entryData->_action ==
MacroActionMacro::Action::RUN &&
_entryData->_runOptions.setInputs &&
!_inputs->HasInputsToSet());
_actionTypes->setVisible(_entryData->_action ==
MacroActionMacro::Action::RUN);
_skipWhenPaused->setVisible(_entryData->_action ==
MacroActionMacro::Action::RUN);
adjustSize();
updateGeometry();

View File

@ -1,13 +1,8 @@
#pragma once
#include "macro-action-edit.hpp"
#include "macro.hpp"
#include "macro-edit.hpp"
#include "macro-input.hpp"
#include "macro-selection.hpp"
#include "macro-segment-selection.hpp"
#include "regex-config.hpp"
#include "resizable-widget.hpp"
#include "variable-line-edit.hpp"
#include <QCheckBox>
#include <QHBoxLayout>
@ -49,37 +44,24 @@ public:
PAUSE,
UNPAUSE,
RESET_COUNTER,
RUN_ACTIONS,
RUN,
STOP,
DISABLE_ACTION,
ENABLE_ACTION,
TOGGLE_ACTION,
TOGGLE_PAUSE,
NESTED_MACRO,
};
enum class SelectionType { INDEX, LABEL, ID };
Action _action = Action::NESTED_MACRO;
SelectionType _actionSelectionType = SelectionType::INDEX;
bool _useElseSection = false;
Action _action = Action::RUN;
IntVariable _actionIndex = 1;
StringVariable _label = "Custom label";
std::string _actionId;
RegexConfig _regex;
RunOptions _runOptions = {};
std::shared_ptr<Macro> _nestedMacro = std::make_shared<Macro>();
int _customWidgetHeight = 0;
private:
void RunActions(Macro *actionMacro) const;
void AdjustActionState(Macro *) const;
static bool _registered;
static const std::string id;
};
class MacroActionMacroEdit final : public ResizableWidget {
class MacroActionMacroEdit final : public QWidget {
Q_OBJECT
public:
@ -88,20 +70,22 @@ public:
std::shared_ptr<MacroActionMacro> entryData = nullptr);
~MacroActionMacroEdit();
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:
void MacroChanged(const QString &text);
void ActionChanged(int value);
void ActionSelectionTypeChanged(int value);
void ActionIndexChanged(const IntVariable &value);
void LabelChanged();
void ActionTypeChanged(int value);
void RegexChanged(const RegexConfig &);
void ConditionMacroChanged(const QString &text);
void ConditionBehaviorChanged(int value);
void ReevaluateConditionStateChanged(int value);
void ActionSectionChanged(int value);
void ActionTypeChanged(int value);
void SkipWhenPausedChanged(int value);
void SetInputsChanged(int value);
void InputsChanged(const StringList &);
@ -113,17 +97,13 @@ private:
void SetWidgetVisibility();
void SetupMacroInput(Macro *) const;
QComboBox *_actions;
MacroSelection *_macros;
QComboBox *_actionSelectionType;
MacroSegmentSelection *_actionIndex;
VariableLineEdit *_label;
FilterComboBox *_actionTypes;
RegexConfigWidget *_regex;
QComboBox *_actions;
MacroSelection *_conditionMacros;
QComboBox *_conditionBehaviors;
QCheckBox *_reevaluateConditionState;
QComboBox *_actionSections;
QComboBox *_actionTypes;
QCheckBox *_skipWhenPaused;
QCheckBox *_setInputs;
MacroInputEdit *_inputs;
@ -131,7 +111,6 @@ private:
QHBoxLayout *_conditionLayout;
QHBoxLayout *_reevaluateConditionStateLayout;
QHBoxLayout *_setInputsLayout;
MacroEdit *_nestedMacro;
std::shared_ptr<MacroActionMacro> _entryData;
bool _loading = true;

View File

@ -170,7 +170,11 @@ void MacroActionQueueEdit::UpdateEntryData()
void MacroActionQueueEdit::MacroChanged(const QString &text)
{
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_macro = text;
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
@ -178,7 +182,11 @@ void MacroActionQueueEdit::MacroChanged(const QString &text)
void MacroActionQueueEdit::QueueChanged(const QString &text)
{
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_queue = GetWeakActionQueueByQString(text);
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
@ -186,7 +194,11 @@ void MacroActionQueueEdit::QueueChanged(const QString &text)
void MacroActionQueueEdit::ActionChanged(int value)
{
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_action = static_cast<MacroActionQueue::Action>(value);
SetWidgetVisibility();
emit HeaderInfoChanged(

View File

@ -1,21 +1,19 @@
#include "macro-action-script.hpp"
#include "layout-helpers.hpp"
#include "macro-helpers.hpp"
#include "properties-view.hpp"
#include "sync-helpers.hpp"
namespace advss {
MacroActionScript::MacroActionScript(
Macro *m, const std::string &id, const OBSData &defaultSettings,
const std::string &propertiesSignalName,
const std::string &triggerSignalName,
const std::string &completionSignalName,
const std::string &newInstanceSignalName,
const std::string &deletedInstanceSignalName)
MacroActionScript::MacroActionScript(Macro *m, const std::string &id,
const OBSData &defaultSettings,
const std::string &propertiesSignalName,
const std::string &triggerSignal,
const std::string &completionSignal)
: MacroAction(m),
MacroSegmentScript(defaultSettings, propertiesSignalName,
triggerSignalName, completionSignalName,
newInstanceSignalName, deletedInstanceSignalName),
triggerSignal, completionSignal),
_id(id)
{
}
@ -91,29 +89,4 @@ void MacroActionScript::WaitForCompletion() const
}
}
void MacroActionScript::RegisterTempVarHelper(const std::string &variableId,
const std::string &name,
const std::string &helpText)
{
AddTempvar(variableId, name, helpText);
}
void MacroActionScript::DeregisterAllTempVarsHelper()
{
MacroSegment::SetupTempVars();
}
void MacroActionScript::SetTempVarValueHelper(const std::string &variableId,
const std::string &value)
{
MacroAction::SetTempVarValue(variableId, value);
}
void MacroActionScript::SetupTempVars()
{
// This just exists so MacroSegment::SetupTempVars() is not called.
// We want the ScriptHandler to handle the registration and clearing of
// the temp vars.
}
} // namespace advss

View File

@ -10,10 +10,8 @@ public:
MacroActionScript(Macro *m, const std::string &id,
const OBSData &defaultSettings,
const std::string &propertiesSignalName,
const std::string &triggerSignalName,
const std::string &completionSignalName,
const std::string &newInstanceSignalName,
const std::string &deletedInstanceSignalName);
const std::string &triggerSignal,
const std::string &signalComplete);
MacroActionScript(const advss::MacroActionScript &);
bool PerformAction();
void LogAction() const;
@ -24,13 +22,6 @@ public:
private:
void WaitForCompletion() const;
void RegisterTempVarHelper(const std::string &variableId,
const std::string &name,
const std::string &helpText);
void DeregisterAllTempVarsHelper();
void SetTempVarValueHelper(const std::string &variableId,
const std::string &value);
void SetupTempVars();
std::string _id = "";
};

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,6 @@
#include "resizing-text-edit.hpp"
#include "scene-selection.hpp"
#include "single-char-selection.hpp"
#include "string-list.hpp"
#include "variable-line-edit.hpp"
#include "variable-text-edit.hpp"
#include "variable-spinbox.hpp"
@ -29,8 +28,8 @@ public:
int GetSegmentIndexValue() const;
void ResolveVariablesToFixedValues();
enum class Action {
SET_VALUE,
enum class Type {
SET_FIXED_VALUE,
APPEND,
APPEND_VAR,
INCREMENT,
@ -53,23 +52,18 @@ public:
SWAP_VALUES,
TRIM,
CHANGE_CASE,
RANDOM_NUMBER,
QUERY_JSON,
ARRAY_JSON,
COPY_VAR,
RANDOM_LIST_VALUE,
};
Action _action = Action::SET_VALUE;
Type _type = Type::SET_FIXED_VALUE;
std::weak_ptr<Variable> _variable;
std::weak_ptr<Variable> _variable2;
StringVariable _strValue = "";
DoubleVariable _numValue = 0;
IntVariable _subStringStart = 0;
IntVariable _subStringSize = 0;
double _numValue = 0;
int _subStringStart = 0;
int _subStringSize = 0;
RegexConfig _subStringRegex = RegexConfig::PartialMatchRegexConfig();
std::string _regexPattern = ".*";
IntVariable _regexMatchIdx = 0;
int _regexMatchIdx = 0;
RegexConfig _findRegex;
StringVariable _findStr = obs_module_text(
"AdvSceneSwitcher.action.variable.findAndReplace.find");
@ -105,16 +99,6 @@ public:
};
CaseType _caseType = CaseType::LOWER_CASE;
DoubleVariable _randomNumberStart = 0;
DoubleVariable _randomNumberEnd = 100;
bool _generateInteger = true;
StringList _randomValues = {"value1", "value2", "value3"};
bool _allowRepeatValues = true;
std::optional<std::string> _lastRandomValue;
StringVariable _jsonQuery = "$.some.nested.value";
IntVariable _jsonIndex = 0;
private:
void DecrementCurrentSegmentVariableRef();
@ -124,8 +108,6 @@ private:
void HandleMathExpression(Variable *);
void HandleCaseChange(Variable *);
void SetToSceneItemName(Variable *);
void GenerateRandomNumber(Variable *);
void PickRandomValue(Variable *);
std::weak_ptr<MacroSegment> _macroSegment;
int _segmentIdxLoadValue = -1;
@ -154,15 +136,15 @@ private slots:
void Variable2Changed(const QString &);
void ActionChanged(int);
void StrValueChanged();
void NumValueChanged(const NumberVariable<double> &value);
void NumValueChanged(double);
void SegmentIndexChanged(const IntVariable &);
void UpdateSegmentVariableValue();
void MacroSegmentOrderChanged();
void SubStringStartChanged(const NumberVariable<int> &start);
void SubStringSizeChanged(const NumberVariable<int> &size);
void SubStringStartChanged(int val);
void SubStringSizeChanged(int val);
void SubStringRegexChanged(const RegexConfig &conf);
void RegexPatternChanged();
void RegexMatchIdxChanged(const NumberVariable<int> &index);
void RegexMatchIdxChanged(int val);
void FindStrValueChanged();
void FindRegexChanged(const RegexConfig &conf);
void ReplaceStrValueChanged();
@ -179,13 +161,6 @@ private slots:
void StringLengthChanged(const NumberVariable<int> &);
void CharSelectionChanged(const QString &);
void CaseTypeChanged(int index);
void RandomNumberStartChanged(const NumberVariable<double> &);
void RandomNumberEndChanged(const NumberVariable<double> &);
void GenerateIntegerChanged(int);
void RandomValueListChanged(const StringList &);
void AllowRepeatValuesChanged(int);
void JsonQueryChanged();
void JsonIndexChanged(const NumberVariable<int> &);
signals:
void HeaderInfoChanged(const QString &);
@ -198,17 +173,18 @@ private:
VariableSelection *_variables2;
FilterComboBox *_actions;
VariableTextEdit *_strValue;
VariableDoubleSpinBox *_numValue;
QDoubleSpinBox *_numValue;
MacroSegmentSelection *_segmentIdx;
QLabel *_segmentValueStatus;
ResizingPlainTextEdit *_segmentValue;
QVBoxLayout *_substringLayout;
QHBoxLayout *_subStringControlsLayout;
VariableSpinBox *_subStringStart;
VariableSpinBox *_subStringSize;
RegexConfigWidget *_subStringRegex;
QHBoxLayout *_subStringIndexEntryLayout;
QHBoxLayout *_subStringRegexEntryLayout;
QSpinBox *_subStringStart;
QSpinBox *_subStringSize;
RegexConfigWidget *_substringRegex;
ResizingPlainTextEdit *_regexPattern;
VariableSpinBox *_regexMatchIdx;
QSpinBox *_regexMatchIdx;
QHBoxLayout *_findReplaceLayout;
RegexConfigWidget *_findRegex;
VariableTextEdit *_findStr;
@ -230,16 +206,6 @@ private:
VariableSpinBox *_stringLength;
SingleCharSelection *_paddingCharSelection;
FilterComboBox *_caseType;
VariableDoubleSpinBox *_randomNumberStart;
VariableDoubleSpinBox *_randomNumberEnd;
QCheckBox *_generateInteger;
QVBoxLayout *_randomNumberLayout;
StringListEdit *_randomValues;
QCheckBox *_allowRepeatValues;
QVBoxLayout *_randomValueLayout;
VariableLineEdit *_jsonQuery;
QLabel *_jsonQueryHelp;
VariableSpinBox *_jsonIndex;
QHBoxLayout *_entryLayout;
std::shared_ptr<MacroActionVariable> _entryData;

View File

@ -11,12 +11,15 @@ bool MacroAction::Save(obs_data_t *obj) const
{
MacroSegment::Save(obj);
obs_data_set_string(obj, "id", GetId().c_str());
obs_data_set_bool(obj, "enabled", _enabled);
return true;
}
bool MacroAction::Load(obs_data_t *obj)
{
MacroSegment::Load(obj);
obs_data_set_default_bool(obj, "enabled", true);
_enabled = obs_data_get_bool(obj, "enabled");
return true;
}
@ -25,6 +28,16 @@ void MacroAction::LogAction() const
ablog(LOG_INFO, "performed action %s", GetId().c_str());
}
void MacroAction::SetEnabled(bool value)
{
_enabled = value;
}
bool MacroAction::Enabled() const
{
return _enabled;
}
void MacroAction::ResolveVariablesToFixedValues() {}
std::string_view MacroAction::GetDefaultID()

View File

@ -19,9 +19,13 @@ public:
// Used to resolve variables before actions are added to action queues
virtual void ResolveVariablesToFixedValues();
void SetEnabled(bool);
bool Enabled() const;
static std::string_view GetDefaultID();
private:
bool _enabled = true;
};
class EXPORT MacroRefAction : virtual public MacroAction {

View File

@ -100,7 +100,7 @@ void DurationModifierEdit::Collapse(bool collapse)
MacroConditionEdit::MacroConditionEdit(
QWidget *parent, std::shared_ptr<MacroCondition> *entryData,
bool isRootCondition)
const std::string &id, bool isRootCondition)
: MacroSegmentEdit(parent),
_logicSelection(new QComboBox()),
_conditionSelection(new FilterComboBox()),
@ -138,7 +138,7 @@ MacroConditionEdit::MacroConditionEdit(
mainLayout->addWidget(_frame);
setLayout(mainLayout);
SetupWidgets(true);
UpdateEntryData(id);
_loading = false;
}
@ -152,11 +152,9 @@ void MacroConditionEdit::LogicSelectionChanged(int idx)
const auto logic = static_cast<Logic::Type>(
_logicSelection->itemData(idx).toInt());
(*_entryData)->SetLogicType(logic);
SetEnableAppearance(logic != Logic::Type::NONE);
}
bool MacroConditionEdit::IsRootNode() const
bool MacroConditionEdit::IsRootNode()
{
return _isRoot;
}
@ -166,7 +164,6 @@ void MacroConditionEdit::SetLogicSelection()
const auto logic = (*_entryData)->GetLogicType();
_logicSelection->setCurrentIndex(
_logicSelection->findData(static_cast<int>(logic)));
SetEnableAppearance(logic != Logic::Type::NONE);
}
void MacroConditionEdit::SetRootNode(bool root)
@ -178,36 +175,23 @@ void MacroConditionEdit::SetRootNode(bool root)
SetLogicSelection();
}
void MacroConditionEdit::SetupWidgets(bool basicSetup)
void MacroConditionEdit::UpdateEntryData(const std::string &id)
{
if (_allWidgetsAreSetup) {
return;
}
const auto id = (*_entryData)->GetId();
_conditionSelection->setCurrentText(obs_module_text(
MacroConditionFactory::GetConditionName(id).c_str()));
HeaderInfoChanged(
QString::fromStdString((*_entryData)->GetShortDesc()));
SetLogicSelection();
_dur->setVisible(MacroConditionFactory::UsesDurationModifier(id));
auto modifier = (*_entryData)->GetDurationModifier();
_dur->SetValue(modifier);
if (basicSetup) {
return;
}
auto widget =
MacroConditionFactory::CreateWidget(id, this, *_entryData);
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
this, SLOT(HeaderInfoChanged(const QString &)));
HeaderInfoChanged(
QString::fromStdString((*_entryData)->GetShortDesc()));
SetLogicSelection();
_section->SetContent(widget, (*_entryData)->GetCollapsed());
SetFocusPolicyOfWidgets();
_allWidgetsAreSetup = true;
_dur->setVisible(MacroConditionFactory::UsesDurationModifier(id));
auto modifier = (*_entryData)->GetDurationModifier();
_dur->SetValue(modifier);
SetFocusPolicyOfWidgets();
}
void MacroConditionEdit::SetEntryData(std::shared_ptr<MacroCondition> *data)
@ -239,7 +223,7 @@ void MacroConditionEdit::ConditionSelectionChanged(const QString &text)
(*_entryData)->SetIndex(idx);
(*_entryData)->SetLogicType(logic);
(*_entryData)->PostLoad();
RunAndClearPostLoadSteps();
RunPostLoadSteps();
}
auto widget =
MacroConditionFactory::CreateWidget(id, this, *_entryData);
@ -275,4 +259,289 @@ std::shared_ptr<MacroSegment> MacroConditionEdit::Data() const
return *_entryData;
}
void AdvSceneSwitcher::AddMacroCondition(int idx)
{
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

View File

@ -34,12 +34,14 @@ class MacroConditionEdit : public MacroSegmentEdit {
Q_OBJECT
public:
MacroConditionEdit(QWidget *parent = nullptr,
std::shared_ptr<MacroCondition> * = nullptr,
bool root = true);
bool IsRootNode() const;
MacroConditionEdit(
QWidget *parent = nullptr,
std::shared_ptr<MacroCondition> * = nullptr,
const std::string &id = MacroCondition::GetDefaultID().data(),
bool root = true);
bool IsRootNode();
void SetRootNode(bool);
void SetupWidgets(bool basicSetup = false);
void UpdateEntryData(const std::string &id);
void SetEntryData(std::shared_ptr<MacroCondition> *);
private slots:

View File

@ -1,11 +1,21 @@
#include "macro-condition-factory.hpp"
#include "macro-segment-unknown.hpp"
#include <mutex>
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;
@ -36,10 +46,9 @@ bool MacroConditionFactory::Deregister(const std::string &id)
return true;
}
static std::shared_ptr<MacroCondition>
createUnknownCondition(Macro *m, const std::string &id)
static std::shared_ptr<MacroCondition> createUnknownCondition(Macro *m)
{
return std::make_shared<MacroConditionUnknown>(m, id);
return std::make_shared<MacroConditionUnknown>(m);
}
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()) {
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 *
@ -60,7 +75,7 @@ MacroConditionFactory::CreateWidget(const std::string &id, QWidget *parent,
if (auto it = GetMap().find(id); it != GetMap().end()) {
return it->second._createWidget(parent, cond);
}
return CreateUnknownSegmentWidget(false);
return createUnknownConditionWidget();
}
std::string MacroConditionFactory::GetConditionName(const std::string &id)

View File

@ -20,7 +20,7 @@ class MacroConditionFactory {
public:
MacroConditionFactory() = delete;
EXPORT static bool Register(const std::string &, MacroConditionInfo);
EXPORT static bool Deregister(const std::string &);
static bool Deregister(const std::string &);
static std::shared_ptr<MacroCondition> Create(const std::string &,
Macro *m);
static QWidget *CreateWidget(const std::string &id, QWidget *parent,

View File

@ -1,7 +1,6 @@
#include "macro-condition-macro.hpp"
#include "layout-helpers.hpp"
#include "macro-action-edit.hpp"
#include "macro-signals.hpp"
#include "macro.hpp"
namespace advss {
@ -27,8 +26,6 @@ const static std::map<MacroConditionMacro::Type, std::string>
"AdvSceneSwitcher.condition.macro.type.actionEnabled"},
{MacroConditionMacro::Type::PAUSED,
"AdvSceneSwitcher.condition.macro.type.paused"},
{MacroConditionMacro::Type::ACTIONS_PERFORMED,
"AdvSceneSwitcher.condition.macro.type.actionsPerformed"},
};
const static std::map<MacroConditionMacro::CounterCondition, std::string>
@ -102,7 +99,7 @@ bool MacroConditionMacro::CheckActionStateCondition()
if (!macro) {
return false;
}
if (!IsValidActionIndex(macro.get(), _actionIndex - 1)) {
if (!IsValidMacroSegmentIndex(macro.get(), _actionIndex - 1, false)) {
return false;
}
if (_type == Type::ACTION_DISABLED) {
@ -124,16 +121,6 @@ bool MacroConditionMacro::CheckPauseState()
return macro->Paused();
}
bool MacroConditionMacro::CheckActionsPerformed()
{
auto macro = _macro.GetMacro();
if (!macro) {
return false;
}
return macro->WasExecutedSince(macro->LastConditionCheckTime());
}
bool MacroConditionMacro::CheckCountCondition()
{
auto macro = _macro.GetMacro();
@ -171,8 +158,6 @@ bool MacroConditionMacro::CheckCondition()
return CheckActionStateCondition();
case Type::PAUSED:
return CheckPauseState();
case Type::ACTIONS_PERFORMED:
return CheckActionsPerformed();
default:
break;
}
@ -315,7 +300,6 @@ MacroConditionMacroEdit::MacroConditionMacroEdit(
_actionIndex(new MacroSegmentSelection(
this, MacroSegmentSelection::Type::ACTION))
{
_macros->HideGroups();
_count->setMaximum(10000000);
populateTypeSelection(_types);
populateCounterConditionSelection(_counterConditions);
@ -323,8 +307,7 @@ MacroConditionMacroEdit::MacroConditionMacroEdit(
QWidget::connect(_macros, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(MacroChanged(const QString &)));
QWidget::connect(MacroSignalManager::Instance(),
SIGNAL(Remove(const QString &)), this,
QWidget::connect(parent, SIGNAL(MacroRemoved(const QString &)), this,
SLOT(MacroRemove(const QString &)));
QWidget::connect(_types, SIGNAL(currentIndexChanged(int)), this,
SLOT(TypeChanged(int)));
@ -431,9 +414,6 @@ void MacroConditionMacroEdit::SetupWidgets()
case MacroConditionMacro::Type::PAUSED:
SetupPauseWidgets();
break;
case MacroConditionMacro::Type::ACTIONS_PERFORMED:
SetupActionsPerformedWidgets();
break;
default:
break;
}
@ -492,14 +472,6 @@ void MacroConditionMacroEdit::SetupPauseWidgets()
_settingsLine1, {{"{{macros}}", _macros}});
}
void MacroConditionMacroEdit::SetupActionsPerformedWidgets()
{
PlaceWidgets(
obs_module_text(
"AdvSceneSwitcher.condition.macro.actionsPerformed.entry"),
_settingsLine1, {{"{{macros}}", _macros}});
}
void MacroConditionMacroEdit::SetWidgetVisibility()
{
_macros->setVisible(
@ -509,9 +481,7 @@ void MacroConditionMacroEdit::SetWidgetVisibility()
MacroConditionMacro::Type::ACTION_DISABLED ||
_entryData->GetType() ==
MacroConditionMacro::Type::ACTION_ENABLED ||
_entryData->GetType() == MacroConditionMacro::Type::PAUSED ||
_entryData->GetType() ==
MacroConditionMacro::Type::ACTIONS_PERFORMED);
_entryData->GetType() == MacroConditionMacro::Type::PAUSED);
_counterConditions->setVisible(_entryData->GetType() ==
MacroConditionMacro::Type::COUNT);
_count->setVisible(_entryData->GetType() ==
@ -568,7 +538,11 @@ void MacroConditionMacroEdit::UpdateEntryData()
void MacroConditionMacroEdit::MacroChanged(const QString &text)
{
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_macro = text;
_actionIndex->SetMacro(_entryData->_macro.GetMacro());
emit HeaderInfoChanged(
@ -577,13 +551,21 @@ void MacroConditionMacroEdit::MacroChanged(const QString &text)
void MacroConditionMacroEdit::CountChanged(const NumberVariable<int> &value)
{
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_count = value;
}
void MacroConditionMacroEdit::CountConditionChanged(int cond)
{
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_counterCondition =
static_cast<MacroConditionMacro::CounterCondition>(cond);
}
@ -608,7 +590,11 @@ void MacroConditionMacroEdit::MacroRemove(const QString &)
void MacroConditionMacroEdit::TypeChanged(int type)
{
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->SetType(static_cast<MacroConditionMacro::Type>(type));
SetupWidgets();
}
@ -654,7 +640,11 @@ void MacroConditionMacroEdit::UpdatePaused()
void MacroConditionMacroEdit::MultiStateConditionChanged(int cond)
{
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_multiSateCondition =
static_cast<MacroConditionMacro::MultiStateCondition>(cond);
}
@ -662,13 +652,21 @@ void MacroConditionMacroEdit::MultiStateConditionChanged(int cond)
void MacroConditionMacroEdit::MultiStateCountChanged(
const NumberVariable<int> &value)
{
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_multiSateCount = value;
}
void MacroConditionMacroEdit::Add(const std::string &name)
{
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
MacroRef macro(name);
_entryData->_macros.push_back(macro);
adjustSize();
@ -677,7 +675,11 @@ void MacroConditionMacroEdit::Add(const std::string &name)
void MacroConditionMacroEdit::Remove(int idx)
{
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_macros.erase(std::next(_entryData->_macros.begin(), idx));
adjustSize();
updateGeometry();
@ -685,8 +687,12 @@ void MacroConditionMacroEdit::Remove(int idx)
void MacroConditionMacroEdit::Replace(int idx, const std::string &name)
{
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
MacroRef macro(name);
auto lock = LockContext();
_entryData->_macros[idx] = macro;
adjustSize();
updateGeometry();
@ -694,7 +700,11 @@ void MacroConditionMacroEdit::Replace(int idx, const std::string &name)
void MacroConditionMacroEdit::ActionIndexChanged(const IntVariable &value)
{
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_actionIndex = value;
}

View File

@ -9,6 +9,7 @@
#include <QPushButton>
#include <QHBoxLayout>
#include <QTimer>
#include <QListWidget>
namespace advss {
@ -39,7 +40,6 @@ public:
ACTION_DISABLED,
ACTION_ENABLED,
PAUSED,
ACTIONS_PERFORMED,
};
void SetType(Type);
Type GetType() const { return _type; }
@ -67,7 +67,6 @@ private:
bool CheckMultiStateCondition();
bool CheckActionStateCondition();
bool CheckPauseState();
bool CheckActionsPerformed();
void SetupTempVars();
@ -136,7 +135,6 @@ private:
void SetupCountWidgets();
void SetupActionStateWidgets(bool enable);
void SetupPauseWidgets();
void SetupActionsPerformedWidgets();
void SetWidgetVisibility();
bool _loading = true;
};

View File

@ -27,9 +27,6 @@ bool MacroConditionQueue::CheckCondition()
return false;
}
SetTempVarValue("size", std::to_string(queue->Size()));
SetTempVarValue("running", queue->IsRunning());
switch (_condition) {
case Condition::STARTED:
return queue->IsRunning();
@ -66,18 +63,6 @@ std::string MacroConditionQueue::GetShortDesc() const
return GetActionQueueName(_queue);
}
void MacroConditionQueue::SetupTempVars()
{
MacroCondition::SetupTempVars();
AddTempvar("size",
obs_module_text("AdvSceneSwitcher.tempVar.queue.size"));
AddTempvar(
"running",
obs_module_text("AdvSceneSwitcher.tempVar.queue.running"),
obs_module_text(
"AdvSceneSwitcher.tempVar.queue.running.description"));
}
static inline void populateQueueTypeSelection(QComboBox *list)
{
for (const auto &[_, name] : conditionTypes) {
@ -115,7 +100,11 @@ MacroConditionQueueEdit::MacroConditionQueueEdit(
void MacroConditionQueueEdit::ConditionChanged(int condition)
{
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_condition =
static_cast<MacroConditionQueue::Condition>(condition);
emit HeaderInfoChanged(
@ -125,7 +114,11 @@ void MacroConditionQueueEdit::ConditionChanged(int condition)
void MacroConditionQueueEdit::QueueChanged(const QString &text)
{
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_queue = GetWeakActionQueueByQString(text);
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
@ -133,7 +126,11 @@ void MacroConditionQueueEdit::QueueChanged(const QString &text)
void MacroConditionQueueEdit::SizeChanged(const NumberVariable<int> &value)
{
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_size = value;
}
@ -144,7 +141,6 @@ void MacroConditionQueueEdit::UpdateEntryData()
}
_conditions->setCurrentIndex(static_cast<int>(_entryData->_condition));
_queues->SetActionQueue(_entryData->_queue);
_size->SetValue(_entryData->_size);
SetWidgetVisibility();
}

View File

@ -32,8 +32,6 @@ public:
IntVariable _size = 1;
private:
void SetupTempVars();
static bool _registered;
static const std::string id;
};

View File

@ -8,14 +8,10 @@ namespace advss {
MacroConditionScript::MacroConditionScript(
Macro *m, const std::string &id, const OBSData &defaultSettings,
const std::string &propertiesSignalName,
const std::string &triggerSignalName,
const std::string &completionSignalName,
const std::string &newInstanceSignalName,
const std::string &deletedInstanceSignalName)
const std::string &triggerSignal, const std::string &completionSignal)
: MacroCondition(m),
MacroSegmentScript(defaultSettings, propertiesSignalName,
triggerSignalName, completionSignalName,
newInstanceSignalName, deletedInstanceSignalName),
triggerSignal, completionSignal),
_id(id)
{
}
@ -80,29 +76,4 @@ void MacroConditionScript::WaitForCompletion() const
}
}
void MacroConditionScript::RegisterTempVarHelper(const std::string &variableId,
const std::string &name,
const std::string &helpText)
{
AddTempvar(variableId, name, helpText);
}
void MacroConditionScript::DeregisterAllTempVarsHelper()
{
MacroSegment::SetupTempVars();
}
void MacroConditionScript::SetTempVarValueHelper(const std::string &variableId,
const std::string &value)
{
MacroCondition::SetTempVarValue(variableId, value);
}
void MacroConditionScript::SetupTempVars()
{
// This just exists so MacroSegment::SetupTempVars() is not called.
// We want the ScriptHandler to handle the registration and clearing of
// the temp vars.
}
} // namespace advss

View File

@ -10,10 +10,8 @@ public:
MacroConditionScript(Macro *m, const std::string &id,
const OBSData &defaultSettings,
const std::string &propertiesSignalName,
const std::string &triggerSignalName,
const std::string &completionSignalName,
const std::string &newInstanceSignalName,
const std::string &deletedInstanceSignalName);
const std::string &triggerSignal,
const std::string &signalComplete);
MacroConditionScript(const advss::MacroConditionScript &);
bool CheckCondition();
bool Save(obs_data_t *obj) const;
@ -22,13 +20,6 @@ public:
private:
void WaitForCompletion() const;
void RegisterTempVarHelper(const std::string &variableId,
const std::string &name,
const std::string &helpText);
void DeregisterAllTempVarsHelper();
void SetTempVarValueHelper(const std::string &variableId,
const std::string &value);
void SetupTempVars();
std::string _id = "";
};

View File

@ -154,7 +154,7 @@ bool MacroConditionTempVar::CheckCondition()
bool MacroConditionTempVar::Save(obs_data_t *obj) const
{
MacroCondition::Save(obj);
_tempVar.Save(obj, GetMacro());
_tempVar.Save(obj);
obs_data_set_string(obj, "variableName",
GetWeakVariableName(_variable2).c_str());
_strValue.Save(obj, "strValue");
@ -264,19 +264,32 @@ void MacroConditionTempVarEdit::UpdateEntryData()
void MacroConditionTempVarEdit::VariableChanged(const TempVariableRef &var)
{
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_tempVar = var;
}
void MacroConditionTempVarEdit::Variable2Changed(const QString &text)
{
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_variable2 = GetWeakVariableByQString(text);
}
void MacroConditionTempVarEdit::ConditionChanged(int value)
{
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_type =
static_cast<MacroConditionTempVar::Condition>(value);
SetWidgetVisibility();
@ -284,7 +297,11 @@ void MacroConditionTempVarEdit::ConditionChanged(int value)
void MacroConditionTempVarEdit::StrValueChanged()
{
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_strValue = _strValue->toPlainText().toStdString();
adjustSize();
updateGeometry();
@ -292,13 +309,21 @@ void MacroConditionTempVarEdit::StrValueChanged()
void MacroConditionTempVarEdit::NumValueChanged(double val)
{
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_numValue = val;
}
void MacroConditionTempVarEdit::RegexChanged(const RegexConfig &conf)
{
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_regex = conf;
adjustSize();
updateGeometry();

View File

@ -236,7 +236,11 @@ void MacroConditionVariableEdit::UpdateEntryData()
void MacroConditionVariableEdit::VariableChanged(const QString &text)
{
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_variable = GetWeakVariableByQString(text);
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
@ -244,13 +248,22 @@ void MacroConditionVariableEdit::VariableChanged(const QString &text)
void MacroConditionVariableEdit::Variable2Changed(const QString &text)
{
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_variable2 = GetWeakVariableByQString(text);
}
void MacroConditionVariableEdit::ConditionChanged(int value)
{
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_type =
static_cast<MacroConditionVariable::Condition>(value);
SetWidgetVisibility();
@ -258,7 +271,11 @@ void MacroConditionVariableEdit::ConditionChanged(int value)
void MacroConditionVariableEdit::StrValueChanged()
{
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_strValue = _strValue->toPlainText().toStdString();
adjustSize();
updateGeometry();
@ -266,13 +283,21 @@ void MacroConditionVariableEdit::StrValueChanged()
void MacroConditionVariableEdit::NumValueChanged(double val)
{
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_numValue = val;
}
void MacroConditionVariableEdit::RegexChanged(const RegexConfig &conf)
{
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_regex = conf;
adjustSize();
updateGeometry();

View File

@ -7,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
{
MacroSegment::Save(obj);

View File

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

View File

@ -1,394 +0,0 @@
#include "macro-dock-settings.hpp"
#include "macro-dock.hpp"
#include "macro-dock-window.hpp"
#include "macro.hpp"
#include "plugin-state-helpers.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();
if (macro) {
const auto &settings = macro->GetDockSettings();
_run->setVisible(settings.HasRunButton());
_pauseToggle->setVisible(settings.HasPauseButton());
_statusText->setVisible(settings.HasStatusLabel());
_run->setVisible(macro->DockHasRunButton());
_pauseToggle->setVisible(macro->DockHasPauseButton());
_statusText->setVisible(macro->DockHasStatusLabel());
}
QWidget::connect(_run, SIGNAL(clicked()), this, SLOT(RunClicked()));
@ -110,7 +109,7 @@ void MacroDock::RunClicked()
return;
}
auto ret = macro->PerformActions(true, true, true);
auto ret = macro->PerformActions(true);
if (!ret) {
QString err =
obs_module_text("AdvSceneSwitcher.macroTab.runFail");

File diff suppressed because it is too large Load Diff

View File

@ -1,141 +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();
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 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,6 +1,5 @@
#include "macro-helpers.hpp"
#include "macro.hpp"
#include "macro-action-macro.hpp"
#include "plugin-state-helpers.hpp"
namespace advss {
@ -9,87 +8,6 @@ static std::atomic_bool abortMacroWait = {false};
static std::atomic_bool macroSceneSwitched = {false};
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>>>
GetMacroActions(Macro *macro)
{
@ -99,15 +17,6 @@ GetMacroActions(Macro *macro)
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>>>
GetMacroConditions(Macro *macro)
{
@ -117,32 +26,9 @@ GetMacroConditions(Macro *macro)
return macro->Conditions();
}
bool IsGroupMacro(Macro *macro)
std::string_view GetSceneSwitchActionId()
{
return macro && macro->IsGroup();
}
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;
return MacroAction::GetDefaultID();
}
std::condition_variable &GetMacroWaitCV()
@ -181,7 +67,9 @@ void SetMacroSwitchedScene(bool value)
{
static bool setupDone = false;
if (!setupDone) {
AddIntervalResetStep([]() { macroSceneSwitched = false; });
// Will always be called with switcher lock already held
AddIntervalResetStep([]() { macroSceneSwitched = false; },
false);
setupDone = true;
}
macroSceneSwitched = value;
@ -192,43 +80,35 @@ bool MacroSwitchedScene()
return macroSceneSwitched;
}
std::string GetMacroName(const Macro *macro)
std::string GetMacroName(Macro *macro)
{
return macro ? macro->Name() : "";
}
std::chrono::high_resolution_clock::time_point
LastMacroConditionCheckTime(const Macro *macro)
LastMacroConditionCheckTime(Macro *macro)
{
return macro ? macro->LastConditionCheckTime()
: std::chrono::high_resolution_clock::time_point{};
}
bool MacroIsStopped(const Macro *macro)
bool MacroIsStopped(Macro *macro)
{
return macro ? macro->GetStop() : true;
}
bool MacroIsPaused(const Macro *macro)
bool MacroIsPaused(Macro *macro)
{
return macro ? macro->Paused() : true;
}
bool MacroWasPausedSince(
const Macro *macro,
Macro *macro,
const std::chrono::high_resolution_clock::time_point &time)
{
return macro ? macro->WasPausedSince(time) : false;
}
bool MacroWasCheckedSinceLastStart(const Macro *macro)
{
if (!macro) {
return false;
}
return macro->LastConditionCheckTime().time_since_epoch().count() != 0;
}
void AddMacroHelperThread(Macro *macro, std::thread &&newThread)
{
if (!macro) {
@ -242,11 +122,6 @@ bool RunMacroActions(Macro *macro)
return macro && macro->PerformActions(true);
}
bool RunMacroElseActions(Macro *macro)
{
return macro && macro->PerformActions(false);
}
void ResetMacroConditionTimers(Macro *macro)
{
if (!macro) {
@ -263,42 +138,20 @@ void ResetMacroRunCount(Macro *macro)
macro->ResetRunCount();
}
bool IsValidActionIndex(const Macro *m, const int idx)
bool IsValidMacroSegmentIndex(Macro *m, const int idx, bool isCondition)
{
if (!m || idx < 0) {
return false;
}
if (idx >= (int)m->Actions().size()) {
return false;
if (isCondition) {
if (idx >= (int)m->Conditions().size()) {
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;
}

View File

@ -1,13 +1,12 @@
#pragma once
#include "export-symbol-helper.hpp"
#include <QString>
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <deque>
#include <optional>
#include <string_view>
#include <thread>
struct obs_data;
@ -19,25 +18,16 @@ class Macro;
class MacroAction;
class MacroCondition;
static const int macro_func = 10;
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::deque<std::shared_ptr<Macro>> &GetMacros();
EXPORT std::optional<std::deque<std::shared_ptr<MacroAction>>>
GetMacroActions(Macro *);
EXPORT std::optional<std::deque<std::shared_ptr<MacroAction>>>
GetMacroElseActions(Macro *);
EXPORT std::optional<std::deque<std::shared_ptr<MacroCondition>>>
GetMacroConditions(Macro *);
EXPORT bool IsGroupMacro(Macro *);
EXPORT std::vector<std::shared_ptr<Macro>> GetGroupMacroEntries(Macro *);
std::string_view GetSceneSwitchActionId();
constexpr auto macro_func = 10;
EXPORT std::condition_variable &GetMacroWaitCV();
EXPORT std::condition_variable &GetMacroTransitionCV();
@ -51,24 +41,22 @@ EXPORT std::atomic_int &GetShutdownConditionCount();
EXPORT void SetMacroSwitchedScene(bool value);
EXPORT bool MacroSwitchedScene();
EXPORT std::string GetMacroName(const Macro *);
EXPORT std::string GetMacroName(Macro *);
EXPORT std::chrono::high_resolution_clock::time_point
LastMacroConditionCheckTime(const Macro *);
LastMacroConditionCheckTime(Macro *);
EXPORT bool MacroIsStopped(const Macro *);
EXPORT bool MacroIsPaused(const Macro *);
EXPORT bool MacroIsStopped(Macro *);
EXPORT bool MacroIsPaused(Macro *);
EXPORT bool
MacroWasPausedSince(const Macro *,
MacroWasPausedSince(Macro *,
const std::chrono::high_resolution_clock::time_point &);
EXPORT bool MacroWasCheckedSinceLastStart(const Macro *);
EXPORT void AddMacroHelperThread(Macro *, std::thread &&);
EXPORT bool CheckMacros();
EXPORT bool RunMacroActions(Macro *);
bool RunMacroElseActions(Macro *);
EXPORT bool RunMacros();
void StopAllMacros();
@ -79,8 +67,6 @@ EXPORT void InvalidateMacroTempVarValues();
EXPORT void ResetMacroConditionTimers(Macro *);
EXPORT void ResetMacroRunCount(Macro *);
bool IsValidActionIndex(const Macro *m, const int idx);
bool IsValidElseActionIndex(const Macro *m, const int idx);
bool IsValidConditionIndex(const Macro *m, const int idx);
bool IsValidMacroSegmentIndex(Macro *m, const int idx, bool isCondition);
} // namespace advss

View File

@ -181,7 +181,15 @@ void MacroInputEdit::SetInputVariablesAndValues(
_variables = inputs;
_values = values;
if ((size_t)_values.size() < _variables._inputVariables.size()) {
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
for (int i = 0;
_variables._inputVariables.size() - (size_t)_values.size();
i++) {
_values.push_back({});
}
#else
_values.resize(_variables._inputVariables.size());
#endif
}
SetupWidgets();
}
@ -191,7 +199,7 @@ bool MacroInputEdit::HasInputsToSet() const
return !_variables._inputVariables.empty();
}
void HighlightMacroSettingsButton(bool enable);
void HighligthMacroSettingsButton(bool enable);
void MacroInputEdit::SetupWidgets()
{

View File

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

View File

@ -11,14 +11,10 @@ namespace advss {
MacroRunButton::MacroRunButton(QWidget *parent) : QPushButton(parent)
{
installEventFilter(this);
// GetSettingsWindow() might still return null while this constructor is called
QTimer::singleShot(0, this, [this]() {
auto parentWindow = GetSettingsWindow();
if (parentWindow) {
parentWindow->installEventFilter(this);
}
});
auto parentWindow = window();
if (parentWindow) {
parentWindow->installEventFilter(this);
}
setToolTip(obs_module_text("AdvSceneSwitcher.macroTab.run.tooltip"));

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