mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-08-29 04:36:21 -05:00
Compare commits
2 Commits
ui
...
websocket-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5d568683f7 | ||
|
|
a26c37021d |
@@ -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
|
||||
|
||||
44
.github/scripts/.build-deps.zsh
vendored
44
.github/scripts/.build-deps.zsh
vendored
@@ -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 \
|
||||
@@ -499,8 +491,8 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
|
||||
-DPAHO_BUILD_SHARED=OFF
|
||||
-DPAHO_BUILD_STATIC=ON
|
||||
-DPAHO_WITH_MQTT_C=ON
|
||||
-DPAHO_WITH_SSL=ON
|
||||
-DOPENSSL_USE_STATIC_LIBS=ON
|
||||
-DOPENSSL_ROOT_DIR="${advss_dep_path}"
|
||||
-DPAHO_WITH_SSL=OFF # TODO: figure out linking issues with openssl
|
||||
)
|
||||
|
||||
pushd ${mqtt_dir}
|
||||
|
||||
10
.github/scripts/.build.zsh
vendored
10
.github/scripts/.build.zsh
vendored
@@ -253,12 +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_ROOT_DIR="${advss_deps_path}"
|
||||
-DOPENSSL_INCLUDE_DIR="${advss_deps_path}/include"
|
||||
-DOPENSSL_CRYPTO_LIBRARY="${advss_deps_path}/lib/libcrypto.a"
|
||||
-DOPENSSL_SSL_LIBRARY="${advss_deps_path}/lib/libssl.a"
|
||||
-DOPENSSL_INCLUDE_DIR="${openssl_include_dir}"
|
||||
-DOPENSSL_LIBRARIES="${openssl_lib_dir}/libcrypto.a;${openssl_lib_dir}/libssl.a"
|
||||
--preset ${_preset}
|
||||
)
|
||||
|
||||
|
||||
3
.github/scripts/.package.zsh
vendored
3
.github/scripts/.package.zsh
vendored
@@ -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
|
||||
|
||||
18
.github/scripts/Build-Deps-Windows.ps1
vendored
18
.github/scripts/Build-Deps-Windows.ps1
vendored
@@ -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)) {
|
||||
@@ -234,24 +232,8 @@ function Build {
|
||||
"-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
|
||||
|
||||
|
||||
1
.github/scripts/utils.zsh/check_macos
vendored
1
.github/scripts/utils.zsh/check_macos
vendored
@@ -18,4 +18,5 @@ if (( ! ${+commands[brew]} )) {
|
||||
}
|
||||
|
||||
brew bundle --file ${SCRIPT_HOME}/.Brewfile
|
||||
rehash
|
||||
log_group
|
||||
|
||||
1
.github/scripts/utils.zsh/setup_ccache
vendored
1
.github/scripts/utils.zsh/setup_ccache
vendored
@@ -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
|
||||
|
||||
1
.github/scripts/utils.zsh/setup_linux
vendored
1
.github/scripts/utils.zsh/setup_linux
vendored
@@ -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=()
|
||||
|
||||
10
.github/workflows/build-project.yaml
vendored
10
.github/workflows/build-project.yaml
vendored
@@ -6,7 +6,7 @@ on:
|
||||
description: "Project name detected by parsing build spec file"
|
||||
value: ${{ jobs.check-event.outputs.pluginName }}
|
||||
env:
|
||||
DEP_DIR: .deps/advss-build-dependencies-4
|
||||
DEP_DIR: .deps/advss-build-dependencies
|
||||
jobs:
|
||||
check-event:
|
||||
name: Check GitHub Event Data 🔎
|
||||
@@ -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
|
||||
@@ -213,7 +213,7 @@ jobs:
|
||||
- name: Set up CMake 🏗️
|
||||
uses: jwlawson/actions-setup-cmake@v1.13
|
||||
with:
|
||||
cmake-version: '3.x.x'
|
||||
cmake-version: '3.24.x'
|
||||
|
||||
- name: Set up Homebrew 🍺
|
||||
uses: Homebrew/actions/setup-homebrew@master
|
||||
|
||||
@@ -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)
|
||||
```
|
||||
|
||||
@@ -34,11 +34,6 @@ 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()
|
||||
@@ -128,12 +123,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 +135,21 @@ 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-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-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)
|
||||
|
||||
@@ -181,12 +164,8 @@ target_sources(
|
||||
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,8 +183,6 @@ 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
|
||||
@@ -240,8 +217,6 @@ target_sources(
|
||||
lib/utils/priority-helper.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
|
||||
@@ -456,29 +431,14 @@ else()
|
||||
endif()
|
||||
if(PROCPS2_INCLUDE_DIR)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(libproc2 IMPORTED_TARGET libproc2<4.0.5 QUIET)
|
||||
if(libproc2_FOUND)
|
||||
target_compile_definitions(${LIB_NAME} PRIVATE PROCPS2_USE_INFO)
|
||||
endif()
|
||||
pkg_check_modules(libproc2 REQUIRED IMPORTED_TARGET libproc2)
|
||||
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(
|
||||
@@ -504,11 +464,7 @@ endif()
|
||||
# --- End of section ---
|
||||
|
||||
add_subdirectory(plugins)
|
||||
|
||||
option(ADVSS_ENABLE_TESTS "Build advanced-scene-switcher unit tests" OFF)
|
||||
if(ADVSS_ENABLE_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
add_subdirectory(tests)
|
||||
|
||||
# --- Install ---
|
||||
|
||||
|
||||
@@ -41,8 +41,7 @@
|
||||
"description": "Build for macOS 11.0+ (Universal binary) for CI",
|
||||
"generator": "Xcode",
|
||||
"cacheVariables": {
|
||||
"CMAKE_COMPILE_WARNING_AS_ERROR": true,
|
||||
"ADVSS_ENABLE_TESTS": true
|
||||
"CMAKE_COMPILE_WARNING_AS_ERROR": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -70,8 +69,7 @@
|
||||
"displayName": "Windows x64 CI build",
|
||||
"description": "Build for Windows x64 on CI",
|
||||
"cacheVariables": {
|
||||
"CMAKE_COMPILE_WARNING_AS_ERROR": true,
|
||||
"ADVSS_ENABLE_TESTS": true
|
||||
"CMAKE_COMPILE_WARNING_AS_ERROR": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -99,8 +97,7 @@
|
||||
"description": "Build for Linux x86_64 on CI",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
|
||||
"CMAKE_COMPILE_WARNING_AS_ERROR": true,
|
||||
"ADVSS_ENABLE_TESTS": true
|
||||
"CMAKE_COMPILE_WARNING_AS_ERROR": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -128,8 +125,7 @@
|
||||
"description": "Build for Linux aarch64 on CI",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
|
||||
"CMAKE_COMPILE_WARNING_AS_ERROR": true,
|
||||
"ADVSS_ENABLE_TESTS": true
|
||||
"CMAKE_COMPILE_WARNING_AS_ERROR": true
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -14,6 +14,11 @@ On Linux the plugin is available via the **Flatpak** package manager for users w
|
||||
flatpak install com.obsproject.Studio.Plugin.SceneSwitcher
|
||||
```
|
||||
|
||||
The **Snap** package manager offers an OBS Studio installation which is bundled with the plugin:
|
||||
```
|
||||
sudo snap install obs-studio
|
||||
```
|
||||
|
||||
More information can be found [here](https://github.com/WarmUpTill/SceneSwitcher/wiki/Installation).
|
||||
|
||||
## Contributing
|
||||
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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}")
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -22,7 +22,6 @@ 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"
|
||||
|
||||
@@ -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()
|
||||
@@ -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"
|
||||
@@ -76,6 +76,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?"
|
||||
@@ -99,6 +100,7 @@ AdvSceneSwitcher.macroList.deleted="gelöscht"
|
||||
AdvSceneSwitcher.macroList.duplicate="\"%1\" ist bereits ausgewählt!"
|
||||
|
||||
; Macro Logic
|
||||
AdvSceneSwitcher.logic.none="Eintrag ignorieren"
|
||||
AdvSceneSwitcher.logic.and="Und"
|
||||
AdvSceneSwitcher.logic.or="Oder"
|
||||
AdvSceneSwitcher.logic.andNot="Und nicht"
|
||||
@@ -144,7 +146,11 @@ AdvSceneSwitcher.condition.file="Datei"
|
||||
AdvSceneSwitcher.condition.file.type.match="entspricht"
|
||||
AdvSceneSwitcher.condition.file.type.contentChange="Inhalt geändert"
|
||||
AdvSceneSwitcher.condition.file.type.dateChange="Änderungsdatum geändert"
|
||||
AdvSceneSwitcher.condition.file.layout="{{filePath}}{{conditions}}{{regex}}"
|
||||
AdvSceneSwitcher.condition.file.remote="Entfernte Datei"
|
||||
AdvSceneSwitcher.condition.file.local="Lokale Datei"
|
||||
AdvSceneSwitcher.condition.file.entry.line1="{{fileType}}{{filePath}}{{conditions}}{{useRegex}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFileContent}}"
|
||||
AdvSceneSwitcher.condition.media="Medien"
|
||||
AdvSceneSwitcher.condition.media.source="Quelle"
|
||||
AdvSceneSwitcher.condition.media.anyOnScene="Beliebige Medienquelle in"
|
||||
@@ -210,8 +216,8 @@ AdvSceneSwitcher.condition.record.state.start="Aufnahme läuft"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Aufnahme pausiert"
|
||||
AdvSceneSwitcher.condition.record.state.stop="Aufnahme gestoppt"
|
||||
AdvSceneSwitcher.condition.process="Prozess"
|
||||
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}läuft{{focused}}und ist fokusiert"
|
||||
AdvSceneSwitcher.condition.process.layout.focus="Aktueller Vordergrundprozess: {{focusProcess}}"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}läuft{{focused}}und ist fokusiert"
|
||||
AdvSceneSwitcher.condition.process.entry.focus="Aktueller Vordergrundprozess: {{focusProcess}}"
|
||||
AdvSceneSwitcher.condition.idle="Leerlauf"
|
||||
AdvSceneSwitcher.condition.idle.entry="Keine Tastatur- oder Mauseingaben für {{duration}}"
|
||||
AdvSceneSwitcher.condition.pluginState="Plugin-Status"
|
||||
@@ -285,14 +291,14 @@ AdvSceneSwitcher.condition.replay.state.started="Replay Buffer gestartet"
|
||||
AdvSceneSwitcher.condition.replay.state.saved="Replay Buffer gespeichert"
|
||||
AdvSceneSwitcher.condition.replay.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"
|
||||
@@ -303,13 +309,12 @@ AdvSceneSwitcher.condition.date.ignoreDate="Wenn diese Option nicht aktiviert is
|
||||
AdvSceneSwitcher.condition.date.ignoreTime="Wenn diese Option nicht aktiviert ist, wird die Zeitkomponente ignoriert"
|
||||
AdvSceneSwitcher.condition.date.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"
|
||||
@@ -378,6 +383,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"
|
||||
@@ -407,6 +414,7 @@ AdvSceneSwitcher.action.recording.type.unpause="Aufnahme nicht mehr pausieren"
|
||||
AdvSceneSwitcher.action.recording.type.split="Aufnahme-Datei teilen"
|
||||
AdvSceneSwitcher.action.recording.pause.hint="Bitte beachten, dass je nach Aufnahmeeinstellung die Aufnahme möglicherweise nicht unterbrochen werden kann"
|
||||
AdvSceneSwitcher.action.recording.split.hint="Vergewissern, dass die automatische Dateiaufteilung in den OBS-Einstellungen aktiviert ist!"
|
||||
AdvSceneSwitcher.action.recording.entry="{{actions}}{{recordFolder}}{{recordFileFormat}}{{pauseHint}}{{splitHint}}"
|
||||
AdvSceneSwitcher.action.replay="Replay Buffer"
|
||||
AdvSceneSwitcher.action.replay.saveWarn="Warnung: Ein zu häufiges Speichern kann dazu führen, dass der Replay Buffer nicht gespeichert wird!"
|
||||
AdvSceneSwitcher.action.replay.type.stop="Replay Buffer stoppen"
|
||||
@@ -415,6 +423,7 @@ AdvSceneSwitcher.action.replay.type.save="Replay Buffer speichern"
|
||||
AdvSceneSwitcher.action.streaming="Stream"
|
||||
AdvSceneSwitcher.action.streaming.type.stop="Stream stoppen"
|
||||
AdvSceneSwitcher.action.streaming.type.start="Stream starten"
|
||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
|
||||
AdvSceneSwitcher.action.run="Ausführen"
|
||||
AdvSceneSwitcher.action.sceneVisibility="Sichtbarkeit von Szenenelementen"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.show="Anzeigen"
|
||||
@@ -422,7 +431,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.hide="Verstecken"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.toggle="Umschalten"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.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"
|
||||
@@ -450,14 +459,14 @@ AdvSceneSwitcher.action.macro="Makro"
|
||||
AdvSceneSwitcher.action.macro.type.pause="Pausieren"
|
||||
AdvSceneSwitcher.action.macro.type.unpause="Nicht mehr pausieren"
|
||||
AdvSceneSwitcher.action.macro.type.resetCounter="Zähler zurücksetzen"
|
||||
AdvSceneSwitcher.action.macro.type.runActions="Aktionen ausführen"
|
||||
AdvSceneSwitcher.action.macro.type.run="Aktionen ausführen"
|
||||
AdvSceneSwitcher.action.macro.type.stop="Aktionen stoppen"
|
||||
AdvSceneSwitcher.action.pluginState="Plugin-Status"
|
||||
AdvSceneSwitcher.action.pluginState.type.stop="Erweiterten Automatischen Szenenwechsler stoppen"
|
||||
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"
|
||||
@@ -498,9 +507,9 @@ AdvSceneSwitcher.action.transition.type.scene="Szenenübergang"
|
||||
AdvSceneSwitcher.action.transition.type.sceneOverride="Szenenübergang überschreiben"
|
||||
AdvSceneSwitcher.action.transition.type.sourceShow="Übergang der Quelle anzeigen"
|
||||
AdvSceneSwitcher.action.transition.type.sourceHide="Übergang der Quelle verstecken"
|
||||
AdvSceneSwitcher.action.transition.layout.type="Anpassen {{type}}{{scenes}}{{sources}}"
|
||||
AdvSceneSwitcher.action.transition.layout.transition="{{setTransition}}Übergangstyp festlegen auf {{transitions}}"
|
||||
AdvSceneSwitcher.action.transition.layout.duration="{{setDuration}}Übergangsdauer festlegen auf {{duration}}Sekunden"
|
||||
AdvSceneSwitcher.action.transition.entry.line1="Anpassen {{type}}{{scenes}}{{sources}}"
|
||||
AdvSceneSwitcher.action.transition.entry.line2="{{setTransition}}Übergangstyp festlegen auf {{transitions}}"
|
||||
AdvSceneSwitcher.action.transition.entry.line3="{{setDuration}}Übergangsdauer festlegen auf {{duration}}Sekunden"
|
||||
AdvSceneSwitcher.action.timer="Timer"
|
||||
AdvSceneSwitcher.action.timer.type.pause="Pausieren"
|
||||
AdvSceneSwitcher.action.timer.type.continue="Fortsetzen"
|
||||
@@ -827,6 +836,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"
|
||||
|
||||
@@ -4,7 +4,7 @@ AdvSceneSwitcher.windowTitle="Advanced Scene Switcher"
|
||||
# General Tab
|
||||
AdvSceneSwitcher.generalTab.title="General"
|
||||
AdvSceneSwitcher.generalTab.status="Status"
|
||||
AdvSceneSwitcher.generalTab.status.hotkeytips="Start/stop hotkeys can be defined in the OBS settings"
|
||||
AdvSceneSwitcher.generalTab.status.hotkeytips="Hotkeys can be defined in the OBS settings"
|
||||
AdvSceneSwitcher.generalTab.status.currentStatus="Advanced Scene Switcher is:"
|
||||
AdvSceneSwitcher.generalTab.status.onStartup="On startup of OBS:"
|
||||
AdvSceneSwitcher.generalTab.status.onStartup.asLastRun="Start the scene switcher if it was running"
|
||||
@@ -12,12 +12,11 @@ AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Always start the scene
|
||||
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Do not start the scene switcher"
|
||||
AdvSceneSwitcher.generalTab.status.start="Start"
|
||||
AdvSceneSwitcher.generalTab.status.stop="Stop"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.startup="Automatically start the scene switcher when:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart="Automatically start the scene switcher when:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.never="Never"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.recording="Recording"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Streaming"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.recordingAndStreaming="Recording or Streaming"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.scene="Automatically start the scene switcher on scene:"
|
||||
AdvSceneSwitcher.generalTab.status.checkInterval="Check conditions every"
|
||||
AdvSceneSwitcher.generalTab.status.checkIntervalTooLow="⚠️ Conflict with macro \"%1\"!"
|
||||
AdvSceneSwitcher.generalTab.status.checkIntervalTooLow.tooltip="Macro \"%1\" won't be able to check its condition at the desired interval of %2.\nEither change the condition check value on the General tab or in the settings of macro \"%3\"."
|
||||
@@ -40,13 +39,10 @@ AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="Show system t
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="Disable UI hints"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.comboBoxFilterDisable="Disable filtering by typing in drop down menus"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.warnPluginLoadFailure="Display warning if plugins cannot be loaded"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.suppressCrashRecoveryDialog="Do not ask to keep the plugin stopped after an unclean shutdown"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.warnPluginLoadFailureMessage="<html><body>Loading of the following plugin libraries was unsuccessful, which could result in some Advanced Scene Switcher functions not being available:%1Check the OBS logs for details.<br>This message can be disabled on the General tab.</body></html>"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.warnCorruptedInstallMessage="The plugin installation seems to be corrupted and might crash!\nPlease make sure the plugin was installed correctly!"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.hideLegacyTabs="Hide tabs which can be represented via macros"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.alwaysShowMacroSearch="Always show macro search"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.alwaysShowFeatureTabs="Always show all feature tabs"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.alwaysShowFeatureTabs.tooltip="Show tabs that are normally hidden until first used in a macro (e.g. Action Queues, Variables, Twitch, Websockets)."
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.disableMacroWidgetCache="Disable macro widget caching"
|
||||
AdvSceneSwitcher.generalTab.matchBehavior="Match behavior"
|
||||
AdvSceneSwitcher.generalTab.priority="Priority"
|
||||
AdvSceneSwitcher.generalTab.priority.description="Switching methods priority (Highest priority is at the top)"
|
||||
@@ -77,7 +73,6 @@ AdvSceneSwitcher.generalTab.setTransitionBy="When changing transitions:"
|
||||
AdvSceneSwitcher.generalTab.transitionOverride="Set transition overrides"
|
||||
AdvSceneSwitcher.generalTab.adjustActiveTransitionType="Change active transition type"
|
||||
AdvSceneSwitcher.generalTab.transitionBehaviorSelectionError="At least one option must be enabled:\n\n - Use transition overrides\n\n - Change active transition type"
|
||||
AdvSceneSwitcher.generalTab.uiBehavior="UI settings"
|
||||
|
||||
# Variables Tab
|
||||
AdvSceneSwitcher.variableTab.title="Variables"
|
||||
@@ -95,12 +90,6 @@ AdvSceneSwitcher.variableTab.lastUsed.text.never="Never"
|
||||
AdvSceneSwitcher.variableTab.lastChanged.header="Last changed"
|
||||
AdvSceneSwitcher.variableTab.lastChanged.text.none="No change since launch"
|
||||
AdvSceneSwitcher.variableTab.lastChanged.tooltip="Times changed: %1\n\nPrevious value: %2"
|
||||
AdvSceneSwitcher.variableTab.search.placeholder="Search ..."
|
||||
AdvSceneSwitcher.variableTab.search.all="All columns"
|
||||
AdvSceneSwitcher.variableTab.search.name="Name column"
|
||||
AdvSceneSwitcher.variableTab.search.value="Value column"
|
||||
AdvSceneSwitcher.variableTab.addDock="Add dock"
|
||||
AdvSceneSwitcher.variableTab.clear="Clear"
|
||||
|
||||
# Action Queue Tab
|
||||
AdvSceneSwitcher.actionQueueTab.title="Action Queues"
|
||||
@@ -161,11 +150,9 @@ AdvSceneSwitcher.macroTab.title="Macro"
|
||||
AdvSceneSwitcher.macroTab.macros="Macros"
|
||||
AdvSceneSwitcher.macroTab.priorityWarning="Note: It is recommended to configure macros to be the highest priority functionality.\nThis setting can be changed on the General tab."
|
||||
AdvSceneSwitcher.macroTab.help="Macros allow you to execute a string of actions depending on multiple conditions.\n\nClick on the highlighted plus symbol to add a new Macro."
|
||||
AdvSceneSwitcher.macroTab.macroLastExecutedTooltip="Was last executed %1 seconds ago."
|
||||
AdvSceneSwitcher.macroTab.macroNotYetExecutedTooltip="Was not yet executed."
|
||||
AdvSceneSwitcher.macroTab.editConditionHelp="This section allows you to define macro conditions.\n\nSelect an existing or add a new macro on the left.\nThen click the plus button below to add a new condition."
|
||||
AdvSceneSwitcher.macroTab.editActionHelp="This section allows you to define macro actions.\nThe actions in this section will be performed when the conditions are met.\n\nSelect an existing or add a new macro on the left.\nThen click the plus button below to add a new action."
|
||||
AdvSceneSwitcher.macroTab.editElseActionHelp="This section allows you to define macro actions.\nThe actions in this section will be performed when the conditions are *not* met.\n\nSelect an existing or add a new macro on the left.\nThen click the plus button below to add a new action."
|
||||
AdvSceneSwitcher.macroTab.editConditionHelp="This section allows you to define Macro conditions.\n\nSelect an existing or add a new Macro on the left.\nThen click the plus button below to add a new condition."
|
||||
AdvSceneSwitcher.macroTab.editActionHelp="This section allows you to define Macro actions.\n\nSelect an existing or add a new Macro on the left.\nThen click the plus button below to add a new action."
|
||||
AdvSceneSwitcher.macroTab.editElseActionHelp="This section allows you to define Macro actions, which are executed if the conditions are *not* met.\n\nSelect an existing or add a new Macro on the left.\nThen click the plus button below to add a new action."
|
||||
AdvSceneSwitcher.macroTab.edit="Edit macro"
|
||||
AdvSceneSwitcher.macroTab.edit.logic="Logic type:"
|
||||
AdvSceneSwitcher.macroTab.edit.condition="Condition type:"
|
||||
@@ -178,12 +165,7 @@ AdvSceneSwitcher.macroTab.run.tooltip="Run all macro actions regardless of condi
|
||||
AdvSceneSwitcher.macroTab.runElse="Run macro (else)"
|
||||
AdvSceneSwitcher.macroTab.runFail="Running \"%1\" failed!\nEither one of the actions failed or the macro is running already.\nDo you want to stop it?"
|
||||
AdvSceneSwitcher.macroTab.runInParallel="Run macro in parallel to other macros"
|
||||
AdvSceneSwitcher.macroTab.actionTriggerMode.label="Perform actions:"
|
||||
AdvSceneSwitcher.macroTab.actionTriggerMode.tooltip="Controls when the actions of this macro are performed.\n\n\"Always\" - actions are performed every time the conditions are met.\n\"Macro result changed\" - actions are only performed when the macro transitions between matching and not matching.\n\"Any condition changed\" - actions are only performed when any individual condition changes its result.\n\"Any condition triggered\" - actions are only performed when any individual condition changes from false to true."
|
||||
AdvSceneSwitcher.macroTab.actionTriggerMode.always="always"
|
||||
AdvSceneSwitcher.macroTab.actionTriggerMode.onOverallChange="only when result changes"
|
||||
AdvSceneSwitcher.macroTab.actionTriggerMode.onAnyConditionChange="only when any condition changes"
|
||||
AdvSceneSwitcher.macroTab.actionTriggerMode.onAnyConditionTriggered="only when any condition becomes true"
|
||||
AdvSceneSwitcher.macroTab.onChange="Perform actions only on condition change"
|
||||
AdvSceneSwitcher.macroTab.defaultname="Macro %1"
|
||||
AdvSceneSwitcher.macroTab.defaultGroupName="Group %1"
|
||||
AdvSceneSwitcher.macroTab.macroNameExists="The name \"%1\" is already used by a macro."
|
||||
@@ -195,8 +177,6 @@ AdvSceneSwitcher.macroTab.contextMenuAdd="Add"
|
||||
AdvSceneSwitcher.macroTab.copy="Duplicate Macro"
|
||||
AdvSceneSwitcher.macroTab.group="Group Selected Macros"
|
||||
AdvSceneSwitcher.macroTab.ungroup="Ungroup Selected Groups"
|
||||
AdvSceneSwitcher.macroTab.expandAllGroups="Expand all Groups"
|
||||
AdvSceneSwitcher.macroTab.collapseAllGroups="Collapse all Groups"
|
||||
AdvSceneSwitcher.macroTab.rename="Rename"
|
||||
AdvSceneSwitcher.macroTab.remove="Remove"
|
||||
AdvSceneSwitcher.macroTab.export="Export"
|
||||
@@ -249,8 +229,6 @@ AdvSceneSwitcher.macroTab.pauseStateSaveBehavior.persist="The state the macro wa
|
||||
AdvSceneSwitcher.macroTab.pauseStateSaveBehavior.pause="Paused"
|
||||
AdvSceneSwitcher.macroTab.pauseStateSaveBehavior.unpause="Unpaused"
|
||||
AdvSceneSwitcher.macroTab.currentRegisterDock="Register dock widget to control the pause state of selected macro or run it manually"
|
||||
AdvSceneSwitcher.macroTab.currentIsStandaloneDock="Is standalone dock"
|
||||
AdvSceneSwitcher.macroTab.currentDockWindowName="Add to macro dock with name:"
|
||||
AdvSceneSwitcher.macroTab.currentDockAddRunButton="Add button to run the macro"
|
||||
AdvSceneSwitcher.macroTab.currentDockAddPauseButton="Add button to pause or unpause the macro"
|
||||
AdvSceneSwitcher.macroTab.currentDockAddStatusLabel="Add status label"
|
||||
@@ -287,13 +265,6 @@ AdvSceneSwitcher.macroTab.tooltip.elseActionUpButton="Move selected action up in
|
||||
AdvSceneSwitcher.macroTab.tooltip.elseActionDownButton="Move selected action down in the else section"
|
||||
AdvSceneSwitcher.macroTab.tooltip.elseActionBottomButton="Move selected action to the bottom in the else section"
|
||||
AdvSceneSwitcher.macroTab.tooltip.openMacroSettingsButton="Open macro settings"
|
||||
AdvSceneSwitcher.macroTab.search.placeholder="Search ..."
|
||||
AdvSceneSwitcher.macroTab.search.showSettings="Show search settings"
|
||||
AdvSceneSwitcher.macroTab.search.name="Name"
|
||||
AdvSceneSwitcher.macroTab.search.allSegments="Segment type"
|
||||
AdvSceneSwitcher.macroTab.search.conditions="Condition type"
|
||||
AdvSceneSwitcher.macroTab.search.actions="Action type"
|
||||
AdvSceneSwitcher.macroTab.search.label="Segment label"
|
||||
|
||||
AdvSceneSwitcher.macroDock.pause="Pause"
|
||||
AdvSceneSwitcher.macroDock.unpause="Unpause"
|
||||
@@ -306,6 +277,7 @@ AdvSceneSwitcher.macroList.deleted="deleted"
|
||||
AdvSceneSwitcher.macroList.duplicate="\"%1\" is alreay selected!"
|
||||
|
||||
# Macro Logic
|
||||
AdvSceneSwitcher.logic.none="Ignore entry"
|
||||
AdvSceneSwitcher.logic.and="And"
|
||||
AdvSceneSwitcher.logic.or="Or"
|
||||
AdvSceneSwitcher.logic.andNot="And not"
|
||||
@@ -349,7 +321,6 @@ AdvSceneSwitcher.condition.scene.type.previousPattern="Previous scene matches"
|
||||
AdvSceneSwitcher.condition.scene.type.previewPattern="Preview scene matches"
|
||||
AdvSceneSwitcher.condition.scene.currentSceneTransitionBehaviour="During transition check for transition target scene"
|
||||
AdvSceneSwitcher.condition.scene.previousSceneTransitionBehaviour="During transition check for transition source scene"
|
||||
AdvSceneSwitcher.condition.scene.canvasNotSupported="This check is not supported for the currently selected canvas \"%1\""
|
||||
AdvSceneSwitcher.condition.scene.entry.line1="{{sceneType}}{{scenes}}{{pattern}}{{regex}}"
|
||||
AdvSceneSwitcher.condition.scene.entry.line2="{{useTransitionTargetScene}}"
|
||||
AdvSceneSwitcher.condition.window="Window"
|
||||
@@ -365,10 +336,11 @@ AdvSceneSwitcher.condition.file="File"
|
||||
AdvSceneSwitcher.condition.file.type.match="matches"
|
||||
AdvSceneSwitcher.condition.file.type.contentChange="content changed"
|
||||
AdvSceneSwitcher.condition.file.type.dateChange="modification date changed"
|
||||
AdvSceneSwitcher.condition.file.type.exists="exists"
|
||||
AdvSceneSwitcher.condition.file.type.isFile="is a file"
|
||||
AdvSceneSwitcher.condition.file.type.isFolder="is a folder"
|
||||
AdvSceneSwitcher.condition.file.layout="{{filePath}}{{conditions}}{{regex}}"
|
||||
AdvSceneSwitcher.condition.file.remote="Remote file"
|
||||
AdvSceneSwitcher.condition.file.local="Local file"
|
||||
AdvSceneSwitcher.condition.file.entry.line1="{{fileType}}{{filePath}}{{conditions}}{{useRegex}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFileContent}}"
|
||||
AdvSceneSwitcher.condition.media="Media"
|
||||
AdvSceneSwitcher.condition.media.checkType.state="State matches"
|
||||
AdvSceneSwitcher.condition.media.checkType.time="Time restriction matches"
|
||||
@@ -483,9 +455,8 @@ AdvSceneSwitcher.condition.record.state.stop="Recording stopped"
|
||||
AdvSceneSwitcher.condition.record.state.duration="Recording duration is longer than"
|
||||
AdvSceneSwitcher.condition.record.entry="{{condition}}{{duration}}"
|
||||
AdvSceneSwitcher.condition.process="Process"
|
||||
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}is running{{focused}}and is focused"
|
||||
AdvSceneSwitcher.condition.process.layout.focus="Current foreground process:{{focusProcess}}"
|
||||
AdvSceneSwitcher.condition.process.layout.path="{{checkPath}}Match binary path:{{path}}{{pathRegex}}"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}is running{{focused}}and is focused"
|
||||
AdvSceneSwitcher.condition.process.entry.focus="Current foreground process:{{focusProcess}}"
|
||||
AdvSceneSwitcher.condition.idle="Idle"
|
||||
AdvSceneSwitcher.condition.idle.entry="No keyboard or mouse inputs for{{duration}}"
|
||||
AdvSceneSwitcher.condition.pluginState="Plugin state"
|
||||
@@ -514,7 +485,6 @@ AdvSceneSwitcher.condition.macro.type.multiState="Multiple macro condition state
|
||||
AdvSceneSwitcher.condition.macro.type.actionDisabled="Macro action disabled"
|
||||
AdvSceneSwitcher.condition.macro.type.actionEnabled="Macro action enabled"
|
||||
AdvSceneSwitcher.condition.macro.type.paused="Macro is paused"
|
||||
AdvSceneSwitcher.condition.macro.type.actionsPerformed="Macro actions were executed"
|
||||
AdvSceneSwitcher.condition.macro.type.selection="{{types}}"
|
||||
AdvSceneSwitcher.condition.macro.count.type.below="Less than"
|
||||
AdvSceneSwitcher.condition.macro.count.type.above="More than"
|
||||
@@ -531,7 +501,6 @@ AdvSceneSwitcher.condition.macro.count.entry.line2="Current count:{{currentCount
|
||||
AdvSceneSwitcher.condition.macro.actionState.disabled.entry="Action{{actionIndex}}of{{macros}}is disabled"
|
||||
AdvSceneSwitcher.condition.macro.actionState.enabled.entry="Action{{actionIndex}}of{{macros}}is enabled"
|
||||
AdvSceneSwitcher.condition.macro.paused.entry="Macro{{macros}}is paused"
|
||||
AdvSceneSwitcher.condition.macro.actionsPerformed.entry="The actions of macro{{macros}}were performed"
|
||||
AdvSceneSwitcher.condition.source="Source"
|
||||
AdvSceneSwitcher.condition.source.type.active="Is active"
|
||||
AdvSceneSwitcher.condition.source.type.showing="Is showing"
|
||||
@@ -547,7 +516,6 @@ AdvSceneSwitcher.condition.source.sizeCompare.equal="Equals"
|
||||
AdvSceneSwitcher.condition.source.sizeCompare.more="Bigger than"
|
||||
AdvSceneSwitcher.condition.source.refresh="Refresh"
|
||||
AdvSceneSwitcher.condition.source.refresh.tooltip="Repopulate the source settings selection with the settings of the source which's name matches the variable value."
|
||||
AdvSceneSwitcher.condition.source.includeDefaults="Include default settings values"
|
||||
AdvSceneSwitcher.condition.source.sceneVisibilityHint="Scene specific visibility can be checked using the \"Scene item visibility\" condition"
|
||||
AdvSceneSwitcher.condition.source.getSettings="Get current settings"
|
||||
AdvSceneSwitcher.condition.source.entry.line1="{{sources}}{{conditions}}{{settingSelection}}{{refresh}}{{sizeCompareMethods}}{{size}}"
|
||||
@@ -567,7 +535,6 @@ AdvSceneSwitcher.condition.filter.type.individualSettingListSelectionMatches="Se
|
||||
AdvSceneSwitcher.condition.filter.type.individualSettingChanged="Settings value changed"
|
||||
AdvSceneSwitcher.condition.filter.refresh="Refresh"
|
||||
AdvSceneSwitcher.condition.filter.refresh.tooltip="Repopulate the filter settings selection with the settings of the filter which's name matches the variable value."
|
||||
AdvSceneSwitcher.condition.filter.includeDefaults="Include default settings values"
|
||||
AdvSceneSwitcher.condition.filter.getSettings="Get current settings"
|
||||
AdvSceneSwitcher.condition.filter.entry.line1="On{{sources}}{{filters}}{{conditions}}{{settingSelection}}{{refresh}}"
|
||||
AdvSceneSwitcher.condition.filter.entry.line2="{{settings}}"
|
||||
@@ -591,6 +558,14 @@ AdvSceneSwitcher.condition.replay.state.started="Replay buffer started"
|
||||
AdvSceneSwitcher.condition.replay.state.saved="Replay buffer saved"
|
||||
AdvSceneSwitcher.condition.replay.entry="{{state}}"
|
||||
AdvSceneSwitcher.condition.date="Date"
|
||||
AdvSceneSwitcher.condition.date.anyDay="Any day"
|
||||
AdvSceneSwitcher.condition.date.monday="Monday"
|
||||
AdvSceneSwitcher.condition.date.tuesday="Tuesday"
|
||||
AdvSceneSwitcher.condition.date.wednesday="Wednesday"
|
||||
AdvSceneSwitcher.condition.date.thursday="Thursday"
|
||||
AdvSceneSwitcher.condition.date.friday="Friday"
|
||||
AdvSceneSwitcher.condition.date.saturday="Saturday"
|
||||
AdvSceneSwitcher.condition.date.sunday="Sunday"
|
||||
AdvSceneSwitcher.condition.date.state.at="At"
|
||||
AdvSceneSwitcher.condition.date.state.after="After"
|
||||
AdvSceneSwitcher.condition.date.state.before="Before"
|
||||
@@ -601,13 +576,12 @@ AdvSceneSwitcher.condition.date.ignoreDate="If unchecked the date component will
|
||||
AdvSceneSwitcher.condition.date.ignoreTime="If unchecked the time component will be ignored"
|
||||
AdvSceneSwitcher.condition.date.showAdvancedSettings="Show advanced settings"
|
||||
AdvSceneSwitcher.condition.date.showSimpleSettings="Show simple settings"
|
||||
AdvSceneSwitcher.condition.date.layout.simple.day="On{{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}}Repeat every{{duration}}on date match"
|
||||
AdvSceneSwitcher.condition.date.layout.pattern="Current date \"{{currentDate}}\" matches pattern{{pattern}}"
|
||||
AdvSceneSwitcher.condition.date.layout.nextMatchDate="Next match at: %1"
|
||||
AdvSceneSwitcher.condition.date.layout.updateOnRepeat="{{updateOnRepeat}}On repeat update selected date to repeat date"
|
||||
AdvSceneSwitcher.condition.date.entry.simple="On{{dayOfWeek}}{{weekCondition}}{{ignoreWeekTime}}{{weekTime}}"
|
||||
AdvSceneSwitcher.condition.date.entry.advanced="{{condition}}{{ignoreDate}}{{date}}{{ignoreTime}}{{time}}{{separator}}{{date2}}{{time2}}"
|
||||
AdvSceneSwitcher.condition.date.entry.repeat="{{repeat}}Repeat every{{duration}}on date match"
|
||||
AdvSceneSwitcher.condition.date.entry.pattern="Current date \"{{currentDate}}\" matches pattern{{pattern}}"
|
||||
AdvSceneSwitcher.condition.date.entry.nextMatchDate="Next match at: %1"
|
||||
AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}}On repeat update selected date to repeat date"
|
||||
AdvSceneSwitcher.condition.sceneTransform="Scene item transform"
|
||||
AdvSceneSwitcher.condition.sceneTransform.getTransform="Get transform"
|
||||
AdvSceneSwitcher.condition.sceneTransform.getCurrentValue="Get current value"
|
||||
@@ -673,34 +647,6 @@ AdvSceneSwitcher.condition.websocket.type.event="Scene Switcher Event"
|
||||
AdvSceneSwitcher.condition.websocket.useRegex="Use regular expressions"
|
||||
AdvSceneSwitcher.condition.websocket.entry.request="{{type}}was received:"
|
||||
AdvSceneSwitcher.condition.websocket.entry.event="{{type}}was received from{{connection}}:"
|
||||
AdvSceneSwitcher.condition.http="HTTP"
|
||||
AdvSceneSwitcher.condition.http.layout="Receive{{method}}request on{{server}}"
|
||||
AdvSceneSwitcher.condition.http.layout.path="Path:{{path}}{{regex}}"
|
||||
AdvSceneSwitcher.condition.http.layout.body="Body:{{body}}{{regex}}"
|
||||
AdvSceneSwitcher.condition.http.method.any="any"
|
||||
AdvSceneSwitcher.condition.http.method.get="GET"
|
||||
AdvSceneSwitcher.condition.http.method.post="POST"
|
||||
AdvSceneSwitcher.condition.http.method.put="PUT"
|
||||
AdvSceneSwitcher.condition.http.method.patch="PATCH"
|
||||
AdvSceneSwitcher.condition.http.method.delete="DELETE"
|
||||
AdvSceneSwitcher.httpServer.select="Select HTTP server"
|
||||
AdvSceneSwitcher.httpServer.add="Add HTTP server"
|
||||
AdvSceneSwitcher.httpServer.configure="Configure HTTP server"
|
||||
AdvSceneSwitcher.httpServer.invalid="Invalid HTTP server"
|
||||
AdvSceneSwitcher.httpServer.name="Name:"
|
||||
AdvSceneSwitcher.httpServer.port="Port:"
|
||||
AdvSceneSwitcher.httpServer.startOnLoad="Start on load"
|
||||
AdvSceneSwitcher.httpServer.status.listening="Listening"
|
||||
AdvSceneSwitcher.httpServer.status.stopped="Stopped"
|
||||
AdvSceneSwitcher.httpServerTab.title="HTTP Servers"
|
||||
AdvSceneSwitcher.httpServerTab.help="No HTTP servers configured.\nAdd one to receive incoming HTTP requests in conditions."
|
||||
AdvSceneSwitcher.httpServerTab.addButton.tooltip="Add HTTP server"
|
||||
AdvSceneSwitcher.httpServerTab.removeButton.tooltip="Remove HTTP server"
|
||||
AdvSceneSwitcher.httpServerTab.name.header="Name"
|
||||
AdvSceneSwitcher.httpServerTab.port.header="Port"
|
||||
AdvSceneSwitcher.httpServerTab.status.header="Status"
|
||||
AdvSceneSwitcher.httpServerTab.removeSingle.text="Are you sure you want to remove \"%1\"?"
|
||||
AdvSceneSwitcher.httpServerTab.removeMultiple.text="Are you sure you want to remove %1 HTTP servers?"
|
||||
AdvSceneSwitcher.condition.temporaryVariable="Macro property"
|
||||
AdvSceneSwitcher.condition.variable="Variable"
|
||||
AdvSceneSwitcher.condition.variable.type.compare="equals"
|
||||
@@ -749,7 +695,6 @@ AdvSceneSwitcher.condition.twitch.type.event.channel.raid.outbound="Raided someo
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.raid.inbound="Raid to your channel occured"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.shoutout.outbound="Shoutout to someone's channel given"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.shoutout.inbound="Shoutout to your channel received"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.commercial.start="Commercial break started"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.poll.start="Poll started"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.poll.progress="Poll votes changed (progress)"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.poll.end="Poll ended"
|
||||
@@ -865,21 +810,12 @@ AdvSceneSwitcher.condition.script="Script"
|
||||
# Macro Actions
|
||||
AdvSceneSwitcher.action.unknown="Unknown action"
|
||||
AdvSceneSwitcher.action.scene="Switch scene"
|
||||
AdvSceneSwitcher.action.scene.action.fixed="Scene with name"
|
||||
AdvSceneSwitcher.action.scene.action.sceneListNext="Next scene in scene list"
|
||||
AdvSceneSwitcher.action.scene.action.sceneListPrevious="Previous scene in scene list"
|
||||
AdvSceneSwitcher.action.scene.action.sceneListIndex="Scene in scene list at position"
|
||||
AdvSceneSwitcher.action.scene.type.program="Program"
|
||||
AdvSceneSwitcher.action.scene.type.preview="Preview"
|
||||
AdvSceneSwitcher.action.scene.layout.action.fixed="Switch{{sceneTypes}}to{{actions}}{{scenes}}"
|
||||
AdvSceneSwitcher.action.scene.layout.action.list="Switch{{sceneTypes}}to{{actions}}on{{canvas}}"
|
||||
AdvSceneSwitcher.action.scene.layout.action.list.noCanvasSelection="Switch{{sceneTypes}}to{{actions}}"
|
||||
AdvSceneSwitcher.action.scene.layout.action.listIndex="Switch{{sceneTypes}}to{{actions}}{{index}}on{{canvas}}{{sceneNameAtIndex}}"
|
||||
AdvSceneSwitcher.action.scene.layout.action.listIndex.noCanvasSelection="Switch{{sceneTypes}}to{{actions}}{{index}}{{sceneNameAtIndex}}"
|
||||
AdvSceneSwitcher.action.scene.layout.transition="Use transition{{transitions}}"
|
||||
AdvSceneSwitcher.action.scene.layout.transitionWithDuration="Use transition{{transitions}}with a duration of{{duration}}seconds"
|
||||
AdvSceneSwitcher.action.scene.entry="Switch{{sceneTypes}}scene to{{scenes}}using{{transitions}}with a duration of{{duration}}seconds"
|
||||
AdvSceneSwitcher.action.scene.entry.noDuration="Switch{{sceneTypes}}scene to{{scenes}}using{{transitions}}"
|
||||
AdvSceneSwitcher.action.scene.entry.preview="Switch{{sceneTypes}}scene to{{scenes}}"
|
||||
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Wait until transition to target scene is complete"
|
||||
AdvSceneSwitcher.action.scene.canvasNotSupported="Not supported by the currently selected canvas \"%1\""
|
||||
AdvSceneSwitcher.action.wait="Wait"
|
||||
AdvSceneSwitcher.action.wait.type.fixed="fixed"
|
||||
AdvSceneSwitcher.action.wait.type.random="random"
|
||||
@@ -888,7 +824,6 @@ AdvSceneSwitcher.action.wait.entry.random="Wait for{{waitType}}duration from{{du
|
||||
AdvSceneSwitcher.action.audio="Audio"
|
||||
AdvSceneSwitcher.action.audio.type.mute="Mute"
|
||||
AdvSceneSwitcher.action.audio.type.unmute="Unmute"
|
||||
AdvSceneSwitcher.action.audio.type.toggleMute="Toggle mute"
|
||||
AdvSceneSwitcher.action.audio.type.sourceVolume="Set source volume"
|
||||
AdvSceneSwitcher.action.audio.type.masterVolume="Set master volume"
|
||||
AdvSceneSwitcher.action.audio.type.syncOffset="Set sync offset"
|
||||
@@ -904,15 +839,6 @@ AdvSceneSwitcher.action.audio.fade.rate="{{fade}}Fade{{fadeTypes}}{{rate}}per se
|
||||
AdvSceneSwitcher.action.audio.fade.wait="Wait for fade to complete."
|
||||
AdvSceneSwitcher.action.audio.fade.abort="Abort already active fade."
|
||||
AdvSceneSwitcher.action.audio.entry="{{actions}}{{audioSources}}{{volume}}{{volumeDB}}{{percentDBToggle}}{{syncOffset}}{{monitorTypes}}{{track}}"
|
||||
AdvSceneSwitcher.action.playAudio="Play Audio File"
|
||||
AdvSceneSwitcher.action.playAudio.file.browse="Browse for audio file"
|
||||
AdvSceneSwitcher.action.playAudio.layout.volume="Volume{{volumeDB}}"
|
||||
AdvSceneSwitcher.action.playAudio.layout.monitor="Monitoring{{monitorTypes}}"
|
||||
AdvSceneSwitcher.action.playAudio.wait="Wait for playback to complete"
|
||||
AdvSceneSwitcher.action.playAudio.monitorUnavailable="Audio monitoring not available"
|
||||
AdvSceneSwitcher.action.playAudio.tracks="Tracks"
|
||||
AdvSceneSwitcher.action.playAudio.layout.startOffset="{{useStartOffset}}Start at{{startOffset}}"
|
||||
AdvSceneSwitcher.action.playAudio.layout.playbackDuration="{{useDuration}}Play for{{playbackDuration}}(0 = until end)"
|
||||
AdvSceneSwitcher.action.recording="Recording"
|
||||
AdvSceneSwitcher.action.recording.type.stop="Stop recording"
|
||||
AdvSceneSwitcher.action.recording.type.start="Start recording"
|
||||
@@ -921,10 +847,9 @@ AdvSceneSwitcher.action.recording.type.unpause="Unpause recording"
|
||||
AdvSceneSwitcher.action.recording.type.split="Split recording file"
|
||||
AdvSceneSwitcher.action.recording.type.changeOutputFolder="Change output folder"
|
||||
AdvSceneSwitcher.action.recording.type.changeOutputFileFormat="Change filename formatting"
|
||||
AdvSceneSwitcher.action.recording.type.addChapter="Add chapter"
|
||||
AdvSceneSwitcher.action.recording.pause.hint="Note that depending on your recording settings you might not be able to pause recording"
|
||||
AdvSceneSwitcher.action.recording.split.hint="Make sure to enable automatic file splitting in the OBS settings first!"
|
||||
AdvSceneSwitcher.action.recording.entry="{{actions}}{{recordFolder}}{{recordFileFormat}}{{chapterName}}{{pauseHint}}{{splitHint}}"
|
||||
AdvSceneSwitcher.action.recording.entry="{{actions}}{{recordFolder}}{{recordFileFormat}}{{pauseHint}}{{splitHint}}"
|
||||
AdvSceneSwitcher.action.replay="Replay buffer"
|
||||
AdvSceneSwitcher.action.replay.saveWarn="Warning: Saving too frequently might result in the replay buffer not actually being saved!"
|
||||
AdvSceneSwitcher.action.replay.durationWarn="Warning: Changing the maximum replay time will only apply the next time the replay buffer is started!"
|
||||
@@ -941,8 +866,7 @@ AdvSceneSwitcher.action.streaming.type.server="Set server URL"
|
||||
AdvSceneSwitcher.action.streaming.type.streamKey="Set stream key"
|
||||
AdvSceneSwitcher.action.streaming.type.username="Set username"
|
||||
AdvSceneSwitcher.action.streaming.type.password="Set password"
|
||||
AdvSceneSwitcher.action.streaming.getCurrentValue="Get current value"
|
||||
AdvSceneSwitcher.action.streaming.layout="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}{{getCurrentValue}}"
|
||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
|
||||
AdvSceneSwitcher.action.run="Run"
|
||||
AdvSceneSwitcher.action.run.wait.entry="{{wait}}Wait for process exit or at most {{timeout}}{{waitHelp}}"
|
||||
AdvSceneSwitcher.action.run.wait.help.tooltip="Note that macro properties won't work if you leave this unticked, as the process spawns detached from the rest of logic and there's no control over it."
|
||||
@@ -952,9 +876,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.hide="Hide"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.toggle="Toggle"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.source="Source"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Any"
|
||||
AdvSceneSwitcher.action.sceneVisibility.layout="On{{scenes}}{{actions}}{{sources}}"
|
||||
AdvSceneSwitcher.action.sceneVisibility.layout.transition="{{updateTransition}}Set transition to{{transitions}}"
|
||||
AdvSceneSwitcher.action.sceneVisibility.layout.duration="{{updateDuration}}Set transition duration to{{duration}}seconds"
|
||||
AdvSceneSwitcher.action.sceneVisibility.entry="On{{scenes}}{{actions}}{{sources}}"
|
||||
AdvSceneSwitcher.action.filter="Filter"
|
||||
AdvSceneSwitcher.action.filter.type.enable="Enable"
|
||||
AdvSceneSwitcher.action.filter.type.disable="Disable"
|
||||
@@ -982,11 +904,6 @@ AdvSceneSwitcher.action.source.type.deinterlaceOrder="Set deinterlace field orde
|
||||
AdvSceneSwitcher.action.source.type.openInteractionDialog="Open interaction dialog"
|
||||
AdvSceneSwitcher.action.source.type.openFilterDialog="Open filter dialog"
|
||||
AdvSceneSwitcher.action.source.type.openPropertiesDialog="Open properties dialog"
|
||||
AdvSceneSwitcher.action.source.type.closeInteractionDialog="Close interaction dialog"
|
||||
AdvSceneSwitcher.action.source.type.closeFilterDialog="Close filter dialog"
|
||||
AdvSceneSwitcher.action.source.type.closePropertiesDialog="Close properties dialog"
|
||||
AdvSceneSwitcher.action.source.type.getSetting="Get setting value"
|
||||
AdvSceneSwitcher.action.source.type.getSettings="Get settings JSON"
|
||||
AdvSceneSwitcher.action.source.entry="{{actions}}{{sources}}{{settingsButtons}}{{deinterlaceMode}}{{deinterlaceOrder}}{{refresh}}"
|
||||
AdvSceneSwitcher.action.source.entry.settings="{{settings}}{{settingsInputMethod}}{{settingValue}}{{tempVar}}"
|
||||
AdvSceneSwitcher.action.source.warning="Warning: Enabling and disabling sources globally cannot be controlled by the OBS UI\nYou might be looking for \"Scene item visibility\""
|
||||
@@ -1008,50 +925,6 @@ AdvSceneSwitcher.action.source.inputMethod.individualTempvar="Set to macro prope
|
||||
AdvSceneSwitcher.action.source.inputMethod.json="Set setting JSON string"
|
||||
AdvSceneSwitcher.action.source.refresh="Refresh"
|
||||
AdvSceneSwitcher.action.source.refresh.tooltip="Repopulate the source settings selection with the settings of the source which's name matches the variable value."
|
||||
AdvSceneSwitcher.action.source.dialog.accept="Accept changes"
|
||||
AdvSceneSwitcher.action.sourceInteraction="Source Interaction"
|
||||
AdvSceneSwitcher.action.sourceInteraction.source="Source"
|
||||
AdvSceneSwitcher.action.sourceInteraction.noSelection="Select a step to edit it"
|
||||
AdvSceneSwitcher.action.sourceInteraction.record="Record interaction ..."
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.listEntry.mouseMove="Mouse move (%1, %2)"
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.listEntry.mouseUp="up"
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.listEntry.mouseDown="down"
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.listEntry.mouseClick="Mouse %1 %2 (%3, %4)"
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.listEntry.mouseClickCount=" x%1"
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.listEntry.mouseWheel="Mouse wheel (%1, %2) dx=%3 dy=%4"
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.listEntry.keyUp="up"
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.listEntry.keyDown="down"
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.listEntry.keyPress="Key %1"
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.listEntry.keyPressWithText="Key %1 '%2'"
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.listEntry.typeText="Type \"%1\""
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.listEntry.wait="Wait %1 ms"
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.edit.type="Type"
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.edit.mouseMove="Mouse move"
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.edit.mouseClick="Mouse click"
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.edit.mouseWheel="Mouse wheel"
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.edit.keyPress="Key press"
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.edit.typeText="Type text"
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.edit.wait="Wait"
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.edit.x="X"
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.edit.y="Y"
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.edit.button="Button"
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.edit.mouseUp="Mouse up"
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.edit.clickCount="Click count"
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.edit.wheelDx="Delta X"
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.edit.wheelDy="Delta Y"
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.edit.vkey="Virtual key"
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.edit.keyUp="Key up"
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.edit.text="Text"
|
||||
AdvSceneSwitcher.action.sourceInteraction.step.edit.waitMs="Duration (ms)"
|
||||
AdvSceneSwitcher.action.sourceInteraction.button.left="Left"
|
||||
AdvSceneSwitcher.action.sourceInteraction.button.middle="Middle"
|
||||
AdvSceneSwitcher.action.sourceInteraction.button.right="Right"
|
||||
AdvSceneSwitcher.action.sourceInteraction.record.title="Record Source Interactions"
|
||||
AdvSceneSwitcher.action.sourceInteraction.record.start="Start recording"
|
||||
AdvSceneSwitcher.action.sourceInteraction.record.stop="Stop recording"
|
||||
AdvSceneSwitcher.action.sourceInteraction.record.accept="Accept"
|
||||
AdvSceneSwitcher.action.sourceInteraction.record.placeholder="Start recording and interact with the source to capture steps"
|
||||
AdvSceneSwitcher.action.sourceInteraction.record.invalidSource="No valid source is selected.\nPlease select a source that supports interaction before recording."
|
||||
AdvSceneSwitcher.action.media="Media"
|
||||
AdvSceneSwitcher.action.media.type.play="Play"
|
||||
AdvSceneSwitcher.action.media.type.pause="Pause"
|
||||
@@ -1071,12 +944,12 @@ AdvSceneSwitcher.action.macro.type.pause="Pause"
|
||||
AdvSceneSwitcher.action.macro.type.unpause="Unpause"
|
||||
AdvSceneSwitcher.action.macro.type.togglePause="Toggle pause"
|
||||
AdvSceneSwitcher.action.macro.type.resetCounter="Reset counter"
|
||||
AdvSceneSwitcher.action.macro.type.runActions="Run macro actions"
|
||||
AdvSceneSwitcher.action.macro.type.run="Run macro"
|
||||
AdvSceneSwitcher.action.macro.type.run.conditions.ignore="Do not consider condition state"
|
||||
AdvSceneSwitcher.action.macro.type.run.conditions.true="Only if conditions evaluate to true"
|
||||
AdvSceneSwitcher.action.macro.type.run.conditions.false="Only if conditions evaluate to false"
|
||||
AdvSceneSwitcher.action.macro.type.run.updateConditionMatchState="Check conditions now, even if macro is paused"
|
||||
AdvSceneSwitcher.action.macro.type.run.updateConditionMatchState.help="The plugin operates in phases:\n * The phase evaluating the macro conditions\n * The phase running macro actions\nMacros executed before this particular action might have side effects on the condition state of macros.\nAdditionally, paused macros are assumed to not match their conditions.\nCheck this option to force a fresh condition evaluation before running this action, regardless of whether the macro is paused."
|
||||
AdvSceneSwitcher.action.macro.type.run.updateConditionMatchState="Reevaluate the condition state before executing this action"
|
||||
AdvSceneSwitcher.action.macro.type.run.updateConditionMatchState.help="The plugin operates in phases:\n * The phase evaluating the macro conditions\n * The phase running macro actions\nMacros executed before this particular action might have side effects on the condition state of macros.\nCheck this option if you want those side effects to be taken into account when evaluating the condition state."
|
||||
AdvSceneSwitcher.action.macro.type.run.actionType.regular="actions"
|
||||
AdvSceneSwitcher.action.macro.type.run.actionType.else="else-actions"
|
||||
AdvSceneSwitcher.action.macro.type.run.skipWhenPaused="Skip execution when macro is paused"
|
||||
@@ -1086,22 +959,9 @@ AdvSceneSwitcher.action.macro.type.stop="Stop actions"
|
||||
AdvSceneSwitcher.action.macro.type.disableAction="Disable action"
|
||||
AdvSceneSwitcher.action.macro.type.enableAction="Enable action"
|
||||
AdvSceneSwitcher.action.macro.type.toggleAction="Toggle action"
|
||||
AdvSceneSwitcher.action.macro.type.getInfo="Get macro info"
|
||||
AdvSceneSwitcher.action.macro.type.runMacro="Run macro"
|
||||
AdvSceneSwitcher.action.macro.type.runMacro.noConditionsWarning="Warning: The selected macro has no conditions!"
|
||||
AdvSceneSwitcher.action.macro.type.runMacro.help="Unlike \"Run macro actions\", this option will immediately re-evaluate the conditions of the selected macro and then run either its actions or else-actions depending on the result."
|
||||
AdvSceneSwitcher.action.macro.type.nestedMacro="Nested macro"
|
||||
AdvSceneSwitcher.action.macro.actionSelectionType.index="at index"
|
||||
AdvSceneSwitcher.action.macro.actionSelectionType.label="with label"
|
||||
AdvSceneSwitcher.action.macro.actionSelectionType.id="of action type"
|
||||
AdvSceneSwitcher.action.macro.type.nestedMacro.conditionHelp="This section allows you to define macro conditions.\n\nClick the plus button below to add a new condition."
|
||||
AdvSceneSwitcher.action.macro.type.nestedMacro.actionHelp="This section allows you to define macro actions.\nThe actions in this section will be performed when the conditions are met.\n\nClick the plus button below to add a new action."
|
||||
AdvSceneSwitcher.action.macro.type.nestedMacro.elseActionHelp="This section allows you to define macro actions.\nThe actions in this section will be performed when the conditions are *not* met.\n\nClick the plus button below to add a new action."
|
||||
AdvSceneSwitcher.action.macro.layout.run="{{actions}}{{actionSections}}of{{macros}}"
|
||||
AdvSceneSwitcher.action.macro.layout.run.condition="{{conditionBehaviors}}of{{conditionMacros}}"
|
||||
AdvSceneSwitcher.action.macro.layout.actionState="{{actions}}{{actionSelectionType}}{{actionIndex}}{{label}}{{regex}}{{actionTypes}}in{{actionSections}}section of{{macros}}"
|
||||
AdvSceneSwitcher.action.macro.layout.runMacro="{{actions}}{{runMacroHelp}}{{macros}}"
|
||||
AdvSceneSwitcher.action.macro.layout.other="{{actions}}{{macros}}"
|
||||
AdvSceneSwitcher.action.macro.entry.run="{{actions}}{{actionTypes}}of{{macros}}"
|
||||
AdvSceneSwitcher.action.macro.entry.run.condition="{{conditionBehaviors}}of{{conditionMacros}}"
|
||||
AdvSceneSwitcher.action.macro.entry.other="{{actions}}{{actionIndex}}{{macros}}"
|
||||
AdvSceneSwitcher.action.pluginState="Plugin state"
|
||||
AdvSceneSwitcher.action.pluginState.type.stop="Stop the Advanced Scene Switcher plugin"
|
||||
AdvSceneSwitcher.action.pluginState.type.noMatch="Change the no-match behaviour:"
|
||||
@@ -1109,11 +969,7 @@ AdvSceneSwitcher.action.pluginState.type.import="Import settings from"
|
||||
AdvSceneSwitcher.action.pluginState.importWarning="Note: Action will be ignored while settings window is opened."
|
||||
AdvSceneSwitcher.action.pluginState.type.terminate="Shut down OBS"
|
||||
AdvSceneSwitcher.action.pluginState.terminateConfirm="OBS will be shut down automatically in 10 seconds!\nDo you want to continue shutting down OBS?"
|
||||
AdvSceneSwitcher.action.pluginState.type.enableMacroHighlighting="Enable macro highlighting"
|
||||
AdvSceneSwitcher.action.pluginState.type.disableMacroHighlighting="Disable macro highlighting"
|
||||
AdvSceneSwitcher.action.pluginState.type.toggleMacroHighlighting="Toggle macro highlighting"
|
||||
AdvSceneSwitcher.action.pluginState.confirmShutdown="Ask for shutdown confirmation"
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}"
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
|
||||
AdvSceneSwitcher.action.virtualCamera="Virtual camera"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.stop="Stop virtual camera"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.start="Start virtual camera"
|
||||
@@ -1173,16 +1029,13 @@ AdvSceneSwitcher.action.studioMode.type.enable="Enable studio mode"
|
||||
AdvSceneSwitcher.action.studioMode.type.disable="Disable studio mode"
|
||||
AdvSceneSwitcher.action.studioMode.entry="{{actions}}{{scenes}}"
|
||||
AdvSceneSwitcher.action.transition="Transition"
|
||||
AdvSceneSwitcher.action.transition.type.scene="Modify scene transition"
|
||||
AdvSceneSwitcher.action.transition.type.sceneOverride="Modify scene transition override"
|
||||
AdvSceneSwitcher.action.transition.type.sourceShow="Modify source show transition"
|
||||
AdvSceneSwitcher.action.transition.type.sourceHide="Modify source hide transition"
|
||||
AdvSceneSwitcher.action.transition.type.tbar="Modify T-Bar position"
|
||||
AdvSceneSwitcher.action.transition.type.releaseTbar="Release T-Bar"
|
||||
AdvSceneSwitcher.action.transition.layout.type="{{type}}{{scenes}}{{sources}}"
|
||||
AdvSceneSwitcher.action.transition.layout.transition="{{setTransition}}Set transition type to{{transitions}}"
|
||||
AdvSceneSwitcher.action.transition.layout.duration="{{setDuration}}Set transition duration to{{duration}}seconds"
|
||||
AdvSceneSwitcher.action.transition.layout.tbar="Set T-Bar position to{{tbarPosition}}"
|
||||
AdvSceneSwitcher.action.transition.type.scene="scene transition"
|
||||
AdvSceneSwitcher.action.transition.type.sceneOverride="scene transition override"
|
||||
AdvSceneSwitcher.action.transition.type.sourceShow="source show transition"
|
||||
AdvSceneSwitcher.action.transition.type.sourceHide="source hide transition"
|
||||
AdvSceneSwitcher.action.transition.entry.line1="Modify{{type}}{{scenes}}{{sources}}"
|
||||
AdvSceneSwitcher.action.transition.entry.line2="{{setTransition}}Set transition type to{{transitions}}"
|
||||
AdvSceneSwitcher.action.transition.entry.line3="{{setDuration}}Set transition duration to{{duration}}seconds"
|
||||
AdvSceneSwitcher.action.timer="Timer"
|
||||
AdvSceneSwitcher.action.timer.type.pause="Pause"
|
||||
AdvSceneSwitcher.action.timer.type.continue="Continue"
|
||||
@@ -1227,7 +1080,7 @@ AdvSceneSwitcher.action.websocket.api.genericWebsocket="Generic websocket messag
|
||||
AdvSceneSwitcher.action.websocket.type.request="Request"
|
||||
AdvSceneSwitcher.action.websocket.type.event="Event"
|
||||
AdvSceneSwitcher.action.websocket.settingsConflictGeneric="Possible settings conflict: Generic websocket message selection with connection which follows the OBS protocol!"
|
||||
AdvSceneSwitcher.action.websocket.settingsConflictOBS="Possible settings conflict: Connection selected which only supports generic websocket messages while message type requires OBS protocol!"
|
||||
AdvSceneSwitcher.action.websocket.settingsConflictOBS="Possible settings conflict: Connection selected which only supports generic websockte messages while message type requires OBS protocol!"
|
||||
AdvSceneSwitcher.action.websocket.entry.sceneSwitcher.request="Send{{api}}of type{{type}}via{{connection}}"
|
||||
AdvSceneSwitcher.action.websocket.entry.sceneSwitcher.event="Send{{api}}of type{{type}}to connected clients"
|
||||
AdvSceneSwitcher.action.websocket.entry.generic="Send{{api}}via{{connection}}"
|
||||
@@ -1256,7 +1109,6 @@ AdvSceneSwitcher.action.http.entry.line2="Timeout:{{timeout}}seconds"
|
||||
AdvSceneSwitcher.action.variable="Variable"
|
||||
AdvSceneSwitcher.action.variable.type.set="Set to value"
|
||||
AdvSceneSwitcher.action.variable.type.append="Append"
|
||||
AdvSceneSwitcher.action.variable.type.copy="Copy variable"
|
||||
AdvSceneSwitcher.action.variable.type.appendVar="Append variable"
|
||||
AdvSceneSwitcher.action.variable.type.increment="Increment"
|
||||
AdvSceneSwitcher.action.variable.type.decrement="Decrement"
|
||||
@@ -1283,8 +1135,6 @@ AdvSceneSwitcher.action.variable.type.swapValues="Swap variable values"
|
||||
AdvSceneSwitcher.action.variable.type.trim="Trim whitespace"
|
||||
AdvSceneSwitcher.action.variable.type.changeCase="Change case"
|
||||
AdvSceneSwitcher.action.variable.type.randomNumber="Generate random number"
|
||||
AdvSceneSwitcher.action.variable.type.randomListValue="Select random value"
|
||||
AdvSceneSwitcher.action.variable.type.allowRepeat="Allow repeat values"
|
||||
AdvSceneSwitcher.action.variable.case.type.lowerCase="lowercase"
|
||||
AdvSceneSwitcher.action.variable.case.type.upperCase="UPPERCASE"
|
||||
AdvSceneSwitcher.action.variable.case.type.capitalized="Capitalized"
|
||||
@@ -1307,8 +1157,8 @@ AdvSceneSwitcher.action.variable.currentSegmentValue="Current value:"
|
||||
AdvSceneSwitcher.action.variable.layout.other="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}{{envVariableName}}{{scenes}}{{tempVars}}{{tempVarsHelp}}{{sceneItemIndex}}{{direction}}{{stringLength}}{{paddingCharSelection}}{{caseType}}{{jsonQuery}}{{jsonQueryHelp}}{{jsonIndex}}"
|
||||
AdvSceneSwitcher.action.variable.layout.pad="{{actions}}of{{variables}}to length{{stringLength}}by adding{{paddingCharSelection}}to the{{direction}}"
|
||||
AdvSceneSwitcher.action.variable.layout.truncate="{{actions}}of{{variables}}to length{{stringLength}}by removing characters from the{{direction}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringIndex="Substring start:{{subStringStart}}Substring size:{{subStringSize}}{{subStringRegex}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringRegex="Assign value of{{regexMatchIdx}}match using regular expression:{{subStringRegex}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringIndex="Substring start:{{subStringStart}}Substring size:{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringRegex="Assign value of{{regexMatchIdx}}match using regular expression:"
|
||||
AdvSceneSwitcher.action.variable.layout.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
|
||||
AdvSceneSwitcher.action.variable.layout.userInput.customPrompt="{{useCustomPrompt}}Use custom prompt{{inputPrompt}}"
|
||||
AdvSceneSwitcher.action.variable.layout.userInput.placeholder="{{useInputPlaceholder}}Fill with placeholder{{inputPlaceholder}}"
|
||||
@@ -1339,55 +1189,22 @@ AdvSceneSwitcher.action.sceneLock.entry="On{{scenes}}{{actions}}{{sources}}"
|
||||
AdvSceneSwitcher.action.twitch="Twitch"
|
||||
AdvSceneSwitcher.action.twitch.type.channel.info.title.set="Set stream title"
|
||||
AdvSceneSwitcher.action.twitch.type.channel.info.category.set="Set stream category"
|
||||
AdvSceneSwitcher.action.twitch.type.channel.info.tags.set="Set stream tags"
|
||||
AdvSceneSwitcher.action.twitch.type.channel.info.language.set="Set stream language"
|
||||
AdvSceneSwitcher.action.twitch.type.raid.start="Start raid"
|
||||
AdvSceneSwitcher.action.twitch.type.raid.end="Cancel raid"
|
||||
AdvSceneSwitcher.action.twitch.type.shoutout.send="Send shoutout"
|
||||
AdvSceneSwitcher.action.twitch.type.shieldMode.start="Enable shield mode"
|
||||
AdvSceneSwitcher.action.twitch.type.shieldMode.end="Disable shield mode"
|
||||
AdvSceneSwitcher.action.twitch.type.commercial.start="Start commercial"
|
||||
AdvSceneSwitcher.action.twitch.type.commercial.snooze="Snooze next ad"
|
||||
AdvSceneSwitcher.action.twitch.type.marker.create="Create stream marker"
|
||||
AdvSceneSwitcher.action.twitch.type.clip.create="Create stream clip"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.announcement.send="Send chat announcement"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.enable="Enable chat's emote-only mode"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.disable="Disable chat's emote-only mode"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.followerOnly.enable="Enable chat's follower-only mode"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.followerOnly.disable="Disable chat's follower-only mode"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.subscriberOnly.enable="Enable chat's subscriber-only mode"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.subscriberOnly.disable="Disable chat's subscriber-only mode"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.slowMode.enable="Enable chat's slow mode"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.slowMode.disable="Disable chat's slow mode"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.nonModeratorDelay.enable="Enable chat's non-moderator message delay"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.nonModeratorDelay.disable="Disable chat's non-moderator message delay"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.uniqueMode.enable="Enable chat's unique message mode"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.uniqueMode.disable="Disable chat's unique message mode"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.sendMessage="Send chat message"
|
||||
AdvSceneSwitcher.action.twitch.type.user.getInfo="Get user information"
|
||||
AdvSceneSwitcher.action.twitch.type.user.ban="Ban user"
|
||||
AdvSceneSwitcher.action.twitch.type.user.unban="Unban user"
|
||||
AdvSceneSwitcher.action.twitch.type.user.block="Block user"
|
||||
AdvSceneSwitcher.action.twitch.type.user.unblock="Unblock user"
|
||||
AdvSceneSwitcher.action.twitch.type.user.moderator.add="Add user as moderator"
|
||||
AdvSceneSwitcher.action.twitch.type.user.moderator.delete="Remove user as moderator"
|
||||
AdvSceneSwitcher.action.twitch.type.user.vip.add="Add user as VIP"
|
||||
AdvSceneSwitcher.action.twitch.type.user.vip.delete="Remove user as VIP"
|
||||
AdvSceneSwitcher.action.twitch.type.reward.getInfo="Get channel points reward information"
|
||||
AdvSceneSwitcher.action.twitch.type.channel.getInfo="Get channel information"
|
||||
AdvSceneSwitcher.action.twitch.reward.toggleControl="Toggle reward name / variable selection control"
|
||||
AdvSceneSwitcher.action.twitch.categorySelectionDisabled="Cannot select category without selecting a Twitch account first!"
|
||||
AdvSceneSwitcher.action.twitch.layout.default="On{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{nonModDelayDuration}}{{channel}}{{pointsReward}}"
|
||||
AdvSceneSwitcher.action.twitch.layout.chat="Using account{{account}}{{actions}}on{{channel}}"
|
||||
AdvSceneSwitcher.action.twitch.layout.channel.getInfo="Using account{{account}}{{actions}}of{{channel}}"
|
||||
AdvSceneSwitcher.action.twitch.layout.user.getInfo.row1="Using account{{account}}{{actions}}"
|
||||
AdvSceneSwitcher.action.twitch.layout.user.getInfo.row2="for{{userInfoQueryType}}{{userLogin}}{{userId}}"
|
||||
AdvSceneSwitcher.action.twitch.layout.user.moderation.row1="Using account{{account}}{{actions}}"
|
||||
AdvSceneSwitcher.action.twitch.layout.user.moderation.row2="on channel{{channel}}for{{userInfoQueryType}}{{userLogin}}{{userId}}"
|
||||
AdvSceneSwitcher.action.twitch.layout.user.ban.row1="Using account{{account}}{{actions}}timeout{{duration}}"
|
||||
AdvSceneSwitcher.action.twitch.layout.user.ban.row2="on channel{{channel}}for{{userInfoQueryType}}{{userLogin}}{{userId}}reason{{banReason}}"
|
||||
AdvSceneSwitcher.action.twitch.layout.reward.getInfo.row1="Using account{{account}}{{actions}}for channel{{channel}}"
|
||||
AdvSceneSwitcher.action.twitch.layout.reward.getInfo.row2="{{pointsReward}}{{rewardVariable}}{{toggleRewardSelection}}"
|
||||
AdvSceneSwitcher.action.twitch.entry.default="On{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}{{pointsReward}}"
|
||||
AdvSceneSwitcher.action.twitch.entry.chat="Using account{{account}}{{actions}}on{{channel}}"
|
||||
AdvSceneSwitcher.action.twitch.entry.user.getInfo="Using account{{account}}{{actions}}for{{userInfoQueryType}}{{userLogin}}{{userId}}"
|
||||
AdvSceneSwitcher.action.twitch.entry.reward.getInfo="Using account{{account}}{{actions}}for channel{{channel}}{{pointsReward}}{{rewardVariable}}{{toggleRewardSelection}}"
|
||||
AdvSceneSwitcher.action.twitch.title.title="Enter title"
|
||||
AdvSceneSwitcher.action.twitch.marker.description="Describe marker"
|
||||
AdvSceneSwitcher.action.twitch.clip.hasDelay="Add a slight delay before capturing the clip"
|
||||
@@ -1399,60 +1216,6 @@ AdvSceneSwitcher.action.twitch.announcement.orange="Orange"
|
||||
AdvSceneSwitcher.action.twitch.announcement.purple="Purple"
|
||||
AdvSceneSwitcher.action.twitch.user.getInfo.queryType.id="User Id"
|
||||
AdvSceneSwitcher.action.twitch.user.getInfo.queryType.login="User login"
|
||||
AdvSceneSwitcher.action.twitch.tags.add="Add Channel Tag"
|
||||
AdvSceneSwitcher.action.twitch.tags.getCurrent="Get current channel tags"
|
||||
AdvSceneSwitcher.action.twitch.tags.invalid="Invalid Tag"
|
||||
AdvSceneSwitcher.action.twitch.tags.invalid.info="Tags must be 1–%1 characters long, contain only letters or numbers, and have no spaces or special characters."
|
||||
AdvSceneSwitcher.action.twitch.tags.duplicate="Duplicate Tag"
|
||||
AdvSceneSwitcher.action.twitch.tags.duplicate.info="This tag is already in the list."
|
||||
AdvSceneSwitcher.action.twitch.tags.limit="Tag Limit Reached"
|
||||
AdvSceneSwitcher.action.twitch.tags.limit.info="You can only have up to %1 tags."
|
||||
AdvSceneSwitcher.action.twitch.type.channel.info.contentClassification.set="Set content classification labels"
|
||||
AdvSceneSwitcher.action.twitch.type.channel.info.brandedContent.enable="Enable branded content"
|
||||
AdvSceneSwitcher.action.twitch.type.channel.info.brandedContent.disable="Disable branded content"
|
||||
AdvSceneSwitcher.action.twitch.contentClassification.debatedSocialIssuesAndPolitics="Discussions or debates about politics or sensitive social issues such as elections, civic integrity, military conflict, and civil rights."
|
||||
AdvSceneSwitcher.action.twitch.contentClassification.drugsIntoxication="Excessive tobacco glorification or promotion, any marijuana consumption/use, legal drug and alcohol induced intoxication, discussions of illegal drugs."
|
||||
AdvSceneSwitcher.action.twitch.contentClassification.sexualThemes="Content that focuses on sexualized activities, sexual topics, or experiences."
|
||||
AdvSceneSwitcher.action.twitch.contentClassification.violentGraphic="Simulations and/or depictions of realistic violence, gore, extreme injury, or death."
|
||||
AdvSceneSwitcher.action.twitch.contentClassification.gambling="Participating in or promoting online or in-person gambling, poker, or fantasy sports that involve the exchange of real money."
|
||||
AdvSceneSwitcher.action.twitch.contentClassification.profanityVulgarity="Prolonged and repeated use of obscenities, profanities, and vulgarities, especially as a regular part of speech."
|
||||
AdvSceneSwitcher.action.twitch.contentClassification.getCurrent="Get current content classification labels"
|
||||
AdvSceneSwitcher.action.twitch.language.english="English"
|
||||
AdvSceneSwitcher.action.twitch.language.indonesian="Bahasa Indonesia"
|
||||
AdvSceneSwitcher.action.twitch.language.catalan="Català"
|
||||
AdvSceneSwitcher.action.twitch.language.danish="Dansk"
|
||||
AdvSceneSwitcher.action.twitch.language.german="Deutsch"
|
||||
AdvSceneSwitcher.action.twitch.language.spanish="Español"
|
||||
AdvSceneSwitcher.action.twitch.language.french="Français"
|
||||
AdvSceneSwitcher.action.twitch.language.italian="Italiano"
|
||||
AdvSceneSwitcher.action.twitch.language.hungarian="Magyar"
|
||||
AdvSceneSwitcher.action.twitch.language.dutch="Nederlands"
|
||||
AdvSceneSwitcher.action.twitch.language.norwegian="Norsk"
|
||||
AdvSceneSwitcher.action.twitch.language.polish="Polski"
|
||||
AdvSceneSwitcher.action.twitch.language.portuguese="Português"
|
||||
AdvSceneSwitcher.action.twitch.language.romanian="Română"
|
||||
AdvSceneSwitcher.action.twitch.language.slovak="Slovenčina"
|
||||
AdvSceneSwitcher.action.twitch.language.finnish="Suomi"
|
||||
AdvSceneSwitcher.action.twitch.language.swedish="Svenska"
|
||||
AdvSceneSwitcher.action.twitch.language.tagalog="Tagalog"
|
||||
AdvSceneSwitcher.action.twitch.language.vietnamese="Tiếng Việt"
|
||||
AdvSceneSwitcher.action.twitch.language.turkish="Türkçe"
|
||||
AdvSceneSwitcher.action.twitch.language.czech="Čeština"
|
||||
AdvSceneSwitcher.action.twitch.language.greek="Ελληνικά"
|
||||
AdvSceneSwitcher.action.twitch.language.bulgarian="Български"
|
||||
AdvSceneSwitcher.action.twitch.language.russian="Русский"
|
||||
AdvSceneSwitcher.action.twitch.language.ukrainian="Українська"
|
||||
AdvSceneSwitcher.action.twitch.language.arabic="العربية"
|
||||
AdvSceneSwitcher.action.twitch.language.malay="بهاس ملايو"
|
||||
AdvSceneSwitcher.action.twitch.language.hindi="मानक हिन्दी"
|
||||
AdvSceneSwitcher.action.twitch.language.thai="ภาษาไทย"
|
||||
AdvSceneSwitcher.action.twitch.language.chinese="中文"
|
||||
AdvSceneSwitcher.action.twitch.language.japanese="日本語"
|
||||
AdvSceneSwitcher.action.twitch.language.cantonese="粵語"
|
||||
AdvSceneSwitcher.action.twitch.language.korean="한국어"
|
||||
AdvSceneSwitcher.action.twitch.language.asl="American Sign Language"
|
||||
AdvSceneSwitcher.action.twitch.language.other="Other"
|
||||
AdvSceneSwitcher.action.twitch.language.getCurrent="Get current language"
|
||||
AdvSceneSwitcher.action.clipboard="Clipboard"
|
||||
AdvSceneSwitcher.action.clipboard.type.copy.text="Copy text"
|
||||
AdvSceneSwitcher.action.clipboard.type.copy.image="Copy image"
|
||||
@@ -1492,9 +1255,6 @@ AdvSceneSwitcher.action.obsSetting.action.setBaseCanvasX="Set base resolution X
|
||||
AdvSceneSwitcher.action.obsSetting.action.setBaseCanvasY="Set base resolution Y value"
|
||||
AdvSceneSwitcher.action.obsSetting.action.setOutputCanvasX="Set output resolution X value"
|
||||
AdvSceneSwitcher.action.obsSetting.action.setOutputCanvasY="Set output resolution Y value"
|
||||
AdvSceneSwitcher.action.obsSetting.action.enablePreview="Enable preview"
|
||||
AdvSceneSwitcher.action.obsSetting.action.disablePreview="Disable preview"
|
||||
AdvSceneSwitcher.action.obsSetting.action.togglePreview="Toggle preview enable"
|
||||
AdvSceneSwitcher.action.obsSetting.getCurrentValue="Get current value"
|
||||
AdvSceneSwitcher.action.obsSettings.layout="{{actions}}{{fpsType}}{{fpsIntValue}}{{fpsStringValue}}{{canvasSizeValue}}{{getCurrentValue}}"
|
||||
AdvSceneSwitcher.action.script="Script"
|
||||
@@ -1514,9 +1274,6 @@ AdvSceneSwitcher.hotkey.macro.segment.remove="Remove selected macro segment"
|
||||
AdvSceneSwitcher.askBackup="Detected a new version of the Advanced Scene Switcher.\nShould a backup of the old settings be created?"
|
||||
AdvSceneSwitcher.askForMacro="Select macro{{macroSelection}}"
|
||||
|
||||
AdvSceneSwitcher.crashDetected="OBS did not shut down cleanly (for example, due to a crash or freeze).\n\nThe Advanced Scene Switcher plugin would normally start automatically.\nWould you like to keep it stopped for now?"
|
||||
AdvSceneSwitcher.crashDetected.suppressCheckbox="Do not show this dialog again"
|
||||
|
||||
AdvSceneSwitcher.close="Close"
|
||||
AdvSceneSwitcher.browse="Browse"
|
||||
|
||||
@@ -1668,13 +1425,6 @@ AdvSceneSwitcher.mqttConnection.name="Name:"
|
||||
AdvSceneSwitcher.mqttConnection.address="Address:"
|
||||
AdvSceneSwitcher.mqttConnection.username="Username:"
|
||||
AdvSceneSwitcher.mqttConnection.password="Password:"
|
||||
AdvSceneSwitcher.mqttConnection.trustStore="Trust store:"
|
||||
AdvSceneSwitcher.mqttConnection.trustStore.help="The file in PEM format containing the public digital certificates trusted by the client."
|
||||
AdvSceneSwitcher.mqttConnection.keyStore="Key store:"
|
||||
AdvSceneSwitcher.mqttConnection.keyStore.help="The file in PEM format containing the public certificate chain of the client.\nIt may also include the client's private key."
|
||||
AdvSceneSwitcher.mqttConnection.privateKey="Private key:"
|
||||
AdvSceneSwitcher.mqttConnection.privateKey.help="If not included in the key store, this is the file in PEM format containing the client's private key."
|
||||
AdvSceneSwitcher.mqttConnection.verifyServerCert="Verify server certificate"
|
||||
AdvSceneSwitcher.mqttConnection.reconnect="Reconnect automatically:"
|
||||
AdvSceneSwitcher.mqttConnection.reconnectDelay="Automatically reconnect after:"
|
||||
AdvSceneSwitcher.mqttConnection.connectOnStart="Connect on startup:"
|
||||
@@ -1720,7 +1470,6 @@ AdvSceneSwitcher.twitchToken.bits.read="Read channel's Bits information."
|
||||
AdvSceneSwitcher.twitchToken.channel.raids.manage="Manage channel's raids."
|
||||
AdvSceneSwitcher.twitchToken.moderator.shoutouts.read="Read channel's shoutouts."
|
||||
AdvSceneSwitcher.twitchToken.moderator.shoutouts.manage="Manage channel's shoutouts."
|
||||
AdvSceneSwitcher.twitchToken.channel.ads.read="Read the ads schedule and details on your channel."
|
||||
AdvSceneSwitcher.twitchToken.channel.polls.read="Read channel's polls' state."
|
||||
AdvSceneSwitcher.twitchToken.channel.polls.manage="Manage channel's polls."
|
||||
AdvSceneSwitcher.twitchToken.channel.predictions.read="Read channel's predictions' state."
|
||||
@@ -1746,11 +1495,7 @@ AdvSceneSwitcher.twitchToken.moderator.chat.settings.manage="Manage channel's ch
|
||||
AdvSceneSwitcher.twitchToken.user.whispers.manage="Manage user's whispers."
|
||||
AdvSceneSwitcher.twitchToken.chat.read="View live stream chat messages."
|
||||
AdvSceneSwitcher.twitchToken.chat.edit="Send live stream chat messages."
|
||||
AdvSceneSwitcher.twitchToken.validateTimestamps="Validate timestamps of received Twitch event messages."
|
||||
AdvSceneSwitcher.twitchToken.validateTimestamps.tooltip="Verifies that incoming Twitch messages have valid timestamps to prevent replayed or spoofed messages.\nDisabling this won’t affect normal functionality, and you can try turning it off if you experience issues with the Twitch connection."
|
||||
AdvSceneSwitcher.twitchToken.warnIfInvalid="Display warning if the token expired or is invalid."
|
||||
AdvSceneSwitcher.twitchToken.warnIfInvalid.doNotShowAgain="Don't show again for this connection"
|
||||
AdvSceneSwitcher.twitchToken.warnIfInvalid.message="The Twitch connection \"%1\" is invalid.\nOpen connection settings or ignore?"
|
||||
AdvSceneSwitcher.twitchToken.validateTimestamps="Validate timestamps of received Twitch event messages. (Recommended)"
|
||||
|
||||
AdvSceneSwitcher.twitch.selection.channel.open="Open channel"
|
||||
AdvSceneSwitcher.twitch.selection.channel.open.tooltip.details="Open channel in external application handling the HTTPS protocol."
|
||||
@@ -1785,19 +1530,11 @@ AdvSceneSwitcher.script.language.lua="LUA"
|
||||
AdvSceneSwitcher.script.language.select="--select language--"
|
||||
AdvSceneSwitcher.script.language.layout="Script language:{{language}}"
|
||||
AdvSceneSwitcher.script.file.open="Open"
|
||||
AdvSceneSwitcher.script.file.select="Select Script File"
|
||||
AdvSceneSwitcher.script.file.open.failed="Could not open script file!"
|
||||
AdvSceneSwitcher.script.file.warning.notFound="Warning: The given file path was not found!"
|
||||
AdvSceneSwitcher.script.file.warning.openFail="Warning: Could not open the script file!"
|
||||
AdvSceneSwitcher.script.file.warning.loadMissing="Warning: The script is missing a 'script_load' function!"
|
||||
AdvSceneSwitcher.script.file.layout="Script file:{{path}}{{open}}"
|
||||
|
||||
AdvSceneSwitcher.tempVar.select="--select value--"
|
||||
AdvSceneSwitcher.tempVar.selectionInfo.lastValues="Last values:"
|
||||
AdvSceneSwitcher.tempVar.outputMappings="Save outputs to variables:"
|
||||
AdvSceneSwitcher.tempVar.outputMappings.add="+ Add output mapping"
|
||||
AdvSceneSwitcher.tempVar.outputMappings.toggle="Assign outputs to variables"
|
||||
AdvSceneSwitcher.tempVar.outputMappings.remove="Remove output mapping"
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.broadcaster_user_id="Twitch broadcaster user ID"
|
||||
AdvSceneSwitcher.tempVar.twitch.broadcaster_user_id.description="The numerical Twitch user ID of the broadcaster."
|
||||
@@ -2245,18 +1982,6 @@ AdvSceneSwitcher.tempVar.twitch.offline_image_url.user.getInfo="Offline image UR
|
||||
AdvSceneSwitcher.tempVar.twitch.created_at.user.getInfo="Account creation date"
|
||||
AdvSceneSwitcher.tempVar.twitch.created_at.user.getInfo.description="The UTC date and time that the user's account was created. The timestamp is in RFC3339 format."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.duration_seconds.commercial="Duration"
|
||||
AdvSceneSwitcher.tempVar.twitch.duration_seconds.commercial.description="Length in seconds of the mid-roll ad break requested."
|
||||
AdvSceneSwitcher.tempVar.twitch.started_at.commercial="Started at"
|
||||
AdvSceneSwitcher.tempVar.twitch.started_at.commercial.description="The UTC timestamp of when the ad break began, in RFC3339 format. Note that there is potential delay between this event, when the streamer requested the ad break, and when the viewers will see ads."
|
||||
AdvSceneSwitcher.tempVar.twitch.is_automatic.commercial="Was automatic"
|
||||
AdvSceneSwitcher.tempVar.twitch.is_automatic.commercial.description="Indicates if the ad was automatically scheduled via Ads Manager"
|
||||
AdvSceneSwitcher.tempVar.twitch.requester_user_id.commercial="Requester user ID"
|
||||
AdvSceneSwitcher.tempVar.twitch.requester_user_id.commercial.description="The ID of the user that requested the ad. For automatic ads, this will be the ID of the broadcaster."
|
||||
AdvSceneSwitcher.tempVar.twitch.requester_user_login.commercial="Requester user login"
|
||||
AdvSceneSwitcher.tempVar.twitch.requester_user_login.commercial.description="The login of the user that requested the ad."
|
||||
AdvSceneSwitcher.tempVar.twitch.requester_user_name.commercial="Requester user name"
|
||||
AdvSceneSwitcher.tempVar.twitch.requester_user_name.commercial.description="The display name of the user that requested the ad."
|
||||
|
||||
AdvSceneSwitcher.tempVar.audio.output_volume="Output volume"
|
||||
AdvSceneSwitcher.tempVar.audio.output_volume.description="The volume the audio source is outputting."
|
||||
@@ -2275,14 +2000,11 @@ AdvSceneSwitcher.tempVar.clipboard.mimeType.all.description="All MIME types of t
|
||||
AdvSceneSwitcher.tempVar.scene.current="Current scene"
|
||||
AdvSceneSwitcher.tempVar.scene.previous="Previous scene"
|
||||
AdvSceneSwitcher.tempVar.scene.preview="Preview scene"
|
||||
AdvSceneSwitcher.tempVar.scene.position="Position in scenes list"
|
||||
|
||||
AdvSceneSwitcher.tempVar.window.window="Window title"
|
||||
AdvSceneSwitcher.tempVar.window.window.description="The window title of the matching window."
|
||||
AdvSceneSwitcher.tempVar.window.windowClass="Window class"
|
||||
AdvSceneSwitcher.tempVar.window.windowClass.description="The window class of the matching window."
|
||||
AdvSceneSwitcher.tempVar.window.windowText="Window text"
|
||||
AdvSceneSwitcher.tempVar.window.windowText.description="Text contained within the window (won't work on all window types)."
|
||||
|
||||
AdvSceneSwitcher.tempVar.timer.seconds="Seconds"
|
||||
AdvSceneSwitcher.tempVar.timer.minutes="Minutes"
|
||||
@@ -2307,21 +2029,8 @@ AdvSceneSwitcher.tempVar.macro.runCount="Run count"
|
||||
AdvSceneSwitcher.tempVar.macro.runCount.description="The number of times a macro was executed."
|
||||
AdvSceneSwitcher.tempVar.macro.matchedCount="Matched count"
|
||||
AdvSceneSwitcher.tempVar.macro.matchedCount.description="The number of macros of which the condition state was true."
|
||||
AdvSceneSwitcher.tempVar.macro.info.conditionCount="Condition count"
|
||||
AdvSceneSwitcher.tempVar.macro.info.conditionCount.description="The number of conditions in the macro."
|
||||
AdvSceneSwitcher.tempVar.macro.info.actionCount="Action count"
|
||||
AdvSceneSwitcher.tempVar.macro.info.actionCount.description="The number of actions in the macro."
|
||||
AdvSceneSwitcher.tempVar.macro.info.elseActionCount="Else-action count"
|
||||
AdvSceneSwitcher.tempVar.macro.info.elseActionCount.description="The number of else-actions in the macro."
|
||||
AdvSceneSwitcher.tempVar.macro.info.paused="Paused"
|
||||
AdvSceneSwitcher.tempVar.macro.info.paused.description="Whether the macro is currently paused. Value is \"true\" or \"false\"."
|
||||
AdvSceneSwitcher.tempVar.macro.info.runCount="Run count"
|
||||
AdvSceneSwitcher.tempVar.macro.info.runCount.description="The number of times the macro has been executed."
|
||||
AdvSceneSwitcher.tempVar.macro.info.secondsSinceLastRun="Seconds since last run"
|
||||
AdvSceneSwitcher.tempVar.macro.info.secondsSinceLastRun.description="The number of seconds elapsed since the macro was last executed. Value is -1 if the macro has never been executed."
|
||||
|
||||
AdvSceneSwitcher.tempVar.process.name="Process name"
|
||||
AdvSceneSwitcher.tempVar.process.path="Process path"
|
||||
|
||||
AdvSceneSwitcher.tempVar.run.process.id="Process ID"
|
||||
AdvSceneSwitcher.tempVar.run.process.id.description="PID of the process assigned by the system."
|
||||
@@ -2337,11 +2046,7 @@ AdvSceneSwitcher.tempVar.run.process.none.description="When not waiting for the
|
||||
|
||||
AdvSceneSwitcher.tempVar.recording.durationSeconds="Recording duration"
|
||||
AdvSceneSwitcher.tempVar.recording.durationSeconds.description="Recording duration in seconds.\nThis value does not change while the recording is paused and will be reset to zero if the recording is stopped."
|
||||
AdvSceneSwitcher.tempVar.recording.lastSavePath="Last save path"
|
||||
AdvSceneSwitcher.tempVar.recording.lastSavePath.description="The file path of the last saved recording."
|
||||
|
||||
AdvSceneSwitcher.tempVar.video.similarity="Similarity Rating"
|
||||
AdvSceneSwitcher.tempVar.video.similarity.description="Values range from 0 to 1, where 0 means dissimilar and 1 means highly similar."
|
||||
AdvSceneSwitcher.tempVar.video.patternCount="Pattern count"
|
||||
AdvSceneSwitcher.tempVar.video.patternCount.description="The number of times the given pattern has been found in a given video input frame."
|
||||
AdvSceneSwitcher.tempVar.video.objectCount="Object count"
|
||||
@@ -2352,8 +2057,6 @@ AdvSceneSwitcher.tempVar.video.text="OCR text"
|
||||
AdvSceneSwitcher.tempVar.video.text.description="The text detected in a given video input frame."
|
||||
AdvSceneSwitcher.tempVar.video.color="Average color"
|
||||
AdvSceneSwitcher.tempVar.video.color.description="The average RGB color in a given video input frame in HexArgb format."
|
||||
AdvSceneSwitcher.tempVar.video.dominantColor="Dominant color"
|
||||
AdvSceneSwitcher.tempVar.video.dominantColor.description="The most dominant RGB color in a given video input frame in HexArgb format.\nDetermined using k-means clustering, which groups similar colors and returns the center of the largest group.\nDue to the nature of the algorithm the result may vary slightly between evaluations."
|
||||
|
||||
AdvSceneSwitcher.tempVar.websocket.message="Received websocket message"
|
||||
AdvSceneSwitcher.tempVar.websocket.message.description="The received websocket message, which matched the given pattern"
|
||||
@@ -2380,19 +2083,6 @@ AdvSceneSwitcher.tempVar.clipboard.text.description="The text contained in the c
|
||||
|
||||
AdvSceneSwitcher.tempVar.file.content="File content"
|
||||
AdvSceneSwitcher.tempVar.file.date="File modification date"
|
||||
AdvSceneSwitcher.tempVar.file.basename="File basename"
|
||||
AdvSceneSwitcher.tempVar.file.basename.description="Returns the base name of the file without the path.\nThe base name consists of all characters in the file up to (but not including) the first '.' character."
|
||||
AdvSceneSwitcher.tempVar.file.basenameComplete="File basename (complete)"
|
||||
AdvSceneSwitcher.tempVar.file.basenameComplete.description="Returns the complete base name of the file without the path.\nThe complete base name consists of all characters in the file up to (but not including) the last '.' character."
|
||||
AdvSceneSwitcher.tempVar.file.suffix="File suffix"
|
||||
AdvSceneSwitcher.tempVar.file.suffix.description="Returns the suffix (extension) of the file.\nThe suffix consists of all characters in the file after (but not including) the last '.'."
|
||||
AdvSceneSwitcher.tempVar.file.suffixComplete="File suffix (complete)"
|
||||
AdvSceneSwitcher.tempVar.file.suffixComplete.description="Returns the complete suffix (extension) of the file.\nThe complete suffix consists of all characters in the file after (but not including) the first '.'."
|
||||
AdvSceneSwitcher.tempVar.file.filename="File name"
|
||||
AdvSceneSwitcher.tempVar.file.absoluteFilePath="Absolute file path"
|
||||
AdvSceneSwitcher.tempVar.file.absolutePath="Absolute path"
|
||||
AdvSceneSwitcher.tempVar.file.isAbsolutePath="Path is absolute"
|
||||
|
||||
|
||||
AdvSceneSwitcher.tempVar.folder.newFiles="New files"
|
||||
AdvSceneSwitcher.tempVar.folder.changedFiles="Changed files"
|
||||
@@ -2426,8 +2116,6 @@ AdvSceneSwitcher.tempVar.usb.serialNumber="Serial Number"
|
||||
AdvSceneSwitcher.tempVar.transform.setting="Setting value"
|
||||
AdvSceneSwitcher.tempVar.transform.settings="Settings string"
|
||||
|
||||
AdvSceneSwitcher.tempVar.media.source="Source"
|
||||
AdvSceneSwitcher.tempVar.media.source.description="The name of the source which matched.\nIf multiple sources matched the last one is returned."
|
||||
AdvSceneSwitcher.tempVar.media.state="State"
|
||||
AdvSceneSwitcher.tempVar.media.state.description="The current media state represented as an integer value:\n0 being 'None'\n1 being 'Playing'\n2 being 'Opening'\n3 being 'Buffering'\n4 being 'Paused'\n5 being 'Stopped'\n6 being 'Ended'\n7 being 'Error'"
|
||||
AdvSceneSwitcher.tempVar.media.time="Current time"
|
||||
@@ -2483,33 +2171,16 @@ AdvSceneSwitcher.tempVar.gameCapture.executable="Executable"
|
||||
AdvSceneSwitcher.tempVar.gameCapture.executable.description="Executable name of the application captured by the source."
|
||||
|
||||
AdvSceneSwitcher.tempVar.http.status="Status code"
|
||||
AdvSceneSwitcher.tempVar.http.body="Message body"
|
||||
AdvSceneSwitcher.tempVar.http.error="Error"
|
||||
AdvSceneSwitcher.tempVar.http.error.description="Empty when no error occurred.\nOther possible values:\n\n * Could not establish connection\n * Failed to bind IP address\n * Failed to read connection\n * Failed to write connection\n * Maximum redirect count exceeded\n * Connection handling canceled\n * SSL connection failed\n * SSL certificate loading failed\n * SSL server verification failed\n * Unsupported HTTP multipart boundary characters\n * Compression failed\n * Connection timed out\n * Proxy connection failed\n * Unknown"
|
||||
AdvSceneSwitcher.tempVar.http.method="Method"
|
||||
AdvSceneSwitcher.tempVar.http.method.description="Received HTTP request method"
|
||||
AdvSceneSwitcher.tempVar.http.path="Request path"
|
||||
AdvSceneSwitcher.tempVar.http.path.description="Received HTTP request path"
|
||||
AdvSceneSwitcher.tempVar.http.body="Message body"
|
||||
AdvSceneSwitcher.tempVar.http.body.description="Received HTTP request body"
|
||||
|
||||
AdvSceneSwitcher.tempVar.mqtt.message="Message"
|
||||
|
||||
AdvSceneSwitcher.tempVar.cursor.x="Cursor position (X)"
|
||||
AdvSceneSwitcher.tempVar.cursor.y="Cursor position (Y)"
|
||||
|
||||
AdvSceneSwitcher.tempVar.replay.lastSavePath="Last save path"
|
||||
AdvSceneSwitcher.tempVar.replay.lastSavePath.description="The file path of the last replay buffer saved."
|
||||
|
||||
AdvSceneSwitcher.tempVar.sequence.macro="Macro"
|
||||
AdvSceneSwitcher.tempVar.sequence.macro.description="The name of the macro executed by the \"Sequence\" action.\nIf no macro was executed the returned value is the empty string."
|
||||
AdvSceneSwitcher.tempVar.sequence.nextMacro="Next Macro"
|
||||
AdvSceneSwitcher.tempVar.sequence.nextMacro.description="The name of the macro which will be executed next after the index was set.\nIf no macro will be executed the returned value is the empty string."
|
||||
|
||||
AdvSceneSwitcher.tempVar.random.macro="Macro"
|
||||
AdvSceneSwitcher.tempVar.random.macro.description="The name of the macro executed by the \"Random\" action.\nIf no macro was executed the returned value is the empty string."
|
||||
|
||||
AdvSceneSwitcher.selectScene="--select scene--"
|
||||
AdvSceneSwitcher.selectCanvas="--select canvas--"
|
||||
AdvSceneSwitcher.selectPreviousScene="Previous Scene"
|
||||
AdvSceneSwitcher.selectCurrentScene="Current Scene"
|
||||
AdvSceneSwitcher.selectPreviewScene="Preview Scene"
|
||||
@@ -2570,23 +2241,21 @@ AdvSceneSwitcher.setting.transform.width="Width"
|
||||
|
||||
AdvSceneSwitcher.sceneItemSelection.configure="Configure scene item selection type"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName="Source name"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName.layout="{{nameConflictIndex}}{{sourceName}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName.entry="{{nameConflictIndex}}{{sourceName}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable="Variable name"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable.layout="{{nameConflictIndex}}{{variable}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable.entry="{{nameConflictIndex}}{{variable}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern="Source name matches pattern"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.layout="{{nameConflictIndex}}matching{{pattern}}{{regex}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.entry="{{nameConflictIndex}}matching{{pattern}}{{regex}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceGroup="Sources in source group"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceGroup.layout="{{nameConflictIndex}}Sources in{{sourceGroups}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceGroup.entry="Sources in{{sourceGroups}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType="Sources of type"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType.layout="Source type{{nameConflictIndex}}{{sourceTypes}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType.entry="Source type{{nameConflictIndex}}{{sourceTypes}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index="Source with index"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index.layout="{{index}}source"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index.entry="{{index}}source"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange="Sources in index range"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange.layout="Sources from{{index}}to{{indexEnd}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange.entry="Sources from{{index}}to{{indexEnd}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all="All sources"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all.layout="All sources"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.any="Any source"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.any.layout="Any source"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all.entry="All sources"
|
||||
AdvSceneSwitcher.sceneItemSelection.all="All"
|
||||
AdvSceneSwitcher.sceneItemSelection.any="Any"
|
||||
|
||||
@@ -2597,6 +2266,8 @@ AdvSceneSwitcher.status.inactive="Inactive"
|
||||
AdvSceneSwitcher.running="Plugin running"
|
||||
AdvSceneSwitcher.stopped="Plugin stopped"
|
||||
|
||||
AdvSceneSwitcher.firstBootMessage="<html><head/><body><p>This seems to be the first time the Advanced Scene Switcher was started.<br>Please have a look at the <a href=\"https://github.com/WarmUpTill/SceneSwitcher/wiki\"><span style=\" text-decoration: underline; color:#268bd2;\">Wiki</span></a> for a list of guides and examples.<br>Do not hesitate to ask questions in the plugin's <a href=\"https://obsproject.com/forum/threads/advanced-scene-switcher.48264\"><span style=\" text-decoration: underline; color:#268bd2;\">thread</span></a> on the OBS forums!</p></body></html>"
|
||||
|
||||
AdvSceneSwitcher.deprecatedTabWarning="Development for this tab stopped!\nPlease consider transitioning to using Macros instead.\nThis hint can be disabled on the General tab."
|
||||
|
||||
AdvSceneSwitcher.unit.milliseconds="milliseconds"
|
||||
@@ -2626,47 +2297,6 @@ AdvSceneSwitcher.clearBufferOnMatch="Clear message buffer when matching message
|
||||
AdvSceneSwitcher.script.settings="Settings"
|
||||
AdvSceneSwitcher.script.timeout="Script timeout:{{timeout}}"
|
||||
|
||||
AdvSceneSwitcher.day.monday="Monday"
|
||||
AdvSceneSwitcher.day.tuesday="Tuesday"
|
||||
AdvSceneSwitcher.day.wednesday="Wednesday"
|
||||
AdvSceneSwitcher.day.thursday="Thursday"
|
||||
AdvSceneSwitcher.day.friday="Friday"
|
||||
AdvSceneSwitcher.day.saturday="Saturday"
|
||||
AdvSceneSwitcher.day.sunday="Sunday"
|
||||
AdvSceneSwitcher.day.none="No day"
|
||||
AdvSceneSwitcher.day.any="Any day"
|
||||
|
||||
# First run wizard
|
||||
FirstRunWizard.windowTitle="Advanced Scene Switcher - Setup Wizard"
|
||||
|
||||
FirstRunWizard.welcome.title="Welcome to Advanced Scene Switcher"
|
||||
FirstRunWizard.welcome.subtitle="Let's create your first automation in a few easy steps."
|
||||
FirstRunWizard.welcome.body="<p>Advanced Scene Switcher lets you build <b>Macros</b> - rules of the form:</p><blockquote><i>When [condition] -> perform [action]</i></blockquote><p>This wizard creates a macro that <b>switches to a chosen OBS scene whenever a specific window comes into focus</b>.</p><p>You can skip at any time. Re-open this wizard later from the <b>General</b> tab inside the Advanced Scene Switcher dialog.</p>"
|
||||
|
||||
FirstRunWizard.scene.title="Choose a Target Scene"
|
||||
FirstRunWizard.scene.subtitle="Which OBS scene should become active when your chosen window comes into focus?"
|
||||
FirstRunWizard.scene.label="Switch to scene:"
|
||||
|
||||
FirstRunWizard.window.title="Choose a Trigger Window"
|
||||
FirstRunWizard.window.subtitle="Enter the title of the window that should trigger the scene switch. Partial matches are fine - \"Firefox\" will match any Firefox window."
|
||||
FirstRunWizard.window.label="Window title contains:"
|
||||
FirstRunWizard.window.placeholder="e.g. \"Firefox\", \"Visual Studio Code\""
|
||||
FirstRunWizard.window.autoDetect="Auto-detect focused window"
|
||||
FirstRunWizard.window.autoDetectTooltip="Click, then switch to the target window. The title will be captured automatically after 3 seconds."
|
||||
FirstRunWizard.window.autoDetectCountdown="Detecting in %1 s - focus your window now..."
|
||||
FirstRunWizard.window.hint="<small>Tip: a short partial title is more robust than the full title, which often changes when you switch tabs.</small>"
|
||||
|
||||
FirstRunWizard.review.title="Review Your Macro"
|
||||
FirstRunWizard.review.subtitle="Click Back to make changes, or Finish to create the macro."
|
||||
FirstRunWizard.review.summary="<b>Macro name:</b> Window -> %1<br><br><b>Condition:</b> Focused window title contains <i>\"%2\"</i> (case-insensitive)<br><br><b>Action:</b> Switch to scene <i>\"%1\"</i>"
|
||||
FirstRunWizard.review.errorTitle="Macro Creation Failed"
|
||||
FirstRunWizard.review.errorBody="The macro could not be created automatically.\n\nYou can create it manually on the Macros tab:\n Condition: Window -> contains \"%1\"\n Action: Switch scene -> \"%2\""
|
||||
|
||||
FirstRunWizard.done.title="You're all set!"
|
||||
FirstRunWizard.done.subtitle="Your first macro has been created and is now active."
|
||||
FirstRunWizard.done.body="<p>You can view and edit it on the <b>Macros</b> tab of the Advanced Scene Switcher dialog.</p><p>To learn more:</p><ul><li><a href=\"https://github.com/WarmUpTill/SceneSwitcher/wiki\">Plugin wiki</a></li><li><a href=\"https://obsproject.com/forum/resources/automatic-scene-switching.395/\">OBS forum thread</a></li></ul>"
|
||||
|
||||
FirstRunWizard.openButton="Open Setup Wizard..."
|
||||
# This secion is copied from the OBS locale files
|
||||
|
||||
# OBS commonly shared locale
|
||||
|
||||
@@ -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"
|
||||
@@ -72,6 +72,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"
|
||||
@@ -83,6 +84,7 @@ AdvSceneSwitcher.macroTab.highlightTrueConditions="Resaltar condiciones de la ma
|
||||
AdvSceneSwitcher.macroTab.highlightPerformedActions="Resaltar acciones realizadas recientemente de la macro seleccionada actualmente"
|
||||
|
||||
; Lógica de macros
|
||||
AdvSceneSwitcher.logic.none="Omitir entrada"
|
||||
AdvSceneSwitcher.logic.and="Y"
|
||||
AdvSceneSwitcher.logic.or="O"
|
||||
AdvSceneSwitcher.logic.andNot="Y no"
|
||||
@@ -116,7 +118,9 @@ AdvSceneSwitcher.condition.scene.currentSceneTransitionBehaviour="Durante la tra
|
||||
AdvSceneSwitcher.condition.scene.previousSceneTransitionBehaviour="Durante la transición, verifique la escena de origen de la transición"
|
||||
AdvSceneSwitcher.condition.window="Ventana"
|
||||
AdvSceneSwitcher.condition.file="Archivo"
|
||||
AdvSceneSwitcher.condition.file.layout="Contenido de{{filePath}}{{conditions}}{{regex}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line1="Contenido de{{fileType}}{{filePath}}{{conditions}}{{useRegex}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFileContent}}"
|
||||
AdvSceneSwitcher.condition.media="Medios"
|
||||
AdvSceneSwitcher.condition.media.anyOnScene="Cualquier fuente multimedia activada"
|
||||
AdvSceneSwitcher.condition.media.allOnScene="Todas las fuentes de medios activadas"
|
||||
@@ -172,7 +176,7 @@ AdvSceneSwitcher.condition.record.state.start="Grabación en ejecución"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Grabación en pausa"
|
||||
AdvSceneSwitcher.condition.record.state.stop="Grabación detenida"
|
||||
AdvSceneSwitcher.condition.process="Proceso"
|
||||
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}se está ejecutando{{focused}}y está enfocado"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}se está ejecutando{{focused}}y está enfocado"
|
||||
AdvSceneSwitcher.condition.idle="Inactivo"
|
||||
AdvSceneSwitcher.condition.idle.entry="No hay entradas de teclado o ratón durante {{duration}}"
|
||||
AdvSceneSwitcher.condition.pluginState="Estado del complemento"
|
||||
@@ -237,14 +241,14 @@ AdvSceneSwitcher.condition.replay.state.started="Búfer de reproducción iniciad
|
||||
AdvSceneSwitcher.condition.replay.state.saved="Búfer de reproducción guardado"
|
||||
AdvSceneSwitcher.condition.replay.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"
|
||||
@@ -254,12 +258,11 @@ AdvSceneSwitcher.condition.date.ignoreDate="Si no se marca, se ignorará el comp
|
||||
AdvSceneSwitcher.condition.date.ignoreTime="Si no se marca, se ignorará el componente de tiempo"
|
||||
AdvSceneSwitcher.condition.date.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"
|
||||
@@ -308,6 +311,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"
|
||||
@@ -331,6 +335,7 @@ AdvSceneSwitcher.action.recording.type.start="Iniciar grabación"
|
||||
AdvSceneSwitcher.action.recording.type.pause="Pausar grabación"
|
||||
AdvSceneSwitcher.action.recording.type.unpause="Reanudar grabación"
|
||||
AdvSceneSwitcher.action.recording.pause.hint="Tenga en cuenta que, dependiendo de la configuración de grabación, es posible que no pueda pausar la grabación"
|
||||
AdvSceneSwitcher.action.recording.entry="{{actions}}{{recordFolder}}{{recordFileFormat}}{{pauseHint}}{{splitHint}}"
|
||||
AdvSceneSwitcher.action.replay="Búfer de reproducción"
|
||||
AdvSceneSwitcher.action.replay.saveWarn="Advertencia: ¡Guardar con demasiada frecuencia puede hacer que el búfer de reproducción no se guarde realmente!"
|
||||
AdvSceneSwitcher.action.replay.type.stop="Detener el búfer de reproducción"
|
||||
@@ -339,13 +344,14 @@ AdvSceneSwitcher.action.replay.type.save="Guardar búfer de reproducción"
|
||||
AdvSceneSwitcher.action.streaming="Transmisión"
|
||||
AdvSceneSwitcher.action.streaming.type.stop="Detener transmisión"
|
||||
AdvSceneSwitcher.action.streaming.type.start="Iniciar transmisión"
|
||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
|
||||
AdvSceneSwitcher.action.run="Ejecutar"
|
||||
AdvSceneSwitcher.action.sceneVisibility="Visibilidad del elemento de escena"
|
||||
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"
|
||||
@@ -370,14 +376,14 @@ AdvSceneSwitcher.action.macro="Macro"
|
||||
AdvSceneSwitcher.action.macro.type.pause="Pausa"
|
||||
AdvSceneSwitcher.action.macro.type.unpause="Reanudar"
|
||||
AdvSceneSwitcher.action.macro.type.resetCounter="Reiniciar contador"
|
||||
AdvSceneSwitcher.action.macro.type.runActions="Ejecutar"
|
||||
AdvSceneSwitcher.action.macro.type.run="Ejecutar"
|
||||
AdvSceneSwitcher.action.macro.type.stop="Detener"
|
||||
AdvSceneSwitcher.action.pluginState="Estado del complemento"
|
||||
AdvSceneSwitcher.action.pluginState.type.stop="Detener el complemento Advanced Scene Switcher"
|
||||
AdvSceneSwitcher.action.pluginState.type.noMatch="Cambiar el comportamiento de no coincidencia:"
|
||||
AdvSceneSwitcher.action.pluginState.type.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"
|
||||
@@ -418,9 +424,9 @@ AdvSceneSwitcher.action.transition.type.scene="transición de escena"
|
||||
AdvSceneSwitcher.action.transition.type.sceneOverride="anulación de transición de escena"
|
||||
AdvSceneSwitcher.action.transition.type.sourceShow="transición del programa de origen"
|
||||
AdvSceneSwitcher.action.transition.type.sourceHide="fuente ocultar transición"
|
||||
AdvSceneSwitcher.action.transition.layout.type="Modificar {{type}}{{scenes}}{{sources}}"
|
||||
AdvSceneSwitcher.action.transition.layout.transition="{{setTransition}}Establecer el tipo de transición en {{transitions}}"
|
||||
AdvSceneSwitcher.action.transition.layout.duration="{{setDuration}}Establecer la duración de la transición en {{duration}}segundos"
|
||||
AdvSceneSwitcher.action.transition.entry.line1="Modificar {{type}}{{scenes}}{{sources}}"
|
||||
AdvSceneSwitcher.action.transition.entry.line2="{{setTransition}}Establecer el tipo de transición en {{transitions}}"
|
||||
AdvSceneSwitcher.action.transition.entry.line3="{{setDuration}}Establecer la duración de la transición en {{duration}}segundos"
|
||||
AdvSceneSwitcher.action.timer="Temporizador"
|
||||
AdvSceneSwitcher.action.timer.type.pause="Pausa"
|
||||
AdvSceneSwitcher.action.timer.type.continue="Continuar"
|
||||
@@ -675,6 +681,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"
|
||||
|
||||
@@ -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"
|
||||
@@ -78,6 +78,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\" ?"
|
||||
@@ -131,6 +132,7 @@ AdvSceneSwitcher.macroList.deleted="supprimé"
|
||||
AdvSceneSwitcher.macroList.duplicate="\"%1\" est déjà sélectionné !"
|
||||
|
||||
; Macro Logic
|
||||
AdvSceneSwitcher.logic.none="Ignorer l'entrée"
|
||||
AdvSceneSwitcher.logic.and="Et"
|
||||
AdvSceneSwitcher.logic.or="Ou"
|
||||
AdvSceneSwitcher.logic.andNot="Et pas"
|
||||
@@ -186,6 +188,8 @@ AdvSceneSwitcher.condition.file="Fichier"
|
||||
AdvSceneSwitcher.condition.file.type.match="correspond à"
|
||||
AdvSceneSwitcher.condition.file.type.contentChange="a changé de contenu"
|
||||
AdvSceneSwitcher.condition.file.type.dateChange="a changé de date de modification"
|
||||
AdvSceneSwitcher.condition.file.remote="Fichier distant"
|
||||
AdvSceneSwitcher.condition.file.local="Fichier local"
|
||||
AdvSceneSwitcher.condition.media="Média"
|
||||
AdvSceneSwitcher.condition.media.source="Source"
|
||||
AdvSceneSwitcher.condition.media.anyOnScene="Toute source média sur la scène"
|
||||
@@ -278,8 +282,8 @@ AdvSceneSwitcher.condition.record.state.start="Enregistrement en cours"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Enregistrement en pause"
|
||||
AdvSceneSwitcher.condition.record.state.stop="Arrêt de l'enregistrement"
|
||||
AdvSceneSwitcher.condition.process="Processus"
|
||||
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}en cours d'exécution{{focused}}et est au premier plan"
|
||||
AdvSceneSwitcher.condition.process.layout.focus="Processus au premier plan actuel :{{focusProcess}}"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}en cours d'exécution{{focused}}et est au premier plan"
|
||||
AdvSceneSwitcher.condition.process.entry.focus="Processus au premier plan actuel :{{focusProcess}}"
|
||||
AdvSceneSwitcher.condition.idle="Inactif"
|
||||
AdvSceneSwitcher.condition.idle.entry="Aucune entrée de clavier ou de souris pendant{{duration}}"
|
||||
AdvSceneSwitcher.condition.pluginState="État du plugin"
|
||||
@@ -352,14 +356,14 @@ AdvSceneSwitcher.condition.replay.state.stopped="Tampon de répétition arrêté
|
||||
AdvSceneSwitcher.condition.replay.state.started="Tampon de répétition démarré"
|
||||
AdvSceneSwitcher.condition.replay.state.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"
|
||||
@@ -370,12 +374,11 @@ AdvSceneSwitcher.condition.date.ignoreDate="Si non cochée, la composante date s
|
||||
AdvSceneSwitcher.condition.date.ignoreTime="Si non cochée, la composante heure sera ignorée"
|
||||
AdvSceneSwitcher.condition.date.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"
|
||||
@@ -456,6 +459,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"
|
||||
@@ -507,7 +512,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"
|
||||
@@ -550,7 +555,7 @@ AdvSceneSwitcher.action.macro="Macro"
|
||||
AdvSceneSwitcher.action.macro.type.pause="Pause"
|
||||
AdvSceneSwitcher.action.macro.type.unpause="Reprendre"
|
||||
AdvSceneSwitcher.action.macro.type.resetCounter="Réinitialiser le compteur"
|
||||
AdvSceneSwitcher.action.macro.type.runActions="Exécuter les actions"
|
||||
AdvSceneSwitcher.action.macro.type.run="Exécuter les actions"
|
||||
AdvSceneSwitcher.action.macro.type.stop="Arrêter les actions"
|
||||
AdvSceneSwitcher.action.macro.type.disableAction="Désactiver l'action"
|
||||
AdvSceneSwitcher.action.macro.type.enableAction="Activer l'action"
|
||||
@@ -619,9 +624,9 @@ AdvSceneSwitcher.action.transition.type.scene="Transition de scène"
|
||||
AdvSceneSwitcher.action.transition.type.sceneOverride="Remplacement de la transition de scène"
|
||||
AdvSceneSwitcher.action.transition.type.sourceShow="Transition d'affichage de la source"
|
||||
AdvSceneSwitcher.action.transition.type.sourceHide="Transition de masquage de la source"
|
||||
AdvSceneSwitcher.action.transition.layout.type="Modifier{{type}}{{scenes}}{{sources}}"
|
||||
AdvSceneSwitcher.action.transition.layout.transition="{{setTransition}}Définir le type de transition sur{{transitions}}"
|
||||
AdvSceneSwitcher.action.transition.layout.duration="{{setDuration}}Définir la durée de la transition à{{duration}}secondes"
|
||||
AdvSceneSwitcher.action.transition.entry.line1="Modifier{{type}}{{scenes}}{{sources}}"
|
||||
AdvSceneSwitcher.action.transition.entry.line2="{{setTransition}}Définir le type de transition sur{{transitions}}"
|
||||
AdvSceneSwitcher.action.transition.entry.line3="{{setDuration}}Définir la durée de la transition à{{duration}}secondes"
|
||||
AdvSceneSwitcher.action.timer="Minuterie"
|
||||
AdvSceneSwitcher.action.timer.type.pause="Mettre en pause"
|
||||
AdvSceneSwitcher.action.timer.type.continue="Continuer"
|
||||
@@ -698,8 +703,8 @@ AdvSceneSwitcher.action.variable.invalidSelection="Sélection invalide !"
|
||||
AdvSceneSwitcher.action.variable.actionNoVariableSupport="La récupération de valeurs de variables à partir d'actions %1 n'est pas prise en charge !"
|
||||
AdvSceneSwitcher.action.variable.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.substringIndex="Début de la sous-chaîne :{{subStringStart}}Taille de la sous-chaîne :{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringRegex="Attribuer la valeur du match{{regexMatchIdx}}en utilisant une expression régulière :"
|
||||
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.projector="Projecteur"
|
||||
@@ -1102,15 +1107,15 @@ AdvSceneSwitcher.sceneItemSelection.configure="Configurer le type de sélection
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName="Nom de la source"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.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"
|
||||
|
||||
@@ -1119,6 +1124,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
@@ -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"
|
||||
@@ -147,6 +147,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."
|
||||
@@ -239,6 +240,7 @@ AdvSceneSwitcher.macroList.deleted="excluída"
|
||||
AdvSceneSwitcher.macroList.duplicate="\"%1\" já está selecionada!"
|
||||
|
||||
; Macro Logic
|
||||
AdvSceneSwitcher.logic.none="Ignorar entrada"
|
||||
AdvSceneSwitcher.logic.and="E"
|
||||
AdvSceneSwitcher.logic.or="Ou"
|
||||
AdvSceneSwitcher.logic.andNot="E não"
|
||||
@@ -294,6 +296,11 @@ AdvSceneSwitcher.condition.file="Arquivo"
|
||||
AdvSceneSwitcher.condition.file.type.match="corresponde"
|
||||
AdvSceneSwitcher.condition.file.type.contentChange="conteúdo mudou"
|
||||
AdvSceneSwitcher.condition.file.type.dateChange="data de modificação mudou"
|
||||
AdvSceneSwitcher.condition.file.remote="Arquivo remoto"
|
||||
AdvSceneSwitcher.condition.file.local="Arquivo local"
|
||||
AdvSceneSwitcher.condition.file.entry.line1="{{fileType}}{{filePath}}{{conditions}}{{useRegex}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFileContent}}"
|
||||
AdvSceneSwitcher.condition.media="Mídia"
|
||||
AdvSceneSwitcher.condition.media.checkType.state="Estado corresponde"
|
||||
AdvSceneSwitcher.condition.media.checkType.time="Restrição de tempo corresponde"
|
||||
@@ -394,8 +401,8 @@ AdvSceneSwitcher.condition.record.state.stop="Gravação parada"
|
||||
AdvSceneSwitcher.condition.record.state.duration="Duração da gravação é maior que"
|
||||
AdvSceneSwitcher.condition.record.entry="{{condition}}{{duration}}"
|
||||
AdvSceneSwitcher.condition.process="Processo"
|
||||
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}está em execução{{focused}}e está em foco"
|
||||
AdvSceneSwitcher.condition.process.layout.focus="Processo atual em primeiro plano:{{focusProcess}}"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}está em execução{{focused}}e está em foco"
|
||||
AdvSceneSwitcher.condition.process.entry.focus="Processo atual em primeiro plano:{{focusProcess}}"
|
||||
AdvSceneSwitcher.condition.idle="Inativo"
|
||||
AdvSceneSwitcher.condition.idle.entry="Sem entradas de teclado ou mouse por {{duration}}"
|
||||
AdvSceneSwitcher.condition.pluginState="Estado do plugin"
|
||||
@@ -495,14 +502,14 @@ AdvSceneSwitcher.condition.replay.state.started="Buffer de replay iniciado"
|
||||
AdvSceneSwitcher.condition.replay.state.saved="Buffer de replay salvo"
|
||||
AdvSceneSwitcher.condition.replay.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"
|
||||
@@ -513,13 +520,12 @@ AdvSceneSwitcher.condition.date.ignoreDate="Se desmarcado, o componente de data
|
||||
AdvSceneSwitcher.condition.date.ignoreTime="Se desmarcado, o componente de tempo será ignorado"
|
||||
AdvSceneSwitcher.condition.date.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"
|
||||
@@ -714,6 +720,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"
|
||||
@@ -748,6 +757,7 @@ AdvSceneSwitcher.action.recording.type.changeOutputFolder="Alterar pasta de saí
|
||||
AdvSceneSwitcher.action.recording.type.changeOutputFileFormat="Alterar formatação do nome do arquivo"
|
||||
AdvSceneSwitcher.action.recording.pause.hint="Observe que dependendo das suas configurações de gravação, você pode não conseguir pausar a gravação"
|
||||
AdvSceneSwitcher.action.recording.split.hint="Certifique-se de habilitar a divisão automática de arquivos nas configurações do OBS primeiro!"
|
||||
AdvSceneSwitcher.action.recording.entry="{{actions}}{{recordFolder}}{{recordFileFormat}}{{pauseHint}}{{splitHint}}"
|
||||
AdvSceneSwitcher.action.replay="Buffer de replay"
|
||||
AdvSceneSwitcher.action.replay.saveWarn="Aviso: Salvar com muita frequência pode resultar em o buffer de replay não ser realmente salvo!"
|
||||
AdvSceneSwitcher.action.replay.durationWarn="Aviso: Alterar o tempo máximo de replay só se aplicará na próxima vez que o buffer de replay for iniciado!"
|
||||
@@ -764,6 +774,7 @@ AdvSceneSwitcher.action.streaming.type.server="Definir URL do servidor"
|
||||
AdvSceneSwitcher.action.streaming.type.streamKey="Definir chave de transmissão"
|
||||
AdvSceneSwitcher.action.streaming.type.username="Definir nome de usuário"
|
||||
AdvSceneSwitcher.action.streaming.type.password="Definir senha"
|
||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
|
||||
AdvSceneSwitcher.action.run="Executar"
|
||||
AdvSceneSwitcher.action.run.wait.entry="{{wait}}Aguardar a saída do processo ou no máximo {{timeout}}{{waitHelp}}"
|
||||
AdvSceneSwitcher.action.run.wait.help.tooltip="Observe que as propriedades da macro não funcionarão se você deixar isso desmarcado, pois o processo é iniciado de forma independente do restante da lógica e não há controle sobre ele."
|
||||
@@ -773,7 +784,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.hide="Ocultar"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.toggle="Alternar"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.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"
|
||||
@@ -838,7 +849,7 @@ AdvSceneSwitcher.action.macro="Macro"
|
||||
AdvSceneSwitcher.action.macro.type.pause="Pausar"
|
||||
AdvSceneSwitcher.action.macro.type.unpause="Retomar"
|
||||
AdvSceneSwitcher.action.macro.type.resetCounter="Reiniciar contador"
|
||||
AdvSceneSwitcher.action.macro.type.runActions="Executar macro"
|
||||
AdvSceneSwitcher.action.macro.type.run="Executar macro"
|
||||
AdvSceneSwitcher.action.macro.type.run.conditions.ignore="Não considerar o estado da condição"
|
||||
AdvSceneSwitcher.action.macro.type.run.conditions.true="Apenas se as condições forem verdadeiras"
|
||||
AdvSceneSwitcher.action.macro.type.run.conditions.false="Apenas se as condições forem falsas"
|
||||
@@ -853,9 +864,9 @@ AdvSceneSwitcher.action.macro.type.stop="Parar ações"
|
||||
AdvSceneSwitcher.action.macro.type.disableAction="Desabilitar ação"
|
||||
AdvSceneSwitcher.action.macro.type.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:"
|
||||
@@ -863,7 +874,7 @@ AdvSceneSwitcher.action.pluginState.type.import="Importar configurações de"
|
||||
AdvSceneSwitcher.action.pluginState.importWarning="Nota: Ação será ignorada enquanto a janela de configurações estiver aberta."
|
||||
AdvSceneSwitcher.action.pluginState.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"
|
||||
@@ -925,9 +936,9 @@ AdvSceneSwitcher.action.transition.type.scene="transição de cena"
|
||||
AdvSceneSwitcher.action.transition.type.sceneOverride="substituição de transição de cena"
|
||||
AdvSceneSwitcher.action.transition.type.sourceShow="transição de exibição de fonte"
|
||||
AdvSceneSwitcher.action.transition.type.sourceHide="transição de ocultação de fonte"
|
||||
AdvSceneSwitcher.action.transition.layout.type="Modificar{{type}}{{scenes}}{{sources}}"
|
||||
AdvSceneSwitcher.action.transition.layout.transition="{{setTransition}}Definir tipo de transição para{{transitions}}"
|
||||
AdvSceneSwitcher.action.transition.layout.duration="{{setDuration}}Definir duração da transição para{{duration}}segundos"
|
||||
AdvSceneSwitcher.action.transition.entry.line1="Modificar{{type}}{{scenes}}{{sources}}"
|
||||
AdvSceneSwitcher.action.transition.entry.line2="{{setTransition}}Definir tipo de transição para{{transitions}}"
|
||||
AdvSceneSwitcher.action.transition.entry.line3="{{setDuration}}Definir duração da transição para{{duration}}segundos"
|
||||
AdvSceneSwitcher.action.timer="Temporizador"
|
||||
AdvSceneSwitcher.action.timer.type.pause="Pausar"
|
||||
AdvSceneSwitcher.action.timer.type.continue="Continuar"
|
||||
@@ -1022,8 +1033,8 @@ AdvSceneSwitcher.action.variable.conditionNoVariableSupport="Obter valores de va
|
||||
AdvSceneSwitcher.action.variable.currentSegmentValue="Valor atual:"
|
||||
AdvSceneSwitcher.action.variable.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.substringIndex="Início da substring:{{subStringStart}}Tamanho da substring:{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringRegex="Atribuir valor do{{regexMatchIdx}}correspondência usando expressão regular:"
|
||||
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}}"
|
||||
@@ -1057,8 +1068,8 @@ AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.enable="Habilitar modo apenas
|
||||
AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.disable="Desabilitar modo apenas emotes no chat"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.sendMessage="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}}{{pointsReward}}"
|
||||
AdvSceneSwitcher.action.twitch.entry.chat="Usando conta{{account}}{{actions}}em{{channel}}"
|
||||
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"
|
||||
@@ -1840,19 +1851,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"
|
||||
|
||||
@@ -1863,6 +1874,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"
|
||||
|
||||
@@ -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="Вещание"
|
||||
@@ -70,6 +70,7 @@ AdvSceneSwitcher.macroTab.name="Имя:"
|
||||
AdvSceneSwitcher.macroTab.defaultname="Макрос %1"
|
||||
AdvSceneSwitcher.macroTab.copy="Создать копию"
|
||||
; Macro Logic
|
||||
AdvSceneSwitcher.logic.none="Игнорировать вход"
|
||||
AdvSceneSwitcher.logic.and="И"
|
||||
AdvSceneSwitcher.logic.or="Или"
|
||||
AdvSceneSwitcher.logic.andNot="И не"
|
||||
@@ -84,6 +85,8 @@ AdvSceneSwitcher.condition.scene.type.current="Текущий"
|
||||
AdvSceneSwitcher.condition.scene.type.previous="Предыдущий"
|
||||
AdvSceneSwitcher.condition.window="Окно"
|
||||
AdvSceneSwitcher.condition.file="Файл"
|
||||
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFileContent}}"
|
||||
AdvSceneSwitcher.condition.media="Медиа"
|
||||
AdvSceneSwitcher.condition.video="Видео"
|
||||
AdvSceneSwitcher.condition.video.condition.match="точно соответствует"
|
||||
@@ -102,7 +105,7 @@ AdvSceneSwitcher.condition.record.state.start="Запись запущена"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Запись приостановлена"
|
||||
AdvSceneSwitcher.condition.record.state.stop="Запись остановлена"
|
||||
AdvSceneSwitcher.condition.process="Процесс"
|
||||
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}запущен{{focused}}и сфокусирован"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}запущен{{focused}}и сфокусирован"
|
||||
AdvSceneSwitcher.condition.idle="Простой"
|
||||
AdvSceneSwitcher.condition.idle.entry="Не было ни клавиатуры, ни мыши в течении{{duration}}"
|
||||
AdvSceneSwitcher.condition.pluginState="Состояние плагина"
|
||||
@@ -111,6 +114,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="случайный"
|
||||
@@ -127,6 +131,7 @@ AdvSceneSwitcher.action.recording.type.start="Начать запись"
|
||||
AdvSceneSwitcher.action.recording.type.pause="Пауза записи"
|
||||
AdvSceneSwitcher.action.recording.type.unpause="Снять запись с паузы"
|
||||
AdvSceneSwitcher.action.recording.pause.hint="Обратите внимание, что в зависимости от настроек записи вы можете не иметь возможности приостановить запись"
|
||||
AdvSceneSwitcher.action.recording.entry="{{actions}}{{recordFolder}}{{recordFileFormat}}{{pauseHint}}{{splitHint}}"
|
||||
AdvSceneSwitcher.action.replay="Буфер воспроизведения"
|
||||
AdvSceneSwitcher.action.replay.type.stop="Остановить буфер воспроизведения"
|
||||
AdvSceneSwitcher.action.replay.type.start="Начать воспроизведение буфера"
|
||||
@@ -134,6 +139,7 @@ AdvSceneSwitcher.action.replay.type.save="Сохранить буфер восп
|
||||
AdvSceneSwitcher.action.streaming="Потоковое вещание"
|
||||
AdvSceneSwitcher.action.streaming.type.stop="Остановить потоковое вещание"
|
||||
AdvSceneSwitcher.action.streaming.type.start="Начать потоковое вещание"
|
||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
|
||||
AdvSceneSwitcher.action.run="Запустить"
|
||||
|
||||
|
||||
|
||||
@@ -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"
|
||||
@@ -72,12 +72,14 @@ 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"
|
||||
AdvSceneSwitcher.macroTab.collapseAll="Hepsini Küçült"
|
||||
|
||||
; Macro Logic
|
||||
AdvSceneSwitcher.logic.none="Girişi yoksay"
|
||||
AdvSceneSwitcher.logic.and="Ve"
|
||||
AdvSceneSwitcher.logic.or="Ya da"
|
||||
AdvSceneSwitcher.logic.andNot="ve değil"
|
||||
@@ -106,7 +108,9 @@ AdvSceneSwitcher.condition.scene.type.notChanged="Sahne değişmedi"
|
||||
AdvSceneSwitcher.condition.scene.currentSceneTransitionBehaviour="Geçiş hedefi sahnesi için geçiş kontrolü sırasında"
|
||||
AdvSceneSwitcher.condition.window="Pencere"
|
||||
AdvSceneSwitcher.condition.file="Dosya"
|
||||
AdvSceneSwitcher.condition.file.layout="İçerik{{filePath}}{{conditions}}{{regex}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line1="İçerik{{fileType}}{{filePath}}{{conditions}}{{useRegex}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFileContent}}"
|
||||
AdvSceneSwitcher.condition.media="Medya"
|
||||
AdvSceneSwitcher.condition.media.anyOnScene="Herhangi bir medya kaynağı"
|
||||
AdvSceneSwitcher.condition.media.allOnScene="Tüm medya kaynakları "
|
||||
@@ -149,7 +153,7 @@ AdvSceneSwitcher.condition.record.state.start="Kayıt Çalışıyor"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Kayıt durakladı"
|
||||
AdvSceneSwitcher.condition.record.state.stop="Kayıt durdu"
|
||||
AdvSceneSwitcher.condition.process="İşlem"
|
||||
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}çalışıyor{{focused}}ve odaklandı"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}çalışıyor{{focused}}ve odaklandı"
|
||||
AdvSceneSwitcher.condition.idle="Boşta"
|
||||
AdvSceneSwitcher.condition.idle.entry="...için klavye veya fare girişi yok {{duration}}"
|
||||
AdvSceneSwitcher.condition.pluginState="Eklenti durumu"
|
||||
@@ -245,6 +249,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"
|
||||
@@ -262,6 +267,7 @@ AdvSceneSwitcher.action.recording.type.start="Kayıt Başlat"
|
||||
AdvSceneSwitcher.action.recording.type.pause="Kayıt Duraklat"
|
||||
AdvSceneSwitcher.action.recording.type.unpause="Kayıt Duraklatma"
|
||||
AdvSceneSwitcher.action.recording.pause.hint="Kayıt ayarlarınıza bağlı olarak kaydı duraklatamayabileceğinizi unutmayın."
|
||||
AdvSceneSwitcher.action.recording.entry="{{actions}}{{recordFolder}}{{recordFileFormat}}{{pauseHint}}{{splitHint}}"
|
||||
AdvSceneSwitcher.action.replay="Tekrar arabelleği"
|
||||
AdvSceneSwitcher.action.replay.type.stop="Tekrar arabelleğini durdur"
|
||||
AdvSceneSwitcher.action.replay.type.start="Tekrar arabelleğini başlat"
|
||||
@@ -269,13 +275,14 @@ AdvSceneSwitcher.action.replay.type.save="Tekrar arabelleğini kaydet"
|
||||
AdvSceneSwitcher.action.streaming="Yayın"
|
||||
AdvSceneSwitcher.action.streaming.type.stop="Yayın durdur"
|
||||
AdvSceneSwitcher.action.streaming.type.start="Yayın başlat"
|
||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
|
||||
AdvSceneSwitcher.action.run="Çalıştır"
|
||||
AdvSceneSwitcher.action.sceneVisibility="Sahne öğesi görünürlüğü"
|
||||
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"
|
||||
@@ -299,13 +306,13 @@ AdvSceneSwitcher.action.macro="Makro"
|
||||
AdvSceneSwitcher.action.macro.type.pause="Duraklat"
|
||||
AdvSceneSwitcher.action.macro.type.unpause="Duraklatma"
|
||||
AdvSceneSwitcher.action.macro.type.resetCounter="Sayacı sıfırla"
|
||||
AdvSceneSwitcher.action.macro.type.runActions="Çalıştır"
|
||||
AdvSceneSwitcher.action.macro.type.run="Çalıştır"
|
||||
AdvSceneSwitcher.action.pluginState="Eklenti durumu"
|
||||
AdvSceneSwitcher.action.pluginState.type.stop="Advanced Scene Switcher eklentisini durdurun"
|
||||
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"
|
||||
@@ -336,8 +343,8 @@ AdvSceneSwitcher.action.file.type.write="Yaz"
|
||||
AdvSceneSwitcher.action.file.type.append="Ekle"
|
||||
AdvSceneSwitcher.action.file.entry="{{actions}} {{filePath}}:"
|
||||
AdvSceneSwitcher.action.transition="Geçiş"
|
||||
AdvSceneSwitcher.action.transition.layout.transition="{{setTransition}}Geçiş türünü ayarla {{transitions}}"
|
||||
AdvSceneSwitcher.action.transition.layout.duration="{{setDuration}}Geçiş süresini şuna ayarla: {{duration}}saniyeler"
|
||||
AdvSceneSwitcher.action.transition.entry.line2="{{setTransition}}Geçiş türünü ayarla {{transitions}}"
|
||||
AdvSceneSwitcher.action.transition.entry.line3="{{setDuration}}Geçiş süresini şuna ayarla: {{duration}}saniyeler"
|
||||
AdvSceneSwitcher.action.timer="Zamanlayıcı"
|
||||
AdvSceneSwitcher.action.timer.type.pause="Duraklat"
|
||||
AdvSceneSwitcher.action.timer.type.continue="Devam et"
|
||||
@@ -581,6 +588,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"
|
||||
|
||||
@@ -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="直播"
|
||||
@@ -151,6 +151,7 @@ AdvSceneSwitcher.macroTab.run.tooltip="无论条件如何,都运行所有宏
|
||||
AdvSceneSwitcher.macroTab.runElse="运行宏(不满足条件)"
|
||||
AdvSceneSwitcher.macroTab.runFail="运行 \"%1\" 失败!\n要么其中一个操作失败,要么宏已在运行中.\n你想停止它吗?"
|
||||
AdvSceneSwitcher.macroTab.runInParallel="与其他宏并行运行宏"
|
||||
AdvSceneSwitcher.macroTab.onChange="仅在条件结果发生变化时执行操作(条件结果不变时只执行一次操作)"
|
||||
AdvSceneSwitcher.macroTab.defaultname="宏 %1"
|
||||
AdvSceneSwitcher.macroTab.defaultGroupName="分组 %1"
|
||||
AdvSceneSwitcher.macroTab.macroNameExists="名称 \"%1\" 已被宏使用."
|
||||
@@ -259,6 +260,7 @@ AdvSceneSwitcher.macroList.deleted="删除"
|
||||
AdvSceneSwitcher.macroList.duplicate="\"%1\" 已选择!"
|
||||
|
||||
; Macro Logic
|
||||
AdvSceneSwitcher.logic.none="忽略条件"
|
||||
AdvSceneSwitcher.logic.and="且"
|
||||
AdvSceneSwitcher.logic.or="或"
|
||||
AdvSceneSwitcher.logic.andNot="且不"
|
||||
@@ -317,7 +319,11 @@ AdvSceneSwitcher.condition.file="文件"
|
||||
AdvSceneSwitcher.condition.file.type.match="内容匹配"
|
||||
AdvSceneSwitcher.condition.file.type.contentChange="内容发生改变"
|
||||
AdvSceneSwitcher.condition.file.type.dateChange="修改日期发生改变"
|
||||
AdvSceneSwitcher.condition.file.layout="{{filePath}}{{conditions}}{{regex}}"
|
||||
AdvSceneSwitcher.condition.file.remote="网络文件"
|
||||
AdvSceneSwitcher.condition.file.local="本地文件"
|
||||
AdvSceneSwitcher.condition.file.entry.line1="{{fileType}}{{filePath}}{{conditions}}{{useRegex}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFileContent}}"
|
||||
AdvSceneSwitcher.condition.media="媒体"
|
||||
AdvSceneSwitcher.condition.media.checkType.state="状态匹配"
|
||||
AdvSceneSwitcher.condition.media.checkType.time="时间限制匹配"
|
||||
@@ -423,8 +429,8 @@ AdvSceneSwitcher.condition.record.state.stop="录制停止"
|
||||
AdvSceneSwitcher.condition.record.state.duration="录制时间长于"
|
||||
AdvSceneSwitcher.condition.record.entry="{{condition}}{{duration}}"
|
||||
AdvSceneSwitcher.condition.process="进程"
|
||||
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}为正在运行中{{focused}}且为焦点"
|
||||
AdvSceneSwitcher.condition.process.layout.focus="当前焦点进程: {{focusProcess}}"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}为正在运行中{{focused}}且为焦点"
|
||||
AdvSceneSwitcher.condition.process.entry.focus="当前焦点进程: {{focusProcess}}"
|
||||
AdvSceneSwitcher.condition.idle="闲置检测"
|
||||
AdvSceneSwitcher.condition.idle.entry="{{duration}}内没有键盘或鼠标输入"
|
||||
AdvSceneSwitcher.condition.pluginState="插件状态"
|
||||
@@ -524,14 +530,14 @@ AdvSceneSwitcher.condition.replay.state.started="回放缓存已启动"
|
||||
AdvSceneSwitcher.condition.replay.state.saved="已保存回放缓存"
|
||||
AdvSceneSwitcher.condition.replay.entry="{{state}}"
|
||||
AdvSceneSwitcher.condition.date="日期"
|
||||
AdvSceneSwitcher.day.any="每一天"
|
||||
AdvSceneSwitcher.day.monday="周一"
|
||||
AdvSceneSwitcher.day.tuesday="周二"
|
||||
AdvSceneSwitcher.day.wednesday="周三"
|
||||
AdvSceneSwitcher.day.thursday="周四"
|
||||
AdvSceneSwitcher.day.friday="周五"
|
||||
AdvSceneSwitcher.day.saturday="周六"
|
||||
AdvSceneSwitcher.day.sunday="周日"
|
||||
AdvSceneSwitcher.condition.date.anyDay="每一天"
|
||||
AdvSceneSwitcher.condition.date.monday="周一"
|
||||
AdvSceneSwitcher.condition.date.tuesday="周二"
|
||||
AdvSceneSwitcher.condition.date.wednesday="周三"
|
||||
AdvSceneSwitcher.condition.date.thursday="周四"
|
||||
AdvSceneSwitcher.condition.date.friday="周五"
|
||||
AdvSceneSwitcher.condition.date.saturday="周六"
|
||||
AdvSceneSwitcher.condition.date.sunday="周日"
|
||||
AdvSceneSwitcher.condition.date.state.at="现在"
|
||||
AdvSceneSwitcher.condition.date.state.after="之后"
|
||||
AdvSceneSwitcher.condition.date.state.before="之前"
|
||||
@@ -542,13 +548,12 @@ AdvSceneSwitcher.condition.date.ignoreDate="如果未选中,日期组件将被
|
||||
AdvSceneSwitcher.condition.date.ignoreTime="如果未选中,时间组件将被忽略"
|
||||
AdvSceneSwitcher.condition.date.showAdvancedSettings="显示高级设置"
|
||||
AdvSceneSwitcher.condition.date.showSimpleSettings="显示简单设置"
|
||||
AdvSceneSwitcher.condition.date.layout.simple.day="{{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}} 每 {{duration}} 重复一次时间/日期匹配"
|
||||
AdvSceneSwitcher.condition.date.layout.pattern="当前日期 \"{{currentDate}}\" 与 {{pattern}} 模式匹配 , 例子:2025 03 18 24 00 00 = .... .. .. .. .. .. ,难崩,我测试了一段时间才明白"
|
||||
AdvSceneSwitcher.condition.date.layout.nextMatchDate="下一次匹配 在: %1"
|
||||
AdvSceneSwitcher.condition.date.layout.updateOnRepeat="{{updateOnRepeat}} 在重复时将选定日期更新为重复日期"
|
||||
AdvSceneSwitcher.condition.date.entry.simple="{{dayOfWeek}}{{weekCondition}}{{ignoreWeekTime}}{{weekTime}}"
|
||||
AdvSceneSwitcher.condition.date.entry.advanced="{{condition}}{{ignoreDate}}{{date}}{{ignoreTime}}{{time}}{{separator}}{{date2}}{{time2}}"
|
||||
AdvSceneSwitcher.condition.date.entry.repeat="{{repeat}} 每 {{duration}} 重复一次时间/日期匹配"
|
||||
AdvSceneSwitcher.condition.date.entry.pattern="当前日期 \"{{currentDate}}\" 与 {{pattern}} 模式匹配 , 例子:2025 03 18 24 00 00 = .... .. .. .. .. .. ,难崩,我测试了一段时间才明白"
|
||||
AdvSceneSwitcher.condition.date.entry.nextMatchDate="下一次匹配 在: %1"
|
||||
AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}} 在重复时将选定日期更新为重复日期"
|
||||
AdvSceneSwitcher.condition.sceneTransform="场景项目变换"
|
||||
AdvSceneSwitcher.condition.sceneTransform.getTransform="获取变换"
|
||||
AdvSceneSwitcher.condition.sceneTransform.getCurrentValue="获取当前值"
|
||||
@@ -693,7 +698,7 @@ AdvSceneSwitcher.condition.twitch.type.event.channel.user.moderator.deletion="
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.stream.online.live="开始直播"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.stream.online.playlist="开始播放列表"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.stream.online.watchParty="开始观看派对"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.stream.online.premiere="开始首播"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.stream.online.premiere="开始首播
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.stream.online.rerun="开始重播"
|
||||
AdvSceneSwitcher.condition.twitch.type.polling.channel.live="当前正在直播"
|
||||
AdvSceneSwitcher.condition.twitch.type.polling.channel.title="当前为头衔赛"
|
||||
@@ -774,6 +779,9 @@ AdvSceneSwitcher.action.unknown="未知操作"
|
||||
AdvSceneSwitcher.action.scene="切换场景"
|
||||
AdvSceneSwitcher.action.scene.type.program="程序"
|
||||
AdvSceneSwitcher.action.scene.type.preview="预览"
|
||||
AdvSceneSwitcher.action.scene.entry="切换到场景{{sceneTypes}}{{scenes}}使用{{transitions}}时长{{duration}}秒"
|
||||
AdvSceneSwitcher.action.scene.entry.noDuration="切换到场景{{sceneTypes}}{{scenes}}使用{{transitions}}"
|
||||
AdvSceneSwitcher.action.scene.entry.preview="将{{sceneTypes}}场景切换到{{scenes}}"
|
||||
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="等待转场到目标场景的动画完成"
|
||||
AdvSceneSwitcher.action.wait="等待"
|
||||
AdvSceneSwitcher.action.wait.type.fixed="固定"
|
||||
@@ -808,6 +816,7 @@ AdvSceneSwitcher.action.recording.type.changeOutputFolder="更改输出文件夹
|
||||
AdvSceneSwitcher.action.recording.type.changeOutputFileFormat="改变文件名的格式"
|
||||
AdvSceneSwitcher.action.recording.pause.hint="请注意,根据您的录制设置,您可能无法暂停录制"
|
||||
AdvSceneSwitcher.action.recording.split.hint="注意,请先确保在OBS设置中启用自动分割文件!"
|
||||
AdvSceneSwitcher.action.recording.entry="{{actions}}{{recordFolder}}{{recordFileFormat}}{{pauseHint}}{{splitHint}}"
|
||||
AdvSceneSwitcher.action.replay="回放缓存"
|
||||
AdvSceneSwitcher.action.replay.saveWarn="警告:保存过于频繁可能会导致回放缓存实际上未保存!"
|
||||
AdvSceneSwitcher.action.replay.durationWarn="警告:更改回放缓存时长上限,仅适用于下次回放缓存开启时!"
|
||||
@@ -824,6 +833,7 @@ AdvSceneSwitcher.action.streaming.type.server="设置服务器"
|
||||
AdvSceneSwitcher.action.streaming.type.streamKey="设置推流码"
|
||||
AdvSceneSwitcher.action.streaming.type.username="设置用户名"
|
||||
AdvSceneSwitcher.action.streaming.type.password="设置密码"
|
||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
|
||||
AdvSceneSwitcher.action.run="运行"
|
||||
AdvSceneSwitcher.action.run.wait.entry="{{wait}}进程退出或最多等待{{timeout}}{{waitHelp}}"
|
||||
AdvSceneSwitcher.action.run.wait.help.tooltip="请注意,如果不勾选此选项,宏属性将不起作用,因为进程的启动会脱离逻辑的其他部分,因此无法对其进行控制."
|
||||
@@ -833,7 +843,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.hide="隐藏"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.toggle="切换可见性"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.source="源"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="任何"
|
||||
AdvSceneSwitcher.action.sceneVisibility.layout="{{scenes}}{{actions}}{{sources}}"
|
||||
AdvSceneSwitcher.action.sceneVisibility.entry="{{scenes}}{{actions}}{{sources}}"
|
||||
AdvSceneSwitcher.action.filter="滤镜"
|
||||
AdvSceneSwitcher.action.filter.type.enable="开启"
|
||||
AdvSceneSwitcher.action.filter.type.disable="关闭"
|
||||
@@ -898,7 +908,7 @@ AdvSceneSwitcher.action.macro="宏"
|
||||
AdvSceneSwitcher.action.macro.type.pause="停用"
|
||||
AdvSceneSwitcher.action.macro.type.unpause="启用"
|
||||
AdvSceneSwitcher.action.macro.type.resetCounter="重置计数器"
|
||||
AdvSceneSwitcher.action.macro.type.runActions="运行宏"
|
||||
AdvSceneSwitcher.action.macro.type.run="运行宏"
|
||||
AdvSceneSwitcher.action.macro.type.run.conditions.ignore="忽略条件结果"
|
||||
AdvSceneSwitcher.action.macro.type.run.conditions.true="仅当条件结果为真时"
|
||||
AdvSceneSwitcher.action.macro.type.run.conditions.false="仅当条件结果为假时"
|
||||
@@ -913,9 +923,9 @@ AdvSceneSwitcher.action.macro.type.stop="停止操作"
|
||||
AdvSceneSwitcher.action.macro.type.disableAction="停用操作"
|
||||
AdvSceneSwitcher.action.macro.type.enableAction="启用操作"
|
||||
AdvSceneSwitcher.action.macro.type.toggleAction="切换操作开关"
|
||||
AdvSceneSwitcher.action.macro.layout.run="{{actions}}{{actionSections}}{{macros}}"
|
||||
AdvSceneSwitcher.action.macro.layout.run.condition="{{conditionBehaviors}}{{conditionMacros}}"
|
||||
AdvSceneSwitcher.action.macro.layout.other="{{actions}}{{macros}}"
|
||||
AdvSceneSwitcher.action.macro.entry.run="{{actions}}{{actionTypes}}{{macros}}"
|
||||
AdvSceneSwitcher.action.macro.entry.run.condition="{{conditionBehaviors}}{{conditionMacros}}"
|
||||
AdvSceneSwitcher.action.macro.entry.other="{{actions}}{{actionIndex}}{{macros}}"
|
||||
AdvSceneSwitcher.action.pluginState="插件状态"
|
||||
AdvSceneSwitcher.action.pluginState.type.stop="停止高级场景切换插件"
|
||||
AdvSceneSwitcher.action.pluginState.type.noMatch="没有匹配项时:"
|
||||
@@ -923,7 +933,7 @@ AdvSceneSwitcher.action.pluginState.type.import="导入设置"
|
||||
AdvSceneSwitcher.action.pluginState.importWarning="注意:当设置窗口打开时,操作将被忽略."
|
||||
AdvSceneSwitcher.action.pluginState.type.terminate="关闭OBS"
|
||||
AdvSceneSwitcher.action.pluginState.terminateConfirm="OBS将在10秒后自动关闭!\n你想继续关闭OBS吗?"
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}"
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
|
||||
AdvSceneSwitcher.action.virtualCamera="虚拟摄像机"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.stop="停止虚拟摄像机"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.start="启动虚拟摄像机"
|
||||
@@ -987,9 +997,9 @@ AdvSceneSwitcher.action.transition.type.scene="场景转场动画"
|
||||
AdvSceneSwitcher.action.transition.type.sceneOverride="覆盖场景转场动画"
|
||||
AdvSceneSwitcher.action.transition.type.sourceShow="显示源转场动画"
|
||||
AdvSceneSwitcher.action.transition.type.sourceHide="隐藏源转场动画"
|
||||
AdvSceneSwitcher.action.transition.layout.type="更改 {{type}}{{scenes}}{{sources}}"
|
||||
AdvSceneSwitcher.action.transition.layout.transition="{{setTransition}}将转场动画类型设置为 {{transitions}}"
|
||||
AdvSceneSwitcher.action.transition.layout.duration="{{setDuration}}将转场动画时长设置为 {{duration}}秒"
|
||||
AdvSceneSwitcher.action.transition.entry.line1="更改 {{type}}{{scenes}}{{sources}}"
|
||||
AdvSceneSwitcher.action.transition.entry.line2="{{setTransition}}将转场动画类型设置为 {{transitions}}"
|
||||
AdvSceneSwitcher.action.transition.entry.line3="{{setDuration}}将转场动画时长设置为 {{duration}}秒"
|
||||
AdvSceneSwitcher.action.timer="计时器"
|
||||
AdvSceneSwitcher.action.timer.type.pause="暂停"
|
||||
AdvSceneSwitcher.action.timer.type.continue="继续"
|
||||
@@ -1093,8 +1103,8 @@ AdvSceneSwitcher.action.variable.conditionNoVariableSupport="不支持从 %1 条
|
||||
AdvSceneSwitcher.action.variable.currentSegmentValue="当前值:"
|
||||
AdvSceneSwitcher.action.variable.layout.pad="{{actions}}于{{variables}}的{{direction}}起,内容为{{paddingCharSelection}}将其变量值长度增加至{{stringLength}}."
|
||||
AdvSceneSwitcher.action.variable.layout.truncate="{{actions}}于{{variables}}的{{direction}}起,将变量长度缩减至{{stringLength}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringIndex="截取字符串开始位置:{{subStringStart}} 截取字符串长度:{{subStringSize}}{{subStringRegex}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringRegex="使用正则表达式为 {{regexMatchIdx}} 匹配的值:{{subStringRegex}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringIndex="截取字符串开始位置:{{subStringStart}} 截取字符串长度:{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringRegex="使用正则表达式为 {{regexMatchIdx}} 匹配的值:"
|
||||
AdvSceneSwitcher.action.variable.layout.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
|
||||
AdvSceneSwitcher.action.variable.layout.userInput.customPrompt="{{useCustomPrompt}}使用自定义提示{{inputPrompt}}"
|
||||
AdvSceneSwitcher.action.variable.layout.userInput.placeholder="{{useInputPlaceholder}}用占位符填充{{inputPlaceholder}}"
|
||||
@@ -1132,17 +1142,10 @@ AdvSceneSwitcher.action.twitch.type.user.getInfo="获取用户信息"
|
||||
AdvSceneSwitcher.action.twitch.type.reward.getInfo="获取频道积分奖励信息"
|
||||
AdvSceneSwitcher.action.twitch.reward.toggleControl="切换奖励名称/变量选择控制"
|
||||
AdvSceneSwitcher.action.twitch.categorySelectionDisabled="在未选择 Twitch 帐户的情况下无法选择类别!"
|
||||
AdvSceneSwitcher.action.twitch.layout.default="{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}{{pointsReward}}{{nonModDelayDuration}}"
|
||||
AdvSceneSwitcher.action.twitch.layout.chat="使用账户{{account}}{{actions}}{{channel}}"
|
||||
AdvSceneSwitcher.action.twitch.layout.channel.getInfo="使用账户{{account}}{{actions}}频道{{channel}}"
|
||||
AdvSceneSwitcher.action.twitch.layout.user.getInfo.row1="使用账户{{account}}{{actions}}"
|
||||
AdvSceneSwitcher.action.twitch.layout.user.getInfo.row2="{{userInfoQueryType}}{{userLogin}}{{userId}}"
|
||||
AdvSceneSwitcher.action.twitch.layout.user.moderation.row1="使用账户{{account}}{{actions}}"
|
||||
AdvSceneSwitcher.action.twitch.layout.user.moderation.row2="频道{{channel}}{{userInfoQueryType}}{{userLogin}}{{userId}}"
|
||||
AdvSceneSwitcher.action.twitch.layout.user.ban.row1="使用账户{{account}}{{actions}}超时{{duration}}"
|
||||
AdvSceneSwitcher.action.twitch.layout.user.ban.row2="频道{{channel}}{{userInfoQueryType}}{{userLogin}}{{userId}}原因{{banReason}}"
|
||||
AdvSceneSwitcher.action.twitch.layout.reward.getInfo.row1="使用账户{{account}}{{actions}} 频道{{channel}}"
|
||||
AdvSceneSwitcher.action.twitch.layout.reward.getInfo.row2="{{pointsReward}}{{rewardVariable}}{{toggleRewardSelection}}"
|
||||
AdvSceneSwitcher.action.twitch.entry.default="{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}{{pointsReward}}"
|
||||
AdvSceneSwitcher.action.twitch.entry.chat="使用账户{{account}}{{actions}}{{channel}}"
|
||||
AdvSceneSwitcher.action.twitch.entry.user.getInfo="使用账户{{account}}{{actions}}{{userInfoQueryType}}{{userLogin}}{{userId}}"
|
||||
AdvSceneSwitcher.action.twitch.entry.reward.getInfo="使用账户{{account}}{{actions}} 频道{{channel}}{{pointsReward}}{{rewardVariable}}{{toggleRewardSelection}}"
|
||||
AdvSceneSwitcher.action.twitch.title.title="输入标题"
|
||||
AdvSceneSwitcher.action.twitch.marker.description="标记描述"
|
||||
AdvSceneSwitcher.action.twitch.clip.hasDelay="在捕捉视频片段前稍加延迟"
|
||||
@@ -2092,19 +2095,21 @@ AdvSceneSwitcher.setting.transform.width="宽度"
|
||||
|
||||
AdvSceneSwitcher.sceneItemSelection.configure="配置场景项目选择类型"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName="源名称"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName.entry="{{nameConflictIndex}}{{sourceName}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable="变量名称"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable.entry="{{nameConflictIndex}}{{variable}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern="源名称与匹配相符"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.layout="{{nameConflictIndex}}匹配{{pattern}}{{regex}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.entry="{{nameConflictIndex}}匹配{{pattern}}{{regex}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceGroup="源分组中的来源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceGroup.layout="{{nameConflictIndex}}{{sourceGroups}}中的源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceGroup.entry="{{sourceGroups}}中的源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType="源类型"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType.layout="源类型{{nameConflictIndex}}{{sourceTypes}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType.entry="源类型{{nameConflictIndex}}{{sourceTypes}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index="附有索引的源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index.layout="{{index}}源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index.entry="{{index}}源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange="索引范围内的源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange.layout="从{{index}}到{{indexEnd}}的源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange.entry="从{{index}}到{{indexEnd}}的源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all="所有源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all.layout="所有源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all.entry="所有源"
|
||||
AdvSceneSwitcher.sceneItemSelection.all="全部"
|
||||
AdvSceneSwitcher.sceneItemSelection.any="任何"
|
||||
|
||||
@@ -2115,6 +2120,8 @@ AdvSceneSwitcher.status.inactive="已停止"
|
||||
AdvSceneSwitcher.running="插件正在运行"
|
||||
AdvSceneSwitcher.stopped="插件已停止"
|
||||
|
||||
AdvSceneSwitcher.firstBootMessage="<html><head/><body><p>这似乎是您第一次启动高级场景切换器.<br>请看一下 <a href=\"https://github.com/WarmUpTill/SceneSwitcher/wiki\"><span style=\" text-decoration: underline; color:#268bd2;\">Wiki</span></a> 查看指南和示例列表.<br>如果有问题,在在OBS论坛插件帖子内提问 <a href=\"https://obsproject.com/forum/threads/advanced-scene-switcher.48264\"><span style=\" text-decoration: underline; color:#268bd2;\">thread</span></a></p></body></html>"
|
||||
|
||||
AdvSceneSwitcher.deprecatedTabWarning="此选项卡的开发已停止!请考虑转换为使用宏来代替。\n可以在“常规”选项卡上禁用此提示."
|
||||
|
||||
AdvSceneSwitcher.unit.milliseconds="毫秒"
|
||||
@@ -2126,9 +2133,9 @@ AdvSceneSwitcher.unit.weeks="周"
|
||||
AdvSceneSwitcher.unit.months="月"
|
||||
AdvSceneSwitcher.unit.years="年"
|
||||
AdvSceneSwitcher.duration.condition.none="没有时间限制"
|
||||
AdvSceneSwitcher.duration.condition.more="时间大于"
|
||||
AdvSceneSwitcher.duration.condition.more="时间少于"
|
||||
AdvSceneSwitcher.duration.condition.equal="时间等于"
|
||||
AdvSceneSwitcher.duration.condition.less="时间少于"
|
||||
AdvSceneSwitcher.duration.condition.less="时间大于"
|
||||
AdvSceneSwitcher.duration.condition.within="最后"
|
||||
|
||||
AdvSceneSwitcher.time.relative="%1 %2 之前"
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg fill="#fefefe" xmlns="http://www.w3.org/2000/svg"
|
||||
width="800px" height="800px" viewBox="0 0 52 52" enable-background="new 0 0 52 52" xml:space="preserve">
|
||||
<path d="M42.6,17.8c2.4,0,7.2-2,7.2-8.4c0-6.4-4.6-6.8-6.1-6.8c-2.8,0-5.6,2-8.1,6.3c-2.5,4.4-5.3,9.1-5.3,9.1
|
||||
l-0.1,0c-0.6-3.1-1.1-5.6-1.3-6.7c-0.5-2.7-3.6-8.4-9.9-8.4c-6.4,0-12.2,3.7-12.2,3.7l0,0C5.8,7.3,5.1,8.5,5.1,9.9
|
||||
c0,2.1,1.7,3.9,3.9,3.9c0.6,0,1.2-0.2,1.7-0.4l0,0c0,0,4.8-2.7,5.9,0c0.3,0.8,0.6,1.7,0.9,2.7c1.2,4.2,2.4,9.1,3.3,13.5l-4.2,6
|
||||
c0,0-4.7-1.7-7.1-1.7s-7.2,2-7.2,8.4s4.6,6.8,6.1,6.8c2.8,0,5.6-2,8.1-6.3c2.5-4.4,5.3-9.1,5.3-9.1c0.8,4,1.5,7.1,1.9,8.5
|
||||
c1.6,4.5,5.3,7.2,10.1,7.2c0,0,5,0,10.9-3.3c1.4-0.6,2.4-2,2.4-3.6c0-2.1-1.7-3.9-3.9-3.9c-0.6,0-1.2,0.2-1.7,0.4l0,0
|
||||
c0,0-4.2,2.4-5.6,0.5c-1-2-1.9-4.6-2.6-7.8c-0.6-2.8-1.3-6.2-2-9.5l4.3-6.2C35.5,16.1,40.2,17.8,42.6,17.8z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 973 B |
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg fill="#202020" xmlns="http://www.w3.org/2000/svg"
|
||||
width="800px" height="800px" viewBox="0 0 52 52" enable-background="new 0 0 52 52" xml:space="preserve">
|
||||
<path d="M42.6,17.8c2.4,0,7.2-2,7.2-8.4c0-6.4-4.6-6.8-6.1-6.8c-2.8,0-5.6,2-8.1,6.3c-2.5,4.4-5.3,9.1-5.3,9.1
|
||||
l-0.1,0c-0.6-3.1-1.1-5.6-1.3-6.7c-0.5-2.7-3.6-8.4-9.9-8.4c-6.4,0-12.2,3.7-12.2,3.7l0,0C5.8,7.3,5.1,8.5,5.1,9.9
|
||||
c0,2.1,1.7,3.9,3.9,3.9c0.6,0,1.2-0.2,1.7-0.4l0,0c0,0,4.8-2.7,5.9,0c0.3,0.8,0.6,1.7,0.9,2.7c1.2,4.2,2.4,9.1,3.3,13.5l-4.2,6
|
||||
c0,0-4.7-1.7-7.1-1.7s-7.2,2-7.2,8.4s4.6,6.8,6.1,6.8c2.8,0,5.6-2,8.1-6.3c2.5-4.4,5.3-9.1,5.3-9.1c0.8,4,1.5,7.1,1.9,8.5
|
||||
c1.6,4.5,5.3,7.2,10.1,7.2c0,0,5,0,10.9-3.3c1.4-0.6,2.4-2,2.4-3.6c0-2.1-1.7-3.9-3.9-3.9c-0.6,0-1.2,0.2-1.7,0.4l0,0
|
||||
c0,0-4.2,2.4-5.6,0.5c-1-2-1.9-4.6-2.6-7.8c-0.6-2.8-1.3-6.2-2-9.5l4.3-6.2C35.5,16.1,40.2,17.8,42.6,17.8z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 973 B |
2
deps/json
vendored
2
deps/json
vendored
Submodule deps/json updated: 55f93686c0...bc889afb4c
2
deps/libusb
vendored
2
deps/libusb
vendored
Submodule deps/libusb updated: 15a7ebb4d4...d52e355daa
58
deps/obs-websocket/lib/obs-websocket-api.h
vendored
58
deps/obs-websocket/lib/obs-websocket-api.h
vendored
@@ -22,7 +22,7 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
|
||||
#include <obs.h>
|
||||
|
||||
#define OBS_WEBSOCKET_API_VERSION 2
|
||||
#define OBS_WEBSOCKET_API_VERSION 3
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -31,6 +31,8 @@ extern "C" {
|
||||
typedef void *obs_websocket_vendor;
|
||||
typedef void (*obs_websocket_request_callback_function)(obs_data_t *,
|
||||
obs_data_t *, void *);
|
||||
typedef void (*obs_websocket_event_callback_function)(uint64_t, const char *,
|
||||
const char *, void *);
|
||||
|
||||
struct obs_websocket_request_response {
|
||||
unsigned int status_code;
|
||||
@@ -45,6 +47,11 @@ struct obs_websocket_request_callback {
|
||||
void *priv_data;
|
||||
};
|
||||
|
||||
struct obs_websocket_event_callback {
|
||||
obs_websocket_event_callback_function callback;
|
||||
void *priv_data;
|
||||
};
|
||||
|
||||
static proc_handler_t *_ph;
|
||||
|
||||
/* ==================== INTERNAL API FUNCTIONS ==================== */
|
||||
@@ -123,7 +130,6 @@ obs_websocket_call_request(const char *request_type, obs_data_t *request_data
|
||||
request_data_string = obs_data_get_json(request_data);
|
||||
|
||||
calldata_t cd = {0, 0, 0, 0};
|
||||
|
||||
calldata_set_string(&cd, "request_type", request_type);
|
||||
calldata_set_string(&cd, "request_data", request_data_string);
|
||||
|
||||
@@ -152,6 +158,48 @@ static inline void obs_websocket_request_response_free(
|
||||
bfree(response);
|
||||
}
|
||||
|
||||
// Register an event handler to receive obs-websocket events
|
||||
static inline bool obs_websocket_register_event_callback(
|
||||
obs_websocket_event_callback_function event_callback, void *priv_data)
|
||||
{
|
||||
if (!obs_websocket_ensure_ph())
|
||||
return false;
|
||||
|
||||
struct obs_websocket_event_callback cb = {event_callback, priv_data};
|
||||
|
||||
calldata_t cd = {0, 0, 0, 0};
|
||||
calldata_set_ptr(&cd, "callback", &cb);
|
||||
|
||||
proc_handler_call(_ph, "register_event_callback", &cd);
|
||||
|
||||
bool ret = calldata_bool(&cd, "success");
|
||||
|
||||
calldata_free(&cd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Unregister an existing event handler
|
||||
static inline bool obs_websocket_unregister_event_callback(
|
||||
obs_websocket_event_callback_function event_callback, void *priv_data)
|
||||
{
|
||||
if (!obs_websocket_ensure_ph())
|
||||
return false;
|
||||
|
||||
struct obs_websocket_event_callback cb = {event_callback, priv_data};
|
||||
|
||||
calldata_t cd = {0, 0, 0, 0};
|
||||
calldata_set_ptr(&cd, "callback", &cb);
|
||||
|
||||
proc_handler_call(_ph, "unregister_event_callback", &cd);
|
||||
|
||||
bool ret = calldata_bool(&cd, "success");
|
||||
|
||||
calldata_free(&cd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ==================== VENDOR API FUNCTIONS ==================== */
|
||||
|
||||
// ALWAYS CALL ONLY VIA `obs_module_post_load()` CALLBACK!
|
||||
@@ -163,7 +211,6 @@ obs_websocket_register_vendor(const char *vendor_name)
|
||||
return NULL;
|
||||
|
||||
calldata_t cd = {0, 0, 0, 0};
|
||||
|
||||
calldata_set_string(&cd, "name", vendor_name);
|
||||
|
||||
proc_handler_call(_ph, "vendor_register", &cd);
|
||||
@@ -179,11 +226,10 @@ static inline bool obs_websocket_vendor_register_request(
|
||||
obs_websocket_request_callback_function request_callback,
|
||||
void *priv_data)
|
||||
{
|
||||
calldata_t cd = {0, 0, 0, 0};
|
||||
|
||||
struct obs_websocket_request_callback cb = {request_callback,
|
||||
priv_data};
|
||||
|
||||
calldata_t cd = {0, 0, 0, 0};
|
||||
calldata_set_string(&cd, "type", request_type);
|
||||
calldata_set_ptr(&cd, "callback", &cb);
|
||||
|
||||
@@ -200,7 +246,6 @@ obs_websocket_vendor_unregister_request(obs_websocket_vendor vendor,
|
||||
const char *request_type)
|
||||
{
|
||||
calldata_t cd = {0, 0, 0, 0};
|
||||
|
||||
calldata_set_string(&cd, "type", request_type);
|
||||
|
||||
bool success = obs_websocket_vendor_run_simple_proc(
|
||||
@@ -217,7 +262,6 @@ static inline bool obs_websocket_vendor_emit_event(obs_websocket_vendor vendor,
|
||||
obs_data_t *event_data)
|
||||
{
|
||||
calldata_t cd = {0, 0, 0, 0};
|
||||
|
||||
calldata_set_string(&cd, "type", event_name);
|
||||
calldata_set_ptr(&cd, "data", (void *)event_data);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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>
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "backup.hpp"
|
||||
#include "crash-handler.hpp"
|
||||
#include "log-helper.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "obs-module-helper.hpp"
|
||||
@@ -147,7 +146,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 +200,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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,7 +334,8 @@ void SwitcherData::SetPreconditions()
|
||||
{
|
||||
// Window title
|
||||
lastTitle = currentTitle;
|
||||
auto title = GetCurrentWindowTitle();
|
||||
std::string title;
|
||||
GetCurrentWindowTitle(title);
|
||||
for (auto &window : ignoreWindowsSwitches) {
|
||||
bool equals = (title == window);
|
||||
bool matches = false;
|
||||
@@ -342,7 +355,7 @@ void SwitcherData::SetPreconditions()
|
||||
currentTitle = title;
|
||||
|
||||
// Process name
|
||||
currentForegroundProcess = GetForegroundProcessName();
|
||||
GetForegroundProcessName(currentForegroundProcess);
|
||||
|
||||
// Macro
|
||||
InvalidateMacroTempVarValues();
|
||||
@@ -417,7 +430,7 @@ bool SwitcherData::CheckForMatch(OBSWeakSource &scene,
|
||||
|
||||
static void ResetMacros()
|
||||
{
|
||||
for (auto &m : GetTopLevelMacros()) {
|
||||
for (auto &m : GetMacros()) {
|
||||
ResetMacroRunCount(m.get());
|
||||
ResetMacroConditionTimers(m.get());
|
||||
}
|
||||
@@ -506,8 +519,6 @@ bool SwitcherData::AnySceneTransitionStarted()
|
||||
******************************************************************************/
|
||||
extern "C" EXPORT void FreeSceneSwitcher()
|
||||
{
|
||||
switcher->Stop();
|
||||
|
||||
PlatformCleanup();
|
||||
RunPluginCleanupSteps();
|
||||
|
||||
@@ -536,7 +547,6 @@ static void handleSceneChange()
|
||||
}
|
||||
|
||||
switcher->checkDefaultSceneTransitions();
|
||||
switcher->CheckAutoStart();
|
||||
}
|
||||
|
||||
static void setLiveTime()
|
||||
@@ -551,28 +561,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()
|
||||
@@ -608,7 +608,7 @@ static void handleSceneCollectionChanging()
|
||||
AdvSceneSwitcher::window->close();
|
||||
}
|
||||
if (!switcher->stop) {
|
||||
switcher->sceneCollectionStop = true;
|
||||
switcher->sceneColletionStop = true;
|
||||
switcher->Stop();
|
||||
}
|
||||
}
|
||||
@@ -629,20 +629,13 @@ static void handleSceneCollectionCleanup()
|
||||
return;
|
||||
}
|
||||
|
||||
// OBS_FRONTEND_EVENT_SCENE_COLLECTION_CLEANUP is also called on
|
||||
// shutdown.
|
||||
// Here we also don't want to clear the settings.
|
||||
if (switcher->obsIsShuttingDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
SaveSceneSwitcher(nullptr, false, nullptr);
|
||||
}
|
||||
|
||||
// Note to future self:
|
||||
// be careful using switcher->m here as there is potential for deadlocks when using
|
||||
// frontend functions such as obs_frontend_set_current_scene()
|
||||
static void OBSEvent(enum obs_frontend_event event, void *)
|
||||
static void OBSEvent(enum obs_frontend_event event, void *switcher)
|
||||
{
|
||||
if (!switcher) {
|
||||
return;
|
||||
@@ -751,21 +744,6 @@ 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)
|
||||
{
|
||||
auto window = GetSettingsWindow();
|
||||
@@ -776,6 +754,8 @@ void HighlightMacroSettingsButton(bool enable)
|
||||
enable);
|
||||
}
|
||||
|
||||
void SetupActionQueues();
|
||||
|
||||
extern "C" EXPORT void InitSceneSwitcher(obs_module_t *module,
|
||||
translateFunc translate)
|
||||
{
|
||||
@@ -787,11 +767,12 @@ extern "C" EXPORT void InitSceneSwitcher(obs_module_t *module,
|
||||
PlatformInit();
|
||||
LoadPlugins();
|
||||
SetupDock();
|
||||
SetupActionQueues();
|
||||
|
||||
RunPluginInitSteps();
|
||||
|
||||
obs_frontend_add_save_callback(SaveSceneSwitcher, nullptr);
|
||||
obs_frontend_add_event_callback(OBSEvent, nullptr);
|
||||
obs_frontend_add_event_callback(OBSEvent, switcher);
|
||||
|
||||
QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction(
|
||||
obs_module_text("AdvSceneSwitcher.pluginName"));
|
||||
|
||||
@@ -45,6 +45,7 @@ protected:
|
||||
/* --- Begin of general tab section --- */
|
||||
public:
|
||||
void SetupGeneralTab();
|
||||
void UpdateNonMatchingScene(const QString &name);
|
||||
void SetDeprecationWarnings();
|
||||
|
||||
public slots:
|
||||
@@ -57,6 +58,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();
|
||||
@@ -65,20 +67,18 @@ public slots:
|
||||
void on_showTrayNotifications_stateChanged(int state);
|
||||
void on_uiHintsDisable_stateChanged(int state);
|
||||
void on_disableComboBoxFilter_stateChanged(int state);
|
||||
void on_disableMacroWidgetCache_stateChanged(int state);
|
||||
void on_warnPluginLoadFailure_stateChanged(int state);
|
||||
void on_suppressCrashRecoveryDialog_stateChanged(int state);
|
||||
void on_hideLegacyTabs_stateChanged(int state);
|
||||
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> &);
|
||||
@@ -86,6 +86,7 @@ public:
|
||||
void RenameMacro(std::shared_ptr<Macro> &, const QString &name);
|
||||
std::shared_ptr<Macro> GetSelectedMacro() const;
|
||||
std::vector<std::shared_ptr<Macro>> GetSelectedMacros() const;
|
||||
void SetEditMacro(Macro &m);
|
||||
void SetMacroEditAreaDisabled(bool) const;
|
||||
void HighlightAction(int idx, QColor color = QColor(Qt::green)) const;
|
||||
void HighlightElseAction(int idx,
|
||||
@@ -109,18 +110,107 @@ public slots:
|
||||
void on_macroDown_clicked() const;
|
||||
void on_macroName_editingFinished();
|
||||
void on_runMacroInParallel_stateChanged(int value) const;
|
||||
void on_actionTriggerMode_currentIndexChanged(int index) const;
|
||||
void on_runMacroOnChange_stateChanged(int value) const;
|
||||
void on_conditionAdd_clicked();
|
||||
void on_conditionRemove_clicked();
|
||||
void on_conditionTop_clicked();
|
||||
void on_conditionUp_clicked();
|
||||
void on_conditionDown_clicked();
|
||||
void on_conditionBottom_clicked();
|
||||
void on_actionAdd_clicked();
|
||||
void on_actionRemove_clicked();
|
||||
void on_actionTop_clicked();
|
||||
void on_actionUp_clicked();
|
||||
void on_actionDown_clicked();
|
||||
void on_actionBottom_clicked();
|
||||
void on_toggleElseActions_clicked() const;
|
||||
void on_elseActionAdd_clicked();
|
||||
void on_elseActionRemove_clicked();
|
||||
void on_elseActionTop_clicked();
|
||||
void on_elseActionUp_clicked();
|
||||
void on_elseActionDown_clicked();
|
||||
void on_elseActionBottom_clicked();
|
||||
void MacroSelectionAboutToChange() const;
|
||||
void MacroSelectionChanged();
|
||||
void 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 ImportMacros();
|
||||
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 SwapElseActions(Macro *m, int pos1, int pos2);
|
||||
void MoveMacroElseActionUp(int idx);
|
||||
void MoveMacroElseActionDown(int idx);
|
||||
void MacroConditionSelectionChanged(int idx);
|
||||
void MacroConditionReorder(int to, int target);
|
||||
void AddMacroCondition(int idx);
|
||||
void AddMacroCondition(Macro *macro, int idx, const std::string &id,
|
||||
obs_data_t *data, Logic::Type logic);
|
||||
void RemoveMacroCondition(int idx);
|
||||
void MoveMacroConditionUp(int idx);
|
||||
void MoveMacroConditionDown(int idx);
|
||||
void HighlightControls() const;
|
||||
void HighlightOnChange() const;
|
||||
void on_macroSettings_clicked();
|
||||
void CopyMacroSegment();
|
||||
void PasteMacroSegment();
|
||||
|
||||
signals:
|
||||
void MacroAdded(const QString &name);
|
||||
void MacroRemoved(const QString &name);
|
||||
void MacroRenamed(const QString &oldName, const QString &newName);
|
||||
void MacroSegmentOrderChanged();
|
||||
void SegmentTempVarsChanged(MacroSegment *);
|
||||
void HighlightMacrosChanged(bool value);
|
||||
|
||||
void ConnectionAdded(const QString &);
|
||||
void ConnectionRenamed(const QString &oldName, const QString &newName);
|
||||
void ConnectionRemoved(const QString &);
|
||||
|
||||
private:
|
||||
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 --- */
|
||||
|
||||
|
||||
281
lib/general.cpp
281
lib/general.cpp
@@ -1,19 +1,17 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "crash-handler.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"
|
||||
|
||||
@@ -27,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) {
|
||||
@@ -48,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);
|
||||
}
|
||||
|
||||
@@ -123,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) {
|
||||
@@ -144,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();
|
||||
}
|
||||
@@ -186,6 +205,16 @@ void AdvSceneSwitcher::on_disableComboBoxFilter_stateChanged(int state)
|
||||
FilterComboBox::SetFilterBehaviourEnabled(!state);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_disableMacroWidgetCache_stateChanged(int state)
|
||||
{
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
switcher->disableMacroWidgetCache = state;
|
||||
MacroSegmentList::SetCachingEnabled(!state);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_warnPluginLoadFailure_stateChanged(int state)
|
||||
{
|
||||
if (loading) {
|
||||
@@ -195,15 +224,6 @@ void AdvSceneSwitcher::on_warnPluginLoadFailure_stateChanged(int state)
|
||||
switcher->warnPluginLoadFailure = state;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_suppressCrashRecoveryDialog_stateChanged(int state)
|
||||
{
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
SetSuppressCrashDialog(state);
|
||||
}
|
||||
|
||||
static bool isLegacyTab(const QString &name)
|
||||
{
|
||||
return name == obs_module_text(
|
||||
@@ -370,46 +390,14 @@ void AdvSceneSwitcher::RestoreWindowGeo()
|
||||
}
|
||||
}
|
||||
|
||||
static void renameMacroIfNecessary(const std::shared_ptr<Macro> ¯o)
|
||||
{
|
||||
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"));
|
||||
switcher->Start();
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -463,13 +451,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);
|
||||
@@ -490,7 +481,7 @@ void SwitcherData::LoadSettings(obs_data_t *obj)
|
||||
LoadHotkeys(obj);
|
||||
LoadUISettings(obj);
|
||||
|
||||
RunAndClearPostLoadSteps();
|
||||
RunPostLoadSteps();
|
||||
|
||||
// Reset on startup and scene collection change
|
||||
ResetLastOpenedTab();
|
||||
@@ -506,6 +497,7 @@ void SwitcherData::SaveSettings(obs_data_t *obj)
|
||||
saveSceneGroups(obj);
|
||||
SaveMacros(obj);
|
||||
SaveGlobalMacroSettings(obj);
|
||||
SaveVariables(obj);
|
||||
saveWindowTitleSwitches(obj);
|
||||
saveScreenRegionSwitches(obj);
|
||||
savePauseSwitches(obj);
|
||||
@@ -524,16 +516,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");
|
||||
@@ -541,18 +535,13 @@ 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);
|
||||
obs_data_set_int(obj, "autoStartEvent",
|
||||
static_cast<int>(autoStartEvent));
|
||||
|
||||
SaveLogLevel(obj);
|
||||
|
||||
@@ -561,6 +550,8 @@ void SwitcherData::SaveGeneralSettings(obs_data_t *obj)
|
||||
obs_data_set_bool(obj, "disableHints", disableHints);
|
||||
obs_data_set_bool(obj, "disableFilterComboboxFilter",
|
||||
disableFilterComboboxFilter);
|
||||
obs_data_set_bool(obj, "disableMacroWidgetCache",
|
||||
disableMacroWidgetCache);
|
||||
obs_data_set_bool(obj, "warnPluginLoadFailure", warnPluginLoadFailure);
|
||||
obs_data_set_bool(obj, "hideLegacyTabs", hideLegacyTabs);
|
||||
|
||||
@@ -585,14 +576,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");
|
||||
@@ -613,15 +599,8 @@ 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);
|
||||
|
||||
@@ -630,6 +609,8 @@ void SwitcherData::LoadGeneralSettings(obs_data_t *obj)
|
||||
disableHints = obs_data_get_bool(obj, "disableHints");
|
||||
disableFilterComboboxFilter =
|
||||
obs_data_get_bool(obj, "disableFilterComboboxFilter");
|
||||
disableMacroWidgetCache =
|
||||
obs_data_get_bool(obj, "disableMacroWidgetCache");
|
||||
obs_data_set_default_bool(obj, "warnPluginLoadFailure", true);
|
||||
warnPluginLoadFailure = obs_data_get_bool(obj, "warnPluginLoadFailure");
|
||||
obs_data_set_default_bool(obj, "hideLegacyTabs", true);
|
||||
@@ -699,10 +680,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) {
|
||||
@@ -710,27 +691,6 @@ void SwitcherData::CheckNoMatchSwitch(bool &match, OBSWeakSource &scene,
|
||||
}
|
||||
}
|
||||
|
||||
void SwitcherData::CheckAutoStart()
|
||||
{
|
||||
if (!useAutoStartScene) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool shouldStartPlugin = false;
|
||||
if (autoStartSceneRegex.Enabled()) {
|
||||
const auto currentSceneName = GetWeakSourceName(currentScene);
|
||||
shouldStartPlugin = autoStartSceneRegex.Matches(
|
||||
currentSceneName, autoStartSceneName);
|
||||
} else {
|
||||
shouldStartPlugin = autoStartScene.GetScene(false) ==
|
||||
currentScene;
|
||||
}
|
||||
|
||||
if (shouldStartPlugin) {
|
||||
Start();
|
||||
}
|
||||
}
|
||||
|
||||
void SwitcherData::checkSwitchCooldown(bool &match)
|
||||
{
|
||||
if (!match || !enableCooldown) {
|
||||
@@ -873,7 +833,7 @@ static void setupGeneralTabInactiveWarning(QTabWidget *tabs)
|
||||
inactiveTimer->start();
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::SetCheckIntervalTooLowVisibility() const
|
||||
void advss::AdvSceneSwitcher::SetCheckIntervalTooLowVisibility() const
|
||||
{
|
||||
auto macro = GetMacroWithInvalidConditionInterval();
|
||||
if (!macro) {
|
||||
@@ -897,6 +857,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);
|
||||
@@ -908,17 +870,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);
|
||||
@@ -953,8 +906,10 @@ void AdvSceneSwitcher::SetupGeneralTab()
|
||||
switcher->disableFilterComboboxFilter);
|
||||
FilterComboBox::SetFilterBehaviourEnabled(
|
||||
!switcher->disableFilterComboboxFilter);
|
||||
ui->disableMacroWidgetCache->setChecked(
|
||||
switcher->disableMacroWidgetCache);
|
||||
MacroSegmentList::SetCachingEnabled(!switcher->disableMacroWidgetCache);
|
||||
ui->warnPluginLoadFailure->setChecked(switcher->warnPluginLoadFailure);
|
||||
ui->suppressCrashRecoveryDialog->setChecked(GetSuppressCrashDialog());
|
||||
ui->hideLegacyTabs->setChecked(switcher->hideLegacyTabs);
|
||||
|
||||
populatePriorityFunctionList(ui->priorityList);
|
||||
@@ -967,88 +922,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 ®ex) {
|
||||
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);
|
||||
@@ -1069,8 +942,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);
|
||||
}
|
||||
|
||||
@@ -92,11 +92,12 @@ bool SwitcherData::checkExeSwitch(OBSWeakSource &scene,
|
||||
}
|
||||
|
||||
std::string title = switcher->currentTitle;
|
||||
QStringList runningProcesses;
|
||||
bool ignored = false;
|
||||
bool match = false;
|
||||
|
||||
// Check for match
|
||||
const auto runningProcesses = GetProcessList();
|
||||
GetProcessList(runningProcesses);
|
||||
for (ExecutableSwitch &s : executableSwitches) {
|
||||
if (!s.initialized()) {
|
||||
continue;
|
||||
|
||||
@@ -230,7 +230,8 @@ bool SwitcherData::checkWindowTitleSwitch(OBSWeakSource &scene,
|
||||
|
||||
std::string currentWindowTitle = switcher->currentTitle;
|
||||
bool match = false;
|
||||
const auto windowList = GetWindowList();
|
||||
std::vector<std::string> windowList;
|
||||
GetWindowList(windowList);
|
||||
|
||||
for (WindowSwitch &s : windowSwitches) {
|
||||
if (!s.initialized()) {
|
||||
|
||||
@@ -32,9 +32,6 @@
|
||||
#endif
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <climits>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include "kwin-helpers.h"
|
||||
|
||||
namespace advss {
|
||||
@@ -236,9 +233,9 @@ std::string getWindowName(Window window)
|
||||
return windowTitle;
|
||||
}
|
||||
|
||||
std::vector<std::string> GetWindowList()
|
||||
void GetWindowList(std::vector<std::string> &windows)
|
||||
{
|
||||
std::vector<std::string> windows;
|
||||
windows.resize(0);
|
||||
for (auto window : getTopLevelWindows()) {
|
||||
auto name = getWindowName(window);
|
||||
if (name.empty()) {
|
||||
@@ -246,7 +243,18 @@ std::vector<std::string> GetWindowList()
|
||||
}
|
||||
windows.emplace_back(name);
|
||||
}
|
||||
return windows;
|
||||
}
|
||||
|
||||
void GetWindowList(QStringList &windows)
|
||||
{
|
||||
windows.clear();
|
||||
for (auto window : getTopLevelWindows()) {
|
||||
auto name = getWindowName(window);
|
||||
if (name.empty()) {
|
||||
continue;
|
||||
}
|
||||
windows << QString::fromStdString(name);
|
||||
}
|
||||
}
|
||||
|
||||
int getActiveWindow(Window *&window)
|
||||
@@ -270,24 +278,29 @@ int getActiveWindow(Window *&window)
|
||||
&bytes, (uint8_t **)&window);
|
||||
}
|
||||
|
||||
std::string GetCurrentWindowTitle()
|
||||
void GetCurrentWindowTitle(std::string &title)
|
||||
{
|
||||
if (KWin) {
|
||||
return FocusNotifier::getActiveWindowTitle();
|
||||
title = FocusNotifier::getActiveWindowTitle();
|
||||
return;
|
||||
}
|
||||
|
||||
Window *data = 0;
|
||||
if (getActiveWindow(data) != Success || !data) {
|
||||
return {};
|
||||
return;
|
||||
}
|
||||
if (!data[0]) {
|
||||
XFree(data);
|
||||
return {};
|
||||
return;
|
||||
}
|
||||
|
||||
auto name = getWindowName(data[0]);
|
||||
XFree(data);
|
||||
return name;
|
||||
|
||||
if (name.empty()) {
|
||||
return;
|
||||
}
|
||||
title = name;
|
||||
}
|
||||
|
||||
bool windowStatesAreSet(const std::string &windowTitle,
|
||||
@@ -396,17 +409,16 @@ static void getProcessListProcps2(QStringList &processes)
|
||||
#endif
|
||||
}
|
||||
|
||||
QStringList GetProcessList()
|
||||
void GetProcessList(QStringList &processes)
|
||||
{
|
||||
QStringList processes;
|
||||
processes.clear();
|
||||
if (libprocpsSupported) {
|
||||
getProcessListProcps(processes);
|
||||
return processes;
|
||||
return;
|
||||
}
|
||||
if (libprocps2Supported) {
|
||||
getProcessListProcps2(processes);
|
||||
}
|
||||
return processes;
|
||||
}
|
||||
|
||||
long getForegroundProcessPid()
|
||||
@@ -457,83 +469,24 @@ std::string getProcNameFromPid(long pid)
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string GetForegroundProcessName()
|
||||
void GetForegroundProcessName(QString &proc)
|
||||
{
|
||||
std::string temp;
|
||||
GetForegroundProcessName(temp);
|
||||
proc = QString::fromStdString(temp);
|
||||
}
|
||||
|
||||
void GetForegroundProcessName(std::string &proc)
|
||||
{
|
||||
proc.resize(0);
|
||||
auto pid = getForegroundProcessPid();
|
||||
return getProcNameFromPid(pid);
|
||||
}
|
||||
|
||||
static std::string getProcessPathFromPid(long pid)
|
||||
{
|
||||
std::string linkPath = "/proc/" + std::to_string(pid) + "/exe";
|
||||
char buf[PATH_MAX];
|
||||
ssize_t len = readlink(linkPath.c_str(), buf, sizeof(buf) - 1);
|
||||
if (len <= 0) {
|
||||
return {};
|
||||
}
|
||||
buf[len] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::string GetForegroundProcessPath()
|
||||
{
|
||||
auto pid = getForegroundProcessPid();
|
||||
if (pid <= 0) {
|
||||
return {};
|
||||
}
|
||||
return getProcessPathFromPid(pid);
|
||||
}
|
||||
|
||||
QStringList GetProcessPathsFromName(const QString &name)
|
||||
{
|
||||
QStringList paths;
|
||||
const std::string nameStr = name.toStdString();
|
||||
DIR *procDir = opendir("/proc");
|
||||
if (!procDir) {
|
||||
return paths;
|
||||
}
|
||||
|
||||
struct dirent *entry;
|
||||
while ((entry = readdir(procDir)) != nullptr) {
|
||||
bool isPid = (entry->d_name[0] != '\0');
|
||||
for (const char *c = entry->d_name; *c; c++) {
|
||||
if (!isdigit(*c)) {
|
||||
isPid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isPid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string pid = entry->d_name;
|
||||
std::string commPath = "/proc/" + pid + "/comm";
|
||||
std::ifstream commFile(commPath);
|
||||
if (!commFile) {
|
||||
continue;
|
||||
}
|
||||
std::string comm;
|
||||
std::getline(commFile, comm);
|
||||
if (comm != nameStr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string path = getProcessPathFromPid(std::stol(pid));
|
||||
if (path.empty()) {
|
||||
continue;
|
||||
}
|
||||
QString qPath = QString::fromStdString(path);
|
||||
if (!paths.contains(qPath)) {
|
||||
paths.append(qPath);
|
||||
}
|
||||
}
|
||||
closedir(procDir);
|
||||
return paths;
|
||||
proc = getProcNameFromPid(pid);
|
||||
}
|
||||
|
||||
bool IsInFocus(const QString &executable)
|
||||
{
|
||||
const auto current = GetForegroundProcessName();
|
||||
std::string current;
|
||||
GetForegroundProcessName(current);
|
||||
|
||||
// True if executable switch equals current window
|
||||
bool equals = (executable.toStdString() == current);
|
||||
|
||||
@@ -28,7 +28,8 @@ 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()),
|
||||
@@ -49,12 +50,10 @@ MacroActionEdit::MacroActionEdit(QWidget *parent,
|
||||
_section->AddHeaderWidget(_enable);
|
||||
_section->AddHeaderWidget(_actionSelection);
|
||||
_section->AddHeaderWidget(_headerInfo);
|
||||
_section->AddHeaderWidget(_varMappingToggle);
|
||||
|
||||
auto actionLayout = new QVBoxLayout;
|
||||
actionLayout->setContentsMargins({7, 7, 7, 7});
|
||||
actionLayout->addWidget(_section);
|
||||
actionLayout->addWidget(_outputMappings);
|
||||
_contentLayout->addLayout(actionLayout);
|
||||
|
||||
auto mainLayout = new QHBoxLayout;
|
||||
@@ -63,6 +62,7 @@ MacroActionEdit::MacroActionEdit(QWidget *parent,
|
||||
mainLayout->addWidget(_frame);
|
||||
setLayout(mainLayout);
|
||||
|
||||
_entryData = entryData;
|
||||
SetupWidgets(true);
|
||||
|
||||
actionStateTimer->start(300);
|
||||
@@ -91,10 +91,7 @@ void MacroActionEdit::SetupWidgets(bool basicSetup)
|
||||
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
|
||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||
this, SLOT(HeaderInfoChanged(const QString &)));
|
||||
QWidget::connect(widget, SIGNAL(ShowVariableMappings(bool)), this,
|
||||
SLOT(ShowVariableMappings(bool)));
|
||||
_section->SetContent(widget, (*_entryData)->GetCollapsed());
|
||||
SetupVarMappings((*_entryData).get());
|
||||
SetFocusPolicyOfWidgets();
|
||||
|
||||
_allWidgetsAreSetup = true;
|
||||
@@ -120,15 +117,12 @@ 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 &)),
|
||||
this, SLOT(HeaderInfoChanged(const QString &)));
|
||||
QWidget::connect(widget, SIGNAL(ShowVariableMappings(bool)), this,
|
||||
SLOT(ShowVariableMappings(bool)));
|
||||
_section->SetContent(widget);
|
||||
SetupVarMappings((*_entryData).get());
|
||||
SetFocusPolicyOfWidgets();
|
||||
}
|
||||
|
||||
@@ -164,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, ¯o->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, ¯o->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
|
||||
|
||||
@@ -13,8 +13,10 @@ class MacroActionEdit : public MacroSegmentEdit {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MacroActionEdit(QWidget *parent = nullptr,
|
||||
std::shared_ptr<MacroAction> * = nullptr);
|
||||
MacroActionEdit(
|
||||
QWidget *parent = nullptr,
|
||||
std::shared_ptr<MacroAction> * = nullptr,
|
||||
const std::string &id = MacroAction::GetDefaultID().data());
|
||||
void SetupWidgets(bool basicSetup = false);
|
||||
void SetEntryData(std::shared_ptr<MacroAction> *);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
#include "help-icon.hpp"
|
||||
#include "layout-helpers.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "macro-action-factory.hpp"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace advss {
|
||||
|
||||
@@ -15,165 +12,54 @@ bool MacroActionMacro::_registered = MacroActionFactory::Register(
|
||||
{MacroActionMacro::Create, MacroActionMacroEdit::Create,
|
||||
"AdvSceneSwitcher.action.macro"});
|
||||
|
||||
void MacroActionMacro::AdjustActionState(Macro *macro) const
|
||||
{
|
||||
const auto ¯oActions = _useElseSection ? macro->ElseActions()
|
||||
: macro->Actions();
|
||||
|
||||
std::vector<std::shared_ptr<MacroAction>> actionsToModify;
|
||||
switch (_actionSelectionType) {
|
||||
case SelectionType::INDEX: {
|
||||
const bool isValidAction =
|
||||
(_useElseSection &&
|
||||
IsValidElseActionIndex(macro, _actionIndex - 1)) ||
|
||||
(!_useElseSection &&
|
||||
IsValidActionIndex(macro, _actionIndex - 1));
|
||||
|
||||
if (isValidAction) {
|
||||
actionsToModify.emplace_back(
|
||||
macroActions.at(_actionIndex - 1));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SelectionType::LABEL:
|
||||
for (const auto &action : macroActions) {
|
||||
if (!action->GetUseCustomLabel()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto label = action->GetCustomLabel();
|
||||
|
||||
if (_regex.Enabled()) {
|
||||
if (_regex.Matches(label, _label)) {
|
||||
actionsToModify.emplace_back(action);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (label == std::string(_label)) {
|
||||
actionsToModify.emplace_back(action);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SelectionType::ID:
|
||||
for (const auto &action : macroActions) {
|
||||
if (action->GetId() == _actionId) {
|
||||
actionsToModify.emplace_back(action);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (const auto &action : actionsToModify) {
|
||||
switch (_action) {
|
||||
case Action::DISABLE_ACTION:
|
||||
action->SetEnabled(false);
|
||||
break;
|
||||
case Action::ENABLE_ACTION:
|
||||
action->SetEnabled(true);
|
||||
break;
|
||||
case Action::TOGGLE_ACTION:
|
||||
action->SetEnabled(!action->Enabled());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool MacroActionMacro::PerformAction()
|
||||
{
|
||||
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;
|
||||
case Action::RUN_MACRO: {
|
||||
if (_runOptions.skipWhenPaused && macro->Paused()) {
|
||||
break;
|
||||
}
|
||||
const bool conditionsMatched =
|
||||
macro->CheckConditions(true);
|
||||
macro->PerformActions(conditionsMatched, false, true);
|
||||
break;
|
||||
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:
|
||||
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);
|
||||
}
|
||||
case Action::GET_INFO: {
|
||||
SetTempVarValue(
|
||||
"conditionCount",
|
||||
std::to_string(macro->Conditions().size()));
|
||||
SetTempVarValue(
|
||||
"actionCount",
|
||||
std::to_string(macro->Actions().size()));
|
||||
SetTempVarValue(
|
||||
"elseActionCount",
|
||||
std::to_string(macro->ElseActions().size()));
|
||||
SetTempVarValue("paused",
|
||||
macro->Paused() ? "true" : "false");
|
||||
SetTempVarValue("runCount",
|
||||
std::to_string(macro->RunCount()));
|
||||
const auto lastRun = macro->GetLastExecutionTime();
|
||||
const bool hasRun =
|
||||
lastRun.time_since_epoch().count() != 0;
|
||||
const auto secondsSinceLastRun =
|
||||
hasRun ? std::chrono::duration_cast<
|
||||
std::chrono::seconds>(
|
||||
std::chrono::
|
||||
high_resolution_clock::
|
||||
now() -
|
||||
lastRun)
|
||||
.count()
|
||||
: -1;
|
||||
SetTempVarValue("secondsSinceLastRun",
|
||||
std::to_string(secondsSinceLastRun));
|
||||
break;
|
||||
break;
|
||||
case Action::ENABLE_ACTION:
|
||||
if (IsValidMacroSegmentIndex(macro.get(), _actionIndex - 1,
|
||||
false)) {
|
||||
macro->Actions().at(_actionIndex - 1)->SetEnabled(true);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
break;
|
||||
case Action::TOGGLE_ACTION:
|
||||
if (IsValidMacroSegmentIndex(macro.get(), _actionIndex - 1,
|
||||
false)) {
|
||||
auto action = macro->Actions().at(_actionIndex - 1);
|
||||
action->SetEnabled(!action->Enabled());
|
||||
}
|
||||
};
|
||||
|
||||
if (!IsGroupMacro(macro.get())) {
|
||||
performActionForMacro(macro.get());
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
auto macros = GetGroupMacroEntries(macro.get());
|
||||
for (const auto ¯o : macros) {
|
||||
performActionForMacro(macro.get());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -194,7 +80,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;
|
||||
@@ -213,15 +99,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;
|
||||
case Action::GET_INFO:
|
||||
ablog(LOG_INFO, "get info for \"%s\"", macro->Name().c_str());
|
||||
break;
|
||||
case Action::RUN_MACRO:
|
||||
ablog(LOG_INFO, "run macro \"%s\"", macro->Name().c_str());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -230,44 +107,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);
|
||||
SetAction(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);
|
||||
_action = static_cast<MacroActionMacro::Action>(
|
||||
obs_data_get_int(obj, "action"));
|
||||
_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;
|
||||
}
|
||||
|
||||
@@ -276,7 +130,6 @@ bool MacroActionMacro::PostLoad()
|
||||
MacroRefAction::PostLoad();
|
||||
MacroAction::PostLoad();
|
||||
_runOptions.macro.PostLoad();
|
||||
_nestedMacro->PostLoad();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -292,23 +145,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,
|
||||
@@ -350,56 +192,6 @@ void MacroActionMacro::RunActions(Macro *actionMacro) const
|
||||
}
|
||||
}
|
||||
|
||||
void MacroActionMacro::SetAction(Action action)
|
||||
{
|
||||
_action = action;
|
||||
SetupTempVars();
|
||||
}
|
||||
|
||||
void MacroActionMacro::SetupTempVars()
|
||||
{
|
||||
MacroAction::SetupTempVars();
|
||||
|
||||
if (_action != Action::GET_INFO) {
|
||||
return;
|
||||
}
|
||||
|
||||
AddTempvar(
|
||||
"conditionCount",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.macro.info.conditionCount"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.macro.info.conditionCount.description"));
|
||||
AddTempvar(
|
||||
"actionCount",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.macro.info.actionCount"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.macro.info.actionCount.description"));
|
||||
AddTempvar(
|
||||
"elseActionCount",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.macro.info.elseActionCount"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.macro.info.elseActionCount.description"));
|
||||
AddTempvar(
|
||||
"paused",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.macro.info.paused"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.macro.info.paused.description"));
|
||||
AddTempvar(
|
||||
"runCount",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.macro.info.runCount"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.macro.info.runCount.description"));
|
||||
AddTempvar(
|
||||
"secondsSinceLastRun",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.macro.info.secondsSinceLastRun"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.macro.info.secondsSinceLastRun.description"));
|
||||
}
|
||||
|
||||
static void populateActionSelection(QComboBox *list)
|
||||
{
|
||||
static const std::vector<std::pair<MacroActionMacro::Action, std::string>>
|
||||
@@ -412,12 +204,8 @@ static void populateActionSelection(QComboBox *list)
|
||||
"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.runActions"},
|
||||
{MacroActionMacro::Action::RUN_MACRO,
|
||||
"AdvSceneSwitcher.action.macro.type.runMacro"},
|
||||
{MacroActionMacro::Action::RUN,
|
||||
"AdvSceneSwitcher.action.macro.type.run"},
|
||||
{MacroActionMacro::Action::STOP,
|
||||
"AdvSceneSwitcher.action.macro.type.stop"},
|
||||
{MacroActionMacro::Action::DISABLE_ACTION,
|
||||
@@ -426,8 +214,6 @@ static void populateActionSelection(QComboBox *list)
|
||||
"AdvSceneSwitcher.action.macro.type.enableAction"},
|
||||
{MacroActionMacro::Action::TOGGLE_ACTION,
|
||||
"AdvSceneSwitcher.action.macro.type.toggleAction"},
|
||||
{MacroActionMacro::Action::GET_INFO,
|
||||
"AdvSceneSwitcher.action.macro.type.getInfo"},
|
||||
};
|
||||
|
||||
for (const auto &[value, name] : actions) {
|
||||
@@ -446,7 +232,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"));
|
||||
@@ -454,99 +240,49 @@ 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"))),
|
||||
_noConditionsWarning(new QLabel(obs_module_text(
|
||||
"AdvSceneSwitcher.action.macro.type.runMacro.noConditionsWarning"))),
|
||||
_runMacroHelp(new HelpIcon(obs_module_text(
|
||||
"AdvSceneSwitcher.action.macro.type.runMacro.help"))),
|
||||
_setInputs(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.action.macro.type.run.setInputs"))),
|
||||
_inputs(new MacroInputEdit()),
|
||||
_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,
|
||||
@@ -574,8 +310,6 @@ MacroActionMacroEdit::MacroActionMacroEdit(
|
||||
layout->addLayout(_setInputsLayout);
|
||||
layout->addWidget(_inputs);
|
||||
layout->addWidget(_skipWhenPaused);
|
||||
layout->addWidget(_noConditionsWarning);
|
||||
layout->addWidget(_nestedMacro);
|
||||
setLayout(layout);
|
||||
_entryData = entryData;
|
||||
UpdateEntryData();
|
||||
@@ -587,12 +321,6 @@ void HighlightMacroSettingsButton(bool enable);
|
||||
MacroActionMacroEdit::~MacroActionMacroEdit()
|
||||
{
|
||||
HighlightMacroSettingsButton(false);
|
||||
|
||||
if (!_entryData) {
|
||||
return;
|
||||
}
|
||||
_entryData->_customWidgetHeight = GetCustomHeight();
|
||||
_nestedMacro->SetMacro({}); // Save splitter states
|
||||
}
|
||||
|
||||
void MacroActionMacroEdit::UpdateEntryData()
|
||||
@@ -600,42 +328,24 @@ void MacroActionMacroEdit::UpdateEntryData()
|
||||
if (!_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
_actions->setCurrentIndex(
|
||||
_actions->findData(static_cast<int>(_entryData->GetAction())));
|
||||
_actionSelectionType->setCurrentIndex(_actionSelectionType->findData(
|
||||
static_cast<int>(_entryData->_actionSelectionType)));
|
||||
_actions->findData(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 ¯o = _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();
|
||||
@@ -651,17 +361,8 @@ void MacroActionMacroEdit::MacroChanged(const QString &text)
|
||||
void MacroActionMacroEdit::ActionChanged(int idx)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->SetAction(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>(
|
||||
_actions->itemData(idx).toInt());
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
@@ -671,25 +372,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 ®ex)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_regex = regex;
|
||||
}
|
||||
|
||||
void MacroActionMacroEdit::ConditionMacroChanged(const QString &text)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
@@ -711,13 +393,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)
|
||||
@@ -744,14 +423,9 @@ void MacroActionMacroEdit::InputsChanged(const StringList &inputs)
|
||||
void MacroActionMacroEdit::SetWidgetVisibility()
|
||||
{
|
||||
_entryLayout->removeWidget(_actions);
|
||||
_entryLayout->removeWidget(_runMacroHelp);
|
||||
_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);
|
||||
|
||||
@@ -760,47 +434,20 @@ void MacroActionMacroEdit::SetWidgetVisibility()
|
||||
|
||||
const std::unordered_map<std::string, QWidget *> placeholders = {
|
||||
{"{{actions}}", _actions},
|
||||
{"{{runMacroHelp}}", _runMacroHelp},
|
||||
{"{{actionIndex}}", _actionIndex},
|
||||
{"{{macros}}", _macros},
|
||||
{"{{actionSections}}", _actionSections},
|
||||
{"{{actionTypes}}", _actionTypes},
|
||||
{"{{conditionBehaviors}}", _conditionBehaviors},
|
||||
{"{{conditionMacros}}", _conditionMacros},
|
||||
{"{{actionSelectionType}}", _actionSelectionType},
|
||||
{"{{label}}", _label},
|
||||
{"{{regex}}", _regex},
|
||||
{"{{actionTypes}}", _actionTypes},
|
||||
|
||||
};
|
||||
|
||||
const auto action = _entryData->GetAction();
|
||||
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:
|
||||
case MacroActionMacro::Action::GET_INFO:
|
||||
layoutText = "AdvSceneSwitcher.action.macro.layout.other";
|
||||
break;
|
||||
case MacroActionMacro::Action::RUN_MACRO:
|
||||
layoutText = "AdvSceneSwitcher.action.macro.layout.runMacro";
|
||||
break;
|
||||
case MacroActionMacro::Action::RUN_ACTIONS:
|
||||
layoutText = "AdvSceneSwitcher.action.macro.layout.run";
|
||||
break;
|
||||
case MacroActionMacro::Action::DISABLE_ACTION:
|
||||
case MacroActionMacro::Action::ENABLE_ACTION:
|
||||
case MacroActionMacro::Action::TOGGLE_ACTION:
|
||||
layoutText = "AdvSceneSwitcher.action.macro.layout.actionState";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
PlaceWidgets(obs_module_text(layoutText), _entryLayout, placeholders);
|
||||
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) {
|
||||
@@ -809,82 +456,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 ||
|
||||
action == MacroActionMacro::Action::RUN_MACRO) {
|
||||
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 ||
|
||||
action == MacroActionMacro::Action::RUN_MACRO);
|
||||
|
||||
if (action == MacroActionMacro::Action::RUN_MACRO) {
|
||||
auto macro = _entryData->_macro.GetMacro();
|
||||
_noConditionsWarning->setVisible(!macro ||
|
||||
macro->Conditions().empty());
|
||||
} else {
|
||||
_noConditionsWarning->setVisible(false);
|
||||
}
|
||||
_runMacroHelp->setVisible(action ==
|
||||
MacroActionMacro::Action::RUN_MACRO);
|
||||
|
||||
_nestedMacro->setVisible(action ==
|
||||
MacroActionMacro::Action::NESTED_MACRO);
|
||||
_macros->setVisible(action != MacroActionMacro::Action::NESTED_MACRO);
|
||||
SetResizingEnabled(action == MacroActionMacro::Action::NESTED_MACRO);
|
||||
|
||||
if (_nestedMacro->IsEmpty()) {
|
||||
_nestedMacro->ShowAllMacroSections();
|
||||
// TODO: find a better solution than setting a fixed height
|
||||
_entryData->_customWidgetHeight = 600;
|
||||
}
|
||||
SetCustomHeight(_entryData->_customWidgetHeight);
|
||||
HighlightMacroSettingsButton(_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();
|
||||
|
||||
@@ -1,17 +1,11 @@
|
||||
#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>
|
||||
#include <QLabel>
|
||||
|
||||
namespace advss {
|
||||
|
||||
@@ -50,44 +44,25 @@ public:
|
||||
PAUSE,
|
||||
UNPAUSE,
|
||||
RESET_COUNTER,
|
||||
RUN_ACTIONS,
|
||||
RUN,
|
||||
STOP,
|
||||
DISABLE_ACTION,
|
||||
ENABLE_ACTION,
|
||||
TOGGLE_ACTION,
|
||||
TOGGLE_PAUSE,
|
||||
NESTED_MACRO,
|
||||
GET_INFO,
|
||||
RUN_MACRO,
|
||||
};
|
||||
|
||||
void SetAction(Action);
|
||||
Action GetAction() const { return _action; }
|
||||
|
||||
enum class SelectionType { INDEX, LABEL, ID };
|
||||
|
||||
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 SetupTempVars();
|
||||
void RunActions(Macro *actionMacro) const;
|
||||
void AdjustActionState(Macro *) const;
|
||||
|
||||
Action _action = Action::NESTED_MACRO;
|
||||
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
class MacroActionMacroEdit final : public ResizableWidget {
|
||||
class MacroActionMacroEdit final : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
@@ -96,20 +71,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 &);
|
||||
@@ -121,27 +98,20 @@ 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;
|
||||
QLabel *_noConditionsWarning;
|
||||
HelpIcon *_runMacroHelp;
|
||||
QCheckBox *_setInputs;
|
||||
MacroInputEdit *_inputs;
|
||||
QHBoxLayout *_entryLayout;
|
||||
QHBoxLayout *_conditionLayout;
|
||||
QHBoxLayout *_reevaluateConditionStateLayout;
|
||||
QHBoxLayout *_setInputsLayout;
|
||||
MacroEdit *_nestedMacro;
|
||||
|
||||
std::shared_ptr<MacroActionMacro> _entryData;
|
||||
bool _loading = true;
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#include "macro-action-variable.hpp"
|
||||
#include "help-icon.hpp"
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "json-helpers.hpp"
|
||||
#include "layout-helpers.hpp"
|
||||
#include "macro-condition-edit.hpp"
|
||||
#include "macro-signals.hpp"
|
||||
#include "math-helpers.hpp"
|
||||
#include "macro-condition-edit.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "non-modal-dialog.hpp"
|
||||
#include "source-helpers.hpp"
|
||||
@@ -17,15 +16,6 @@ namespace advss {
|
||||
|
||||
const std::string MacroActionVariable::id = "variable";
|
||||
|
||||
std::vector<TempVariableRef> MacroActionVariable::GetTempVarRefs() const
|
||||
{
|
||||
auto refs = MacroSegment::GetTempVarRefs();
|
||||
if (_tempVar.HasValidID()) {
|
||||
refs.push_back(_tempVar);
|
||||
}
|
||||
return refs;
|
||||
}
|
||||
|
||||
bool MacroActionVariable::_registered = MacroActionFactory::Register(
|
||||
MacroActionVariable::id,
|
||||
{MacroActionVariable::Create, MacroActionVariableEdit::Create,
|
||||
@@ -228,43 +218,6 @@ void MacroActionVariable::GenerateRandomNumber(Variable *var)
|
||||
}
|
||||
}
|
||||
|
||||
void MacroActionVariable::PickRandomValue(Variable *var)
|
||||
{
|
||||
static std::random_device rd;
|
||||
static std::mt19937 gen(rd());
|
||||
static const uint8_t maxIter = 255;
|
||||
|
||||
if (_randomValues.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_randomValues.size() == 1) {
|
||||
const auto &value = _randomValues.at(0);
|
||||
var->SetValue(value);
|
||||
_lastRandomValue = value;
|
||||
}
|
||||
|
||||
std::uniform_int_distribution<int> dis(0, _randomValues.size() - 1);
|
||||
StringVariable value = _randomValues.at(dis(gen));
|
||||
|
||||
uint8_t iter = 0;
|
||||
for (; !_allowRepeatValues && iter < maxIter &&
|
||||
_lastRandomValue.has_value() &&
|
||||
std::string(value) == _lastRandomValue.value();
|
||||
iter++) {
|
||||
value = _randomValues.at(dis(gen));
|
||||
}
|
||||
|
||||
if (iter == maxIter) {
|
||||
blog(LOG_INFO,
|
||||
"giving up picking non-repeat random value after %d tries",
|
||||
maxIter);
|
||||
}
|
||||
|
||||
var->SetValue(value);
|
||||
_lastRandomValue = value;
|
||||
}
|
||||
|
||||
struct AskForInputParams {
|
||||
AskForInputParams(const QString &prompt_, const QString &placeholder_)
|
||||
: prompt(prompt_),
|
||||
@@ -332,14 +285,6 @@ bool MacroActionVariable::PerformAction()
|
||||
case Action::APPEND:
|
||||
apppend(*var, _strValue);
|
||||
break;
|
||||
case Action::COPY_VAR: {
|
||||
auto var2 = _variable2.lock();
|
||||
if (!var2) {
|
||||
return true;
|
||||
}
|
||||
var->SetValue(var2->Value());
|
||||
break;
|
||||
}
|
||||
case Action::APPEND_VAR: {
|
||||
auto var2 = _variable2.lock();
|
||||
if (!var2) {
|
||||
@@ -504,9 +449,6 @@ bool MacroActionVariable::PerformAction()
|
||||
case Action::RANDOM_NUMBER:
|
||||
GenerateRandomNumber(var.get());
|
||||
return true;
|
||||
case Action::RANDOM_LIST_VALUE:
|
||||
PickRandomValue(var.get());
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -538,7 +480,7 @@ bool MacroActionVariable::Save(obs_data_t *obj) const
|
||||
_inputPlaceholder.Save(obj, "inputPlaceholder");
|
||||
_envVariableName.Save(obj, "environmentVariableName");
|
||||
_scene.Save(obj);
|
||||
_tempVar.Save(obj, GetMacro());
|
||||
_tempVar.Save(obj);
|
||||
_sceneItemIndex.Save(obj, "sceneItemIndex");
|
||||
obs_data_set_int(obj, "direction", static_cast<int>(_direction));
|
||||
_stringLength.Save(obj, "stringLength");
|
||||
@@ -547,8 +489,6 @@ bool MacroActionVariable::Save(obs_data_t *obj) const
|
||||
_randomNumberStart.Save(obj, "randomNumberStart");
|
||||
_randomNumberEnd.Save(obj, "randomNumberEnd");
|
||||
obs_data_set_bool(obj, "generateInteger", _generateInteger);
|
||||
_randomValues.Save(obj, "randomValues", "value");
|
||||
obs_data_set_bool(obj, "allowRepeatValues", _allowRepeatValues);
|
||||
_jsonQuery.Save(obj, "jsonQuery");
|
||||
_jsonIndex.Save(obj, "jsonIndex");
|
||||
|
||||
@@ -607,8 +547,6 @@ bool MacroActionVariable::Load(obs_data_t *obj)
|
||||
_randomNumberStart.Load(obj, "randomNumberStart");
|
||||
_randomNumberEnd.Load(obj, "randomNumberEnd");
|
||||
_generateInteger = obs_data_get_bool(obj, "generateInteger");
|
||||
_randomValues.Load(obj, "randomValues", "value");
|
||||
_allowRepeatValues = obs_data_get_bool(obj, "allowRepeatValues");
|
||||
_jsonQuery.Load(obj, "jsonQuery");
|
||||
_jsonIndex.Load(obj, "jsonIndex");
|
||||
|
||||
@@ -731,8 +669,6 @@ static inline void populateActionSelection(QComboBox *list)
|
||||
actions = {
|
||||
{MacroActionVariable::Action::SET_VALUE,
|
||||
"AdvSceneSwitcher.action.variable.type.set"},
|
||||
{MacroActionVariable::Action::COPY_VAR,
|
||||
"AdvSceneSwitcher.action.variable.type.copy"},
|
||||
{MacroActionVariable::Action::APPEND,
|
||||
"AdvSceneSwitcher.action.variable.type.append"},
|
||||
{MacroActionVariable::Action::PAD,
|
||||
@@ -777,8 +713,6 @@ static inline void populateActionSelection(QComboBox *list)
|
||||
"AdvSceneSwitcher.action.variable.type.roundToInt"},
|
||||
{MacroActionVariable::Action::RANDOM_NUMBER,
|
||||
"AdvSceneSwitcher.action.variable.type.randomNumber"},
|
||||
{MacroActionVariable::Action::RANDOM_LIST_VALUE,
|
||||
"AdvSceneSwitcher.action.variable.type.randomListValue"},
|
||||
{true, ""}, // Separator
|
||||
|
||||
{MacroActionVariable::Action::USER_INPUT,
|
||||
@@ -856,10 +790,11 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
_segmentValueStatus(new QLabel()),
|
||||
_segmentValue(new ResizingPlainTextEdit(this, 10, 1, 1)),
|
||||
_substringLayout(new QVBoxLayout()),
|
||||
_subStringControlsLayout(new QHBoxLayout()),
|
||||
_subStringIndexEntryLayout(new QHBoxLayout()),
|
||||
_subStringRegexEntryLayout(new QHBoxLayout()),
|
||||
_subStringStart(new VariableSpinBox(this)),
|
||||
_subStringSize(new VariableSpinBox(this)),
|
||||
_subStringRegex(new RegexConfigWidget(parent)),
|
||||
_substringRegex(new RegexConfigWidget(parent)),
|
||||
_regexPattern(new ResizingPlainTextEdit(this, 10, 1, 1)),
|
||||
_regexMatchIdx(new VariableSpinBox(this)),
|
||||
_findReplaceLayout(new QHBoxLayout()),
|
||||
@@ -891,18 +826,9 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.generateInteger"),
|
||||
this)),
|
||||
_randomNumberLayout(new QVBoxLayout()),
|
||||
_randomValues(new StringListEdit(this)),
|
||||
_allowRepeatValues(new QCheckBox(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.type.allowRepeat"),
|
||||
this)),
|
||||
_randomValueLayout(new QVBoxLayout()),
|
||||
_randomLayout(new QVBoxLayout()),
|
||||
_jsonQuery(new VariableLineEdit(this)),
|
||||
_jsonQueryHelp(new HelpIcon(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.type.queryJson.info"),
|
||||
this)),
|
||||
_jsonQueryHelp(new QLabel(this)),
|
||||
_jsonIndex(new VariableSpinBox(this)),
|
||||
_entryLayout(new QHBoxLayout())
|
||||
{
|
||||
@@ -933,7 +859,14 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
_randomNumberStart->setMaximum(9999999999);
|
||||
_randomNumberEnd->setMinimum(-9999999999);
|
||||
_randomNumberEnd->setMaximum(9999999999);
|
||||
_randomValues->SetMaxStringSize(99999999);
|
||||
const QString path = GetThemeTypeName() == "Light"
|
||||
? ":/res/images/help.svg"
|
||||
: ":/res/images/help_light.svg";
|
||||
const QIcon icon(path);
|
||||
const QPixmap pixmap = icon.pixmap(QSize(16, 16));
|
||||
_jsonQueryHelp->setPixmap(pixmap);
|
||||
_jsonQueryHelp->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.type.queryJson.info"));
|
||||
_jsonIndex->setMaximum(999);
|
||||
|
||||
QWidget::connect(_variables, SIGNAL(SelectionChanged(const QString &)),
|
||||
@@ -951,8 +884,7 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
QWidget::connect(_segmentIdx,
|
||||
SIGNAL(SelectionChanged(const IntVariable &)), this,
|
||||
SLOT(SegmentIndexChanged(const IntVariable &)));
|
||||
QWidget::connect(MacroSignalManager::Instance(),
|
||||
SIGNAL(SegmentOrderChanged()), this,
|
||||
QWidget::connect(window(), SIGNAL(MacroSegmentOrderChanged()), this,
|
||||
SLOT(MacroSegmentOrderChanged()));
|
||||
QWidget::connect(
|
||||
_subStringStart,
|
||||
@@ -962,7 +894,7 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
_subStringSize,
|
||||
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
||||
this, SLOT(SubStringSizeChanged(const NumberVariable<int> &)));
|
||||
QWidget::connect(_subStringRegex,
|
||||
QWidget::connect(_substringRegex,
|
||||
SIGNAL(RegexConfigChanged(const RegexConfig &)), this,
|
||||
SLOT(SubStringRegexChanged(const RegexConfig &)));
|
||||
QWidget::connect(_regexPattern, SIGNAL(textChanged()), this,
|
||||
@@ -1022,11 +954,6 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
SLOT(RandomNumberEndChanged(const NumberVariable<double> &)));
|
||||
QWidget::connect(_generateInteger, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(GenerateIntegerChanged(int)));
|
||||
QWidget::connect(_randomValues,
|
||||
SIGNAL(StringListChanged(const StringList &)), this,
|
||||
SLOT(RandomValueListChanged(const StringList &)));
|
||||
QWidget::connect(_allowRepeatValues, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(AllowRepeatValuesChanged(int)));
|
||||
QWidget::connect(_jsonQuery, SIGNAL(editingFinished()), this,
|
||||
SLOT(JsonQueryChanged()));
|
||||
QWidget::connect(
|
||||
@@ -1041,6 +968,9 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
{"{{strValue}}", _strValue},
|
||||
{"{{numValue}}", _numValue},
|
||||
{"{{segmentIndex}}", _segmentIdx},
|
||||
{"{{subStringStart}}", _subStringStart},
|
||||
{"{{subStringSize}}", _subStringSize},
|
||||
{"{{regexMatchIdx}}", _regexMatchIdx},
|
||||
{"{{findRegex}}", _findRegex},
|
||||
{"{{findStr}}", _findStr},
|
||||
{"{{replaceStr}}", _replaceStr},
|
||||
@@ -1072,7 +1002,12 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.layout.substringIndex"),
|
||||
_subStringControlsLayout, widgetPlaceholders);
|
||||
_subStringIndexEntryLayout, widgetPlaceholders);
|
||||
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.layout.substringRegex"),
|
||||
_subStringRegexEntryLayout, widgetPlaceholders);
|
||||
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
@@ -1093,17 +1028,15 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.layout.randomNumber"),
|
||||
randomLayout, widgetPlaceholders);
|
||||
_randomNumberLayout->addLayout(randomLayout);
|
||||
_randomNumberLayout->addWidget(_generateInteger);
|
||||
|
||||
_randomValueLayout->addWidget(_randomValues);
|
||||
_randomValueLayout->addWidget(_allowRepeatValues);
|
||||
_randomLayout->addLayout(randomLayout);
|
||||
_randomLayout->addWidget(_generateInteger);
|
||||
|
||||
auto regexConfigLayout = new QHBoxLayout;
|
||||
regexConfigLayout->addWidget(_subStringRegex);
|
||||
regexConfigLayout->addWidget(_substringRegex);
|
||||
regexConfigLayout->addStretch();
|
||||
|
||||
_substringLayout->addLayout(_subStringControlsLayout);
|
||||
_substringLayout->addLayout(_subStringIndexEntryLayout);
|
||||
_substringLayout->addLayout(_subStringRegexEntryLayout);
|
||||
_substringLayout->addWidget(_regexPattern);
|
||||
_substringLayout->addLayout(regexConfigLayout);
|
||||
|
||||
@@ -1116,8 +1049,7 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
layout->addWidget(_mathExpressionResult);
|
||||
layout->addLayout(_promptLayout);
|
||||
layout->addLayout(_placeholderLayout);
|
||||
layout->addLayout(_randomNumberLayout);
|
||||
layout->addLayout(_randomValueLayout);
|
||||
layout->addLayout(_randomLayout);
|
||||
setLayout(layout);
|
||||
|
||||
_entryData = entryData;
|
||||
@@ -1151,7 +1083,7 @@ void MacroActionVariableEdit::UpdateEntryData()
|
||||
: MacroSegmentSelection::Type::ACTION);
|
||||
_subStringStart->SetValue(_entryData->_subStringStart);
|
||||
_subStringSize->SetValue(_entryData->_subStringSize);
|
||||
_subStringRegex->SetRegexConfig(_entryData->_subStringRegex);
|
||||
_substringRegex->SetRegexConfig(_entryData->_subStringRegex);
|
||||
_findRegex->SetRegexConfig(_entryData->_findRegex);
|
||||
_regexPattern->setPlainText(
|
||||
QString::fromStdString(_entryData->_regexPattern));
|
||||
@@ -1176,8 +1108,6 @@ void MacroActionVariableEdit::UpdateEntryData()
|
||||
_randomNumberStart->SetValue(_entryData->_randomNumberStart);
|
||||
_randomNumberEnd->SetValue(_entryData->_randomNumberEnd);
|
||||
_generateInteger->setChecked(_entryData->_generateInteger);
|
||||
_allowRepeatValues->setChecked(_entryData->_allowRepeatValues);
|
||||
_randomValues->SetStringList(_entryData->_randomValues);
|
||||
_jsonQuery->setText(_entryData->_jsonQuery);
|
||||
_jsonIndex->SetValue(_entryData->_jsonIndex);
|
||||
|
||||
@@ -1459,7 +1389,6 @@ void MacroActionVariableEdit::SelectionChanged(const TempVariableRef &var)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_tempVar = var;
|
||||
IncrementTempVarInUseGeneration();
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
@@ -1521,18 +1450,6 @@ void MacroActionVariableEdit::GenerateIntegerChanged(int value)
|
||||
_entryData->_generateInteger = value;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::RandomValueListChanged(const StringList &values)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_randomValues = values;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::AllowRepeatValuesChanged(int value)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_allowRepeatValues = value;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::JsonQueryChanged()
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
@@ -1571,20 +1488,8 @@ void MacroActionVariableEdit::SetWidgetVisibility()
|
||||
{"{{jsonQuery}}", _jsonQuery},
|
||||
{"{{jsonQueryHelp}}", _jsonQueryHelp},
|
||||
{"{{jsonIndex}}", _jsonIndex},
|
||||
{"{{subStringRegex}}", _subStringRegex},
|
||||
{"{{subStringStart}}", _subStringStart},
|
||||
{"{{subStringSize}}", _subStringSize},
|
||||
{"{{regexMatchIdx}}", _regexMatchIdx},
|
||||
};
|
||||
|
||||
for (const auto &[_, widget] : widgetPlaceholders) {
|
||||
_entryLayout->removeWidget(widget);
|
||||
_subStringControlsLayout->removeWidget(widget);
|
||||
}
|
||||
|
||||
ClearLayout(_entryLayout);
|
||||
ClearLayout(_subStringControlsLayout);
|
||||
|
||||
const char *layoutString = "";
|
||||
if (_entryData->_action == MacroActionVariable::Action::PAD) {
|
||||
layoutString = obs_module_text(
|
||||
@@ -1598,6 +1503,11 @@ void MacroActionVariableEdit::SetWidgetVisibility()
|
||||
"AdvSceneSwitcher.action.variable.layout.other");
|
||||
}
|
||||
|
||||
for (const auto &[_, widget] : widgetPlaceholders) {
|
||||
_entryLayout->removeWidget(widget);
|
||||
}
|
||||
|
||||
ClearLayout(_entryLayout);
|
||||
PlaceWidgets(layoutString, _entryLayout, widgetPlaceholders);
|
||||
|
||||
if (_entryData->_action == MacroActionVariable::Action::SET_VALUE ||
|
||||
@@ -1614,7 +1524,6 @@ void MacroActionVariableEdit::SetWidgetVisibility()
|
||||
}
|
||||
|
||||
_variables2->setVisible(
|
||||
_entryData->_action == MacroActionVariable::Action::COPY_VAR ||
|
||||
_entryData->_action ==
|
||||
MacroActionVariable::Action::APPEND_VAR ||
|
||||
_entryData->_action ==
|
||||
@@ -1644,25 +1553,15 @@ void MacroActionVariableEdit::SetWidgetVisibility()
|
||||
MacroActionVariable::Action::SET_ACTION_VALUE ||
|
||||
_entryData->_action ==
|
||||
MacroActionVariable::Action::SET_CONDITION_VALUE);
|
||||
|
||||
bool showRegex = _entryData->_subStringRegex.Enabled();
|
||||
layoutString =
|
||||
showRegex
|
||||
? "AdvSceneSwitcher.action.variable.layout.substringRegex"
|
||||
: "AdvSceneSwitcher.action.variable.layout.substringIndex";
|
||||
PlaceWidgets(obs_module_text(layoutString), _subStringControlsLayout,
|
||||
widgetPlaceholders);
|
||||
_subStringStart->setVisible(!showRegex);
|
||||
_subStringSize->setVisible(!showRegex);
|
||||
_regexMatchIdx->setVisible(showRegex);
|
||||
|
||||
SetLayoutVisible(_substringLayout,
|
||||
_entryData->_action ==
|
||||
MacroActionVariable::Action::SUBSTRING);
|
||||
_regexPattern->setVisible(
|
||||
showRegex &&
|
||||
_entryData->_action == MacroActionVariable::Action::SUBSTRING);
|
||||
|
||||
if (_entryData->_action == MacroActionVariable::Action::SUBSTRING) {
|
||||
bool showRegex = _entryData->_subStringRegex.Enabled();
|
||||
SetLayoutVisible(_subStringIndexEntryLayout, !showRegex);
|
||||
SetLayoutVisible(_subStringRegexEntryLayout, showRegex);
|
||||
_regexPattern->setVisible(showRegex);
|
||||
}
|
||||
SetLayoutVisible(_findReplaceLayout,
|
||||
_entryData->_action ==
|
||||
MacroActionVariable::Action::FIND_AND_REPLACE);
|
||||
@@ -1727,13 +1626,9 @@ void MacroActionVariableEdit::SetWidgetVisibility()
|
||||
MacroActionVariable::Action::PAD);
|
||||
_caseType->setVisible(_entryData->_action ==
|
||||
MacroActionVariable::Action::CHANGE_CASE);
|
||||
SetLayoutVisible(_randomNumberLayout,
|
||||
SetLayoutVisible(_randomLayout,
|
||||
_entryData->_action ==
|
||||
MacroActionVariable::Action::RANDOM_NUMBER);
|
||||
SetLayoutVisible(
|
||||
_randomValueLayout,
|
||||
_entryData->_action ==
|
||||
MacroActionVariable::Action::RANDOM_LIST_VALUE);
|
||||
_jsonQuery->setVisible(_entryData->_action ==
|
||||
MacroActionVariable::Action::QUERY_JSON);
|
||||
_jsonQueryHelp->setVisible(_entryData->_action ==
|
||||
|
||||
@@ -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"
|
||||
@@ -23,7 +22,6 @@ public:
|
||||
bool PostLoad();
|
||||
std::string GetShortDesc() const;
|
||||
std::string GetId() const { return id; };
|
||||
std::vector<TempVariableRef> GetTempVarRefs() const;
|
||||
static std::shared_ptr<MacroAction> Create(Macro *m);
|
||||
std::shared_ptr<MacroAction> Copy() const;
|
||||
void SetSegmentIndexValue(int);
|
||||
@@ -57,8 +55,6 @@ public:
|
||||
RANDOM_NUMBER,
|
||||
QUERY_JSON,
|
||||
ARRAY_JSON,
|
||||
COPY_VAR,
|
||||
RANDOM_LIST_VALUE,
|
||||
};
|
||||
|
||||
Action _action = Action::SET_VALUE;
|
||||
@@ -110,10 +106,6 @@ public:
|
||||
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;
|
||||
|
||||
@@ -126,7 +118,6 @@ private:
|
||||
void HandleCaseChange(Variable *);
|
||||
void SetToSceneItemName(Variable *);
|
||||
void GenerateRandomNumber(Variable *);
|
||||
void PickRandomValue(Variable *);
|
||||
|
||||
std::weak_ptr<MacroSegment> _macroSegment;
|
||||
int _segmentIdxLoadValue = -1;
|
||||
@@ -183,8 +174,6 @@ private slots:
|
||||
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> &);
|
||||
|
||||
@@ -204,10 +193,11 @@ private:
|
||||
QLabel *_segmentValueStatus;
|
||||
ResizingPlainTextEdit *_segmentValue;
|
||||
QVBoxLayout *_substringLayout;
|
||||
QHBoxLayout *_subStringControlsLayout;
|
||||
QHBoxLayout *_subStringIndexEntryLayout;
|
||||
QHBoxLayout *_subStringRegexEntryLayout;
|
||||
VariableSpinBox *_subStringStart;
|
||||
VariableSpinBox *_subStringSize;
|
||||
RegexConfigWidget *_subStringRegex;
|
||||
RegexConfigWidget *_substringRegex;
|
||||
ResizingPlainTextEdit *_regexPattern;
|
||||
VariableSpinBox *_regexMatchIdx;
|
||||
QHBoxLayout *_findReplaceLayout;
|
||||
@@ -234,10 +224,7 @@ private:
|
||||
VariableDoubleSpinBox *_randomNumberStart;
|
||||
VariableDoubleSpinBox *_randomNumberEnd;
|
||||
QCheckBox *_generateInteger;
|
||||
QVBoxLayout *_randomNumberLayout;
|
||||
StringListEdit *_randomValues;
|
||||
QCheckBox *_allowRepeatValues;
|
||||
QVBoxLayout *_randomValueLayout;
|
||||
QVBoxLayout *_randomLayout;
|
||||
VariableLineEdit *_jsonQuery;
|
||||
QLabel *_jsonQueryHelp;
|
||||
VariableSpinBox *_jsonIndex;
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "path-helpers.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "section.hpp"
|
||||
#include "switch-button.hpp"
|
||||
#include "ui-helpers.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
@@ -101,17 +100,14 @@ void DurationModifierEdit::Collapse(bool collapse)
|
||||
|
||||
MacroConditionEdit::MacroConditionEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroCondition> *entryData,
|
||||
bool isRootCondition)
|
||||
const std::string &id, bool isRootCondition)
|
||||
: MacroSegmentEdit(parent),
|
||||
_enable(new SwitchButton()),
|
||||
_logicSelection(new QComboBox()),
|
||||
_conditionSelection(new FilterComboBox()),
|
||||
_dur(new DurationModifierEdit()),
|
||||
_entryData(entryData),
|
||||
_isRoot(isRootCondition)
|
||||
{
|
||||
QWidget::connect(_enable, SIGNAL(checked(bool)), this,
|
||||
SLOT(ConditionEnableChanged(bool)));
|
||||
QWidget::connect(_logicSelection, SIGNAL(currentIndexChanged(int)),
|
||||
this, SLOT(LogicSelectionChanged(int)));
|
||||
QWidget::connect(_conditionSelection,
|
||||
@@ -126,17 +122,14 @@ MacroConditionEdit::MacroConditionEdit(
|
||||
Logic::PopulateLogicTypeSelection(_logicSelection, isRootCondition);
|
||||
populateConditionSelection(_conditionSelection);
|
||||
|
||||
_section->AddHeaderWidget(_enable);
|
||||
_section->AddHeaderWidget(_logicSelection);
|
||||
_section->AddHeaderWidget(_conditionSelection);
|
||||
_section->AddHeaderWidget(_headerInfo);
|
||||
_section->AddHeaderWidget(_dur);
|
||||
_section->AddHeaderWidget(_varMappingToggle);
|
||||
|
||||
QVBoxLayout *conditionLayout = new QVBoxLayout;
|
||||
conditionLayout->setContentsMargins({7, 7, 7, 7});
|
||||
conditionLayout->addWidget(_section);
|
||||
conditionLayout->addWidget(_outputMappings);
|
||||
_contentLayout->addLayout(conditionLayout);
|
||||
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||
@@ -159,17 +152,8 @@ void MacroConditionEdit::LogicSelectionChanged(int idx)
|
||||
const auto logic = static_cast<Logic::Type>(
|
||||
_logicSelection->itemData(idx).toInt());
|
||||
(*_entryData)->SetLogicType(logic);
|
||||
}
|
||||
|
||||
void MacroConditionEdit::ConditionEnableChanged(bool value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
(*_entryData)->SetEnabled(value);
|
||||
SetDisableEffect(!value);
|
||||
SetEnableAppearance(logic != Logic::Type::NONE);
|
||||
}
|
||||
|
||||
bool MacroConditionEdit::IsRootNode() const
|
||||
@@ -182,9 +166,7 @@ void MacroConditionEdit::SetLogicSelection()
|
||||
const auto logic = (*_entryData)->GetLogicType();
|
||||
_logicSelection->setCurrentIndex(
|
||||
_logicSelection->findData(static_cast<int>(logic)));
|
||||
const bool enabled = (*_entryData)->Enabled();
|
||||
_enable->setChecked(enabled);
|
||||
SetEnableAppearance(enabled);
|
||||
SetEnableAppearance(logic != Logic::Type::NONE);
|
||||
}
|
||||
|
||||
void MacroConditionEdit::SetRootNode(bool root)
|
||||
@@ -222,10 +204,7 @@ void MacroConditionEdit::SetupWidgets(bool basicSetup)
|
||||
MacroConditionFactory::CreateWidget(id, this, *_entryData);
|
||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||
this, SLOT(HeaderInfoChanged(const QString &)));
|
||||
QWidget::connect(widget, SIGNAL(ShowVariableMappings(bool)), this,
|
||||
SLOT(ShowVariableMappings(bool)));
|
||||
_section->SetContent(widget, (*_entryData)->GetCollapsed());
|
||||
SetupVarMappings((*_entryData).get());
|
||||
SetFocusPolicyOfWidgets();
|
||||
|
||||
_allWidgetsAreSetup = true;
|
||||
@@ -255,23 +234,18 @@ void MacroConditionEdit::ConditionSelectionChanged(const QString &text)
|
||||
{
|
||||
auto lock = LockContext();
|
||||
auto logic = (*_entryData)->GetLogicType();
|
||||
const bool enabled = (*_entryData)->Enabled();
|
||||
_entryData->reset();
|
||||
*_entryData = MacroConditionFactory::Create(id, macro);
|
||||
(*_entryData)->SetIndex(idx);
|
||||
(*_entryData)->SetLogicType(logic);
|
||||
(*_entryData)->SetEnabled(enabled);
|
||||
(*_entryData)->PostLoad();
|
||||
RunAndClearPostLoadSteps();
|
||||
RunPostLoadSteps();
|
||||
}
|
||||
auto widget =
|
||||
MacroConditionFactory::CreateWidget(id, this, *_entryData);
|
||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||
this, SLOT(HeaderInfoChanged(const QString &)));
|
||||
QWidget::connect(widget, SIGNAL(ShowVariableMappings(bool)), this,
|
||||
SLOT(ShowVariableMappings(bool)));
|
||||
_section->SetContent(widget);
|
||||
SetupVarMappings((*_entryData).get());
|
||||
_dur->setVisible(MacroConditionFactory::UsesDurationModifier(id));
|
||||
SetFocusPolicyOfWidgets();
|
||||
}
|
||||
@@ -301,4 +275,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, ¯o->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
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
|
||||
namespace advss {
|
||||
|
||||
class SwitchButton;
|
||||
|
||||
class DurationModifierEdit : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -36,9 +34,11 @@ class MacroConditionEdit : public MacroSegmentEdit {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MacroConditionEdit(QWidget *parent = nullptr,
|
||||
std::shared_ptr<MacroCondition> * = nullptr,
|
||||
bool root = true);
|
||||
MacroConditionEdit(
|
||||
QWidget *parent = nullptr,
|
||||
std::shared_ptr<MacroCondition> * = nullptr,
|
||||
const std::string &id = MacroCondition::GetDefaultID().data(),
|
||||
bool root = true);
|
||||
bool IsRootNode() const;
|
||||
void SetRootNode(bool);
|
||||
void SetupWidgets(bool basicSetup = false);
|
||||
@@ -49,13 +49,11 @@ private slots:
|
||||
void ConditionSelectionChanged(const QString &text);
|
||||
void DurationChanged(const Duration &value);
|
||||
void DurationModifierChanged(DurationModifier::Type m);
|
||||
void ConditionEnableChanged(bool);
|
||||
|
||||
private:
|
||||
void SetLogicSelection();
|
||||
std::shared_ptr<MacroSegment> Data() const;
|
||||
|
||||
SwitchButton *_enable;
|
||||
QComboBox *_logicSelection;
|
||||
FilterComboBox *_conditionSelection;
|
||||
DurationModifierEdit *_dur;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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() ==
|
||||
|
||||
@@ -39,7 +39,6 @@ public:
|
||||
ACTION_DISABLED,
|
||||
ACTION_ENABLED,
|
||||
PAUSED,
|
||||
ACTIONS_PERFORMED,
|
||||
};
|
||||
void SetType(Type);
|
||||
Type GetType() const { return _type; }
|
||||
@@ -67,7 +66,6 @@ private:
|
||||
bool CheckMultiStateCondition();
|
||||
bool CheckActionStateCondition();
|
||||
bool CheckPauseState();
|
||||
bool CheckActionsPerformed();
|
||||
|
||||
void SetupTempVars();
|
||||
|
||||
@@ -136,7 +134,6 @@ private:
|
||||
void SetupCountWidgets();
|
||||
void SetupActionStateWidgets(bool enable);
|
||||
void SetupPauseWidgets();
|
||||
void SetupActionsPerformedWidgets();
|
||||
void SetWidgetVisibility();
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
@@ -6,15 +6,6 @@ namespace advss {
|
||||
|
||||
const std::string MacroConditionTempVar::id = "temp_var";
|
||||
|
||||
std::vector<TempVariableRef> MacroConditionTempVar::GetTempVarRefs() const
|
||||
{
|
||||
auto refs = MacroSegment::GetTempVarRefs();
|
||||
if (_tempVar.HasValidID()) {
|
||||
refs.push_back(_tempVar);
|
||||
}
|
||||
return refs;
|
||||
}
|
||||
|
||||
bool MacroConditionTempVar::_registered = MacroConditionFactory::Register(
|
||||
MacroConditionTempVar::id,
|
||||
{MacroConditionTempVar::Create, MacroConditionTempVarEdit::Create,
|
||||
@@ -163,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");
|
||||
@@ -275,7 +266,6 @@ void MacroConditionTempVarEdit::VariableChanged(const TempVariableRef &var)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_tempVar = var;
|
||||
IncrementTempVarInUseGeneration();
|
||||
}
|
||||
|
||||
void MacroConditionTempVarEdit::Variable2Changed(const QString &text)
|
||||
|
||||
@@ -20,7 +20,6 @@ public:
|
||||
bool Load(obs_data_t *obj);
|
||||
std::string GetShortDesc() const;
|
||||
std::string GetId() const { return id; };
|
||||
std::vector<TempVariableRef> GetTempVarRefs() const;
|
||||
static std::shared_ptr<MacroCondition> Create(Macro *m)
|
||||
{
|
||||
return std::make_shared<MacroConditionTempVar>(m);
|
||||
|
||||
@@ -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);
|
||||
@@ -31,10 +20,6 @@ bool MacroCondition::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroSegment::Load(obj);
|
||||
_logic.Load(obj, "logic");
|
||||
if (_logic.GetType() == Logic::Type::NONE) {
|
||||
SetEnabled(false);
|
||||
_logic.SetType(Logic::Type::AND);
|
||||
}
|
||||
_durationModifier.Load(obj);
|
||||
return true;
|
||||
}
|
||||
@@ -54,8 +39,7 @@ void MacroCondition::ValidateLogicSelection(bool isRootCondition,
|
||||
return;
|
||||
}
|
||||
|
||||
_logic.SetType(Logic::Type::AND);
|
||||
SetEnabled(false);
|
||||
_logic.SetType(Logic::Type::NONE);
|
||||
blog(LOG_WARNING,
|
||||
"setting invalid logic selection to 'ignore' for macro %s",
|
||||
context);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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>> ¯os,
|
||||
Macro *macro)
|
||||
{
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto iterate = [¯os](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 ¯os = 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()
|
||||
@@ -242,11 +128,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 +144,20 @@ void ResetMacroRunCount(Macro *macro)
|
||||
macro->ResetRunCount();
|
||||
}
|
||||
|
||||
bool IsValidActionIndex(const Macro *m, const int idx)
|
||||
bool IsValidMacroSegmentIndex(const 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
@@ -68,7 +58,6 @@ EXPORT void AddMacroHelperThread(Macro *, std::thread &&);
|
||||
EXPORT bool CheckMacros();
|
||||
|
||||
EXPORT bool RunMacroActions(Macro *);
|
||||
bool RunMacroElseActions(Macro *);
|
||||
EXPORT bool RunMacros();
|
||||
void StopAllMacros();
|
||||
|
||||
@@ -79,8 +68,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(const Macro *m, const int idx, bool isCondition);
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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"));
|
||||
|
||||
|
||||
@@ -1,323 +0,0 @@
|
||||
#include "macro-search.hpp"
|
||||
#include "layout-helpers.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "macro-action-factory.hpp"
|
||||
#include "macro-condition-factory.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "macro-signals.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "ui-helpers.hpp"
|
||||
|
||||
#include <obs.hpp>
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QLayout>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
|
||||
namespace advss {
|
||||
|
||||
static bool searchEnabled = false;
|
||||
static bool setup();
|
||||
static bool setupDone = setup();
|
||||
|
||||
static QLayout *searchLayout = nullptr;
|
||||
static QComboBox *searchType = nullptr;
|
||||
static RegexConfigWidget *searchRegex = nullptr;
|
||||
static QPushButton *showSettings = nullptr;
|
||||
static std::function<void()> refreshFilter;
|
||||
|
||||
static void save(obs_data_t *data)
|
||||
{
|
||||
GetMacroSearchSettings().Save(data, "macroSearchSettings");
|
||||
}
|
||||
|
||||
static void load(obs_data_t *data)
|
||||
{
|
||||
GetMacroSearchSettings().Load(data, "macroSearchSettings");
|
||||
}
|
||||
|
||||
static bool setup()
|
||||
{
|
||||
AddSaveStep(save);
|
||||
AddLoadStep(load);
|
||||
return true;
|
||||
}
|
||||
|
||||
void MacroSearchSettings::Save(obs_data_t *data, const char *name)
|
||||
{
|
||||
OBSDataAutoRelease settings = obs_data_create();
|
||||
obs_data_set_bool(settings, "showAlways", showAlways);
|
||||
obs_data_set_int(settings, "searchType", static_cast<int>(searchType));
|
||||
obs_data_set_string(settings, "searchString", searchString.c_str());
|
||||
regex.Save(settings);
|
||||
obs_data_set_obj(data, name, settings);
|
||||
}
|
||||
|
||||
void MacroSearchSettings::Load(obs_data_t *data, const char *name)
|
||||
{
|
||||
OBSDataAutoRelease settings = obs_data_get_obj(data, name);
|
||||
showAlways = obs_data_get_bool(settings, "showAlways");
|
||||
searchType = static_cast<SearchType>(
|
||||
obs_data_get_int(settings, "searchType"));
|
||||
searchString = obs_data_get_string(settings, "searchString");
|
||||
regex.Load(settings);
|
||||
}
|
||||
|
||||
static void showAdvancedSearchSettings(bool show)
|
||||
{
|
||||
assert(searchType);
|
||||
assert(searchRegex);
|
||||
|
||||
searchType->setVisible(show);
|
||||
searchRegex->setVisible(show);
|
||||
}
|
||||
|
||||
static bool shouldShowSearch()
|
||||
{
|
||||
static const int showSearchThreshold = 10;
|
||||
return GetMacroSearchSettings().showAlways ||
|
||||
GetTopLevelMacros().size() >= showSearchThreshold;
|
||||
}
|
||||
|
||||
void CheckMacroSearchVisibility()
|
||||
{
|
||||
assert(searchLayout);
|
||||
assert(searchType);
|
||||
assert(searchRegex);
|
||||
assert(showSettings);
|
||||
|
||||
searchEnabled = shouldShowSearch();
|
||||
SetLayoutVisible(searchLayout, searchEnabled);
|
||||
showAdvancedSearchSettings(false);
|
||||
showSettings->setChecked(false);
|
||||
refreshFilter();
|
||||
}
|
||||
|
||||
void SetupMacroSearchWidgets(QLayout *searchLayoutArg, QLineEdit *searchText,
|
||||
QPushButton *searchClear, QComboBox *searchTypeArg,
|
||||
RegexConfigWidget *searchRegexArg,
|
||||
QPushButton *showSettingsArg,
|
||||
const std::function<void()> &refreshArg)
|
||||
{
|
||||
searchLayout = searchLayoutArg;
|
||||
searchType = searchTypeArg;
|
||||
searchRegex = searchRegexArg;
|
||||
refreshFilter = refreshArg;
|
||||
showSettings = showSettingsArg;
|
||||
|
||||
searchClear->setMaximumWidth(22);
|
||||
SetButtonIcon(searchClear, GetThemeTypeName() == "Light"
|
||||
? "theme:Light/close.svg"
|
||||
: "theme:Dark/close.svg");
|
||||
searchClear->setDisabled(GetMacroSearchSettings().searchString.empty());
|
||||
|
||||
QWidget::connect(searchClear, &QPushButton::clicked, searchClear,
|
||||
[=]() {
|
||||
searchText->setText("");
|
||||
searchClear->setDisabled(true);
|
||||
});
|
||||
|
||||
const auto ph = searchText->placeholderText();
|
||||
const QFontMetrics fm(searchText->font());
|
||||
const int width = fm.horizontalAdvance(ph);
|
||||
// Add a little padding so the text isn't cramped
|
||||
searchText->setMinimumWidth(width + 10);
|
||||
|
||||
searchText->setText(
|
||||
QString::fromStdString(GetMacroSearchSettings().searchString));
|
||||
QWidget::connect(searchText, &QLineEdit::textChanged, searchText,
|
||||
[searchClear](const QString &text) {
|
||||
GetMacroSearchSettings().searchString =
|
||||
text.toStdString();
|
||||
searchClear->setDisabled(text.isEmpty());
|
||||
refreshFilter();
|
||||
});
|
||||
|
||||
searchType->addItem(
|
||||
obs_module_text("AdvSceneSwitcher.macroTab.search.name"),
|
||||
static_cast<int>(MacroSearchSettings::SearchType::NAME));
|
||||
searchType->addItem(
|
||||
obs_module_text("AdvSceneSwitcher.macroTab.search.allSegments"),
|
||||
static_cast<int>(
|
||||
MacroSearchSettings::SearchType::ALL_SEGMENTS));
|
||||
searchType->addItem(
|
||||
obs_module_text("AdvSceneSwitcher.macroTab.search.conditions"),
|
||||
static_cast<int>(MacroSearchSettings::SearchType::CONDITIONS));
|
||||
searchType->addItem(
|
||||
obs_module_text("AdvSceneSwitcher.macroTab.search.actions"),
|
||||
static_cast<int>(MacroSearchSettings::SearchType::ACTIONS));
|
||||
searchType->addItem(
|
||||
obs_module_text("AdvSceneSwitcher.macroTab.search.label"),
|
||||
static_cast<int>(MacroSearchSettings::SearchType::LABEL));
|
||||
searchType->setCurrentIndex(searchType->findData(
|
||||
static_cast<int>(GetMacroSearchSettings().searchType)));
|
||||
QWidget::connect(
|
||||
searchType, &QComboBox::currentIndexChanged, searchType, []() {
|
||||
GetMacroSearchSettings().searchType =
|
||||
static_cast<MacroSearchSettings::SearchType>(
|
||||
searchType->currentData().toInt());
|
||||
refreshFilter();
|
||||
});
|
||||
|
||||
searchRegex->SetRegexConfig(GetMacroSearchSettings().regex);
|
||||
QWidget::connect(searchRegex, &RegexConfigWidget::RegexConfigChanged,
|
||||
searchRegex, [](const RegexConfig ®ex) {
|
||||
GetMacroSearchSettings().regex = regex;
|
||||
refreshFilter();
|
||||
});
|
||||
|
||||
showSettings->setCheckable(true);
|
||||
showSettings->setMaximumWidth(11);
|
||||
SetButtonIcon(showSettings, GetThemeTypeName() == "Light"
|
||||
? ":/res/images/dots-vert.svg"
|
||||
: "theme:Dark/dots-vert.svg");
|
||||
QWidget::connect(showSettings, &QPushButton::toggled, showSettings,
|
||||
showAdvancedSearchSettings);
|
||||
|
||||
QWidget::connect(MacroSignalManager::Instance(),
|
||||
&MacroSignalManager::Rename, searchText,
|
||||
[]() { refreshFilter(); });
|
||||
|
||||
CheckMacroSearchVisibility();
|
||||
}
|
||||
|
||||
MacroSearchSettings &GetMacroSearchSettings()
|
||||
{
|
||||
static MacroSearchSettings settings;
|
||||
return settings;
|
||||
}
|
||||
|
||||
static bool stringMatches(const std::string &text)
|
||||
{
|
||||
const auto &settings = GetMacroSearchSettings();
|
||||
const auto ®ex = settings.regex;
|
||||
const auto &searchString = settings.searchString;
|
||||
|
||||
if (regex.Enabled()) {
|
||||
return regex.Matches(text, searchString);
|
||||
}
|
||||
|
||||
return QString::fromStdString(text).contains(
|
||||
QString::fromStdString(searchString), Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
static bool segmentTypeMatches(MacroSegment *segment, bool isCondition)
|
||||
{
|
||||
if (!segment) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto getNameFromId =
|
||||
isCondition ? MacroConditionFactory::GetConditionName
|
||||
: MacroActionFactory::GetActionName;
|
||||
const auto name = getNameFromId(segment->GetId());
|
||||
return stringMatches(obs_module_text(name.c_str()));
|
||||
}
|
||||
|
||||
static bool segmentLabelMatches(MacroSegment *segment)
|
||||
{
|
||||
if (!segment) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!segment->GetUseCustomLabel()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto label = segment->GetCustomLabel();
|
||||
return stringMatches(label);
|
||||
}
|
||||
|
||||
bool MacroMatchesSearchFilter(Macro *macro)
|
||||
{
|
||||
assert(macro);
|
||||
|
||||
if (!searchEnabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto &settings = GetMacroSearchSettings();
|
||||
|
||||
if (settings.searchString.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (macro->IsGroup()) {
|
||||
const auto groupEntries = GetGroupMacroEntries(macro);
|
||||
for (const auto &entry : groupEntries) {
|
||||
if (MacroMatchesSearchFilter(entry.get())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (settings.searchType) {
|
||||
case MacroSearchSettings::SearchType::NAME: {
|
||||
const auto name = macro->Name();
|
||||
return stringMatches(name);
|
||||
}
|
||||
case MacroSearchSettings::SearchType::ALL_SEGMENTS:
|
||||
for (const auto &condition : macro->Conditions()) {
|
||||
if (segmentTypeMatches(condition.get(), true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (const auto &action : macro->Actions()) {
|
||||
if (segmentTypeMatches(action.get(), false)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (const auto &action : macro->ElseActions()) {
|
||||
if (segmentTypeMatches(action.get(), false)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
case MacroSearchSettings::SearchType::CONDITIONS:
|
||||
for (const auto &condition : macro->Conditions()) {
|
||||
if (segmentTypeMatches(condition.get(), true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
case MacroSearchSettings::SearchType::ACTIONS:
|
||||
for (const auto &action : macro->Actions()) {
|
||||
if (segmentTypeMatches(action.get(), false)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (const auto &action : macro->ElseActions()) {
|
||||
if (segmentTypeMatches(action.get(), false)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
case MacroSearchSettings::SearchType::LABEL:
|
||||
for (const auto &condition : macro->Conditions()) {
|
||||
if (segmentLabelMatches(condition.get())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (const auto &action : macro->Actions()) {
|
||||
if (segmentLabelMatches(action.get())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (const auto &action : macro->ElseActions()) {
|
||||
if (segmentLabelMatches(action.get())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Unhandled search type
|
||||
assert(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
@@ -1,43 +0,0 @@
|
||||
#pragma once
|
||||
#include "regex-config.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
class QComboBox;
|
||||
class QLayout;
|
||||
class QLineEdit;
|
||||
class QPushButton;
|
||||
|
||||
namespace advss {
|
||||
|
||||
class Macro;
|
||||
|
||||
struct MacroSearchSettings {
|
||||
void Save(obs_data_t *data, const char *name);
|
||||
void Load(obs_data_t *data, const char *name);
|
||||
|
||||
enum class SearchType {
|
||||
NAME = 0,
|
||||
ALL_SEGMENTS = 10,
|
||||
CONDITIONS = 20,
|
||||
ACTIONS = 30,
|
||||
LABEL = 40,
|
||||
};
|
||||
|
||||
SearchType searchType = SearchType::NAME;
|
||||
std::string searchString;
|
||||
RegexConfig regex;
|
||||
bool showAlways = false;
|
||||
};
|
||||
|
||||
void CheckMacroSearchVisibility();
|
||||
void SetupMacroSearchWidgets(QLayout *searchLayout, QLineEdit *searchText,
|
||||
QPushButton *searchClear, QComboBox *searchType,
|
||||
RegexConfigWidget *searchRegex,
|
||||
QPushButton *showSettings,
|
||||
const std::function<void()> &refresh);
|
||||
MacroSearchSettings &GetMacroSearchSettings();
|
||||
bool MacroMatchesSearchFilter(Macro *macro);
|
||||
|
||||
} // namespace advss
|
||||
@@ -13,7 +13,7 @@ struct MacroSegmentCopyInfo {
|
||||
};
|
||||
static MacroSegmentCopyInfo copyInfo;
|
||||
|
||||
void MacroEdit::CopyMacroSegment()
|
||||
void AdvSceneSwitcher::CopyMacroSegment()
|
||||
{
|
||||
copyInfo.segment.reset();
|
||||
copyInfo.type = MacroSegmentCopyInfo::Type::NONE;
|
||||
@@ -23,7 +23,7 @@ void MacroEdit::CopyMacroSegment()
|
||||
return;
|
||||
}
|
||||
|
||||
auto macro = _currentMacro;
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
@@ -43,13 +43,13 @@ void MacroEdit::CopyMacroSegment()
|
||||
}
|
||||
}
|
||||
|
||||
void MacroEdit::PasteMacroSegment()
|
||||
void AdvSceneSwitcher::PasteMacroSegment()
|
||||
{
|
||||
if (copyInfo.type == MacroSegmentCopyInfo::Type::NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto macro = _currentMacro;
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro || !copyInfo.segment) {
|
||||
return;
|
||||
}
|
||||
@@ -113,14 +113,14 @@ void SetCopySegmentTargetActionType(bool setToElseAction)
|
||||
}
|
||||
}
|
||||
|
||||
void SetupSegmentCopyPasteShortcutHandlers(MacroEdit *edit)
|
||||
void SetupSegmentCopyPasteShortcutHandlers(AdvSceneSwitcher *window)
|
||||
{
|
||||
auto copyShortcut = new QShortcut(QKeySequence("Ctrl+C"), edit);
|
||||
QWidget::connect(copyShortcut, &QShortcut::activated, edit,
|
||||
&MacroEdit::CopyMacroSegment);
|
||||
auto pasteShortcut = new QShortcut(QKeySequence("Ctrl+V"), edit);
|
||||
QWidget::connect(pasteShortcut, &QShortcut::activated, edit,
|
||||
&MacroEdit::PasteMacroSegment);
|
||||
auto copyShortcut = new QShortcut(QKeySequence("Ctrl+C"), window);
|
||||
QWidget::connect(copyShortcut, &QShortcut::activated, window,
|
||||
&AdvSceneSwitcher::CopyMacroSegment);
|
||||
auto pasteShortcut = new QShortcut(QKeySequence("Ctrl+V"), window);
|
||||
QWidget::connect(pasteShortcut, &QShortcut::activated, window,
|
||||
&AdvSceneSwitcher::PasteMacroSegment);
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
namespace advss {
|
||||
|
||||
class MacroEdit;
|
||||
class AdvSceneSwitcher;
|
||||
|
||||
bool MacroSegmentIsInClipboard();
|
||||
bool MacroActionIsInClipboard();
|
||||
void SetCopySegmentTargetActionType(bool setToElseAction);
|
||||
void SetupSegmentCopyPasteShortcutHandlers(MacroEdit *edit);
|
||||
void SetupSegmentCopyPasteShortcutHandlers(AdvSceneSwitcher *window);
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -17,39 +17,27 @@ bool MacroSegmentList::_useCache = true;
|
||||
|
||||
MacroSegmentList::MacroSegmentList(QWidget *parent)
|
||||
: QScrollArea(parent),
|
||||
_stackedWidget(new QStackedWidget(this)),
|
||||
_layout(new QVBoxLayout),
|
||||
_contentLayout(new QVBoxLayout),
|
||||
_helpMsg(new QLabel(this))
|
||||
_helpMsg(new QLabel)
|
||||
{
|
||||
_helpMsg->setWordWrap(true);
|
||||
_helpMsg->setAlignment(Qt::AlignCenter);
|
||||
auto helpWidget = new QWidget(this);
|
||||
auto helpLayout = new QVBoxLayout(helpWidget);
|
||||
helpLayout->addWidget(_helpMsg);
|
||||
helpLayout->setAlignment(Qt::AlignCenter);
|
||||
|
||||
auto contentWidget = new QWidget(this);
|
||||
contentWidget->setLayout(_contentLayout);
|
||||
_contentLayout->setSpacing(0);
|
||||
|
||||
auto contentWrapper = new QWidget(this);
|
||||
auto wrapperLayout = new QVBoxLayout(contentWrapper);
|
||||
wrapperLayout->setContentsMargins(0, 0, 0, 0);
|
||||
wrapperLayout->addWidget(contentWidget);
|
||||
// Move macro segments to the top of the list
|
||||
wrapperLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding,
|
||||
QSizePolicy::Expanding));
|
||||
|
||||
_stackedWidget->addWidget(helpWidget);
|
||||
_stackedWidget->addWidget(contentWrapper);
|
||||
|
||||
setWidget(_stackedWidget);
|
||||
auto helperLayout = new QGridLayout();
|
||||
helperLayout->addWidget(_helpMsg, 0, 0,
|
||||
Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
helperLayout->addLayout(_contentLayout, 0, 0);
|
||||
helperLayout->setSizeConstraint(QLayout::SetMinAndMaxSize);
|
||||
_layout->addLayout(helperLayout, 10);
|
||||
_layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding,
|
||||
QSizePolicy::Expanding));
|
||||
auto wrapper = new QWidget;
|
||||
wrapper->setLayout(_layout);
|
||||
setWidget(wrapper);
|
||||
setWidgetResizable(true);
|
||||
setAcceptDrops(true);
|
||||
|
||||
SetHelpMsgVisible(true);
|
||||
|
||||
connect(verticalScrollBar(), &QScrollBar::valueChanged, this,
|
||||
[this]() { SetupVisibleMacroSegmentWidgets(); });
|
||||
}
|
||||
@@ -119,11 +107,9 @@ void MacroSegmentList::SetHelpMsg(const QString &msg) const
|
||||
_helpMsg->setText(msg);
|
||||
}
|
||||
|
||||
void MacroSegmentList::SetHelpMsgVisible(bool visible)
|
||||
void MacroSegmentList::SetHelpMsgVisible(bool visible) const
|
||||
{
|
||||
_stackedWidget->setCurrentIndex(visible ? 0 : 1);
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
_helpMsg->setVisible(visible);
|
||||
}
|
||||
|
||||
void MacroSegmentList::Insert(int idx, QWidget *widget)
|
||||
@@ -131,33 +117,23 @@ void MacroSegmentList::Insert(int idx, QWidget *widget)
|
||||
widget->installEventFilter(this);
|
||||
_contentLayout->insertWidget(idx, widget);
|
||||
SetupVisibleMacroSegmentWidgets();
|
||||
SetHelpMsgVisible(false);
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void MacroSegmentList::Add(QWidget *widget)
|
||||
{
|
||||
Insert(_contentLayout->count(), widget);
|
||||
widget->installEventFilter(this);
|
||||
_contentLayout->addWidget(widget);
|
||||
SetupVisibleMacroSegmentWidgets();
|
||||
}
|
||||
|
||||
void MacroSegmentList::Remove(int idx)
|
||||
void MacroSegmentList::Remove(int idx) const
|
||||
{
|
||||
DeleteLayoutItemWidget(_contentLayout->takeAt(idx));
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
if (IsEmpty()) {
|
||||
SetHelpMsgVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroSegmentList::Clear(int idx)
|
||||
void MacroSegmentList::Clear(int idx) const
|
||||
{
|
||||
ClearLayout(_contentLayout, idx);
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
|
||||
SetHelpMsgVisible(true);
|
||||
}
|
||||
|
||||
void MacroSegmentList::SetCachingEnabled(bool enable)
|
||||
@@ -202,8 +178,6 @@ bool MacroSegmentList::PopulateWidgetsFromCache(const Macro *macro)
|
||||
widget->show();
|
||||
}
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -437,24 +411,6 @@ void MacroSegmentList::SetVisibilityCheckEnable(bool enable)
|
||||
}
|
||||
}
|
||||
|
||||
bool MacroSegmentList::IsEmpty() const
|
||||
{
|
||||
return _contentLayout->count() == 0;
|
||||
}
|
||||
|
||||
QSize MacroSegmentList::minimumSizeHint() const
|
||||
{
|
||||
return _stackedWidget->currentWidget()->minimumSizeHint();
|
||||
}
|
||||
|
||||
QSize MacroSegmentList::sizeHint() const
|
||||
{
|
||||
const auto contentSize = _stackedWidget->currentWidget()->sizeHint();
|
||||
const auto hint =
|
||||
QSize(width(), contentSize.height() + 2 * frameWidth());
|
||||
return hint;
|
||||
}
|
||||
|
||||
void MacroSegmentList::SetupVisibleMacroSegmentWidgets()
|
||||
{
|
||||
if (!_checkVisibility) {
|
||||
@@ -472,7 +428,6 @@ void MacroSegmentList::SetupVisibleMacroSegmentWidgets()
|
||||
|
||||
segment->SetupWidgets();
|
||||
}
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
int MacroSegmentList::GetSegmentIndexFromPos(const QPoint &pos) const
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
#pragma once
|
||||
#include "macro-segment.hpp"
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include <QLabel>
|
||||
#include <QScrollArea>
|
||||
#include <QStackedWidget>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
#include <QScrollArea>
|
||||
#include <QVBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <thread>
|
||||
|
||||
namespace advss {
|
||||
|
||||
@@ -19,63 +17,51 @@ class MacroSegmentList : public QScrollArea {
|
||||
public:
|
||||
MacroSegmentList(QWidget *parent = nullptr);
|
||||
~MacroSegmentList();
|
||||
|
||||
void SetHelpMsg(const QString &msg) const;
|
||||
void SetHelpMsgVisible(bool visible);
|
||||
|
||||
void SetHelpMsgVisible(bool visible) const;
|
||||
MacroSegmentEdit *WidgetAt(int idx) const;
|
||||
MacroSegmentEdit *WidgetAt(const QPoint &) const;
|
||||
|
||||
int IndexAt(const QPoint &) const;
|
||||
void Insert(int idx, QWidget *widget);
|
||||
void Add(QWidget *widget);
|
||||
void Remove(int idx);
|
||||
void Clear(int idx = 0); // Clear all elements >= idx
|
||||
bool IsEmpty() const;
|
||||
|
||||
void Remove(int idx) const;
|
||||
void Clear(int idx = 0) const; // Clear all elements >= idx
|
||||
static void SetCachingEnabled(bool enable);
|
||||
void CacheCurrentWidgetsFor(const Macro *);
|
||||
bool PopulateWidgetsFromCache(const Macro *);
|
||||
void ClearWidgetsFromCacheFor(const Macro *);
|
||||
void SetVisibilityCheckEnable(bool enable);
|
||||
|
||||
void Highlight(int idx, QColor color = QColor(Qt::green));
|
||||
|
||||
void SetCollapsed(bool) const;
|
||||
void SetSelection(int idx) const;
|
||||
QVBoxLayout *ContentLayout() const { return _contentLayout; }
|
||||
|
||||
QSize minimumSizeHint() const override;
|
||||
QSize sizeHint() const override;
|
||||
void SetVisibilityCheckEnable(bool enable);
|
||||
|
||||
signals:
|
||||
void SelectionChanged(int idx);
|
||||
void Reorder(int source, int target);
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *object, QEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
void dragLeaveEvent(QDragLeaveEvent *event) override;
|
||||
void dragEnterEvent(QDragEnterEvent *event) override;
|
||||
void dragMoveEvent(QDragMoveEvent *event) override;
|
||||
void dropEvent(QDropEvent *event) override;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
bool eventFilter(QObject *object, QEvent *event);
|
||||
void mousePressEvent(QMouseEvent *event);
|
||||
void mouseMoveEvent(QMouseEvent *event);
|
||||
void mouseReleaseEvent(QMouseEvent *event);
|
||||
void dragLeaveEvent(QDragLeaveEvent *event);
|
||||
void dragEnterEvent(QDragEnterEvent *event);
|
||||
void dragMoveEvent(QDragMoveEvent *event);
|
||||
void dropEvent(QDropEvent *event);
|
||||
void resizeEvent(QResizeEvent *event);
|
||||
|
||||
private:
|
||||
void SetupVisibleMacroSegmentWidgets();
|
||||
void ClearWidgetCache();
|
||||
|
||||
int GetSegmentIndexFromPos(const QPoint &) const;
|
||||
bool IsInListArea(const QPoint &) const;
|
||||
QRect GetContentItemRectWithPadding(int idx) const;
|
||||
|
||||
int GetDragIndex(const QPoint &) const;
|
||||
int GetDropIndex(const QPoint &) const;
|
||||
void CheckScroll() const;
|
||||
void CheckDropLine(const QPoint &);
|
||||
bool IsInListArea(const QPoint &) const;
|
||||
QRect GetContentItemRectWithPadding(int idx) const;
|
||||
void HideLastDropLine();
|
||||
void ClearWidgetCache();
|
||||
|
||||
int _dragPosition = -1;
|
||||
int _dropLineIdx = -1;
|
||||
@@ -83,7 +69,6 @@ private:
|
||||
std::thread _autoScrollThread;
|
||||
std::atomic_bool _autoScroll{false};
|
||||
|
||||
QStackedWidget *_stackedWidget;
|
||||
QVBoxLayout *_layout;
|
||||
QVBoxLayout *_contentLayout;
|
||||
QLabel *_helpMsg;
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include "macro-condition-factory.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "macro-segment.hpp"
|
||||
#include "macro-signals.hpp"
|
||||
#include "obs-module-helper.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "ui-helpers.hpp"
|
||||
@@ -32,8 +31,7 @@ MacroSegmentSelection::MacroSegmentSelection(QWidget *parent, Type type,
|
||||
_index,
|
||||
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
||||
this, SLOT(IndexChanged(const NumberVariable<int> &)));
|
||||
QWidget::connect(MacroSignalManager::Instance(),
|
||||
SIGNAL(SegmentOrderChanged()), this,
|
||||
QWidget::connect(window(), SIGNAL(MacroSegmentOrderChanged()), this,
|
||||
SLOT(MacroSegmentOrderChanged()));
|
||||
|
||||
auto layout = new QHBoxLayout;
|
||||
@@ -73,46 +71,35 @@ void MacroSegmentSelection::MacroSegmentOrderChanged()
|
||||
}
|
||||
|
||||
static QString GetMacroSegmentDescription(Macro *macro, int idx,
|
||||
MacroSegmentSelection::Type type)
|
||||
bool isCondition)
|
||||
{
|
||||
if (!macro) {
|
||||
return "";
|
||||
}
|
||||
|
||||
MacroSegment *segment;
|
||||
|
||||
switch (type) {
|
||||
case MacroSegmentSelection::Type::CONDITION:
|
||||
if (!IsValidConditionIndex(macro, idx)) {
|
||||
return "";
|
||||
}
|
||||
segment = GetMacroConditions(macro)->at(idx).get();
|
||||
break;
|
||||
case MacroSegmentSelection::Type::ACTION:
|
||||
if (!IsValidActionIndex(macro, idx)) {
|
||||
return "";
|
||||
}
|
||||
segment = GetMacroActions(macro)->at(idx).get();
|
||||
break;
|
||||
case MacroSegmentSelection::Type::ELSE_ACTION:
|
||||
if (!IsValidElseActionIndex(macro, idx)) {
|
||||
return "";
|
||||
}
|
||||
segment = GetMacroElseActions(macro)->at(idx).get();
|
||||
break;
|
||||
default:
|
||||
if (!IsValidMacroSegmentIndex(macro, idx, isCondition)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const auto idToName = type == MacroSegmentSelection::Type::CONDITION
|
||||
? MacroConditionFactory::GetConditionName
|
||||
: MacroActionFactory::GetActionName;
|
||||
const QString typeStr =
|
||||
obs_module_text(idToName(segment->GetId()).c_str());
|
||||
const QString description =
|
||||
QString::fromStdString(segment->GetShortDesc());
|
||||
MacroSegment *segment;
|
||||
if (isCondition) {
|
||||
segment = GetMacroConditions(macro)->at(idx).get();
|
||||
} else {
|
||||
segment = GetMacroActions(macro)->at(idx).get();
|
||||
}
|
||||
|
||||
QString result = typeStr;
|
||||
QString description = QString::fromStdString(segment->GetShortDesc());
|
||||
QString type;
|
||||
if (isCondition) {
|
||||
type = obs_module_text(MacroConditionFactory::GetConditionName(
|
||||
segment->GetId())
|
||||
.c_str());
|
||||
} else {
|
||||
type = obs_module_text(
|
||||
MacroActionFactory::GetActionName(segment->GetId())
|
||||
.c_str());
|
||||
}
|
||||
|
||||
QString result = type;
|
||||
if (!description.isEmpty()) {
|
||||
result += ": " + description;
|
||||
}
|
||||
@@ -134,25 +121,11 @@ void MacroSegmentSelection::SetupDescription() const
|
||||
return;
|
||||
}
|
||||
|
||||
bool validIndex = false;
|
||||
switch (_type) {
|
||||
case Type::CONDITION:
|
||||
validIndex = IsValidConditionIndex(_macro, index - 1);
|
||||
break;
|
||||
case Type::ACTION:
|
||||
validIndex = IsValidActionIndex(_macro, index - 1);
|
||||
break;
|
||||
case Type::ELSE_ACTION:
|
||||
validIndex = IsValidElseActionIndex(_macro, index - 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
QString description;
|
||||
if (validIndex) {
|
||||
description =
|
||||
GetMacroSegmentDescription(_macro, index - 1, _type);
|
||||
if (IsValidMacroSegmentIndex(_macro, index - 1,
|
||||
_type == Type::CONDITION)) {
|
||||
description = GetMacroSegmentDescription(
|
||||
_macro, index - 1, _type == Type::CONDITION);
|
||||
} else {
|
||||
description = obs_module_text(
|
||||
"AdvSceneSwitcher.macroSegmentSelection.invalid");
|
||||
@@ -190,23 +163,8 @@ void MacroSegmentSelection::MarkSelectedSegment()
|
||||
if (index.GetType() == IntVariable::Type::VARIABLE) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool validIndex = false;
|
||||
switch (_type) {
|
||||
case Type::CONDITION:
|
||||
validIndex = IsValidConditionIndex(_macro, index - 1);
|
||||
break;
|
||||
case Type::ACTION:
|
||||
validIndex = IsValidActionIndex(_macro, index - 1);
|
||||
break;
|
||||
case Type::ELSE_ACTION:
|
||||
validIndex = IsValidElseActionIndex(_macro, index - 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!validIndex) {
|
||||
if (!IsValidMacroSegmentIndex(_macro, index - 1,
|
||||
_type == Type::CONDITION)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ class Macro;
|
||||
class MacroSegmentSelection : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum class Type { CONDITION, ACTION, ELSE_ACTION };
|
||||
enum class Type { CONDITION, ACTION };
|
||||
|
||||
MacroSegmentSelection(QWidget *parent, Type type,
|
||||
bool allowVariables = true);
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
#pragma once
|
||||
#include "macro-action.hpp"
|
||||
#include "macro-condition.hpp"
|
||||
|
||||
#include <obs.hpp>
|
||||
|
||||
#include <QLabel>
|
||||
|
||||
namespace advss {
|
||||
|
||||
// Retains the settings and ID of the macro segment even if they can't be
|
||||
// interpreted correctly right now.
|
||||
//
|
||||
// As soon as a version of the plugin supporting the original ID is running it
|
||||
// will take over again
|
||||
template<typename T> class MacroSegmentUnknown : public T {
|
||||
public:
|
||||
MacroSegmentUnknown(Macro *macro, const std::string &originalId);
|
||||
bool CheckCondition() { return false; }
|
||||
std::shared_ptr<MacroAction> Copy() const;
|
||||
bool PerformAction() { return true; };
|
||||
bool Save(obs_data_t *data) const;
|
||||
bool Load(obs_data_t *data);
|
||||
std::string GetId() const { return "unknown"; }
|
||||
|
||||
private:
|
||||
std::string _id;
|
||||
OBSData _settings;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline MacroSegmentUnknown<T>::MacroSegmentUnknown(
|
||||
Macro *macro, const std::string &originalId)
|
||||
: T(macro),
|
||||
_id(originalId),
|
||||
_settings(obs_data_create())
|
||||
{
|
||||
obs_data_release(_settings);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline std::shared_ptr<MacroAction> MacroSegmentUnknown<T>::Copy() const
|
||||
{
|
||||
if constexpr (std::is_same_v<T, MacroAction>) {
|
||||
return std::make_shared<MacroSegmentUnknown<T>>(
|
||||
MacroAction::GetMacro(), _id);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool MacroSegmentUnknown<T>::Save(obs_data_t *data) const
|
||||
{
|
||||
T::Save(data);
|
||||
obs_data_apply(data, _settings);
|
||||
obs_data_set_string(_settings, "id", _id.c_str());
|
||||
return true;
|
||||
};
|
||||
|
||||
template<typename T> inline bool MacroSegmentUnknown<T>::Load(obs_data_t *data)
|
||||
{
|
||||
T::Load(data);
|
||||
obs_data_apply(_settings, data);
|
||||
return true;
|
||||
};
|
||||
|
||||
inline QWidget *CreateUnknownSegmentWidget(bool isAction)
|
||||
{
|
||||
return new QLabel(obs_module_text(
|
||||
isAction ? "AdvSceneSwitcher.action.unknown"
|
||||
: "AdvSceneSwitcher.condition.unknown"));
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
@@ -1,10 +1,8 @@
|
||||
#include "macro-segment.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "mouse-wheel-guard.hpp"
|
||||
#include "path-helpers.hpp"
|
||||
#include "section.hpp"
|
||||
#include "ui-helpers.hpp"
|
||||
#include "variable.hpp"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QEvent>
|
||||
@@ -15,84 +13,20 @@
|
||||
|
||||
namespace advss {
|
||||
|
||||
std::vector<TempVariableRef> MacroSegment::GetTempVarRefs() const
|
||||
{
|
||||
std::vector<TempVariableRef> refs;
|
||||
for (const auto &mapping : _varMappings) {
|
||||
if (mapping.tempVar.HasValidID()) {
|
||||
refs.push_back(mapping.tempVar);
|
||||
}
|
||||
}
|
||||
return refs;
|
||||
}
|
||||
|
||||
void MacroSegment::ApplyVarMappings()
|
||||
{
|
||||
auto macro = GetMacro();
|
||||
for (const auto &mapping : _varMappings) {
|
||||
auto var = mapping.variable.lock();
|
||||
if (!var) {
|
||||
continue;
|
||||
}
|
||||
const auto tempVar = mapping.tempVar.GetTempVariable(macro);
|
||||
if (!tempVar) {
|
||||
continue;
|
||||
}
|
||||
const auto value = tempVar->Value();
|
||||
if (!value) {
|
||||
continue;
|
||||
}
|
||||
var->SetValue(*value);
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<VarMapping> &MacroSegment::GetVarMappings() const
|
||||
{
|
||||
return _varMappings;
|
||||
}
|
||||
|
||||
void MacroSegment::SetVarMappings(const std::vector<VarMapping> &mappings)
|
||||
{
|
||||
_varMappings = mappings;
|
||||
}
|
||||
|
||||
std::vector<TempVariable> MacroSegment::GetOwnTempVars() const
|
||||
{
|
||||
return _tempVariables;
|
||||
}
|
||||
|
||||
MacroSegment::MacroSegment(Macro *m, bool supportsVariableValue)
|
||||
: _macro(m),
|
||||
_supportsVariableValue(supportsVariableValue)
|
||||
{
|
||||
}
|
||||
|
||||
void MacroSegment::SetVarMappingExpanded(bool expanded)
|
||||
{
|
||||
_varMappingExpanded = expanded;
|
||||
}
|
||||
|
||||
bool MacroSegment::Save(obs_data_t *obj) const
|
||||
{
|
||||
OBSDataAutoRelease data = obs_data_create();
|
||||
obs_data_set_bool(data, "collapsed", _collapsed);
|
||||
obs_data_set_bool(data, "varMappingExpanded", _varMappingExpanded);
|
||||
obs_data_set_bool(data, "useCustomLabel", _useCustomLabel);
|
||||
obs_data_set_string(data, "customLabel", _customLabel.c_str());
|
||||
obs_data_set_bool(data, "enabled", _enabled);
|
||||
obs_data_set_int(data, "version", 2);
|
||||
|
||||
OBSDataArrayAutoRelease mappingsArray = obs_data_array_create();
|
||||
for (const auto &mapping : _varMappings) {
|
||||
OBSDataAutoRelease item = obs_data_create();
|
||||
mapping.tempVar.Save(item, GetMacro(), "tempVar");
|
||||
obs_data_set_string(
|
||||
item, "variable",
|
||||
GetWeakVariableName(mapping.variable).c_str());
|
||||
obs_data_array_push_back(mappingsArray, item);
|
||||
}
|
||||
obs_data_set_array(data, "varMappings", mappingsArray);
|
||||
|
||||
obs_data_set_int(data, "version", 1);
|
||||
obs_data_set_obj(obj, "segmentSettings", data);
|
||||
return true;
|
||||
}
|
||||
@@ -101,7 +35,6 @@ bool MacroSegment::Load(obs_data_t *obj)
|
||||
{
|
||||
OBSDataAutoRelease data = obs_data_get_obj(obj, "segmentSettings");
|
||||
_collapsed = obs_data_get_bool(data, "collapsed");
|
||||
_varMappingExpanded = obs_data_get_bool(data, "varMappingExpanded");
|
||||
_useCustomLabel = obs_data_get_bool(data, "useCustomLabel");
|
||||
_customLabel = obs_data_get_string(data, "customLabel");
|
||||
obs_data_set_default_bool(data, "enabled", true);
|
||||
@@ -112,26 +45,6 @@ bool MacroSegment::Load(obs_data_t *obj)
|
||||
_enabled = obs_data_get_bool(obj, "enabled");
|
||||
}
|
||||
|
||||
// Reset the previously unused "enabled" value for conditions to "true"
|
||||
if (obs_data_get_int(data, "version") < 2 &&
|
||||
obs_data_has_user_value(obj, "logic")) {
|
||||
_enabled = true;
|
||||
}
|
||||
|
||||
_varMappings.clear();
|
||||
OBSDataArrayAutoRelease mappingsArray =
|
||||
obs_data_get_array(data, "varMappings");
|
||||
const size_t count = obs_data_array_count(mappingsArray);
|
||||
_varMappings.reserve(count);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
OBSDataAutoRelease item = obs_data_array_item(mappingsArray, i);
|
||||
VarMapping mapping;
|
||||
mapping.variable = GetWeakVariableByName(
|
||||
obs_data_get_string(item, "variable"));
|
||||
_varMappings.push_back(std::move(mapping));
|
||||
_varMappings.back().tempVar.Load(item, GetMacro(), "tempVar");
|
||||
}
|
||||
|
||||
ClearAvailableTempvars();
|
||||
return true;
|
||||
}
|
||||
@@ -239,16 +152,6 @@ void MacroSegment::AddTempvar(const std::string &id, const std::string &name,
|
||||
NotifyUIAboutTempVarChange(this);
|
||||
}
|
||||
|
||||
bool MacroSegment::IsTempVarInUse(const std::string &id) const
|
||||
{
|
||||
for (const auto &var : _tempVariables) {
|
||||
if (var.ID() == id) {
|
||||
return var.IsInUse();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MacroSegment::SetTempVarValue(const std::string &id,
|
||||
const std::string &value)
|
||||
{
|
||||
@@ -308,38 +211,11 @@ MacroSegmentEdit::MacroSegmentEdit(QWidget *parent)
|
||||
_headerInfo(new QLabel()),
|
||||
_frame(new QWidget),
|
||||
_contentLayout(new QVBoxLayout),
|
||||
_outputMappings(new TempVarOutputMappingsWidget(this)),
|
||||
_varMappingToggle(new QPushButton(this)),
|
||||
_noBorderframe(new QFrame),
|
||||
_borderFrame(new QFrame),
|
||||
_dropLineAbove(new QFrame),
|
||||
_dropLineBelow(new QFrame)
|
||||
{
|
||||
const auto iconPath = QString::fromStdString(GetDataFilePath(
|
||||
"res/images/" + GetThemeTypeName() + "Variable.svg"));
|
||||
_varMappingToggle->setIcon(QIcon(iconPath));
|
||||
_varMappingToggle->setMaximumWidth(22);
|
||||
_varMappingToggle->setFlat(true);
|
||||
_varMappingToggle->setCheckable(true);
|
||||
_varMappingToggle->setVisible(false);
|
||||
_varMappingToggle->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.outputMappings.toggle"));
|
||||
|
||||
QWidget::connect(_varMappingToggle, &QPushButton::toggled,
|
||||
_outputMappings,
|
||||
&TempVarOutputMappingsWidget::SetPanelExpanded);
|
||||
QWidget::connect(_varMappingToggle, &QPushButton::toggled, this,
|
||||
[this](bool checked) {
|
||||
if (Data()) {
|
||||
Data()->SetVarMappingExpanded(checked);
|
||||
}
|
||||
});
|
||||
QWidget::connect(_outputMappings,
|
||||
&TempVarOutputMappingsWidget::ExpandableChanged,
|
||||
_varMappingToggle, &QPushButton::setVisible);
|
||||
QWidget::connect(_section, &Section::Collapsed, _outputMappings,
|
||||
&TempVarOutputMappingsWidget::SetSectionCollapsed);
|
||||
|
||||
_dropLineAbove->setLineWidth(3);
|
||||
_dropLineAbove->setFixedHeight(11);
|
||||
_dropLineBelow->setLineWidth(3);
|
||||
@@ -380,6 +256,23 @@ MacroSegmentEdit::MacroSegmentEdit(QWidget *parent)
|
||||
|
||||
QWidget::connect(_section, &Section::Collapsed, this,
|
||||
&MacroSegmentEdit::Collapsed);
|
||||
// Macro signals
|
||||
QWidget::connect(parent, SIGNAL(MacroAdded(const QString &)), this,
|
||||
SIGNAL(MacroAdded(const QString &)));
|
||||
QWidget::connect(parent, SIGNAL(MacroRemoved(const QString &)), this,
|
||||
SIGNAL(MacroRemoved(const QString &)));
|
||||
QWidget::connect(
|
||||
parent, SIGNAL(MacroRenamed(const QString &, const QString &)),
|
||||
this, SIGNAL(MacroRenamed(const QString &, const QString &)));
|
||||
// Scene group signals
|
||||
QWidget::connect(parent, SIGNAL(SceneGroupAdded(const QString &)), this,
|
||||
SIGNAL(SceneGroupAdded(const QString &)));
|
||||
QWidget::connect(parent, SIGNAL(SceneGroupRemoved(const QString &)),
|
||||
this, SIGNAL(SceneGroupRemoved(const QString &)));
|
||||
QWidget::connect(
|
||||
parent,
|
||||
SIGNAL(SceneGroupRenamed(const QString &, const QString)), this,
|
||||
SIGNAL(SceneGroupRenamed(const QString &, const QString)));
|
||||
|
||||
auto frameLayout = new QGridLayout;
|
||||
frameLayout->setContentsMargins(0, 0, 0, 0);
|
||||
@@ -401,21 +294,6 @@ MacroSegmentEdit::MacroSegmentEdit(QWidget *parent)
|
||||
_headerInfo->installEventFilter(this);
|
||||
}
|
||||
|
||||
void MacroSegmentEdit::SetupVarMappings(MacroSegment *segment)
|
||||
{
|
||||
_outputMappings->SetSegment(segment);
|
||||
_varMappingToggle->setChecked(segment &&
|
||||
segment->GetVarMappingExpanded());
|
||||
}
|
||||
|
||||
void MacroSegmentEdit::ShowVariableMappings(bool show)
|
||||
{
|
||||
_varMappingToggle->setChecked(show);
|
||||
if (Data()) {
|
||||
Data()->SetVarMappingExpanded(show);
|
||||
}
|
||||
}
|
||||
|
||||
bool MacroSegmentEdit::eventFilter(QObject *obj, QEvent *ev)
|
||||
{
|
||||
if (obj == _headerInfo && ev->type() == QEvent::MouseMove) {
|
||||
|
||||
@@ -9,23 +9,15 @@
|
||||
|
||||
#include <QWidget>
|
||||
#include <QFrame>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <QTimer>
|
||||
#include <obs-data.h>
|
||||
#include <memory>
|
||||
|
||||
class QLabel;
|
||||
|
||||
namespace advss {
|
||||
|
||||
class Macro;
|
||||
class Variable;
|
||||
|
||||
struct VarMapping {
|
||||
TempVariableRef tempVar;
|
||||
std::weak_ptr<Variable> variable;
|
||||
};
|
||||
|
||||
class EXPORT MacroSegment : public Lockable {
|
||||
public:
|
||||
@@ -36,15 +28,12 @@ public:
|
||||
int GetIndex() const { return _idx; }
|
||||
void SetCollapsed(bool collapsed) { _collapsed = collapsed; }
|
||||
bool GetCollapsed() const { return _collapsed; }
|
||||
void SetVarMappingExpanded(bool expanded);
|
||||
bool GetVarMappingExpanded() const { return _varMappingExpanded; }
|
||||
void SetUseCustomLabel(bool enable) { _useCustomLabel = enable; }
|
||||
bool GetUseCustomLabel() const { return _useCustomLabel; }
|
||||
void SetCustomLabel(const std::string &label) { _customLabel = label; }
|
||||
std::string GetCustomLabel() const { return _customLabel; }
|
||||
virtual bool Save(obs_data_t *obj) const = 0;
|
||||
virtual bool Load(obs_data_t *obj) = 0;
|
||||
virtual std::vector<TempVariableRef> GetTempVarRefs() const;
|
||||
virtual bool PostLoad();
|
||||
virtual std::string GetShortDesc() const;
|
||||
virtual std::string GetId() const = 0;
|
||||
@@ -53,10 +42,6 @@ public:
|
||||
void SetEnabled(bool);
|
||||
bool Enabled() const;
|
||||
virtual std::string GetVariableValue() const;
|
||||
void ApplyVarMappings();
|
||||
const std::vector<VarMapping> &GetVarMappings() const;
|
||||
void SetVarMappings(const std::vector<VarMapping> &mappings);
|
||||
std::vector<TempVariable> GetOwnTempVars() const;
|
||||
|
||||
protected:
|
||||
friend bool SupportsVariableValue(MacroSegment *);
|
||||
@@ -69,7 +54,6 @@ protected:
|
||||
void AddTempvar(const std::string &id, const std::string &name,
|
||||
const std::string &description = "");
|
||||
|
||||
bool IsTempVarInUse(const std::string &id) const;
|
||||
void SetTempVarValue(const std::string &id, const std::string &value);
|
||||
|
||||
template<typename T, typename = std::enable_if_t<
|
||||
@@ -80,14 +64,6 @@ protected:
|
||||
: std::string("false"));
|
||||
}
|
||||
|
||||
template<typename F, typename = std::enable_if_t<std::is_invocable_v<F>>>
|
||||
void SetTempVarValue(const std::string &id, F &&valueProvider)
|
||||
{
|
||||
if (IsTempVarInUse(id)) {
|
||||
SetTempVarValue(id, valueProvider());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void ClearAvailableTempvars();
|
||||
std::optional<const TempVariable>
|
||||
@@ -101,7 +77,6 @@ private:
|
||||
// UI helper
|
||||
bool _highlight = false;
|
||||
bool _collapsed = false;
|
||||
bool _varMappingExpanded = false;
|
||||
bool _enabled = true;
|
||||
|
||||
// Custom header labels
|
||||
@@ -114,7 +89,6 @@ private:
|
||||
int _variableRefs = 0;
|
||||
std::string _variableValue;
|
||||
std::vector<TempVariable> _tempVariables;
|
||||
std::vector<VarMapping> _varMappings;
|
||||
|
||||
friend class Macro;
|
||||
};
|
||||
@@ -134,14 +108,18 @@ public:
|
||||
virtual std::shared_ptr<MacroSegment> Data() const = 0;
|
||||
virtual void SetupWidgets(bool basicSetup = false) = 0;
|
||||
|
||||
void SetupVarMappings(MacroSegment *segment);
|
||||
|
||||
public slots:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
void ShowVariableMappings(bool show);
|
||||
|
||||
protected slots:
|
||||
void Collapsed(bool) const;
|
||||
signals:
|
||||
void MacroAdded(const QString &name);
|
||||
void MacroRemoved(const QString &name);
|
||||
void MacroRenamed(const QString &oldName, const QString &newName);
|
||||
void SceneGroupAdded(const QString &name);
|
||||
void SceneGroupRemoved(const QString &name);
|
||||
void SceneGroupRenamed(const QString &oldName, const QString newName);
|
||||
|
||||
protected:
|
||||
void SetDisableEffect(bool);
|
||||
@@ -153,8 +131,6 @@ protected:
|
||||
QLabel *_headerInfo;
|
||||
QWidget *_frame;
|
||||
QVBoxLayout *_contentLayout;
|
||||
TempVarOutputMappingsWidget *_outputMappings;
|
||||
QPushButton *_varMappingToggle;
|
||||
bool _allWidgetsAreSetup = false;
|
||||
|
||||
private:
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "layout-helpers.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "macro-signals.hpp"
|
||||
#include "ui-helpers.hpp"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
@@ -14,18 +13,22 @@ MacroSelection::MacroSelection(QWidget *parent)
|
||||
: FilterComboBox(parent,
|
||||
obs_module_text("AdvSceneSwitcher.selectMacro"))
|
||||
{
|
||||
for (const auto &m : GetTopLevelMacros()) {
|
||||
for (const auto &m : GetMacros()) {
|
||||
if (m->IsGroup()) {
|
||||
continue;
|
||||
}
|
||||
addItem(QString::fromStdString(m->Name()));
|
||||
}
|
||||
|
||||
QWidget::connect(MacroSignalManager::Instance(),
|
||||
SIGNAL(Add(const QString &)), this,
|
||||
QWidget::connect(GetSettingsWindow(),
|
||||
SIGNAL(MacroAdded(const QString &)), this,
|
||||
SLOT(MacroAdd(const QString &)));
|
||||
QWidget::connect(MacroSignalManager::Instance(),
|
||||
SIGNAL(Remove(const QString &)), this,
|
||||
QWidget::connect(GetSettingsWindow(),
|
||||
SIGNAL(MacroRemoved(const QString &)), this,
|
||||
SLOT(MacroRemove(const QString &)));
|
||||
QWidget::connect(MacroSignalManager::Instance(),
|
||||
SIGNAL(Rename(const QString &, const QString &)), this,
|
||||
QWidget::connect(GetSettingsWindow(),
|
||||
SIGNAL(MacroRenamed(const QString &, const QString &)),
|
||||
this,
|
||||
SLOT(MacroRename(const QString &, const QString &)));
|
||||
}
|
||||
|
||||
@@ -46,12 +49,11 @@ void MacroSelection::SetCurrentMacro(const MacroRef ¯o)
|
||||
|
||||
void MacroSelection::HideSelectedMacro()
|
||||
{
|
||||
auto ssWindow = static_cast<AdvSceneSwitcher *>(GetSettingsWindow());
|
||||
auto ssWindow = static_cast<AdvSceneSwitcher *>(window());
|
||||
if (!ssWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef UNIT_TEST
|
||||
const auto m = ssWindow->ui->macros->GetCurrentMacro();
|
||||
if (!m) {
|
||||
return;
|
||||
@@ -62,23 +64,6 @@ void MacroSelection::HideSelectedMacro()
|
||||
}
|
||||
|
||||
qobject_cast<QListView *>(view())->setRowHidden(idx, true);
|
||||
#endif // !UNIT_TEST
|
||||
}
|
||||
|
||||
void MacroSelection::HideGroups()
|
||||
{
|
||||
for (const auto ¯o : GetTopLevelMacros()) {
|
||||
if (!macro->IsGroup()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int idx = findText(QString::fromStdString(macro->Name()));
|
||||
if (idx == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
qobject_cast<QListView *>(view())->setRowHidden(idx, true);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroSelection::ShowAllMacros()
|
||||
|
||||
@@ -15,7 +15,6 @@ public:
|
||||
MacroSelection(QWidget *parent);
|
||||
void SetCurrentMacro(const MacroRef &);
|
||||
void HideSelectedMacro(); // Macro currently being edited
|
||||
void HideGroups();
|
||||
void ShowAllMacros();
|
||||
|
||||
private slots:
|
||||
|
||||
@@ -94,9 +94,6 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
|
||||
_currentInputs(new MacroInputSelection()),
|
||||
_currentMacroRegisterDock(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.currentRegisterDock"))),
|
||||
_currentMacroIsStandaloneDock(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.currentIsStandaloneDock"))),
|
||||
_currentMacroDockWindowName(new QLineEdit(this)),
|
||||
_currentMacroDockAddRunButton(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.currentDockAddRunButton"))),
|
||||
_currentMacroDockAddPauseButton(new QCheckBox(obs_module_text(
|
||||
@@ -201,15 +198,6 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
|
||||
int row = 0;
|
||||
_dockLayout->addWidget(_currentMacroRegisterDock, row, 1, 1, 2);
|
||||
row++;
|
||||
_dockLayout->addWidget(_currentMacroIsStandaloneDock, row, 1, 1, 2);
|
||||
row++;
|
||||
_dockLayout->addWidget(
|
||||
new QLabel(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.currentDockWindowName")),
|
||||
row, 1);
|
||||
_dockLayout->addWidget(_currentMacroDockWindowName, row, 2);
|
||||
_dockWindowNameRow = row;
|
||||
row++;
|
||||
_dockLayout->addWidget(_currentMacroDockAddRunButton, row, 1, 1, 2);
|
||||
row++;
|
||||
_dockLayout->addWidget(
|
||||
@@ -264,8 +252,6 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
|
||||
|
||||
connect(_currentMacroRegisterDock, &QCheckBox::stateChanged, this,
|
||||
&MacroSettingsDialog::DockEnableChanged);
|
||||
connect(_currentMacroIsStandaloneDock, &QCheckBox::stateChanged, this,
|
||||
&MacroSettingsDialog::IsStandaloneDockChanged);
|
||||
connect(_currentMacroDockAddRunButton, &QCheckBox::stateChanged, this,
|
||||
&MacroSettingsDialog::RunButtonEnableChanged);
|
||||
connect(_currentMacroDockAddPauseButton, &QCheckBox::stateChanged, this,
|
||||
@@ -343,37 +329,55 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
|
||||
_currentSkipOnStartup->setChecked(macro->SkipExecOnStart());
|
||||
_currentStopActionsIfNotDone->setChecked(macro->StopActionsIfNotDone());
|
||||
_currentInputs->SetInputs(macro->GetInputVariables());
|
||||
const auto &dockSettings = macro->GetDockSettings();
|
||||
const bool dockEnabled = dockSettings.DockEnabled();
|
||||
const bool dockEnabled = macro->DockEnabled();
|
||||
_currentMacroRegisterDock->setChecked(dockEnabled);
|
||||
_currentMacroIsStandaloneDock->setChecked(
|
||||
dockSettings.IsStandaloneDock());
|
||||
_currentMacroDockWindowName->setText(
|
||||
QString::fromStdString(dockSettings.DockWindowName()));
|
||||
_currentMacroDockAddRunButton->setChecked(dockSettings.HasRunButton());
|
||||
_currentMacroDockAddRunButton->setChecked(macro->DockHasRunButton());
|
||||
_currentMacroDockAddPauseButton->setChecked(
|
||||
dockSettings.HasPauseButton());
|
||||
macro->DockHasPauseButton());
|
||||
_currentMacroDockAddStatusLabel->setChecked(
|
||||
dockSettings.HasStatusLabel());
|
||||
macro->DockHasStatusLabel());
|
||||
_currentMacroDockHighlightIfConditionsTrue->setChecked(
|
||||
dockSettings.HighlightEnabled());
|
||||
_runButtonText->setText(dockSettings.RunButtonText());
|
||||
_pauseButtonText->setText(dockSettings.PauseButtonText());
|
||||
_unpauseButtonText->setText(dockSettings.UnpauseButtonText());
|
||||
_conditionsTrueStatusText->setText(
|
||||
dockSettings.ConditionsTrueStatusText());
|
||||
_conditionsFalseStatusText->setText(
|
||||
dockSettings.ConditionsFalseStatusText());
|
||||
macro->DockHighlightEnabled());
|
||||
_runButtonText->setText(macro->RunButtonText());
|
||||
_pauseButtonText->setText(macro->PauseButtonText());
|
||||
_unpauseButtonText->setText(macro->UnpauseButtonText());
|
||||
_conditionsTrueStatusText->setText(macro->ConditionsTrueStatusText());
|
||||
_conditionsFalseStatusText->setText(macro->ConditionsFalseStatusText());
|
||||
|
||||
DockEnableChanged(dockEnabled);
|
||||
_currentMacroDockAddRunButton->setVisible(dockEnabled);
|
||||
_currentMacroDockAddPauseButton->setVisible(dockEnabled);
|
||||
_currentMacroDockAddStatusLabel->setVisible(dockEnabled);
|
||||
_currentMacroDockHighlightIfConditionsTrue->setVisible(dockEnabled);
|
||||
SetGridLayoutRowVisible(_dockLayout, _runButtonTextRow,
|
||||
dockEnabled && macro->DockHasRunButton());
|
||||
SetGridLayoutRowVisible(_dockLayout, _pauseButtonTextRow,
|
||||
dockEnabled && macro->DockHasPauseButton());
|
||||
SetGridLayoutRowVisible(_dockLayout, _unpauseButtonTextRow,
|
||||
dockEnabled && macro->DockHasPauseButton());
|
||||
SetGridLayoutRowVisible(_dockLayout, _conditionsTrueTextRow,
|
||||
dockEnabled && macro->DockHasStatusLabel());
|
||||
SetGridLayoutRowVisible(_dockLayout, _conditionsFalseTextRow,
|
||||
dockEnabled && macro->DockHasStatusLabel());
|
||||
MinimizeSizeOfColumn(_dockLayout, 0);
|
||||
|
||||
Resize();
|
||||
|
||||
// Try to set sensible initial size for the dialog window
|
||||
QSize contentSize = contentWidget->sizeHint();
|
||||
resize(contentSize.width() + layout->contentsMargins().left() +
|
||||
layout->contentsMargins().right() +
|
||||
dialogLayout->contentsMargins().left() +
|
||||
dialogLayout->contentsMargins().right() +
|
||||
scrollArea->verticalScrollBar()->sizeHint().width() + 20,
|
||||
contentSize.height() + dialogLayout->spacing() +
|
||||
buttonbox->sizeHint().height() +
|
||||
dialogLayout->contentsMargins().top() +
|
||||
dialogLayout->contentsMargins().bottom() +
|
||||
scrollArea->horizontalScrollBar()->sizeHint().height() +
|
||||
20);
|
||||
}
|
||||
|
||||
void MacroSettingsDialog::DockEnableChanged(int enabled)
|
||||
{
|
||||
_currentMacroIsStandaloneDock->setVisible(enabled);
|
||||
_currentMacroDockAddRunButton->setVisible(enabled);
|
||||
_currentMacroDockAddPauseButton->setVisible(enabled);
|
||||
_currentMacroDockAddStatusLabel->setVisible(enabled);
|
||||
@@ -397,12 +401,6 @@ void MacroSettingsDialog::DockEnableChanged(int enabled)
|
||||
Resize();
|
||||
}
|
||||
|
||||
void MacroSettingsDialog::IsStandaloneDockChanged(int enabled)
|
||||
{
|
||||
SetGridLayoutRowVisible(_dockLayout, _dockWindowNameRow, !enabled);
|
||||
Resize();
|
||||
}
|
||||
|
||||
void MacroSettingsDialog::RunButtonEnableChanged(int enabled)
|
||||
{
|
||||
SetGridLayoutRowVisible(_dockLayout, _runButtonTextRow, enabled);
|
||||
@@ -480,30 +478,23 @@ bool MacroSettingsDialog::AskForSettings(QWidget *parent,
|
||||
macro->SetSkipExecOnStart(dialog._currentSkipOnStartup->isChecked());
|
||||
macro->SetStopActionsIfNotDone(
|
||||
dialog._currentStopActionsIfNotDone->isChecked());
|
||||
|
||||
auto &dockSettings = macro->GetDockSettings();
|
||||
dockSettings.EnableDock(dialog._currentMacroRegisterDock->isChecked());
|
||||
dockSettings.SetIsStandaloneDock(
|
||||
dialog._currentMacroIsStandaloneDock->isChecked());
|
||||
dockSettings.SetDockWindowName(
|
||||
dialog._currentMacroDockWindowName->text().toStdString());
|
||||
dockSettings.SetHasRunButton(
|
||||
macro->EnableDock(dialog._currentMacroRegisterDock->isChecked());
|
||||
macro->SetDockHasRunButton(
|
||||
dialog._currentMacroDockAddRunButton->isChecked());
|
||||
dockSettings.SetHasPauseButton(
|
||||
macro->SetDockHasPauseButton(
|
||||
dialog._currentMacroDockAddPauseButton->isChecked());
|
||||
dockSettings.SetHasStatusLabel(
|
||||
macro->SetDockHasStatusLabel(
|
||||
dialog._currentMacroDockAddStatusLabel->isChecked());
|
||||
dockSettings.SetHighlightEnable(
|
||||
macro->SetHighlightEnable(
|
||||
dialog._currentMacroDockHighlightIfConditionsTrue->isChecked());
|
||||
dockSettings.SetRunButtonText(
|
||||
dialog._runButtonText->text().toStdString());
|
||||
dockSettings.SetPauseButtonText(
|
||||
macro->SetRunButtonText(dialog._runButtonText->text().toStdString());
|
||||
macro->SetPauseButtonText(
|
||||
dialog._pauseButtonText->text().toStdString());
|
||||
dockSettings.SetUnpauseButtonText(
|
||||
macro->SetUnpauseButtonText(
|
||||
dialog._unpauseButtonText->text().toStdString());
|
||||
dockSettings.SetConditionsTrueStatusText(
|
||||
macro->SetConditionsTrueStatusText(
|
||||
dialog._conditionsTrueStatusText->text().toStdString());
|
||||
dockSettings.SetConditionsFalseStatusText(
|
||||
macro->SetConditionsFalseStatusText(
|
||||
dialog._conditionsFalseStatusText->text().toStdString());
|
||||
macro->SetInputVariables(dialog._currentInputs->GetInputs());
|
||||
return true;
|
||||
|
||||
@@ -41,7 +41,6 @@ public:
|
||||
Macro *macro);
|
||||
private slots:
|
||||
void DockEnableChanged(int);
|
||||
void IsStandaloneDockChanged(int);
|
||||
void RunButtonEnableChanged(int);
|
||||
void PauseButtonEnableChanged(int);
|
||||
void StatusLabelEnableChanged(int);
|
||||
@@ -70,8 +69,6 @@ private:
|
||||
QCheckBox *_currentStopActionsIfNotDone;
|
||||
MacroInputSelection *_currentInputs;
|
||||
QCheckBox *_currentMacroRegisterDock;
|
||||
QCheckBox *_currentMacroIsStandaloneDock;
|
||||
QLineEdit *_currentMacroDockWindowName;
|
||||
QCheckBox *_currentMacroDockAddRunButton;
|
||||
QCheckBox *_currentMacroDockAddPauseButton;
|
||||
QCheckBox *_currentMacroDockAddStatusLabel;
|
||||
@@ -84,7 +81,6 @@ private:
|
||||
QGroupBox *_dockOptions;
|
||||
QGridLayout *_dockLayout;
|
||||
|
||||
int _dockWindowNameRow = -1;
|
||||
int _runButtonTextRow = -1;
|
||||
int _pauseButtonTextRow = -1;
|
||||
int _unpauseButtonTextRow = -1;
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
#include "macro-signals.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
MacroSignalManager::MacroSignalManager(QObject *parent) : QObject(parent) {}
|
||||
|
||||
MacroSignalManager *MacroSignalManager::Instance()
|
||||
{
|
||||
static MacroSignalManager manager;
|
||||
return &manager;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
@@ -1,26 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
#include "export-symbol-helper.hpp"
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
namespace advss {
|
||||
|
||||
class ADVSS_EXPORT MacroSignalManager : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static MacroSignalManager *Instance();
|
||||
|
||||
signals:
|
||||
void Rename(const QString &, const QString &);
|
||||
void Add(const QString &);
|
||||
void Remove(const QString &);
|
||||
void SegmentOrderChanged();
|
||||
void HighlightChanged(bool value);
|
||||
|
||||
private:
|
||||
MacroSignalManager(QObject *parent = nullptr);
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,21 +1,20 @@
|
||||
#include "macro-tree.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "macro-search.hpp"
|
||||
#include "macro-signals.hpp"
|
||||
#include "path-helpers.hpp"
|
||||
#include "sync-helpers.hpp"
|
||||
#include "ui-helpers.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <obs.h>
|
||||
#include <string>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QSpacerItem>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QMouseEvent>
|
||||
#include <QStylePainter>
|
||||
#include <QToolTip>
|
||||
|
||||
Q_DECLARE_METATYPE(std::shared_ptr<advss::Macro>);
|
||||
|
||||
@@ -61,11 +60,12 @@ MacroTreeItem::MacroTreeItem(MacroTree *tree, std::shared_ptr<Macro> macroItem,
|
||||
|
||||
_boxLayout = new QHBoxLayout();
|
||||
_boxLayout->setContentsMargins(0, 0, 0, 0);
|
||||
_boxLayout->addWidget(_running);
|
||||
if (isGroup) {
|
||||
_boxLayout->addWidget(_iconLabel);
|
||||
_boxLayout->addSpacing(2);
|
||||
_running->hide();
|
||||
}
|
||||
_boxLayout->addWidget(_running);
|
||||
_boxLayout->addWidget(_label);
|
||||
#ifdef __APPLE__
|
||||
/* Hack: Fixes a bug where scrollbars would be above the lock icon */
|
||||
@@ -75,138 +75,29 @@ MacroTreeItem::MacroTreeItem(MacroTree *tree, std::shared_ptr<Macro> macroItem,
|
||||
Update(true);
|
||||
setLayout(_boxLayout);
|
||||
|
||||
connect(_running, SIGNAL(clicked(bool)), this,
|
||||
SLOT(RunningClicked(bool)));
|
||||
connect(MacroSignalManager::Instance(), SIGNAL(HighlightChanged(bool)),
|
||||
this, SLOT(EnableHighlight(bool)));
|
||||
connect(MacroSignalManager::Instance(),
|
||||
SIGNAL(Rename(const QString &, const QString &)), this,
|
||||
auto setRunning = [this](bool val) {
|
||||
_macro->SetPaused(!val);
|
||||
};
|
||||
connect(_running, &QAbstractButton::clicked, setRunning);
|
||||
connect(_tree->window(), SIGNAL(HighlightMacrosChanged(bool)), this,
|
||||
SLOT(EnableHighlight(bool)));
|
||||
connect(_tree->window(),
|
||||
SIGNAL(MacroRenamed(const QString &, const QString &)), this,
|
||||
SLOT(MacroRenamed(const QString &, const QString &)));
|
||||
connect(&_timer, SIGNAL(timeout()), this, SLOT(HighlightIfExecuted()));
|
||||
connect(&_timer, SIGNAL(timeout()), this, SLOT(UpdateRunning()));
|
||||
|
||||
UpdateRunning();
|
||||
connect(&_timer, SIGNAL(timeout()), this, SLOT(UpdatePaused()));
|
||||
_timer.start(1500);
|
||||
}
|
||||
|
||||
bool MacroTreeItem::event(QEvent *event)
|
||||
{
|
||||
if (event->type() != QEvent::ToolTip) {
|
||||
return QFrame::event(event);
|
||||
}
|
||||
|
||||
if (_macro->IsGroup()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
QString text;
|
||||
if (!_macro->WasExecutedSince({})) {
|
||||
text = obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.macroNotYetExecutedTooltip");
|
||||
} else {
|
||||
const QString formatStr = obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.macroLastExecutedTooltip");
|
||||
const auto secondsSinceLastRun =
|
||||
std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::high_resolution_clock::now() -
|
||||
_macro->GetLastExecutionTime());
|
||||
text = formatStr.arg(secondsSinceLastRun.count());
|
||||
}
|
||||
|
||||
auto helpEvent = static_cast<QHelpEvent *>(event);
|
||||
QToolTip::showText(helpEvent->globalPos(), text, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void MacroTreeItem::EnableHighlight(bool enable)
|
||||
{
|
||||
_highlight = enable;
|
||||
}
|
||||
|
||||
void MacroTreeItem::RunningClicked(bool running)
|
||||
{
|
||||
const auto updateWidget = [this](Macro *macro) {
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto ¯os = GetTopLevelMacros();
|
||||
|
||||
bool found = false;
|
||||
int idx = 0;
|
||||
for (const auto &m : macros) {
|
||||
if (m.get() == macro) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto widget = _tree->GetItemWidget(idx);
|
||||
if (widget) {
|
||||
widget->UpdateRunning();
|
||||
}
|
||||
};
|
||||
|
||||
if (!_macro->IsGroup()) {
|
||||
_macro->SetPaused(!running);
|
||||
if (!_macro->IsSubitem()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto group = _macro->Parent();
|
||||
updateWidget(group.get());
|
||||
return;
|
||||
}
|
||||
|
||||
const auto macros = GetGroupMacroEntries(_macro.get());
|
||||
for (const auto ¯o : macros) {
|
||||
macro->SetPaused(!running);
|
||||
}
|
||||
|
||||
// Update backend values before updating UI to prevent flickering in
|
||||
// running state of the group
|
||||
for (const auto ¯o : macros) {
|
||||
updateWidget(macro.get());
|
||||
}
|
||||
UpdateRunning();
|
||||
}
|
||||
|
||||
void MacroTreeItem::UpdateRunning()
|
||||
void MacroTreeItem::UpdatePaused()
|
||||
{
|
||||
const QSignalBlocker blocker(_running);
|
||||
|
||||
if (!_macro->IsGroup()) {
|
||||
_running->setChecked(!_macro->Paused());
|
||||
return;
|
||||
}
|
||||
|
||||
const auto macros = GetGroupMacroEntries(_macro.get());
|
||||
bool allRunning = true;
|
||||
bool allPaused = true;
|
||||
for (const auto ¯o : macros) {
|
||||
if (macro->Paused()) {
|
||||
allRunning = false;
|
||||
} else {
|
||||
allPaused = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (allRunning) {
|
||||
_running->setCheckState(Qt::Checked);
|
||||
return;
|
||||
}
|
||||
|
||||
if (allPaused) {
|
||||
_running->setCheckState(Qt::Unchecked);
|
||||
return;
|
||||
}
|
||||
|
||||
_running->setCheckState(Qt::PartiallyChecked);
|
||||
_running->setChecked(!_macro->Paused());
|
||||
}
|
||||
|
||||
void MacroTreeItem::HighlightIfExecuted()
|
||||
@@ -215,20 +106,10 @@ void MacroTreeItem::HighlightIfExecuted()
|
||||
return;
|
||||
}
|
||||
|
||||
bool wasHighlighted = false;
|
||||
if (_lastHighlightCheckTime.time_since_epoch().count() != 0 &&
|
||||
_macro->WasExecutedSince(_lastHighlightCheckTime)) {
|
||||
HighlightWidget(this, Qt::green, QColor(0, 0, 0, 0), true);
|
||||
wasHighlighted = true;
|
||||
}
|
||||
|
||||
if (!wasHighlighted &&
|
||||
_lastHighlightCheckTime.time_since_epoch().count() != 0 &&
|
||||
_macro->ActionTriggerModePreventedActionsSince(
|
||||
_lastHighlightCheckTime)) {
|
||||
HighlightWidget(this, Qt::yellow, QColor(0, 0, 0, 0), true);
|
||||
}
|
||||
|
||||
_lastHighlightCheckTime = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
@@ -305,7 +186,7 @@ void MacroTreeItem::Update(bool force)
|
||||
_expand->blockSignals(true);
|
||||
_expand->setChecked(_macro->IsCollapsed());
|
||||
_expand->blockSignals(false);
|
||||
connect(_expand, &QCheckBox::toggled, this,
|
||||
connect(_expand, &QPushButton::toggled, this,
|
||||
&MacroTreeItem::ExpandClicked);
|
||||
} else {
|
||||
_spacer = new QSpacerItem(3, 1);
|
||||
@@ -331,6 +212,7 @@ void MacroTreeModel::Reset(std::deque<std::shared_ptr<Macro>> &newItems)
|
||||
_macros = newItems;
|
||||
endResetModel();
|
||||
|
||||
UpdateGroupState(false);
|
||||
_mt->ResetWidgets();
|
||||
}
|
||||
|
||||
@@ -532,20 +414,6 @@ void MacroTreeModel::Add(std::shared_ptr<Macro> item)
|
||||
QItemSelectionModel::Select);
|
||||
}
|
||||
|
||||
void MacroTreeModel::MoveToBeginningOfGroup(std::shared_ptr<Macro> item,
|
||||
std::shared_ptr<Macro> group)
|
||||
{
|
||||
auto it = std::find(_macros.begin(), _macros.end(), item);
|
||||
assert(it != _macros.end());
|
||||
std::shared_ptr<Macro> tmp = *it;
|
||||
_macros.erase(it);
|
||||
it = std::find(_macros.begin(), _macros.end(), group);
|
||||
assert(it != _macros.end());
|
||||
_macros.insert(std::next(it), tmp);
|
||||
|
||||
Reset(_macros);
|
||||
}
|
||||
|
||||
void MacroTreeModel::Remove(std::shared_ptr<Macro> item)
|
||||
{
|
||||
auto lock = LockContext();
|
||||
@@ -575,6 +443,9 @@ void MacroTreeModel::Remove(std::shared_ptr<Macro> item)
|
||||
|
||||
_mt->selectionModel()->clear();
|
||||
|
||||
if (isGroup) {
|
||||
UpdateGroupState(true);
|
||||
}
|
||||
assert(IsInValidState());
|
||||
}
|
||||
|
||||
@@ -663,6 +534,7 @@ MacroTreeModel::MacroTreeModel(MacroTree *st_,
|
||||
_mt(st_),
|
||||
_macros(macros)
|
||||
{
|
||||
UpdateGroupState(false);
|
||||
}
|
||||
|
||||
int MacroTreeModel::rowCount(const QModelIndex &parent) const
|
||||
@@ -816,6 +688,7 @@ void MacroTreeModel::GroupSelectedItems(QModelIndexList &indices)
|
||||
offset++;
|
||||
}
|
||||
|
||||
_hasGroups = true;
|
||||
_mt->selectionModel()->clear();
|
||||
|
||||
Reset(_macros);
|
||||
@@ -873,12 +746,29 @@ void MacroTreeModel::CollapseGroup(std::shared_ptr<Macro> item)
|
||||
assert(IsInValidState());
|
||||
}
|
||||
|
||||
void MacroTreeModel::UpdateGroupState(bool update)
|
||||
{
|
||||
bool nowHasGroups = false;
|
||||
for (auto &item : _macros) {
|
||||
if (item->IsGroup()) {
|
||||
nowHasGroups = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nowHasGroups != _hasGroups) {
|
||||
_hasGroups = nowHasGroups;
|
||||
if (update) {
|
||||
_mt->UpdateWidgets(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MacroTree::Reset(std::deque<std::shared_ptr<Macro>> ¯os,
|
||||
bool highlight)
|
||||
{
|
||||
_highlight = highlight;
|
||||
|
||||
auto mtm = new MacroTreeModel(this, macros);
|
||||
MacroTreeModel *mtm = new MacroTreeModel(this, macros);
|
||||
setModel(mtm);
|
||||
GetModel()->Reset(macros);
|
||||
connect(selectionModel(),
|
||||
@@ -899,13 +789,6 @@ void MacroTree::Add(std::shared_ptr<Macro> item,
|
||||
assert(GetModel()->IsInValidState());
|
||||
}
|
||||
|
||||
void MacroTree::AddToGroup(std::shared_ptr<Macro> item,
|
||||
std::shared_ptr<Macro> group) const
|
||||
{
|
||||
GetModel()->Add(item);
|
||||
GetModel()->MoveToBeginningOfGroup(item, group);
|
||||
}
|
||||
|
||||
std::shared_ptr<Macro> MacroTree::GetCurrentMacro() const
|
||||
{
|
||||
return GetModel()->GetCurrentMacro();
|
||||
@@ -935,6 +818,7 @@ MacroTree::MacroTree(QWidget *parent_) : QListView(parent_)
|
||||
void MacroTree::ResetWidgets()
|
||||
{
|
||||
MacroTreeModel *mtm = GetModel();
|
||||
mtm->UpdateGroupState(false);
|
||||
int modelIdx = 0;
|
||||
for (int i = 0; i < (int)mtm->_macros.size(); i++) {
|
||||
QModelIndex index = mtm->createIndex(modelIdx, 0, nullptr);
|
||||
@@ -963,7 +847,7 @@ void MacroTree::UpdateWidgets(bool force)
|
||||
|
||||
for (int i = 0; i < (int)mtm->_macros.size(); i++) {
|
||||
std::shared_ptr<Macro> item = mtm->_macros[i];
|
||||
auto widget = GetItemWidget(i);
|
||||
MacroTreeItem *widget = GetItemWidget(i);
|
||||
|
||||
if (!widget) {
|
||||
UpdateWidget(mtm->createIndex(i, 0, nullptr), item);
|
||||
@@ -1276,34 +1160,6 @@ bool MacroTree::SelectionEmpty() const
|
||||
return selectedIndexes().empty();
|
||||
}
|
||||
|
||||
bool MacroTree::GroupsExist() const
|
||||
{
|
||||
for (const auto ¯o : GetTopLevelMacros()) {
|
||||
if (macro->IsGroup()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MacroTree::ExpandGroup(std::shared_ptr<Macro> item) const
|
||||
{
|
||||
auto *mtm = GetModel();
|
||||
mtm->ExpandGroup(item);
|
||||
}
|
||||
|
||||
void MacroTree::CollapseGroup(std::shared_ptr<Macro> item) const
|
||||
{
|
||||
auto *mtm = GetModel();
|
||||
mtm->CollapseGroup(item);
|
||||
}
|
||||
|
||||
void MacroTree::RefreshFilter()
|
||||
{
|
||||
UpdateWidgets();
|
||||
doItemsLayout();
|
||||
}
|
||||
|
||||
void MacroTree::MoveItemBefore(const std::shared_ptr<Macro> &item,
|
||||
const std::shared_ptr<Macro> &after) const
|
||||
{
|
||||
@@ -1318,7 +1174,7 @@ void MacroTree::MoveItemAfter(const std::shared_ptr<Macro> &item,
|
||||
|
||||
MacroTreeModel *MacroTree::GetModel() const
|
||||
{
|
||||
return qobject_cast<MacroTreeModel *>(model());
|
||||
return reinterpret_cast<MacroTreeModel *>(model());
|
||||
}
|
||||
|
||||
void MacroTree::Remove(std::shared_ptr<Macro> item) const
|
||||
@@ -1404,26 +1260,6 @@ void MacroTree::UngroupSelectedGroups()
|
||||
assert(GetModel()->IsInValidState());
|
||||
}
|
||||
|
||||
void MacroTree::ExpandAll()
|
||||
{
|
||||
for (const auto ¯o : GetTopLevelMacros()) {
|
||||
if (!macro->IsGroup()) {
|
||||
continue;
|
||||
}
|
||||
ExpandGroup(macro);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroTree::CollapseAll()
|
||||
{
|
||||
for (const auto ¯o : GetTopLevelMacros()) {
|
||||
if (!macro->IsGroup()) {
|
||||
continue;
|
||||
}
|
||||
CollapseGroup(macro);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroTree::SelectionChangedHelper(const QItemSelection &,
|
||||
const QItemSelection &)
|
||||
{
|
||||
@@ -1433,8 +1269,8 @@ void MacroTree::SelectionChangedHelper(const QItemSelection &,
|
||||
|
||||
inline MacroTreeItem *MacroTree::GetItemWidget(int idx) const
|
||||
{
|
||||
auto widget = indexWidget(GetModel()->createIndex(idx, 0, nullptr));
|
||||
return qobject_cast<MacroTreeItem *>(widget);
|
||||
QWidget *widget = indexWidget(GetModel()->createIndex(idx, 0, nullptr));
|
||||
return reinterpret_cast<MacroTreeItem *>(widget);
|
||||
}
|
||||
|
||||
void MacroTree::paintEvent(QPaintEvent *event)
|
||||
@@ -1461,25 +1297,14 @@ MacroTreeDelegate::MacroTreeDelegate(QObject *parent)
|
||||
QSize MacroTreeDelegate::sizeHint(const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
auto tree = qobject_cast<MacroTree *>(parent());
|
||||
auto widget = tree->indexWidget(index);
|
||||
MacroTree *tree = qobject_cast<MacroTree *>(parent());
|
||||
QWidget *item = tree->indexWidget(index);
|
||||
|
||||
if (!widget) {
|
||||
if (!item) {
|
||||
return QStyledItemDelegate::sizeHint(option, index);
|
||||
}
|
||||
|
||||
auto name = index.data(Qt::AccessibleTextRole).toString();
|
||||
auto macro = GetMacroByQString(name);
|
||||
|
||||
if (!macro) {
|
||||
return QStyledItemDelegate::sizeHint(option, index);
|
||||
}
|
||||
|
||||
if (MacroMatchesSearchFilter(macro)) {
|
||||
return QSize(widget->sizeHint());
|
||||
}
|
||||
|
||||
return QSize(0, 0);
|
||||
return QSize(item->sizeHint());
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -34,14 +34,10 @@ public:
|
||||
explicit MacroTreeItem(MacroTree *tree, std::shared_ptr<Macro> macro,
|
||||
bool highlight);
|
||||
|
||||
protected:
|
||||
bool event(QEvent *) override;
|
||||
|
||||
private slots:
|
||||
void ExpandClicked(bool checked);
|
||||
void EnableHighlight(bool enable);
|
||||
void RunningClicked(bool);
|
||||
void UpdateRunning();
|
||||
void UpdatePaused();
|
||||
void HighlightIfExecuted();
|
||||
void MacroRenamed(const QString &, const QString &);
|
||||
|
||||
@@ -95,8 +91,6 @@ private:
|
||||
void MoveItemAfter(const std::shared_ptr<Macro> &item,
|
||||
const std::shared_ptr<Macro> &after);
|
||||
void Add(std::shared_ptr<Macro> item);
|
||||
void MoveToBeginningOfGroup(std::shared_ptr<Macro> item,
|
||||
std::shared_ptr<Macro>);
|
||||
void Remove(std::shared_ptr<Macro> item);
|
||||
std::shared_ptr<Macro> Neighbor(const std::shared_ptr<Macro> &m,
|
||||
bool above) const;
|
||||
@@ -110,6 +104,7 @@ private:
|
||||
void UngroupSelectedGroups(QModelIndexList &indices);
|
||||
void ExpandGroup(std::shared_ptr<Macro> item);
|
||||
void CollapseGroup(std::shared_ptr<Macro> item);
|
||||
void UpdateGroupState(bool update);
|
||||
int GetItemMacroIndex(const std::shared_ptr<Macro> &item) const;
|
||||
int GetItemModelIndex(const std::shared_ptr<Macro> &item) const;
|
||||
bool IsLastItem(std::shared_ptr<Macro> item) const;
|
||||
@@ -117,6 +112,7 @@ private:
|
||||
|
||||
MacroTree *_mt;
|
||||
std::deque<std::shared_ptr<Macro>> &_macros;
|
||||
bool _hasGroups = false;
|
||||
|
||||
friend class MacroTree;
|
||||
friend class MacroTreeItem;
|
||||
@@ -130,8 +126,6 @@ public:
|
||||
void Reset(std::deque<std::shared_ptr<Macro>> &, bool highlight);
|
||||
void Add(std::shared_ptr<Macro> item,
|
||||
std::shared_ptr<Macro> after = {}) const;
|
||||
void AddToGroup(std::shared_ptr<Macro> item,
|
||||
std::shared_ptr<Macro> group) const;
|
||||
void Remove(std::shared_ptr<Macro> item) const;
|
||||
void Up(std::shared_ptr<Macro> item) const;
|
||||
void Down(std::shared_ptr<Macro> item) const;
|
||||
@@ -141,16 +135,10 @@ public:
|
||||
bool GroupedItemsSelected() const;
|
||||
bool SingleItemSelected() const;
|
||||
bool SelectionEmpty() const;
|
||||
bool GroupsExist() const;
|
||||
void ExpandGroup(std::shared_ptr<Macro> item) const;
|
||||
void CollapseGroup(std::shared_ptr<Macro> item) const;
|
||||
void RefreshFilter();
|
||||
|
||||
public slots:
|
||||
void GroupSelectedItems();
|
||||
void UngroupSelectedGroups();
|
||||
void ExpandAll();
|
||||
void CollapseAll();
|
||||
void SelectionChangedHelper(const QItemSelection &,
|
||||
const QItemSelection &);
|
||||
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
#include "websocket-api.hpp"
|
||||
#include "log-helper.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "variable.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
|
||||
#include <obs.hpp>
|
||||
|
||||
namespace advss {
|
||||
|
||||
static bool setup();
|
||||
static bool setupDone = setup();
|
||||
static void receiveRunMacroMessage(obs_data_t *data, obs_data_t *);
|
||||
static void receiveSetVariablesMessage(obs_data_t *data, obs_data_t *);
|
||||
|
||||
static const char *runMacroMessage = "AdvancedSceneSwitcherRunMacro";
|
||||
static const char *setVariablesMessage = "AdvancedSceneSwitcherSetVariables";
|
||||
|
||||
static bool setup()
|
||||
{
|
||||
AddPluginInitStep([]() {
|
||||
RegisterWebsocketRequest(runMacroMessage,
|
||||
receiveRunMacroMessage);
|
||||
RegisterWebsocketRequest(setVariablesMessage,
|
||||
receiveSetVariablesMessage);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
static void setVariables(obs_data_t *data)
|
||||
{
|
||||
OBSDataArrayAutoRelease variables =
|
||||
obs_data_get_array(data, "variables");
|
||||
size_t count = obs_data_array_count(variables);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
OBSDataAutoRelease item = obs_data_array_item(variables, i);
|
||||
if (!obs_data_has_user_value(item, "name")) {
|
||||
blog(LOG_INFO,
|
||||
"ignoring invalid variable entry in \"%s\" websocket message (missing \"name\")",
|
||||
runMacroMessage);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!obs_data_has_user_value(item, "value")) {
|
||||
blog(LOG_INFO,
|
||||
"ignoring invalid variable entry in \"%s\" websocket message (missing \"value\")",
|
||||
runMacroMessage);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto varName = obs_data_get_string(item, "name");
|
||||
auto value = obs_data_get_string(item, "value");
|
||||
|
||||
auto weakVar = GetWeakVariableByName(varName);
|
||||
auto var = weakVar.lock();
|
||||
if (!var) {
|
||||
blog(LOG_INFO,
|
||||
"ignoring invalid variable name \"%s\" in \"%s\" websocket message",
|
||||
varName, runMacroMessage);
|
||||
continue;
|
||||
}
|
||||
|
||||
var->SetValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
static void receiveRunMacroMessage(obs_data_t *data, obs_data_t *)
|
||||
{
|
||||
if (!obs_data_has_user_value(data, "name")) {
|
||||
blog(LOG_INFO,
|
||||
"ignoring invalid \"%s\" websocket message (missing \"name\")",
|
||||
runMacroMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
auto name = obs_data_get_string(data, "name");
|
||||
const auto weakMacro =
|
||||
GetWeakMacroByName(obs_data_get_string(data, "name"));
|
||||
const auto macro = weakMacro.lock();
|
||||
if (!macro) {
|
||||
blog(LOG_INFO,
|
||||
"ignoring invalid \"%s\" websocket message (macro \"%s\") not found",
|
||||
runMacroMessage, name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (obs_data_has_user_value(data, "variables")) {
|
||||
setVariables(data);
|
||||
}
|
||||
|
||||
const bool runElse = obs_data_get_bool(data, "runElseActions");
|
||||
if (runElse) {
|
||||
RunMacroElseActions(macro.get());
|
||||
} else {
|
||||
RunMacroActions(macro.get());
|
||||
}
|
||||
}
|
||||
|
||||
static void receiveSetVariablesMessage(obs_data_t *data, obs_data_t *)
|
||||
{
|
||||
if (!obs_data_has_user_value(data, "variables")) {
|
||||
blog(LOG_INFO,
|
||||
"ignoring invalid \"%s\" websocket message (missing \"variables\")",
|
||||
setVariablesMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
setVariables(data);
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "macro.hpp"
|
||||
#include "macro-action-factory.hpp"
|
||||
#include "macro-condition-factory.hpp"
|
||||
#include "macro-dock.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "macro-settings.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
@@ -14,21 +15,69 @@
|
||||
#include <QAction>
|
||||
#include <QMainWindow>
|
||||
#include <unordered_map>
|
||||
#include <util/platform.h>
|
||||
|
||||
namespace advss {
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(30, 0, 0)
|
||||
#include <QDockWidget>
|
||||
|
||||
static bool setup()
|
||||
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)
|
||||
{
|
||||
AddPluginCleanupStep([]() {
|
||||
GetTopLevelMacros().clear();
|
||||
GetTemporaryMacros().clear();
|
||||
});
|
||||
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 bool setupDone = setup();
|
||||
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);
|
||||
}
|
||||
|
||||
Macro::Macro(const std::string &name) : _dockSettings(this)
|
||||
#endif
|
||||
|
||||
namespace advss {
|
||||
|
||||
static std::deque<std::shared_ptr<Macro>> macros;
|
||||
|
||||
Macro::Macro(const std::string &name)
|
||||
{
|
||||
SetName(name);
|
||||
}
|
||||
@@ -50,6 +99,12 @@ Macro::~Macro()
|
||||
_die = true;
|
||||
Stop();
|
||||
ClearHotkeys();
|
||||
|
||||
// Keep the dock widgets in case of shutdown so they can be restored by
|
||||
// OBS on startup
|
||||
if (!OBSIsShuttingDown()) {
|
||||
RemoveDock();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Macro>
|
||||
@@ -68,7 +123,6 @@ Macro::CreateGroup(const std::string &name,
|
||||
|
||||
void Macro::RemoveGroup(std::shared_ptr<Macro> group)
|
||||
{
|
||||
auto ¯os = GetTopLevelMacros();
|
||||
auto it = std::find(macros.begin(), macros.end(), group);
|
||||
if (it == macros.end()) {
|
||||
return;
|
||||
@@ -85,7 +139,6 @@ void Macro::RemoveGroup(std::shared_ptr<Macro> group)
|
||||
|
||||
void Macro::PrepareMoveToGroup(Macro *group, std::shared_ptr<Macro> item)
|
||||
{
|
||||
auto ¯os = GetTopLevelMacros();
|
||||
for (const auto &m : macros) {
|
||||
if (m.get() == group) {
|
||||
PrepareMoveToGroup(m, item);
|
||||
@@ -122,9 +175,8 @@ static bool checkCondition(const std::shared_ptr<MacroCondition> &condition)
|
||||
const auto startTime = std::chrono::high_resolution_clock::now();
|
||||
bool conditionMatched = false;
|
||||
condition->WithLock([&condition, &conditionMatched]() {
|
||||
conditionMatched = condition->EvaluateCondition();
|
||||
conditionMatched = condition->CheckCondition();
|
||||
});
|
||||
condition->ApplyVarMappings();
|
||||
const auto endTime = std::chrono::high_resolution_clock::now();
|
||||
const auto timeSpent = endTime - startTime;
|
||||
|
||||
@@ -157,15 +209,6 @@ bool Macro::CheckConditionHelper(
|
||||
return conditionMatched;
|
||||
};
|
||||
|
||||
if (!condition->Enabled()) {
|
||||
vblog(LOG_INFO, "ignoring condition '%s' for '%s'",
|
||||
condition->GetId().c_str(), _name.c_str());
|
||||
if (!_useShortCircuitEvaluation) {
|
||||
(void)evaluateCondition();
|
||||
}
|
||||
return _matched;
|
||||
}
|
||||
|
||||
const auto logicType = condition->GetLogicType();
|
||||
if (logicType == Logic::Type::NONE) {
|
||||
vblog(LOG_INFO, "ignoring condition '%s' for '%s'",
|
||||
@@ -262,37 +305,9 @@ bool Macro::CheckConditions(bool ignorePause)
|
||||
|
||||
vblog(LOG_INFO, "Macro %s returned %d", _name.c_str(), _matched);
|
||||
|
||||
_actionModeMatch = false;
|
||||
switch (_actionTriggerMode) {
|
||||
case Macro::ActionTriggerMode::ALWAYS:
|
||||
_actionModeMatch = true;
|
||||
break;
|
||||
case Macro::ActionTriggerMode::MACRO_RESULT_CHANGED:
|
||||
_actionModeMatch = _lastMatched != _matched;
|
||||
break;
|
||||
case Macro::ActionTriggerMode::ANY_CONDITION_CHANGED:
|
||||
for (const auto &condition : _conditions) {
|
||||
if (condition->HasChanged()) {
|
||||
_actionModeMatch = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Macro::ActionTriggerMode::ANY_CONDITION_TRIGGERED:
|
||||
for (const auto &condition : _conditions) {
|
||||
if (condition->IsRisingEdge()) {
|
||||
_actionModeMatch = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
const bool hasActionsToExecute = _matched ? (_actions.size() > 0)
|
||||
: (_elseActions.size() > 0);
|
||||
if (!_actionModeMatch && hasActionsToExecute && !_paused) {
|
||||
_lastActionRunModePreventTime =
|
||||
std::chrono::high_resolution_clock::now();
|
||||
_conditionSateChanged = _lastMatched != _matched;
|
||||
if (!_conditionSateChanged && _performActionsOnChange) {
|
||||
_onPreventedActionExecution = true;
|
||||
}
|
||||
|
||||
_lastMatched = _matched;
|
||||
@@ -351,16 +366,6 @@ bool Macro::WasExecutedSince(const TimePoint &time) const
|
||||
return _lastExecutionTime > time;
|
||||
}
|
||||
|
||||
bool Macro::ActionTriggerModePreventedActionsSince(const TimePoint &time) const
|
||||
{
|
||||
return _lastActionRunModePreventTime > time;
|
||||
}
|
||||
|
||||
Macro::TimePoint Macro::GetLastExecutionTime() const
|
||||
{
|
||||
return _lastExecutionTime;
|
||||
}
|
||||
|
||||
bool Macro::ConditionsShouldBeChecked() const
|
||||
{
|
||||
if (!_useCustomConditionCheckInterval) {
|
||||
@@ -387,9 +392,10 @@ bool Macro::ShouldRunActions() const
|
||||
|
||||
const bool hasActionsToExecute =
|
||||
!_paused && (_matched || _elseActions.size() > 0) &&
|
||||
_actionModeMatch;
|
||||
(!_performActionsOnChange || _conditionSateChanged);
|
||||
|
||||
if (VerboseLoggingEnabled() && !_actionModeMatch && !_paused) {
|
||||
if (VerboseLoggingEnabled() && _performActionsOnChange &&
|
||||
!_conditionSateChanged) {
|
||||
if (_matched && _actions.size() > 0) {
|
||||
blog(LOG_INFO, "skip actions for Macro %s (on change)",
|
||||
_name.c_str());
|
||||
@@ -406,9 +412,15 @@ bool Macro::ShouldRunActions() const
|
||||
|
||||
void Macro::SetName(const std::string &name)
|
||||
{
|
||||
const bool nameChanged = _name == name;
|
||||
_name = name;
|
||||
|
||||
SetHotkeysDesc();
|
||||
_dockSettings.HandleMacroNameChange();
|
||||
|
||||
if (nameChanged) {
|
||||
_dockId = GenerateDockId();
|
||||
}
|
||||
EnableDock(_registerDock);
|
||||
}
|
||||
|
||||
void Macro::ResetTimers()
|
||||
@@ -420,24 +432,10 @@ void Macro::ResetTimers()
|
||||
_lastExecutionTime = {};
|
||||
}
|
||||
|
||||
void Macro::SetActionTriggerMode(ActionTriggerMode mode)
|
||||
{
|
||||
_actionTriggerMode = mode;
|
||||
}
|
||||
|
||||
Macro::ActionTriggerMode Macro::GetActionTriggerMode() const
|
||||
{
|
||||
return _actionTriggerMode;
|
||||
}
|
||||
|
||||
bool Macro::RunActionsHelper(
|
||||
const std::deque<std::shared_ptr<MacroAction>> &actionsToRun,
|
||||
bool ignorePause)
|
||||
{
|
||||
if (_paused && !ignorePause) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create copy of action list as elements might be removed, inserted, or
|
||||
// reordered while actions are currently being executed.
|
||||
auto actions = actionsToRun;
|
||||
@@ -453,7 +451,6 @@ bool Macro::RunActionsHelper(
|
||||
action->WithLock([&action, &actionResult]() {
|
||||
actionResult = action->PerformAction();
|
||||
});
|
||||
action->ApplyVarMappings();
|
||||
actionsExecutedSuccessfully =
|
||||
actionsExecutedSuccessfully && actionResult;
|
||||
} else {
|
||||
@@ -488,6 +485,11 @@ bool Macro::WasPausedSince(const TimePoint &time) const
|
||||
return _lastUnpauseTime > time;
|
||||
}
|
||||
|
||||
void Macro::SetMatchOnChange(bool onChange)
|
||||
{
|
||||
_performActionsOnChange = onChange;
|
||||
}
|
||||
|
||||
void Macro::SetStopActionsIfNotDone(bool stopActionsIfNotDone)
|
||||
{
|
||||
_stopActionsIfNotDone = stopActionsIfNotDone;
|
||||
@@ -603,7 +605,7 @@ void Macro::SetInputVariables(const MacroInputVariables &inputVariables)
|
||||
_inputVariables = inputVariables;
|
||||
}
|
||||
|
||||
std::vector<TempVariable> Macro::GetTempVars(const MacroSegment *filter) const
|
||||
std::vector<TempVariable> Macro::GetTempVars(MacroSegment *filter) const
|
||||
{
|
||||
std::vector<TempVariable> res;
|
||||
|
||||
@@ -631,7 +633,7 @@ std::vector<TempVariable> Macro::GetTempVars(const MacroSegment *filter) const
|
||||
return ptr.get() == segment;
|
||||
}) != _conditions.end();
|
||||
};
|
||||
auto isAction = [this](const MacroSegment *segment) -> bool {
|
||||
auto isAction = [this](MacroSegment *segment) -> bool {
|
||||
return std::find_if(_actions.begin(), _actions.end(),
|
||||
[segment](
|
||||
const std::shared_ptr<MacroSegment>
|
||||
@@ -639,7 +641,7 @@ std::vector<TempVariable> Macro::GetTempVars(const MacroSegment *filter) const
|
||||
return ptr.get() == segment;
|
||||
}) != _actions.end();
|
||||
};
|
||||
auto isElseAction = [this](const MacroSegment *segment) -> bool {
|
||||
auto isElseAction = [this](MacroSegment *segment) -> bool {
|
||||
return std::find_if(_elseActions.begin(), _elseActions.end(),
|
||||
[segment](
|
||||
const std::shared_ptr<MacroSegment>
|
||||
@@ -808,8 +810,7 @@ bool Macro::Save(obs_data_t *obj, bool saveForCopy) const
|
||||
obs_data_set_bool(obj, "pause", _paused);
|
||||
obs_data_set_bool(obj, "parallel", _runInParallel);
|
||||
obs_data_set_bool(obj, "checkConditionsInParallel", _checkInParallel);
|
||||
obs_data_set_int(obj, "actionTriggerMode",
|
||||
static_cast<int>(_actionTriggerMode));
|
||||
obs_data_set_bool(obj, "onChange", _performActionsOnChange);
|
||||
obs_data_set_bool(obj, "skipExecOnStart", _skipExecOnStart);
|
||||
obs_data_set_bool(obj, "stopActionsIfNotDone", _stopActionsIfNotDone);
|
||||
obs_data_set_bool(obj, "useShortCircuitEvaluation",
|
||||
@@ -818,7 +819,7 @@ bool Macro::Save(obs_data_t *obj, bool saveForCopy) const
|
||||
_useCustomConditionCheckInterval);
|
||||
_customConditionCheckInterval.Save(obj, "customConditionCheckInterval");
|
||||
|
||||
_dockSettings.Save(obj, saveForCopy);
|
||||
SaveDockSettings(obj, saveForCopy);
|
||||
|
||||
SaveSplitterPos(_actionConditionSplitterPosition, obj,
|
||||
"macroActionConditionSplitterPosition");
|
||||
@@ -895,15 +896,7 @@ bool Macro::Load(obs_data_t *obj)
|
||||
}
|
||||
_runInParallel = obs_data_get_bool(obj, "parallel");
|
||||
_checkInParallel = obs_data_get_bool(obj, "checkConditionsInParallel");
|
||||
if (obs_data_has_user_value(obj, "onChange")) {
|
||||
const bool onChange = obs_data_get_bool(obj, "onChange");
|
||||
_actionTriggerMode =
|
||||
onChange ? ActionTriggerMode::MACRO_RESULT_CHANGED
|
||||
: ActionTriggerMode::ALWAYS;
|
||||
} else {
|
||||
_actionTriggerMode = static_cast<ActionTriggerMode>(
|
||||
obs_data_get_int(obj, "actionTriggerMode"));
|
||||
}
|
||||
_performActionsOnChange = obs_data_get_bool(obj, "onChange");
|
||||
_skipExecOnStart = obs_data_get_bool(obj, "skipExecOnStart");
|
||||
_stopActionsIfNotDone = obs_data_get_bool(obj, "stopActionsIfNotDone");
|
||||
_useShortCircuitEvaluation =
|
||||
@@ -912,7 +905,7 @@ bool Macro::Load(obs_data_t *obj)
|
||||
obs_data_get_bool(obj, "useCustomConditionCheckInterval");
|
||||
_customConditionCheckInterval.Load(obj, "customConditionCheckInterval");
|
||||
|
||||
_dockSettings.Load(obj);
|
||||
LoadDockSettings(obj);
|
||||
|
||||
LoadSplitterPos(_actionConditionSplitterPosition, obj,
|
||||
"macroActionConditionSplitterPosition");
|
||||
@@ -991,7 +984,7 @@ bool Macro::Load(obs_data_t *obj)
|
||||
auto newEntry = MacroActionFactory::Create(id, this);
|
||||
if (newEntry) {
|
||||
_elseActions.emplace_back(newEntry);
|
||||
auto action = _elseActions.back().get();
|
||||
auto action = _actions.back().get();
|
||||
action->WithLock([action, &arrayObj]() {
|
||||
action->Load(arrayObj);
|
||||
});
|
||||
@@ -1025,12 +1018,12 @@ bool Macro::PostLoad()
|
||||
bool Macro::SwitchesScene() const
|
||||
{
|
||||
for (const auto &a : _actions) {
|
||||
if (a->GetId() == MacroAction::GetDefaultID()) {
|
||||
if (a->GetId() == GetSceneSwitchActionId()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (const auto &a : _elseActions) {
|
||||
if (a->GetId() == MacroAction::GetDefaultID()) {
|
||||
if (a->GetId() == GetSceneSwitchActionId()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1063,8 +1056,18 @@ bool Macro::HasValidSplitterPositions() const
|
||||
!_elseActionSplitterPosition.empty();
|
||||
}
|
||||
|
||||
bool Macro::OnChangePreventedActionsRecently()
|
||||
{
|
||||
if (_onPreventedActionExecution) {
|
||||
_onPreventedActionExecution = false;
|
||||
return _matched ? _actions.size() > 0 : _elseActions.size() > 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Macro::ResetUIHelpers()
|
||||
{
|
||||
_onPreventedActionExecution = false;
|
||||
for (auto c : _conditions) {
|
||||
c->GetHighlightAndReset();
|
||||
}
|
||||
@@ -1092,6 +1095,224 @@ bool Macro::PauseHotkeysEnabled() const
|
||||
return _registerHotkeys;
|
||||
}
|
||||
|
||||
void Macro::SaveDockSettings(obs_data_t *obj, bool saveForCopy) const
|
||||
{
|
||||
auto dockSettings = obs_data_create();
|
||||
obs_data_set_bool(dockSettings, "register", _registerDock);
|
||||
obs_data_set_bool(dockSettings, "hasRunButton", _dockHasRunButton);
|
||||
obs_data_set_bool(dockSettings, "hasPauseButton", _dockHasPauseButton);
|
||||
obs_data_set_bool(dockSettings, "hasStatusLabel", _dockHasStatusLabel);
|
||||
obs_data_set_bool(dockSettings, "highlightIfConditionsTrue",
|
||||
_dockHighlight);
|
||||
_runButtonText.Save(dockSettings, "runButtonText");
|
||||
_pauseButtonText.Save(dockSettings, "pauseButtonText");
|
||||
_unpauseButtonText.Save(dockSettings, "unpauseButtonText");
|
||||
_conditionsTrueStatusText.Save(dockSettings,
|
||||
"conditionsTrueStatusText");
|
||||
_conditionsFalseStatusText.Save(dockSettings,
|
||||
"conditionsFalseStatusText");
|
||||
if (saveForCopy) {
|
||||
auto uuid = GenerateDockId();
|
||||
obs_data_set_string(dockSettings, "dockId", uuid.c_str());
|
||||
|
||||
} else {
|
||||
obs_data_set_string(dockSettings, "dockId", _dockId.c_str());
|
||||
}
|
||||
obs_data_set_int(dockSettings, "version", 1);
|
||||
obs_data_set_obj(obj, "dockSettings", dockSettings);
|
||||
obs_data_release(dockSettings);
|
||||
}
|
||||
|
||||
void Macro::LoadDockSettings(obs_data_t *obj)
|
||||
{
|
||||
auto dockSettings = obs_data_get_obj(obj, "dockSettings");
|
||||
if (!dockSettings) {
|
||||
// TODO: Remove this fallback
|
||||
_dockHasRunButton = obs_data_get_bool(obj, "dockHasRunButton");
|
||||
_dockHasPauseButton =
|
||||
obs_data_get_bool(obj, "dockHasPauseButton");
|
||||
EnableDock(obs_data_get_bool(obj, "registerDock"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!obs_data_has_user_value(dockSettings, "version")) {
|
||||
_dockId = std::string("ADVSS-") + _name;
|
||||
} else {
|
||||
_dockId = obs_data_get_string(dockSettings, "dockId");
|
||||
}
|
||||
|
||||
const bool dockEnabled = obs_data_get_bool(dockSettings, "register");
|
||||
|
||||
// TODO: remove these default settings in a future version
|
||||
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"));
|
||||
_runButtonText.Load(dockSettings, "runButtonText");
|
||||
_pauseButtonText.Load(dockSettings, "pauseButtonText");
|
||||
_unpauseButtonText.Load(dockSettings, "unpauseButtonText");
|
||||
_conditionsTrueStatusText.Load(dockSettings,
|
||||
"conditionsTrueStatusText");
|
||||
_conditionsFalseStatusText.Load(dockSettings,
|
||||
"conditionsFalseStatusText");
|
||||
if (dockEnabled) {
|
||||
_dockHasRunButton =
|
||||
obs_data_get_bool(dockSettings, "hasRunButton");
|
||||
_dockHasPauseButton =
|
||||
obs_data_get_bool(dockSettings, "hasPauseButton");
|
||||
_dockHasStatusLabel =
|
||||
obs_data_get_bool(dockSettings, "hasStatusLabel");
|
||||
_dockHighlight = obs_data_get_bool(dockSettings,
|
||||
"highlightIfConditionsTrue");
|
||||
}
|
||||
EnableDock(dockEnabled);
|
||||
obs_data_release(dockSettings);
|
||||
}
|
||||
|
||||
void Macro::EnableDock(bool value)
|
||||
{
|
||||
// Reset dock regardless
|
||||
RemoveDock();
|
||||
|
||||
if (!value) {
|
||||
_registerDock = value;
|
||||
return;
|
||||
}
|
||||
|
||||
_dock = new MacroDock(GetWeakMacroByName(_name.c_str()), _runButtonText,
|
||||
_pauseButtonText, _unpauseButtonText,
|
||||
_conditionsTrueStatusText,
|
||||
_conditionsFalseStatusText, _dockHighlight);
|
||||
|
||||
if (!obs_frontend_add_dock_by_id(_dockId.c_str(), _name.c_str(),
|
||||
_dock)) {
|
||||
blog(LOG_INFO, "failed to add macro dock for macro %s",
|
||||
_name.c_str());
|
||||
_dock->deleteLater();
|
||||
_dock = nullptr;
|
||||
_registerDock = false;
|
||||
return;
|
||||
}
|
||||
|
||||
_registerDock = value;
|
||||
}
|
||||
|
||||
void Macro::SetDockHasRunButton(bool value)
|
||||
{
|
||||
_dockHasRunButton = value;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
_dock->ShowRunButton(value);
|
||||
}
|
||||
|
||||
void Macro::SetDockHasPauseButton(bool value)
|
||||
{
|
||||
_dockHasPauseButton = value;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
_dock->ShowPauseButton(value);
|
||||
}
|
||||
|
||||
void Macro::SetDockHasStatusLabel(bool value)
|
||||
{
|
||||
_dockHasStatusLabel = value;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
_dock->ShowStatusLabel(value);
|
||||
}
|
||||
|
||||
void Macro::SetHighlightEnable(bool value)
|
||||
{
|
||||
_dockHighlight = value;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
_dock->EnableHighlight(value);
|
||||
}
|
||||
|
||||
void Macro::SetRunButtonText(const std::string &text)
|
||||
{
|
||||
_runButtonText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
_dock->SetRunButtonText(text);
|
||||
}
|
||||
|
||||
void Macro::SetPauseButtonText(const std::string &text)
|
||||
{
|
||||
_pauseButtonText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
_dock->SetPauseButtonText(text);
|
||||
}
|
||||
|
||||
void Macro::SetUnpauseButtonText(const std::string &text)
|
||||
{
|
||||
_unpauseButtonText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
_dock->SetUnpauseButtonText(text);
|
||||
}
|
||||
|
||||
void Macro::SetConditionsTrueStatusText(const std::string &text)
|
||||
{
|
||||
_conditionsTrueStatusText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
_dock->SetConditionsTrueText(text);
|
||||
}
|
||||
|
||||
StringVariable Macro::ConditionsTrueStatusText() const
|
||||
{
|
||||
return _conditionsTrueStatusText;
|
||||
}
|
||||
|
||||
void Macro::SetConditionsFalseStatusText(const std::string &text)
|
||||
{
|
||||
_conditionsFalseStatusText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
_dock->SetConditionsFalseText(text);
|
||||
}
|
||||
|
||||
StringVariable Macro::ConditionsFalseStatusText() const
|
||||
{
|
||||
return _conditionsFalseStatusText;
|
||||
}
|
||||
|
||||
void Macro::RemoveDock()
|
||||
{
|
||||
obs_frontend_remove_dock(_dockId.c_str());
|
||||
_dock = nullptr;
|
||||
}
|
||||
|
||||
std::string Macro::GenerateDockId()
|
||||
{
|
||||
#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
|
||||
}
|
||||
|
||||
static void pauseCB(void *data, obs_hotkey_id, obs_hotkey_t *, bool pressed)
|
||||
{
|
||||
if (pressed) {
|
||||
@@ -1163,11 +1384,9 @@ void Macro::ClearHotkeys() const
|
||||
void setHotkeyDescriptionHelper(const char *formatModuleText,
|
||||
const std::string name, const obs_hotkey_id id)
|
||||
{
|
||||
#ifndef UNIT_TEST
|
||||
QString format{obs_module_text(formatModuleText)};
|
||||
QString hotkeyDesc = format.arg(QString::fromStdString(name));
|
||||
obs_hotkey_set_description(id, hotkeyDesc.toStdString().c_str());
|
||||
#endif // !UNIT_TEST
|
||||
}
|
||||
|
||||
void Macro::SetHotkeysDesc() const
|
||||
@@ -1183,7 +1402,7 @@ void Macro::SetHotkeysDesc() const
|
||||
void SaveMacros(obs_data_t *obj)
|
||||
{
|
||||
obs_data_array_t *macroArray = obs_data_array_create();
|
||||
for (const auto &m : GetTopLevelMacros()) {
|
||||
for (const auto &m : macros) {
|
||||
obs_data_t *array_obj = obs_data_create();
|
||||
|
||||
m->Save(array_obj);
|
||||
@@ -1197,9 +1416,7 @@ void SaveMacros(obs_data_t *obj)
|
||||
|
||||
void LoadMacros(obs_data_t *obj)
|
||||
{
|
||||
auto ¯os = GetTopLevelMacros();
|
||||
macros.clear();
|
||||
|
||||
obs_data_array_t *macroArray = obs_data_get_array(obj, "macros");
|
||||
size_t count = obs_data_array_count(macroArray);
|
||||
|
||||
@@ -1249,10 +1466,15 @@ void LoadMacros(obs_data_t *obj)
|
||||
}
|
||||
}
|
||||
|
||||
std::deque<std::shared_ptr<Macro>> &GetMacros()
|
||||
{
|
||||
return macros;
|
||||
}
|
||||
|
||||
bool CheckMacros()
|
||||
{
|
||||
bool matchFound = false;
|
||||
for (const auto &m : GetTopLevelMacros()) {
|
||||
for (const auto &m : macros) {
|
||||
if (!m->ConditionsShouldBeChecked()) {
|
||||
vblog(LOG_INFO,
|
||||
"skipping condition check for macro \"%s\" "
|
||||
@@ -1279,7 +1501,7 @@ bool RunMacros()
|
||||
// reordered while macros are currently being executed.
|
||||
// For example, this can happen if a macro is performing a wait action,
|
||||
// as the main lock will be unlocked during this time.
|
||||
auto runPhaseMacros = GetTopLevelMacros();
|
||||
auto runPhaseMacros = macros;
|
||||
|
||||
// Avoid deadlocks when opening settings window and calling frontend
|
||||
// API functions at the same time.
|
||||
@@ -1319,14 +1541,41 @@ bool RunMacros()
|
||||
|
||||
void StopAllMacros()
|
||||
{
|
||||
for (const auto &m : GetAllMacros()) {
|
||||
for (const auto &m : macros) {
|
||||
m->Stop();
|
||||
}
|
||||
}
|
||||
|
||||
Macro *GetMacroByName(const char *name)
|
||||
{
|
||||
for (const auto &m : macros) {
|
||||
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 : macros) {
|
||||
if (m->Name() == name) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void InvalidateMacroTempVarValues()
|
||||
{
|
||||
for (const auto &m : GetTopLevelMacros()) {
|
||||
for (const auto &m : macros) {
|
||||
// Do not invalidate the temp vars set during condition checks
|
||||
// or action executions running in parallel to the "main" macro
|
||||
// loop, as otherwise access to the information stored in those
|
||||
@@ -1341,8 +1590,6 @@ void InvalidateMacroTempVarValues()
|
||||
|
||||
std::shared_ptr<Macro> GetMacroWithInvalidConditionInterval()
|
||||
{
|
||||
auto ¯os = GetTopLevelMacros();
|
||||
|
||||
if (macros.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
#include "macro-action.hpp"
|
||||
#include "macro-condition.hpp"
|
||||
#include "macro-dock-settings.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "macro-input.hpp"
|
||||
#include "macro-ref.hpp"
|
||||
@@ -9,6 +8,8 @@
|
||||
#include "temp-variable.hpp"
|
||||
|
||||
#include <future>
|
||||
#include <QString>
|
||||
#include <QByteArray>
|
||||
#include <string>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
@@ -19,6 +20,7 @@
|
||||
|
||||
namespace advss {
|
||||
|
||||
class MacroDock;
|
||||
class GlobalMacroSettings;
|
||||
|
||||
class Macro {
|
||||
@@ -26,16 +28,6 @@ class Macro {
|
||||
|
||||
public:
|
||||
enum class PauseStateSaveBehavior { PERSIST, PAUSE, UNPAUSE };
|
||||
enum class ActionTriggerMode {
|
||||
// Trigger always
|
||||
ALWAYS,
|
||||
// Trigger when macro match result flips
|
||||
MACRO_RESULT_CHANGED,
|
||||
// Trigger when any individual condition changes
|
||||
ANY_CONDITION_CHANGED,
|
||||
// Trigger when any individual condition evaluates to true
|
||||
ANY_CONDITION_TRIGGERED,
|
||||
};
|
||||
|
||||
Macro(const std::string &name = "");
|
||||
Macro(const std::string &name, const GlobalMacroSettings &settings);
|
||||
@@ -64,8 +56,8 @@ public:
|
||||
bool GetStop() const { return _stop; }
|
||||
void ResetTimers();
|
||||
|
||||
void SetActionTriggerMode(ActionTriggerMode);
|
||||
ActionTriggerMode GetActionTriggerMode() const;
|
||||
void SetMatchOnChange(bool onChange);
|
||||
bool MatchOnChange() const { return _performActionsOnChange; }
|
||||
|
||||
void SetSkipExecOnStart(bool skip) { _skipExecOnStart = skip; }
|
||||
bool SkipExecOnStart() const { return _skipExecOnStart; }
|
||||
@@ -96,7 +88,7 @@ public:
|
||||
void SetInputVariables(const MacroInputVariables &);
|
||||
|
||||
// Temporary variable helpers
|
||||
std::vector<TempVariable> GetTempVars(const MacroSegment *filter) const;
|
||||
std::vector<TempVariable> GetTempVars(MacroSegment *filter) const;
|
||||
std::optional<const TempVariable>
|
||||
GetTempVar(const MacroSegment *, const std::string &id) const;
|
||||
void InvalidateTempVarValues() const;
|
||||
@@ -147,8 +139,7 @@ public:
|
||||
const QList<int> &GetElseActionSplitterPosition() const;
|
||||
bool HasValidSplitterPositions() const;
|
||||
bool WasExecutedSince(const TimePoint &) const;
|
||||
bool ActionTriggerModePreventedActionsSince(const TimePoint &) const;
|
||||
TimePoint GetLastExecutionTime() const;
|
||||
bool OnChangePreventedActionsRecently();
|
||||
void ResetUIHelpers();
|
||||
|
||||
// Hotkeys
|
||||
@@ -156,7 +147,26 @@ public:
|
||||
bool PauseHotkeysEnabled() const;
|
||||
|
||||
// Docks
|
||||
MacroDockSettings &GetDockSettings() { return _dockSettings; }
|
||||
void EnableDock(bool);
|
||||
bool DockEnabled() const { return _registerDock; }
|
||||
void SetDockHasRunButton(bool value);
|
||||
bool DockHasRunButton() const { return _dockHasRunButton; }
|
||||
void SetDockHasPauseButton(bool value);
|
||||
bool DockHasPauseButton() const { return _dockHasPauseButton; }
|
||||
void SetDockHasStatusLabel(bool value);
|
||||
bool DockHasStatusLabel() const { return _dockHasStatusLabel; }
|
||||
void SetHighlightEnable(bool value);
|
||||
bool DockHighlightEnabled() const { return _dockHighlight; }
|
||||
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;
|
||||
|
||||
private:
|
||||
void SetupHotkeys();
|
||||
@@ -172,6 +182,11 @@ private:
|
||||
bool RunActions(bool ignorePause);
|
||||
bool RunElseActions(bool ignorePause);
|
||||
|
||||
void SaveDockSettings(obs_data_t *obj, bool saveForCopy) const;
|
||||
void LoadDockSettings(obs_data_t *obj);
|
||||
void RemoveDock();
|
||||
static std::string GenerateDockId();
|
||||
|
||||
std::string _name = "";
|
||||
bool _die = false;
|
||||
bool _stop = false;
|
||||
@@ -179,7 +194,6 @@ private:
|
||||
TimePoint _lastCheckTime{};
|
||||
TimePoint _lastUnpauseTime{};
|
||||
TimePoint _lastExecutionTime{};
|
||||
TimePoint _lastActionRunModePreventTime{};
|
||||
std::vector<std::thread> _helperThreads;
|
||||
|
||||
std::deque<std::shared_ptr<MacroCondition>> _conditions;
|
||||
@@ -194,13 +208,14 @@ private:
|
||||
bool _useShortCircuitEvaluation = false;
|
||||
bool _useCustomConditionCheckInterval = false;
|
||||
Duration _customConditionCheckInterval = 0.3;
|
||||
bool _actionModeMatch = false;
|
||||
bool _conditionSateChanged = false;
|
||||
|
||||
bool _runInParallel = false;
|
||||
bool _checkInParallel = false;
|
||||
bool _matched = false;
|
||||
std::future<void> _conditionCheckFuture;
|
||||
bool _lastMatched = false;
|
||||
bool _performActionsOnChange = true;
|
||||
bool _skipExecOnStart = false;
|
||||
bool _stopActionsIfNotDone = false;
|
||||
bool _paused = false;
|
||||
@@ -210,25 +225,45 @@ private:
|
||||
obs_hotkey_id _unpauseHotkey = OBS_INVALID_HOTKEY_ID;
|
||||
obs_hotkey_id _togglePauseHotkey = OBS_INVALID_HOTKEY_ID;
|
||||
|
||||
ActionTriggerMode _actionTriggerMode =
|
||||
ActionTriggerMode::MACRO_RESULT_CHANGED;
|
||||
|
||||
PauseStateSaveBehavior _pauseSaveBehavior =
|
||||
PauseStateSaveBehavior::PERSIST;
|
||||
|
||||
MacroInputVariables _inputVariables;
|
||||
|
||||
// UI helpers
|
||||
bool _onPreventedActionExecution = false;
|
||||
|
||||
QList<int> _actionConditionSplitterPosition;
|
||||
QList<int> _elseActionSplitterPosition;
|
||||
|
||||
MacroDockSettings _dockSettings;
|
||||
bool _registerDock = false;
|
||||
bool _dockHasRunButton = true;
|
||||
bool _dockHasPauseButton = true;
|
||||
bool _dockHasStatusLabel = false;
|
||||
bool _dockHighlight = 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");
|
||||
MacroDock *_dock = nullptr;
|
||||
std::string _dockId = GenerateDockId();
|
||||
};
|
||||
|
||||
void LoadMacros(obs_data_t *obj);
|
||||
void SaveMacros(obs_data_t *obj);
|
||||
std::deque<std::shared_ptr<Macro>> &GetMacros();
|
||||
bool CheckMacros();
|
||||
bool RunMacros();
|
||||
void StopAllMacros();
|
||||
Macro *GetMacroByName(const char *name);
|
||||
Macro *GetMacroByQString(const QString &name);
|
||||
std::weak_ptr<Macro> GetWeakMacroByName(const char *name);
|
||||
void InvalidateMacroTempVarValues();
|
||||
std::shared_ptr<Macro> GetMacroWithInvalidConditionInterval();
|
||||
|
||||
|
||||
@@ -14,9 +14,10 @@
|
||||
|
||||
namespace advss {
|
||||
|
||||
std::vector<std::string> GetWindowList()
|
||||
void GetWindowList(std::vector<std::string> &windows)
|
||||
{
|
||||
std::vector<std::string> windows;
|
||||
windows.resize(0);
|
||||
|
||||
@autoreleasepool {
|
||||
CFArrayRef cfApps = CGWindowListCopyWindowInfo(
|
||||
kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
|
||||
@@ -48,12 +49,21 @@ std::vector<std::string> GetWindowList()
|
||||
apps = nil;
|
||||
CFRelease(cfApps);
|
||||
}
|
||||
return windows;
|
||||
}
|
||||
|
||||
std::string GetCurrentWindowTitle()
|
||||
void GetWindowList(QStringList &windows)
|
||||
{
|
||||
std::string title;
|
||||
windows.clear();
|
||||
std::vector<std::string> temp;
|
||||
GetWindowList(temp);
|
||||
for (auto &w : temp) {
|
||||
windows << QString::fromStdString(w);
|
||||
}
|
||||
}
|
||||
|
||||
void GetCurrentWindowTitle(std::string &title)
|
||||
{
|
||||
title.resize(0);
|
||||
@autoreleasepool {
|
||||
CFArrayRef cfApps = CGWindowListCopyWindowInfo(
|
||||
kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
|
||||
@@ -97,7 +107,6 @@ std::string GetCurrentWindowTitle()
|
||||
apps = nil;
|
||||
CFRelease(cfApps);
|
||||
}
|
||||
return title;
|
||||
}
|
||||
|
||||
bool isWindowOriginOnScreen(NSDictionary *app, NSScreen *screen,
|
||||
@@ -249,7 +258,7 @@ bool IsFullscreen(const std::string &title)
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<std::string> GetTextInWindow(const std::string &)
|
||||
std::optional<std::string> GetTextInWindow(const std::string &window)
|
||||
{
|
||||
// Not implemented
|
||||
return {};
|
||||
@@ -264,9 +273,9 @@ int SecondsSinceLastInput()
|
||||
return (int)time;
|
||||
}
|
||||
|
||||
QStringList GetProcessList()
|
||||
void GetProcessList(QStringList &list)
|
||||
{
|
||||
QStringList list;
|
||||
list.clear();
|
||||
@autoreleasepool {
|
||||
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
|
||||
NSArray *array = [ws runningApplications];
|
||||
@@ -282,11 +291,11 @@ QStringList GetProcessList()
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
std::string GetForegroundProcessName()
|
||||
void GetForegroundProcessName(std::string &proc)
|
||||
{
|
||||
proc.resize(0);
|
||||
@autoreleasepool {
|
||||
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
|
||||
NSArray *array = [ws runningApplications];
|
||||
@@ -299,73 +308,23 @@ std::string GetForegroundProcessName()
|
||||
break;
|
||||
}
|
||||
const char *str = name.UTF8String;
|
||||
if (str) {
|
||||
return str;
|
||||
}
|
||||
proc = std::string(str);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string GetForegroundProcessPath()
|
||||
void GetForegroundProcessName(QString &proc)
|
||||
{
|
||||
@autoreleasepool {
|
||||
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
|
||||
for (NSRunningApplication *app in [ws runningApplications]) {
|
||||
if (!app.isActive) {
|
||||
continue;
|
||||
}
|
||||
NSURL *url = app.executableURL;
|
||||
if (!url) {
|
||||
break;
|
||||
}
|
||||
const char *str = url.path.UTF8String;
|
||||
if (str) {
|
||||
return str;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
QStringList GetProcessPathsFromName(const QString &name)
|
||||
{
|
||||
QStringList paths;
|
||||
@autoreleasepool {
|
||||
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
|
||||
for (NSRunningApplication *app in [ws runningApplications]) {
|
||||
NSString *appName = app.localizedName;
|
||||
if (!appName) {
|
||||
continue;
|
||||
}
|
||||
const char *nameStr = appName.UTF8String;
|
||||
if (!nameStr ||
|
||||
name != QString::fromUtf8(nameStr)) {
|
||||
continue;
|
||||
}
|
||||
NSURL *url = app.executableURL;
|
||||
if (!url) {
|
||||
continue;
|
||||
}
|
||||
const char *pathStr = url.path.UTF8String;
|
||||
if (!pathStr) {
|
||||
continue;
|
||||
}
|
||||
QString path = QString::fromUtf8(pathStr);
|
||||
if (!paths.contains(path)) {
|
||||
paths.append(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
std::string temp;
|
||||
GetForegroundProcessName(temp);
|
||||
proc = QString::fromStdString(temp);
|
||||
}
|
||||
|
||||
bool IsInFocus(const QString &executable)
|
||||
{
|
||||
const auto current = GetForegroundProcessName();
|
||||
std::string current;
|
||||
GetForegroundProcessName(current);
|
||||
|
||||
// True if executable switch equals current window
|
||||
bool equals = (executable.toStdString() == current);
|
||||
|
||||
@@ -11,16 +11,15 @@ namespace advss {
|
||||
|
||||
enum class HotkeyType;
|
||||
|
||||
EXPORT std::vector<std::string> GetWindowList();
|
||||
EXPORT std::string GetCurrentWindowTitle();
|
||||
EXPORT void GetWindowList(std::vector<std::string> &windows);
|
||||
EXPORT void GetWindowList(QStringList &windows);
|
||||
EXPORT void GetCurrentWindowTitle(std::string &title);
|
||||
EXPORT bool IsFullscreen(const std::string &title);
|
||||
EXPORT bool IsMaximized(const std::string &title);
|
||||
EXPORT std::optional<std::string> GetTextInWindow(const std::string &window);
|
||||
EXPORT int SecondsSinceLastInput();
|
||||
EXPORT QStringList GetProcessList();
|
||||
EXPORT std::string GetForegroundProcessName();
|
||||
EXPORT std::string GetForegroundProcessPath();
|
||||
EXPORT QStringList GetProcessPathsFromName(const QString &name);
|
||||
EXPORT void GetProcessList(QStringList &processes);
|
||||
EXPORT void GetForegroundProcessName(std::string &name);
|
||||
EXPORT bool IsInFocus(const QString &executable);
|
||||
void PlatformInit();
|
||||
void PlatformCleanup();
|
||||
|
||||
@@ -16,17 +16,14 @@ static void setupTab(QTabWidget *);
|
||||
|
||||
static ActionQueueTable *tabWidget = nullptr;
|
||||
|
||||
static bool setup()
|
||||
void RegisterActionQueueTab()
|
||||
{
|
||||
AddPluginInitStep([] {
|
||||
AddPluginInitStep([]() {
|
||||
AddSetupTabCallback("actionQueueTab", ActionQueueTable::Create,
|
||||
setupTab);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool setupDone = setup();
|
||||
|
||||
static void setTabVisible(QTabWidget *tabWidget, bool visible)
|
||||
{
|
||||
SetTabVisibleByName(
|
||||
|
||||
@@ -12,16 +12,20 @@ std::deque<std::shared_ptr<Item>> &GetActionQueues()
|
||||
return queues;
|
||||
}
|
||||
|
||||
static bool setup()
|
||||
void RegisterActionQueueTab();
|
||||
|
||||
void SetupActionQueues()
|
||||
{
|
||||
static bool done = false;
|
||||
if (done) {
|
||||
return;
|
||||
}
|
||||
AddSaveStep(SaveActionQueues);
|
||||
AddLoadStep(LoadActionQueues);
|
||||
AddPluginCleanupStep([]() { queues.clear(); });
|
||||
return true;
|
||||
RegisterActionQueueTab();
|
||||
done = true;
|
||||
}
|
||||
|
||||
static bool setupDone = setup();
|
||||
|
||||
ActionQueue::ActionQueue() : Item()
|
||||
{
|
||||
_lastEmpty = std::chrono::high_resolution_clock::now();
|
||||
@@ -109,7 +113,7 @@ void ActionQueue::Add(const std::shared_ptr<MacroAction> &action)
|
||||
action->Save(data);
|
||||
copy->Load(data);
|
||||
copy->PostLoad();
|
||||
RunAndClearPostLoadSteps();
|
||||
RunPostLoadSteps();
|
||||
copy->ResolveVariablesToFixedValues();
|
||||
_actions.emplace_back(copy);
|
||||
} else {
|
||||
@@ -419,7 +423,7 @@ void ImportQueues(obs_data_t *data)
|
||||
importedQueues->emplace_back(queue);
|
||||
}
|
||||
|
||||
QueueUITask(signalImportedQueues, importedQueues);
|
||||
QeueUITask(signalImportedQueues, importedQueues);
|
||||
}
|
||||
|
||||
std::weak_ptr<ActionQueue> GetWeakActionQueueByName(const std::string &name)
|
||||
|
||||
@@ -101,6 +101,7 @@ signals:
|
||||
};
|
||||
|
||||
std::deque<std::shared_ptr<Item>> &GetActionQueues();
|
||||
void SetupActionQueues();
|
||||
void SaveActionQueues(obs_data_t *);
|
||||
void LoadActionQueues(obs_data_t *);
|
||||
void ImportQueues(obs_data_t *);
|
||||
|
||||
@@ -25,6 +25,14 @@ SwitcherData::SwitcherData(obs_module_t *m, translateFunc t)
|
||||
_translate = t;
|
||||
}
|
||||
|
||||
SwitcherData::~SwitcherData()
|
||||
{
|
||||
// Assume that OBS is shutting down, as the switcher object will only be
|
||||
// destroyed when the plugin is unloaded
|
||||
obsIsShuttingDown = true;
|
||||
Stop();
|
||||
}
|
||||
|
||||
const char *SwitcherData::Translate(const char *text)
|
||||
{
|
||||
return _translate(text);
|
||||
@@ -44,6 +52,11 @@ void SwitcherData::Prune()
|
||||
}
|
||||
}
|
||||
|
||||
if (nonMatchingScene && !WeakSourceValid(nonMatchingScene)) {
|
||||
switchIfNotMatching = NoMatchBehavior::NO_SWITCH;
|
||||
nonMatchingScene = nullptr;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < randomSwitches.size(); i++) {
|
||||
RandomSwitch &s = randomSwitches[i];
|
||||
if (!s.valid()) {
|
||||
@@ -152,7 +165,7 @@ bool SwitcherData::VersionChanged(obs_data_t *obj, std::string currentVersion)
|
||||
if (!obs_data_has_user_value(obj, "version")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switcher->firstBoot = false;
|
||||
std::string previousVersion = obs_data_get_string(obj, "version");
|
||||
return previousVersion != currentVersion;
|
||||
}
|
||||
@@ -163,6 +176,31 @@ void SwitcherData::SaveVersion(obs_data_t *obj,
|
||||
obs_data_set_string(obj, "version", currentVersion.c_str());
|
||||
}
|
||||
|
||||
void SwitcherData::RunPostLoadSteps()
|
||||
{
|
||||
for (const auto &func : postLoadSteps) {
|
||||
func();
|
||||
}
|
||||
postLoadSteps.clear();
|
||||
}
|
||||
|
||||
void SwitcherData::AddSaveStep(std::function<void(obs_data_t *)> function)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
saveSteps.emplace_back(function);
|
||||
}
|
||||
|
||||
void SwitcherData::AddLoadStep(std::function<void(obs_data_t *)> function)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
loadSteps.emplace_back(function);
|
||||
}
|
||||
|
||||
void SwitcherData::AddPostLoadStep(std::function<void()> function)
|
||||
{
|
||||
postLoadSteps.emplace_back(function);
|
||||
}
|
||||
|
||||
static void startHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *, bool pressed)
|
||||
{
|
||||
if (pressed) {
|
||||
|
||||
@@ -14,12 +14,10 @@
|
||||
#include "switch-sequence.hpp"
|
||||
#include "switch-video.hpp"
|
||||
|
||||
#include "macro-settings.hpp"
|
||||
#include "duration-control.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "priority-helper.hpp"
|
||||
#include "regex-config.hpp"
|
||||
#include "scene-selection.hpp"
|
||||
#include "variable-string.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
|
||||
#include <condition_variable>
|
||||
#include <vector>
|
||||
@@ -47,6 +45,9 @@ std::unique_lock<std::mutex> *GetSwitcherLoopLock();
|
||||
|
||||
class SwitcherData {
|
||||
public:
|
||||
SwitcherData(obs_module_t *modulePtr, translateFunc translate);
|
||||
~SwitcherData();
|
||||
|
||||
void Thread();
|
||||
void Start();
|
||||
void Stop();
|
||||
@@ -59,12 +60,15 @@ public:
|
||||
bool AnySceneTransitionStarted();
|
||||
|
||||
void SetPreconditions();
|
||||
void AddSaveStep(std::function<void(obs_data_t *)>);
|
||||
void AddLoadStep(std::function<void(obs_data_t *)>);
|
||||
void AddPostLoadStep(std::function<void()>);
|
||||
void RunPostLoadSteps();
|
||||
bool CheckForMatch(OBSWeakSource &scene, OBSWeakSource &transition,
|
||||
int &linger, bool &setPreviousSceneAsMatch,
|
||||
bool ¯oMatch);
|
||||
void CheckNoMatchSwitch(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition, int &sleep);
|
||||
void CheckAutoStart();
|
||||
|
||||
/* --- Start of saving / loading section --- */
|
||||
|
||||
@@ -84,9 +88,6 @@ public:
|
||||
|
||||
/* --- End of saving / loading section --- */
|
||||
|
||||
SwitcherData(obs_module_t *m, translateFunc t);
|
||||
inline ~SwitcherData() { Stop(); }
|
||||
|
||||
public:
|
||||
SwitcherThread *th = nullptr;
|
||||
std::mutex m;
|
||||
@@ -94,9 +95,14 @@ public:
|
||||
bool stop = false;
|
||||
std::condition_variable cv;
|
||||
|
||||
std::vector<std::function<void(obs_data_t *)>> saveSteps;
|
||||
std::vector<std::function<void(obs_data_t *)>> loadSteps;
|
||||
std::vector<std::function<void()>> postLoadSteps;
|
||||
|
||||
bool firstBoot = true;
|
||||
bool transitionActive = false;
|
||||
bool sceneCollectionStop = false;
|
||||
bool obsIsShuttingDown = false;
|
||||
bool sceneColletionStop = false;
|
||||
std::atomic_bool obsIsShuttingDown = {false};
|
||||
bool firstInterval = true;
|
||||
bool firstIntervalAfterStop = true;
|
||||
bool startupLoadDone = false;
|
||||
@@ -108,7 +114,7 @@ public:
|
||||
/* --- Start of General tab section --- */
|
||||
|
||||
int interval = default_interval;
|
||||
SceneSelection nonMatchingScene;
|
||||
OBSWeakSource nonMatchingScene;
|
||||
NoMatchBehavior switchIfNotMatching = NoMatchBehavior::NO_SWITCH;
|
||||
Duration noMatchDelay;
|
||||
enum class StartupBehavior { PERSIST = 0, START = 1, STOP = 2 };
|
||||
@@ -120,10 +126,6 @@ public:
|
||||
RECORINDG_OR_STREAMING
|
||||
};
|
||||
AutoStart autoStartEvent = AutoStart::NEVER;
|
||||
bool useAutoStartScene = false;
|
||||
SceneSelection autoStartScene;
|
||||
StringVariable autoStartSceneName;
|
||||
RegexConfig autoStartSceneRegex;
|
||||
bool enableCooldown = false;
|
||||
Duration cooldown;
|
||||
bool showSystemTrayNotifications = false;
|
||||
@@ -162,6 +164,7 @@ public:
|
||||
bool warnPluginLoadFailure = true;
|
||||
bool disableHints = false;
|
||||
bool disableFilterComboboxFilter = false;
|
||||
bool disableMacroWidgetCache = false;
|
||||
bool hideLegacyTabs = true;
|
||||
bool saveWindowGeo = false;
|
||||
QPoint windowPos = {};
|
||||
|
||||
@@ -1,42 +1,34 @@
|
||||
#include "auto-update-tooltip-label.hpp"
|
||||
|
||||
#include <QToolTip>
|
||||
|
||||
namespace advss {
|
||||
|
||||
AutoUpdateHelpIcon::AutoUpdateHelpIcon(
|
||||
AutoUpdateTooltipLabel::AutoUpdateTooltipLabel(
|
||||
QWidget *parent, const std::function<QString()> &updateTooltipCallback,
|
||||
int updateIntervalMs)
|
||||
: HelpIcon("", parent),
|
||||
: QLabel(parent),
|
||||
_callback(updateTooltipCallback),
|
||||
_timer(new QTimer(this)),
|
||||
_updateIntervalMs(updateIntervalMs)
|
||||
{
|
||||
connect(_timer, &QTimer::timeout, this,
|
||||
&AutoUpdateHelpIcon::UpdateTooltip);
|
||||
&AutoUpdateTooltipLabel::UpdateTooltip);
|
||||
}
|
||||
|
||||
void AutoUpdateHelpIcon::enterEvent(QEnterEvent *event)
|
||||
void AutoUpdateTooltipLabel::enterEvent(QEnterEvent *event)
|
||||
{
|
||||
UpdateTooltip();
|
||||
_timer->start(_updateIntervalMs);
|
||||
QLabel::enterEvent(event);
|
||||
}
|
||||
|
||||
void AutoUpdateHelpIcon::leaveEvent(QEvent *event)
|
||||
void AutoUpdateTooltipLabel::leaveEvent(QEvent *event)
|
||||
{
|
||||
_timer->stop();
|
||||
QLabel::leaveEvent(event);
|
||||
}
|
||||
|
||||
void AutoUpdateHelpIcon::UpdateTooltip()
|
||||
void AutoUpdateTooltipLabel::UpdateTooltip()
|
||||
{
|
||||
if (!underMouse()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QString text = _callback();
|
||||
QToolTip::showText(QCursor::pos(), text, this);
|
||||
setToolTip(_callback());
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
#pragma once
|
||||
#include "export-symbol-helper.hpp"
|
||||
#include "help-icon.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <QLabel>
|
||||
#include <QTimer>
|
||||
|
||||
namespace advss {
|
||||
|
||||
class ADVSS_EXPORT AutoUpdateHelpIcon : public HelpIcon {
|
||||
class ADVSS_EXPORT AutoUpdateTooltipLabel : public QLabel {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AutoUpdateHelpIcon(QWidget *parent,
|
||||
const std::function<QString()> &updateTooltipCallback,
|
||||
int updateIntervalMs = 300);
|
||||
AutoUpdateTooltipLabel(
|
||||
QWidget *parent,
|
||||
const std::function<QString()> &updateTooltipCallback,
|
||||
int updateIntervalMs = 300);
|
||||
|
||||
protected:
|
||||
void enterEvent(QEnterEvent *event) override;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user