mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-08-29 12:45:28 -05:00
Compare commits
177 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b25c1250e5 | ||
|
|
98f3f51ba9 | ||
|
|
f0df9ead3c | ||
|
|
7b1a57070d | ||
|
|
a412f2fd5e | ||
|
|
4f0c8c4ab5 | ||
|
|
946c90a749 | ||
|
|
7ba4eaab9c | ||
|
|
74553a82fc | ||
|
|
39fcb2d743 | ||
|
|
7041feaea3 | ||
|
|
9b1ffaeded | ||
|
|
07d397bdac | ||
|
|
a86ff4f1f0 | ||
|
|
953eca2732 | ||
|
|
d6c5fb149a | ||
|
|
12982708cf | ||
|
|
0cf9e1dd81 | ||
|
|
71e20c4983 | ||
|
|
2147f6d3bf | ||
|
|
23df42d2d3 | ||
|
|
bcf0a0b7fd | ||
|
|
dd78b03a28 | ||
|
|
84dd5e6930 | ||
|
|
dcee98fea7 | ||
|
|
9ffb982ae5 | ||
|
|
428850306f | ||
|
|
abfd6798e3 | ||
|
|
fffadd94de | ||
|
|
d0919776f3 | ||
|
|
267855fded | ||
|
|
4bdebb7feb | ||
|
|
ab5f69d2ef | ||
|
|
63ee36ddfe | ||
|
|
43967f5ded | ||
|
|
c043053b2b | ||
|
|
220f27bd0a | ||
|
|
83914d5378 | ||
|
|
57e4b1a3f1 | ||
|
|
c85e556924 | ||
|
|
8c0be8011d | ||
|
|
7914f75876 | ||
|
|
7d1253e14e | ||
|
|
d7c58b3eb3 | ||
|
|
fb664b6f08 | ||
|
|
258a6d076e | ||
|
|
32ab060153 | ||
|
|
91d3784f9b | ||
|
|
8a5aac3d31 | ||
|
|
06c6effb7d | ||
|
|
f3789c05bd | ||
|
|
c64e1f5e51 | ||
|
|
5d8e24c19a | ||
|
|
f756de05c3 | ||
|
|
574fdb496f | ||
|
|
5580da69eb | ||
|
|
35274863c9 | ||
|
|
1f31b81f0d | ||
|
|
cde111ddeb | ||
|
|
845c12c01c | ||
|
|
99a0118d31 | ||
|
|
bb7ee17362 | ||
|
|
70854ef012 | ||
|
|
053c14056d | ||
|
|
9397d50764 | ||
|
|
473e24cc42 | ||
|
|
d9394605f4 | ||
|
|
d2b9074852 | ||
|
|
b525eb7a0e | ||
|
|
3805aaeeec | ||
|
|
50dc404689 | ||
|
|
975eacbc7e | ||
|
|
7e56dc35b8 | ||
|
|
b3566d98bf | ||
|
|
15379a8e20 | ||
|
|
1e178f4223 | ||
|
|
c16a7b93ea | ||
|
|
f89bb1a750 | ||
|
|
79961aabe4 | ||
|
|
4686fc2b01 | ||
|
|
569b915c07 | ||
|
|
324d3fe7a5 | ||
|
|
ae8d0bf5cb | ||
|
|
17efa82057 | ||
|
|
c17523a476 | ||
|
|
33635d6991 | ||
|
|
d290dbe86b | ||
|
|
c1f5c49eda | ||
|
|
c3f4caa6f3 | ||
|
|
d4c7b0e455 | ||
|
|
b0cb52fe90 | ||
|
|
386f831cd4 | ||
|
|
449daa80cc | ||
|
|
3003547b83 | ||
|
|
1664eb672f | ||
|
|
0939dcacb6 | ||
|
|
54b81d1a42 | ||
|
|
626606100f | ||
|
|
53a0b76e8c | ||
|
|
e16ac9400a | ||
|
|
94060c236b | ||
|
|
890792c270 | ||
|
|
7bc1fc3d0d | ||
|
|
9ea90ed61b | ||
|
|
ce40b80d90 | ||
|
|
53fcd94c5a | ||
|
|
ecb6247959 | ||
|
|
3b4cb6934d | ||
|
|
babe93a6ce | ||
|
|
1e9173699c | ||
|
|
37ba7aa2ca | ||
|
|
a83d2d9910 | ||
|
|
0449064f5d | ||
|
|
6cf1073a3c | ||
|
|
9ac9171206 | ||
|
|
25ce8cd2e4 | ||
|
|
e50522ab89 | ||
|
|
4801502f32 | ||
|
|
e13e4b5ddd | ||
|
|
de8da553f1 | ||
|
|
6558792e73 | ||
|
|
ea5e92017e | ||
|
|
46199efb58 | ||
|
|
8a6eae6c97 | ||
|
|
67eef8a004 | ||
|
|
b5341e5cde | ||
|
|
ac6140b17a | ||
|
|
b1489d98f0 | ||
|
|
3b7119ec58 | ||
|
|
efa34d080e | ||
|
|
19a6277841 | ||
|
|
107e1413ed | ||
|
|
94416dd881 | ||
|
|
8efc39958f | ||
|
|
569f794e33 | ||
|
|
fc1460e592 | ||
|
|
d6e4ee0203 | ||
|
|
0c8135078d | ||
|
|
24f4b864c4 | ||
|
|
41e47f32b6 | ||
|
|
a73ccb15a1 | ||
|
|
36a78f49a5 | ||
|
|
cbd459b0a5 | ||
|
|
03bb1fd089 | ||
|
|
4e2c254717 | ||
|
|
fffb6c5f29 | ||
|
|
81f669e226 | ||
|
|
6484ae54c0 | ||
|
|
1c52caf5e9 | ||
|
|
ce1d4cce57 | ||
|
|
8246197ae6 | ||
|
|
8f90bf8846 | ||
|
|
b955e8a0ea | ||
|
|
81da32f7a2 | ||
|
|
5324fa9350 | ||
|
|
c375daa258 | ||
|
|
4f3bd699c8 | ||
|
|
f5024621c0 | ||
|
|
8308506d71 | ||
|
|
6605c19202 | ||
|
|
fdf1a94f97 | ||
|
|
6b6e37da92 | ||
|
|
0f0fc8ae4e | ||
|
|
4d7e2992e5 | ||
|
|
a5050d4810 | ||
|
|
9df6963f08 | ||
|
|
b833dd4576 | ||
|
|
39378ae20f | ||
|
|
5a2cb943f7 | ||
|
|
b88209f63d | ||
|
|
9c848938f8 | ||
|
|
07b86dda41 | ||
|
|
49e8bf7639 | ||
|
|
a2d0a7f544 | ||
|
|
1a8c894ddf | ||
|
|
3f51f63298 | ||
|
|
a0b4df574b |
79
.github/actions/build-dependencies/action.yml
vendored
Normal file
79
.github/actions/build-dependencies/action.yml
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
name: 'Setup plugin build dependencies'
|
||||
description: 'Builds the plugin build dependencies'
|
||||
inputs:
|
||||
target:
|
||||
description: 'Build target for dependencies'
|
||||
required: true
|
||||
config:
|
||||
description: 'Build configuration'
|
||||
required: false
|
||||
default: 'Release'
|
||||
visualStudio:
|
||||
description: 'Visual Studio version (Windows only)'
|
||||
required: false
|
||||
default: 'Visual Studio 16 2019'
|
||||
workingDirectory:
|
||||
description: 'Working directory for packaging'
|
||||
required: false
|
||||
default: ${{ github.workspace }}
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: Setup cmake
|
||||
uses: jwlawson/actions-setup-cmake@v1.13
|
||||
with:
|
||||
cmake-version: '3.24.x'
|
||||
|
||||
- name: Restore cached dependencies
|
||||
id: restore-cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ env.DEP_DIR }}
|
||||
key: ${{ env.DEP_DIR }}-${{ runner.os }}-${{ inputs.target }}
|
||||
|
||||
- name: Run macOS Build
|
||||
if: ${{ runner.os == 'macOS' && steps.restore-cache.outputs.cache-hit != 'true' }}
|
||||
shell: zsh {0}
|
||||
run: |
|
||||
build_args=(
|
||||
-c ${{ inputs.config }}
|
||||
-t macos-${{ inputs.target }}
|
||||
)
|
||||
|
||||
if (( ${+CI} && ${+RUNNER_DEBUG} )) build_args+=(--debug)
|
||||
|
||||
${{ inputs.workingDirectory }}/.github/scripts/build-deps-macos.zsh -o ${{ env.DEP_DIR }} ${build_args}
|
||||
|
||||
- name: Run Linux Build
|
||||
if: ${{ runner.os == 'Linux' && steps.restore-cache.outputs.cache-hit != 'true' }}
|
||||
shell: bash
|
||||
run: |
|
||||
build_args=(
|
||||
-c ${{ inputs.config }}
|
||||
-t linux-${{ inputs.target }}
|
||||
)
|
||||
|
||||
if [[ -n "${CI}" && -n "${RUNNER_DEBUG}" ]]; then
|
||||
build_args+=(--debug)
|
||||
fi
|
||||
|
||||
${{ inputs.workingDirectory }}/.github/scripts/build-deps-linux.sh -o ${{ env.DEP_DIR }} "${build_args[@]}"
|
||||
|
||||
- name: Run Windows Build
|
||||
if: ${{ runner.os == 'Windows' && steps.restore-cache.outputs.cache-hit != 'true' }}
|
||||
shell: pwsh
|
||||
run: |
|
||||
$BuildArgs = @{
|
||||
Target = '${{ inputs.target }}'
|
||||
Configuration = '${{ inputs.config }}'
|
||||
CMakeGenerator = '${{ inputs.visualStudio }}'
|
||||
}
|
||||
|
||||
if ( ( Test-Path env:CI ) -and ( Test-Path env:RUNNER_DEBUG ) ) {
|
||||
$BuildArgs += @{
|
||||
Debug = $true
|
||||
}
|
||||
}
|
||||
|
||||
${{ inputs.workingDirectory }}/.github/scripts/Build-Deps-Windows.ps1 -OutDirName ${{ env.DEP_DIR }} @BuildArgs
|
||||
|
||||
6
.github/actions/build-plugin/action.yml
vendored
6
.github/actions/build-plugin/action.yml
vendored
@@ -49,7 +49,7 @@ runs:
|
||||
if [[ '${{ inputs.codesign }}' == 'true' ]] build_args+=(-s)
|
||||
if (( ${+CI} && ${+RUNNER_DEBUG} )) build_args+=(--debug)
|
||||
|
||||
${{ inputs.workingDirectory }}/.github/scripts/build-macos.zsh ${build_args}
|
||||
${{ inputs.workingDirectory }}/.github/scripts/build-macos.zsh -d ${{ env.DEP_DIR }} ${build_args}
|
||||
|
||||
- name: Run Linux Build
|
||||
if: ${{ runner.os == 'Linux' }}
|
||||
@@ -68,7 +68,7 @@ runs:
|
||||
build_args+=(-p)
|
||||
fi
|
||||
|
||||
${{ inputs.workingDirectory }}/.github/scripts/build-linux.sh "${build_args[@]}"
|
||||
${{ inputs.workingDirectory }}/.github/scripts/build-linux.sh -d ${{ env.DEP_DIR }} "${build_args[@]}"
|
||||
|
||||
- name: Run Windows Build
|
||||
if: ${{ runner.os == 'Windows' }}
|
||||
@@ -86,4 +86,4 @@ runs:
|
||||
}
|
||||
}
|
||||
|
||||
${{ inputs.workingDirectory }}/.github/scripts/Build-Windows.ps1 @BuildArgs
|
||||
${{ inputs.workingDirectory }}/.github/scripts/Build-Windows.ps1 -ADVSSDepName ${{ env.DEP_DIR }} @BuildArgs
|
||||
|
||||
5
.github/scripts/.Aptfile
vendored
5
.github/scripts/.Aptfile
vendored
@@ -7,3 +7,8 @@ package 'ninja-build', bin: 'ninja'
|
||||
package 'pkg-config'
|
||||
package 'clang'
|
||||
package 'clang-format-13'
|
||||
package 'libxtst-dev'
|
||||
package 'libxss-dev'
|
||||
package 'libopencv-dev'
|
||||
package 'libtesseract-dev'
|
||||
package 'libprocps-dev'
|
||||
|
||||
1
.github/scripts/.Wingetfile
vendored
1
.github/scripts/.Wingetfile
vendored
@@ -1,3 +1,4 @@
|
||||
package '7zip.7zip', path: '7-zip', bin: '7z'
|
||||
package 'cmake', path: 'Cmake\bin', bin: 'cmake'
|
||||
package 'innosetup', path: 'Inno Setup 6', bin: 'iscc'
|
||||
package 'OpenSSL', path: 'OpenSSL', bin: 'openssl'
|
||||
|
||||
324
.github/scripts/.build-deps.zsh
vendored
Executable file
324
.github/scripts/.build-deps.zsh
vendored
Executable file
@@ -0,0 +1,324 @@
|
||||
#!/usr/bin/env zsh
|
||||
|
||||
builtin emulate -L zsh
|
||||
setopt EXTENDED_GLOB
|
||||
setopt PUSHD_SILENT
|
||||
setopt ERR_EXIT
|
||||
setopt ERR_RETURN
|
||||
setopt NO_UNSET
|
||||
setopt PIPE_FAIL
|
||||
setopt NO_AUTO_PUSHD
|
||||
setopt NO_PUSHD_IGNORE_DUPS
|
||||
setopt FUNCTION_ARGZERO
|
||||
|
||||
## Enable for script debugging
|
||||
# setopt WARN_CREATE_GLOBAL
|
||||
# setopt WARN_NESTED_VAR
|
||||
# setopt XTRACE
|
||||
|
||||
autoload -Uz is-at-least && if ! is-at-least 5.2; then
|
||||
print -u2 -PR "%F{1}${funcstack[1]##*/}:%f Running on Zsh version %B${ZSH_VERSION}%b, but Zsh %B5.2%b is the minimum supported version. Upgrade Zsh to fix this issue."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
_trap_error() {
|
||||
print -u2 -PR '%F{1} ✖︎ script execution error%f'
|
||||
print -PR -e "
|
||||
Callstack:
|
||||
${(j:\n :)funcfiletrace}
|
||||
"
|
||||
exit 2
|
||||
}
|
||||
|
||||
build() {
|
||||
if (( ! ${+SCRIPT_HOME} )) typeset -g SCRIPT_HOME=${ZSH_ARGZERO:A:h}
|
||||
local host_os=${${(s:-:)ZSH_ARGZERO:t:r}[3]}
|
||||
local target="${host_os}-${CPUTYPE}"
|
||||
local project_root=${SCRIPT_HOME:A:h:h}
|
||||
local buildspec_file="${project_root}/buildspec.json"
|
||||
|
||||
trap '_trap_error' ZERR
|
||||
|
||||
fpath=("${SCRIPT_HOME}/utils.zsh" ${fpath})
|
||||
autoload -Uz log_info log_error log_output set_loglevel check_${host_os} setup_${host_os} setup_obs setup_ccache
|
||||
|
||||
if [[ ! -r ${buildspec_file} ]] {
|
||||
log_error \
|
||||
'No buildspec.json found. Please create a build specification for your project.' \
|
||||
'A buildspec.json.template file is provided in the repository to get you started.'
|
||||
return 2
|
||||
}
|
||||
|
||||
typeset -g -a skips=()
|
||||
local -i _verbosity=1
|
||||
local -r _version='1.0.0'
|
||||
local -r -a _valid_targets=(
|
||||
macos-x86_64
|
||||
macos-arm64
|
||||
macos-universal
|
||||
linux-x86_64
|
||||
)
|
||||
local -r -a _valid_configs=(Debug RelWithDebInfo Release MinSizeRel)
|
||||
if [[ ${host_os} == 'macos' ]] {
|
||||
local -r -a _valid_generators=(Xcode Ninja 'Unix Makefiles')
|
||||
local generator="${${CI:+Ninja}:-Xcode}"
|
||||
} else {
|
||||
local -r -a _valid_generators=(Ninja 'Unix Makefiles')
|
||||
local generator='Ninja'
|
||||
}
|
||||
local -r _usage="
|
||||
Usage: %B${functrace[1]%:*}%b <option> [<options>]
|
||||
|
||||
%BOptions%b:
|
||||
|
||||
%F{yellow} Build configuration options%f
|
||||
-----------------------------------------------------------------------------
|
||||
%B-t | --target%b Specify target - default: %B%F{green}${host_os}-${CPUTYPE}%f%b
|
||||
%B-c | --config%b Build configuration - default: %B%F{green}RelWithDebInfo%f%b
|
||||
%B-o | --out%b Output directory - default: %B%F{green}RelWithDebInfo%f%b
|
||||
%B--generator%b Specify build system to generate - default: %B%F{green}Ninja%f%b
|
||||
Available generators:
|
||||
- Ninja
|
||||
- Unix Makefiles
|
||||
- Xcode (macOS only)
|
||||
|
||||
%F{yellow} Output options%f
|
||||
-----------------------------------------------------------------------------
|
||||
%B-q | --quiet%b Quiet (error output only)
|
||||
%B-v | --verbose%b Verbose (more detailed output)
|
||||
%B--skip-[all|build|deps|unpack]%b Skip all|building OBS|checking for dependencies|unpacking dependencies
|
||||
%B--debug%b Debug (very detailed and added output)
|
||||
|
||||
%F{yellow} General options%f
|
||||
-----------------------------------------------------------------------------
|
||||
%B-h | --help%b Print this usage help
|
||||
%B-V | --version%b Print script version information"
|
||||
|
||||
local -a args
|
||||
while (( # )) {
|
||||
case ${1} {
|
||||
-t|--target|-c|--config|--generator)
|
||||
if (( # == 1 )) || [[ ${2:0:1} == '-' ]] {
|
||||
log_error "Missing value for option %B${1}%b"
|
||||
log_output ${_usage}
|
||||
exit 2
|
||||
}
|
||||
;;
|
||||
}
|
||||
case ${1} {
|
||||
--)
|
||||
shift
|
||||
args+=($@)
|
||||
break
|
||||
;;
|
||||
-t|--target)
|
||||
if (( ! ${_valid_targets[(Ie)${2}]} )) {
|
||||
log_error "Invalid value %B${2}%b for option %B${1}%b"
|
||||
log_output ${_usage}
|
||||
exit 2
|
||||
}
|
||||
target=${2}
|
||||
shift 2
|
||||
;;
|
||||
-c|--config)
|
||||
if (( ! ${_valid_configs[(Ie)${2}]} )) {
|
||||
log_error "Invalid value %B${2}%b for option %B${1}%b"
|
||||
log_output ${_usage}
|
||||
exit 2
|
||||
}
|
||||
BUILD_CONFIG=${2}
|
||||
shift 2
|
||||
;;
|
||||
-o|--out)
|
||||
OUT_DIR="${2}"
|
||||
shift 2
|
||||
;;
|
||||
-q|--quiet) (( _verbosity -= 1 )) || true; shift ;;
|
||||
-v|--verbose) (( _verbosity += 1 )); shift ;;
|
||||
-h|--help) log_output ${_usage}; exit 0 ;;
|
||||
-V|--version) print -Pr "${_version}"; exit 0 ;;
|
||||
--debug) _verbosity=3; shift ;;
|
||||
--generator)
|
||||
if (( ! ${_valid_generators[(Ie)${2}]} )) {
|
||||
log_error "Invalid value %B${2}%b for option %B${1}%b"
|
||||
log_output ${_usage}
|
||||
exit 2
|
||||
}
|
||||
generator=${2}
|
||||
shift 2
|
||||
;;
|
||||
--skip-*)
|
||||
local _skip="${${(s:-:)1}[-1]}"
|
||||
local _check=(all deps unpack build)
|
||||
(( ${_check[(Ie)${_skip}]} )) || log_warning "Invalid skip mode %B${_skip}%b supplied"
|
||||
typeset -g -a skips=(${skips} ${_skip})
|
||||
shift
|
||||
;;
|
||||
*) log_error "Unknown option: %B${1}%b"; log_output ${_usage}; exit 2 ;;
|
||||
}
|
||||
}
|
||||
|
||||
set -- ${(@)args}
|
||||
set_loglevel ${_verbosity}
|
||||
|
||||
check_${host_os}
|
||||
setup_ccache
|
||||
|
||||
typeset -g QT_VERSION
|
||||
typeset -g DEPLOYMENT_TARGET
|
||||
typeset -g OBS_DEPS_VERSION
|
||||
setup_${host_os}
|
||||
|
||||
local product_name
|
||||
local product_version
|
||||
local git_tag="$(git describe --tags)"
|
||||
|
||||
read -r product_name product_version <<< \
|
||||
"$(jq -r '. | {name, version} | join(" ")' ${buildspec_file})"
|
||||
|
||||
if [[ "${git_tag}" =~ '^([0-9]+\.){0,2}(\*|[0-9]+)$' ]] {
|
||||
log_info "Using git tag as version identifier '${git_tag}'"
|
||||
product_version="${git_tag}"
|
||||
} else {
|
||||
log_info "Using buildspec.json version identifier '${product_version}'"
|
||||
}
|
||||
|
||||
if [[ -z "${OUT_DIR}" ]] {
|
||||
OUT_DIR="advss-build-dependencies"
|
||||
}
|
||||
mkdir -p "${project_root}/../${OUT_DIR}"
|
||||
local advss_dep_path="$(realpath ${project_root}/../${OUT_DIR})"
|
||||
local _plugin_deps="${project_root:h}/obs-build-dependencies/plugin-deps-${OBS_DEPS_VERSION}-qt${QT_VERSION}-${target##*-}"
|
||||
|
||||
case ${host_os} {
|
||||
macos)
|
||||
local opencv_dir="${project_root}/deps/opencv"
|
||||
local opencv_build_dir="${opencv_dir}/build_${target##*-}"
|
||||
|
||||
local -a opencv_cmake_args=(
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
-DBUILD_LIST=core,imgproc,objdetect
|
||||
-DCMAKE_OSX_ARCHITECTURES=${${target##*-}//universal/x86_64;arm64}
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${DEPLOYMENT_TARGET:-10.15}
|
||||
-DCMAKE_PREFIX_PATH="${advss_dep_path};${_plugin_deps}"
|
||||
-DCMAKE_INSTALL_PREFIX="${advss_dep_path}"
|
||||
)
|
||||
|
||||
if [ "${target}" != "macos-x86_64" ]; then
|
||||
opencv_cmake_args+=(-DWITH_IPP=OFF)
|
||||
fi
|
||||
|
||||
pushd ${opencv_dir}
|
||||
log_info "Configure OpenCV ..."
|
||||
cmake -S . -B ${opencv_build_dir} -G ${generator} ${opencv_cmake_args}
|
||||
|
||||
log_info "Building OpenCV ..."
|
||||
cmake --build ${opencv_build_dir} --config Release
|
||||
|
||||
log_info "Installing OpenCV..."
|
||||
cmake --install ${opencv_build_dir} --prefix "${advss_dep_path}" --config Release || true
|
||||
popd
|
||||
|
||||
local leptonica_dir="${project_root}/deps/leptonica"
|
||||
local leptonica_build_dir="${leptonica_dir}/build_${target##*-}"
|
||||
|
||||
local -a leptonica_cmake_args=(
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
-DCMAKE_OSX_ARCHITECTURES=${${target##*-}//universal/x86_64;arm64}
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${DEPLOYMENT_TARGET:-10.15}
|
||||
-DSW_BUILD=OFF
|
||||
-DOPENJPEG_SUPPORT=OFF
|
||||
-DLIBWEBP_SUPPORT=OFF
|
||||
-DCMAKE_DISABLE_FIND_PACKAGE_GIF=TRUE
|
||||
-DCMAKE_DISABLE_FIND_PACKAGE_JPEG=TRUE
|
||||
-DCMAKE_DISABLE_FIND_PACKAGE_TIFF=TRUE
|
||||
-DCMAKE_DISABLE_FIND_PACKAGE_PNG=TRUE
|
||||
-DCMAKE_PREFIX_PATH="${advss_dep_path};${_plugin_deps}"
|
||||
-DCMAKE_INSTALL_PREFIX="${advss_dep_path}"
|
||||
)
|
||||
|
||||
pushd ${leptonica_dir}
|
||||
log_info "Configure Leptonica ..."
|
||||
cmake -S . -B ${leptonica_build_dir} -G ${generator} ${leptonica_cmake_args}
|
||||
|
||||
log_info "Building Leptonica ..."
|
||||
cmake --build ${leptonica_build_dir} --config Release
|
||||
|
||||
log_info "Installing Leptonica..."
|
||||
# Workaround for "unknown file attribute: H" errors when running install
|
||||
cmake --install ${leptonica_build_dir} --prefix "${advss_dep_path}" --config Release || :
|
||||
popd
|
||||
|
||||
local tesseract_dir="${project_root}/deps/tesseract"
|
||||
local tesseract_build_dir="${tesseract_dir}/build_${target##*-}"
|
||||
|
||||
local -a tesseract_cmake_args=(
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
-DCMAKE_OSX_ARCHITECTURES=${${target##*-}//universal/x86_64;arm64}
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${DEPLOYMENT_TARGET:-10.15}
|
||||
-DSW_BUILD=OFF
|
||||
-DBUILD_TRAINING_TOOLS=OFF
|
||||
-DCMAKE_PREFIX_PATH="${advss_dep_path};${_plugin_deps}"
|
||||
-DCMAKE_INSTALL_PREFIX="${advss_dep_path}"
|
||||
)
|
||||
|
||||
if [ "${target}" != "macos-x86_64" ]; then
|
||||
tesseract_cmake_args+=(
|
||||
-DCMAKE_SYSTEM_PROCESSOR=aarch64
|
||||
-DHAVE_AVX=FALSE
|
||||
-DHAVE_AVX2=FALSE
|
||||
-DHAVE_AVX512F=FALSE
|
||||
-DHAVE_FMA=FALSE
|
||||
-DHAVE_SSE4_1=FALSE
|
||||
-DHAVE_NEON=TRUE
|
||||
)
|
||||
sed -i'.original' 's/HAVE_NEON FALSE/HAVE_NEON TRUE/g' "${tesseract_dir}/CMakeLists.txt"
|
||||
fi
|
||||
|
||||
pushd ${tesseract_dir}
|
||||
log_info "Configure Tesseract ..."
|
||||
cmake -S . -B ${tesseract_build_dir} -G ${generator} ${tesseract_cmake_args}
|
||||
|
||||
log_info "Building Tesseract ..."
|
||||
cmake --build ${tesseract_build_dir} --config Release
|
||||
|
||||
log_info "Installing Tesseract..."
|
||||
cmake --install ${tesseract_build_dir} --prefix "${advss_dep_path}" --config Release
|
||||
popd
|
||||
|
||||
pushd ${advss_dep_path}
|
||||
log_info "Prepare openssl ..."
|
||||
rm -rf openssl
|
||||
git clone git://git.openssl.org/openssl.git --branch openssl-3.1.2 --depth 1
|
||||
mv openssl openssl_x86
|
||||
cp -r openssl_x86 openssl_arm
|
||||
|
||||
log_info "Building openssl x86 ..."
|
||||
export MACOSX_DEPLOYMENT_TARGET=10.9
|
||||
cd openssl_x86
|
||||
./Configure darwin64-x86_64-cc shared
|
||||
make
|
||||
|
||||
log_info "Building openssl arm ..."
|
||||
export MACOSX_DEPLOYMENT_TARGET=10.15
|
||||
cd ../openssl_arm
|
||||
./Configure enable-rc5 zlib darwin64-arm64-cc no-asm
|
||||
make
|
||||
|
||||
log_info "Combine arm and x86 openssl binaries ..."
|
||||
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..."
|
||||
mv openssl_x86 openssl
|
||||
rm -rf openssl_arm
|
||||
;;
|
||||
linux)
|
||||
# Nothing to do for now
|
||||
;;
|
||||
}
|
||||
}
|
||||
|
||||
build ${@}
|
||||
112
.github/scripts/.build.zsh
vendored
112
.github/scripts/.build.zsh
vendored
@@ -36,6 +36,7 @@ build() {
|
||||
local target="${host_os}-${CPUTYPE}"
|
||||
local project_root=${SCRIPT_HOME:A:h:h}
|
||||
local buildspec_file="${project_root}/buildspec.json"
|
||||
local dep_dir=""
|
||||
|
||||
trap '_trap_error' ZERR
|
||||
|
||||
@@ -77,6 +78,7 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
|
||||
%B-c | --config%b Build configuration - default: %B%F{green}RelWithDebInfo%f%b
|
||||
%B-s | --codesign%b Enable codesigning (macOS only)
|
||||
%B-p | --portable%b Enable portable mode (Linux only)
|
||||
%B-d | --dep%b Dependency directory name - default: %B%F{green}advss-build-dependencies%f%b
|
||||
%B--generator%b Specify build system to generate - default: %B%F{green}Ninja%f%b
|
||||
Available generators:
|
||||
- Ninja
|
||||
@@ -130,6 +132,10 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
|
||||
BUILD_CONFIG=${2}
|
||||
shift 2
|
||||
;;
|
||||
-d|--dep)
|
||||
dep_dir="${2}"
|
||||
shift 2
|
||||
;;
|
||||
-s|--codesign) CODESIGN=1; shift ;;
|
||||
-p|--portable) typeset -g PORTABLE=1; shift ;;
|
||||
-q|--quiet) (( _verbosity -= 1 )) || true; shift ;;
|
||||
@@ -168,6 +174,15 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
|
||||
typeset -g OBS_DEPS_VERSION
|
||||
setup_${host_os}
|
||||
|
||||
local advss_deps_path
|
||||
if [[ -z "${dep_dir}" ]] {
|
||||
log_info "Building advss deps ..."
|
||||
dep_dir="advss-build-dependencies"
|
||||
${SCRIPT_HOME}/build-deps-${host_os}.zsh -c "${BUILD_CONFIG:-RelWithDebInfo}" -t "${target}" --generator "${generator}" -o "${dep_dir}" --skip-deps --skip-unpack
|
||||
}
|
||||
advss_deps_path=$(realpath ${project_root}/../${dep_dir})
|
||||
log_info "Using advss deps at $advss_deps_path ..."
|
||||
|
||||
local product_name
|
||||
local product_version
|
||||
local git_tag="$(git describe --tags)"
|
||||
@@ -187,96 +202,6 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
|
||||
sed -i '' \
|
||||
"s/project(\(.*\) VERSION \(.*\))/project(${product_name} VERSION ${product_version})/" \
|
||||
"${project_root}/CMakeLists.txt"
|
||||
|
||||
local opencv_dir="${project_root}/deps/opencv"
|
||||
local opencv_build_dir="${opencv_dir}/build_${target##*-}"
|
||||
|
||||
local -a opencv_cmake_args=(
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
-DBUILD_LIST=core,imgproc,objdetect
|
||||
-DCMAKE_OSX_ARCHITECTURES=${${target##*-}//universal/x86_64;arm64}
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${DEPLOYMENT_TARGET:-10.15}
|
||||
)
|
||||
|
||||
if [ "${target}" != "macos-x86_64" ]; then
|
||||
opencv_cmake_args+=(-DWITH_IPP=OFF)
|
||||
fi
|
||||
|
||||
pushd ${opencv_dir}
|
||||
log_info "Configure OpenCV ..."
|
||||
cmake -S . -B ${opencv_build_dir} -G ${generator} ${opencv_cmake_args}
|
||||
|
||||
log_info "Building OpenCV ..."
|
||||
cmake --build ${opencv_build_dir} --config Release
|
||||
|
||||
log_info "Installing OpenCV..."
|
||||
cmake --install ${opencv_build_dir} --config Release || true
|
||||
popd
|
||||
|
||||
local leptonica_dir="${project_root}/deps/leptonica"
|
||||
local leptonica_build_dir="${leptonica_dir}/build_${target##*-}"
|
||||
|
||||
local -a leptonica_cmake_args=(
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
-DCMAKE_OSX_ARCHITECTURES=${${target##*-}//universal/x86_64;arm64}
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${DEPLOYMENT_TARGET:-10.15}
|
||||
-DSW_BUILD=OFF
|
||||
-DOPENJPEG_SUPPORT=OFF
|
||||
-DLIBWEBP_SUPPORT=OFF
|
||||
-DCMAKE_DISABLE_FIND_PACKAGE_GIF=TRUE
|
||||
-DCMAKE_DISABLE_FIND_PACKAGE_JPEG=TRUE
|
||||
-DCMAKE_DISABLE_FIND_PACKAGE_TIFF=TRUE
|
||||
-DCMAKE_DISABLE_FIND_PACKAGE_PNG=TRUE
|
||||
)
|
||||
|
||||
pushd ${leptonica_dir}
|
||||
log_info "Configure Leptonica ..."
|
||||
cmake -S . -B ${leptonica_build_dir} -G ${generator} ${leptonica_cmake_args}
|
||||
|
||||
log_info "Building Leptonica ..."
|
||||
cmake --build ${leptonica_build_dir} --config Release
|
||||
|
||||
log_info "Installing Leptonica..."
|
||||
# Workaround for "unknown file attribute: H" errors when running install
|
||||
cmake --install ${leptonica_build_dir} --config Release || :
|
||||
popd
|
||||
|
||||
local tesseract_dir="${project_root}/deps/tesseract"
|
||||
local tesseract_build_dir="${tesseract_dir}/build_${target##*-}"
|
||||
|
||||
local -a tesseract_cmake_args=(
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
-DCMAKE_OSX_ARCHITECTURES=${${target##*-}//universal/x86_64;arm64}
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${DEPLOYMENT_TARGET:-10.15}
|
||||
-DSW_BUILD=OFF
|
||||
-DBUILD_TRAINING_TOOLS=OFF
|
||||
)
|
||||
|
||||
if [ "${target}" != "macos-x86_64" ]; then
|
||||
tesseract_cmake_args+=(
|
||||
-DCMAKE_SYSTEM_PROCESSOR=aarch64
|
||||
-DHAVE_AVX=FALSE
|
||||
-DHAVE_AVX2=FALSE
|
||||
-DHAVE_AVX512F=FALSE
|
||||
-DHAVE_FMA=FALSE
|
||||
-DHAVE_SSE4_1=FALSE
|
||||
-DHAVE_NEON=TRUE
|
||||
)
|
||||
sed -i'.original' 's/HAVE_NEON FALSE/HAVE_NEON TRUE/g' "${tesseract_dir}/CMakeLists.txt"
|
||||
fi
|
||||
|
||||
pushd ${tesseract_dir}
|
||||
log_info "Configure Tesseract ..."
|
||||
cmake -S . -B ${tesseract_build_dir} -G ${generator} ${tesseract_cmake_args}
|
||||
|
||||
log_info "Building Tesseract ..."
|
||||
#cmake --build ${tesseract_build_dir} --config Release --target libtesseract
|
||||
cmake --build ${tesseract_build_dir} --config Release
|
||||
|
||||
log_info "Installing Tesseract..."
|
||||
#cmake --install ${tesseract_build_dir} --config Release --component libtesseract
|
||||
cmake --install ${tesseract_build_dir} --config Release
|
||||
popd
|
||||
;;
|
||||
linux)
|
||||
sed -i'' \
|
||||
@@ -295,7 +220,7 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
|
||||
local -a cmake_args=(
|
||||
-DCMAKE_BUILD_TYPE=${BUILD_CONFIG:-RelWithDebInfo}
|
||||
-DQT_VERSION=${QT_VERSION}
|
||||
-DCMAKE_PREFIX_PATH="${_plugin_deps}"
|
||||
-DCMAKE_PREFIX_PATH="${_plugin_deps};${advss_deps_path}"
|
||||
)
|
||||
|
||||
if (( _loglevel == 0 )) cmake_args+=(-Wno_deprecated -Wno-dev --log-level=ERROR)
|
||||
@@ -312,12 +237,17 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
|
||||
|
||||
num_procs=$(( $(sysctl -n hw.ncpu) + 1 ))
|
||||
|
||||
local openssl_lib_dir="${advss_deps_path}/openssl-combined/"
|
||||
local openssl_include_dir="${advss_deps_path}/openssl/include"
|
||||
|
||||
cmake_args+=(
|
||||
-DCMAKE_FRAMEWORK_PATH="${_plugin_deps}/Frameworks"
|
||||
-DCMAKE_OSX_ARCHITECTURES=${${target##*-}//universal/x86_64;arm64}
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${DEPLOYMENT_TARGET:-10.15}
|
||||
-DOBS_CODESIGN_LINKER=ON
|
||||
-DOBS_BUNDLE_CODESIGN_IDENTITY="${CODESIGN_IDENT:--}"
|
||||
-DOPENSSL_INCLUDE_DIR="${openssl_include_dir}"
|
||||
-DOPENSSL_LIBRARIES="${openssl_lib_dir}/libcrypto.a;${openssl_lib_dir}/libssl.a"
|
||||
)
|
||||
|
||||
;;
|
||||
|
||||
172
.github/scripts/Build-Deps-Windows.ps1
vendored
Normal file
172
.github/scripts/Build-Deps-Windows.ps1
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[ValidateSet('Debug', 'RelWithDebInfo', 'Release', 'MinSizeRel')]
|
||||
[string] $Configuration = 'RelWithDebInfo',
|
||||
[ValidateSet('x86', 'x64')]
|
||||
[string] $Target,
|
||||
[ValidateSet('Visual Studio 17 2022', 'Visual Studio 16 2019')]
|
||||
[string] $CMakeGenerator,
|
||||
[string] $OutDirName,
|
||||
[switch] $SkipDeps,
|
||||
[switch] $SkipUnpack
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
if ( $DebugPreference -eq 'Continue' ) {
|
||||
$VerbosePreference = 'Continue'
|
||||
$InformationPreference = 'Continue'
|
||||
}
|
||||
|
||||
if ( $PSVersionTable.PSVersion -lt '7.0.0' ) {
|
||||
Write-Warning 'The obs-deps PowerShell build script requires PowerShell Core 7. Install or upgrade your PowerShell version: https://aka.ms/pscore6'
|
||||
exit 2
|
||||
}
|
||||
|
||||
function Build {
|
||||
trap {
|
||||
Pop-Location -Stack BuildTemp -ErrorAction 'SilentlyContinue'
|
||||
Write-Error $_
|
||||
exit 2
|
||||
}
|
||||
|
||||
$ScriptHome = $PSScriptRoot
|
||||
$ProjectRoot = Resolve-Path -Path "$PSScriptRoot/../.."
|
||||
$BuildSpecFile = "${ProjectRoot}/buildspec.json"
|
||||
|
||||
$UtilityFunctions = Get-ChildItem -Path $PSScriptRoot/utils.pwsh/*.ps1 -Recurse
|
||||
|
||||
foreach ($Utility in $UtilityFunctions) {
|
||||
Write-Debug "Loading $($Utility.FullName)"
|
||||
. $Utility.FullName
|
||||
}
|
||||
|
||||
$BuildSpec = Get-Content -Path ${BuildSpecFile} -Raw | ConvertFrom-Json
|
||||
$ProductName = $BuildSpec.name
|
||||
$ProductVersion = $BuildSpec.version
|
||||
|
||||
$script:VisualStudioVersion = ''
|
||||
$script:PlatformSDK = '10.0.18363.657'
|
||||
|
||||
Setup-Host
|
||||
|
||||
if ( $CmakeGenerator -eq '' ) {
|
||||
$CmakeGenerator = $script:VisualStudioVersion
|
||||
}
|
||||
|
||||
$DepsPath = "plugin-deps-${script:DepsVersion}-*-${script:Target}"
|
||||
$OBSDepPath = "$(Resolve-Path -Path ${ProjectRoot}/../obs-build-dependencies/${DepsPath})"
|
||||
|
||||
if ( $OutDirName -eq '' ) {
|
||||
$OutDirName = "advss-build-dependencies"
|
||||
}
|
||||
New-Item -ItemType Directory -Force -Path ${ProjectRoot}/../${OutDirName}
|
||||
|
||||
$ADVSSDepPath = "$(Resolve-Path -Path ${ProjectRoot}/../${OutDirName})"
|
||||
|
||||
$OpenCVPath = "${ProjectRoot}/deps/opencv"
|
||||
$OpenCVBuildPath = "${OpenCVPath}/build"
|
||||
|
||||
Push-Location -Stack BuildOpenCVTemp
|
||||
Ensure-Location $ProjectRoot
|
||||
|
||||
$OpenCVCmakeArgs = @(
|
||||
'-G', $CmakeGenerator
|
||||
"-DCMAKE_SYSTEM_VERSION=${script:PlatformSDK}"
|
||||
"-DCMAKE_GENERATOR_PLATFORM=$(if (${script:Target} -eq "x86") { "Win32" } else { "x64" })"
|
||||
"-DCMAKE_BUILD_TYPE=Release"
|
||||
"-DCMAKE_PREFIX_PATH:PATH=${OBSDepPath}"
|
||||
"-DCMAKE_INSTALL_PREFIX:PATH=${ADVSSDepPath}"
|
||||
"-DBUILD_LIST=core,imgproc,objdetect"
|
||||
)
|
||||
|
||||
Log-Information "Configuring OpenCV..."
|
||||
Invoke-External cmake -S ${OpenCVPath} -B ${OpenCVBuildPath} @OpenCVCmakeArgs
|
||||
|
||||
$OpenCVCmakeArgs = @(
|
||||
'--config', "Release"
|
||||
)
|
||||
|
||||
if ( $VerbosePreference -eq 'Continue' ) {
|
||||
$OpenCVCmakeArgs += ('--verbose')
|
||||
}
|
||||
|
||||
Log-Information "Building OpenCV..."
|
||||
Invoke-External cmake --build "${OpenCVBuildPath}" @OpenCVCmakeArgs
|
||||
Log-Information "Install OpenCV}..."
|
||||
Invoke-External cmake --install "${OpenCVBuildPath}" --prefix "${ADVSSDepPath}" @OpenCVCmakeArgs
|
||||
|
||||
$LeptonicaPath = "${ProjectRoot}/deps/leptonica"
|
||||
$LeptonicaBuildPath = "${LeptonicaPath}/build"
|
||||
|
||||
Push-Location -Stack BuildLeptonicaTemp
|
||||
Ensure-Location $ProjectRoot
|
||||
|
||||
$LeptonicaCmakeArgs = @(
|
||||
'-G', $CmakeGenerator
|
||||
"-DCMAKE_SYSTEM_VERSION=${script:PlatformSDK}"
|
||||
"-DCMAKE_GENERATOR_PLATFORM=$(if (${script:Target} -eq "x86") { "Win32" } else { "x64" })"
|
||||
"-DCMAKE_BUILD_TYPE=${Configuration}"
|
||||
"-DCMAKE_PREFIX_PATH:PATH=${OBSDepPath}"
|
||||
"-DCMAKE_INSTALL_PREFIX:PATH=${ADVSSDepPath}"
|
||||
"-DSW_BUILD=OFF"
|
||||
"-DLIBWEBP_SUPPORT=OFF"
|
||||
)
|
||||
|
||||
Log-Information "Configuring leptonica..."
|
||||
Invoke-External cmake -S ${LeptonicaPath} -B ${LeptonicaBuildPath} @LeptonicaCmakeArgs
|
||||
|
||||
$LeptonicaCmakeArgs = @(
|
||||
'--config', "${Configuration}"
|
||||
)
|
||||
|
||||
if ( $VerbosePreference -eq 'Continue' ) {
|
||||
$LeptonicaCmakeArgs += ('--verbose')
|
||||
}
|
||||
|
||||
Log-Information "Building leptonica..."
|
||||
Invoke-External cmake --build "${LeptonicaBuildPath}" @LeptonicaCmakeArgs
|
||||
|
||||
Log-Information "Install leptonica..."
|
||||
Invoke-External cmake --install "${LeptonicaBuildPath}" --prefix "${ADVSSDepPath}" @LeptonicaCmakeArgs
|
||||
|
||||
Push-Location -Stack BuildTesseractTemp
|
||||
Ensure-Location $ProjectRoot
|
||||
|
||||
$TesseractPath = "${ProjectRoot}/deps/tesseract"
|
||||
$TesseractBuildPath = "${TesseractPath}/build"
|
||||
|
||||
# Explicitly disable PkgConfig and tiff as it will lead build errors
|
||||
$TesseractCmakeArgs = @(
|
||||
'-G', $CmakeGenerator
|
||||
"-DCMAKE_SYSTEM_VERSION=${script:PlatformSDK}"
|
||||
"-DCMAKE_GENERATOR_PLATFORM=$(if (${script:Target} -eq "x86") { "Win32" } else { "x64" })"
|
||||
"-DCMAKE_BUILD_TYPE=${Configuration}"
|
||||
"-DCMAKE_PREFIX_PATH:PATH=${OBSDepPath}"
|
||||
"-DCMAKE_INSTALL_PREFIX:PATH=${ADVSSDepPath}"
|
||||
"-DSW_BUILD=OFF"
|
||||
"-DDISABLE_CURL=ON"
|
||||
"-DBUILD_TRAINING_TOOLS=OFF"
|
||||
"-DCMAKE_DISABLE_FIND_PACKAGE_TIFF=TRUE"
|
||||
"-DCMAKE_DISABLE_FIND_PACKAGE_PkgConfig=TRUE"
|
||||
)
|
||||
|
||||
Log-Information "Configuring tesseract..."
|
||||
Invoke-External cmake -S ${TesseractPath} -B ${TesseractBuildPath} @TesseractCmakeArgs
|
||||
|
||||
$TesseractCmakeArgs = @(
|
||||
'--config', "${Configuration}"
|
||||
)
|
||||
|
||||
if ( $VerbosePreference -eq 'Continue' ) {
|
||||
$TesseractCmakeArgs += ('--verbose')
|
||||
}
|
||||
|
||||
Log-Information "Building tesseract..."
|
||||
Invoke-External cmake --build "${TesseractBuildPath}" @TesseractCmakeArgs
|
||||
|
||||
Log-Information "Install tesseract..."
|
||||
Invoke-External cmake --install "${TesseractBuildPath}" --prefix "${ADVSSDepPath}" @TesseractCmakeArgs
|
||||
}
|
||||
|
||||
Build
|
||||
116
.github/scripts/Build-Windows.ps1
vendored
116
.github/scripts/Build-Windows.ps1
vendored
@@ -6,6 +6,7 @@ param(
|
||||
[string] $Target,
|
||||
[ValidateSet('Visual Studio 17 2022', 'Visual Studio 16 2019')]
|
||||
[string] $CMakeGenerator,
|
||||
[string] $ADVSSDepName,
|
||||
[switch] $SkipAll,
|
||||
[switch] $SkipBuild,
|
||||
[switch] $SkipDeps,
|
||||
@@ -60,116 +61,17 @@ function Build {
|
||||
$DepsPath = "plugin-deps-${script:DepsVersion}-qt${script:QtVersion}-${script:Target}"
|
||||
$DepInstallPath = "$(Resolve-Path -Path ${ProjectRoot}/../obs-build-dependencies/${DepsPath})"
|
||||
|
||||
$OpenCVPath = "${ProjectRoot}/deps/opencv"
|
||||
$OpenCVBuildPath = "${OpenCVPath}/build"
|
||||
|
||||
Push-Location -Stack BuildOpenCVTemp
|
||||
if ( ! ( ( $SkipAll ) -or ( $SkipBuild ) ) ) {
|
||||
Ensure-Location $ProjectRoot
|
||||
|
||||
$OpenCVCmakeArgs = @(
|
||||
'-G', $CmakeGenerator
|
||||
"-DCMAKE_SYSTEM_VERSION=${script:PlatformSDK}"
|
||||
"-DCMAKE_GENERATOR_PLATFORM=$(if (${script:Target} -eq "x86") { "Win32" } else { "x64" })"
|
||||
"-DCMAKE_BUILD_TYPE=Release"
|
||||
"-DCMAKE_PREFIX_PATH:PATH=${DepInstallPath}"
|
||||
"-DBUILD_LIST=core,imgproc,objdetect"
|
||||
)
|
||||
|
||||
Log-Information "Configuring OpenCV..."
|
||||
Invoke-External cmake -S ${OpenCVPath} -B ${OpenCVBuildPath} @OpenCVCmakeArgs
|
||||
|
||||
$OpenCVCmakeArgs = @(
|
||||
'--config', "Release"
|
||||
)
|
||||
|
||||
if ( $VerbosePreference -eq 'Continue' ) {
|
||||
$OpenCVCmakeArgs += ('--verbose')
|
||||
}
|
||||
|
||||
Log-Information "Building OpenCV..."
|
||||
Invoke-External cmake --build "${OpenCVBuildPath}" @OpenCVCmakeArgs
|
||||
if ( $ADVSSDepName -eq '' ) {
|
||||
Log-Information "Building advss deps ..."
|
||||
$ADVSSDepName = "advss-build-dependencies"
|
||||
invoke-expression -Command "$PSScriptRoot/Build-Deps-Windows.ps1 -Configuration $Configuration -Target $Target -CMakeGenerator `"$CMakeGenerator`" -OutDirName $ADVSSDepName -SkipDeps -SkipUnpack"
|
||||
}
|
||||
Log-Information "Install OpenCV}..."
|
||||
Invoke-External cmake --install "${OpenCVBuildPath}" --prefix "${DepInstallPath}" @OpenCVCmakeArgs
|
||||
|
||||
$LeptonicaPath = "${ProjectRoot}/deps/leptonica"
|
||||
$LeptonicaBuildPath = "${LeptonicaPath}/build"
|
||||
|
||||
Push-Location -Stack BuildLeptonicaTemp
|
||||
if ( ! ( ( $SkipAll ) -or ( $SkipBuild ) ) ) {
|
||||
Ensure-Location $ProjectRoot
|
||||
|
||||
$LeptonicaCmakeArgs = @(
|
||||
'-G', $CmakeGenerator
|
||||
"-DCMAKE_SYSTEM_VERSION=${script:PlatformSDK}"
|
||||
"-DCMAKE_GENERATOR_PLATFORM=$(if (${script:Target} -eq "x86") { "Win32" } else { "x64" })"
|
||||
"-DCMAKE_BUILD_TYPE=${Configuration}"
|
||||
"-DCMAKE_PREFIX_PATH:PATH=${DepInstallPath}"
|
||||
"-DCMAKE_INSTALL_PREFIX:PATH=${DepInstallPath}"
|
||||
"-DSW_BUILD=OFF"
|
||||
"-DLIBWEBP_SUPPORT=OFF"
|
||||
)
|
||||
|
||||
Log-Information "Configuring leptonica..."
|
||||
Invoke-External cmake -S ${LeptonicaPath} -B ${LeptonicaBuildPath} @LeptonicaCmakeArgs
|
||||
|
||||
$LeptonicaCmakeArgs = @(
|
||||
'--config', "${Configuration}"
|
||||
)
|
||||
|
||||
if ( $VerbosePreference -eq 'Continue' ) {
|
||||
$LeptonicaCmakeArgs += ('--verbose')
|
||||
}
|
||||
|
||||
Log-Information "Building leptonica..."
|
||||
Invoke-External cmake --build "${LeptonicaBuildPath}" @LeptonicaCmakeArgs
|
||||
}
|
||||
Log-Information "Install leptonica..."
|
||||
Invoke-External cmake --install "${LeptonicaBuildPath}" --prefix "${DepInstallPath}" @LeptonicaCmakeArgs
|
||||
|
||||
Push-Location -Stack BuildTesseractTemp
|
||||
if ( ! ( ( $SkipAll ) -or ( $SkipBuild ) ) ) {
|
||||
Ensure-Location $ProjectRoot
|
||||
|
||||
$TesseractPath = "${ProjectRoot}/deps/tesseract"
|
||||
$TesseractBuildPath = "${TesseractPath}/build"
|
||||
|
||||
# Explicitly disable PkgConfig and tiff as it will lead build errors
|
||||
$TesseractCmakeArgs = @(
|
||||
'-G', $CmakeGenerator
|
||||
"-DCMAKE_SYSTEM_VERSION=${script:PlatformSDK}"
|
||||
"-DCMAKE_GENERATOR_PLATFORM=$(if (${script:Target} -eq "x86") { "Win32" } else { "x64" })"
|
||||
"-DCMAKE_BUILD_TYPE=${Configuration}"
|
||||
"-DCMAKE_PREFIX_PATH:PATH=${DepInstallPath}"
|
||||
"-DCMAKE_INSTALL_PREFIX:PATH=${DepInstallPath}"
|
||||
"-DSW_BUILD=OFF"
|
||||
"-DDISABLE_CURL=ON"
|
||||
"-DBUILD_TRAINING_TOOLS=OFF"
|
||||
"-DCMAKE_DISABLE_FIND_PACKAGE_TIFF=TRUE"
|
||||
"-DCMAKE_DISABLE_FIND_PACKAGE_PkgConfig=TRUE"
|
||||
)
|
||||
|
||||
Log-Information "Configuring tesseract..."
|
||||
Invoke-External cmake -S ${TesseractPath} -B ${TesseractBuildPath} @TesseractCmakeArgs
|
||||
|
||||
$TesseractCmakeArgs = @(
|
||||
'--config', "${Configuration}"
|
||||
)
|
||||
|
||||
if ( $VerbosePreference -eq 'Continue' ) {
|
||||
$TesseractCmakeArgs += ('--verbose')
|
||||
}
|
||||
|
||||
Log-Information "Building tesseract..."
|
||||
Invoke-External cmake --build "${TesseractBuildPath}" @TesseractCmakeArgs
|
||||
}
|
||||
Log-Information "Install tesseract..."
|
||||
Invoke-External cmake --install "${TesseractBuildPath}" --prefix "${DepInstallPath}" @TesseractCmakeArgs
|
||||
$ADVSSDepPath = "$(Resolve-Path -Path ${ProjectRoot}/../${script:ADVSSDepName})"
|
||||
Log-Information "Using advss deps at $ADVSSDepPath ..."
|
||||
|
||||
(Get-Content -Path ${ProjectRoot}/CMakeLists.txt -Raw) `
|
||||
-replace "project\((.*) VERSION (.*)\)", "project(${ProductName} VERSION ${ProductVersion})" `
|
||||
| Out-File -Path ${ProjectRoot}/CMakeLists.txt
|
||||
| Out-File -Path ${ProjectRoot}/CMakeLists.txt -NoNewline
|
||||
|
||||
Setup-Obs
|
||||
|
||||
@@ -182,7 +84,7 @@ function Build {
|
||||
"-DCMAKE_SYSTEM_VERSION=${script:PlatformSDK}"
|
||||
"-DCMAKE_GENERATOR_PLATFORM=$(if (${script:Target} -eq "x86") { "Win32" } else { "x64" })"
|
||||
"-DCMAKE_BUILD_TYPE=${Configuration}"
|
||||
"-DCMAKE_PREFIX_PATH:PATH=${DepInstallPath}"
|
||||
"-DCMAKE_PREFIX_PATH:PATH=${DepInstallPath};${ADVSSDepPath}"
|
||||
"-DQT_VERSION=${script:QtVersion}"
|
||||
)
|
||||
|
||||
|
||||
13
.github/scripts/build-deps-linux.sh
vendored
Executable file
13
.github/scripts/build-deps-linux.sh
vendored
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
|
||||
if ! type zsh > /dev/null 2>&1; then
|
||||
echo ' => Installing script dependency Zsh.'
|
||||
|
||||
sudo apt-get -y update
|
||||
sudo apt-get -y install zsh
|
||||
fi
|
||||
|
||||
SCRIPT=$(readlink -f "${0}")
|
||||
SCRIPT_DIR=$(dirname "${SCRIPT}")
|
||||
|
||||
zsh ${SCRIPT_DIR}/build-deps-linux.zsh "${@}"
|
||||
1
.github/scripts/build-deps-linux.zsh
vendored
Symbolic link
1
.github/scripts/build-deps-linux.zsh
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
.build-deps.zsh
|
||||
1
.github/scripts/build-deps-macos.zsh
vendored
Symbolic link
1
.github/scripts/build-deps-macos.zsh
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
.build-deps.zsh
|
||||
2
.github/scripts/utils.zsh/check_packages
vendored
2
.github/scripts/utils.zsh/check_packages
vendored
@@ -24,7 +24,7 @@ if (( ! ${+commands[packagesbuild]} )) {
|
||||
pushd
|
||||
mkcd ${project_root:h}/obs-build-dependencies
|
||||
|
||||
local packages_url='http://s.sudre.free.fr/Software/files/Packages.dmg'
|
||||
local packages_url='https://web.archive.org/web/20230727054218/http://s.sudre.free.fr/Software/files/Packages.dmg'
|
||||
local packages_hash='6afdd25386295974dad8f078b8f1e41cabebd08e72d970bf92f707c7e48b16c9'
|
||||
|
||||
if [[ ! -f Packages.dmg ]] {
|
||||
|
||||
7
.github/scripts/utils.zsh/setup_linux
vendored
7
.github/scripts/utils.zsh/setup_linux
vendored
@@ -34,13 +34,6 @@ if (( ! (${skips[(Ie)all]} + ${skips[(Ie)deps]}) )) {
|
||||
|
||||
log_info 'Installing obs plugin dependencies...'
|
||||
|
||||
sudo apt-get install -y \
|
||||
libxtst-dev \
|
||||
libxss-dev \
|
||||
libopencv-dev \
|
||||
libtesseract-dev \
|
||||
libprocps-dev
|
||||
|
||||
local -a _qt_packages=()
|
||||
|
||||
if (( QT_VERSION == 5 )) {
|
||||
|
||||
29
.github/workflows/main.yml
vendored
29
.github/workflows/main.yml
vendored
@@ -17,6 +17,7 @@ on:
|
||||
env:
|
||||
PLUGIN_NAME: SceneSwitcher
|
||||
LIB_NAME: advanced-scene-switcher
|
||||
DEP_DIR: advss-build-dependencies-1
|
||||
|
||||
jobs:
|
||||
clang_check:
|
||||
@@ -115,9 +116,6 @@ jobs:
|
||||
with:
|
||||
path: |
|
||||
${{ github.workspace }}/.ccache
|
||||
${{ github.workspace }}/plugin/deps/opencv/build_*
|
||||
${{ github.workspace }}/plugin/deps/leptonica/build_*
|
||||
${{ github.workspace }}/plugin/deps/tesseract/build*
|
||||
key: macos-${{ matrix.arch }}-ccache-plugin-${{ steps.setup.outputs.ccacheDate }}
|
||||
restore-keys: |
|
||||
macos-${{ matrix.arch }}-ccache-plugin-
|
||||
@@ -146,6 +144,13 @@ jobs:
|
||||
print "CODESIGN_IDENT=${{ secrets.MACOS_SIGNING_APPLICATION_IDENTITY }}" >> $GITHUB_ENV
|
||||
print "CODESIGN_IDENT_INSTALLER=${{ secrets.MACOS_SIGNING_INSTALLER_IDENTITY }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Build Dependencies
|
||||
uses: ./plugin/.github/actions/build-dependencies
|
||||
with:
|
||||
workingDirectory: ${{ github.workspace }}/plugin
|
||||
target: ${{ matrix.arch }}
|
||||
config: RelWithDebInfo
|
||||
|
||||
- name: Build Plugin
|
||||
uses: ./plugin/.github/actions/build-plugin
|
||||
with:
|
||||
@@ -248,6 +253,13 @@ jobs:
|
||||
echo 'found=false' >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Build Dependencies
|
||||
uses: ./plugin/.github/actions/build-dependencies
|
||||
with:
|
||||
workingDirectory: ${{ github.workspace }}/plugin
|
||||
target: ${{ matrix.arch }}
|
||||
config: RelWithDebInfo
|
||||
|
||||
- name: Build Plugin
|
||||
uses: ./plugin/.github/actions/build-plugin
|
||||
with:
|
||||
@@ -329,9 +341,6 @@ jobs:
|
||||
with:
|
||||
path: |
|
||||
${{ github.workspace }}/.ccache
|
||||
${{ github.workspace }}/plugin/deps/opencv/build_*
|
||||
${{ github.workspace }}/plugin/deps/leptonica/build_*
|
||||
${{ github.workspace }}/plugin/deps/tesseract/build*
|
||||
key: windows-${{ matrix.arch }}-ccache-plugin-${{ steps.setup.outputs.ccacheDate }}
|
||||
restore-keys: |
|
||||
windows-${{ matrix.arch }}-ccache-plugin-
|
||||
@@ -357,6 +366,14 @@ jobs:
|
||||
|
||||
"found=$(([string]${LabelFound}).ToLower())" >> $env:GITHUB_OUTPUT
|
||||
|
||||
- name: Build Dependencies
|
||||
uses: ./plugin/.github/actions/build-dependencies
|
||||
with:
|
||||
workingDirectory: ${{ github.workspace }}/plugin
|
||||
target: ${{ matrix.arch }}
|
||||
config: RelWithDebInfo
|
||||
visualStudio: 'Visual Studio 17 2022'
|
||||
|
||||
- name: Build Plugin
|
||||
uses: ./plugin/.github/actions/build-plugin
|
||||
with:
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -91,6 +91,7 @@ Thumbs.db
|
||||
.settings
|
||||
.idea
|
||||
.metadata
|
||||
.vscode
|
||||
*.iml
|
||||
*.ipr
|
||||
*.sublime*
|
||||
|
||||
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -19,3 +19,9 @@
|
||||
[submodule "deps/libremidi"]
|
||||
path = deps/libremidi
|
||||
url = https://github.com/jcelerier/libremidi.git
|
||||
[submodule "deps/cpp-httplib"]
|
||||
path = deps/cpp-httplib
|
||||
url = https://github.com/yhirose/cpp-httplib.git
|
||||
[submodule "deps/json"]
|
||||
path = deps/json
|
||||
url = https://github.com/nlohmann/json.git
|
||||
|
||||
@@ -93,8 +93,12 @@ target_sources(
|
||||
${LIB_NAME}
|
||||
PRIVATE src/macro-core/macro-action-audio.cpp
|
||||
src/macro-core/macro-action-audio.hpp
|
||||
src/macro-core/macro-action-clipboard.cpp
|
||||
src/macro-core/macro-action-clipboard.hpp
|
||||
src/macro-core/macro-action-edit.cpp
|
||||
src/macro-core/macro-action-edit.hpp
|
||||
src/macro-core/macro-action-factory.cpp
|
||||
src/macro-core/macro-action-factory.hpp
|
||||
src/macro-core/macro-action-file.cpp
|
||||
src/macro-core/macro-action-file.hpp
|
||||
src/macro-core/macro-action-filter.cpp
|
||||
@@ -171,6 +175,8 @@ target_sources(
|
||||
src/macro-core/macro-condition-display.hpp
|
||||
src/macro-core/macro-condition-edit.cpp
|
||||
src/macro-core/macro-condition-edit.hpp
|
||||
src/macro-core/macro-condition-factory.cpp
|
||||
src/macro-core/macro-condition-factory.hpp
|
||||
src/macro-core/macro-condition-file.cpp
|
||||
src/macro-core/macro-condition-file.hpp
|
||||
src/macro-core/macro-condition-filter.cpp
|
||||
@@ -213,6 +219,8 @@ target_sources(
|
||||
src/macro-core/macro-condition-streaming.hpp
|
||||
src/macro-core/macro-condition-studio-mode.cpp
|
||||
src/macro-core/macro-condition-studio-mode.hpp
|
||||
src/macro-core/macro-condition-tempvar.cpp
|
||||
src/macro-core/macro-condition-tempvar.hpp
|
||||
src/macro-core/macro-condition-timer.cpp
|
||||
src/macro-core/macro-condition-timer.hpp
|
||||
src/macro-core/macro-condition-transition.cpp
|
||||
@@ -229,6 +237,8 @@ target_sources(
|
||||
src/macro-core/macro-condition.hpp
|
||||
src/macro-core/macro-dock.cpp
|
||||
src/macro-core/macro-dock.hpp
|
||||
src/macro-core/macro-helpers.cpp
|
||||
src/macro-core/macro-helpers.hpp
|
||||
src/macro-core/macro-properties.cpp
|
||||
src/macro-core/macro-properties.hpp
|
||||
src/macro-core/macro-ref.cpp
|
||||
@@ -252,8 +262,11 @@ target_sources(
|
||||
src/utils/connection-manager.hpp
|
||||
src/utils/curl-helper.cpp
|
||||
src/utils/curl-helper.hpp
|
||||
src/utils/duration.cpp
|
||||
src/utils/duration.hpp
|
||||
src/utils/duration-control.cpp
|
||||
src/utils/duration-control.hpp
|
||||
src/utils/export-symbol-helper.hpp
|
||||
src/utils/item-selection-helpers.cpp
|
||||
src/utils/item-selection-helpers.hpp
|
||||
src/utils/log-helper.hpp
|
||||
@@ -267,6 +280,8 @@ target_sources(
|
||||
src/utils/macro-export-import-dialog.hpp
|
||||
src/utils/macro-list.cpp
|
||||
src/utils/macro-list.hpp
|
||||
src/utils/macro-run-button.cpp
|
||||
src/utils/macro-run-button.hpp
|
||||
src/utils/macro-segment-selection.cpp
|
||||
src/utils/macro-segment-selection.hpp
|
||||
src/utils/math-helpers.cpp
|
||||
@@ -282,6 +297,8 @@ target_sources(
|
||||
src/utils/obs-module-helper.hpp
|
||||
src/utils/osc-helpers.cpp
|
||||
src/utils/osc-helpers.hpp
|
||||
src/utils/plugin-state-helpers.cpp
|
||||
src/utils/plugin-state-helpers.hpp
|
||||
src/utils/priority-helper.cpp
|
||||
src/utils/priority-helper.hpp
|
||||
src/utils/process-config.cpp
|
||||
@@ -304,14 +321,18 @@ target_sources(
|
||||
src/utils/slider-spinbox.hpp
|
||||
src/utils/source-selection.cpp
|
||||
src/utils/source-selection.hpp
|
||||
src/utils/source-setting.cpp
|
||||
src/utils/source-setting.hpp
|
||||
src/utils/string-list.cpp
|
||||
src/utils/string-list.hpp
|
||||
src/utils/striped-frame.cpp
|
||||
src/utils/striped-frame.hpp
|
||||
src/utils/switch-button.cpp
|
||||
src/utils/switch-button.hpp
|
||||
src/utils/sync-helper.cpp
|
||||
src/utils/sync-helper.hpp
|
||||
src/utils/sync-helpers.cpp
|
||||
src/utils/sync-helpers.hpp
|
||||
src/utils/temp-variable.cpp
|
||||
src/utils/temp-variable.hpp
|
||||
src/utils/transition-selection.cpp
|
||||
src/utils/transition-selection.hpp
|
||||
src/utils/utility.cpp
|
||||
@@ -375,6 +396,14 @@ target_include_directories(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/deps/obs-websocket/lib"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/deps/exprtk")
|
||||
|
||||
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/deps/json/CMakeLists.txt")
|
||||
add_subdirectory(deps/json)
|
||||
else()
|
||||
find_package(nlohmann_json REQUIRED)
|
||||
endif()
|
||||
target_link_libraries(${LIB_NAME} PUBLIC nlohmann_json::nlohmann_json)
|
||||
target_compile_definitions(${LIB_NAME} PRIVATE ADVSS_EXPORT_SYMBOLS=1)
|
||||
|
||||
# --- End of section ---
|
||||
|
||||
# --- Windows-specific build settings and tasks ---
|
||||
@@ -441,27 +470,24 @@ else()
|
||||
|
||||
find_path(PROCPS_INCLUDE_DIR NAMES proc/procps.h)
|
||||
find_path(PROCPS2_INCLUDE_DIR NAMES libproc2/pids.h)
|
||||
find_library(PROCPS_LIBRARY NAMES procps)
|
||||
find_library(PROCPS2_LIBRARY NAMES proc2)
|
||||
if(PROCPS_INCLUDE_DIR AND PROCPS_LIBRARY)
|
||||
if(PROCPS_INCLUDE_DIR)
|
||||
message(STATUS "${PROJECT_NAME} using procps")
|
||||
set(PROC_INCLUDE_DIR "${PROCPS_INCLUDE_DIR}")
|
||||
set(PROC_LIBRARY "${PROCPS_LIBRARY}")
|
||||
target_compile_definitions(${LIB_NAME} PRIVATE USE_PROCPS)
|
||||
elseif(PROCPS2_INCLUDE_DIR AND PROCPS2_LIBRARY)
|
||||
target_compile_definitions(${LIB_NAME} PRIVATE PROCPS_AVAILABLE)
|
||||
set(PROCESS_CONDITION_SUPPORTED 1)
|
||||
endif()
|
||||
if(PROCPS2_INCLUDE_DIR)
|
||||
message(STATUS "${PROJECT_NAME} using libproc2")
|
||||
set(PROC_INCLUDE_DIR "${PROCPS2_INCLUDE_DIR}")
|
||||
set(PROC_LIBRARY "${PROCPS2_LIBRARY}")
|
||||
else()
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"found neither procps nor libproc2!
|
||||
please either set ...
|
||||
PROCPS_INCLUDE_DIR and PROCPS_LIBRARY
|
||||
... or ...
|
||||
PROCPS2_INCLUDE_DIR and PROCPS2_LIBRARY")
|
||||
target_compile_definitions(${LIB_NAME} PRIVATE PROCPS2_AVAILABLE)
|
||||
set(PROCESS_CONDITION_SUPPORTED 1)
|
||||
endif()
|
||||
if(NOT DEFINED PROCESS_CONDITION_SUPPORTED)
|
||||
message(
|
||||
WARNING
|
||||
"found neither procps nor libproc2! Process condition will not be functional!"
|
||||
)
|
||||
endif()
|
||||
target_link_libraries(${LIB_NAME} PRIVATE "${PROC_LIBRARY}")
|
||||
target_include_directories(${LIB_NAME} PRIVATE "${PROC_INCLUDE_DIR}")
|
||||
|
||||
find_package(CURL)
|
||||
|
||||
@@ -146,23 +146,19 @@ AdvSceneSwitcher.condition.scene.previousSceneTransitionBehaviour="Während des
|
||||
AdvSceneSwitcher.condition.scene.entry.line1="{{sceneType}}{{scenes}}{{pattern}}"
|
||||
AdvSceneSwitcher.condition.scene.entry.line2="{{useTransitionTargetScene}}"
|
||||
AdvSceneSwitcher.condition.window="Fenster"
|
||||
AdvSceneSwitcher.condition.window.entry.line1="{{windows}} existiert und ..."
|
||||
AdvSceneSwitcher.condition.window.entry.line2="... ist {{fullscreen}} Vollbild {{maximized}} Maximiert {{focused}} Fokusiert {{windowFocusChanged}} Vordergrundfenster geändert"
|
||||
AdvSceneSwitcher.condition.window.entry.line3="Aktuelles Vordergrundfenster: {{focusWindow}}"
|
||||
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.remote="Entfernte Datei"
|
||||
AdvSceneSwitcher.condition.file.local="Lokale Datei"
|
||||
AdvSceneSwitcher.condition.file.entry.line1="{{fileType}}{{filePath}}{{conditions}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line1="{{fileType}}{{filePath}}{{conditions}}{{useRegex}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line3="{{useRegex}} {{checkModificationDate}} {{checkFileContent}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFileContent}}"
|
||||
AdvSceneSwitcher.condition.media="Medien"
|
||||
AdvSceneSwitcher.condition.media.source="Quelle"
|
||||
AdvSceneSwitcher.condition.media.anyOnScene="Beliebige Medienquelle in"
|
||||
AdvSceneSwitcher.condition.media.allOnScene="Alle Medienquellen in"
|
||||
AdvSceneSwitcher.condition.media.matchOnChange="Nur bei Änderung übereinstimmen (Hinweis: Diese Option wird in einer zukünftigen Version entfernt werden - bitte stattdessen Dauer-Modifikatoren verwenden)"
|
||||
AdvSceneSwitcher.condition.media.inconsistencyInfo="Leider verhalten sich nicht alle Medien-Quell-Typen gleich (z.B. Medien-Quelle vs. VLC-Video-Quelle \"Gestoppt\"-Status).\nBitte experimentieren, was in eurem Setup funktioniert!"
|
||||
AdvSceneSwitcher.condition.media.entry="{{sourceTypes}}{{mediaSources}}{{scenes}}Status ist{{states}}und{{timeRestrictions}}{{time}}"
|
||||
AdvSceneSwitcher.condition.video="Video"
|
||||
@@ -224,9 +220,8 @@ AdvSceneSwitcher.condition.record="Aufnahme"
|
||||
AdvSceneSwitcher.condition.record.state.start="Aufnahme läuft"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Aufnahme pausiert"
|
||||
AdvSceneSwitcher.condition.record.state.stop="Aufnahme gestoppt"
|
||||
AdvSceneSwitcher.condition.record.entry="{{recordState}}"
|
||||
AdvSceneSwitcher.condition.process="Prozess"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}} läuft {{focused}} und ist fokusiert"
|
||||
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}}"
|
||||
@@ -328,7 +323,9 @@ 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.entry.line1="Auf{{scenes}}{{sources}}passt zur Transformation"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line1="Auf{{scenes}}{{sources}}{{types}}"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.type.matches="entspricht Transformation"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.type.changed="hat sich geändert"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line2="{{settings}}"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line3="{{regex}} {{getSettings}}"
|
||||
AdvSceneSwitcher.condition.transition="Übergang"
|
||||
@@ -392,12 +389,11 @@ AdvSceneSwitcher.condition.variable.type.valueChanged="Wert verändert"
|
||||
AdvSceneSwitcher.condition.variable.type.equalsVariable="entspricht Variable"
|
||||
AdvSceneSwitcher.condition.variable.type.lessThanVariable="ist kleiner als die Variable"
|
||||
AdvSceneSwitcher.condition.variable.type.greaterThanVariable="ist größer als die Variable"
|
||||
AdvSceneSwitcher.condition.variable.entry="{{variables}}{{conditions}}{{strValue}}{{numValue}}{{variables2}}"
|
||||
|
||||
; Macro Actions
|
||||
AdvSceneSwitcher.action.switchScene="Szene wechseln"
|
||||
AdvSceneSwitcher.action.scene.entry="Wechsle zu Szene{{scenes}}mittels{{transitions}}mit einer Dauer von{{duration}}Sekunden"
|
||||
AdvSceneSwitcher.action.scene.entry.noDuration="Wechsle zu Szene{{scenes}}mittels{{transitions}}"
|
||||
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"
|
||||
@@ -440,11 +436,6 @@ 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.run.arguments="Argumente:"
|
||||
AdvSceneSwitcher.action.run.addArgument="Argument hinzufügen"
|
||||
AdvSceneSwitcher.action.run.addArgumentDescription="Neues Argument hinzufügen:"
|
||||
AdvSceneSwitcher.action.run.entry="Ausführen {{filePath}}"
|
||||
AdvSceneSwitcher.action.run.entry.workingDirectory="Arbeitsverzeichnis:{{workingDirectory}}"
|
||||
AdvSceneSwitcher.action.sceneVisibility="Sichtbarkeit von Szenenelementen"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.show="Anzeigen"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.hide="Verstecken"
|
||||
@@ -476,8 +467,7 @@ AdvSceneSwitcher.action.media.type.stop="Stoppen"
|
||||
AdvSceneSwitcher.action.media.type.restart="Neu starten"
|
||||
AdvSceneSwitcher.action.media.type.next="Nächste"
|
||||
AdvSceneSwitcher.action.media.type.previous="Vorherige"
|
||||
AdvSceneSwitcher.action.media.type.seek="Suche nach"
|
||||
AdvSceneSwitcher.action.media.entry="{{actions}}{{duration}}{{mediaSources}}"
|
||||
AdvSceneSwitcher.action.media.type.seek.duration="Suche nach"
|
||||
AdvSceneSwitcher.action.macro="Makro"
|
||||
AdvSceneSwitcher.action.macro.type.pause="Pausieren"
|
||||
AdvSceneSwitcher.action.macro.type.unpause="Nicht mehr pausieren"
|
||||
@@ -506,7 +496,6 @@ AdvSceneSwitcher.action.hotkey.leftMeta="Linke Meta-Taste"
|
||||
AdvSceneSwitcher.action.hotkey.rightMeta="Rechte Meta-Taste"
|
||||
AdvSceneSwitcher.action.hotkey.onlyOBS="Tastendruck nur an OBS senden"
|
||||
AdvSceneSwitcher.action.hotkey.disabled="Globale Tastendrücke können nicht simuliert werden - die Funktionalität beschränkt sich auf das Senden von Tastendrücken an OBS!"
|
||||
AdvSceneSwitcher.action.hotkey.entry="Drücke {{keys}} für {{duration}}"
|
||||
AdvSceneSwitcher.action.sceneOrder="Reihenfolge der Szenenelemente"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveUp="Nach oben verschieben"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveDown="Nach unten verschieben"
|
||||
@@ -567,8 +556,6 @@ AdvSceneSwitcher.action.sequence.continueFrom="Weiter mit ausgewähltem Element"
|
||||
AdvSceneSwitcher.action.websocket="Websocket"
|
||||
AdvSceneSwitcher.action.websocket.type.request="Anfrage"
|
||||
AdvSceneSwitcher.action.websocket.type.event="Ereignis"
|
||||
AdvSceneSwitcher.action.websocket.entry.request="Szenenwechsler {{type}} via {{connection}} senden"
|
||||
AdvSceneSwitcher.action.websocket.entry.event="Szenenwechsler {{type}} an verbundene Clients senden"
|
||||
AdvSceneSwitcher.action.http="HTTP"
|
||||
AdvSceneSwitcher.action.http.type.get="GET"
|
||||
AdvSceneSwitcher.action.http.type.post="POST"
|
||||
@@ -586,7 +573,6 @@ AdvSceneSwitcher.action.variable.invalidSelection="Ungültige Auswahl!"
|
||||
AdvSceneSwitcher.action.variable.actionNoVariableSupport="Das Abrufen von Variablenwerten aus %1 Aktionen wird nicht unterstützt!"
|
||||
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="Das Abrufen von Variablenwerten aus %1 Bedingungen wird nicht unterstützt!"
|
||||
AdvSceneSwitcher.action.variable.currentSegmentValue="Aktueller Wert:"
|
||||
AdvSceneSwitcher.action.variable.entry="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}"
|
||||
|
||||
|
||||
; Transition Tab
|
||||
@@ -724,7 +710,7 @@ AdvSceneSwitcher.sceneSequenceTab.loadFail="Laden der Einstellungen ist fehlgesc
|
||||
AdvSceneSwitcher.sceneSequenceTab.loadSuccess="Laden der Einstellungen war erfolgreich!"
|
||||
AdvSceneSwitcher.sceneSequenceTab.fileType="Text Dateien (*.txt)"
|
||||
AdvSceneSwitcher.sceneSequenceTab.interruptible="kann unterbrochen werden"
|
||||
AdvSceneSwitcher.sceneSequenceTab.interruptibleHint="Andere Szenenwechselmethoden können diese Sequenz unterbrechen"
|
||||
AdvSceneSwitcher.sceneSequenceTab.interruptibleHint="Andere Szenenwechselmethoden können diese Sequenz unterbrechen"
|
||||
AdvSceneSwitcher.sceneSequenceTab.entry="Wenn {{startScenes}} aktiv ist wechsle zu {{scenes}} nach {{delay}} mit {{transitions}} {{interruptible}}"
|
||||
AdvSceneSwitcher.sceneSequenceTab.extendEdit="Szenenfolge erweitern"
|
||||
AdvSceneSwitcher.sceneSequenceTab.extendEntry="Nach {{delay}} wechsle zu {{scenes}} mit {{transitions}}"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -41,17 +41,17 @@ AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Exportar los a
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Importar los ajustes para Advanced Scene Switcher ..."
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Archivos de texto (*.txt)"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="La importacion la configuracion de escenas fallo"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Configuración de escenas importada correctamente"
|
||||
AdvSceneSwitcher.generalTab.priority.fileContent="Contenido del archivo"
|
||||
AdvSceneSwitcher.generalTab.priority.sceneSequence="Secuencia de escenas"
|
||||
AdvSceneSwitcher.generalTab.priority.idleDetection="Detección de inactivos"
|
||||
AdvSceneSwitcher.generalTab.priority.executable="Ejecutable"
|
||||
AdvSceneSwitcher.generalTab.priority.screenRegion="Región de pantalla"
|
||||
AdvSceneSwitcher.generalTab.priority.windowTitle="Título de la ventana"
|
||||
AdvSceneSwitcher.generalTab.priority.media="Medios"
|
||||
AdvSceneSwitcher.generalTab.priority.time="Tiempo"
|
||||
AdvSceneSwitcher.generalTab.priority.audio="Audio"
|
||||
AdvSceneSwitcher.generalTab.priority.video="Video"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Configuración de escenas importada correctamente"
|
||||
AdvSceneSwitcher.generalTab.priority.fileContent="Contenido del archivo"
|
||||
AdvSceneSwitcher.generalTab.priority.sceneSequence="Secuencia de escenas"
|
||||
AdvSceneSwitcher.generalTab.priority.idleDetection="Detección de inactivos"
|
||||
AdvSceneSwitcher.generalTab.priority.executable="Ejecutable"
|
||||
AdvSceneSwitcher.generalTab.priority.screenRegion="Región de pantalla"
|
||||
AdvSceneSwitcher.generalTab.priority.windowTitle="Título de la ventana"
|
||||
AdvSceneSwitcher.generalTab.priority.media="Medios"
|
||||
AdvSceneSwitcher.generalTab.priority.time="Tiempo"
|
||||
AdvSceneSwitcher.generalTab.priority.audio="Audio"
|
||||
AdvSceneSwitcher.generalTab.priority.video="Video"
|
||||
AdvSceneSwitcher.generalTab.priority.macro="Macro"
|
||||
AdvSceneSwitcher.generalTab.setTransitionBy="Al cambiar las transiciones:"
|
||||
AdvSceneSwitcher.generalTab.transitionOverride="Establecer anulaciones de transición"
|
||||
@@ -61,38 +61,38 @@ AdvSceneSwitcher.generalTab.transitionBehaviorSelectionError="Al menos una opci
|
||||
; Macro Tab
|
||||
AdvSceneSwitcher.macroTab.title="Macro"
|
||||
AdvSceneSwitcher.macroTab.macros="Macros"
|
||||
AdvSceneSwitcher.macroTab.priorityWarning="Nota: Se recomienda configurar las macros para que sean la funcionalidad de máxima prioridad.\nEsta configuración se puede cambiar en la ficha General."
|
||||
AdvSceneSwitcher.macroTab.help="Las macros le permiten ejecutar una cadena de acciones en función de varias condiciones.\n\nHaga clic en el símbolo más resaltado para agregar una nueva macro."
|
||||
AdvSceneSwitcher.macroTab.editConditionHelp="Esta sección le permite definir las condiciones de la macro.\n\nSeleccione una macro existente o agregue una nueva a la izquierda.\nLuego haga clic en el botón más a continuación para agregar una nueva condición."
|
||||
AdvSceneSwitcher.macroTab.priorityWarning="Nota: Se recomienda configurar las macros para que sean la funcionalidad de máxima prioridad.\nEsta configuración se puede cambiar en la ficha General."
|
||||
AdvSceneSwitcher.macroTab.help="Las macros le permiten ejecutar una cadena de acciones en función de varias condiciones.\n\nHaga clic en el símbolo más resaltado para agregar una nueva macro."
|
||||
AdvSceneSwitcher.macroTab.editConditionHelp="Esta sección le permite definir las condiciones de la macro.\n\nSeleccione una macro existente o agregue una nueva a la izquierda.\nLuego haga clic en el botón más a continuación para agregar una nueva condición."
|
||||
AdvSceneSwitcher.macroTab.editActionHelp="Esta sección le permite definir acciones de la macro.\n\nSeleccione una macro existente o agregue una nueva a la izquierda.\nLuego haga clic en el botón más a continuación para agregar una nueva acción"
|
||||
AdvSceneSwitcher.macroTab.edit="Editar macro"
|
||||
AdvSceneSwitcher.macroTab.edit.logic="Tipo de lógica:"
|
||||
AdvSceneSwitcher.macroTab.edit.condition="Tipo de condición:"
|
||||
AdvSceneSwitcher.macroTab.edit.logic="Tipo de lógica:"
|
||||
AdvSceneSwitcher.macroTab.edit.condition="Tipo de condición:"
|
||||
AdvSceneSwitcher.macroTab.edit.action="Tipo de acción:"
|
||||
AdvSceneSwitcher.macroTab.add="Agregar nueva macro"
|
||||
AdvSceneSwitcher.macroTab.name="Nombre:"
|
||||
AdvSceneSwitcher.macroTab.run="Ejecutar macro"
|
||||
AdvSceneSwitcher.macroTab.runFail="Error al ejecutar \"%1\" si se ha producido un error en una de las acciones o si la macro ya se está ejecutando."
|
||||
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.exists="El nombre de la macro ya existe"
|
||||
AdvSceneSwitcher.macroTab.copy="Crear copia"
|
||||
AdvSceneSwitcher.macroTab.expandAll="Expandir todo"
|
||||
AdvSceneSwitcher.macroTab.collapseAll="Contraer todo"
|
||||
AdvSceneSwitcher.macroTab.maximize="Maximizar"
|
||||
AdvSceneSwitcher.macroTab.add="Agregar nueva macro"
|
||||
AdvSceneSwitcher.macroTab.name="Nombre:"
|
||||
AdvSceneSwitcher.macroTab.run="Ejecutar macro"
|
||||
AdvSceneSwitcher.macroTab.runFail="Error al ejecutar \"%1\" si se ha producido un error en una de las acciones o si la macro ya se está ejecutando."
|
||||
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.exists="El nombre de la macro ya existe"
|
||||
AdvSceneSwitcher.macroTab.copy="Crear copia"
|
||||
AdvSceneSwitcher.macroTab.expandAll="Expandir todo"
|
||||
AdvSceneSwitcher.macroTab.collapseAll="Contraer todo"
|
||||
AdvSceneSwitcher.macroTab.maximize="Maximizar"
|
||||
AdvSceneSwitcher.macroTab.minimize="Minimizar"
|
||||
AdvSceneSwitcher.macroTab.highlightExecutedMacros="Resaltar macros ejecutadas recientemente"
|
||||
AdvSceneSwitcher.macroTab.highlightTrueConditions="Resaltar condiciones de la macro seleccionada, que se evaluaron como verdaderas recientemente"
|
||||
AdvSceneSwitcher.macroTab.highlightPerformedActions="Resaltar acciones realizadas recientemente de la macro seleccionada actualmente"
|
||||
AdvSceneSwitcher.macroTab.highlightExecutedMacros="Resaltar macros ejecutadas recientemente"
|
||||
AdvSceneSwitcher.macroTab.highlightTrueConditions="Resaltar condiciones de la macro seleccionada, que se evaluaron como verdaderas recientemente"
|
||||
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"
|
||||
AdvSceneSwitcher.logic.orNot="O no"
|
||||
AdvSceneSwitcher.logic.rootNone="Si"
|
||||
; Lógica de macros
|
||||
AdvSceneSwitcher.logic.none="Omitir entrada"
|
||||
AdvSceneSwitcher.logic.and="Y"
|
||||
AdvSceneSwitcher.logic.or="O"
|
||||
AdvSceneSwitcher.logic.andNot="Y no"
|
||||
AdvSceneSwitcher.logic.orNot="O no"
|
||||
AdvSceneSwitcher.logic.rootNone="Si"
|
||||
AdvSceneSwitcher.logic.not="Si no"
|
||||
|
||||
; Macro Conditions
|
||||
@@ -122,16 +122,13 @@ AdvSceneSwitcher.condition.scene.previousSceneTransitionBehaviour="Durante la tr
|
||||
AdvSceneSwitcher.condition.scene.entry.line1="{{sceneType}}{{scenes}}{{pattern}}"
|
||||
AdvSceneSwitcher.condition.scene.entry.line2="{{useTransitionTargetScene}}"
|
||||
AdvSceneSwitcher.condition.window="Ventana"
|
||||
AdvSceneSwitcher.condition.window.entry.line1="{{windows}} existen y ..."
|
||||
AdvSceneSwitcher.condition.window.entry.line2="... es {{fullscreen}} pantalla completa {{maximized}} maximizada {{focused}} enfocada {{windowFocusChanged}} ventana de primer plano cambiada"
|
||||
AdvSceneSwitcher.condition.file="Archivo"
|
||||
AdvSceneSwitcher.condition.file.entry.line1="Contenido de{{fileType}}{{filePath}}{{conditions}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line1="Contenido de{{fileType}}{{filePath}}{{conditions}}{{useRegex}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line3="{{useRegex}} {{checkModificationDate}} {{checkFileContent}}"
|
||||
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"
|
||||
AdvSceneSwitcher.condition.media.matchOnChange="Solo coincidir con el cambio (Nota: esta opción se eliminará en una versión futura; use modificadores de duración en su lugar)"
|
||||
AdvSceneSwitcher.condition.media.inconsistencyInfo="Desafortunadamente, no todos los tipos de fuentes de medios se comportan de la misma manera (p. ej., fuente de medios frente a estado \"Detenido\" de fuente de video VLC).\n¡Así que experimente lo que funciona para su configuración!"
|
||||
AdvSceneSwitcher.condition.media.entry="El estado de{{sourceTypes}}{{mediaSources}}{{scenes}}es{{states}}y{{timeRestrictions}}{{time}}"
|
||||
AdvSceneSwitcher.condition.video="Video"
|
||||
@@ -184,9 +181,8 @@ AdvSceneSwitcher.condition.record="Grabación"
|
||||
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.record.entry="{{recordState}}"
|
||||
AdvSceneSwitcher.condition.process="Proceso"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}} 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"
|
||||
@@ -277,7 +273,8 @@ AdvSceneSwitcher.condition.date.entry.nextMatchDate="Próxima coincidencia en: %
|
||||
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.entry.line1="En{{scenes}}{{sources}}coincide con la transformación"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line1="En{{scenes}}{{sources}}{{types}}"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.type.matches="coincide con la transformación"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line2="{{settings}}"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line3="{{regex}} {{getSettings}}"
|
||||
AdvSceneSwitcher.condition.transition="Transición"
|
||||
@@ -324,8 +321,8 @@ AdvSceneSwitcher.condition.stats.dockHint="Puede abrir el panel de \"Estadístic
|
||||
AdvSceneSwitcher.condition.stats.entry="{{stats}} esta {{condition}} {{value}}"
|
||||
|
||||
; Macro Actions
|
||||
AdvSceneSwitcher.action.switchScene="Cambiar escena"
|
||||
AdvSceneSwitcher.action.scene.entry="Cambiar a la escena {{scenes}} usando {{transitions}} con una duración de {{duration}} segundos"
|
||||
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"
|
||||
@@ -362,10 +359,6 @@ 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.run.arguments="Argumentos:"
|
||||
AdvSceneSwitcher.action.run.addArgument="Agregar argumento"
|
||||
AdvSceneSwitcher.action.run.addArgumentDescription="Añadir nuevo argumento:"
|
||||
AdvSceneSwitcher.action.run.entry="Ejecutar {{filePath}}"
|
||||
AdvSceneSwitcher.action.sceneVisibility="Visibilidad del elemento de escena"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.show="Mostrar"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.hide="Ocultar"
|
||||
@@ -392,8 +385,7 @@ AdvSceneSwitcher.action.media.type.stop="Detener"
|
||||
AdvSceneSwitcher.action.media.type.restart="Reiniciar"
|
||||
AdvSceneSwitcher.action.media.type.next="Siguiente"
|
||||
AdvSceneSwitcher.action.media.type.previous="Anterior"
|
||||
AdvSceneSwitcher.action.media.type.seek="Buscar"
|
||||
AdvSceneSwitcher.action.media.entry="{{actions}}{{duration}}{{mediaSources}}"
|
||||
AdvSceneSwitcher.action.media.type.seek.duration="Buscar"
|
||||
AdvSceneSwitcher.action.macro="Macro"
|
||||
AdvSceneSwitcher.action.macro.type.pause="Pausa"
|
||||
AdvSceneSwitcher.action.macro.type.unpause="Reanudar"
|
||||
@@ -422,7 +414,6 @@ AdvSceneSwitcher.action.hotkey.leftMeta="Meta izquierda"
|
||||
AdvSceneSwitcher.action.hotkey.rightMeta="Meta derecho"
|
||||
AdvSceneSwitcher.action.hotkey.onlyOBS="Enviar pulsación de tecla solo a OBS"
|
||||
AdvSceneSwitcher.action.hotkey.disabled="No se puede simular la pulsación de teclas: ¡funcionalidad desactivada!"
|
||||
AdvSceneSwitcher.action.hotkey.entry="Presione {{keys}} durante {{duration}}"
|
||||
AdvSceneSwitcher.action.sceneOrder="Orden de elementos de escena"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveUp="Mover hacia arriba"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveDown="Mover hacia abajo"
|
||||
@@ -573,7 +564,7 @@ AdvSceneSwitcher.fileTab.help="Esta pestaña te permitirá cambiar escenas autom
|
||||
; Random Tab
|
||||
AdvSceneSwitcher.randomTab.title="Aleatorio"
|
||||
AdvSceneSwitcher.randomTab.randomDisabledWarning="Funcionalidad deshabilitada - para activarla, selecciona \"Si no se cumple ninguna condición de cambio, cambiar a cualquier escena en la pestaña Aleatorio\" en la pestaña General"
|
||||
AdvSceneSwitcher.randomTab.entry="Si no se cumple ninguna condición de cambio, cambiar a {{scenes}} usando {{transitions}} después de {{delay}}"
|
||||
AdvSceneSwitcher.randomTab.entry="Si no se cumple ninguna condición de cambio, cambiar a {{scenes}} usando {{transitions}} después de {{delay}}"
|
||||
AdvSceneSwitcher.randomTab.help="El selector de escenas elegirá aleatoriamente una entrada en esta pestaña para cambiar durante el tiempo configurado.\nTen en cuenta que la misma entrada no se elegirá dos veces seguidas.\n\nHaz clic en el símbolo más resaltado para continuar."
|
||||
|
||||
; Time Tab
|
||||
|
||||
1199
data/locale/fr-FR.ini
Normal file
1199
data/locale/fr-FR.ini
Normal file
File diff suppressed because it is too large
Load Diff
@@ -86,10 +86,9 @@ AdvSceneSwitcher.condition.scene="Сцена"
|
||||
AdvSceneSwitcher.condition.scene.type.current="Текущий"
|
||||
AdvSceneSwitcher.condition.scene.type.previous="Предыдущий"
|
||||
AdvSceneSwitcher.condition.window="Окно"
|
||||
AdvSceneSwitcher.condition.window.entry.line1="{{windows}} существует и ..."
|
||||
AdvSceneSwitcher.condition.file="Файл"
|
||||
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line3="{{useRegex}} {{checkModificationDate}} {{checkFileContent}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFileContent}}"
|
||||
AdvSceneSwitcher.condition.media="Медиа"
|
||||
AdvSceneSwitcher.condition.video="Видео"
|
||||
AdvSceneSwitcher.condition.video.condition.match="точно соответствует"
|
||||
@@ -108,7 +107,7 @@ AdvSceneSwitcher.condition.record.state.start="Запись запущена"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Запись приостановлена"
|
||||
AdvSceneSwitcher.condition.record.state.stop="Запись остановлена"
|
||||
AdvSceneSwitcher.condition.process="Процесс"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}} запущен {{focused}} и сфокусирован"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}запущен{{focused}}и сфокусирован"
|
||||
AdvSceneSwitcher.condition.idle="Простой"
|
||||
AdvSceneSwitcher.condition.idle.entry="Не было ни клавиатуры, ни мыши в течении{{duration}}"
|
||||
AdvSceneSwitcher.condition.pluginState="Состояние плагина"
|
||||
@@ -116,8 +115,8 @@ AdvSceneSwitcher.condition.pluginState.state.sceneSwitched="Автоматиче
|
||||
AdvSceneSwitcher.condition.pluginState.entry="{{condition}}"
|
||||
|
||||
; Macro Actions
|
||||
AdvSceneSwitcher.action.switchScene="Переключить сцену"
|
||||
AdvSceneSwitcher.action.scene.entry="Перейти к сцене {{scenes}} используя {{transitions}} с продолжительностью {{duration}} секунд"
|
||||
AdvSceneSwitcher.action.scene="Переключить сцену"
|
||||
AdvSceneSwitcher.action.scene.entry="Перейти к сцене{{sceneTypes}}{{scenes}}используя{{transitions}}с продолжительностью{{duration}}секунд"
|
||||
AdvSceneSwitcher.action.wait="Подождать"
|
||||
AdvSceneSwitcher.action.wait.type.fixed="фиксированный"
|
||||
AdvSceneSwitcher.action.wait.type.random="случайный"
|
||||
|
||||
@@ -112,16 +112,13 @@ AdvSceneSwitcher.condition.scene.currentSceneTransitionBehaviour="Geçiş hedefi
|
||||
AdvSceneSwitcher.condition.scene.entry.line1="{{sceneType}}{{scenes}}{{pattern}}"
|
||||
AdvSceneSwitcher.condition.scene.entry.line2="{{useTransitionTargetScene}}"
|
||||
AdvSceneSwitcher.condition.window="Pencere"
|
||||
AdvSceneSwitcher.condition.window.entry.line1="{{windows}} Varolan ve ..."
|
||||
AdvSceneSwitcher.condition.window.entry.line2="... {{fullscreen}} Tam ekran {{maximized}} büyütüldü {{focused}} odaklanıldı {{windowFocusChanged}} ön plan penceresi değişikliği"
|
||||
AdvSceneSwitcher.condition.file="Dosya"
|
||||
AdvSceneSwitcher.condition.file.entry.line1="İçerik{{fileType}}{{filePath}}{{conditions}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line1="İçerik{{fileType}}{{filePath}}{{conditions}}{{useRegex}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line3="{{useRegex}} {{checkModificationDate}} {{checkFileContent}}"
|
||||
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ı "
|
||||
AdvSceneSwitcher.condition.media.matchOnChange="Yalnızca değişiklikle eşleştirin (Not: Bu seçenek gelecekteki bir sürümde kaldırılacaktır - lütfen bunun yerine zaman kısıtlamalarını kullanın)"
|
||||
AdvSceneSwitcher.condition.media.entry="{{sourceTypes}}{{mediaSources}}{{scenes}}durumu{{states}}ve{{timeRestrictions}}{{time}}"
|
||||
AdvSceneSwitcher.condition.video="Video"
|
||||
AdvSceneSwitcher.condition.video.condition.match="Tam olarak eşleşir"
|
||||
@@ -161,9 +158,8 @@ AdvSceneSwitcher.condition.record="Kayıt"
|
||||
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.record.entry="{{recordState}}"
|
||||
AdvSceneSwitcher.condition.process="İşlem"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}} ç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"
|
||||
@@ -233,7 +229,8 @@ AdvSceneSwitcher.condition.date.state.before="Önce"
|
||||
AdvSceneSwitcher.condition.date.state.between="Arasında"
|
||||
AdvSceneSwitcher.condition.sceneTransform="Sahne öğesi dönüşümü"
|
||||
AdvSceneSwitcher.condition.sceneTransform.getTransform="Dönüşümü al"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line1="Açık{{scenes}}{{sources}} dönüşümle eşleşir"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line1="Açık{{scenes}}{{sources}}{{types}}"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.type.matches="dönüşümle eşleşir"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line2="{{settings}}"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line3="{{regex}} {{getSettings}}"
|
||||
AdvSceneSwitcher.condition.transition="Geçiş"
|
||||
@@ -261,8 +258,8 @@ AdvSceneSwitcher.condition.openvr.entry.line2="{{controls}}"
|
||||
AdvSceneSwitcher.condition.openvr.entry.line3="HMD mevcut {{xPos}} x {{yPos}} x {{zPos}}"
|
||||
|
||||
; Macro Actions
|
||||
AdvSceneSwitcher.action.switchScene="Sahne Degistirici"
|
||||
AdvSceneSwitcher.action.scene.entry="Sahneyi {{scenes}} kullanarak {{transitions}} süresi olan {{duration}} saniye"
|
||||
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"
|
||||
@@ -292,10 +289,6 @@ 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.run.arguments="Argümanlar:"
|
||||
AdvSceneSwitcher.action.run.addArgument="Argüman ekle"
|
||||
AdvSceneSwitcher.action.run.addArgumentDescription="Yeni Argüman ekle:"
|
||||
AdvSceneSwitcher.action.run.entry="Çalıştır {{filePath}}"
|
||||
AdvSceneSwitcher.action.sceneVisibility="Sahne öğesi görünürlüğü"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.show="Göster"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.hide="Gizle"
|
||||
@@ -322,7 +315,6 @@ AdvSceneSwitcher.action.media.type.stop="Dur"
|
||||
AdvSceneSwitcher.action.media.type.restart="Yeniden Başlat"
|
||||
AdvSceneSwitcher.action.media.type.next="Sonraki"
|
||||
AdvSceneSwitcher.action.media.type.previous="Önceki"
|
||||
AdvSceneSwitcher.action.media.entry="{{actions}}{{duration}}{{mediaSources}}"
|
||||
AdvSceneSwitcher.action.macro="Makro"
|
||||
AdvSceneSwitcher.action.macro.type.pause="Duraklat"
|
||||
AdvSceneSwitcher.action.macro.type.unpause="Duraklatma"
|
||||
@@ -350,7 +342,6 @@ AdvSceneSwitcher.action.hotkey.leftMeta="Sol Meta"
|
||||
AdvSceneSwitcher.action.hotkey.rightMeta="Sağ Meta"
|
||||
AdvSceneSwitcher.action.hotkey.onlyOBS="Tuşa basımı yalnızca OBS'ye gönder"
|
||||
AdvSceneSwitcher.action.hotkey.disabled="Tuşa basma simülasyonu yapılamıyor - işlevsellik devre dışı!"
|
||||
AdvSceneSwitcher.action.hotkey.entry="Bas {{keys}} uygun {{duration}}"
|
||||
AdvSceneSwitcher.action.sceneOrder="Sahne öğesi sırası"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveUp="Yukarı taşı"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveDown="Aşağı indir"
|
||||
|
||||
@@ -178,14 +178,13 @@ AdvSceneSwitcher.condition.file.type.contentChange="内容已更改"
|
||||
AdvSceneSwitcher.condition.file.type.dateChange="修改日期已更改"
|
||||
AdvSceneSwitcher.condition.file.remote="远程文件"
|
||||
AdvSceneSwitcher.condition.file.local="本地文件"
|
||||
AdvSceneSwitcher.condition.file.entry.line1="{{fileType}}{{filePath}}{{conditions}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line1="{{fileType}}{{filePath}}{{conditions}}{{useRegex}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line3="{{useRegex}} {{checkModificationDate}} {{checkFileContent}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFileContent}}"
|
||||
AdvSceneSwitcher.condition.media="媒体"
|
||||
AdvSceneSwitcher.condition.media.source="源"
|
||||
AdvSceneSwitcher.condition.media.anyOnScene="任何媒体源"
|
||||
AdvSceneSwitcher.condition.media.allOnScene="所有媒体源"
|
||||
AdvSceneSwitcher.condition.media.matchOnChange="仅在更改时匹配(注意:此选项将在未来版本中删除-请改用时间限制)"
|
||||
AdvSceneSwitcher.condition.media.inconsistencyInfo="不幸的是,并非所有媒体源类型的行为都相同(例如,媒体源与VLC视频源“停止”状态)。\n所以,请尝试适合您的设置!"
|
||||
AdvSceneSwitcher.condition.media.entry="{{sourceTypes}}{{mediaSources}}{{scenes}} 的状态是 {{states}} 和 {{timeRestrictions}}{{time}}"
|
||||
AdvSceneSwitcher.condition.video="视频"
|
||||
@@ -267,9 +266,8 @@ AdvSceneSwitcher.condition.record="录制"
|
||||
AdvSceneSwitcher.condition.record.state.start="录制运行中"
|
||||
AdvSceneSwitcher.condition.record.state.pause="录制暂停"
|
||||
AdvSceneSwitcher.condition.record.state.stop="录制停止"
|
||||
AdvSceneSwitcher.condition.record.entry="{{recordState}}"
|
||||
AdvSceneSwitcher.condition.process="进程"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}} 是正在运行 {{focused}} 并且是获得焦点"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}是正在运行{{focused}}并且是获得焦点"
|
||||
AdvSceneSwitcher.condition.process.entry.focus="当前焦点进程: {{focusProcess}}"
|
||||
AdvSceneSwitcher.condition.idle="闲置检测"
|
||||
AdvSceneSwitcher.condition.idle.entry="没有键盘或鼠标输入{{duration}}"
|
||||
@@ -371,7 +369,8 @@ AdvSceneSwitcher.condition.date.entry.nextMatchDate="下一次匹配 在: %1"
|
||||
AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}} 重复时,将选定的日期更新为重复日期"
|
||||
AdvSceneSwitcher.condition.sceneTransform="场景项目被改变"
|
||||
AdvSceneSwitcher.condition.sceneTransform.getTransform="内容或者设置被改变了"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line1="在 {{scenes}} {{sources}} 匹配变换"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line1="在 {{scenes}} {{sources}} {{types}}"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.type.matches="匹配变换"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line2="{{settings}}"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line3="{{regex}} {{getSettings}}"
|
||||
AdvSceneSwitcher.condition.transition="转场"
|
||||
@@ -435,7 +434,6 @@ AdvSceneSwitcher.condition.variable.type.valueChanged="值已更改"
|
||||
AdvSceneSwitcher.condition.variable.type.equalsVariable="等于变量"
|
||||
AdvSceneSwitcher.condition.variable.type.lessThanVariable="小于变量"
|
||||
AdvSceneSwitcher.condition.variable.type.greaterThanVariable="大于变量"
|
||||
AdvSceneSwitcher.condition.variable.entry="{{variables}}{{conditions}}{{strValue}}{{numValue}}{{variables2}}"
|
||||
AdvSceneSwitcher.condition.run="运行"
|
||||
AdvSceneSwitcher.condition.run.entry="进程在超时 {{timeout}} 秒之前退出"
|
||||
AdvSceneSwitcher.condition.run.entry.exit="{{checkExitCode}}检查退出代码{{exitCode}}"
|
||||
@@ -448,9 +446,9 @@ AdvSceneSwitcher.condition.display.type.displayCount="连接的显示器的数
|
||||
AdvSceneSwitcher.condition.display.entry="{{conditions}}{{displays}}{{regex}}{{displayCount}}"
|
||||
|
||||
; Macro Actions
|
||||
AdvSceneSwitcher.action.switchScene="切换场景"
|
||||
AdvSceneSwitcher.action.scene.entry="切换场景 {{scenes}} 使用 {{transitions}} 时长 {{duration}} 秒"
|
||||
AdvSceneSwitcher.action.scene.entry.noDuration="切换到场景{{scenes}}使用{{transitions}}"
|
||||
AdvSceneSwitcher.action.scene="切换场景"
|
||||
AdvSceneSwitcher.action.scene.entry="切换场景{{sceneTypes}}{{scenes}}使用{{transitions}}时长{{duration}}秒"
|
||||
AdvSceneSwitcher.action.scene.entry.noDuration="切换到场景{{sceneTypes}}{{scenes}}使用{{transitions}}"
|
||||
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="等待目标场景的过渡完成"
|
||||
AdvSceneSwitcher.action.wait="等待"
|
||||
AdvSceneSwitcher.action.wait.type.fixed="固定数值"
|
||||
@@ -527,8 +525,7 @@ AdvSceneSwitcher.action.media.type.stop="停止"
|
||||
AdvSceneSwitcher.action.media.type.restart="重新启动"
|
||||
AdvSceneSwitcher.action.media.type.next="下一个"
|
||||
AdvSceneSwitcher.action.media.type.previous="上一个"
|
||||
AdvSceneSwitcher.action.media.type.seek="时间轴定位"
|
||||
AdvSceneSwitcher.action.media.entry="{{actions}}{{duration}}{{mediaSources}}"
|
||||
AdvSceneSwitcher.action.media.type.seek.duration="时间轴定位"
|
||||
AdvSceneSwitcher.action.macro="宏"
|
||||
AdvSceneSwitcher.action.macro.type.pause="暂停"
|
||||
AdvSceneSwitcher.action.macro.type.unpause="取消暂停"
|
||||
@@ -559,7 +556,6 @@ AdvSceneSwitcher.action.hotkey.leftMeta="左 Meta"
|
||||
AdvSceneSwitcher.action.hotkey.rightMeta="右 Meta"
|
||||
AdvSceneSwitcher.action.hotkey.onlyOBS="仅向OBS发送按键"
|
||||
AdvSceneSwitcher.action.hotkey.disabled="无法模拟按键-功能已禁用!"
|
||||
AdvSceneSwitcher.action.hotkey.entry="按下 {{keys}} 在 {{duration}} 秒"
|
||||
AdvSceneSwitcher.action.sceneOrder="场景项目顺序"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveUp="上移"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveDown="下移"
|
||||
@@ -624,8 +620,6 @@ AdvSceneSwitcher.action.sequence.continueFrom="继续所选项目"
|
||||
AdvSceneSwitcher.action.websocket="websocket"
|
||||
AdvSceneSwitcher.action.websocket.type.request="request"
|
||||
AdvSceneSwitcher.action.websocket.type.event="event"
|
||||
AdvSceneSwitcher.action.websocket.entry.request="通过{{connection}} 发送场景切换器 {{type}}"
|
||||
AdvSceneSwitcher.action.websocket.entry.event="发送场景切换器 {{type}} 到连接的客户端"
|
||||
AdvSceneSwitcher.action.http="Http"
|
||||
AdvSceneSwitcher.action.http.setHeaders="设置头信息(SET headers)"
|
||||
AdvSceneSwitcher.action.http.headers="头信息(headers):"
|
||||
@@ -655,7 +649,6 @@ AdvSceneSwitcher.action.variable.invalidSelection="无效选择!"
|
||||
AdvSceneSwitcher.action.variable.actionNoVariableSupport="不支持从 %1 个操作获取变量值!"
|
||||
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="不支持从 %1 条件中获取变量值!"
|
||||
AdvSceneSwitcher.action.variable.currentSegmentValue="当前值:"
|
||||
AdvSceneSwitcher.action.variable.entry="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}"
|
||||
AdvSceneSwitcher.action.variable.entry.substringIndex="子字符串开始:{{subStringStart}} 子字符串大小:{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.entry.substringRegex="使用正则表达式为 {{regexMatchIdx}} 匹配的值:"
|
||||
AdvSceneSwitcher.action.variable.entry.findAndReplace="{{findStr}}{{replaceStr}}"
|
||||
|
||||
11
data/res/images/DarkNotEqual.svg
Normal file
11
data/res/images/DarkNotEqual.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0"?>
|
||||
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid meet" version="1.1">
|
||||
<!-- Created with SVG-edit - https://github.com/SVG-Edit/svgedit-->
|
||||
|
||||
<g class="layer">
|
||||
<title>Layer 1</title>
|
||||
<rect fill="#fefefe" height="2.25" id="svg_1" stroke="#fefefe" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" transform="matrix(1, 0, 0, 1, 0, 0)" width="13" x="1.5" y="4"/>
|
||||
<rect fill="#fefefe" height="2.25" id="svg_2" stroke="#fefefe" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" transform="matrix(1, 0, 0, 1, 0, 0)" width="13" x="1.5" y="10"/>
|
||||
<rect fill="#fefefe" height="1" id="svg_4" stroke="#fefefe" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" transform="matrix(0.341951, -0.926734, 0.939718, 0.337226, -1.948, 13.2448)" width="14" x="1" y="7"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 931 B |
8
data/res/images/DarkSearch.svg
Normal file
8
data/res/images/DarkSearch.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="256" height="256" viewBox="0 0 256 256" xml:space="preserve">
|
||||
|
||||
<defs>
|
||||
</defs>
|
||||
<g style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: none; fill-rule: nonzero; opacity: 1;" transform="translate(1.4065934065934016 1.4065934065934016) scale(2.81 2.81)" >
|
||||
<path d="M 87.803 77.194 L 68.212 57.602 c 9.5 -14.422 7.912 -34.054 -4.766 -46.732 c 0 0 -0.001 0 -0.001 0 c -14.495 -14.493 -38.08 -14.494 -52.574 0 c -14.494 14.495 -14.494 38.079 0 52.575 c 7.248 7.247 16.767 10.87 26.287 10.87 c 7.134 0 14.267 -2.035 20.445 -6.104 l 19.591 19.591 C 78.659 89.267 80.579 90 82.498 90 s 3.84 -0.733 5.305 -2.197 C 90.732 84.873 90.732 80.124 87.803 77.194 z M 21.48 52.837 c -8.645 -8.646 -8.645 -22.713 0 -31.358 c 4.323 -4.322 10 -6.483 15.679 -6.483 c 5.678 0 11.356 2.161 15.678 6.483 c 8.644 8.644 8.645 22.707 0.005 31.352 c -0.002 0.002 -0.004 0.003 -0.005 0.005 c -0.002 0.002 -0.003 0.003 -0.004 0.005 C 44.184 61.481 30.123 61.48 21.48 52.837 z" style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: #fefefe; fill-rule: nonzero; opacity: 1;" transform=" matrix(1 0 0 1 0 0) " stroke-linecap="round" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
11
data/res/images/LightNotEqual.svg
Normal file
11
data/res/images/LightNotEqual.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0"?>
|
||||
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid meet" version="1.1">
|
||||
<!-- Created with SVG-edit - https://github.com/SVG-Edit/svgedit-->
|
||||
|
||||
<g class="layer">
|
||||
<title>Layer 1</title>
|
||||
<rect fill="#202020" height="2.25" id="svg_1" stroke="#202020" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" transform="matrix(1, 0, 0, 1, 0, 0)" width="13" x="1.5" y="4"/>
|
||||
<rect fill="#202020" height="2.25" id="svg_2" stroke="#202020" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" transform="matrix(1, 0, 0, 1, 0, 0)" width="13" x="1.5" y="10"/>
|
||||
<rect fill="#202020" height="1" id="svg_4" stroke="#202020" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" transform="matrix(0.341951, -0.926734, 0.939718, 0.337226, -1.948, 13.2448)" width="14" x="1" y="7"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 931 B |
8
data/res/images/LightSearch.svg
Normal file
8
data/res/images/LightSearch.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="256" height="256" viewBox="0 0 256 256" xml:space="preserve">
|
||||
|
||||
<defs>
|
||||
</defs>
|
||||
<g style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: none; fill-rule: nonzero; opacity: 1;" transform="translate(1.4065934065934016 1.4065934065934016) scale(2.81 2.81)" >
|
||||
<path d="M 87.803 77.194 L 68.212 57.602 c 9.5 -14.422 7.912 -34.054 -4.766 -46.732 c 0 0 -0.001 0 -0.001 0 c -14.495 -14.493 -38.08 -14.494 -52.574 0 c -14.494 14.495 -14.494 38.079 0 52.575 c 7.248 7.247 16.767 10.87 26.287 10.87 c 7.134 0 14.267 -2.035 20.445 -6.104 l 19.591 19.591 C 78.659 89.267 80.579 90 82.498 90 s 3.84 -0.733 5.305 -2.197 C 90.732 84.873 90.732 80.124 87.803 77.194 z M 21.48 52.837 c -8.645 -8.646 -8.645 -22.713 0 -31.358 c 4.323 -4.322 10 -6.483 15.679 -6.483 c 5.678 0 11.356 2.161 15.678 6.483 c 8.644 8.644 8.645 22.707 0.005 31.352 c -0.002 0.002 -0.004 0.003 -0.005 0.005 c -0.002 0.002 -0.003 0.003 -0.004 0.005 C 44.184 61.481 30.123 61.48 21.48 52.837 z" style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: #202020; fill-rule: nonzero; opacity: 1;" transform=" matrix(1 0 0 1 0 0) " stroke-linecap="round" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
2
deps/asio
vendored
2
deps/asio
vendored
Submodule deps/asio updated: b73dc1d2c0...c465349fa5
1
deps/cpp-httplib
vendored
Submodule
1
deps/cpp-httplib
vendored
Submodule
Submodule deps/cpp-httplib added at c7ed1796a7
1
deps/json
vendored
Submodule
1
deps/json
vendored
Submodule
Submodule deps/json added at bc889afb4c
2
deps/websocketpp
vendored
2
deps/websocketpp
vendored
Submodule deps/websocketpp updated: c6d7e295bf...56123c8759
@@ -67,8 +67,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>957</width>
|
||||
<height>905</height>
|
||||
<width>962</width>
|
||||
<height>1033</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_19">
|
||||
@@ -119,7 +119,7 @@
|
||||
<string notr="true">ms</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>50</number>
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>20000</number>
|
||||
@@ -256,6 +256,30 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_11">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="disableComboBoxFilter">
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.generalTab.generalBehavior.comboBoxFilterDisable</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_13">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_26">
|
||||
<item>
|
||||
@@ -805,7 +829,7 @@
|
||||
<property name="title">
|
||||
<string>AdvSceneSwitcher.macroTab.edit</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_33">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_38">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_18" stretch="0,0,0,0,0,0,0,0,0">
|
||||
<item>
|
||||
@@ -819,7 +843,7 @@
|
||||
<widget class="QLineEdit" name="macroName"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="runMacro">
|
||||
<widget class="advss::MacroRunButton" name="runMacro">
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.macroTab.run</string>
|
||||
</property>
|
||||
@@ -912,6 +936,16 @@
|
||||
<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="horizontalLayout_12">
|
||||
<property name="leftMargin">
|
||||
@@ -1066,170 +1100,376 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<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>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_21">
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="actionAdd">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">addIconSmall</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="actionRemove">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">removeIconSmall</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_133">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>5</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_47">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_132">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>5</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="actionTop">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="actionUp">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">upArrowIconSmall</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="actionDown">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">downArrowIconSmall</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="actionBottom">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</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>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
<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="horizontalLayout_21">
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="actionAdd">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">addIconSmall</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="actionRemove">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">removeIconSmall</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_133">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>5</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_47">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_132">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>5</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="actionTop">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="actionUp">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">upArrowIconSmall</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="actionDown">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">downArrowIconSmall</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="actionBottom">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</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="QPushButton" name="toggleElseActions">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<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="horizontalLayout_33">
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="elseActionAdd">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">addIconSmall</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="elseActionRemove">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">removeIconSmall</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_138">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>5</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_50">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_139">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>5</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="elseActionTop">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="elseActionUp">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">upArrowIconSmall</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="elseActionDown">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">downArrowIconSmall</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="elseActionBottom">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_22">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -4619,6 +4859,17 @@
|
||||
<extends>QListView</extends>
|
||||
<header>macro-tree.hpp</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>advss::MacroSegmentList</class>
|
||||
<extends>QScrollArea</extends>
|
||||
<header>macro-segment-list.hpp</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>advss::MacroRunButton</class>
|
||||
<extends>QPushButton</extends>
|
||||
<header>macro-run-button.hpp</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
||||
@@ -1,15 +1,6 @@
|
||||
#include <QMainWindow>
|
||||
#include <QAction>
|
||||
#include <QFileDialog>
|
||||
#include <QDirIterator>
|
||||
#include <regex>
|
||||
#include <filesystem>
|
||||
|
||||
#include <obs-module.h>
|
||||
#include <obs-frontend-api.h>
|
||||
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "status-control.hpp"
|
||||
#include "scene-switch-helpers.hpp"
|
||||
#include "curl-helper.hpp"
|
||||
@@ -17,6 +8,16 @@
|
||||
#include "utility.hpp"
|
||||
#include "version.h"
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QAction>
|
||||
#include <QFileDialog>
|
||||
#include <QTextStream>
|
||||
#include <QDirIterator>
|
||||
#include <regex>
|
||||
#include <filesystem>
|
||||
#include <obs-module.h>
|
||||
#include <obs-frontend-api.h>
|
||||
|
||||
namespace advss {
|
||||
|
||||
AdvSceneSwitcher *AdvSceneSwitcher::window = nullptr;
|
||||
@@ -116,10 +117,27 @@ void AdvSceneSwitcher::LoadUI()
|
||||
loading = false;
|
||||
}
|
||||
|
||||
bool AdvSceneSwitcher::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
auto eventType = event->type();
|
||||
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();
|
||||
}
|
||||
|
||||
return QDialog::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Saving and loading
|
||||
******************************************************************************/
|
||||
static void AskForBackup(obs_data_t *obj);
|
||||
static void AskForBackup(const QString &json);
|
||||
|
||||
static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
||||
{
|
||||
@@ -140,16 +158,25 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
||||
switcher->Stop();
|
||||
|
||||
switcher->m.lock();
|
||||
obs_data_t *obj =
|
||||
OBSDataAutoRelease obj =
|
||||
obs_data_get_obj(save_data, "advanced-scene-switcher");
|
||||
if (!obj) {
|
||||
obj = obs_data_create();
|
||||
}
|
||||
if (switcher->VersionChanged(obj, g_GIT_SHA1)) {
|
||||
AskForBackup(obj);
|
||||
auto json = obs_data_get_json(obj);
|
||||
static QString jsonQString = json ? json : "";
|
||||
std::thread t([]() {
|
||||
obs_queue_task(
|
||||
OBS_TASK_UI,
|
||||
[](void *) {
|
||||
AskForBackup(jsonQString);
|
||||
},
|
||||
nullptr, false);
|
||||
});
|
||||
t.detach();
|
||||
}
|
||||
switcher->LoadSettings(obj);
|
||||
obs_data_release(obj);
|
||||
switcher->m.unlock();
|
||||
|
||||
if (!switcher->stop) {
|
||||
@@ -158,12 +185,12 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
||||
}
|
||||
}
|
||||
|
||||
static void AskForBackup(obs_data_t *obj)
|
||||
static void AskForBackup(const QString &json)
|
||||
{
|
||||
bool backupSettings = DisplayMessage(
|
||||
obs_module_text("AdvSceneSwitcher.askBackup"), true);
|
||||
const bool backupWasConfirmed = DisplayMessage(
|
||||
obs_module_text("AdvSceneSwitcher.askBackup"), true, false);
|
||||
|
||||
if (!backupSettings) {
|
||||
if (!backupWasConfirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -182,8 +209,8 @@ static void AskForBackup(obs_data_t *obj)
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
return;
|
||||
}
|
||||
|
||||
obs_data_save_json(obj, file.fileName().toUtf8().constData());
|
||||
auto out = QTextStream(&file);
|
||||
out << json;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
@@ -210,7 +237,6 @@ void SwitcherData::Thread()
|
||||
// if a longer transition is used than the configured check interval
|
||||
bool setPrevSceneAfterLinger = false;
|
||||
bool macroMatch = false;
|
||||
macroSceneSwitched = false;
|
||||
endTime = std::chrono::high_resolution_clock::now();
|
||||
auto runTime =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
@@ -321,19 +347,14 @@ void SwitcherData::SetPreconditions()
|
||||
// Process name
|
||||
GetForegroundProcessName(currentForegroundProcess);
|
||||
|
||||
// Cursor
|
||||
std::pair<int, int> cursorPos = GetCursorPos();
|
||||
cursorPosChanged = cursorPos.first != switcher->lastCursorPos.first ||
|
||||
cursorPos.second != switcher->lastCursorPos.second;
|
||||
lastCursorPos = GetCursorPos();
|
||||
// Macro
|
||||
InvalidateMacroTempVarValues();
|
||||
}
|
||||
|
||||
void SwitcherData::ResetForNextInterval()
|
||||
{
|
||||
// Core reset functions
|
||||
ClearWebsocketMessages();
|
||||
// Plugin reset functions
|
||||
for (const auto &func : resetForNextIntervalFuncs) {
|
||||
for (const auto &func : resetIntervalSteps) {
|
||||
func();
|
||||
}
|
||||
}
|
||||
@@ -407,7 +428,7 @@ bool SwitcherData::CheckForMatch(OBSWeakSource &scene,
|
||||
|
||||
static void ResetMacros()
|
||||
{
|
||||
for (auto &m : switcher->macros) {
|
||||
for (auto &m : GetMacros()) {
|
||||
m->ResetRunCount();
|
||||
m->ResetTimers();
|
||||
}
|
||||
@@ -450,9 +471,9 @@ void SwitcherData::Stop()
|
||||
if (th && th->isRunning()) {
|
||||
stop = true;
|
||||
cv.notify_all();
|
||||
abortMacroWait = true;
|
||||
macroWaitCv.notify_all();
|
||||
macroTransitionCv.notify_all();
|
||||
SetMacroAbortWait(true);
|
||||
GetMacroWaitCV().notify_all();
|
||||
GetMacroTransitionCV().notify_all();
|
||||
|
||||
// Not waiting if a dialog was closed is a workaround to avoid
|
||||
// deadlocks when a variable input dialog is opened while Stop()
|
||||
@@ -525,9 +546,6 @@ extern "C" void FreeSceneSwitcher()
|
||||
|
||||
static void handleSceneChange()
|
||||
{
|
||||
switcher->lastSceneChangeTime =
|
||||
std::chrono::high_resolution_clock::now();
|
||||
|
||||
// Stop waiting if scene was changed
|
||||
if (switcher->SceneChangedDuringWait()) {
|
||||
switcher->cv.notify_one();
|
||||
@@ -594,28 +612,9 @@ static void handlePeviewSceneChange()
|
||||
}
|
||||
}
|
||||
|
||||
static void setReplayBufferSaved()
|
||||
static void handleTransitionEnd()
|
||||
{
|
||||
switcher->replayBufferSaved = true;
|
||||
}
|
||||
|
||||
static void setTranstionEnd()
|
||||
{
|
||||
switcher->lastTransitionEndTime =
|
||||
std::chrono::high_resolution_clock::now();
|
||||
switcher->macroTransitionCv.notify_all();
|
||||
}
|
||||
|
||||
static void setStreamStarting()
|
||||
{
|
||||
switcher->lastStreamStartingTime =
|
||||
std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
static void setStreamStopping()
|
||||
{
|
||||
switcher->lastStreamStoppingTime =
|
||||
std::chrono::high_resolution_clock::now();
|
||||
GetMacroTransitionCV().notify_all();
|
||||
}
|
||||
|
||||
static void handleShutdown()
|
||||
@@ -624,10 +623,10 @@ static void handleShutdown()
|
||||
return;
|
||||
}
|
||||
switcher->obsIsShuttingDown = true;
|
||||
if (switcher->shutdownConditionCount) {
|
||||
if (ShutdownCheckIsNecessary()) {
|
||||
switcher->Stop();
|
||||
switcher->CheckMacros();
|
||||
switcher->RunMacros();
|
||||
CheckMacros();
|
||||
RunMacros();
|
||||
|
||||
// Unfortunately this will not work as OBS will now allow saving
|
||||
// the scene collection data at this point, So any OBS specific
|
||||
@@ -684,19 +683,8 @@ static void OBSEvent(enum obs_frontend_event event, void *switcher)
|
||||
case OBS_FRONTEND_EVENT_STREAMING_STOPPED:
|
||||
resetLiveTime();
|
||||
break;
|
||||
#if LIBOBS_API_VER >= MAKE_SEMANTIC_VERSION(26, 0, 0)
|
||||
case OBS_FRONTEND_EVENT_REPLAY_BUFFER_SAVED:
|
||||
setReplayBufferSaved();
|
||||
break;
|
||||
#endif
|
||||
case OBS_FRONTEND_EVENT_TRANSITION_STOPPED:
|
||||
setTranstionEnd();
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_STREAMING_STARTING:
|
||||
setStreamStarting();
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_STREAMING_STOPPING:
|
||||
setStreamStopping();
|
||||
handleTransitionEnd();
|
||||
break;
|
||||
#if LIBOBS_API_VER >= MAKE_SEMANTIC_VERSION(27, 2, 0)
|
||||
case OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGING:
|
||||
@@ -755,6 +743,9 @@ void OpenSettingsWindow()
|
||||
}
|
||||
}
|
||||
|
||||
void SetupConnectionManager();
|
||||
void SetupWebsocketHelpers();
|
||||
|
||||
extern "C" void InitSceneSwitcher(obs_module_t *module, translateFunc translate)
|
||||
{
|
||||
blog(LOG_INFO, "version: %s", g_GIT_TAG);
|
||||
@@ -765,6 +756,8 @@ extern "C" void InitSceneSwitcher(obs_module_t *module, translateFunc translate)
|
||||
PlatformInit();
|
||||
LoadPlugins();
|
||||
SetupDock();
|
||||
SetupConnectionManager();
|
||||
SetupWebsocketHelpers();
|
||||
|
||||
obs_frontend_add_save_callback(SaveSceneSwitcher, nullptr);
|
||||
obs_frontend_add_event_callback(OBSEvent, switcher);
|
||||
|
||||
@@ -39,6 +39,9 @@ public:
|
||||
void RestoreWindowGeo();
|
||||
void CheckFirstTimeSetup();
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
|
||||
/* --- Begin of general tab section --- */
|
||||
public:
|
||||
void SetupGeneralTab();
|
||||
@@ -63,6 +66,7 @@ public slots:
|
||||
void on_saveWindowGeo_stateChanged(int state);
|
||||
void on_showTrayNotifications_stateChanged(int state);
|
||||
void on_uiHintsDisable_stateChanged(int state);
|
||||
void on_disableComboBoxFilter_stateChanged(int state);
|
||||
void on_warnPluginLoadFailure_stateChanged(int state);
|
||||
void on_hideLegacyTabs_stateChanged(int state);
|
||||
void on_priorityUp_clicked();
|
||||
@@ -83,10 +87,13 @@ public:
|
||||
void SetEditMacro(Macro &m);
|
||||
void SetMacroEditAreaDisabled(bool);
|
||||
void HighlightAction(int idx, QColor color = QColor(Qt::green));
|
||||
void HighlightElseAction(int idx, QColor color = QColor(Qt::green));
|
||||
void HighlightCondition(int idx, QColor color = QColor(Qt::green));
|
||||
void PopulateMacroActions(Macro &m, uint32_t afterIdx = 0);
|
||||
void PopulateMacroElseActions(Macro &m, uint32_t afterIdx = 0);
|
||||
void PopulateMacroConditions(Macro &m, uint32_t afterIdx = 0);
|
||||
void SetActionData(Macro &m);
|
||||
void SetElseActionData(Macro &m);
|
||||
void SetConditionData(Macro &m);
|
||||
void SwapActions(Macro *m, int pos1, int pos2);
|
||||
void SwapConditions(Macro *m, int pos1, int pos2);
|
||||
@@ -97,7 +104,6 @@ public slots:
|
||||
void on_macroUp_clicked();
|
||||
void on_macroDown_clicked();
|
||||
void on_macroName_editingFinished();
|
||||
void on_runMacro_clicked();
|
||||
void on_runMacroInParallel_stateChanged(int value);
|
||||
void on_runMacroOnChange_stateChanged(int value);
|
||||
void on_conditionAdd_clicked();
|
||||
@@ -112,29 +118,53 @@ public slots:
|
||||
void on_actionUp_clicked();
|
||||
void on_actionDown_clicked();
|
||||
void on_actionBottom_clicked();
|
||||
void on_toggleElseActions_clicked();
|
||||
void on_elseActionAdd_clicked();
|
||||
void on_elseActionRemove_clicked();
|
||||
void on_elseActionTop_clicked();
|
||||
void on_elseActionUp_clicked();
|
||||
void on_elseActionDown_clicked();
|
||||
void on_elseActionBottom_clicked();
|
||||
void MacroSelectionAboutToChange();
|
||||
void MacroSelectionChanged();
|
||||
void UpMacroSegementHotkey();
|
||||
void DownMacroSegementHotkey();
|
||||
void DeleteMacroSegementHotkey();
|
||||
void ShowMacroContextMenu(const QPoint &);
|
||||
void ShowMacroActionsContextMenu(const QPoint &);
|
||||
void ShowMacroElseActionsContextMenu(const QPoint &);
|
||||
void ShowMacroConditionsContextMenu(const QPoint &);
|
||||
void CopyMacro();
|
||||
void RenameCurrentMacro();
|
||||
void ExportMacros();
|
||||
void ImportMacros();
|
||||
void ExpandAllActions();
|
||||
void ExpandAllElseActions();
|
||||
void ExpandAllConditions();
|
||||
void CollapseAllActions();
|
||||
void CollapseAllElseActions();
|
||||
void CollapseAllConditions();
|
||||
void MinimizeActions();
|
||||
void MaximizeActions();
|
||||
void MinimizeElseActions();
|
||||
void MaximizeElseActions();
|
||||
void MinimizeConditions();
|
||||
void MaximizeConditions();
|
||||
void SetElseActionsStateToHidden();
|
||||
void SetElseActionsStateToVisible();
|
||||
void MacroActionSelectionChanged(int idx);
|
||||
void MacroActionReorder(int to, int target);
|
||||
void AddMacroAction(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(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);
|
||||
@@ -154,8 +184,10 @@ signals:
|
||||
void MacroRemoved(const QString &name);
|
||||
void MacroRenamed(const QString &oldName, const QString &newName);
|
||||
void MacroSegmentOrderChanged();
|
||||
void SegmentTempVarsChanged();
|
||||
void HighlightMacrosChanged(bool value);
|
||||
void HighlightActionsChanged(bool value);
|
||||
void HighlightElseActionsChanged(bool value);
|
||||
void HighlightConditionsChanged(bool value);
|
||||
|
||||
void ConnectionAdded(const QString &);
|
||||
@@ -166,19 +198,16 @@ signals:
|
||||
void VariableRemoved(const QString &);
|
||||
|
||||
private:
|
||||
enum class MacroSection { CONDITIONS, ACTIONS, ELSE_ACTIONS };
|
||||
|
||||
void SetupMacroSegmentSelection(MacroSection type, int idx);
|
||||
bool ResolveMacroImportNameConflict(std::shared_ptr<Macro> &);
|
||||
bool MacroTabIsInFocus();
|
||||
|
||||
MacroSegmentList *conditionsList = nullptr;
|
||||
MacroSegmentList *actionsList = nullptr;
|
||||
|
||||
enum class MacroSection {
|
||||
CONDITIONS,
|
||||
ACTIONS,
|
||||
};
|
||||
MacroSection lastInteracted = MacroSection::CONDITIONS;
|
||||
int currentConditionIdx = -1;
|
||||
int currentActionIdx = -1;
|
||||
int currentElseActionIdx = -1;
|
||||
|
||||
/* --- End of macro tab section --- */
|
||||
|
||||
@@ -311,7 +340,7 @@ public slots:
|
||||
void on_timeUp_clicked();
|
||||
void on_timeDown_clicked();
|
||||
|
||||
// Video tab
|
||||
// Audio tab
|
||||
public:
|
||||
void SetupAudioTab();
|
||||
public slots:
|
||||
|
||||
101
src/general.cpp
101
src/general.cpp
@@ -2,6 +2,8 @@
|
||||
#include "switcher-data.hpp"
|
||||
#include "status-control.hpp"
|
||||
#include "file-selection.hpp"
|
||||
#include "filter-combo-box.hpp"
|
||||
#include "variable.hpp"
|
||||
#include "utility.hpp"
|
||||
#include "version.h"
|
||||
|
||||
@@ -32,7 +34,7 @@ void AdvSceneSwitcher::on_noMatchDontSwitch_clicked()
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->switchIfNotMatching = SwitcherData::NoMatch::NO_SWITCH;
|
||||
switcher->switchIfNotMatching = NoMatchBehavior::NO_SWITCH;
|
||||
ui->noMatchSwitchScene->setEnabled(false);
|
||||
ui->randomDisabledWarning->setVisible(true);
|
||||
}
|
||||
@@ -44,7 +46,7 @@ void AdvSceneSwitcher::on_noMatchSwitch_clicked()
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->switchIfNotMatching = SwitcherData::NoMatch::SWITCH;
|
||||
switcher->switchIfNotMatching = NoMatchBehavior::SWITCH;
|
||||
ui->noMatchSwitchScene->setEnabled(true);
|
||||
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
|
||||
ui->randomDisabledWarning->setVisible(true);
|
||||
@@ -57,7 +59,7 @@ void AdvSceneSwitcher::on_noMatchRandomSwitch_clicked()
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->switchIfNotMatching = SwitcherData::NoMatch::RANDOM_SWITCH;
|
||||
switcher->switchIfNotMatching = NoMatchBehavior::RANDOM_SWITCH;
|
||||
ui->noMatchSwitchScene->setEnabled(false);
|
||||
ui->randomDisabledWarning->setVisible(false);
|
||||
}
|
||||
@@ -131,10 +133,9 @@ void AdvSceneSwitcher::closeEvent(QCloseEvent *)
|
||||
}
|
||||
switcher->windowPos = this->pos();
|
||||
switcher->windowSize = this->size();
|
||||
switcher->macroActionConditionSplitterPosition =
|
||||
ui->macroActionConditionSplitter->sizes();
|
||||
switcher->macroListMacroEditSplitterPosition =
|
||||
ui->macroListMacroEditSplitter->sizes();
|
||||
MacroSelectionAboutToChange(); // Trigger saving of splitter states
|
||||
|
||||
obs_frontend_save();
|
||||
}
|
||||
@@ -175,6 +176,16 @@ void AdvSceneSwitcher::on_uiHintsDisable_stateChanged(int state)
|
||||
switcher->disableHints = state;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_disableComboBoxFilter_stateChanged(int state)
|
||||
{
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
switcher->disableFilterComboboxFilter = state;
|
||||
FilterComboBox::SetFilterBehaviourEnabled(!state);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_warnPluginLoadFailure_stateChanged(int state)
|
||||
{
|
||||
if (loading) {
|
||||
@@ -489,12 +500,20 @@ void SwitcherData::LoadSettings(obs_data_t *obj)
|
||||
return;
|
||||
}
|
||||
|
||||
// New post load steps to be declared during load
|
||||
postLoadSteps.clear();
|
||||
|
||||
// Needs to be loaded before any entries which might rely on scene group
|
||||
// selections to be available.
|
||||
loadSceneGroups(obj);
|
||||
LoadVariables(obj);
|
||||
LoadConnections(obj);
|
||||
|
||||
for (const auto &func : loadSteps) {
|
||||
func(obj);
|
||||
}
|
||||
|
||||
LoadMacros(obj);
|
||||
LoadGlobalMacroProperties(obj);
|
||||
loadWindowTitleSwitches(obj);
|
||||
loadScreenRegionSwitches(obj);
|
||||
loadPauseSwitches(obj);
|
||||
@@ -514,6 +533,10 @@ void SwitcherData::LoadSettings(obs_data_t *obj)
|
||||
LoadHotkeys(obj);
|
||||
LoadUISettings(obj);
|
||||
|
||||
for (const auto &func : postLoadSteps) {
|
||||
func();
|
||||
}
|
||||
|
||||
// Reset on startup and scene collection change
|
||||
switcher->lastOpenedTab = -1;
|
||||
startupLoadDone = true;
|
||||
@@ -527,7 +550,7 @@ void SwitcherData::SaveSettings(obs_data_t *obj)
|
||||
|
||||
saveSceneGroups(obj);
|
||||
SaveMacros(obj);
|
||||
SaveConnections(obj);
|
||||
SaveGlobalMacroProperties(obj);
|
||||
SaveVariables(obj);
|
||||
saveWindowTitleSwitches(obj);
|
||||
saveScreenRegionSwitches(obj);
|
||||
@@ -548,6 +571,10 @@ void SwitcherData::SaveSettings(obs_data_t *obj)
|
||||
SaveHotkeys(obj);
|
||||
SaveUISettings(obj);
|
||||
SaveVersion(obj, g_GIT_SHA1);
|
||||
|
||||
for (const auto &func : saveSteps) {
|
||||
func(obj);
|
||||
}
|
||||
}
|
||||
|
||||
void SwitcherData::SaveGeneralSettings(obs_data_t *obj)
|
||||
@@ -575,6 +602,8 @@ void SwitcherData::SaveGeneralSettings(obs_data_t *obj)
|
||||
obs_data_set_bool(obj, "showSystemTrayNotifications",
|
||||
showSystemTrayNotifications);
|
||||
obs_data_set_bool(obj, "disableHints", disableHints);
|
||||
obs_data_set_bool(obj, "disableFilterComboboxFilter",
|
||||
disableFilterComboboxFilter);
|
||||
obs_data_set_bool(obj, "warnPluginLoadFailure", warnPluginLoadFailure);
|
||||
obs_data_set_bool(obj, "hideLegacyTabs", hideLegacyTabs);
|
||||
|
||||
@@ -596,9 +625,9 @@ void SwitcherData::LoadGeneralSettings(obs_data_t *obj)
|
||||
interval = obs_data_get_int(obj, "interval");
|
||||
|
||||
obs_data_set_default_int(obj, "switch_if_not_matching",
|
||||
static_cast<int>(NoMatch::NO_SWITCH));
|
||||
switchIfNotMatching =
|
||||
(NoMatch)obs_data_get_int(obj, "switch_if_not_matching");
|
||||
static_cast<int>(NoMatchBehavior::NO_SWITCH));
|
||||
switchIfNotMatching = static_cast<NoMatchBehavior>(
|
||||
obs_data_get_int(obj, "switch_if_not_matching"));
|
||||
std::string nonMatchingSceneName =
|
||||
obs_data_get_string(obj, "non_matching_scene");
|
||||
nonMatchingScene = GetWeakSourceByName(nonMatchingSceneName.c_str());
|
||||
@@ -623,6 +652,8 @@ void SwitcherData::LoadGeneralSettings(obs_data_t *obj)
|
||||
showSystemTrayNotifications =
|
||||
obs_data_get_bool(obj, "showSystemTrayNotifications");
|
||||
disableHints = obs_data_get_bool(obj, "disableHints");
|
||||
disableFilterComboboxFilter =
|
||||
obs_data_get_bool(obj, "disableFilterComboboxFilter");
|
||||
obs_data_set_default_bool(obj, "warnPluginLoadFailure", true);
|
||||
warnPluginLoadFailure = obs_data_get_bool(obj, "warnPluginLoadFailure");
|
||||
obs_data_set_default_bool(obj, "hideLegacyTabs", true);
|
||||
@@ -652,34 +683,6 @@ void SwitcherData::LoadGeneralSettings(obs_data_t *obj)
|
||||
lastImportPath = obs_data_get_string(obj, "lastImportPath");
|
||||
}
|
||||
|
||||
static void saveSplitterPos(QList<int> &sizes, obs_data_t *obj,
|
||||
const std::string name)
|
||||
{
|
||||
auto array = obs_data_array_create();
|
||||
for (int i = 0; i < sizes.count(); ++i) {
|
||||
obs_data_t *array_obj = obs_data_create();
|
||||
obs_data_set_int(array_obj, "pos", sizes[i]);
|
||||
obs_data_array_push_back(array, array_obj);
|
||||
obs_data_release(array_obj);
|
||||
}
|
||||
obs_data_set_array(obj, name.c_str(), array);
|
||||
obs_data_array_release(array);
|
||||
}
|
||||
|
||||
static void loadSplitterPos(QList<int> &sizes, obs_data_t *obj,
|
||||
const std::string name)
|
||||
{
|
||||
sizes.clear();
|
||||
obs_data_array_t *array = obs_data_get_array(obj, name.c_str());
|
||||
size_t count = obs_data_array_count(array);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
obs_data_t *item = obs_data_array_item(array, i);
|
||||
sizes << obs_data_get_int(item, "pos");
|
||||
obs_data_release(item);
|
||||
}
|
||||
obs_data_array_release(array);
|
||||
}
|
||||
|
||||
void SwitcherData::SaveUISettings(obs_data_t *obj)
|
||||
{
|
||||
obs_data_set_int(obj, "generalTabPos", tabOrder[0]);
|
||||
@@ -707,9 +710,7 @@ void SwitcherData::SaveUISettings(obs_data_t *obj)
|
||||
obs_data_set_int(obj, "windowWidth", windowSize.width());
|
||||
obs_data_set_int(obj, "windowHeight", windowSize.height());
|
||||
|
||||
saveSplitterPos(macroActionConditionSplitterPosition, obj,
|
||||
"macroActionConditionSplitterPosition");
|
||||
saveSplitterPos(macroListMacroEditSplitterPosition, obj,
|
||||
SaveSplitterPos(macroListMacroEditSplitterPosition, obj,
|
||||
"macroListMacroEditSplitterPosition");
|
||||
}
|
||||
|
||||
@@ -763,9 +764,8 @@ void SwitcherData::LoadUISettings(obs_data_t *obj)
|
||||
(int)obs_data_get_int(obj, "windowPosY")};
|
||||
windowSize = {(int)obs_data_get_int(obj, "windowWidth"),
|
||||
(int)obs_data_get_int(obj, "windowHeight")};
|
||||
loadSplitterPos(macroActionConditionSplitterPosition, obj,
|
||||
"macroActionConditionSplitterPosition");
|
||||
loadSplitterPos(macroListMacroEditSplitterPosition, obj,
|
||||
|
||||
LoadSplitterPos(macroListMacroEditSplitterPosition, obj,
|
||||
"macroListMacroEditSplitterPosition");
|
||||
}
|
||||
|
||||
@@ -801,12 +801,13 @@ void SwitcherData::CheckNoMatchSwitch(bool &match, OBSWeakSource &scene,
|
||||
return;
|
||||
}
|
||||
|
||||
if (switchIfNotMatching == NoMatch::SWITCH && nonMatchingScene) {
|
||||
if (switchIfNotMatching == NoMatchBehavior::SWITCH &&
|
||||
nonMatchingScene) {
|
||||
match = true;
|
||||
scene = nonMatchingScene;
|
||||
transition = nullptr;
|
||||
}
|
||||
if (switchIfNotMatching == NoMatch::RANDOM_SWITCH) {
|
||||
if (switchIfNotMatching == NoMatchBehavior::RANDOM_SWITCH) {
|
||||
match = checkRandom(scene, transition, sleep);
|
||||
}
|
||||
}
|
||||
@@ -957,11 +958,11 @@ void AdvSceneSwitcher::SetupGeneralTab()
|
||||
{
|
||||
PopulateSceneSelection(ui->noMatchSwitchScene, false);
|
||||
|
||||
if (switcher->switchIfNotMatching == SwitcherData::NoMatch::SWITCH) {
|
||||
if (switcher->switchIfNotMatching == NoMatchBehavior::SWITCH) {
|
||||
ui->noMatchSwitch->setChecked(true);
|
||||
ui->noMatchSwitchScene->setEnabled(true);
|
||||
} else if (switcher->switchIfNotMatching ==
|
||||
SwitcherData::NoMatch::NO_SWITCH) {
|
||||
NoMatchBehavior::NO_SWITCH) {
|
||||
ui->noMatchDontSwitch->setChecked(true);
|
||||
ui->noMatchSwitchScene->setEnabled(false);
|
||||
} else {
|
||||
@@ -997,6 +998,10 @@ void AdvSceneSwitcher::SetupGeneralTab()
|
||||
ui->showTrayNotifications->setChecked(
|
||||
switcher->showSystemTrayNotifications);
|
||||
ui->uiHintsDisable->setChecked(switcher->disableHints);
|
||||
ui->disableComboBoxFilter->setChecked(
|
||||
switcher->disableFilterComboboxFilter);
|
||||
FilterComboBox::SetFilterBehaviourEnabled(
|
||||
!switcher->disableFilterComboboxFilter);
|
||||
ui->warnPluginLoadFailure->setChecked(switcher->warnPluginLoadFailure);
|
||||
ui->hideLegacyTabs->setChecked(switcher->hideLegacyTabs);
|
||||
|
||||
|
||||
@@ -160,7 +160,9 @@ enum class HotkeyType {
|
||||
Key_NumpadMultiply,
|
||||
Key_NumpadDivide,
|
||||
Key_NumpadDecimal,
|
||||
Key_NumpadEnter
|
||||
Key_NumpadEnter,
|
||||
|
||||
Key_Tilde,
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -12,6 +12,11 @@ namespace advss {
|
||||
static QMetaObject::Connection addPulse;
|
||||
SceneGroupEditWidget *typeEdit = nullptr;
|
||||
|
||||
std::deque<SceneGroup> &GetSceneGroups()
|
||||
{
|
||||
return switcher->sceneGroups;
|
||||
}
|
||||
|
||||
void SceneGroup::advanceIdx()
|
||||
{
|
||||
currentIdx++;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
#include <QDialog>
|
||||
#include <QLabel>
|
||||
@@ -87,5 +87,6 @@ private:
|
||||
|
||||
SceneGroup *GetSceneGroupByName(const char *name);
|
||||
SceneGroup *GetSceneGroupByQString(const QString &name);
|
||||
std::deque<SceneGroup> &GetSceneGroups();
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -119,7 +119,7 @@ void SwitcherData::writeToStatusFile(const QString &msg)
|
||||
if (file.open(QIODevice::ReadWrite)) {
|
||||
QTextStream stream(&file);
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
stream << msg << endl;
|
||||
stream << msg << "\n";
|
||||
#else
|
||||
stream << msg << Qt::endl;
|
||||
#endif
|
||||
@@ -177,17 +177,17 @@ static std::string getRemoteData(std::string &url)
|
||||
{
|
||||
std::string readBuffer;
|
||||
|
||||
switcher->curl.SetOpt(CURLOPT_URL, url.c_str());
|
||||
switcher->curl.SetOpt(CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||
switcher->curl.SetOpt(CURLOPT_WRITEDATA, &readBuffer);
|
||||
CurlHelper::SetOpt(CURLOPT_URL, url.c_str());
|
||||
CurlHelper::SetOpt(CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||
CurlHelper::SetOpt(CURLOPT_WRITEDATA, &readBuffer);
|
||||
|
||||
// Set timeout to at least one second
|
||||
int timeout = switcher->interval / 1000;
|
||||
if (timeout == 0) {
|
||||
timeout = 1;
|
||||
}
|
||||
switcher->curl.SetOpt(CURLOPT_TIMEOUT, 1);
|
||||
switcher->curl.Perform();
|
||||
CurlHelper::SetOpt(CURLOPT_TIMEOUT, 1);
|
||||
CurlHelper::Perform();
|
||||
|
||||
return readBuffer;
|
||||
}
|
||||
@@ -422,7 +422,7 @@ void AdvSceneSwitcher::SetupFileTab()
|
||||
obs_module_text("AdvSceneSwitcher.fileTab.remoteFileWarning2"));
|
||||
ui->remoteFileWarningLabel->hide();
|
||||
|
||||
if (switcher->curl.Initialized()) {
|
||||
if (CurlHelper::Initialized()) {
|
||||
ui->libcurlWarning->setVisible(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -143,8 +143,7 @@ void AdvSceneSwitcher::SetupRandomTab()
|
||||
border-radius: 7px; \
|
||||
border-color: rgb(0,0,0,0) \
|
||||
}");
|
||||
if (switcher->switchIfNotMatching !=
|
||||
SwitcherData::NoMatch::RANDOM_SWITCH) {
|
||||
if (switcher->switchIfNotMatching != NoMatchBehavior::RANDOM_SWITCH) {
|
||||
if (!switcher->disableHints) {
|
||||
PulseWidget(ui->randomDisabledWarning, QColor(Qt::red),
|
||||
QColor(0, 0, 0, 0));
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "platform-funcs.hpp"
|
||||
#include "hotkey.hpp"
|
||||
#include "log-helper.hpp"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
@@ -25,9 +26,10 @@
|
||||
#include <QStringList>
|
||||
#include <QRegularExpression>
|
||||
#include <QLibrary>
|
||||
#ifdef USE_PROCPS
|
||||
#ifdef PROCPS_AVAILABLE
|
||||
#include <proc/readproc.h>
|
||||
#else
|
||||
#endif
|
||||
#ifdef PROCPS2_AVAILABLE
|
||||
#include <libproc2/pids.h>
|
||||
#endif
|
||||
#include <fstream>
|
||||
@@ -53,6 +55,31 @@ std::chrono::high_resolution_clock::time_point lastMouseLeftClickTime{};
|
||||
std::chrono::high_resolution_clock::time_point lastMouseMiddleClickTime{};
|
||||
std::chrono::high_resolution_clock::time_point lastMouseRightClickTime{};
|
||||
|
||||
static QLibrary *libprocps = nullptr;
|
||||
#ifdef PROCPS_AVAILABLE
|
||||
typedef PROCTAB *(*openproc_func)(int flags);
|
||||
typedef void (*closeproc_func)(PROCTAB *PT);
|
||||
typedef proc_t *(*readproc_func)(PROCTAB *__restrict const PT,
|
||||
proc_t *__restrict p);
|
||||
static openproc_func openproc_ = nullptr;
|
||||
static closeproc_func closeproc_ = nullptr;
|
||||
static readproc_func readproc_ = nullptr;
|
||||
#endif
|
||||
static bool libprocpsSupported = false;
|
||||
|
||||
static QLibrary *libproc2 = nullptr;
|
||||
#ifdef PROCPS2_AVAILABLE
|
||||
typedef int (*procps_pids_new_func)(struct pids_info **info,
|
||||
enum pids_item *items, int numitems);
|
||||
typedef struct pids_stack *(*procps_pids_get_func)(struct pids_info *info,
|
||||
enum pids_fetch_type which);
|
||||
typedef int (*procps_pids_unref_func)(struct pids_info **info);
|
||||
static procps_pids_new_func procps_pids_new_ = nullptr;
|
||||
static procps_pids_get_func procps_pids_get_ = nullptr;
|
||||
static procps_pids_unref_func procps_pids_unref_ = nullptr;
|
||||
#endif
|
||||
static bool libprocps2Supported = false;
|
||||
|
||||
Display *disp()
|
||||
{
|
||||
if (!xdisplay) {
|
||||
@@ -332,52 +359,63 @@ bool IsFullscreen(const std::string &title)
|
||||
return windowStatesAreSet(title, states);
|
||||
}
|
||||
|
||||
std::optional<std::string> GetTextInWindow(const std::string &window)
|
||||
std::optional<std::string> GetTextInWindow(const std::string &)
|
||||
{
|
||||
// Not implemented
|
||||
return {};
|
||||
}
|
||||
|
||||
#ifdef USE_PROCPS
|
||||
void GetProcessList(QStringList &processes)
|
||||
static void getProcessListProcps(QStringList &processes)
|
||||
{
|
||||
processes.clear();
|
||||
PROCTAB *proc = openproc(PROC_FILLSTAT);
|
||||
#ifdef PROCPS_AVAILABLE
|
||||
PROCTAB *proc = openproc_(PROC_FILLSTAT);
|
||||
proc_t proc_info;
|
||||
memset(&proc_info, 0, sizeof(proc_info));
|
||||
while (readproc(proc, &proc_info) != NULL) {
|
||||
while (readproc_(proc, &proc_info) != NULL) {
|
||||
QString procName(proc_info.cmd);
|
||||
if (!procName.isEmpty() && !processes.contains(procName)) {
|
||||
processes << procName;
|
||||
}
|
||||
}
|
||||
closeproc(proc);
|
||||
closeproc_(proc);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
void GetProcessList(QStringList &processes)
|
||||
|
||||
static void getProcessListProcps2(QStringList &processes)
|
||||
{
|
||||
processes.clear();
|
||||
#ifdef PROCPS2_AVAILABLE
|
||||
struct pids_info *info = NULL;
|
||||
struct pids_stack *stack;
|
||||
enum pids_item Items[] = {
|
||||
PIDS_CMD,
|
||||
};
|
||||
|
||||
if (procps_pids_new(&info, Items, sizeof(Items) / sizeof(Items[0])) <
|
||||
if (procps_pids_new_(&info, Items, sizeof(Items) / sizeof(Items[0])) <
|
||||
0) {
|
||||
return;
|
||||
}
|
||||
|
||||
while ((stack = procps_pids_get(info, PIDS_FETCH_TASKS_ONLY))) {
|
||||
while ((stack = procps_pids_get_(info, PIDS_FETCH_TASKS_ONLY))) {
|
||||
auto cmd = PIDS_VAL(0, str, stack, info);
|
||||
QString procName(cmd);
|
||||
if (!procName.isEmpty() && !processes.contains(procName)) {
|
||||
processes << procName;
|
||||
}
|
||||
}
|
||||
procps_pids_unref(&info);
|
||||
}
|
||||
procps_pids_unref_(&info);
|
||||
#endif
|
||||
}
|
||||
|
||||
void GetProcessList(QStringList &processes)
|
||||
{
|
||||
processes.clear();
|
||||
if (libprocpsSupported) {
|
||||
getProcessListProcps(processes);
|
||||
return;
|
||||
}
|
||||
if (libprocps2Supported) {
|
||||
getProcessListProcps2(processes);
|
||||
}
|
||||
}
|
||||
|
||||
long getForegroundProcessPid()
|
||||
{
|
||||
@@ -517,6 +555,9 @@ static std::unordered_map<HotkeyType, long> keyTable = {
|
||||
{HotkeyType::Key_8, XK_8},
|
||||
{HotkeyType::Key_9, XK_9},
|
||||
|
||||
// Other
|
||||
{HotkeyType::Key_Tilde, XK_asciitilde},
|
||||
|
||||
{HotkeyType::Key_F1, XK_F1},
|
||||
{HotkeyType::Key_F2, XK_F2},
|
||||
{HotkeyType::Key_F3, XK_F3},
|
||||
@@ -633,6 +674,58 @@ void PressKeys(const std::vector<HotkeyType> keys, int duration)
|
||||
XFlush(display);
|
||||
}
|
||||
|
||||
static void initXtst()
|
||||
{
|
||||
libXtstHandle = new QLibrary("libXtst", nullptr);
|
||||
pressFunc = (keyPressFunc)libXtstHandle->resolve("XTestFakeKeyEvent");
|
||||
int _;
|
||||
canSimulateKeyPresses = pressFunc &&
|
||||
XQueryExtension(disp(), "XTEST", &_, &_, &_);
|
||||
}
|
||||
|
||||
static void initXss()
|
||||
{
|
||||
libXssHandle = new QLibrary("libXss", nullptr);
|
||||
allocSSFunc = (XScreenSaverAllocInfoFunc)libXssHandle->resolve(
|
||||
"XScreenSaverAllocInfo");
|
||||
querySSFunc = (XScreenSaverQueryInfoFunc)libXssHandle->resolve(
|
||||
"XScreenSaverQueryInfo");
|
||||
int _;
|
||||
canGetIdleTime = allocSSFunc && querySSFunc &&
|
||||
XQueryExtension(disp(), ScreenSaverName, &_, &_, &_);
|
||||
}
|
||||
|
||||
static void initProcps()
|
||||
{
|
||||
#ifdef PROCPS_AVAILABLE
|
||||
libprocps = new QLibrary("libprocps", nullptr);
|
||||
openproc_ = (openproc_func)libprocps->resolve("openproc");
|
||||
closeproc_ = (closeproc_func)libprocps->resolve("closeproc");
|
||||
readproc_ = (readproc_func)libprocps->resolve("readproc");
|
||||
if (openproc_ && closeproc_ && readproc_) {
|
||||
libprocpsSupported = true;
|
||||
blog(LOG_INFO, "libprocps symbols resolved successfully!");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void initProc2()
|
||||
{
|
||||
#ifdef PROCPS2_AVAILABLE
|
||||
libproc2 = new QLibrary("libproc2", nullptr);
|
||||
procps_pids_new_ =
|
||||
(procps_pids_new_func)libproc2->resolve("procps_pids_new");
|
||||
procps_pids_get_ =
|
||||
(procps_pids_get_func)libproc2->resolve("procps_pids_get");
|
||||
procps_pids_unref_ =
|
||||
(procps_pids_unref_func)libproc2->resolve("procps_pids_unref");
|
||||
if (procps_pids_new_ && procps_pids_get_ && procps_pids_unref_) {
|
||||
libprocps2Supported = true;
|
||||
blog(LOG_INFO, "libproc2 symbols resolved successfully!");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void PlatformInit()
|
||||
{
|
||||
auto display = disp();
|
||||
@@ -640,31 +733,26 @@ void PlatformInit()
|
||||
return;
|
||||
}
|
||||
|
||||
libXtstHandle = new QLibrary("libXtst", nullptr);
|
||||
pressFunc = (keyPressFunc)libXtstHandle->resolve("XTestFakeKeyEvent");
|
||||
int _;
|
||||
canSimulateKeyPresses = pressFunc &&
|
||||
XQueryExtension(disp(), "XTEST", &_, &_, &_);
|
||||
initXtst();
|
||||
initXss();
|
||||
initProcps();
|
||||
initProc2();
|
||||
}
|
||||
|
||||
libXssHandle = new QLibrary("libXss", nullptr);
|
||||
allocSSFunc = (XScreenSaverAllocInfoFunc)libXssHandle->resolve(
|
||||
"XScreenSaverAllocInfo");
|
||||
querySSFunc = (XScreenSaverQueryInfoFunc)libXssHandle->resolve(
|
||||
"XScreenSaverQueryInfo");
|
||||
canGetIdleTime = allocSSFunc && querySSFunc &&
|
||||
XQueryExtension(disp(), ScreenSaverName, &_, &_, &_);
|
||||
static void cleanupHelper(QLibrary *lib)
|
||||
{
|
||||
if (lib) {
|
||||
delete lib;
|
||||
lib = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void PlatformCleanup()
|
||||
{
|
||||
if (libXtstHandle) {
|
||||
delete libXtstHandle;
|
||||
libXtstHandle = nullptr;
|
||||
}
|
||||
if (libXssHandle) {
|
||||
delete libXssHandle;
|
||||
libXssHandle = nullptr;
|
||||
}
|
||||
cleanupHelper(libXtstHandle);
|
||||
cleanupHelper(libXssHandle);
|
||||
cleanupHelper(libprocps);
|
||||
cleanupHelper(libproc2);
|
||||
cleanupDisplay();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "macro-action-audio.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace advss {
|
||||
@@ -36,16 +36,41 @@ const static std::map<MacroActionAudio::FadeType, std::string> fadeTypes = {
|
||||
"AdvSceneSwitcher.action.audio.fade.type.rate"},
|
||||
};
|
||||
|
||||
namespace {
|
||||
struct FadeInfo {
|
||||
std::atomic_bool active = {false};
|
||||
std::atomic_int id = {0};
|
||||
};
|
||||
}
|
||||
|
||||
static FadeInfo masterAudioFade;
|
||||
static std::unordered_map<std::string, FadeInfo> audioFades;
|
||||
|
||||
constexpr auto fadeInterval = std::chrono::milliseconds(100);
|
||||
constexpr float minFade = 0.000001f;
|
||||
|
||||
// For backwards compatibility
|
||||
#if LIBOBS_API_VER >= MAKE_SEMANTIC_VERSION(29, 0, 0)
|
||||
static float get_master_volume()
|
||||
{
|
||||
return 1.f;
|
||||
}
|
||||
|
||||
static void set_master_volume(float)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#else
|
||||
auto get_master_volume = obs_get_master_volume;
|
||||
auto set_master_volume = obs_set_master_volume;
|
||||
#endif
|
||||
|
||||
void MacroActionAudio::SetFadeActive(bool value)
|
||||
{
|
||||
if (_action == Action::SOURCE_VOLUME) {
|
||||
switcher->activeAudioFades[_audioSource.ToString()].active =
|
||||
value;
|
||||
audioFades[_audioSource.ToString()].active = value;
|
||||
} else {
|
||||
switcher->masterAudioFade.active = value;
|
||||
masterAudioFade.active = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,14 +78,13 @@ bool MacroActionAudio::FadeActive()
|
||||
{
|
||||
bool active = true;
|
||||
if (_action == Action::SOURCE_VOLUME) {
|
||||
auto it = switcher->activeAudioFades.find(
|
||||
_audioSource.ToString());
|
||||
if (it == switcher->activeAudioFades.end()) {
|
||||
auto it = audioFades.find(_audioSource.ToString());
|
||||
if (it == audioFades.end()) {
|
||||
return false;
|
||||
}
|
||||
active = it->second.active;
|
||||
} else {
|
||||
active = switcher->masterAudioFade.active;
|
||||
active = masterAudioFade.active;
|
||||
}
|
||||
|
||||
return active;
|
||||
@@ -70,14 +94,13 @@ std::atomic_int *MacroActionAudio::GetFadeIdPtr()
|
||||
{
|
||||
|
||||
if (_action == Action::SOURCE_VOLUME) {
|
||||
auto it = switcher->activeAudioFades.find(
|
||||
_audioSource.ToString());
|
||||
if (it == switcher->activeAudioFades.end()) {
|
||||
auto it = audioFades.find(_audioSource.ToString());
|
||||
if (it == audioFades.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return &it->second.id;
|
||||
}
|
||||
return &switcher->masterAudioFade.id;
|
||||
return &masterAudioFade.id;
|
||||
}
|
||||
|
||||
void MacroActionAudio::SetVolume(float vol)
|
||||
@@ -87,7 +110,7 @@ void MacroActionAudio::SetVolume(float vol)
|
||||
obs_source_set_volume(s, vol);
|
||||
obs_source_release(s);
|
||||
} else {
|
||||
obs_set_master_volume(vol);
|
||||
set_master_volume(vol);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +125,7 @@ float MacroActionAudio::GetVolume()
|
||||
curVol = obs_source_get_volume(s);
|
||||
obs_source_release(s);
|
||||
} else {
|
||||
curVol = obs_get_master_volume();
|
||||
curVol = get_master_volume();
|
||||
}
|
||||
return curVol;
|
||||
}
|
||||
@@ -287,15 +310,13 @@ std::string MacroActionAudio::GetShortDesc() const
|
||||
static inline void populateActionSelection(QComboBox *list)
|
||||
{
|
||||
for (const auto &[action, name] : actionTypes) {
|
||||
if (action == MacroActionAudio::Action::MONITOR) {
|
||||
if (obs_audio_monitoring_available()) {
|
||||
list->addItem(obs_module_text(name.c_str()),
|
||||
static_cast<int>(action));
|
||||
}
|
||||
} else {
|
||||
list->addItem(obs_module_text(name.c_str()),
|
||||
static_cast<int>(action));
|
||||
if (action == MacroActionAudio::Action::MONITOR &&
|
||||
!obs_audio_monitoring_available()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
list->addItem(obs_module_text(name.c_str()),
|
||||
static_cast<int>(action));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,6 +494,14 @@ void MacroActionAudioEdit::SetWidgetVisibility()
|
||||
_wait->setVisible(hasVolumeControl(_entryData->_action) &&
|
||||
_entryData->_fade);
|
||||
|
||||
// TODO: Remove this in a future version:
|
||||
if (_entryData->_action != MacroActionAudio::Action::MASTER_VOLUME &&
|
||||
obs_get_version() >= MAKE_SEMANTIC_VERSION(29, 0, 0)) {
|
||||
_actions->removeItem(_actions->findText(obs_module_text(
|
||||
actionTypes.at(MacroActionAudio::Action::MASTER_VOLUME)
|
||||
.c_str())));
|
||||
}
|
||||
|
||||
updateGeometry();
|
||||
adjustSize();
|
||||
}
|
||||
|
||||
256
src/macro-core/macro-action-clipboard.cpp
Normal file
256
src/macro-core/macro-action-clipboard.cpp
Normal file
@@ -0,0 +1,256 @@
|
||||
#include "macro-action-clipboard.hpp"
|
||||
#include "curl-helper.hpp"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QImage>
|
||||
#include <QMimeData>
|
||||
|
||||
namespace advss {
|
||||
|
||||
const std::string MacroActionClipboard::id = "clipboard";
|
||||
|
||||
bool MacroActionClipboard::_registered = MacroActionFactory::Register(
|
||||
MacroActionClipboard::id,
|
||||
{MacroActionClipboard::Create, MacroActionClipboardEdit::Create,
|
||||
"AdvSceneSwitcher.action.clipboard"});
|
||||
|
||||
const static std::map<MacroActionClipboard::Action, std::string> actionTypes = {
|
||||
{MacroActionClipboard::Action::COPY_TEXT,
|
||||
"AdvSceneSwitcher.action.clipboard.type.copy.text"},
|
||||
{MacroActionClipboard::Action::COPY_IMAGE,
|
||||
"AdvSceneSwitcher.action.clipboard.type.copy.image"},
|
||||
};
|
||||
|
||||
static size_t writeCallback(void *ptr, size_t size, size_t nmemb,
|
||||
QByteArray *buffer)
|
||||
{
|
||||
buffer->append((char *)ptr, nmemb);
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
static std::optional<QImage> getImageFromUrl(const char *url)
|
||||
{
|
||||
QByteArray response;
|
||||
|
||||
CurlHelper::SetOpt(CURLOPT_URL, url);
|
||||
CurlHelper::SetOpt(CURLOPT_HTTPGET, 1L);
|
||||
CurlHelper::SetOpt(CURLOPT_TIMEOUT_MS, 30000);
|
||||
CurlHelper::SetOpt(CURLOPT_WRITEFUNCTION, writeCallback);
|
||||
CurlHelper::SetOpt(CURLOPT_WRITEDATA, &response);
|
||||
auto code = CurlHelper::Perform();
|
||||
|
||||
if (code != CURLE_OK) {
|
||||
blog(LOG_WARNING,
|
||||
"Retrieving image failed in %s with error: %s", __func__,
|
||||
CurlHelper::GetError(code));
|
||||
return {};
|
||||
}
|
||||
|
||||
return QImage::fromData(response);
|
||||
}
|
||||
|
||||
static void setMimeTypeParams(ClipboardQueueParams *params,
|
||||
QClipboard *clipboard)
|
||||
{
|
||||
auto mimeData = clipboard->mimeData();
|
||||
if (!mimeData) {
|
||||
return;
|
||||
}
|
||||
auto mimeTypeList = mimeData->formats();
|
||||
if (mimeTypeList.empty()) {
|
||||
return;
|
||||
}
|
||||
params->mimeTypePrimary = mimeTypeList.first().toStdString();
|
||||
params->mimeTypeAll = mimeTypeList.join(" ").toStdString();
|
||||
}
|
||||
|
||||
static void copyText(void *param)
|
||||
{
|
||||
auto params = static_cast<ClipboardTextQueueParams *>(param);
|
||||
QClipboard *clipboard = QApplication::clipboard();
|
||||
|
||||
clipboard->setText(params->text.c_str());
|
||||
|
||||
setMimeTypeParams(params, clipboard);
|
||||
}
|
||||
|
||||
static void copyImageFromUrl(void *param)
|
||||
{
|
||||
auto params = static_cast<ClipboardImageQueueParams *>(param);
|
||||
auto url = params->url.c_str();
|
||||
auto image = getImageFromUrl(url);
|
||||
|
||||
if (!image || (*image).isNull()) {
|
||||
blog(LOG_WARNING, "Failed to convert %s URL to image!", url);
|
||||
return;
|
||||
}
|
||||
|
||||
QClipboard *clipboard = QApplication::clipboard();
|
||||
clipboard->setImage(*image);
|
||||
|
||||
setMimeTypeParams(params, clipboard);
|
||||
}
|
||||
|
||||
bool MacroActionClipboard::PerformAction()
|
||||
{
|
||||
switch (_action) {
|
||||
case Action::COPY_TEXT: {
|
||||
ClipboardTextQueueParams params{"", "", _text};
|
||||
obs_queue_task(OBS_TASK_UI, copyText, ¶ms, true);
|
||||
SetTempVarValues(params);
|
||||
break;
|
||||
}
|
||||
case Action::COPY_IMAGE: {
|
||||
ClipboardImageQueueParams params{"", "", _url};
|
||||
obs_queue_task(OBS_TASK_UI, copyImageFromUrl, ¶ms, true);
|
||||
SetTempVarValues(params);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MacroActionClipboard::SetupTempVars()
|
||||
{
|
||||
MacroAction::SetupTempVars();
|
||||
|
||||
AddTempvar(
|
||||
"mimeType.primary",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.clipboard.mimeType.primary"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.clipboard.mimeType.primary.description"));
|
||||
AddTempvar(
|
||||
"mimeType.all",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.clipboard.mimeType.all"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.clipboard.mimeType.all.description"));
|
||||
}
|
||||
|
||||
void MacroActionClipboard::SetTempVarValues(const ClipboardQueueParams ¶ms)
|
||||
{
|
||||
SetTempVarValue("mimeType.primary", params.mimeTypePrimary);
|
||||
SetTempVarValue("mimeType.all", params.mimeTypeAll);
|
||||
}
|
||||
|
||||
bool MacroActionClipboard::Save(obs_data_t *obj) const
|
||||
{
|
||||
MacroAction::Save(obj);
|
||||
obs_data_set_int(obj, "action", static_cast<int>(_action));
|
||||
_text.Save(obj, "text");
|
||||
_url.Save(obj, "url");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacroActionClipboard::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroAction::Load(obj);
|
||||
_action = static_cast<Action>(obs_data_get_int(obj, "action"));
|
||||
_text.Load(obj, "text");
|
||||
_url.Load(obj, "url");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void populateActionSelection(QComboBox *list)
|
||||
{
|
||||
for (const auto &[action, name] : actionTypes) {
|
||||
list->addItem(obs_module_text(name.c_str()),
|
||||
static_cast<int>(action));
|
||||
}
|
||||
}
|
||||
|
||||
MacroActionClipboardEdit::MacroActionClipboardEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroActionClipboard> entryData)
|
||||
: QWidget(parent),
|
||||
_actions(new FilterComboBox(this)),
|
||||
_text(new VariableLineEdit(this)),
|
||||
_url(new VariableLineEdit(this))
|
||||
{
|
||||
populateActionSelection(_actions);
|
||||
_url->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.action.clipboard.copy.image.url.tooltip"));
|
||||
|
||||
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(ActionChanged(int)));
|
||||
QWidget::connect(_text, SIGNAL(editingFinished()), this,
|
||||
SLOT(TextChanged()));
|
||||
QWidget::connect(_url, SIGNAL(editingFinished()), this,
|
||||
SLOT(UrlChanged()));
|
||||
|
||||
auto mainLayout = new QHBoxLayout();
|
||||
mainLayout->addWidget(_actions);
|
||||
mainLayout->addWidget(_text);
|
||||
mainLayout->addWidget(_url);
|
||||
setLayout(mainLayout);
|
||||
|
||||
_entryData = entryData;
|
||||
UpdateEntryData();
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
void MacroActionClipboardEdit::ActionChanged(int index)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_action = static_cast<MacroActionClipboard::Action>(
|
||||
_actions->itemData(index).toInt());
|
||||
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionClipboardEdit::TextChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_text = _text->text().toStdString();
|
||||
}
|
||||
|
||||
void MacroActionClipboardEdit::UrlChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_url = _url->text().toStdString();
|
||||
}
|
||||
|
||||
void MacroActionClipboardEdit::SetWidgetVisibility()
|
||||
{
|
||||
_text->setVisible(_entryData->_action ==
|
||||
MacroActionClipboard::Action::COPY_TEXT);
|
||||
_url->setVisible(_entryData->_action ==
|
||||
MacroActionClipboard::Action::COPY_IMAGE);
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void MacroActionClipboardEdit::UpdateEntryData()
|
||||
{
|
||||
if (!_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
_actions->setCurrentIndex(
|
||||
_actions->findData(static_cast<int>(_entryData->_action)));
|
||||
_text->setText(_entryData->_text);
|
||||
_url->setText(_entryData->_url);
|
||||
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
89
src/macro-core/macro-action-clipboard.hpp
Normal file
89
src/macro-core/macro-action-clipboard.hpp
Normal file
@@ -0,0 +1,89 @@
|
||||
#pragma once
|
||||
#include "macro-action-edit.hpp"
|
||||
#include "filter-combo-box.hpp"
|
||||
|
||||
#include <variable-line-edit.hpp>
|
||||
|
||||
namespace advss {
|
||||
|
||||
struct ClipboardQueueParams {
|
||||
std::string mimeTypePrimary;
|
||||
std::string mimeTypeAll;
|
||||
};
|
||||
|
||||
struct ClipboardTextQueueParams : ClipboardQueueParams {
|
||||
StringVariable text;
|
||||
};
|
||||
|
||||
struct ClipboardImageQueueParams : ClipboardQueueParams {
|
||||
StringVariable url;
|
||||
};
|
||||
|
||||
class MacroActionClipboard : public MacroAction {
|
||||
public:
|
||||
MacroActionClipboard(Macro *m) : MacroAction(m) {}
|
||||
static std::shared_ptr<MacroAction> Create(Macro *m)
|
||||
{
|
||||
return std::make_shared<MacroActionClipboard>(m);
|
||||
}
|
||||
std::string GetId() const { return id; };
|
||||
|
||||
bool PerformAction();
|
||||
bool Save(obs_data_t *obj) const;
|
||||
bool Load(obs_data_t *obj);
|
||||
|
||||
enum class Action {
|
||||
COPY_TEXT,
|
||||
COPY_IMAGE,
|
||||
};
|
||||
|
||||
Action _action = Action::COPY_TEXT;
|
||||
|
||||
StringVariable _text = obs_module_text(
|
||||
"AdvSceneSwitcher.action.clipboard.copy.text.text.placeholder");
|
||||
StringVariable _url = obs_module_text(
|
||||
"AdvSceneSwitcher.action.clipboard.copy.image.url.placeholder");
|
||||
|
||||
private:
|
||||
void SetupTempVars();
|
||||
void SetTempVarValues(const ClipboardQueueParams ¶ms);
|
||||
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
class MacroActionClipboardEdit : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MacroActionClipboardEdit(
|
||||
QWidget *parent,
|
||||
std::shared_ptr<MacroActionClipboard> entryData = nullptr);
|
||||
static QWidget *Create(QWidget *parent,
|
||||
std::shared_ptr<MacroAction> action)
|
||||
{
|
||||
return new MacroActionClipboardEdit(
|
||||
parent, std::dynamic_pointer_cast<MacroActionClipboard>(
|
||||
action));
|
||||
}
|
||||
void UpdateEntryData();
|
||||
|
||||
protected:
|
||||
std::shared_ptr<MacroActionClipboard> _entryData;
|
||||
|
||||
private slots:
|
||||
void ActionChanged(int index);
|
||||
void TextChanged();
|
||||
void UrlChanged();
|
||||
|
||||
private:
|
||||
void SetWidgetVisibility();
|
||||
|
||||
bool _loading = true;
|
||||
|
||||
FilterComboBox *_actions;
|
||||
VariableLineEdit *_text;
|
||||
VariableLineEdit *_url;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "macro-action-edit.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "macro-properties.hpp"
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "macro-action-scene-switch.hpp"
|
||||
#include "section.hpp"
|
||||
#include "switch-button.hpp"
|
||||
@@ -10,61 +12,9 @@
|
||||
|
||||
namespace advss {
|
||||
|
||||
std::map<std::string, MacroActionInfo> &MacroActionFactory::GetMap()
|
||||
{
|
||||
static std::map<std::string, MacroActionInfo> _methods;
|
||||
return _methods;
|
||||
}
|
||||
|
||||
bool MacroActionFactory::Register(const std::string &id, MacroActionInfo info)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it == GetMap().end()) {
|
||||
GetMap()[id] = info;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroAction> MacroActionFactory::Create(const std::string &id,
|
||||
Macro *m)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it != GetMap().end())
|
||||
return it->second._createFunc(m);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QWidget *MacroActionFactory::CreateWidget(const std::string &id,
|
||||
QWidget *parent,
|
||||
std::shared_ptr<MacroAction> action)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it != GetMap().end())
|
||||
return it->second._createWidgetFunc(parent, action);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string MacroActionFactory::GetActionName(const std::string &id)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||
return it->second._name;
|
||||
}
|
||||
return "unknown action";
|
||||
}
|
||||
|
||||
std::string MacroActionFactory::GetIdByName(const QString &name)
|
||||
{
|
||||
for (auto it : GetMap()) {
|
||||
if (name == obs_module_text(it.second._name.c_str())) {
|
||||
return it.first;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static inline void populateActionSelection(QComboBox *list)
|
||||
{
|
||||
for (auto &[_, action] : MacroActionFactory::GetActionTypes()) {
|
||||
for (const auto &[_, action] : MacroActionFactory::GetActionTypes()) {
|
||||
QString entry(obs_module_text(action._name.c_str()));
|
||||
if (list->findText(entry) == -1) {
|
||||
list->addItem(entry);
|
||||
@@ -80,7 +30,8 @@ static inline void populateActionSelection(QComboBox *list)
|
||||
MacroActionEdit::MacroActionEdit(QWidget *parent,
|
||||
std::shared_ptr<MacroAction> *entryData,
|
||||
const std::string &id)
|
||||
: MacroSegmentEdit(switcher->macroProperties._highlightActions, parent),
|
||||
: MacroSegmentEdit(GetGlobalMacroProperties()._highlightActions,
|
||||
parent),
|
||||
_actionSelection(new FilterComboBox()),
|
||||
_enable(new SwitchButton()),
|
||||
_entryData(entryData)
|
||||
@@ -134,10 +85,11 @@ void MacroActionEdit::ActionSelectionChanged(const QString &text)
|
||||
auto idx = _entryData->get()->GetIndex();
|
||||
auto macro = _entryData->get()->GetMacro();
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->reset();
|
||||
*_entryData = MacroActionFactory::Create(id, macro);
|
||||
(*_entryData)->SetIndex(idx);
|
||||
(*_entryData)->PostLoad();
|
||||
}
|
||||
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
|
||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||
@@ -184,7 +136,7 @@ void MacroActionEdit::ActionEnableChanged(bool value)
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
(*_entryData)->SetEnabled(value);
|
||||
SetDisableEffect(!value);
|
||||
}
|
||||
@@ -204,7 +156,7 @@ void MacroActionEdit::SetEnableAppearance(bool value)
|
||||
SetDisableEffect(!value);
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroSegment> MacroActionEdit::Data()
|
||||
std::shared_ptr<MacroSegment> MacroActionEdit::Data() const
|
||||
{
|
||||
return *_entryData;
|
||||
}
|
||||
@@ -228,7 +180,7 @@ void AdvSceneSwitcher::AddMacroAction(int idx)
|
||||
id = temp.GetId();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
macro->Actions().emplace(
|
||||
macro->Actions().begin() + idx,
|
||||
MacroActionFactory::Create(id, macro.get()));
|
||||
@@ -236,10 +188,11 @@ void AdvSceneSwitcher::AddMacroAction(int idx)
|
||||
auto data = obs_data_create();
|
||||
macro->Actions().at(idx - 1)->Save(data);
|
||||
macro->Actions().at(idx)->Load(data);
|
||||
macro->Actions().at(idx)->PostLoad();
|
||||
obs_data_release(data);
|
||||
}
|
||||
macro->UpdateActionIndices();
|
||||
actionsList->Insert(
|
||||
ui->actionsList->Insert(
|
||||
idx,
|
||||
new MacroActionEdit(this, ¯o->Actions()[idx], id));
|
||||
SetActionData(*macro);
|
||||
@@ -263,7 +216,7 @@ void AdvSceneSwitcher::on_actionAdd_clicked()
|
||||
if (currentActionIdx != -1) {
|
||||
MacroActionSelectionChanged(currentActionIdx + 1);
|
||||
}
|
||||
actionsList->SetHelpMsgVisible(false);
|
||||
ui->actionsList->SetHelpMsgVisible(false);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::RemoveMacroAction(int idx)
|
||||
@@ -278,11 +231,11 @@ void AdvSceneSwitcher::RemoveMacroAction(int idx)
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
actionsList->Remove(idx);
|
||||
auto lock = LockContext();
|
||||
ui->actionsList->Remove(idx);
|
||||
macro->Actions().erase(macro->Actions().begin() + idx);
|
||||
switcher->abortMacroWait = true;
|
||||
switcher->macroWaitCv.notify_all();
|
||||
SetMacroAbortWait(true);
|
||||
GetMacroWaitCV().notify_all();
|
||||
macro->UpdateActionIndices();
|
||||
SetActionData(*macro);
|
||||
}
|
||||
@@ -322,10 +275,11 @@ void AdvSceneSwitcher::on_actionUp_clicked()
|
||||
MoveMacroActionUp(currentActionIdx);
|
||||
MacroActionSelectionChanged(currentActionIdx - 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_actionDown_clicked()
|
||||
{
|
||||
if (currentActionIdx == -1 ||
|
||||
currentActionIdx == actionsList->ContentLayout()->count() - 1) {
|
||||
currentActionIdx == ui->actionsList->ContentLayout()->count() - 1) {
|
||||
return;
|
||||
}
|
||||
MoveMacroActionDown(currentActionIdx);
|
||||
@@ -337,11 +291,82 @@ void AdvSceneSwitcher::on_actionBottom_clicked()
|
||||
if (currentActionIdx == -1) {
|
||||
return;
|
||||
}
|
||||
const int newIdx = actionsList->ContentLayout()->count() - 1;
|
||||
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);
|
||||
}
|
||||
ui->elseActionsList->SetHelpMsgVisible(false);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_elseActionRemove_clicked()
|
||||
{
|
||||
if (currentElseActionIdx == -1) {
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
RemoveMacroElseAction((int)macro->Actions().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) {
|
||||
@@ -351,15 +376,15 @@ void AdvSceneSwitcher::SwapActions(Macro *m, int pos1, int pos2)
|
||||
std::swap(pos1, pos2);
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
iter_swap(m->Actions().begin() + pos1, m->Actions().begin() + pos2);
|
||||
m->UpdateActionIndices();
|
||||
auto widget1 = static_cast<MacroActionEdit *>(
|
||||
actionsList->ContentLayout()->takeAt(pos1)->widget());
|
||||
ui->actionsList->ContentLayout()->takeAt(pos1)->widget());
|
||||
auto widget2 = static_cast<MacroActionEdit *>(
|
||||
actionsList->ContentLayout()->takeAt(pos2 - 1)->widget());
|
||||
actionsList->Insert(pos1, widget2);
|
||||
actionsList->Insert(pos2, widget1);
|
||||
ui->actionsList->ContentLayout()->takeAt(pos2 - 1)->widget());
|
||||
ui->actionsList->Insert(pos1, widget2);
|
||||
ui->actionsList->Insert(pos2, widget1);
|
||||
SetActionData(*m);
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
@@ -394,24 +419,159 @@ void AdvSceneSwitcher::MoveMacroActionDown(int idx)
|
||||
HighlightAction(idx + 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MacroActionSelectionChanged(int idx)
|
||||
void AdvSceneSwitcher::MacroElseActionSelectionChanged(int idx)
|
||||
{
|
||||
SetupMacroSegmentSelection(MacroSection::ELSE_ACTIONS, idx);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MacroElseActionReorder(int to, int from)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
actionsList->SetSelection(idx);
|
||||
conditionsList->SetSelection(-1);
|
||||
|
||||
if (idx < 0 || (unsigned)idx >= macro->Actions().size()) {
|
||||
currentActionIdx = -1;
|
||||
} else {
|
||||
currentActionIdx = idx;
|
||||
lastInteracted = MacroSection::ACTIONS;
|
||||
if (to == from || from < 0 || from > (int)macro->ElseActions().size() ||
|
||||
to < 0 || to > (int)macro->ElseActions().size()) {
|
||||
return;
|
||||
}
|
||||
currentConditionIdx = -1;
|
||||
HighlightControls();
|
||||
{
|
||||
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(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 0 || idx > (int)macro->ElseActions().size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string id;
|
||||
if (idx - 1 >= 0) {
|
||||
id = macro->ElseActions().at(idx - 1)->GetId();
|
||||
} else {
|
||||
MacroActionSwitchScene temp(nullptr);
|
||||
id = temp.GetId();
|
||||
}
|
||||
{
|
||||
auto lock = LockContext();
|
||||
macro->ElseActions().emplace(
|
||||
macro->ElseActions().begin() + idx,
|
||||
MacroActionFactory::Create(id, macro.get()));
|
||||
if (idx - 1 >= 0) {
|
||||
OBSDataAutoRelease data = obs_data_create();
|
||||
macro->ElseActions().at(idx - 1)->Save(data);
|
||||
macro->ElseActions().at(idx)->Load(data);
|
||||
}
|
||||
macro->ElseActions().at(idx)->PostLoad();
|
||||
macro->UpdateElseActionIndices();
|
||||
ui->elseActionsList->Insert(
|
||||
idx, new MacroActionEdit(
|
||||
this, ¯o->ElseActions()[idx], id));
|
||||
SetElseActionData(*macro);
|
||||
}
|
||||
HighlightElseAction(idx);
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
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();
|
||||
SetActionData(*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)
|
||||
@@ -426,13 +586,13 @@ void AdvSceneSwitcher::MacroActionReorder(int to, int from)
|
||||
return;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
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();
|
||||
actionsList->ContentLayout()->insertItem(
|
||||
to, actionsList->ContentLayout()->takeAt(from));
|
||||
ui->actionsList->ContentLayout()->insertItem(
|
||||
to, ui->actionsList->ContentLayout()->takeAt(from));
|
||||
SetActionData(*macro);
|
||||
}
|
||||
HighlightAction(to);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "macro-action.hpp"
|
||||
#include "macro-action-factory.hpp"
|
||||
#include "filter-combo-box.hpp"
|
||||
|
||||
#include <memory>
|
||||
@@ -8,32 +9,6 @@ namespace advss {
|
||||
|
||||
class SwitchButton;
|
||||
|
||||
struct MacroActionInfo {
|
||||
using TCreateMethod = std::shared_ptr<MacroAction> (*)(Macro *m);
|
||||
using TCreateWidgetMethod = QWidget *(*)(QWidget *parent,
|
||||
std::shared_ptr<MacroAction>);
|
||||
TCreateMethod _createFunc = nullptr;
|
||||
TCreateWidgetMethod _createWidgetFunc = nullptr;
|
||||
std::string _name;
|
||||
};
|
||||
|
||||
class MacroActionFactory {
|
||||
public:
|
||||
MacroActionFactory() = delete;
|
||||
|
||||
static bool Register(const std::string &id, MacroActionInfo);
|
||||
static std::shared_ptr<MacroAction> Create(const std::string &id,
|
||||
Macro *m);
|
||||
static QWidget *CreateWidget(const std::string &id, QWidget *parent,
|
||||
std::shared_ptr<MacroAction> action);
|
||||
static auto GetActionTypes() { return GetMap(); }
|
||||
static std::string GetActionName(const std::string &id);
|
||||
static std::string GetIdByName(const QString &name);
|
||||
|
||||
private:
|
||||
static std::map<std::string, MacroActionInfo> &GetMap();
|
||||
};
|
||||
|
||||
class MacroActionEdit : public MacroSegmentEdit {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -50,7 +25,7 @@ private slots:
|
||||
void UpdateActionState();
|
||||
|
||||
private:
|
||||
std::shared_ptr<MacroSegment> Data();
|
||||
std::shared_ptr<MacroSegment> Data() const;
|
||||
void SetDisableEffect(bool);
|
||||
void SetEnableAppearance(bool);
|
||||
|
||||
|
||||
57
src/macro-core/macro-action-factory.cpp
Normal file
57
src/macro-core/macro-action-factory.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
#include "macro-action-factory.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
std::map<std::string, MacroActionInfo> &MacroActionFactory::GetMap()
|
||||
{
|
||||
static std::map<std::string, MacroActionInfo> _methods;
|
||||
return _methods;
|
||||
}
|
||||
|
||||
bool MacroActionFactory::Register(const std::string &id, MacroActionInfo info)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it == GetMap().end()) {
|
||||
GetMap()[id] = info;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroAction> MacroActionFactory::Create(const std::string &id,
|
||||
Macro *m)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it != GetMap().end())
|
||||
return it->second._create(m);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QWidget *MacroActionFactory::CreateWidget(const std::string &id,
|
||||
QWidget *parent,
|
||||
std::shared_ptr<MacroAction> action)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it != GetMap().end())
|
||||
return it->second._createWidget(parent, action);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string MacroActionFactory::GetActionName(const std::string &id)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||
return it->second._name;
|
||||
}
|
||||
return "unknown action";
|
||||
}
|
||||
|
||||
std::string MacroActionFactory::GetIdByName(const QString &name)
|
||||
{
|
||||
for (auto it : GetMap()) {
|
||||
if (name == obs_module_text(it.second._name.c_str())) {
|
||||
return it.first;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
34
src/macro-core/macro-action-factory.hpp
Normal file
34
src/macro-core/macro-action-factory.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
#include "macro-action.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace advss {
|
||||
|
||||
struct MacroActionInfo {
|
||||
using CreateAction = std::shared_ptr<MacroAction> (*)(Macro *m);
|
||||
using CreateActionWidget = QWidget *(*)(QWidget *parent,
|
||||
std::shared_ptr<MacroAction>);
|
||||
CreateAction _create = nullptr;
|
||||
CreateActionWidget _createWidget = nullptr;
|
||||
std::string _name;
|
||||
};
|
||||
|
||||
class MacroActionFactory {
|
||||
public:
|
||||
MacroActionFactory() = delete;
|
||||
|
||||
static bool Register(const std::string &id, MacroActionInfo);
|
||||
static std::shared_ptr<MacroAction> Create(const std::string &id,
|
||||
Macro *m);
|
||||
static QWidget *CreateWidget(const std::string &id, QWidget *parent,
|
||||
std::shared_ptr<MacroAction> action);
|
||||
static auto GetActionTypes() { return GetMap(); }
|
||||
static std::string GetActionName(const std::string &id);
|
||||
static std::string GetIdByName(const QString &name);
|
||||
|
||||
private:
|
||||
static std::map<std::string, MacroActionInfo> &GetMap();
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
@@ -21,26 +21,69 @@ const static std::map<MacroActionFilter::Action, std::string> actionTypes = {
|
||||
"AdvSceneSwitcher.action.filter.type.settings"},
|
||||
};
|
||||
|
||||
bool MacroActionFilter::PerformAction()
|
||||
const static std::map<MacroActionFilter::SettingsInputMethod, std::string>
|
||||
inputMethods = {
|
||||
{MacroActionFilter::SettingsInputMethod::INDIVIDUAL_MANUAL,
|
||||
"AdvSceneSwitcher.action.filter.inputMethod.individualManual"},
|
||||
{MacroActionFilter::SettingsInputMethod::INDIVIDUAL_TEMPVAR,
|
||||
"AdvSceneSwitcher.action.filter.inputMethod.individualTempvar"},
|
||||
{MacroActionFilter::SettingsInputMethod::JSON_STRING,
|
||||
"AdvSceneSwitcher.action.filter.inputMethod.json"},
|
||||
};
|
||||
|
||||
static void performActionHelper(
|
||||
MacroActionFilter::Action action, const OBSWeakSource &filter,
|
||||
MacroActionFilter::SettingsInputMethod settingsInputMethod,
|
||||
const SourceSetting &setting, const std::string &manualSettingValue,
|
||||
const TempVariableRef &tempVar, Macro *macro,
|
||||
const StringVariable &settingsString)
|
||||
{
|
||||
auto s = obs_weak_source_get_source(_filter.GetFilter(_source));
|
||||
switch (_action) {
|
||||
case Action::ENABLE:
|
||||
obs_source_set_enabled(s, true);
|
||||
OBSSourceAutoRelease source = obs_weak_source_get_source(filter);
|
||||
switch (action) {
|
||||
case MacroActionFilter::Action::ENABLE:
|
||||
obs_source_set_enabled(source, true);
|
||||
break;
|
||||
case Action::DISABLE:
|
||||
obs_source_set_enabled(s, false);
|
||||
case MacroActionFilter::Action::DISABLE:
|
||||
obs_source_set_enabled(source, false);
|
||||
break;
|
||||
case Action::TOGGLE:
|
||||
obs_source_set_enabled(s, !obs_source_enabled(s));
|
||||
case MacroActionFilter::Action::TOGGLE:
|
||||
obs_source_set_enabled(source, !obs_source_enabled(source));
|
||||
break;
|
||||
case Action::SETTINGS:
|
||||
SetSourceSettings(s, _settings);
|
||||
case MacroActionFilter::Action::SETTINGS:
|
||||
switch (settingsInputMethod) {
|
||||
case MacroActionFilter::SettingsInputMethod::INDIVIDUAL_MANUAL:
|
||||
SetSourceSetting(source, setting, manualSettingValue);
|
||||
break;
|
||||
case MacroActionFilter::SettingsInputMethod::INDIVIDUAL_TEMPVAR: {
|
||||
auto var = tempVar.GetTempVariable(macro);
|
||||
if (!var) {
|
||||
break;
|
||||
}
|
||||
auto value = var->Value();
|
||||
if (!value) {
|
||||
break;
|
||||
}
|
||||
SetSourceSetting(source, setting, *value);
|
||||
break;
|
||||
}
|
||||
case MacroActionFilter::SettingsInputMethod::JSON_STRING:
|
||||
SetSourceSettings(source, settingsString);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
obs_source_release(s);
|
||||
}
|
||||
|
||||
bool MacroActionFilter::PerformAction()
|
||||
{
|
||||
auto filters = _filter.GetFilters(_source);
|
||||
for (const auto &filter : filters) {
|
||||
performActionHelper(_action, filter, _settingsInputMethod,
|
||||
_setting, _manualSettingValue, _tempVar,
|
||||
GetMacro(), _settingsString);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -64,7 +107,12 @@ bool MacroActionFilter::Save(obs_data_t *obj) const
|
||||
_source.Save(obj);
|
||||
_filter.Save(obj, "filter");
|
||||
obs_data_set_int(obj, "action", static_cast<int>(_action));
|
||||
_settings.Save(obj, "settings");
|
||||
obs_data_set_int(obj, "inputMethod",
|
||||
static_cast<int>(_settingsInputMethod));
|
||||
_setting.Save(obj);
|
||||
_manualSettingValue.Save(obj, "manualSettingValue");
|
||||
_tempVar.Save(obj);
|
||||
_settingsString.Save(obj, "settings");
|
||||
obs_data_set_int(obj, "version", 1);
|
||||
return true;
|
||||
}
|
||||
@@ -85,7 +133,17 @@ bool MacroActionFilter::Load(obs_data_t *obj)
|
||||
} else {
|
||||
_action = static_cast<Action>(obs_data_get_int(obj, "action"));
|
||||
}
|
||||
_settings.Load(obj, "settings");
|
||||
// TODO: Remove fallback in future version
|
||||
if (obs_data_has_user_value(obj, "inputMethod")) {
|
||||
_settingsInputMethod = static_cast<SettingsInputMethod>(
|
||||
obs_data_get_int(obj, "inputMethod"));
|
||||
} else {
|
||||
_settingsInputMethod = SettingsInputMethod::JSON_STRING;
|
||||
}
|
||||
_setting.Load(obj);
|
||||
_settingsString.Load(obj, "settings");
|
||||
_manualSettingValue.Load(obj, "manualSettingValue");
|
||||
_tempVar.Load(obj, GetMacro());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -104,6 +162,15 @@ static inline void populateActionSelection(QComboBox *list)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void populateSettingsInputMethods(QComboBox *list)
|
||||
{
|
||||
list->clear();
|
||||
for (const auto &[value, name] : inputMethods) {
|
||||
list->addItem(obs_module_text(name.c_str()),
|
||||
static_cast<int>(value));
|
||||
}
|
||||
}
|
||||
|
||||
MacroActionFilterEdit::MacroActionFilterEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroActionFilter> entryData)
|
||||
: QWidget(parent),
|
||||
@@ -112,7 +179,12 @@ MacroActionFilterEdit::MacroActionFilterEdit(
|
||||
_actions(new QComboBox()),
|
||||
_getSettings(new QPushButton(obs_module_text(
|
||||
"AdvSceneSwitcher.action.filter.getSettings"))),
|
||||
_settings(new VariableTextEdit(this))
|
||||
_settingsLayout(new QHBoxLayout()),
|
||||
_settingsInputMethods(new QComboBox(this)),
|
||||
_manualSettingValue(new VariableTextEdit(this, 5, 1, 1)),
|
||||
_tempVars(new TempVariableSelection(this)),
|
||||
_filterSettings(new SourceSettingSelection(this)),
|
||||
_settingsString(new VariableTextEdit(this))
|
||||
{
|
||||
_filters->setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||
|
||||
@@ -121,6 +193,8 @@ MacroActionFilterEdit::MacroActionFilterEdit(
|
||||
sources.sort();
|
||||
_sources->SetSourceNameList(sources);
|
||||
|
||||
populateSettingsInputMethods(_settingsInputMethods);
|
||||
|
||||
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(ActionChanged(int)));
|
||||
QWidget::connect(_sources,
|
||||
@@ -131,27 +205,48 @@ MacroActionFilterEdit::MacroActionFilterEdit(
|
||||
SLOT(FilterChanged(const FilterSelection &)));
|
||||
QWidget::connect(_getSettings, SIGNAL(clicked()), this,
|
||||
SLOT(GetSettingsClicked()));
|
||||
QWidget::connect(_settings, SIGNAL(textChanged()), this,
|
||||
SLOT(SettingsChanged()));
|
||||
QWidget::connect(_settingsString, SIGNAL(textChanged()), this,
|
||||
SLOT(SettingsStringChanged()));
|
||||
QWidget::connect(_tempVars,
|
||||
SIGNAL(SelectionChanged(const TempVariableRef &)),
|
||||
this, SLOT(SelectionChanged(const TempVariableRef &)));
|
||||
QWidget::connect(_settingsInputMethods,
|
||||
SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(SettingsInputMethodChanged(int)));
|
||||
QWidget::connect(_manualSettingValue, SIGNAL(textChanged()), this,
|
||||
SLOT(ManualSettingsValueChanged()));
|
||||
QWidget::connect(_filterSettings,
|
||||
SIGNAL(SelectionChanged(const SourceSetting &)), this,
|
||||
SLOT(SelectionChanged(const SourceSetting &)));
|
||||
|
||||
QHBoxLayout *entryLayout = new QHBoxLayout;
|
||||
auto entrylayout = new QHBoxLayout;
|
||||
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{sources}}", _sources}, {"{{filters}}", _filters},
|
||||
{"{{actions}}", _actions}, {"{{settings}}", _settings},
|
||||
{"{{sources}}", _sources},
|
||||
{"{{filters}}", _filters},
|
||||
{"{{actions}}", _actions},
|
||||
{"{{settings}}", _filterSettings},
|
||||
{"{{settingsInputMethod}}", _settingsInputMethods},
|
||||
{"{{settingValue}}", _manualSettingValue},
|
||||
{"{{tempVar}}", _tempVars},
|
||||
{"{{getSettings}}", _getSettings},
|
||||
};
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.filter.entry"),
|
||||
entryLayout, widgetPlaceholders);
|
||||
entrylayout, widgetPlaceholders);
|
||||
_settingsLayout->setContentsMargins(0, 0, 0, 0);
|
||||
PlaceWidgets(obs_module_text(
|
||||
"AdvSceneSwitcher.action.filter.entry.settings"),
|
||||
_settingsLayout, widgetPlaceholders);
|
||||
|
||||
QHBoxLayout *buttonLayout = new QHBoxLayout;
|
||||
auto buttonLayout = new QHBoxLayout;
|
||||
buttonLayout->addWidget(_getSettings);
|
||||
buttonLayout->addStretch();
|
||||
buttonLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(entryLayout);
|
||||
mainLayout->addWidget(_settings);
|
||||
auto mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(entrylayout);
|
||||
mainLayout->addLayout(_settingsLayout);
|
||||
mainLayout->addWidget(_settingsString);
|
||||
mainLayout->addLayout(buttonLayout);
|
||||
setLayout(mainLayout);
|
||||
|
||||
@@ -169,12 +264,16 @@ void MacroActionFilterEdit::UpdateEntryData()
|
||||
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
|
||||
_sources->SetSource(_entryData->_source);
|
||||
_filters->SetFilter(_entryData->_source, _entryData->_filter);
|
||||
_settings->setPlainText(_entryData->_settings);
|
||||
SetWidgetVisibility(_entryData->_action ==
|
||||
MacroActionFilter::Action::SETTINGS);
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
_settingsString->setPlainText(_entryData->_settingsString);
|
||||
const auto filters =
|
||||
_entryData->_filter.GetFilters(_entryData->_source);
|
||||
_filterSettings->SetSource(filters.empty() ? nullptr : filters.at(0));
|
||||
_filterSettings->SetSetting(_entryData->_setting);
|
||||
_settingsInputMethods->setCurrentIndex(_settingsInputMethods->findData(
|
||||
static_cast<int>(_entryData->_settingsInputMethod)));
|
||||
_tempVars->SetVariable(_entryData->_tempVar);
|
||||
_manualSettingValue->setPlainText(_entryData->_manualSettingValue);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionFilterEdit::SourceChanged(const SourceSelection &source)
|
||||
@@ -193,8 +292,13 @@ void MacroActionFilterEdit::FilterChanged(const FilterSelection &filter)
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_filter = filter;
|
||||
{
|
||||
auto lock = LockContext();
|
||||
_entryData->_filter = filter;
|
||||
}
|
||||
const auto filters =
|
||||
_entryData->_filter.GetFilters(_entryData->_source);
|
||||
_filterSettings->SetSource(filters.empty() ? nullptr : filters.at(0));
|
||||
emit HeaderInfoChanged(
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
}
|
||||
@@ -207,38 +311,130 @@ void MacroActionFilterEdit::ActionChanged(int value)
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_action = static_cast<MacroActionFilter::Action>(value);
|
||||
SetWidgetVisibility(_entryData->_action ==
|
||||
MacroActionFilter::Action::SETTINGS);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionFilterEdit::GetSettingsClicked()
|
||||
{
|
||||
if (_loading || !_entryData ||
|
||||
!_entryData->_filter.GetFilter(_entryData->_source)) {
|
||||
_entryData->_filter.GetFilters(_entryData->_source).empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
_settings->setPlainText(FormatJsonString(GetSourceSettings(
|
||||
_entryData->_filter.GetFilter(_entryData->_source))));
|
||||
switch (_entryData->_settingsInputMethod) {
|
||||
case MacroActionFilter::SettingsInputMethod::INDIVIDUAL_MANUAL: {
|
||||
const auto filters =
|
||||
_entryData->_filter.GetFilters(_entryData->_source);
|
||||
_manualSettingValue->setPlainText(GetSourceSettingValue(
|
||||
filters.empty() ? nullptr : filters.at(0),
|
||||
_entryData->_setting));
|
||||
break;
|
||||
}
|
||||
case MacroActionFilter::SettingsInputMethod::INDIVIDUAL_TEMPVAR:
|
||||
break;
|
||||
case MacroActionFilter::SettingsInputMethod::JSON_STRING: {
|
||||
const auto filters =
|
||||
_entryData->_filter.GetFilters(_entryData->_source);
|
||||
_settingsString->setPlainText(
|
||||
FormatJsonString(GetSourceSettings(
|
||||
filters.empty() ? nullptr : filters.at(0))));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MacroActionFilterEdit::SettingsChanged()
|
||||
void MacroActionFilterEdit::SettingsStringChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_settings = _settings->toPlainText().toStdString();
|
||||
_entryData->_settingsString =
|
||||
_settingsString->toPlainText().toStdString();
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void MacroActionFilterEdit::SetWidgetVisibility(bool showSettings)
|
||||
void MacroActionFilterEdit::SettingsInputMethodChanged(int idx)
|
||||
{
|
||||
_settings->setVisible(showSettings);
|
||||
_getSettings->setVisible(showSettings);
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_settingsInputMethod =
|
||||
static_cast<MacroActionFilter::SettingsInputMethod>(
|
||||
_settingsInputMethods->itemData(idx).toInt());
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionFilterEdit::SelectionChanged(const TempVariableRef &var)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_tempVar = var;
|
||||
}
|
||||
|
||||
void MacroActionFilterEdit::SelectionChanged(const SourceSetting &setting)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_setting = setting;
|
||||
}
|
||||
|
||||
void MacroActionFilterEdit::ManualSettingsValueChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_manualSettingValue =
|
||||
_manualSettingValue->toPlainText().toStdString();
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void MacroActionFilterEdit::SetWidgetVisibility()
|
||||
{
|
||||
SetLayoutVisible(_settingsLayout,
|
||||
_entryData->_action ==
|
||||
MacroActionFilter::Action::SETTINGS);
|
||||
_filterSettings->setVisible(
|
||||
_entryData->_action == MacroActionFilter::Action::SETTINGS &&
|
||||
_entryData->_settingsInputMethod !=
|
||||
MacroActionFilter::SettingsInputMethod::JSON_STRING);
|
||||
_settingsString->setVisible(
|
||||
_entryData->_action == MacroActionFilter::Action::SETTINGS &&
|
||||
_entryData->_settingsInputMethod ==
|
||||
MacroActionFilter::SettingsInputMethod::JSON_STRING);
|
||||
_getSettings->setVisible(_entryData->_action ==
|
||||
MacroActionFilter::Action::SETTINGS);
|
||||
_tempVars->setVisible(_entryData->_action ==
|
||||
MacroActionFilter::Action::SETTINGS &&
|
||||
_entryData->_settingsInputMethod ==
|
||||
MacroActionFilter::SettingsInputMethod::
|
||||
INDIVIDUAL_TEMPVAR);
|
||||
|
||||
if (_entryData->_action == MacroActionFilter::Action::SETTINGS &&
|
||||
_entryData->_settingsInputMethod ==
|
||||
MacroActionFilter::SettingsInputMethod::INDIVIDUAL_MANUAL) {
|
||||
RemoveStretchIfPresent(_settingsLayout);
|
||||
_manualSettingValue->show();
|
||||
} else {
|
||||
AddStretchIfNecessary(_settingsLayout);
|
||||
_manualSettingValue->hide();
|
||||
}
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "variable-text-edit.hpp"
|
||||
#include "source-selection.hpp"
|
||||
#include "filter-selection.hpp"
|
||||
#include "source-setting.hpp"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QSpinBox>
|
||||
@@ -31,10 +32,21 @@ public:
|
||||
SETTINGS,
|
||||
};
|
||||
|
||||
enum class SettingsInputMethod {
|
||||
INDIVIDUAL_MANUAL,
|
||||
INDIVIDUAL_TEMPVAR,
|
||||
JSON_STRING,
|
||||
};
|
||||
SettingsInputMethod _settingsInputMethod =
|
||||
SettingsInputMethod::INDIVIDUAL_MANUAL;
|
||||
|
||||
SourceSelection _source;
|
||||
FilterSelection _filter;
|
||||
Action _action = Action::ENABLE;
|
||||
StringVariable _settings = "";
|
||||
StringVariable _settingsString = "";
|
||||
TempVariableRef _tempVar;
|
||||
StringVariable _manualSettingValue = "";
|
||||
SourceSetting _setting;
|
||||
|
||||
private:
|
||||
static bool _registered;
|
||||
@@ -62,7 +74,11 @@ private slots:
|
||||
void FilterChanged(const FilterSelection &);
|
||||
void ActionChanged(int value);
|
||||
void GetSettingsClicked();
|
||||
void SettingsChanged();
|
||||
void SettingsStringChanged();
|
||||
void SettingsInputMethodChanged(int);
|
||||
void SelectionChanged(const TempVariableRef &);
|
||||
void SelectionChanged(const SourceSetting &);
|
||||
void ManualSettingsValueChanged();
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
|
||||
@@ -71,11 +87,17 @@ protected:
|
||||
FilterSelectionWidget *_filters;
|
||||
QComboBox *_actions;
|
||||
QPushButton *_getSettings;
|
||||
VariableTextEdit *_settings;
|
||||
QHBoxLayout *_settingsLayout;
|
||||
QComboBox *_settingsInputMethods;
|
||||
VariableTextEdit *_manualSettingValue;
|
||||
TempVariableSelection *_tempVars;
|
||||
SourceSettingSelection *_filterSettings;
|
||||
VariableTextEdit *_settingsString;
|
||||
|
||||
std::shared_ptr<MacroActionFilter> _entryData;
|
||||
|
||||
private:
|
||||
void SetWidgetVisibility(bool);
|
||||
void SetWidgetVisibility();
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "platform-funcs.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <thread>
|
||||
#include <obs-interaction.h>
|
||||
|
||||
namespace advss {
|
||||
@@ -13,14 +14,14 @@ bool MacroActionHotkey::_registered = MacroActionFactory::Register(
|
||||
{MacroActionHotkey::Create, MacroActionHotkeyEdit::Create,
|
||||
"AdvSceneSwitcher.action.hotkey"});
|
||||
|
||||
const static std::map<MacroActionHotkey::Action, std::string> actionTypes = {
|
||||
static const std::map<MacroActionHotkey::Action, std::string> actionTypes = {
|
||||
{MacroActionHotkey::Action::OBS_HOTKEY,
|
||||
"AdvSceneSwitcher.action.hotkey.type.obs"},
|
||||
{MacroActionHotkey::Action::CUSTOM,
|
||||
"AdvSceneSwitcher.action.hotkey.type.custom"},
|
||||
};
|
||||
|
||||
const static std::map<obs_hotkey_registerer_type, std::string> hotkeyTypes = {
|
||||
static const std::map<obs_hotkey_registerer_type, std::string> hotkeyTypes = {
|
||||
{OBS_HOTKEY_REGISTERER_FRONTEND,
|
||||
"AdvSceneSwitcher.action.hotkey.type.obs.type.frontend"},
|
||||
{OBS_HOTKEY_REGISTERER_SOURCE,
|
||||
@@ -33,7 +34,7 @@ const static std::map<obs_hotkey_registerer_type, std::string> hotkeyTypes = {
|
||||
"AdvSceneSwitcher.action.hotkey.type.obs.type.service"},
|
||||
};
|
||||
|
||||
static std::unordered_map<HotkeyType, long> keyTable = {
|
||||
static const std::unordered_map<HotkeyType, long> keyTable = {
|
||||
// Chars
|
||||
{HotkeyType::Key_A, OBS_KEY_A},
|
||||
{HotkeyType::Key_B, OBS_KEY_B},
|
||||
@@ -74,6 +75,9 @@ static std::unordered_map<HotkeyType, long> keyTable = {
|
||||
{HotkeyType::Key_8, OBS_KEY_8},
|
||||
{HotkeyType::Key_9, OBS_KEY_9},
|
||||
|
||||
// Other
|
||||
{HotkeyType::Key_Tilde, OBS_KEY_ASCIITILDE},
|
||||
|
||||
{HotkeyType::Key_F1, OBS_KEY_F1},
|
||||
{HotkeyType::Key_F2, OBS_KEY_F2},
|
||||
{HotkeyType::Key_F3, OBS_KEY_F3},
|
||||
@@ -524,6 +528,7 @@ static inline void populateKeySelection(QComboBox *list)
|
||||
list->addItem("NumpadDivide");
|
||||
list->addItem("NumpadDecimal");
|
||||
list->addItem("NumpadEnter");
|
||||
list->addItem("Tilde");
|
||||
}
|
||||
|
||||
static void populateActionSelection(QComboBox *list)
|
||||
@@ -723,7 +728,7 @@ static QString getHotkeyDescriptionByName(const std::string &name)
|
||||
QString description = "";
|
||||
} params;
|
||||
|
||||
auto func = [](void *param, obs_hotkey_id id, obs_hotkey_t *hotkey) {
|
||||
auto func = [](void *param, obs_hotkey_id, obs_hotkey_t *hotkey) {
|
||||
auto params = static_cast<Parameters *>(param);
|
||||
std::string name = obs_hotkey_get_name(hotkey);
|
||||
addNamePrefix(name, hotkey);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "macro-action-http.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "utility.hpp"
|
||||
#include "curl-helper.hpp"
|
||||
|
||||
@@ -36,44 +35,44 @@ void MacroActionHttp::SetupHeaders()
|
||||
}
|
||||
struct curl_slist *headers = nullptr;
|
||||
for (auto &header : _headers) {
|
||||
headers = switcher->curl.SlistAppend(headers, header.c_str());
|
||||
headers = CurlHelper::SlistAppend(headers, header.c_str());
|
||||
}
|
||||
if (!_headers.empty()) {
|
||||
switcher->curl.SetOpt(CURLOPT_HTTPHEADER, headers);
|
||||
CurlHelper::SetOpt(CURLOPT_HTTPHEADER, headers);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroActionHttp::Get()
|
||||
{
|
||||
switcher->curl.SetOpt(CURLOPT_URL, _url.c_str());
|
||||
switcher->curl.SetOpt(CURLOPT_HTTPGET, 1L);
|
||||
switcher->curl.SetOpt(CURLOPT_TIMEOUT_MS, _timeout.Milliseconds());
|
||||
CurlHelper::SetOpt(CURLOPT_URL, _url.c_str());
|
||||
CurlHelper::SetOpt(CURLOPT_HTTPGET, 1L);
|
||||
CurlHelper::SetOpt(CURLOPT_TIMEOUT_MS, _timeout.Milliseconds());
|
||||
SetupHeaders();
|
||||
|
||||
std::string response;
|
||||
if (IsReferencedInVars()) {
|
||||
switcher->curl.SetOpt(CURLOPT_WRITEFUNCTION, WriteCB);
|
||||
CurlHelper::SetOpt(CURLOPT_WRITEFUNCTION, WriteCB);
|
||||
} else {
|
||||
switcher->curl.SetOpt(CURLOPT_WRITEFUNCTION, DropCB);
|
||||
CurlHelper::SetOpt(CURLOPT_WRITEFUNCTION, DropCB);
|
||||
}
|
||||
switcher->curl.SetOpt(CURLOPT_WRITEDATA, &response);
|
||||
switcher->curl.Perform();
|
||||
CurlHelper::SetOpt(CURLOPT_WRITEDATA, &response);
|
||||
CurlHelper::Perform();
|
||||
|
||||
SetVariableValue(response);
|
||||
}
|
||||
|
||||
void MacroActionHttp::Post()
|
||||
{
|
||||
switcher->curl.SetOpt(CURLOPT_URL, _url.c_str());
|
||||
switcher->curl.SetOpt(CURLOPT_POSTFIELDS, _data.c_str());
|
||||
switcher->curl.SetOpt(CURLOPT_TIMEOUT_MS, _timeout.Milliseconds());
|
||||
CurlHelper::SetOpt(CURLOPT_URL, _url.c_str());
|
||||
CurlHelper::SetOpt(CURLOPT_POSTFIELDS, _data.c_str());
|
||||
CurlHelper::SetOpt(CURLOPT_TIMEOUT_MS, _timeout.Milliseconds());
|
||||
SetupHeaders();
|
||||
switcher->curl.Perform();
|
||||
CurlHelper::Perform();
|
||||
}
|
||||
|
||||
bool MacroActionHttp::PerformAction()
|
||||
{
|
||||
if (!switcher->curl.Initialized()) {
|
||||
if (!CurlHelper::Initialized()) {
|
||||
blog(LOG_WARNING,
|
||||
"cannot perform http action (curl not found)");
|
||||
return true;
|
||||
|
||||
@@ -49,7 +49,7 @@ bool MacroActionMacro::PerformAction()
|
||||
break;
|
||||
case Action::RUN:
|
||||
if (!macro->Paused()) {
|
||||
macro->PerformActions();
|
||||
macro->PerformActions(true, false, true);
|
||||
}
|
||||
break;
|
||||
case Action::STOP:
|
||||
|
||||
@@ -10,22 +10,45 @@ bool MacroActionMedia::_registered = MacroActionFactory::Register(
|
||||
{MacroActionMedia::Create, MacroActionMediaEdit::Create,
|
||||
"AdvSceneSwitcher.action.media"});
|
||||
|
||||
const static std::map<MediaAction, std::string> actionTypes = {
|
||||
{MediaAction::PLAY, "AdvSceneSwitcher.action.media.type.play"},
|
||||
{MediaAction::PAUSE, "AdvSceneSwitcher.action.media.type.pause"},
|
||||
{MediaAction::STOP, "AdvSceneSwitcher.action.media.type.stop"},
|
||||
{MediaAction::RESTART, "AdvSceneSwitcher.action.media.type.restart"},
|
||||
{MediaAction::NEXT, "AdvSceneSwitcher.action.media.type.next"},
|
||||
{MediaAction::PREVIOUS, "AdvSceneSwitcher.action.media.type.previous"},
|
||||
{MediaAction::SEEK, "AdvSceneSwitcher.action.media.type.seek"},
|
||||
const static std::map<MacroActionMedia::Action, std::string> actionTypes = {
|
||||
{MacroActionMedia::Action::PLAY,
|
||||
"AdvSceneSwitcher.action.media.type.play"},
|
||||
{MacroActionMedia::Action::PAUSE,
|
||||
"AdvSceneSwitcher.action.media.type.pause"},
|
||||
{MacroActionMedia::Action::STOP,
|
||||
"AdvSceneSwitcher.action.media.type.stop"},
|
||||
{MacroActionMedia::Action::RESTART,
|
||||
"AdvSceneSwitcher.action.media.type.restart"},
|
||||
{MacroActionMedia::Action::NEXT,
|
||||
"AdvSceneSwitcher.action.media.type.next"},
|
||||
{MacroActionMedia::Action::PREVIOUS,
|
||||
"AdvSceneSwitcher.action.media.type.previous"},
|
||||
{MacroActionMedia::Action::SEEK_DURATION,
|
||||
"AdvSceneSwitcher.action.media.type.seek.duration"},
|
||||
{MacroActionMedia::Action::SEEK_PERCENTAGE,
|
||||
"AdvSceneSwitcher.action.media.type.seek.percentage"},
|
||||
};
|
||||
|
||||
std::string MacroActionMedia::GetShortDesc() const
|
||||
{
|
||||
return _mediaSource.ToString();
|
||||
}
|
||||
|
||||
void MacroActionMedia::SeekToPercentage(obs_source_t *source) const
|
||||
{
|
||||
auto totalTimeMs = obs_source_media_get_duration(source);
|
||||
auto percentageTimeMs = round(totalTimeMs * _seekPercentage / 100);
|
||||
|
||||
obs_source_media_set_time(source, percentageTimeMs);
|
||||
}
|
||||
|
||||
bool MacroActionMedia::PerformAction()
|
||||
{
|
||||
auto source = obs_weak_source_get_source(_mediaSource.GetSource());
|
||||
obs_media_state state = obs_source_media_get_state(source);
|
||||
|
||||
switch (_action) {
|
||||
case MediaAction::PLAY:
|
||||
case Action::PLAY:
|
||||
if (state == OBS_MEDIA_STATE_STOPPED ||
|
||||
state == OBS_MEDIA_STATE_ENDED) {
|
||||
obs_source_media_restart(source);
|
||||
@@ -33,27 +56,31 @@ bool MacroActionMedia::PerformAction()
|
||||
obs_source_media_play_pause(source, false);
|
||||
}
|
||||
break;
|
||||
case MediaAction::PAUSE:
|
||||
case Action::PAUSE:
|
||||
obs_source_media_play_pause(source, true);
|
||||
break;
|
||||
case MediaAction::STOP:
|
||||
case Action::STOP:
|
||||
obs_source_media_stop(source);
|
||||
break;
|
||||
case MediaAction::RESTART:
|
||||
case Action::RESTART:
|
||||
obs_source_media_restart(source);
|
||||
break;
|
||||
case MediaAction::NEXT:
|
||||
case Action::NEXT:
|
||||
obs_source_media_next(source);
|
||||
break;
|
||||
case MediaAction::PREVIOUS:
|
||||
case Action::PREVIOUS:
|
||||
obs_source_media_previous(source);
|
||||
break;
|
||||
case MediaAction::SEEK:
|
||||
obs_source_media_set_time(source, _seek.Milliseconds());
|
||||
case Action::SEEK_DURATION:
|
||||
obs_source_media_set_time(source, _seekDuration.Milliseconds());
|
||||
break;
|
||||
case Action::SEEK_PERCENTAGE:
|
||||
SeekToPercentage(source);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
obs_source_release(source);
|
||||
return true;
|
||||
}
|
||||
@@ -73,39 +100,42 @@ void MacroActionMedia::LogAction() const
|
||||
bool MacroActionMedia::Save(obs_data_t *obj) const
|
||||
{
|
||||
MacroAction::Save(obj);
|
||||
_mediaSource.Save(obj, "mediaSource");
|
||||
obs_data_set_int(obj, "action", static_cast<int>(_action));
|
||||
_seek.Save(obj);
|
||||
_seekDuration.Save(obj);
|
||||
_seekPercentage.Save(obj, "seekPercentage");
|
||||
_mediaSource.Save(obj, "mediaSource");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacroActionMedia::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroAction::Load(obj);
|
||||
_action = static_cast<Action>(obs_data_get_int(obj, "action"));
|
||||
_seekDuration.Load(obj);
|
||||
_seekPercentage.Load(obj, "seekPercentage");
|
||||
_mediaSource.Load(obj, "mediaSource");
|
||||
_action = static_cast<MediaAction>(obs_data_get_int(obj, "action"));
|
||||
_seek.Load(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string MacroActionMedia::GetShortDesc() const
|
||||
{
|
||||
return _mediaSource.ToString();
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void populateActionSelection(QComboBox *list)
|
||||
{
|
||||
for (auto entry : actionTypes) {
|
||||
list->addItem(obs_module_text(entry.second.c_str()));
|
||||
for (const auto &[_, name] : actionTypes) {
|
||||
list->addItem(obs_module_text(name.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
MacroActionMediaEdit::MacroActionMediaEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroActionMedia> entryData)
|
||||
: QWidget(parent),
|
||||
_sources(new SourceSelectionWidget(this, QStringList(), true)),
|
||||
_actions(new QComboBox()),
|
||||
_seek(new DurationSelection())
|
||||
_seekDuration(new DurationSelection()),
|
||||
_seekPercentage(new SliderSpinBox(
|
||||
0, 100,
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.media.seek.percentage.label"))),
|
||||
_sources(new SourceSelectionWidget(this, QStringList(), true))
|
||||
{
|
||||
populateActionSelection(_actions);
|
||||
auto sources = GetMediaSourceNames();
|
||||
@@ -114,39 +144,67 @@ MacroActionMediaEdit::MacroActionMediaEdit(
|
||||
|
||||
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(ActionChanged(int)));
|
||||
QWidget::connect(_seekDuration,
|
||||
SIGNAL(DurationChanged(const Duration &)), this,
|
||||
SLOT(SeekDurationChanged(const Duration &)));
|
||||
QWidget::connect(
|
||||
_seekPercentage,
|
||||
SIGNAL(DoubleValueChanged(const NumberVariable<double> &)),
|
||||
this,
|
||||
SLOT(SeekPercentageChanged(const NumberVariable<double> &)));
|
||||
QWidget::connect(_sources,
|
||||
SIGNAL(SourceChanged(const SourceSelection &)), this,
|
||||
SLOT(SourceChanged(const SourceSelection &)));
|
||||
QWidget::connect(_seek, SIGNAL(DurationChanged(const Duration &)), this,
|
||||
SLOT(DurationChanged(const Duration &)));
|
||||
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||
auto layout = new QHBoxLayout;
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{mediaSources}}", _sources},
|
||||
{"{{actions}}", _actions},
|
||||
{"{{duration}}", _seek},
|
||||
{"{{seekDuration}}", _seekDuration},
|
||||
{"{{seekPercentage}}", _seekPercentage},
|
||||
{"{{mediaSources}}", _sources},
|
||||
};
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.media.entry"),
|
||||
mainLayout, widgetPlaceholders);
|
||||
setLayout(mainLayout);
|
||||
layout, widgetPlaceholders);
|
||||
setLayout(layout);
|
||||
|
||||
_entryData = entryData;
|
||||
UpdateEntryData();
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
void MacroActionMediaEdit::UpdateEntryData()
|
||||
void MacroActionMediaEdit::ActionChanged(int value)
|
||||
{
|
||||
if (!_entryData) {
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
_sources->SetSource(_entryData->_mediaSource);
|
||||
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
|
||||
_seek->SetDuration(_entryData->_seek);
|
||||
auto lock = LockContext();
|
||||
_entryData->_action = static_cast<MacroActionMedia::Action>(value);
|
||||
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionMediaEdit::SeekDurationChanged(const Duration &seekDuration)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_seekDuration = seekDuration;
|
||||
}
|
||||
|
||||
void MacroActionMediaEdit::SeekPercentageChanged(
|
||||
const NumberVariable<double> &seekPercentage)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_seekPercentage = seekPercentage;
|
||||
}
|
||||
|
||||
void MacroActionMediaEdit::SourceChanged(const SourceSelection &source)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
@@ -159,34 +217,32 @@ void MacroActionMediaEdit::SourceChanged(const SourceSelection &source)
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
}
|
||||
|
||||
void MacroActionMediaEdit::ActionChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_action = static_cast<MediaAction>(value);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionMediaEdit::DurationChanged(const Duration &dur)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_seek = dur;
|
||||
}
|
||||
|
||||
void MacroActionMediaEdit::SetWidgetVisibility()
|
||||
{
|
||||
if (!_entryData) {
|
||||
return;
|
||||
}
|
||||
_seek->setVisible(_entryData->_action == MediaAction::SEEK);
|
||||
|
||||
_seekDuration->setVisible(_entryData->_action ==
|
||||
MacroActionMedia::Action::SEEK_DURATION);
|
||||
_seekPercentage->setVisible(_entryData->_action ==
|
||||
MacroActionMedia::Action::SEEK_PERCENTAGE);
|
||||
|
||||
adjustSize();
|
||||
}
|
||||
|
||||
void MacroActionMediaEdit::UpdateEntryData()
|
||||
{
|
||||
if (!_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
|
||||
_seekDuration->SetDuration(_entryData->_seekDuration);
|
||||
_seekPercentage->SetDoubleValue(_entryData->_seekPercentage);
|
||||
_sources->SetSource(_entryData->_mediaSource);
|
||||
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,42 +1,45 @@
|
||||
#pragma once
|
||||
#include "macro-action-edit.hpp"
|
||||
#include "duration-control.hpp"
|
||||
#include "slider-spinbox.hpp"
|
||||
#include "source-selection.hpp"
|
||||
|
||||
#include <QSpinBox>
|
||||
#include <QHBoxLayout>
|
||||
|
||||
namespace advss {
|
||||
|
||||
enum class MediaAction {
|
||||
PLAY,
|
||||
PAUSE,
|
||||
STOP,
|
||||
RESTART,
|
||||
NEXT,
|
||||
PREVIOUS,
|
||||
SEEK,
|
||||
};
|
||||
|
||||
class MacroActionMedia : public MacroAction {
|
||||
public:
|
||||
MacroActionMedia(Macro *m) : MacroAction(m) {}
|
||||
bool PerformAction();
|
||||
void LogAction() const;
|
||||
bool Save(obs_data_t *obj) const;
|
||||
bool Load(obs_data_t *obj);
|
||||
std::string GetShortDesc() const;
|
||||
std::string GetId() const { return id; };
|
||||
static std::shared_ptr<MacroAction> Create(Macro *m)
|
||||
{
|
||||
return std::make_shared<MacroActionMedia>(m);
|
||||
}
|
||||
std::string GetId() const { return id; };
|
||||
std::string GetShortDesc() const;
|
||||
|
||||
bool PerformAction();
|
||||
void LogAction() const;
|
||||
bool Save(obs_data_t *obj) const;
|
||||
bool Load(obs_data_t *obj);
|
||||
|
||||
enum class Action {
|
||||
PLAY,
|
||||
PAUSE,
|
||||
STOP,
|
||||
RESTART,
|
||||
NEXT,
|
||||
PREVIOUS,
|
||||
SEEK_DURATION,
|
||||
SEEK_PERCENTAGE,
|
||||
};
|
||||
|
||||
Action _action = Action::PLAY;
|
||||
Duration _seekDuration;
|
||||
DoubleVariable _seekPercentage = 50;
|
||||
SourceSelection _mediaSource;
|
||||
MediaAction _action = MediaAction::PLAY;
|
||||
Duration _seek;
|
||||
|
||||
private:
|
||||
void SeekToPercentage(obs_source_t *source) const;
|
||||
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
};
|
||||
@@ -48,7 +51,6 @@ public:
|
||||
MacroActionMediaEdit(
|
||||
QWidget *parent,
|
||||
std::shared_ptr<MacroActionMedia> entryData = nullptr);
|
||||
void UpdateEntryData();
|
||||
static QWidget *Create(QWidget *parent,
|
||||
std::shared_ptr<MacroAction> action)
|
||||
{
|
||||
@@ -56,24 +58,27 @@ public:
|
||||
parent,
|
||||
std::dynamic_pointer_cast<MacroActionMedia>(action));
|
||||
}
|
||||
void UpdateEntryData();
|
||||
|
||||
private slots:
|
||||
void SourceChanged(const SourceSelection &);
|
||||
void ActionChanged(int value);
|
||||
void DurationChanged(const Duration &value);
|
||||
void SeekDurationChanged(const Duration &seekDuration);
|
||||
void
|
||||
SeekPercentageChanged(const NumberVariable<double> &seekPercentage);
|
||||
void SourceChanged(const SourceSelection &source);
|
||||
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
|
||||
protected:
|
||||
SourceSelectionWidget *_sources;
|
||||
QComboBox *_actions;
|
||||
DurationSelection *_seek;
|
||||
std::shared_ptr<MacroActionMedia> _entryData;
|
||||
|
||||
private:
|
||||
void SetWidgetVisibility();
|
||||
|
||||
QHBoxLayout *_mainLayout;
|
||||
QComboBox *_actions;
|
||||
DurationSelection *_seekDuration;
|
||||
SliderSpinBox *_seekPercentage;
|
||||
SourceSelectionWidget *_sources;
|
||||
|
||||
std::shared_ptr<MacroActionMedia> _entryData;
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#include "macro-action-plugin-state.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <thread>
|
||||
#include <condition_variable>
|
||||
#include <QMainWindow>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
@@ -27,40 +28,38 @@ const static std::map<PluginStateAction, std::string> actionTypes = {
|
||||
"AdvSceneSwitcher.action.pluginState.type.terminate"},
|
||||
};
|
||||
|
||||
const static std::map<SwitcherData::NoMatch, std::string> noMatchValues = {
|
||||
{SwitcherData::NoMatch::NO_SWITCH,
|
||||
const static std::map<NoMatchBehavior, std::string> noMatchValues = {
|
||||
{NoMatchBehavior::NO_SWITCH,
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.dontSwitch"},
|
||||
{SwitcherData::NoMatch::SWITCH,
|
||||
{NoMatchBehavior::SWITCH,
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchTo"},
|
||||
{SwitcherData::NoMatch::RANDOM_SWITCH,
|
||||
{NoMatchBehavior::RANDOM_SWITCH,
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchToRandom"},
|
||||
};
|
||||
|
||||
static void stopPlugin()
|
||||
{
|
||||
std::thread t([]() { switcher->Stop(); });
|
||||
std::thread t([]() { StopPlugin(); });
|
||||
t.detach();
|
||||
}
|
||||
|
||||
static void importSettings(const std::string &path)
|
||||
{
|
||||
if (switcher->settingsWindowOpened) {
|
||||
if (SettingsWindowIsOpened()) {
|
||||
return;
|
||||
}
|
||||
obs_data_t *obj = obs_data_create_from_json_file(path.c_str());
|
||||
OBSDataAutoRelease obj = obs_data_create_from_json_file(path.c_str());
|
||||
if (!obj) {
|
||||
return;
|
||||
}
|
||||
switcher->LoadSettings(obj);
|
||||
obs_data_release(obj);
|
||||
LoadPluginSettings(obj);
|
||||
}
|
||||
|
||||
static void setNoMatchBehaviour(int value, OBSWeakSource &scene)
|
||||
{
|
||||
switcher->switchIfNotMatching =
|
||||
static_cast<SwitcherData::NoMatch>(value);
|
||||
if (switcher->switchIfNotMatching == SwitcherData::NoMatch::SWITCH) {
|
||||
switcher->nonMatchingScene = scene;
|
||||
SetPluginNoMatchBehavior(static_cast<NoMatchBehavior>(value));
|
||||
if (GetPluginNoMatchBehavior() == NoMatchBehavior::SWITCH) {
|
||||
SetNoMatchScene(scene);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,8 +341,8 @@ void MacroActionPluginStateEdit::SetWidgetVisibility()
|
||||
break;
|
||||
case PluginStateAction::NO_MATCH_BEHAVIOUR:
|
||||
_values->show();
|
||||
if (static_cast<SwitcherData::NoMatch>(_entryData->_value) ==
|
||||
SwitcherData::NoMatch::SWITCH) {
|
||||
if (static_cast<NoMatchBehavior>(_entryData->_value) ==
|
||||
NoMatchBehavior::SWITCH) {
|
||||
_scenes->show();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -57,6 +57,12 @@ bool MacroActionProjector::PerformAction()
|
||||
break;
|
||||
}
|
||||
|
||||
if (_fullscreen && _monitor == -1) {
|
||||
blog(LOG_INFO, "refusing to open fullscreen projector"
|
||||
" with invalid display selection");
|
||||
return true;
|
||||
}
|
||||
|
||||
obs_frontend_open_projector(type, _fullscreen ? _monitor : -1, "",
|
||||
name.c_str());
|
||||
|
||||
@@ -85,6 +91,7 @@ bool MacroActionProjector::Save(obs_data_t *obj) const
|
||||
MacroAction::Save(obj);
|
||||
obs_data_set_int(obj, "type", static_cast<int>(_type));
|
||||
obs_data_set_int(obj, "monitor", _monitor);
|
||||
obs_data_set_string(obj, "monitorName", _monitorName.c_str());
|
||||
obs_data_set_bool(obj, "fullscreen", _fullscreen);
|
||||
_scene.Save(obj);
|
||||
_source.Save(obj);
|
||||
@@ -96,12 +103,50 @@ bool MacroActionProjector::Load(obs_data_t *obj)
|
||||
MacroAction::Load(obj);
|
||||
_type = static_cast<Type>(obs_data_get_int(obj, "type"));
|
||||
_monitor = obs_data_get_int(obj, "monitor");
|
||||
_monitorName = obs_data_get_string(obj, "monitorName");
|
||||
_fullscreen = obs_data_get_bool(obj, "fullscreen");
|
||||
_scene.Load(obj);
|
||||
_source.Load(obj);
|
||||
|
||||
if (MonitorSetupChanged()) {
|
||||
blog(LOG_INFO, "monitor setup seems to have changed! "
|
||||
"resetting projector action monitor selection!");
|
||||
_monitor = -1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MacroActionProjector::SetMonitor(int idx)
|
||||
{
|
||||
_monitor = idx;
|
||||
auto monitorNames = GetMonitorNames();
|
||||
if (_monitor < 0 || _monitor >= monitorNames.size()) {
|
||||
// Monitor setup changed while settings were selected?
|
||||
_monitorName = "";
|
||||
return;
|
||||
}
|
||||
_monitorName = monitorNames.at(_monitor).toStdString();
|
||||
}
|
||||
|
||||
int MacroActionProjector::GetMonitor() const
|
||||
{
|
||||
return _monitor;
|
||||
}
|
||||
|
||||
bool MacroActionProjector::MonitorSetupChanged()
|
||||
{
|
||||
if (_monitorName.empty()) {
|
||||
return false;
|
||||
}
|
||||
auto monitorNames = GetMonitorNames();
|
||||
if (_monitor < 0 || _monitor >= monitorNames.size()) {
|
||||
return true;
|
||||
}
|
||||
return monitorNames.at(_monitor) !=
|
||||
QString::fromStdString(_monitorName);
|
||||
}
|
||||
|
||||
static inline void populateSelectionTypes(QComboBox *list)
|
||||
{
|
||||
for (auto entry : selectionTypes) {
|
||||
@@ -134,6 +179,8 @@ MacroActionProjectorEdit::MacroActionProjectorEdit(
|
||||
sources.sort();
|
||||
_sources->SetSourceNameList(sources);
|
||||
_monitors->addItems(GetMonitorNames());
|
||||
_monitors->setPlaceholderText(
|
||||
obs_module_text("AdvSceneSwitcher.selectDisplay"));
|
||||
|
||||
QWidget::connect(_windowTypes, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(WindowTypeChanged(int)));
|
||||
@@ -177,7 +224,7 @@ void MacroActionProjectorEdit::UpdateEntryData()
|
||||
_types->setCurrentIndex(static_cast<int>(_entryData->_type));
|
||||
_scenes->SetScene(_entryData->_scene);
|
||||
_sources->SetSource(_entryData->_source);
|
||||
_monitors->setCurrentIndex(_entryData->_monitor);
|
||||
_monitors->setCurrentIndex(_entryData->GetMonitor());
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
@@ -208,7 +255,7 @@ void MacroActionProjectorEdit::MonitorChanged(int value)
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_monitor = value;
|
||||
_entryData->SetMonitor(value);
|
||||
}
|
||||
|
||||
void MacroActionProjectorEdit::WindowTypeChanged(int)
|
||||
|
||||
@@ -17,6 +17,8 @@ public:
|
||||
{
|
||||
return std::make_shared<MacroActionProjector>(m);
|
||||
}
|
||||
void SetMonitor(int);
|
||||
int GetMonitor() const;
|
||||
|
||||
enum class Type {
|
||||
SOURCE,
|
||||
@@ -29,10 +31,15 @@ public:
|
||||
Type _type = Type::SCENE;
|
||||
SourceSelection _source;
|
||||
SceneSelection _scene;
|
||||
int _monitor = 0;
|
||||
bool _fullscreen = true;
|
||||
|
||||
private:
|
||||
bool MonitorSetupChanged();
|
||||
|
||||
int _monitor = -1;
|
||||
// Only used to detect display setup changes
|
||||
std::string _monitorName = "";
|
||||
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
@@ -54,12 +54,12 @@ bool MacroActionRandom::PerformAction()
|
||||
}
|
||||
if (macros.size() == 1) {
|
||||
lastRandomMacro = macros[0];
|
||||
return macros[0]->PerformActions();
|
||||
return macros[0]->PerformActions(true);
|
||||
}
|
||||
srand((unsigned int)time(0));
|
||||
size_t idx = std::rand() % (macros.size());
|
||||
lastRandomMacro = macros[idx];
|
||||
return macros[idx]->PerformActions();
|
||||
return macros[idx]->PerformActions(true);
|
||||
}
|
||||
|
||||
void MacroActionRandom::LogAction() const
|
||||
|
||||
@@ -14,9 +14,14 @@ bool MacroActionRun::_registered = MacroActionFactory::Register(
|
||||
|
||||
bool MacroActionRun::PerformAction()
|
||||
{
|
||||
bool procStarted = QProcess::startDetached(
|
||||
QString::fromStdString(_procConfig.Path()), _procConfig.Args(),
|
||||
QString::fromStdString(_procConfig.WorkingDir()));
|
||||
if (_wait) {
|
||||
_procConfig.StartProcessAndWait(_timeout.Milliseconds());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool procStarted = _procConfig.StartProcessDetached();
|
||||
|
||||
// Fall back to using default application to open given file
|
||||
if (!procStarted && _procConfig.Args().empty()) {
|
||||
vblog(LOG_INFO, "run \"%s\" using QDesktopServices",
|
||||
_procConfig.Path().c_str());
|
||||
@@ -35,6 +40,9 @@ bool MacroActionRun::Save(obs_data_t *obj) const
|
||||
{
|
||||
MacroAction::Save(obj);
|
||||
_procConfig.Save(obj);
|
||||
_timeout.Save(obj);
|
||||
obs_data_set_bool(obj, "wait", _wait);
|
||||
obs_data_set_int(obj, "version", 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -42,6 +50,12 @@ bool MacroActionRun::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroAction::Load(obj);
|
||||
_procConfig.Load(obj);
|
||||
// TODO: Remove this fallback in a future version
|
||||
if (!obs_data_has_user_value(obj, "version")) {
|
||||
return true;
|
||||
}
|
||||
_timeout.Load(obj);
|
||||
_wait = obs_data_get_bool(obj, "wait");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -52,14 +66,30 @@ std::string MacroActionRun::GetShortDesc() const
|
||||
|
||||
MacroActionRunEdit::MacroActionRunEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroActionRun> entryData)
|
||||
: QWidget(parent), _procConfig(new ProcessConfigEdit(this))
|
||||
: QWidget(parent),
|
||||
_procConfig(new ProcessConfigEdit(this)),
|
||||
_waitLayout(new QHBoxLayout()),
|
||||
_wait(new QCheckBox()),
|
||||
_timeout(new DurationSelection(this, true, 0.1))
|
||||
{
|
||||
QWidget::connect(_procConfig,
|
||||
SIGNAL(ConfigChanged(const ProcessConfig &)), this,
|
||||
SLOT(ProcessConfigChanged(const ProcessConfig &)));
|
||||
QWidget::connect(_procConfig, SIGNAL(AdvancedSettingsEnabled()), this,
|
||||
SLOT(ProcessConfigAdvancedSettingsShown()));
|
||||
QWidget::connect(_wait, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(WaitChanged(int)));
|
||||
QWidget::connect(_timeout, SIGNAL(DurationChanged(const Duration &)),
|
||||
this, SLOT(TimeoutChanged(const Duration &)));
|
||||
|
||||
auto *layout = new QVBoxLayout;
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.run.entry.wait"),
|
||||
_waitLayout,
|
||||
{{"{{wait}}", _wait}, {"{{timeout}}", _timeout}});
|
||||
SetLayoutVisible(_waitLayout, false);
|
||||
|
||||
auto layout = new QVBoxLayout;
|
||||
layout->addWidget(_procConfig);
|
||||
layout->addLayout(_waitLayout);
|
||||
setLayout(layout);
|
||||
|
||||
_entryData = entryData;
|
||||
@@ -73,6 +103,31 @@ void MacroActionRunEdit::UpdateEntryData()
|
||||
return;
|
||||
}
|
||||
_procConfig->SetProcessConfig(_entryData->_procConfig);
|
||||
_wait->setChecked(_entryData->_wait);
|
||||
_timeout->SetDuration(_entryData->_timeout);
|
||||
}
|
||||
|
||||
void MacroActionRunEdit::ProcessConfigAdvancedSettingsShown()
|
||||
{
|
||||
SetLayoutVisible(_waitLayout, true);
|
||||
}
|
||||
|
||||
void MacroActionRunEdit::WaitChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
auto lock = LockContext();
|
||||
_entryData->_wait = value;
|
||||
}
|
||||
|
||||
void MacroActionRunEdit::TimeoutChanged(const Duration &timeout)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
auto lock = LockContext();
|
||||
_entryData->_timeout = timeout;
|
||||
}
|
||||
|
||||
void MacroActionRunEdit::ProcessConfigChanged(const ProcessConfig &conf)
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#pragma once
|
||||
#include "macro-action-edit.hpp"
|
||||
#include "process-config.hpp"
|
||||
#include "duration-control.hpp"
|
||||
|
||||
#include <QCheckBox>
|
||||
|
||||
namespace advss {
|
||||
|
||||
@@ -19,6 +22,8 @@ public:
|
||||
}
|
||||
|
||||
ProcessConfig _procConfig;
|
||||
bool _wait = false;
|
||||
Duration _timeout = 1;
|
||||
|
||||
private:
|
||||
static bool _registered;
|
||||
@@ -42,14 +47,19 @@ public:
|
||||
|
||||
private slots:
|
||||
void ProcessConfigChanged(const ProcessConfig &);
|
||||
void ProcessConfigAdvancedSettingsShown();
|
||||
void WaitChanged(int);
|
||||
void TimeoutChanged(const Duration &);
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
|
||||
protected:
|
||||
std::shared_ptr<MacroActionRun> _entryData;
|
||||
|
||||
private:
|
||||
ProcessConfigEdit *_procConfig;
|
||||
QHBoxLayout *_waitLayout;
|
||||
QCheckBox *_wait;
|
||||
DurationSelection *_timeout;
|
||||
|
||||
std::shared_ptr<MacroActionRun> _entryData;
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "macro-action-scene-collection.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace advss {
|
||||
@@ -17,7 +17,7 @@ bool MacroActionSceneCollection::PerformAction()
|
||||
// Changing the scene collection will also reload the settings of the
|
||||
// scene switcher, so to avoid issues of not being able to change
|
||||
// settings ignore this action if the settings dialog is opened.
|
||||
if (switcher->settingsWindowOpened) {
|
||||
if (SettingsWindowIsOpened()) {
|
||||
return false;
|
||||
}
|
||||
obs_frontend_set_current_scene_collection(_sceneCollection.c_str());
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "macro-action-scene-switch.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "scene-switch-helpers.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
@@ -7,12 +9,20 @@ namespace advss {
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
const std::string MacroActionSwitchScene::id = "scene_switch";
|
||||
const std::string MacroActionSwitchScene::id = GetSceneSwitchActionId().data();
|
||||
|
||||
bool MacroActionSwitchScene::_registered = MacroActionFactory::Register(
|
||||
MacroActionSwitchScene::id,
|
||||
{MacroActionSwitchScene::Create, MacroActionSwitchSceneEdit::Create,
|
||||
"AdvSceneSwitcher.action.switchScene"});
|
||||
"AdvSceneSwitcher.action.scene"});
|
||||
|
||||
const static std::map<MacroActionSwitchScene::SceneType, std::string>
|
||||
sceneTypes = {
|
||||
{MacroActionSwitchScene::SceneType::PROGRAM,
|
||||
"AdvSceneSwitcher.action.scene.type.program"},
|
||||
{MacroActionSwitchScene::SceneType::PREVIEW,
|
||||
"AdvSceneSwitcher.action.scene.type.preview"},
|
||||
};
|
||||
|
||||
static void waitForTransitionChange(OBSWeakSource &transition,
|
||||
std::unique_lock<std::mutex> *lock,
|
||||
@@ -25,9 +35,9 @@ static void waitForTransitionChange(OBSWeakSource &transition,
|
||||
}
|
||||
|
||||
bool stillTransitioning = true;
|
||||
while (stillTransitioning && !switcher->abortMacroWait &&
|
||||
while (stillTransitioning && !MacroWaitShouldAbort() &&
|
||||
!macro->GetStop()) {
|
||||
switcher->macroTransitionCv.wait_for(*lock, time);
|
||||
GetMacroTransitionCV().wait_for(*lock, time);
|
||||
float t = obs_transition_get_time(source);
|
||||
stillTransitioning = t < 1.0f && t > 0.0f;
|
||||
}
|
||||
@@ -41,8 +51,8 @@ static void waitForTransitionChangeFixedDuration(
|
||||
auto time = std::chrono::high_resolution_clock::now() +
|
||||
std::chrono::milliseconds(duration);
|
||||
|
||||
while (!switcher->abortMacroWait && !macro->GetStop()) {
|
||||
if (switcher->macroTransitionCv.wait_until(*lock, time) ==
|
||||
while (!MacroWaitShouldAbort() && !macro->GetStop()) {
|
||||
if (GetMacroTransitionCV().wait_until(*lock, time) ==
|
||||
std::cv_status::timeout) {
|
||||
break;
|
||||
}
|
||||
@@ -83,11 +93,16 @@ static OBSWeakSource getOverrideTransition(OBSWeakSource &scene)
|
||||
return transition;
|
||||
}
|
||||
|
||||
static int getExpectedTransitionDuration(OBSWeakSource &scene, OBSWeakSource &t,
|
||||
static int getExpectedTransitionDuration(OBSWeakSource &scene,
|
||||
OBSWeakSource &transiton_,
|
||||
double duration)
|
||||
{
|
||||
OBSWeakSource transition = t;
|
||||
if (!switcher->transitionOverrideOverride) {
|
||||
OBSWeakSource transition = transiton_;
|
||||
|
||||
// If we are not modifying the transition override, we will have to
|
||||
// check, if a transition override is set by the user and use its
|
||||
// duration instead
|
||||
if (!ShouldModifyTransitionOverrides()) {
|
||||
auto overrideTransition = getOverrideTransition(scene);
|
||||
if (overrideTransition) {
|
||||
transition = overrideTransition;
|
||||
@@ -96,6 +111,7 @@ static int getExpectedTransitionDuration(OBSWeakSource &scene, OBSWeakSource &t,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isUsingFixedLengthTransition(transition)) {
|
||||
return -1; // no API is available to access the fixed duration
|
||||
}
|
||||
@@ -110,9 +126,9 @@ bool MacroActionSwitchScene::WaitForTransition(OBSWeakSource &scene,
|
||||
{
|
||||
const int expectedTransitionDuration = getExpectedTransitionDuration(
|
||||
scene, transition, _duration.Seconds());
|
||||
switcher->abortMacroWait = false;
|
||||
SetMacroAbortWait(false);
|
||||
|
||||
std::unique_lock<std::mutex> lock(switcher->m);
|
||||
std::unique_lock<std::mutex> lock(*GetMutex());
|
||||
if (expectedTransitionDuration < 0) {
|
||||
waitForTransitionChange(transition, &lock, GetMacro());
|
||||
} else {
|
||||
@@ -120,16 +136,24 @@ bool MacroActionSwitchScene::WaitForTransition(OBSWeakSource &scene,
|
||||
&lock, GetMacro());
|
||||
}
|
||||
|
||||
return !switcher->abortMacroWait;
|
||||
return !MacroWaitShouldAbort();
|
||||
}
|
||||
|
||||
bool MacroActionSwitchScene::PerformAction()
|
||||
{
|
||||
auto scene = _scene.GetScene();
|
||||
|
||||
if (_sceneType == SceneType::PREVIEW) {
|
||||
OBSSourceAutoRelease previewScneSource =
|
||||
obs_weak_source_get_source(scene);
|
||||
obs_frontend_set_current_preview_scene(previewScneSource);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto transition = _transition.GetTransition();
|
||||
SwitchScene({scene, transition, (int)(_duration.Milliseconds())},
|
||||
obs_frontend_preview_program_mode_active());
|
||||
if (_blockUntilTransitionDone && scene) {
|
||||
if (_blockUntilTransitionDone && scene && scene != GetCurrentScene()) {
|
||||
return WaitForTransition(scene, transition);
|
||||
}
|
||||
return true;
|
||||
@@ -137,24 +161,9 @@ bool MacroActionSwitchScene::PerformAction()
|
||||
|
||||
void MacroActionSwitchScene::LogAction() const
|
||||
{
|
||||
auto t = _scene.GetType();
|
||||
auto sceneName = GetWeakSourceName(_scene.GetScene(false));
|
||||
switch (t) {
|
||||
case SceneSelection::Type::SCENE:
|
||||
vblog(LOG_INFO, "switch to scene '%s'",
|
||||
_scene.ToString(true).c_str());
|
||||
break;
|
||||
case SceneSelection::Type::GROUP:
|
||||
vblog(LOG_INFO, "switch to scene '%s' (scene group '%s')",
|
||||
sceneName.c_str(), _scene.ToString(true).c_str());
|
||||
break;
|
||||
case SceneSelection::Type::PREVIOUS:
|
||||
vblog(LOG_INFO, "switch to previous scene '%s'",
|
||||
sceneName.c_str());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
vblog(LOG_INFO, "switch%s scene to '%s'",
|
||||
_sceneType == SceneType::PREVIEW ? " preview" : "",
|
||||
_scene.ToString(true).c_str());
|
||||
}
|
||||
|
||||
bool MacroActionSwitchScene::Save(obs_data_t *obj) const
|
||||
@@ -165,6 +174,7 @@ bool MacroActionSwitchScene::Save(obs_data_t *obj) const
|
||||
_duration.Save(obj);
|
||||
obs_data_set_bool(obj, "blockUntilTransitionDone",
|
||||
_blockUntilTransitionDone);
|
||||
obs_data_set_int(obj, "sceneType", static_cast<int>(_sceneType));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -176,6 +186,7 @@ bool MacroActionSwitchScene::Load(obs_data_t *obj)
|
||||
_duration.Load(obj);
|
||||
_blockUntilTransitionDone =
|
||||
obs_data_get_bool(obj, "blockUntilTransitionDone");
|
||||
_sceneType = static_cast<SceneType>(obs_data_get_int(obj, "sceneType"));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -184,6 +195,13 @@ std::string MacroActionSwitchScene::GetShortDesc() const
|
||||
return _scene.ToString();
|
||||
}
|
||||
|
||||
static inline void populateTypeSelection(QComboBox *list)
|
||||
{
|
||||
for (const auto &[_, name] : sceneTypes) {
|
||||
list->addItem(obs_module_text(name.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
MacroActionSwitchSceneEdit::MacroActionSwitchSceneEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroActionSwitchScene> entryData)
|
||||
: QWidget(parent),
|
||||
@@ -192,9 +210,11 @@ MacroActionSwitchSceneEdit::MacroActionSwitchSceneEdit(
|
||||
_duration(new DurationSelection(parent, false)),
|
||||
_blockUntilTransitionDone(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.action.scene.blockUntilTransitionDone"))),
|
||||
_sceneTypes(new QComboBox()),
|
||||
_entryLayout(new QHBoxLayout())
|
||||
{
|
||||
_duration->SpinBox()->setSpecialValueText("-");
|
||||
populateTypeSelection(_sceneTypes);
|
||||
|
||||
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
|
||||
this, SLOT(SceneChanged(const SceneSelection &)));
|
||||
@@ -206,28 +226,29 @@ MacroActionSwitchSceneEdit::MacroActionSwitchSceneEdit(
|
||||
this, SLOT(DurationChanged(const Duration &)));
|
||||
QWidget::connect(_blockUntilTransitionDone, SIGNAL(stateChanged(int)),
|
||||
this, SLOT(BlockUntilTransitionDoneChanged(int)));
|
||||
QWidget::connect(_sceneTypes, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(SceneTypeChanged(int)));
|
||||
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{scenes}}", _scenes},
|
||||
{"{{transitions}}", _transitions},
|
||||
{"{{duration}}", _duration},
|
||||
{"{{blockUntilTransitionDone}}", _blockUntilTransitionDone},
|
||||
};
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.scene.entry"),
|
||||
_entryLayout, widgetPlaceholders);
|
||||
_entryLayout,
|
||||
{{"{{scenes}}", _scenes},
|
||||
{"{{transitions}}", _transitions},
|
||||
{"{{duration}}", _duration},
|
||||
{"{{sceneTypes}}", _sceneTypes}});
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
auto mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(_entryLayout);
|
||||
mainLayout->addWidget(_blockUntilTransitionDone);
|
||||
setLayout(mainLayout);
|
||||
|
||||
_entryData = entryData;
|
||||
_sceneTypes->setCurrentIndex(static_cast<int>(_entryData->_sceneType));
|
||||
_scenes->SetScene(_entryData->_scene);
|
||||
_transitions->SetTransition(_entryData->_transition);
|
||||
_duration->SetDuration(_entryData->_duration);
|
||||
_blockUntilTransitionDone->setChecked(
|
||||
_entryData->_blockUntilTransitionDone);
|
||||
SetDurationVisibility();
|
||||
SetWidgetVisibility();
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
@@ -251,8 +272,44 @@ void MacroActionSwitchSceneEdit::BlockUntilTransitionDoneChanged(int state)
|
||||
_entryData->_blockUntilTransitionDone = state;
|
||||
}
|
||||
|
||||
void MacroActionSwitchSceneEdit::SetDurationVisibility()
|
||||
void MacroActionSwitchSceneEdit::SceneTypeChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_sceneType =
|
||||
static_cast<MacroActionSwitchScene::SceneType>(value);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionSwitchSceneEdit::SetWidgetVisibility()
|
||||
{
|
||||
_entryLayout->removeWidget(_scenes);
|
||||
_entryLayout->removeWidget(_transitions);
|
||||
_entryLayout->removeWidget(_duration);
|
||||
_entryLayout->removeWidget(_sceneTypes);
|
||||
ClearLayout(_entryLayout);
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{scenes}}", _scenes},
|
||||
{"{{transitions}}", _transitions},
|
||||
{"{{duration}}", _duration},
|
||||
{"{{sceneTypes}}", _sceneTypes},
|
||||
};
|
||||
|
||||
if (_entryData->_sceneType ==
|
||||
MacroActionSwitchScene::SceneType::PREVIEW) {
|
||||
_transitions->hide();
|
||||
_duration->hide();
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.scene.entry.preview"),
|
||||
_entryLayout, widgetPlaceholders);
|
||||
return;
|
||||
}
|
||||
|
||||
_transitions->show();
|
||||
if (_entryData->_transition.GetType() !=
|
||||
TransitionSelection::Type::TRANSITION) {
|
||||
_duration->show();
|
||||
@@ -261,15 +318,6 @@ void MacroActionSwitchSceneEdit::SetDurationVisibility()
|
||||
_entryData->_transition.GetTransition());
|
||||
_duration->setVisible(!fixedDuration);
|
||||
|
||||
_entryLayout->removeWidget(_scenes);
|
||||
_entryLayout->removeWidget(_transitions);
|
||||
_entryLayout->removeWidget(_duration);
|
||||
ClearLayout(_entryLayout);
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{scenes}}", _scenes},
|
||||
{"{{transitions}}", _transitions},
|
||||
{"{{duration}}", _duration},
|
||||
};
|
||||
if (fixedDuration) {
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
@@ -302,7 +350,7 @@ void MacroActionSwitchSceneEdit::TransitionChanged(const TransitionSelection &t)
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_transition = t;
|
||||
SetDurationVisibility();
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -22,6 +22,9 @@ public:
|
||||
{
|
||||
return std::make_shared<MacroActionSwitchScene>(m);
|
||||
}
|
||||
|
||||
enum class SceneType { PROGRAM, PREVIEW };
|
||||
SceneType _sceneType = SceneType::PROGRAM;
|
||||
SceneSelection _scene;
|
||||
TransitionSelection _transition;
|
||||
Duration _duration;
|
||||
@@ -55,20 +58,21 @@ private slots:
|
||||
void TransitionChanged(const TransitionSelection &);
|
||||
void DurationChanged(const Duration &seconds);
|
||||
void BlockUntilTransitionDoneChanged(int state);
|
||||
void SceneTypeChanged(int);
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
|
||||
protected:
|
||||
private:
|
||||
void SetWidgetVisibility();
|
||||
|
||||
SceneSelectionWidget *_scenes;
|
||||
TransitionSelectionWidget *_transitions;
|
||||
DurationSelection *_duration;
|
||||
QCheckBox *_blockUntilTransitionDone;
|
||||
QComboBox *_sceneTypes;
|
||||
QHBoxLayout *_entryLayout;
|
||||
|
||||
std::shared_ptr<MacroActionSwitchScene> _entryData;
|
||||
|
||||
private:
|
||||
void SetDurationVisibility();
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ void MacroActionScreenshot::CustomScreenshot(OBSWeakSource &source)
|
||||
}
|
||||
auto s = obs_weak_source_get_source(source);
|
||||
_screenshot.~ScreenshotHelper();
|
||||
new (&_screenshot) ScreenshotHelper(s, false, 0, true, _path);
|
||||
new (&_screenshot) ScreenshotHelper(s, QRect(), false, 0, true, _path);
|
||||
obs_source_release(s);
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ bool MacroActionSequence::PerformAction()
|
||||
return true;
|
||||
}
|
||||
|
||||
return macro->PerformActions();
|
||||
return macro->PerformActions(true);
|
||||
}
|
||||
|
||||
void MacroActionSequence::LogAction() const
|
||||
|
||||
@@ -27,6 +27,12 @@ const static std::map<MacroActionSource::Action, std::string> actionTypes = {
|
||||
"AdvSceneSwitcher.action.source.type.deinterlaceMode"},
|
||||
{MacroActionSource::Action::DEINTERLACE_FIELD_ORDER,
|
||||
"AdvSceneSwitcher.action.source.type.deinterlaceOrder"},
|
||||
{MacroActionSource::Action::OPEN_INTERACTION_DIALOG,
|
||||
"AdvSceneSwitcher.action.source.type.openInteractionDialog"},
|
||||
{MacroActionSource::Action::OPEN_FILTER_DIALOG,
|
||||
"AdvSceneSwitcher.action.source.type.openFilterDialog"},
|
||||
{MacroActionSource::Action::OPEN_PROPERTIES_DIALOG,
|
||||
"AdvSceneSwitcher.action.source.type.openPropertiesDialog"},
|
||||
};
|
||||
|
||||
const static std::map<obs_deinterlace_mode, std::string> deinterlaceModes = {
|
||||
@@ -58,6 +64,16 @@ const static std::map<obs_deinterlace_field_order, std::string>
|
||||
"AdvSceneSwitcher.action.source.deinterlaceOrder.bottomFieldFirst"},
|
||||
};
|
||||
|
||||
const static std::map<MacroActionSource::SettingsInputMethod, std::string>
|
||||
inputMethods = {
|
||||
{MacroActionSource::SettingsInputMethod::INDIVIDUAL_MANUAL,
|
||||
"AdvSceneSwitcher.action.source.inputMethod.individualManual"},
|
||||
{MacroActionSource::SettingsInputMethod::INDIVIDUAL_TEMPVAR,
|
||||
"AdvSceneSwitcher.action.source.inputMethod.individualTempvar"},
|
||||
{MacroActionSource::SettingsInputMethod::JSON_STRING,
|
||||
"AdvSceneSwitcher.action.source.inputMethod.json"},
|
||||
};
|
||||
|
||||
static std::vector<SourceSettingButton> getSourceButtons(OBSWeakSource source)
|
||||
{
|
||||
auto s = obs_weak_source_get_source(source);
|
||||
@@ -73,6 +89,7 @@ static std::vector<SourceSettingButton> getSourceButtons(OBSWeakSource source)
|
||||
buttons.emplace_back(button);
|
||||
} while (obs_property_next(&it));
|
||||
obs_source_release(s);
|
||||
obs_properties_destroy(sourceProperties);
|
||||
return buttons;
|
||||
}
|
||||
|
||||
@@ -110,6 +127,12 @@ static void refreshSourceSettings(obs_source_t *s)
|
||||
}
|
||||
}
|
||||
|
||||
static bool isInteractable(obs_source_t *source)
|
||||
{
|
||||
uint32_t flags = obs_source_get_output_flags(source);
|
||||
return (flags & OBS_SOURCE_INTERACTION) != 0;
|
||||
}
|
||||
|
||||
bool MacroActionSource::PerformAction()
|
||||
{
|
||||
auto s = obs_weak_source_get_source(_source.GetSource());
|
||||
@@ -121,7 +144,26 @@ bool MacroActionSource::PerformAction()
|
||||
obs_source_set_enabled(s, false);
|
||||
break;
|
||||
case Action::SETTINGS:
|
||||
SetSourceSettings(s, _settings);
|
||||
switch (_settingsInputMethod) {
|
||||
case SettingsInputMethod::INDIVIDUAL_MANUAL:
|
||||
SetSourceSetting(s, _setting, _manualSettingValue);
|
||||
break;
|
||||
case SettingsInputMethod::INDIVIDUAL_TEMPVAR: {
|
||||
auto var = _tempVar.GetTempVariable(GetMacro());
|
||||
if (!var) {
|
||||
break;
|
||||
}
|
||||
auto value = var->Value();
|
||||
if (!value) {
|
||||
break;
|
||||
}
|
||||
SetSourceSetting(s, _setting, *value);
|
||||
break;
|
||||
}
|
||||
case SettingsInputMethod::JSON_STRING:
|
||||
SetSourceSettings(s, _settingsString);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Action::REFRESH_SETTINGS:
|
||||
refreshSourceSettings(s);
|
||||
@@ -135,6 +177,22 @@ bool MacroActionSource::PerformAction()
|
||||
case Action::DEINTERLACE_FIELD_ORDER:
|
||||
obs_source_set_deinterlace_field_order(s, _deinterlaceOrder);
|
||||
break;
|
||||
case Action::OPEN_INTERACTION_DIALOG:
|
||||
if (isInteractable(s)) {
|
||||
obs_frontend_open_source_interaction(s);
|
||||
} else {
|
||||
blog(LOG_INFO,
|
||||
"refusing to open interaction dialog "
|
||||
"for non intractable source \"%s\"",
|
||||
_source.ToString().c_str());
|
||||
}
|
||||
break;
|
||||
case Action::OPEN_FILTER_DIALOG:
|
||||
obs_frontend_open_source_filters(s);
|
||||
break;
|
||||
case Action::OPEN_PROPERTIES_DIALOG:
|
||||
obs_frontend_open_source_properties(s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -160,7 +218,12 @@ bool MacroActionSource::Save(obs_data_t *obj) const
|
||||
_source.Save(obj);
|
||||
obs_data_set_int(obj, "action", static_cast<int>(_action));
|
||||
_button.Save(obj);
|
||||
_settings.Save(obj, "settings");
|
||||
obs_data_set_int(obj, "inputMethod",
|
||||
static_cast<int>(_settingsInputMethod));
|
||||
_setting.Save(obj);
|
||||
_manualSettingValue.Save(obj, "manualSettingValue");
|
||||
_tempVar.Save(obj);
|
||||
_settingsString.Save(obj, "settings");
|
||||
obs_data_set_int(obj, "deinterlaceMode",
|
||||
static_cast<int>(_deinterlaceMode));
|
||||
obs_data_set_int(obj, "deinterlaceOrder",
|
||||
@@ -174,7 +237,17 @@ bool MacroActionSource::Load(obs_data_t *obj)
|
||||
_source.Load(obj);
|
||||
_action = static_cast<Action>(obs_data_get_int(obj, "action"));
|
||||
_button.Load(obj);
|
||||
_settings.Load(obj, "settings");
|
||||
// TODO: Remove fallback in future version
|
||||
if (obs_data_has_user_value(obj, "inputMethod")) {
|
||||
_settingsInputMethod = static_cast<SettingsInputMethod>(
|
||||
obs_data_get_int(obj, "inputMethod"));
|
||||
} else {
|
||||
_settingsInputMethod = SettingsInputMethod::JSON_STRING;
|
||||
}
|
||||
_setting.Load(obj);
|
||||
_settingsString.Load(obj, "settings");
|
||||
_manualSettingValue.Load(obj, "manualSettingValue");
|
||||
_tempVar.Load(obj, GetMacro());
|
||||
_deinterlaceMode = static_cast<obs_deinterlace_mode>(
|
||||
obs_data_get_int(obj, "deinterlaceMode"));
|
||||
_deinterlaceOrder = static_cast<obs_deinterlace_field_order>(
|
||||
@@ -237,19 +310,34 @@ static inline void populateDeinterlaceFieldOrderSelection(QComboBox *list)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void populateSettingsInputMethods(QComboBox *list)
|
||||
{
|
||||
list->clear();
|
||||
for (const auto &[value, name] : inputMethods) {
|
||||
list->addItem(obs_module_text(name.c_str()),
|
||||
static_cast<int>(value));
|
||||
}
|
||||
}
|
||||
|
||||
MacroActionSourceEdit::MacroActionSourceEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroActionSource> entryData)
|
||||
: QWidget(parent),
|
||||
_sources(new SourceSelectionWidget(this, QStringList(), true)),
|
||||
_actions(new QComboBox()),
|
||||
_settingsButtons(new QComboBox()),
|
||||
_settingsLayout(new QHBoxLayout()),
|
||||
_settingsInputMethods(new QComboBox(this)),
|
||||
_manualSettingValue(new VariableTextEdit(this, 5, 1, 1)),
|
||||
_tempVars(new TempVariableSelection(this)),
|
||||
_sourceSettings(new SourceSettingSelection(this)),
|
||||
_settingsString(new VariableTextEdit(this)),
|
||||
_getSettings(new QPushButton(obs_module_text(
|
||||
"AdvSceneSwitcher.action.source.getSettings"))),
|
||||
_settings(new VariableTextEdit(this)),
|
||||
_deinterlaceMode(new QComboBox()),
|
||||
_deinterlaceOrder(new QComboBox()),
|
||||
_warning(new QLabel(
|
||||
obs_module_text("AdvSceneSwitcher.action.source.warning")))
|
||||
|
||||
{
|
||||
populateActionSelection(_actions);
|
||||
auto sources = GetSourceNames();
|
||||
@@ -257,6 +345,7 @@ MacroActionSourceEdit::MacroActionSourceEdit(
|
||||
_sources->SetSourceNameList(sources);
|
||||
populateDeinterlaceModeSelection(_deinterlaceMode);
|
||||
populateDeinterlaceFieldOrderSelection(_deinterlaceOrder);
|
||||
populateSettingsInputMethods(_settingsInputMethods);
|
||||
|
||||
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(ActionChanged(int)));
|
||||
@@ -267,20 +356,33 @@ MacroActionSourceEdit::MacroActionSourceEdit(
|
||||
SLOT(SourceChanged(const SourceSelection &)));
|
||||
QWidget::connect(_getSettings, SIGNAL(clicked()), this,
|
||||
SLOT(GetSettingsClicked()));
|
||||
QWidget::connect(_settings, SIGNAL(textChanged()), this,
|
||||
SLOT(SettingsChanged()));
|
||||
QWidget::connect(_settingsString, SIGNAL(textChanged()), this,
|
||||
SLOT(SettingsStringChanged()));
|
||||
QWidget::connect(_deinterlaceMode, SIGNAL(currentIndexChanged(int)),
|
||||
this, SLOT(DeinterlaceModeChanged(int)));
|
||||
QWidget::connect(_deinterlaceOrder, SIGNAL(currentIndexChanged(int)),
|
||||
this, SLOT(DeinterlaceOrderChanged(int)));
|
||||
QWidget::connect(_tempVars,
|
||||
SIGNAL(SelectionChanged(const TempVariableRef &)),
|
||||
this, SLOT(SelectionChanged(const TempVariableRef &)));
|
||||
QWidget::connect(_settingsInputMethods,
|
||||
SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(SettingsInputMethodChanged(int)));
|
||||
QWidget::connect(_manualSettingValue, SIGNAL(textChanged()), this,
|
||||
SLOT(ManualSettingsValueChanged()));
|
||||
QWidget::connect(_sourceSettings,
|
||||
SIGNAL(SelectionChanged(const SourceSetting &)), this,
|
||||
SLOT(SelectionChanged(const SourceSetting &)));
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
QHBoxLayout *entryLayout = new QHBoxLayout;
|
||||
QHBoxLayout *buttonLayout = new QHBoxLayout;
|
||||
auto entryLayout = new QHBoxLayout;
|
||||
entryLayout->setContentsMargins(0, 0, 0, 0);
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{sources}}", _sources},
|
||||
{"{{actions}}", _actions},
|
||||
{"{{settings}}", _settings},
|
||||
{"{{settings}}", _sourceSettings},
|
||||
{"{{settingsInputMethod}}", _settingsInputMethods},
|
||||
{"{{settingValue}}", _manualSettingValue},
|
||||
{"{{tempVar}}", _tempVars},
|
||||
{"{{getSettings}}", _getSettings},
|
||||
{"{{settingsButtons}}", _settingsButtons},
|
||||
{"{{deinterlaceMode}}", _deinterlaceMode},
|
||||
@@ -288,9 +390,17 @@ MacroActionSourceEdit::MacroActionSourceEdit(
|
||||
};
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.source.entry"),
|
||||
entryLayout, widgetPlaceholders);
|
||||
_settingsLayout->setContentsMargins(0, 0, 0, 0);
|
||||
PlaceWidgets(obs_module_text(
|
||||
"AdvSceneSwitcher.action.source.entry.settings"),
|
||||
_settingsLayout, widgetPlaceholders);
|
||||
auto mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(entryLayout);
|
||||
mainLayout->addLayout(_settingsLayout);
|
||||
mainLayout->addWidget(_warning);
|
||||
mainLayout->addWidget(_settings);
|
||||
mainLayout->addWidget(_settingsString);
|
||||
auto buttonLayout = new QHBoxLayout;
|
||||
buttonLayout->setContentsMargins(0, 0, 0, 0);
|
||||
buttonLayout->addWidget(_getSettings);
|
||||
buttonLayout->addStretch();
|
||||
mainLayout->addLayout(buttonLayout);
|
||||
@@ -311,13 +421,20 @@ void MacroActionSourceEdit::UpdateEntryData()
|
||||
_entryData->_source.GetSource());
|
||||
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
|
||||
_sources->SetSource(_entryData->_source);
|
||||
_sourceSettings->SetSource(_entryData->_source.GetSource());
|
||||
_sourceSettings->SetSetting(_entryData->_setting);
|
||||
_settingsButtons->setCurrentText(
|
||||
QString::fromStdString(_entryData->_button.ToString()));
|
||||
_settings->setPlainText(_entryData->_settings);
|
||||
_settingsString->setPlainText(_entryData->_settingsString);
|
||||
_deinterlaceMode->setCurrentIndex(_deinterlaceMode->findData(
|
||||
static_cast<int>(_entryData->_deinterlaceMode)));
|
||||
_deinterlaceOrder->setCurrentIndex(_deinterlaceOrder->findData(
|
||||
static_cast<int>(_entryData->_deinterlaceOrder)));
|
||||
_settingsInputMethods->setCurrentIndex(_settingsInputMethods->findData(
|
||||
static_cast<int>(_entryData->_settingsInputMethod)));
|
||||
_tempVars->SetVariable(_entryData->_tempVar);
|
||||
_manualSettingValue->setPlainText(_entryData->_manualSettingValue);
|
||||
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
@@ -333,6 +450,7 @@ void MacroActionSourceEdit::SourceChanged(const SourceSelection &source)
|
||||
}
|
||||
populateSourceButtonSelection(_settingsButtons,
|
||||
_entryData->_source.GetSource());
|
||||
_sourceSettings->SetSource(_entryData->_source.GetSource());
|
||||
emit HeaderInfoChanged(
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
}
|
||||
@@ -365,18 +483,29 @@ void MacroActionSourceEdit::GetSettingsClicked()
|
||||
return;
|
||||
}
|
||||
|
||||
_settings->setPlainText(FormatJsonString(
|
||||
GetSourceSettings(_entryData->_source.GetSource())));
|
||||
switch (_entryData->_settingsInputMethod) {
|
||||
case MacroActionSource::SettingsInputMethod::INDIVIDUAL_MANUAL:
|
||||
_manualSettingValue->setPlainText(GetSourceSettingValue(
|
||||
_entryData->_source.GetSource(), _entryData->_setting));
|
||||
break;
|
||||
case MacroActionSource::SettingsInputMethod::INDIVIDUAL_TEMPVAR:
|
||||
break;
|
||||
case MacroActionSource::SettingsInputMethod::JSON_STRING:
|
||||
_settingsString->setPlainText(FormatJsonString(
|
||||
GetSourceSettings(_entryData->_source.GetSource())));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MacroActionSourceEdit::SettingsChanged()
|
||||
void MacroActionSourceEdit::SettingsStringChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_settings = _settings->toPlainText().toStdString();
|
||||
_entryData->_settingsString =
|
||||
_settingsString->toPlainText().toStdString();
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
@@ -405,15 +534,87 @@ void MacroActionSourceEdit::DeinterlaceOrderChanged(int idx)
|
||||
_deinterlaceOrder->itemData(idx).toInt());
|
||||
}
|
||||
|
||||
void MacroActionSourceEdit::SelectionChanged(const TempVariableRef &var)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_tempVar = var;
|
||||
}
|
||||
|
||||
void MacroActionSourceEdit::SettingsInputMethodChanged(int idx)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_settingsInputMethod =
|
||||
static_cast<MacroActionSource::SettingsInputMethod>(
|
||||
_settingsInputMethods->itemData(idx).toInt());
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionSourceEdit::SelectionChanged(const SourceSetting &setting)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_setting = setting;
|
||||
}
|
||||
|
||||
void MacroActionSourceEdit::ManualSettingsValueChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_manualSettingValue =
|
||||
_manualSettingValue->toPlainText().toStdString();
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void MacroActionSourceEdit::SetWidgetVisibility()
|
||||
{
|
||||
const bool showSettings = _entryData->_action ==
|
||||
MacroActionSource::Action::SETTINGS;
|
||||
SetLayoutVisible(_settingsLayout,
|
||||
_entryData->_action ==
|
||||
MacroActionSource::Action::SETTINGS);
|
||||
_sourceSettings->setVisible(
|
||||
_entryData->_action == MacroActionSource::Action::SETTINGS &&
|
||||
_entryData->_settingsInputMethod !=
|
||||
MacroActionSource::SettingsInputMethod::JSON_STRING);
|
||||
_settingsString->setVisible(
|
||||
_entryData->_action == MacroActionSource::Action::SETTINGS &&
|
||||
_entryData->_settingsInputMethod ==
|
||||
MacroActionSource::SettingsInputMethod::JSON_STRING);
|
||||
_getSettings->setVisible(_entryData->_action ==
|
||||
MacroActionSource::Action::SETTINGS);
|
||||
_tempVars->setVisible(_entryData->_action ==
|
||||
MacroActionSource::Action::SETTINGS &&
|
||||
_entryData->_settingsInputMethod ==
|
||||
MacroActionSource::SettingsInputMethod::
|
||||
INDIVIDUAL_TEMPVAR);
|
||||
|
||||
if (_entryData->_action == MacroActionSource::Action::SETTINGS &&
|
||||
_entryData->_settingsInputMethod ==
|
||||
MacroActionSource::SettingsInputMethod::INDIVIDUAL_MANUAL) {
|
||||
RemoveStretchIfPresent(_settingsLayout);
|
||||
_manualSettingValue->show();
|
||||
} else {
|
||||
AddStretchIfNecessary(_settingsLayout);
|
||||
_manualSettingValue->hide();
|
||||
}
|
||||
|
||||
const bool showWarning =
|
||||
_entryData->_action == MacroActionSource::Action::ENABLE ||
|
||||
_entryData->_action == MacroActionSource::Action::DISABLE;
|
||||
_settings->setVisible(showSettings);
|
||||
_getSettings->setVisible(showSettings);
|
||||
_warning->setVisible(showWarning);
|
||||
_settingsButtons->setVisible(
|
||||
_entryData->_action ==
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "macro-action-edit.hpp"
|
||||
#include "variable-text-edit.hpp"
|
||||
#include "source-selection.hpp"
|
||||
#include "source-setting.hpp"
|
||||
|
||||
#include <QSpinBox>
|
||||
#include <QLabel>
|
||||
@@ -35,10 +36,13 @@ public:
|
||||
|
||||
SourceSelection _source;
|
||||
SourceSettingButton _button;
|
||||
StringVariable _settings = "";
|
||||
StringVariable _settingsString = "";
|
||||
StringVariable _manualSettingValue = "";
|
||||
obs_deinterlace_mode _deinterlaceMode = OBS_DEINTERLACE_MODE_DISABLE;
|
||||
obs_deinterlace_field_order _deinterlaceOrder =
|
||||
OBS_DEINTERLACE_FIELD_ORDER_TOP;
|
||||
TempVariableRef _tempVar;
|
||||
SourceSetting _setting;
|
||||
|
||||
enum class Action {
|
||||
ENABLE,
|
||||
@@ -48,8 +52,19 @@ public:
|
||||
SETTINGS_BUTTON,
|
||||
DEINTERLACE_MODE,
|
||||
DEINTERLACE_FIELD_ORDER,
|
||||
OPEN_INTERACTION_DIALOG,
|
||||
OPEN_FILTER_DIALOG,
|
||||
OPEN_PROPERTIES_DIALOG,
|
||||
};
|
||||
Action _action = Action::ENABLE;
|
||||
Action _action = Action::SETTINGS;
|
||||
|
||||
enum class SettingsInputMethod {
|
||||
INDIVIDUAL_MANUAL,
|
||||
INDIVIDUAL_TEMPVAR,
|
||||
JSON_STRING,
|
||||
};
|
||||
SettingsInputMethod _settingsInputMethod =
|
||||
SettingsInputMethod::INDIVIDUAL_MANUAL;
|
||||
|
||||
private:
|
||||
static bool _registered;
|
||||
@@ -77,9 +92,13 @@ private slots:
|
||||
void ActionChanged(int value);
|
||||
void ButtonChanged(int idx);
|
||||
void GetSettingsClicked();
|
||||
void SettingsChanged();
|
||||
void SettingsStringChanged();
|
||||
void DeinterlaceModeChanged(int);
|
||||
void DeinterlaceOrderChanged(int);
|
||||
void SelectionChanged(const TempVariableRef &);
|
||||
void SettingsInputMethodChanged(int);
|
||||
void SelectionChanged(const SourceSetting &);
|
||||
void ManualSettingsValueChanged();
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
|
||||
@@ -87,11 +106,17 @@ protected:
|
||||
SourceSelectionWidget *_sources;
|
||||
QComboBox *_actions;
|
||||
QComboBox *_settingsButtons;
|
||||
QHBoxLayout *_settingsLayout;
|
||||
QComboBox *_settingsInputMethods;
|
||||
VariableTextEdit *_manualSettingValue;
|
||||
TempVariableSelection *_tempVars;
|
||||
SourceSettingSelection *_sourceSettings;
|
||||
VariableTextEdit *_settingsString;
|
||||
QPushButton *_getSettings;
|
||||
VariableTextEdit *_settings;
|
||||
QComboBox *_deinterlaceMode;
|
||||
QComboBox *_deinterlaceOrder;
|
||||
QLabel *_warning;
|
||||
|
||||
std::shared_ptr<MacroActionSource> _entryData;
|
||||
|
||||
private:
|
||||
|
||||
@@ -10,14 +10,14 @@ bool MacroActionSudioMode::_registered = MacroActionFactory::Register(
|
||||
{MacroActionSudioMode::Create, MacroActionSudioModeEdit::Create,
|
||||
"AdvSceneSwitcher.action.studioMode"});
|
||||
|
||||
const static std::map<StudioModeAction, std::string> actionTypes = {
|
||||
{StudioModeAction::SWAP_SCENE,
|
||||
const static std::map<MacroActionSudioMode::Action, std::string> actionTypes = {
|
||||
{MacroActionSudioMode::Action::SWAP_SCENE,
|
||||
"AdvSceneSwitcher.action.studioMode.type.swap"},
|
||||
{StudioModeAction::SET_SCENE,
|
||||
{MacroActionSudioMode::Action::SET_SCENE,
|
||||
"AdvSceneSwitcher.action.studioMode.type.setScene"},
|
||||
{StudioModeAction::ENABLE_STUDIO_MODE,
|
||||
{MacroActionSudioMode::Action::ENABLE_STUDIO_MODE,
|
||||
"AdvSceneSwitcher.action.studioMode.type.enable"},
|
||||
{StudioModeAction::DISABLE_STUDIO_MODE,
|
||||
{MacroActionSudioMode::Action::DISABLE_STUDIO_MODE,
|
||||
"AdvSceneSwitcher.action.studioMode.type.disable"},
|
||||
};
|
||||
|
||||
@@ -41,19 +41,19 @@ static void enableStudioMode(bool enable)
|
||||
bool MacroActionSudioMode::PerformAction()
|
||||
{
|
||||
switch (_action) {
|
||||
case StudioModeAction::SWAP_SCENE:
|
||||
case Action::SWAP_SCENE:
|
||||
obs_frontend_preview_program_trigger_transition();
|
||||
break;
|
||||
case StudioModeAction::SET_SCENE: {
|
||||
case Action::SET_SCENE: {
|
||||
auto s = obs_weak_source_get_source(_scene.GetScene());
|
||||
obs_frontend_set_current_preview_scene(s);
|
||||
obs_source_release(s);
|
||||
break;
|
||||
}
|
||||
case StudioModeAction::ENABLE_STUDIO_MODE:
|
||||
case Action::ENABLE_STUDIO_MODE:
|
||||
enableStudioMode(true);
|
||||
break;
|
||||
case StudioModeAction::DISABLE_STUDIO_MODE:
|
||||
case Action::DISABLE_STUDIO_MODE:
|
||||
enableStudioMode(false);
|
||||
break;
|
||||
default:
|
||||
@@ -86,15 +86,14 @@ bool MacroActionSudioMode::Save(obs_data_t *obj) const
|
||||
bool MacroActionSudioMode::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroAction::Load(obj);
|
||||
_action =
|
||||
static_cast<StudioModeAction>(obs_data_get_int(obj, "action"));
|
||||
_action = static_cast<Action>(obs_data_get_int(obj, "action"));
|
||||
_scene.Load(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string MacroActionSudioMode::GetShortDesc() const
|
||||
{
|
||||
if (_action == StudioModeAction::SET_SCENE) {
|
||||
if (_action == Action::SET_SCENE) {
|
||||
return _scene.ToString();
|
||||
}
|
||||
return "";
|
||||
@@ -102,8 +101,9 @@ std::string MacroActionSudioMode::GetShortDesc() const
|
||||
|
||||
static inline void populateActionSelection(QComboBox *list)
|
||||
{
|
||||
for (auto entry : actionTypes) {
|
||||
list->addItem(obs_module_text(entry.second.c_str()));
|
||||
for (const auto &[id, name] : actionTypes) {
|
||||
list->addItem(obs_module_text(name.c_str()),
|
||||
static_cast<int>(id));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,9 +139,10 @@ void MacroActionSudioModeEdit::UpdateEntryData()
|
||||
if (!_entryData) {
|
||||
return;
|
||||
}
|
||||
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
|
||||
_actions->setCurrentIndex(
|
||||
_actions->findData(static_cast<int>(_entryData->_action)));
|
||||
_scenes->SetScene(_entryData->_scene);
|
||||
_scenes->setVisible(_entryData->_action == StudioModeAction::SET_SCENE);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionSudioModeEdit::SceneChanged(const SceneSelection &s)
|
||||
@@ -156,15 +157,27 @@ void MacroActionSudioModeEdit::SceneChanged(const SceneSelection &s)
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
}
|
||||
|
||||
void MacroActionSudioModeEdit::ActionChanged(int value)
|
||||
void MacroActionSudioModeEdit::SetWidgetVisibility()
|
||||
{
|
||||
_scenes->setVisible(_entryData->_action ==
|
||||
MacroActionSudioMode::Action::SET_SCENE);
|
||||
|
||||
if (_entryData->_action != MacroActionSudioMode::Action::SET_SCENE) {
|
||||
_actions->removeItem(_actions->findData(static_cast<int>(
|
||||
MacroActionSudioMode::Action::SET_SCENE)));
|
||||
}
|
||||
}
|
||||
|
||||
void MacroActionSudioModeEdit::ActionChanged(int index)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_action = static_cast<StudioModeAction>(value);
|
||||
_scenes->setVisible(_entryData->_action == StudioModeAction::SET_SCENE);
|
||||
_entryData->_action = static_cast<MacroActionSudioMode::Action>(
|
||||
_actions->itemData(index).toInt());
|
||||
SetWidgetVisibility();
|
||||
emit HeaderInfoChanged(
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
}
|
||||
|
||||
@@ -4,13 +4,6 @@
|
||||
|
||||
namespace advss {
|
||||
|
||||
enum class StudioModeAction {
|
||||
SWAP_SCENE,
|
||||
SET_SCENE,
|
||||
ENABLE_STUDIO_MODE,
|
||||
DISABLE_STUDIO_MODE,
|
||||
};
|
||||
|
||||
class MacroActionSudioMode : public MacroAction {
|
||||
public:
|
||||
MacroActionSudioMode(Macro *m) : MacroAction(m) {}
|
||||
@@ -25,7 +18,14 @@ public:
|
||||
return std::make_shared<MacroActionSudioMode>(m);
|
||||
}
|
||||
|
||||
StudioModeAction _action = StudioModeAction::SWAP_SCENE;
|
||||
enum class Action {
|
||||
SWAP_SCENE,
|
||||
SET_SCENE, // TODO: Remove in future version as the
|
||||
// functionality moved to the scene switch action
|
||||
ENABLE_STUDIO_MODE,
|
||||
DISABLE_STUDIO_MODE,
|
||||
};
|
||||
Action _action = Action::SWAP_SCENE;
|
||||
SceneSelection _scene;
|
||||
|
||||
private:
|
||||
@@ -55,12 +55,13 @@ private slots:
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
|
||||
protected:
|
||||
private:
|
||||
void SetWidgetVisibility();
|
||||
|
||||
QComboBox *_actions;
|
||||
SceneSelectionWidget *_scenes;
|
||||
std::shared_ptr<MacroActionSudioMode> _entryData;
|
||||
|
||||
private:
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "macro-action-variable.hpp"
|
||||
#include "macro-condition-edit.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "math-helpers.hpp"
|
||||
@@ -41,6 +40,18 @@ const static std::map<MacroActionVariable::Type, std::string> actionTypes = {
|
||||
"AdvSceneSwitcher.action.variable.type.mathExpression"},
|
||||
{MacroActionVariable::Type::USER_INPUT,
|
||||
"AdvSceneSwitcher.action.variable.type.askForValue"},
|
||||
{MacroActionVariable::Type::ENV_VARIABLE,
|
||||
"AdvSceneSwitcher.action.variable.type.environmentVariable"},
|
||||
{MacroActionVariable::Type::SCENE_ITEM_COUNT,
|
||||
"AdvSceneSwitcher.action.variable.type.sceneItemCount"},
|
||||
{MacroActionVariable::Type::STRING_LENGTH,
|
||||
"AdvSceneSwitcher.action.variable.type.stringLength"},
|
||||
{MacroActionVariable::Type::EXTRACT_JSON,
|
||||
"AdvSceneSwitcher.action.variable.type.extractJson"},
|
||||
{MacroActionVariable::Type::SET_TO_TEMPVAR,
|
||||
"AdvSceneSwitcher.action.variable.type.setToTempvar"},
|
||||
{MacroActionVariable::Type::SCENE_ITEM_NAME,
|
||||
"AdvSceneSwitcher.action.variable.type.sceneItemName"},
|
||||
};
|
||||
|
||||
static void apppend(Variable &var, const std::string &value)
|
||||
@@ -124,8 +135,52 @@ void MacroActionVariable::HandleMathExpression(Variable *var)
|
||||
var->SetValue(std::get<double>(result));
|
||||
}
|
||||
|
||||
struct GetSceneItemNameHelper {
|
||||
int curIdx = 0;
|
||||
int targetIdx = 0;
|
||||
std::string name = "";
|
||||
};
|
||||
|
||||
static bool getSceneItemAtIdx(obs_scene_t *, obs_sceneitem_t *item, void *ptr)
|
||||
{
|
||||
auto data = reinterpret_cast<GetSceneItemNameHelper *>(ptr);
|
||||
if (obs_sceneitem_is_group(item)) {
|
||||
obs_scene_t *scene = obs_sceneitem_group_get_scene(item);
|
||||
obs_scene_enum_items(scene, getSceneItemAtIdx, ptr);
|
||||
}
|
||||
if (data->curIdx == data->targetIdx) {
|
||||
data->name =
|
||||
obs_source_get_name(obs_sceneitem_get_source(item));
|
||||
data->curIdx--;
|
||||
return false;
|
||||
}
|
||||
data->curIdx--;
|
||||
return true;
|
||||
}
|
||||
|
||||
void MacroActionVariable::SetToSceneItemName(Variable *var)
|
||||
{
|
||||
auto weakSource = _scene.GetScene();
|
||||
if (!weakSource) {
|
||||
var->SetValue("");
|
||||
return;
|
||||
}
|
||||
auto index = _sceneItemIndex.GetValue();
|
||||
if (index < 1) {
|
||||
var->SetValue("");
|
||||
return;
|
||||
}
|
||||
auto sceneItemCount = GetSceneItemCount(weakSource);
|
||||
OBSSourceAutoRelease source = obs_weak_source_get_source(weakSource);
|
||||
auto scene = obs_scene_from_source(source);
|
||||
GetSceneItemNameHelper data{sceneItemCount, index};
|
||||
obs_scene_enum_items(scene, getSceneItemAtIdx, &data);
|
||||
var->SetValue(data.name);
|
||||
}
|
||||
|
||||
struct AskForInputParams {
|
||||
QString prompt;
|
||||
QString placeholder;
|
||||
std::optional<std::string> result;
|
||||
};
|
||||
|
||||
@@ -134,6 +189,7 @@ static void askForInput(void *param)
|
||||
auto parameters = static_cast<AskForInputParams *>(param);
|
||||
auto dialog = new NonModalMessageDialog(
|
||||
parameters->prompt, NonModalMessageDialog::Type::INPUT);
|
||||
dialog->SetInput(parameters->placeholder);
|
||||
parameters->result = dialog->GetInput();
|
||||
}
|
||||
|
||||
@@ -213,6 +269,9 @@ bool MacroActionVariable::PerformAction()
|
||||
"AdvSceneSwitcher.action.variable.askForValuePromptDefault"))
|
||||
.arg(QString::fromStdString(
|
||||
var->Name())),
|
||||
_useCustomPrompt && _useInputPlaceholder
|
||||
? QString::fromStdString(_inputPlaceholder)
|
||||
: "",
|
||||
{}};
|
||||
obs_queue_task(OBS_TASK_UI, askForInput, ¶ms, true);
|
||||
if (!params.result.has_value()) {
|
||||
@@ -221,6 +280,41 @@ bool MacroActionVariable::PerformAction()
|
||||
var->SetValue(*params.result);
|
||||
return true;
|
||||
}
|
||||
case Type::ENV_VARIABLE: {
|
||||
var->SetValue(std::getenv(_envVariableName.c_str()));
|
||||
return true;
|
||||
}
|
||||
case Type::SCENE_ITEM_COUNT: {
|
||||
var->SetValue(GetSceneItemCount(_scene.GetScene(false)));
|
||||
return true;
|
||||
}
|
||||
case Type::STRING_LENGTH: {
|
||||
var->SetValue(std::string(_strValue).length());
|
||||
return true;
|
||||
}
|
||||
case Type::EXTRACT_JSON: {
|
||||
auto value = GetJsonField(var->Value(), _strValue);
|
||||
if (!value.has_value()) {
|
||||
return true;
|
||||
}
|
||||
var->SetValue(*value);
|
||||
return true;
|
||||
}
|
||||
case Type::SET_TO_TEMPVAR: {
|
||||
auto tempVar = _tempVar.GetTempVariable(GetMacro());
|
||||
if (!tempVar) {
|
||||
return true;
|
||||
}
|
||||
auto value = tempVar->Value();
|
||||
if (!value) {
|
||||
return true;
|
||||
}
|
||||
var->SetValue(*value);
|
||||
return true;
|
||||
}
|
||||
case Type::SCENE_ITEM_NAME:
|
||||
SetToSceneItemName(var.get());
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -233,7 +327,7 @@ bool MacroActionVariable::Save(obs_data_t *obj) const
|
||||
GetWeakVariableName(_variable).c_str());
|
||||
obs_data_set_string(obj, "variable2Name",
|
||||
GetWeakVariableName(_variable2).c_str());
|
||||
obs_data_set_string(obj, "strValue", _strValue.c_str());
|
||||
_strValue.Save(obj, "strValue");
|
||||
obs_data_set_double(obj, "numValue", _numValue);
|
||||
obs_data_set_int(obj, "condition", static_cast<int>(_type));
|
||||
obs_data_set_int(obj, "segmentIdx", GetSegmentIndexValue());
|
||||
@@ -241,12 +335,18 @@ bool MacroActionVariable::Save(obs_data_t *obj) const
|
||||
obs_data_set_int(obj, "subStringSize", _subStringSize);
|
||||
obs_data_set_string(obj, "regexPattern", _regexPattern.c_str());
|
||||
obs_data_set_int(obj, "regexMatchIdx", _regexMatchIdx);
|
||||
obs_data_set_string(obj, "findStr", _findStr.c_str());
|
||||
obs_data_set_string(obj, "replaceStr", _replaceStr.c_str());
|
||||
_findStr.Save(obj, "findStr");
|
||||
_replaceStr.Save(obj, "replaceStr");
|
||||
_regex.Save(obj);
|
||||
_mathExpression.Save(obj, "mathExpression");
|
||||
obs_data_set_bool(obj, "useCustomPrompt", _useCustomPrompt);
|
||||
_inputPrompt.Save(obj, "inputPrompt");
|
||||
obs_data_set_bool(obj, "useInputPlaceholder", _useInputPlaceholder);
|
||||
_inputPlaceholder.Save(obj, "inputPlaceholder");
|
||||
_envVariableName.Save(obj, "environmentVariableName");
|
||||
_scene.Save(obj);
|
||||
_tempVar.Save(obj);
|
||||
_sceneItemIndex.Save(obj, "sceneItemIndex");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -257,7 +357,7 @@ bool MacroActionVariable::Load(obs_data_t *obj)
|
||||
GetWeakVariableByName(obs_data_get_string(obj, "variableName"));
|
||||
_variable2 = GetWeakVariableByName(
|
||||
obs_data_get_string(obj, "variable2Name"));
|
||||
_strValue = obs_data_get_string(obj, "strValue");
|
||||
_strValue.Load(obj, "strValue");
|
||||
_numValue = obs_data_get_double(obj, "numValue");
|
||||
_type = static_cast<Type>(obs_data_get_int(obj, "condition"));
|
||||
_segmentIdxLoadValue = obs_data_get_int(obj, "segmentIdx");
|
||||
@@ -266,11 +366,17 @@ bool MacroActionVariable::Load(obs_data_t *obj)
|
||||
_regex.Load(obj);
|
||||
_regexPattern = obs_data_get_string(obj, "regexPattern");
|
||||
_regexMatchIdx = obs_data_get_int(obj, "regexMatchIdx");
|
||||
_findStr = obs_data_get_string(obj, "findStr");
|
||||
_replaceStr = obs_data_get_string(obj, "replaceStr");
|
||||
_findStr.Load(obj, "findStr");
|
||||
_replaceStr.Load(obj, "replaceStr");
|
||||
_mathExpression.Load(obj, "mathExpression");
|
||||
_useCustomPrompt = obs_data_get_bool(obj, "useCustomPrompt");
|
||||
_inputPrompt.Load(obj, "inputPrompt");
|
||||
_useInputPlaceholder = obs_data_get_bool(obj, "useInputPlaceholder");
|
||||
_inputPlaceholder.Load(obj, "inputPlaceholder");
|
||||
_envVariableName.Load(obj, "environmentVariableName");
|
||||
_scene.Load(obj);
|
||||
_tempVar.Load(obj, GetMacro());
|
||||
_sceneItemIndex.Load(obj, "sceneItemIndex");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -313,7 +419,7 @@ void MacroActionVariable::SetSegmentIndexValue(int value)
|
||||
|
||||
_macroSegment = segment;
|
||||
if (segment) {
|
||||
segment->IncrementVariableRef();
|
||||
IncrementVariableRef(segment.get());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,13 +461,14 @@ void MacroActionVariable::DecrementCurrentSegmentVariableRef()
|
||||
return;
|
||||
}
|
||||
|
||||
segment->DecrementVariableRef();
|
||||
DecrementVariableRef(segment.get());
|
||||
}
|
||||
|
||||
static inline void populateTypeSelection(QComboBox *list)
|
||||
{
|
||||
for (auto entry : actionTypes) {
|
||||
list->addItem(obs_module_text(entry.second.c_str()));
|
||||
for (const auto &[action, name] : actionTypes) {
|
||||
list->addItem(obs_module_text(name.c_str()),
|
||||
static_cast<int>(action));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,8 +477,8 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
: QWidget(parent),
|
||||
_variables(new VariableSelection(this)),
|
||||
_variables2(new VariableSelection(this)),
|
||||
_actions(new QComboBox()),
|
||||
_strValue(new ResizingPlainTextEdit(this, 5, 1, 1)),
|
||||
_actions(new FilterComboBox(this)),
|
||||
_strValue(new VariableTextEdit(this, 5, 1, 1)),
|
||||
_numValue(new QDoubleSpinBox()),
|
||||
_segmentIdx(new MacroSegmentSelection(
|
||||
this, MacroSegmentSelection::Type::CONDITION, false)),
|
||||
@@ -386,13 +493,21 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
_regexPattern(new ResizingPlainTextEdit(this, 10, 1, 1)),
|
||||
_regexMatchIdx(new QSpinBox()),
|
||||
_findReplaceLayout(new QHBoxLayout()),
|
||||
_findStr(new ResizingPlainTextEdit(this, 10, 1, 1)),
|
||||
_replaceStr(new ResizingPlainTextEdit(this, 10, 1, 1)),
|
||||
_findStr(new VariableTextEdit(this, 10, 1, 1)),
|
||||
_replaceStr(new VariableTextEdit(this, 10, 1, 1)),
|
||||
_mathExpression(new VariableLineEdit(this)),
|
||||
_mathExpressionResult(new QLabel()),
|
||||
_promptLayout(new QHBoxLayout()),
|
||||
_useCustomPrompt(new QCheckBox()),
|
||||
_inputPrompt(new VariableLineEdit(this))
|
||||
_inputPrompt(new VariableLineEdit(this)),
|
||||
_placeholderLayout(new QHBoxLayout()),
|
||||
_useInputPlaceholder(new QCheckBox()),
|
||||
_inputPlaceholder(new VariableLineEdit(this)),
|
||||
_envVariable(new VariableLineEdit(this)),
|
||||
_scenes(new SceneSelectionWidget(this, true, false, true, true,
|
||||
true)),
|
||||
_tempVars(new TempVariableSelection(this)),
|
||||
_sceneItemIndex(new VariableSpinBox())
|
||||
{
|
||||
_numValue->setMinimum(-9999999999);
|
||||
_numValue->setMaximum(9999999999);
|
||||
@@ -410,6 +525,7 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
_regexMatchIdx->setSuffix(".");
|
||||
_inputPrompt->setSizePolicy(QSizePolicy::MinimumExpanding,
|
||||
QSizePolicy::Preferred);
|
||||
_sceneItemIndex->setMinimum(1);
|
||||
populateTypeSelection(_actions);
|
||||
|
||||
QWidget::connect(_variables, SIGNAL(SelectionChanged(const QString &)),
|
||||
@@ -447,6 +563,21 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
SLOT(UseCustomPromptChanged(int)));
|
||||
QWidget::connect(_inputPrompt, SIGNAL(editingFinished()), this,
|
||||
SLOT(InputPromptChanged()));
|
||||
QWidget::connect(_useInputPlaceholder, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(UseInputPlaceholderChanged(int)));
|
||||
QWidget::connect(_inputPlaceholder, SIGNAL(editingFinished()), this,
|
||||
SLOT(InputPlaceholderChanged()));
|
||||
QWidget::connect(_envVariable, SIGNAL(editingFinished()), this,
|
||||
SLOT(EnvVariableChanged()));
|
||||
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
|
||||
this, SLOT(SceneChanged(const SceneSelection &)));
|
||||
QWidget::connect(_tempVars,
|
||||
SIGNAL(SelectionChanged(const TempVariableRef &)),
|
||||
this, SLOT(SelectionChanged(const TempVariableRef &)));
|
||||
QWidget::connect(
|
||||
_sceneItemIndex,
|
||||
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
||||
this, SLOT(SceneItemIndexChanged(const NumberVariable<int> &)));
|
||||
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{variables}}", _variables},
|
||||
@@ -463,6 +594,12 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
{"{{mathExpression}}", _mathExpression},
|
||||
{"{{useCustomPrompt}}", _useCustomPrompt},
|
||||
{"{{inputPrompt}}", _inputPrompt},
|
||||
{"{{useInputPlaceholder}}", _useInputPlaceholder},
|
||||
{"{{inputPlaceholder}}", _inputPlaceholder},
|
||||
{"{{envVariableName}}", _envVariable},
|
||||
{"{{scenes}}", _scenes},
|
||||
{"{{tempVars}}", _tempVars},
|
||||
{"{{sceneItemIndex}}", _sceneItemIndex},
|
||||
};
|
||||
auto entryLayout = new QHBoxLayout;
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.variable.entry"),
|
||||
@@ -485,8 +622,12 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.entry.userInput"),
|
||||
"AdvSceneSwitcher.action.variable.entry.userInput.customPrompt"),
|
||||
_promptLayout, widgetPlaceholders);
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.entry.userInput.placeholder"),
|
||||
_placeholderLayout, widgetPlaceholders);
|
||||
|
||||
auto regexConfigLayout = new QHBoxLayout;
|
||||
regexConfigLayout->addWidget(_regex);
|
||||
@@ -505,6 +646,7 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
layout->addLayout(_findReplaceLayout);
|
||||
layout->addWidget(_mathExpressionResult);
|
||||
layout->addLayout(_promptLayout);
|
||||
layout->addLayout(_placeholderLayout);
|
||||
setLayout(layout);
|
||||
|
||||
_entryData = entryData;
|
||||
@@ -525,8 +667,9 @@ void MacroActionVariableEdit::UpdateEntryData()
|
||||
|
||||
_variables->SetVariable(_entryData->_variable);
|
||||
_variables2->SetVariable(_entryData->_variable2);
|
||||
_actions->setCurrentIndex(static_cast<int>(_entryData->_type));
|
||||
_strValue->setPlainText(QString::fromStdString(_entryData->_strValue));
|
||||
_actions->setCurrentIndex(
|
||||
_actions->findData(static_cast<int>(_entryData->_type)));
|
||||
_strValue->setPlainText(_entryData->_strValue);
|
||||
_numValue->setValue(_entryData->_numValue);
|
||||
_segmentIdx->SetValue(_entryData->GetSegmentIndexValue() + 1);
|
||||
_segmentIdx->SetMacro(_entryData->GetMacro());
|
||||
@@ -541,12 +684,17 @@ void MacroActionVariableEdit::UpdateEntryData()
|
||||
_regexPattern->setPlainText(
|
||||
QString::fromStdString(_entryData->_regexPattern));
|
||||
_regexMatchIdx->setValue(_entryData->_regexMatchIdx + 1);
|
||||
_findStr->setPlainText(QString::fromStdString(_entryData->_findStr));
|
||||
_replaceStr->setPlainText(
|
||||
QString::fromStdString(_entryData->_replaceStr));
|
||||
_findStr->setPlainText(_entryData->_findStr);
|
||||
_replaceStr->setPlainText(_entryData->_replaceStr);
|
||||
_mathExpression->setText(_entryData->_mathExpression);
|
||||
_useCustomPrompt->setChecked(_entryData->_useCustomPrompt);
|
||||
_inputPrompt->setText(_entryData->_inputPrompt);
|
||||
_useInputPlaceholder->setChecked(_entryData->_useInputPlaceholder);
|
||||
_inputPlaceholder->setText(_entryData->_inputPlaceholder);
|
||||
_envVariable->setText(_entryData->_envVariableName);
|
||||
_scenes->SetScene(_entryData->_scene);
|
||||
_tempVars->SetVariable(_entryData->_tempVar);
|
||||
_sceneItemIndex->SetValue(_entryData->_sceneItemIndex);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
@@ -570,14 +718,15 @@ void MacroActionVariableEdit::Variable2Changed(const QString &text)
|
||||
_entryData->_variable2 = GetWeakVariableByQString(text);
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::ActionChanged(int value)
|
||||
void MacroActionVariableEdit::ActionChanged(int idx)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
if (_loading || !_entryData || idx == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_type = static_cast<MacroActionVariable::Type>(value);
|
||||
_entryData->_type = static_cast<MacroActionVariable::Type>(
|
||||
_actions->itemData(idx).toInt());
|
||||
|
||||
if (_entryData->_type == MacroActionVariable::Type::SET_ACTION_VALUE) {
|
||||
_segmentIdx->SetType(MacroSegmentSelection::Type::ACTION);
|
||||
@@ -674,7 +823,7 @@ void MacroActionVariableEdit::UpdateSegmentVariableValue()
|
||||
return;
|
||||
}
|
||||
|
||||
if (!segment->SupportsVariableValue()) {
|
||||
if (!SupportsVariableValue(segment.get())) {
|
||||
std::string type;
|
||||
QString fmt;
|
||||
|
||||
@@ -699,8 +848,14 @@ void MacroActionVariableEdit::UpdateSegmentVariableValue()
|
||||
_segmentValueStatus->setText(obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.currentSegmentValue"));
|
||||
_segmentValue->show();
|
||||
_segmentValue->setPlainText(
|
||||
QString::fromStdString(segment->GetVariableValue()));
|
||||
|
||||
// Only update the text if the value changed to prevent possible text
|
||||
// selections being lost
|
||||
auto previousText = _segmentValue->toPlainText();
|
||||
auto newText = QString::fromStdString(segment->GetVariableValue());
|
||||
if (newText != previousText) {
|
||||
_segmentValue->setPlainText(newText);
|
||||
}
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
@@ -818,15 +973,9 @@ void MacroActionVariableEdit::UseCustomPromptChanged(int value)
|
||||
return;
|
||||
}
|
||||
|
||||
_inputPrompt->setVisible(value);
|
||||
if (value) {
|
||||
RemoveStretchIfPresent(_promptLayout);
|
||||
} else {
|
||||
AddStretchIfNecessary(_promptLayout);
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_useCustomPrompt = value;
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::InputPromptChanged()
|
||||
@@ -839,6 +988,68 @@ void MacroActionVariableEdit::InputPromptChanged()
|
||||
_entryData->_inputPrompt = _inputPrompt->text().toStdString();
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::UseInputPlaceholderChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_useInputPlaceholder = value;
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::InputPlaceholderChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_inputPlaceholder = _inputPlaceholder->text().toStdString();
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::EnvVariableChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_envVariableName = _envVariable->text().toStdString();
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::SceneChanged(const SceneSelection &scene)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_scene = scene;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::SelectionChanged(const TempVariableRef &var)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_tempVar = var;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::SceneItemIndexChanged(
|
||||
const NumberVariable<int> &value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_sceneItemIndex = value;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::SetWidgetVisibility()
|
||||
{
|
||||
if (!_entryData) {
|
||||
@@ -850,7 +1061,9 @@ void MacroActionVariableEdit::SetWidgetVisibility()
|
||||
_strValue->setVisible(
|
||||
_entryData->_type ==
|
||||
MacroActionVariable::Type::SET_FIXED_VALUE ||
|
||||
_entryData->_type == MacroActionVariable::Type::APPEND);
|
||||
_entryData->_type == MacroActionVariable::Type::APPEND ||
|
||||
_entryData->_type == MacroActionVariable::Type::STRING_LENGTH ||
|
||||
_entryData->_type == MacroActionVariable::Type::EXTRACT_JSON);
|
||||
_numValue->setVisible(
|
||||
_entryData->_type == MacroActionVariable::Type::INCREMENT ||
|
||||
_entryData->_type == MacroActionVariable::Type::DECREMENT);
|
||||
@@ -887,7 +1100,41 @@ void MacroActionVariableEdit::SetWidgetVisibility()
|
||||
SetLayoutVisible(_promptLayout,
|
||||
_entryData->_type ==
|
||||
MacroActionVariable::Type::USER_INPUT);
|
||||
_inputPrompt->setVisible(_entryData->_useCustomPrompt);
|
||||
_inputPrompt->setVisible(
|
||||
_entryData->_type == MacroActionVariable::Type::USER_INPUT &&
|
||||
_entryData->_useCustomPrompt);
|
||||
if (_entryData->_useCustomPrompt) {
|
||||
RemoveStretchIfPresent(_promptLayout);
|
||||
} else {
|
||||
AddStretchIfNecessary(_promptLayout);
|
||||
}
|
||||
SetLayoutVisible(
|
||||
_placeholderLayout,
|
||||
_entryData->_type == MacroActionVariable::Type::USER_INPUT &&
|
||||
_entryData->_useCustomPrompt);
|
||||
_useInputPlaceholder->setVisible(
|
||||
_entryData->_type == MacroActionVariable::Type::USER_INPUT &&
|
||||
_entryData->_useCustomPrompt);
|
||||
_inputPlaceholder->setVisible(
|
||||
_entryData->_type == MacroActionVariable::Type::USER_INPUT &&
|
||||
_entryData->_useCustomPrompt &&
|
||||
_entryData->_useInputPlaceholder);
|
||||
if (_entryData->_useInputPlaceholder) {
|
||||
RemoveStretchIfPresent(_placeholderLayout);
|
||||
} else {
|
||||
AddStretchIfNecessary(_placeholderLayout);
|
||||
}
|
||||
_envVariable->setVisible(_entryData->_type ==
|
||||
MacroActionVariable::Type::ENV_VARIABLE);
|
||||
_scenes->setVisible(
|
||||
_entryData->_type ==
|
||||
MacroActionVariable::Type::SCENE_ITEM_COUNT ||
|
||||
_entryData->_type ==
|
||||
MacroActionVariable::Type::SCENE_ITEM_NAME);
|
||||
_tempVars->setVisible(_entryData->_type ==
|
||||
MacroActionVariable::Type::SET_TO_TEMPVAR);
|
||||
_sceneItemIndex->setVisible(_entryData->_type ==
|
||||
MacroActionVariable::Type::SCENE_ITEM_NAME);
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
#include "macro-segment-selection.hpp"
|
||||
#include "regex-config.hpp"
|
||||
#include "resizing-text-edit.hpp"
|
||||
#include "scene-selection.hpp"
|
||||
#include "variable-line-edit.hpp"
|
||||
#include "variable-text-edit.hpp"
|
||||
#include "variable-spinbox.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
@@ -37,27 +40,44 @@ public:
|
||||
FIND_AND_REPLACE,
|
||||
MATH_EXPRESSION,
|
||||
USER_INPUT,
|
||||
ENV_VARIABLE,
|
||||
SCENE_ITEM_COUNT,
|
||||
STRING_LENGTH,
|
||||
EXTRACT_JSON,
|
||||
SET_TO_TEMPVAR,
|
||||
SCENE_ITEM_NAME,
|
||||
};
|
||||
|
||||
Type _type = Type::SET_FIXED_VALUE;
|
||||
std::weak_ptr<Variable> _variable;
|
||||
std::weak_ptr<Variable> _variable2;
|
||||
std::string _strValue = "";
|
||||
StringVariable _strValue = "";
|
||||
double _numValue = 0;
|
||||
int _subStringStart = 0;
|
||||
int _subStringSize = 0;
|
||||
RegexConfig _regex = RegexConfig::PartialMatchRegexConfig();
|
||||
std::string _regexPattern = ".*";
|
||||
int _regexMatchIdx = 0;
|
||||
std::string _findStr = obs_module_text(
|
||||
StringVariable _findStr = obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.findAndReplace.find");
|
||||
std::string _replaceStr = obs_module_text(
|
||||
StringVariable _replaceStr = obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.findAndReplace.replace");
|
||||
StringVariable _mathExpression = obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.mathExpression.example");
|
||||
bool _useCustomPrompt = false;
|
||||
StringVariable _inputPrompt = obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.askForValuePrompt");
|
||||
bool _useInputPlaceholder = false;
|
||||
StringVariable _inputPlaceholder =
|
||||
obs_module_text("AdvSceneSwitcher.enterText");
|
||||
#ifdef _WIN32
|
||||
StringVariable _envVariableName = "USERPROFILE";
|
||||
#else
|
||||
StringVariable _envVariableName = "HOME";
|
||||
#endif
|
||||
SceneSelection _scene;
|
||||
TempVariableRef _tempVar;
|
||||
IntVariable _sceneItemIndex = 1;
|
||||
|
||||
private:
|
||||
void DecrementCurrentSegmentVariableRef();
|
||||
@@ -65,6 +85,7 @@ private:
|
||||
void HandleRegexSubString(Variable *);
|
||||
void HandleFindAndReplace(Variable *);
|
||||
void HandleMathExpression(Variable *);
|
||||
void SetToSceneItemName(Variable *);
|
||||
|
||||
std::weak_ptr<MacroSegment> _macroSegment;
|
||||
int _segmentIdxLoadValue = -1;
|
||||
@@ -107,15 +128,24 @@ private slots:
|
||||
void MathExpressionChanged();
|
||||
void UseCustomPromptChanged(int);
|
||||
void InputPromptChanged();
|
||||
void UseInputPlaceholderChanged(int);
|
||||
void InputPlaceholderChanged();
|
||||
void EnvVariableChanged();
|
||||
void SceneChanged(const SceneSelection &);
|
||||
void SelectionChanged(const TempVariableRef &var);
|
||||
void SceneItemIndexChanged(const NumberVariable<int> &);
|
||||
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
|
||||
protected:
|
||||
private:
|
||||
void SetWidgetVisibility();
|
||||
void SetSegmentValueError(const QString &);
|
||||
|
||||
VariableSelection *_variables;
|
||||
VariableSelection *_variables2;
|
||||
QComboBox *_actions;
|
||||
ResizingPlainTextEdit *_strValue;
|
||||
FilterComboBox *_actions;
|
||||
VariableTextEdit *_strValue;
|
||||
QDoubleSpinBox *_numValue;
|
||||
MacroSegmentSelection *_segmentIdx;
|
||||
QLabel *_segmentValueStatus;
|
||||
@@ -129,19 +159,22 @@ protected:
|
||||
ResizingPlainTextEdit *_regexPattern;
|
||||
QSpinBox *_regexMatchIdx;
|
||||
QHBoxLayout *_findReplaceLayout;
|
||||
ResizingPlainTextEdit *_findStr;
|
||||
ResizingPlainTextEdit *_replaceStr;
|
||||
VariableTextEdit *_findStr;
|
||||
VariableTextEdit *_replaceStr;
|
||||
VariableLineEdit *_mathExpression;
|
||||
QLabel *_mathExpressionResult;
|
||||
QHBoxLayout *_promptLayout;
|
||||
QCheckBox *_useCustomPrompt;
|
||||
VariableLineEdit *_inputPrompt;
|
||||
QHBoxLayout *_placeholderLayout;
|
||||
QCheckBox *_useInputPlaceholder;
|
||||
VariableLineEdit *_inputPlaceholder;
|
||||
VariableLineEdit *_envVariable;
|
||||
SceneSelectionWidget *_scenes;
|
||||
TempVariableSelection *_tempVars;
|
||||
VariableSpinBox *_sceneItemIndex;
|
||||
|
||||
std::shared_ptr<MacroActionVariable> _entryData;
|
||||
|
||||
private:
|
||||
void SetWidgetVisibility();
|
||||
void SetSegmentValueError(const QString &);
|
||||
|
||||
QTimer _timer;
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "macro-action-wait.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "sync-helpers.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <random>
|
||||
@@ -24,8 +26,8 @@ static std::default_random_engine re(rd());
|
||||
static void waitHelper(std::unique_lock<std::mutex> *lock, Macro *macro,
|
||||
std::chrono::high_resolution_clock::time_point &time)
|
||||
{
|
||||
while (!switcher->abortMacroWait && !macro->GetStop()) {
|
||||
if (switcher->macroWaitCv.wait_until(*lock, time) ==
|
||||
while (!MacroWaitShouldAbort() && !macro->GetStop()) {
|
||||
if (GetMacroWaitCV().wait_until(*lock, time) ==
|
||||
std::cv_status::timeout) {
|
||||
break;
|
||||
}
|
||||
@@ -53,11 +55,11 @@ bool MacroActionWait::PerformAction()
|
||||
auto time = std::chrono::high_resolution_clock::now() +
|
||||
std::chrono::milliseconds((int)(sleepDuration * 1000));
|
||||
|
||||
switcher->abortMacroWait = false;
|
||||
std::unique_lock<std::mutex> lock(switcher->m);
|
||||
SetMacroAbortWait(false);
|
||||
std::unique_lock<std::mutex> lock(*GetMutex());
|
||||
waitHelper(&lock, GetMacro(), time);
|
||||
|
||||
return !switcher->abortMacroWait;
|
||||
return !MacroWaitShouldAbort();
|
||||
}
|
||||
|
||||
bool MacroActionWait::Save(obs_data_t *obj) const
|
||||
|
||||
@@ -192,7 +192,7 @@ void MacroActionWebsocketEdit::CheckForSettingsConflict()
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void MacroActionWebsocketEdit::SetupWidgetVisibility()
|
||||
void MacroActionWebsocketEdit::SetWidgetVisibility()
|
||||
{
|
||||
_messageType->setVisible(_entryData->_api ==
|
||||
MacroActionWebsocket::API::SCENE_SWITCHER);
|
||||
@@ -283,7 +283,7 @@ void MacroActionWebsocketEdit::UpdateEntryData()
|
||||
_message->setPlainText(_entryData->_message);
|
||||
_connection->SetConnection(_entryData->_connection);
|
||||
|
||||
SetupWidgetVisibility();
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionWebsocketEdit::APITypeChanged(int index)
|
||||
@@ -294,7 +294,7 @@ void MacroActionWebsocketEdit::APITypeChanged(int index)
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_api = static_cast<MacroActionWebsocket::API>(index);
|
||||
SetupWidgetVisibility();
|
||||
SetWidgetVisibility();
|
||||
emit HeaderInfoChanged(
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
}
|
||||
@@ -308,7 +308,7 @@ void MacroActionWebsocketEdit::MessageTypeChanged(int index)
|
||||
auto lock = LockContext();
|
||||
_entryData->_type =
|
||||
static_cast<MacroActionWebsocket::MessageType>(index);
|
||||
SetupWidgetVisibility();
|
||||
SetWidgetVisibility();
|
||||
emit HeaderInfoChanged(
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ protected:
|
||||
|
||||
private:
|
||||
void CheckForSettingsConflict();
|
||||
void SetupWidgetVisibility();
|
||||
void SetWidgetVisibility();
|
||||
void SetupRequestEdit();
|
||||
void SetupEventEdit();
|
||||
void SetupGenericEdit();
|
||||
|
||||
@@ -47,6 +47,12 @@ const static std::map<MacroConditionAudio::VolumeCondition, std::string>
|
||||
"AdvSceneSwitcher.condition.audio.state.unmute"},
|
||||
};
|
||||
|
||||
void MacroConditionAudio::SetType(const Type &type)
|
||||
{
|
||||
_checkType = type;
|
||||
SetupTempVars();
|
||||
}
|
||||
|
||||
MacroConditionAudio::~MacroConditionAudio()
|
||||
{
|
||||
obs_volmeter_remove_callback(_volmeter, SetVolumeLevel, this);
|
||||
@@ -56,17 +62,17 @@ MacroConditionAudio::~MacroConditionAudio()
|
||||
bool MacroConditionAudio::CheckOutputCondition()
|
||||
{
|
||||
bool ret = false;
|
||||
auto s = obs_weak_source_get_source(_audioSource.GetSource());
|
||||
OBSSourceAutoRelease source =
|
||||
obs_weak_source_get_source(_audioSource.GetSource());
|
||||
|
||||
// peak will have a value from -60 db to 0 db so we need to scale it
|
||||
double curVolume = ((double)_peak + 60) * 1.7;
|
||||
|
||||
switch (_outputCondition) {
|
||||
case OutputCondition::ABOVE:
|
||||
// peak will have a value from -60 db to 0 db
|
||||
ret = curVolume > _volume;
|
||||
break;
|
||||
case OutputCondition::BELOW:
|
||||
// peak will have a value from -60 db to 0 db
|
||||
ret = curVolume < _volume;
|
||||
break;
|
||||
default:
|
||||
@@ -74,24 +80,25 @@ bool MacroConditionAudio::CheckOutputCondition()
|
||||
}
|
||||
|
||||
SetVariableValue(std::to_string(curVolume));
|
||||
SetTempVarValue("output_volume", std::to_string(curVolume));
|
||||
|
||||
// Reset for next check
|
||||
_peak = -std::numeric_limits<float>::infinity();
|
||||
obs_source_release(s);
|
||||
if (_audioSource.GetType() == SourceSelection::Type::VARIABLE) {
|
||||
ResetVolmeter();
|
||||
}
|
||||
|
||||
return ret;
|
||||
return ret && source;
|
||||
}
|
||||
|
||||
bool MacroConditionAudio::CheckVolumeCondition()
|
||||
{
|
||||
bool ret = false;
|
||||
auto s = obs_weak_source_get_source(_audioSource.GetSource());
|
||||
OBSSourceAutoRelease source =
|
||||
obs_weak_source_get_source(_audioSource.GetSource());
|
||||
|
||||
float curVolume = obs_source_get_volume(s);
|
||||
bool muted = obs_source_muted(s);
|
||||
float curVolume = obs_source_get_volume(source);
|
||||
bool muted = obs_source_muted(source);
|
||||
|
||||
switch (_volumeCondition) {
|
||||
case VolumeCondition::ABOVE:
|
||||
@@ -118,8 +125,10 @@ bool MacroConditionAudio::CheckVolumeCondition()
|
||||
break;
|
||||
}
|
||||
|
||||
obs_source_release(s);
|
||||
return ret;
|
||||
SetTempVarValue("configured_volume", std::to_string(curVolume));
|
||||
SetTempVarValue("muted", (source && muted) ? "true" : "false");
|
||||
|
||||
return ret && source;
|
||||
}
|
||||
|
||||
bool MacroConditionAudio::CheckSyncOffset()
|
||||
@@ -129,16 +138,17 @@ bool MacroConditionAudio::CheckSyncOffset()
|
||||
}
|
||||
|
||||
bool ret = false;
|
||||
auto s = obs_weak_source_get_source(_audioSource.GetSource());
|
||||
auto curOffset = obs_source_get_sync_offset(s) / nsPerMs;
|
||||
OBSSourceAutoRelease source =
|
||||
obs_weak_source_get_source(_audioSource.GetSource());
|
||||
auto curOffset = obs_source_get_sync_offset(source) / nsPerMs;
|
||||
if (_outputCondition == OutputCondition::ABOVE) {
|
||||
ret = curOffset > _syncOffset;
|
||||
} else {
|
||||
ret = curOffset < _syncOffset;
|
||||
}
|
||||
SetVariableValue(std::to_string(curOffset));
|
||||
obs_source_release(s);
|
||||
return ret;
|
||||
SetTempVarValue("sync_offset", std::to_string(curOffset));
|
||||
return ret && source;
|
||||
}
|
||||
|
||||
bool MacroConditionAudio::CheckMonitor()
|
||||
@@ -148,11 +158,13 @@ bool MacroConditionAudio::CheckMonitor()
|
||||
}
|
||||
|
||||
bool ret = false;
|
||||
auto s = obs_weak_source_get_source(_audioSource.GetSource());
|
||||
ret = obs_source_get_monitoring_type(s) == _monitorType;
|
||||
OBSSourceAutoRelease source =
|
||||
obs_weak_source_get_source(_audioSource.GetSource());
|
||||
ret = obs_source_get_monitoring_type(source) == _monitorType;
|
||||
SetVariableValue("");
|
||||
obs_source_release(s);
|
||||
return ret;
|
||||
SetTempVarValue("monitor",
|
||||
std::to_string(obs_source_get_monitoring_type(source)));
|
||||
return ret && source;
|
||||
}
|
||||
|
||||
bool MacroConditionAudio::CheckBalance()
|
||||
@@ -162,16 +174,17 @@ bool MacroConditionAudio::CheckBalance()
|
||||
}
|
||||
|
||||
bool ret = false;
|
||||
auto s = obs_weak_source_get_source(_audioSource.GetSource());
|
||||
auto curBalance = obs_source_get_balance_value(s);
|
||||
OBSSourceAutoRelease source =
|
||||
obs_weak_source_get_source(_audioSource.GetSource());
|
||||
auto curBalance = obs_source_get_balance_value(source);
|
||||
if (_outputCondition == OutputCondition::ABOVE) {
|
||||
ret = curBalance > _balance;
|
||||
} else {
|
||||
ret = curBalance < _balance;
|
||||
}
|
||||
SetVariableValue(std::to_string(curBalance));
|
||||
obs_source_release(s);
|
||||
return ret;
|
||||
SetTempVarValue("balance", std::to_string(curBalance));
|
||||
return ret && source;
|
||||
}
|
||||
|
||||
bool MacroConditionAudio::CheckCondition()
|
||||
@@ -225,13 +238,12 @@ obs_volmeter_t *AddVolmeterToSource(MacroConditionAudio *entry,
|
||||
obs_volmeter_t *volmeter = obs_volmeter_create(OBS_FADER_LOG);
|
||||
obs_volmeter_add_callback(volmeter, MacroConditionAudio::SetVolumeLevel,
|
||||
entry);
|
||||
obs_source_t *as = obs_weak_source_get_source(source);
|
||||
if (!obs_volmeter_attach_source(volmeter, as)) {
|
||||
const char *name = obs_source_get_name(as);
|
||||
OBSSourceAutoRelease audioSource = obs_weak_source_get_source(source);
|
||||
if (!obs_volmeter_attach_source(volmeter, audioSource)) {
|
||||
const char *name = obs_source_get_name(audioSource);
|
||||
blog(LOG_WARNING, "failed to attach volmeter to source %s",
|
||||
name);
|
||||
}
|
||||
obs_source_release(as);
|
||||
|
||||
return volmeter;
|
||||
}
|
||||
@@ -290,6 +302,50 @@ void MacroConditionAudio::ResetVolmeter()
|
||||
_volmeter = AddVolmeterToSource(this, _audioSource.GetSource());
|
||||
}
|
||||
|
||||
void MacroConditionAudio::SetupTempVars()
|
||||
{
|
||||
MacroCondition::SetupTempVars();
|
||||
switch (_checkType) {
|
||||
case Type::OUTPUT_VOLUME:
|
||||
AddTempvar(
|
||||
"output_volume",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.audio.output_volume"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.audio.output_volume.description"));
|
||||
break;
|
||||
case Type::CONFIGURED_VOLUME:
|
||||
AddTempvar(
|
||||
"configured_volume",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.audio.configured_volume"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.audio.configured_volume.description"));
|
||||
AddTempvar("muted",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.audio.muted"));
|
||||
break;
|
||||
case Type::SYNC_OFFSET:
|
||||
AddTempvar(
|
||||
"sync_offset",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.audio.sync_offset"));
|
||||
break;
|
||||
case Type::MONITOR:
|
||||
AddTempvar("monitor",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.audio.monitor"));
|
||||
break;
|
||||
case Type::BALANCE:
|
||||
AddTempvar("balance",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.audio.balance"));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void populateCheckTypes(QComboBox *list)
|
||||
{
|
||||
list->clear();
|
||||
@@ -397,10 +453,9 @@ MacroConditionAudioEdit::MacroConditionAudioEdit(
|
||||
void MacroConditionAudioEdit::UpdateVolmeterSource()
|
||||
{
|
||||
delete _volMeter;
|
||||
obs_source_t *soruce = obs_weak_source_get_source(
|
||||
OBSSourceAutoRelease soruce = obs_weak_source_get_source(
|
||||
_entryData->_audioSource.GetSource());
|
||||
_volMeter = new VolControl(soruce);
|
||||
obs_source_release(soruce);
|
||||
_volMeter = new VolControl(soruce.Get());
|
||||
|
||||
QLayout *layout = this->layout();
|
||||
layout->addWidget(_volMeter);
|
||||
@@ -479,10 +534,9 @@ void MacroConditionAudioEdit::ConditionChanged(int cond)
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
if (_entryData->_checkType ==
|
||||
MacroConditionAudio::Type::OUTPUT_VOLUME ||
|
||||
_entryData->_checkType == MacroConditionAudio::Type::BALANCE ||
|
||||
_entryData->_checkType == MacroConditionAudio::Type::SYNC_OFFSET) {
|
||||
if (_entryData->GetType() == MacroConditionAudio::Type::OUTPUT_VOLUME ||
|
||||
_entryData->GetType() == MacroConditionAudio::Type::BALANCE ||
|
||||
_entryData->GetType() == MacroConditionAudio::Type::SYNC_OFFSET) {
|
||||
_entryData->_outputCondition =
|
||||
static_cast<MacroConditionAudio::OutputCondition>(cond);
|
||||
} else {
|
||||
@@ -499,16 +553,15 @@ void MacroConditionAudioEdit::CheckTypeChanged(int idx)
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_checkType = static_cast<MacroConditionAudio::Type>(
|
||||
_checkTypes->itemData(idx).toInt());
|
||||
_entryData->SetType(static_cast<MacroConditionAudio::Type>(
|
||||
_checkTypes->itemData(idx).toInt()));
|
||||
|
||||
const QSignalBlocker b(_condition);
|
||||
if (_entryData->_checkType ==
|
||||
MacroConditionAudio::Type::OUTPUT_VOLUME ||
|
||||
_entryData->_checkType == MacroConditionAudio::Type::BALANCE ||
|
||||
_entryData->_checkType == MacroConditionAudio::Type::SYNC_OFFSET) {
|
||||
if (_entryData->GetType() == MacroConditionAudio::Type::OUTPUT_VOLUME ||
|
||||
_entryData->GetType() == MacroConditionAudio::Type::BALANCE ||
|
||||
_entryData->GetType() == MacroConditionAudio::Type::SYNC_OFFSET) {
|
||||
populateOutputConditionSelection(_condition);
|
||||
} else if (_entryData->_checkType ==
|
||||
} else if (_entryData->GetType() ==
|
||||
MacroConditionAudio::Type::CONFIGURED_VOLUME) {
|
||||
populateVolumeConditionSelection(_condition);
|
||||
}
|
||||
@@ -526,17 +579,16 @@ void MacroConditionAudioEdit::UpdateEntryData()
|
||||
_syncOffset->SetValue(_entryData->_syncOffset);
|
||||
_monitorTypes->setCurrentIndex(_entryData->_monitorType);
|
||||
_balance->SetDoubleValue(_entryData->_balance);
|
||||
_checkTypes->setCurrentIndex(_checkTypes->findData(
|
||||
static_cast<int>(_entryData->_checkType)));
|
||||
_checkTypes->setCurrentIndex(
|
||||
_checkTypes->findData(static_cast<int>(_entryData->GetType())));
|
||||
|
||||
if (_entryData->_checkType ==
|
||||
MacroConditionAudio::Type::OUTPUT_VOLUME ||
|
||||
_entryData->_checkType == MacroConditionAudio::Type::BALANCE ||
|
||||
_entryData->_checkType == MacroConditionAudio::Type::SYNC_OFFSET) {
|
||||
if (_entryData->GetType() == MacroConditionAudio::Type::OUTPUT_VOLUME ||
|
||||
_entryData->GetType() == MacroConditionAudio::Type::BALANCE ||
|
||||
_entryData->GetType() == MacroConditionAudio::Type::SYNC_OFFSET) {
|
||||
populateOutputConditionSelection(_condition);
|
||||
_condition->setCurrentIndex(
|
||||
static_cast<int>(_entryData->_outputCondition));
|
||||
} else if (_entryData->_checkType ==
|
||||
} else if (_entryData->GetType() ==
|
||||
MacroConditionAudio::Type::CONFIGURED_VOLUME) {
|
||||
populateVolumeConditionSelection(_condition);
|
||||
_condition->setCurrentIndex(
|
||||
@@ -554,9 +606,9 @@ void MacroConditionAudioEdit::SetWidgetVisibility()
|
||||
}
|
||||
|
||||
_volume->setVisible(
|
||||
_entryData->_checkType ==
|
||||
_entryData->GetType() ==
|
||||
MacroConditionAudio::Type::OUTPUT_VOLUME ||
|
||||
(_entryData->_checkType ==
|
||||
(_entryData->GetType() ==
|
||||
MacroConditionAudio::Type::CONFIGURED_VOLUME &&
|
||||
(_entryData->_volumeCondition ==
|
||||
MacroConditionAudio::VolumeCondition::ABOVE ||
|
||||
@@ -565,20 +617,20 @@ void MacroConditionAudioEdit::SetWidgetVisibility()
|
||||
_entryData->_volumeCondition ==
|
||||
MacroConditionAudio::VolumeCondition::BELOW)));
|
||||
_condition->setVisible(
|
||||
_entryData->_checkType ==
|
||||
_entryData->GetType() ==
|
||||
MacroConditionAudio::Type::OUTPUT_VOLUME ||
|
||||
_entryData->_checkType ==
|
||||
_entryData->GetType() ==
|
||||
MacroConditionAudio::Type::CONFIGURED_VOLUME ||
|
||||
_entryData->_checkType == MacroConditionAudio::Type::BALANCE ||
|
||||
_entryData->_checkType ==
|
||||
_entryData->GetType() == MacroConditionAudio::Type::BALANCE ||
|
||||
_entryData->GetType() ==
|
||||
MacroConditionAudio::Type::SYNC_OFFSET);
|
||||
_syncOffset->setVisible(_entryData->_checkType ==
|
||||
_syncOffset->setVisible(_entryData->GetType() ==
|
||||
MacroConditionAudio::Type::SYNC_OFFSET);
|
||||
_monitorTypes->setVisible(_entryData->_checkType ==
|
||||
_monitorTypes->setVisible(_entryData->GetType() ==
|
||||
MacroConditionAudio::Type::MONITOR);
|
||||
_balance->setVisible(_entryData->_checkType ==
|
||||
_balance->setVisible(_entryData->GetType() ==
|
||||
MacroConditionAudio::Type::BALANCE);
|
||||
_volMeter->setVisible(_entryData->_checkType ==
|
||||
_volMeter->setVisible(_entryData->GetType() ==
|
||||
MacroConditionAudio::Type::OUTPUT_VOLUME);
|
||||
adjustSize();
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ public:
|
||||
MONITOR,
|
||||
BALANCE,
|
||||
};
|
||||
void SetType(const Type &);
|
||||
Type GetType() const { return _checkType; }
|
||||
|
||||
enum class OutputCondition {
|
||||
ABOVE,
|
||||
@@ -56,7 +58,6 @@ public:
|
||||
NumberVariable<int> _syncOffset = 0;
|
||||
obs_monitoring_type _monitorType = OBS_MONITORING_TYPE_NONE;
|
||||
NumberVariable<double> _balance = 0.5;
|
||||
Type _checkType = Type::OUTPUT_VOLUME;
|
||||
OutputCondition _outputCondition = OutputCondition::ABOVE;
|
||||
VolumeCondition _volumeCondition = VolumeCondition::ABOVE;
|
||||
obs_volmeter_t *_volmeter = nullptr;
|
||||
@@ -67,7 +68,9 @@ private:
|
||||
bool CheckSyncOffset();
|
||||
bool CheckMonitor();
|
||||
bool CheckBalance();
|
||||
void SetupTempVars();
|
||||
|
||||
Type _checkType = Type::OUTPUT_VOLUME;
|
||||
float _peak = -std::numeric_limits<float>::infinity();
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "macro-condition-cursor.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "platform-funcs.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
@@ -61,13 +60,15 @@ bool MacroConditionCursor::CheckCondition()
|
||||
std::to_string(cursorPos.second));
|
||||
break;
|
||||
case Condition::MOVING:
|
||||
ret = switcher->cursorPosChanged;
|
||||
ret = cursorPos.first != _lastCursorPosition.first ||
|
||||
cursorPos.second != _lastCursorPosition.second;
|
||||
break;
|
||||
case Condition::CLICK:
|
||||
ret = CheckClick();
|
||||
break;
|
||||
}
|
||||
_lastCheckTime = std::chrono::high_resolution_clock::now();
|
||||
_lastCursorPosition = cursorPos;
|
||||
|
||||
if (GetVariableValue().empty()) {
|
||||
SetVariableValue(ret ? "true" : "false");
|
||||
|
||||
@@ -41,6 +41,7 @@ public:
|
||||
private:
|
||||
bool CheckClick();
|
||||
std::chrono::high_resolution_clock::time_point _lastCheckTime{};
|
||||
std::pair<int, int> _lastCursorPosition;
|
||||
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
|
||||
@@ -60,7 +60,8 @@ const static std::map<MacroConditionDate::Day, std::string> dayOfWeekNames = {
|
||||
bool MacroConditionDate::CheckDayOfWeek(int64_t msSinceLastCheck)
|
||||
{
|
||||
QDateTime cur = QDateTime::currentDateTime();
|
||||
SetVariableValue(cur.toString().toStdString());
|
||||
SetVariables(cur);
|
||||
|
||||
if (_dayOfWeek != Day::ANY &&
|
||||
cur.date().dayOfWeek() != static_cast<int>(_dayOfWeek)) {
|
||||
return false;
|
||||
@@ -133,7 +134,7 @@ bool MacroConditionDate::CheckRegularDate(int64_t msSinceLastCheck)
|
||||
{
|
||||
bool match = false;
|
||||
QDateTime cur = QDateTime::currentDateTime();
|
||||
SetVariableValue(cur.toString().toStdString());
|
||||
SetVariables(cur);
|
||||
|
||||
if (_ignoreDate) {
|
||||
_dateTime.setDate(cur.date());
|
||||
@@ -304,6 +305,37 @@ QDateTime MacroConditionDate::GetNextMatchDateTime() const
|
||||
return _dateTime;
|
||||
}
|
||||
|
||||
void MacroConditionDate::SetVariables(const QDateTime &date)
|
||||
{
|
||||
SetVariableValue(date.toString().toStdString());
|
||||
|
||||
SetTempVarValue("year", std::to_string(date.date().year()));
|
||||
SetTempVarValue("month", std::to_string(date.date().month()));
|
||||
SetTempVarValue("day", std::to_string(date.date().day()));
|
||||
SetTempVarValue("hour", std::to_string(date.time().hour()));
|
||||
SetTempVarValue("minute", std::to_string(date.time().minute()));
|
||||
SetTempVarValue("second", std::to_string(date.time().second()));
|
||||
SetTempVarValue("dayOfWeek", std::to_string(date.date().dayOfWeek()));
|
||||
}
|
||||
|
||||
void MacroConditionDate::SetupTempVars()
|
||||
{
|
||||
MacroCondition::SetupTempVars();
|
||||
AddTempvar("year",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.date.year"));
|
||||
AddTempvar("month",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.date.month"));
|
||||
AddTempvar("day", obs_module_text("AdvSceneSwitcher.tempVar.date.day"));
|
||||
AddTempvar("hour",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.date.hour"));
|
||||
AddTempvar("minute",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.date.minute"));
|
||||
AddTempvar("second",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.date.second"));
|
||||
AddTempvar("dayOfWeek",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.date.dayOfWeek"));
|
||||
}
|
||||
|
||||
static inline void populateDaySelection(QComboBox *list)
|
||||
{
|
||||
for (auto entry : dayOfWeekNames) {
|
||||
@@ -606,10 +638,24 @@ void MacroConditionDateEdit::AdvancedSettingsToggleClicked()
|
||||
{
|
||||
auto lock = LockContext();
|
||||
_entryData->_dayOfWeekCheck = !_entryData->_dayOfWeekCheck;
|
||||
_entryData->_condition = MacroConditionDate::Condition::AT;
|
||||
}
|
||||
_condition->setCurrentIndex(0);
|
||||
_weekCondition->setCurrentIndex(0);
|
||||
|
||||
switch (_entryData->_condition) {
|
||||
case MacroConditionDate::Condition::BETWEEN:
|
||||
case MacroConditionDate::Condition::PATTERN:
|
||||
_condition->setCurrentIndex(0);
|
||||
_weekCondition->setCurrentIndex(0);
|
||||
break;
|
||||
case MacroConditionDate::Condition::AT:
|
||||
case MacroConditionDate::Condition::AFTER:
|
||||
case MacroConditionDate::Condition::BEFORE:
|
||||
_weekCondition->setCurrentIndex(
|
||||
static_cast<int>(_entryData->_condition));
|
||||
_condition->setCurrentIndex(
|
||||
static_cast<int>(_entryData->_condition));
|
||||
break;
|
||||
}
|
||||
|
||||
SetWidgetStatus();
|
||||
emit HeaderInfoChanged(
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
|
||||
@@ -64,6 +64,8 @@ private:
|
||||
bool CheckRegularDate(int64_t);
|
||||
bool CheckBetween(const QDateTime &now);
|
||||
bool CheckPattern(QDateTime now, int64_t secondsSinceLastCheck);
|
||||
void SetVariables(const QDateTime &date);
|
||||
void SetupTempVars();
|
||||
|
||||
QDateTime _dateTime = QDateTime::currentDateTime();
|
||||
QDateTime _dateTime2 = QDateTime::currentDateTime();
|
||||
|
||||
@@ -1,84 +1,24 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "macro-condition-edit.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "macro-properties.hpp"
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "macro-condition-scene.hpp"
|
||||
#include "section.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
std::map<std::string, MacroConditionInfo> &MacroConditionFactory::GetMap()
|
||||
{
|
||||
static std::map<std::string, MacroConditionInfo> _methods;
|
||||
return _methods;
|
||||
}
|
||||
|
||||
bool MacroConditionFactory::Register(const std::string &id,
|
||||
MacroConditionInfo info)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it == GetMap().end()) {
|
||||
GetMap()[id] = info;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroCondition>
|
||||
MacroConditionFactory::Create(const std::string &id, Macro *m)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||
return it->second._createFunc(m);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QWidget *
|
||||
MacroConditionFactory::CreateWidget(const std::string &id, QWidget *parent,
|
||||
std::shared_ptr<MacroCondition> cond)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||
return it->second._createWidgetFunc(parent, cond);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string MacroConditionFactory::GetConditionName(const std::string &id)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||
return it->second._name;
|
||||
}
|
||||
return "unknown condition";
|
||||
}
|
||||
|
||||
std::string MacroConditionFactory::GetIdByName(const QString &name)
|
||||
{
|
||||
for (auto it : GetMap()) {
|
||||
if (name == obs_module_text(it.second._name.c_str())) {
|
||||
return it.first;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
bool MacroConditionFactory::UsesDurationModifier(const std::string &id)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||
return it->second._useDurationModifier;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void populateLogicSelection(QComboBox *list, bool root = false)
|
||||
{
|
||||
if (root) {
|
||||
for (auto entry : MacroCondition::logicTypes) {
|
||||
for (const auto &entry : MacroCondition::logicTypes) {
|
||||
if (static_cast<int>(entry.first) < logic_root_offset) {
|
||||
list->addItem(obs_module_text(
|
||||
entry.second._name.c_str()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (auto entry : MacroCondition::logicTypes) {
|
||||
for (const auto &entry : MacroCondition::logicTypes) {
|
||||
if (static_cast<int>(entry.first) >=
|
||||
logic_root_offset) {
|
||||
list->addItem(obs_module_text(
|
||||
@@ -90,7 +30,7 @@ static inline void populateLogicSelection(QComboBox *list, bool root = false)
|
||||
|
||||
static inline void populateConditionSelection(QComboBox *list)
|
||||
{
|
||||
for (auto &[_, condition] :
|
||||
for (const auto &[_, condition] :
|
||||
MacroConditionFactory::GetConditionTypes()) {
|
||||
QString entry(obs_module_text(condition._name.c_str()));
|
||||
if (list->findText(entry) == -1) {
|
||||
@@ -179,7 +119,7 @@ void DurationModifierEdit::Collapse(bool collapse)
|
||||
MacroConditionEdit::MacroConditionEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroCondition> *entryData,
|
||||
const std::string &id, bool root)
|
||||
: MacroSegmentEdit(switcher->macroProperties._highlightConditions,
|
||||
: MacroSegmentEdit(GetGlobalMacroProperties()._highlightConditions,
|
||||
parent),
|
||||
_logicSelection(new QComboBox()),
|
||||
_conditionSelection(new FilterComboBox()),
|
||||
@@ -312,6 +252,7 @@ void MacroConditionEdit::ConditionSelectionChanged(const QString &text)
|
||||
*_entryData = MacroConditionFactory::Create(id, macro);
|
||||
(*_entryData)->SetIndex(idx);
|
||||
(*_entryData)->SetLogicType(logic);
|
||||
(*_entryData)->PostLoad();
|
||||
}
|
||||
auto widget =
|
||||
MacroConditionFactory::CreateWidget(id, this, *_entryData);
|
||||
@@ -342,7 +283,7 @@ void MacroConditionEdit::DurationModifierChanged(DurationModifier::Type m)
|
||||
(*_entryData)->SetDurationModifier(m);
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroSegment> MacroConditionEdit::Data()
|
||||
std::shared_ptr<MacroSegment> MacroConditionEdit::Data() const
|
||||
{
|
||||
return *_entryData;
|
||||
}
|
||||
@@ -383,9 +324,10 @@ void AdvSceneSwitcher::AddMacroCondition(int idx)
|
||||
macro->Conditions().at(idx)->Load(data);
|
||||
obs_data_release(data);
|
||||
}
|
||||
macro->Conditions().at(idx)->PostLoad();
|
||||
(*cond)->SetLogicType(logic);
|
||||
macro->UpdateConditionIndices();
|
||||
conditionsList->Insert(
|
||||
ui->conditionsList->Insert(
|
||||
idx,
|
||||
new MacroConditionEdit(this, ¯o->Conditions()[idx],
|
||||
id, idx == 0));
|
||||
@@ -410,7 +352,7 @@ void AdvSceneSwitcher::on_conditionAdd_clicked()
|
||||
if (currentConditionIdx != -1) {
|
||||
MacroConditionSelectionChanged(currentConditionIdx + 1);
|
||||
}
|
||||
conditionsList->SetHelpMsgVisible(false);
|
||||
ui->conditionsList->SetHelpMsgVisible(false);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::RemoveMacroCondition(int idx)
|
||||
@@ -426,14 +368,14 @@ void AdvSceneSwitcher::RemoveMacroCondition(int idx)
|
||||
|
||||
{
|
||||
auto lock = LockContext();
|
||||
conditionsList->Remove(idx);
|
||||
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(LogicType::ROOT_NONE);
|
||||
static_cast<MacroConditionEdit *>(
|
||||
conditionsList->WidgetAt(0))
|
||||
ui->conditionsList->WidgetAt(0))
|
||||
->SetRootNode(true);
|
||||
}
|
||||
SetConditionData(*macro);
|
||||
@@ -479,7 +421,7 @@ void AdvSceneSwitcher::on_conditionDown_clicked()
|
||||
{
|
||||
if (currentConditionIdx == -1 ||
|
||||
currentConditionIdx ==
|
||||
conditionsList->ContentLayout()->count() - 1) {
|
||||
ui->conditionsList->ContentLayout()->count() - 1) {
|
||||
return;
|
||||
}
|
||||
MoveMacroConditionDown(currentConditionIdx);
|
||||
@@ -491,7 +433,7 @@ void AdvSceneSwitcher::on_conditionBottom_clicked()
|
||||
if (currentConditionIdx == -1) {
|
||||
return;
|
||||
}
|
||||
const int newIdx = conditionsList->ContentLayout()->count() - 1;
|
||||
const int newIdx = ui->conditionsList->ContentLayout()->count() - 1;
|
||||
MacroConditionReorder(newIdx, currentConditionIdx);
|
||||
MacroConditionSelectionChanged(newIdx);
|
||||
}
|
||||
@@ -521,11 +463,11 @@ void AdvSceneSwitcher::SwapConditions(Macro *m, int pos1, int pos2)
|
||||
}
|
||||
|
||||
auto widget1 = static_cast<MacroConditionEdit *>(
|
||||
conditionsList->ContentLayout()->takeAt(pos1)->widget());
|
||||
ui->conditionsList->ContentLayout()->takeAt(pos1)->widget());
|
||||
auto widget2 = static_cast<MacroConditionEdit *>(
|
||||
conditionsList->ContentLayout()->takeAt(pos2 - 1)->widget());
|
||||
conditionsList->Insert(pos1, widget2);
|
||||
conditionsList->Insert(pos2, widget1);
|
||||
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);
|
||||
@@ -564,22 +506,7 @@ void AdvSceneSwitcher::MoveMacroConditionDown(int idx)
|
||||
|
||||
void AdvSceneSwitcher::MacroConditionSelectionChanged(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
conditionsList->SetSelection(idx);
|
||||
actionsList->SetSelection(-1);
|
||||
|
||||
if (idx < 0 || (unsigned)idx >= macro->Conditions().size()) {
|
||||
currentConditionIdx = -1;
|
||||
} else {
|
||||
currentConditionIdx = idx;
|
||||
lastInteracted = MacroSection::CONDITIONS;
|
||||
}
|
||||
currentActionIdx = -1;
|
||||
HighlightControls();
|
||||
SetupMacroSegmentSelection(MacroSection::CONDITIONS, idx);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MacroConditionReorder(int to, int from)
|
||||
@@ -599,30 +526,30 @@ void AdvSceneSwitcher::MacroConditionReorder(int to, int from)
|
||||
if (to == 0) {
|
||||
condition->SetLogicType(LogicType::ROOT_NONE);
|
||||
static_cast<MacroConditionEdit *>(
|
||||
conditionsList->WidgetAt(from))
|
||||
ui->conditionsList->WidgetAt(from))
|
||||
->SetRootNode(true);
|
||||
macro->Conditions().at(0)->SetLogicType(LogicType::AND);
|
||||
static_cast<MacroConditionEdit *>(
|
||||
conditionsList->WidgetAt(0))
|
||||
ui->conditionsList->WidgetAt(0))
|
||||
->SetRootNode(false);
|
||||
}
|
||||
if (from == 0) {
|
||||
condition->SetLogicType(LogicType::AND);
|
||||
static_cast<MacroConditionEdit *>(
|
||||
conditionsList->WidgetAt(from))
|
||||
ui->conditionsList->WidgetAt(from))
|
||||
->SetRootNode(false);
|
||||
macro->Conditions().at(1)->SetLogicType(
|
||||
LogicType::ROOT_NONE);
|
||||
static_cast<MacroConditionEdit *>(
|
||||
conditionsList->WidgetAt(1))
|
||||
ui->conditionsList->WidgetAt(1))
|
||||
->SetRootNode(true);
|
||||
}
|
||||
macro->Conditions().erase(macro->Conditions().begin() + from);
|
||||
macro->Conditions().insert(macro->Conditions().begin() + to,
|
||||
condition);
|
||||
macro->UpdateConditionIndices();
|
||||
conditionsList->ContentLayout()->insertItem(
|
||||
to, conditionsList->ContentLayout()->takeAt(from));
|
||||
ui->conditionsList->ContentLayout()->insertItem(
|
||||
to, ui->conditionsList->ContentLayout()->takeAt(from));
|
||||
SetConditionData(*macro);
|
||||
}
|
||||
HighlightCondition(to);
|
||||
|
||||
@@ -1,38 +1,12 @@
|
||||
#pragma once
|
||||
#include "macro-condition.hpp"
|
||||
#include "macro-condition-factory.hpp"
|
||||
#include "filter-combo-box.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace advss {
|
||||
|
||||
struct MacroConditionInfo {
|
||||
using TCreateMethod = std::shared_ptr<MacroCondition> (*)(Macro *m);
|
||||
using TCreateWidgetMethod =
|
||||
QWidget *(*)(QWidget *parent, std::shared_ptr<MacroCondition>);
|
||||
TCreateMethod _createFunc = nullptr;
|
||||
TCreateWidgetMethod _createWidgetFunc = nullptr;
|
||||
std::string _name;
|
||||
bool _useDurationModifier = true;
|
||||
};
|
||||
|
||||
class MacroConditionFactory {
|
||||
public:
|
||||
MacroConditionFactory() = delete;
|
||||
static bool Register(const std::string &, MacroConditionInfo);
|
||||
static std::shared_ptr<MacroCondition> Create(const std::string &,
|
||||
Macro *m);
|
||||
static QWidget *CreateWidget(const std::string &id, QWidget *parent,
|
||||
std::shared_ptr<MacroCondition>);
|
||||
static auto GetConditionTypes() { return GetMap(); }
|
||||
static std::string GetConditionName(const std::string &);
|
||||
static std::string GetIdByName(const QString &name);
|
||||
static bool UsesDurationModifier(const std::string &id);
|
||||
|
||||
private:
|
||||
static std::map<std::string, MacroConditionInfo> &GetMap();
|
||||
};
|
||||
|
||||
class DurationModifierEdit : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -75,7 +49,7 @@ private slots:
|
||||
|
||||
private:
|
||||
void SetLogicSelection();
|
||||
std::shared_ptr<MacroSegment> Data();
|
||||
std::shared_ptr<MacroSegment> Data() const;
|
||||
|
||||
QComboBox *_logicSelection;
|
||||
FilterComboBox *_conditionSelection;
|
||||
|
||||
66
src/macro-core/macro-condition-factory.cpp
Normal file
66
src/macro-core/macro-condition-factory.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
#include "macro-condition-factory.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
std::map<std::string, MacroConditionInfo> &MacroConditionFactory::GetMap()
|
||||
{
|
||||
static std::map<std::string, MacroConditionInfo> _methods;
|
||||
return _methods;
|
||||
}
|
||||
|
||||
bool MacroConditionFactory::Register(const std::string &id,
|
||||
MacroConditionInfo info)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it == GetMap().end()) {
|
||||
GetMap()[id] = info;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroCondition>
|
||||
MacroConditionFactory::Create(const std::string &id, Macro *m)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||
return it->second._create(m);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QWidget *
|
||||
MacroConditionFactory::CreateWidget(const std::string &id, QWidget *parent,
|
||||
std::shared_ptr<MacroCondition> cond)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||
return it->second._createWidget(parent, cond);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string MacroConditionFactory::GetConditionName(const std::string &id)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||
return it->second._name;
|
||||
}
|
||||
return "unknown condition";
|
||||
}
|
||||
|
||||
std::string MacroConditionFactory::GetIdByName(const QString &name)
|
||||
{
|
||||
for (auto it : GetMap()) {
|
||||
if (name == obs_module_text(it.second._name.c_str())) {
|
||||
return it.first;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
bool MacroConditionFactory::UsesDurationModifier(const std::string &id)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||
return it->second._useDurationModifier;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
35
src/macro-core/macro-condition-factory.hpp
Normal file
35
src/macro-core/macro-condition-factory.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
#include "macro-condition.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace advss {
|
||||
|
||||
struct MacroConditionInfo {
|
||||
using CreateCondition = std::shared_ptr<MacroCondition> (*)(Macro *m);
|
||||
using CreateConditionWidget =
|
||||
QWidget *(*)(QWidget *parent, std::shared_ptr<MacroCondition>);
|
||||
CreateCondition _create = nullptr;
|
||||
CreateConditionWidget _createWidget = nullptr;
|
||||
std::string _name;
|
||||
bool _useDurationModifier = true;
|
||||
};
|
||||
|
||||
class MacroConditionFactory {
|
||||
public:
|
||||
MacroConditionFactory() = delete;
|
||||
static bool Register(const std::string &, MacroConditionInfo);
|
||||
static std::shared_ptr<MacroCondition> Create(const std::string &,
|
||||
Macro *m);
|
||||
static QWidget *CreateWidget(const std::string &id, QWidget *parent,
|
||||
std::shared_ptr<MacroCondition>);
|
||||
static auto GetConditionTypes() { return GetMap(); }
|
||||
static std::string GetConditionName(const std::string &);
|
||||
static std::string GetIdByName(const QString &name);
|
||||
static bool UsesDurationModifier(const std::string &id);
|
||||
|
||||
private:
|
||||
static std::map<std::string, MacroConditionInfo> &GetMap();
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "macro-condition-file.hpp"
|
||||
#include "utility.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "curl-helper.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
|
||||
#include <QTextStream>
|
||||
#include <QFileDialog>
|
||||
@@ -28,16 +28,16 @@ static size_t WriteCallback(void *contents, size_t size, size_t nmemb,
|
||||
static std::string getRemoteData(std::string &url)
|
||||
{
|
||||
std::string readBuffer;
|
||||
switcher->curl.SetOpt(CURLOPT_URL, url.c_str());
|
||||
switcher->curl.SetOpt(CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||
switcher->curl.SetOpt(CURLOPT_WRITEDATA, &readBuffer);
|
||||
CurlHelper::SetOpt(CURLOPT_URL, url.c_str());
|
||||
CurlHelper::SetOpt(CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||
CurlHelper::SetOpt(CURLOPT_WRITEDATA, &readBuffer);
|
||||
// Set timeout to at least one second
|
||||
int timeout = switcher->interval / 1000;
|
||||
int timeout = GetIntervalValue() / 1000;
|
||||
if (timeout == 0) {
|
||||
timeout = 1;
|
||||
}
|
||||
switcher->curl.SetOpt(CURLOPT_TIMEOUT, 1);
|
||||
switcher->curl.Perform();
|
||||
CurlHelper::SetOpt(CURLOPT_TIMEOUT, 1);
|
||||
CurlHelper::Perform();
|
||||
return readBuffer;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,19 +18,20 @@ const static std::map<MacroConditionFilter::Condition, std::string>
|
||||
"AdvSceneSwitcher.condition.filter.type.active"},
|
||||
{MacroConditionFilter::Condition::DISABLED,
|
||||
"AdvSceneSwitcher.condition.filter.type.showing"},
|
||||
{MacroConditionFilter::Condition::SETTINGS,
|
||||
{MacroConditionFilter::Condition::SETTINGS_MATCH,
|
||||
"AdvSceneSwitcher.condition.filter.type.settings"},
|
||||
{MacroConditionFilter::Condition::SETTINGS_CHANGED,
|
||||
"AdvSceneSwitcher.condition.filter.type.settingsChanged"},
|
||||
};
|
||||
|
||||
bool MacroConditionFilter::CheckCondition()
|
||||
bool MacroConditionFilter::CheckConditionHelper(const OBSWeakSource &filter)
|
||||
{
|
||||
auto filterWeakSource = _filter.GetFilter(_source);
|
||||
if (!filterWeakSource) {
|
||||
bool ret = false;
|
||||
OBSSourceAutoRelease filterSource = obs_weak_source_get_source(filter);
|
||||
if (!filterSource.Get()) {
|
||||
return false;
|
||||
}
|
||||
auto filterSource = obs_weak_source_get_source(filterWeakSource);
|
||||
|
||||
bool ret = false;
|
||||
switch (_condition) {
|
||||
case Condition::ENABLED:
|
||||
ret = obs_source_enabled(filterSource);
|
||||
@@ -38,18 +39,36 @@ bool MacroConditionFilter::CheckCondition()
|
||||
case Condition::DISABLED:
|
||||
ret = !obs_source_enabled(filterSource);
|
||||
break;
|
||||
case Condition::SETTINGS:
|
||||
ret = CompareSourceSettings(filterWeakSource, _settings,
|
||||
_regex);
|
||||
case Condition::SETTINGS_MATCH:
|
||||
ret = CompareSourceSettings(filter, _settings, _regex);
|
||||
if (IsReferencedInVars()) {
|
||||
SetVariableValue(GetSourceSettings(filterWeakSource));
|
||||
SetVariableValue(GetSourceSettings(filter));
|
||||
}
|
||||
break;
|
||||
case Condition::SETTINGS_CHANGED: {
|
||||
std::string settings = GetSourceSettings(_source.GetSource());
|
||||
ret = !_currentSettings.empty() && settings != _currentSettings;
|
||||
_currentSettings = settings;
|
||||
SetVariableValue(settings);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
obs_source_release(filterSource);
|
||||
bool MacroConditionFilter::CheckCondition()
|
||||
{
|
||||
auto filters = _filter.GetFilters(_source);
|
||||
if (filters.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret = true;
|
||||
for (const auto &filter : filters) {
|
||||
ret = ret && CheckConditionHelper(filter);
|
||||
}
|
||||
|
||||
if (GetVariableValue().empty()) {
|
||||
SetVariableValue(ret ? "true" : "false");
|
||||
@@ -95,8 +114,8 @@ std::string MacroConditionFilter::GetShortDesc() const
|
||||
|
||||
static inline void populateConditionSelection(QComboBox *list)
|
||||
{
|
||||
for (auto entry : filterConditionTypes) {
|
||||
list->addItem(obs_module_text(entry.second.c_str()));
|
||||
for (const auto &[_, name] : filterConditionTypes) {
|
||||
list->addItem(obs_module_text(name.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,19 +213,20 @@ void MacroConditionFilterEdit::ConditionChanged(int index)
|
||||
auto lock = LockContext();
|
||||
_entryData->_condition =
|
||||
static_cast<MacroConditionFilter::Condition>(index);
|
||||
SetSettingsSelectionVisible(_entryData->_condition ==
|
||||
MacroConditionFilter::Condition::SETTINGS);
|
||||
SetSettingsSelectionVisible(
|
||||
_entryData->_condition ==
|
||||
MacroConditionFilter::Condition::SETTINGS_MATCH);
|
||||
}
|
||||
|
||||
void MacroConditionFilterEdit::GetSettingsClicked()
|
||||
{
|
||||
if (_loading || !_entryData ||
|
||||
!_entryData->_filter.GetFilter(_entryData->_source)) {
|
||||
_entryData->_filter.GetFilters(_entryData->_source).empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString json = FormatJsonString(GetSourceSettings(
|
||||
_entryData->_filter.GetFilter(_entryData->_source)));
|
||||
_entryData->_filter.GetFilters(_entryData->_source).at(0)));
|
||||
if (_entryData->_regex.Enabled()) {
|
||||
json = EscapeForRegex(json);
|
||||
}
|
||||
@@ -259,8 +279,9 @@ void MacroConditionFilterEdit::UpdateEntryData()
|
||||
_conditions->setCurrentIndex(static_cast<int>(_entryData->_condition));
|
||||
_settings->setPlainText(_entryData->_settings);
|
||||
_regex->SetRegexConfig(_entryData->_regex);
|
||||
SetSettingsSelectionVisible(_entryData->_condition ==
|
||||
MacroConditionFilter::Condition::SETTINGS);
|
||||
SetSettingsSelectionVisible(
|
||||
_entryData->_condition ==
|
||||
MacroConditionFilter::Condition::SETTINGS_MATCH);
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
|
||||
@@ -27,7 +27,8 @@ public:
|
||||
enum class Condition {
|
||||
ENABLED,
|
||||
DISABLED,
|
||||
SETTINGS,
|
||||
SETTINGS_MATCH,
|
||||
SETTINGS_CHANGED,
|
||||
};
|
||||
|
||||
SourceSelection _source;
|
||||
@@ -37,6 +38,9 @@ public:
|
||||
RegexConfig _regex;
|
||||
|
||||
private:
|
||||
bool CheckConditionHelper(const OBSWeakSource &);
|
||||
|
||||
std::string _currentSettings;
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
@@ -24,6 +24,8 @@ const static std::map<MacroConditionMacro::Type, std::string>
|
||||
"AdvSceneSwitcher.condition.macro.type.actionDisabled"},
|
||||
{MacroConditionMacro::Type::ACTION_ENABLED,
|
||||
"AdvSceneSwitcher.condition.macro.type.actionEnabled"},
|
||||
{MacroConditionMacro::Type::PAUSED,
|
||||
"AdvSceneSwitcher.condition.macro.type.paused"},
|
||||
};
|
||||
|
||||
const static std::map<MacroConditionMacro::CounterCondition, std::string>
|
||||
@@ -75,6 +77,8 @@ bool MacroConditionMacro::CheckMultiStateCondition()
|
||||
}
|
||||
}
|
||||
|
||||
SetTempVarValue("matchedCount", std::to_string(matchedCount));
|
||||
|
||||
switch (_multiSateCondition) {
|
||||
case MacroConditionMacro::MultiStateCondition::BELOW:
|
||||
return matchedCount < _multiSateCount;
|
||||
@@ -107,6 +111,16 @@ bool MacroConditionMacro::CheckActionStateCondition()
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MacroConditionMacro::CheckPauseState()
|
||||
{
|
||||
auto macro = _macro.GetMacro();
|
||||
if (!macro) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return macro->Paused();
|
||||
}
|
||||
|
||||
bool MacroConditionMacro::CheckCountCondition()
|
||||
{
|
||||
auto macro = _macro.GetMacro();
|
||||
@@ -114,6 +128,8 @@ bool MacroConditionMacro::CheckCountCondition()
|
||||
return false;
|
||||
}
|
||||
|
||||
SetTempVarValue("runCount", std::to_string(macro->RunCount()));
|
||||
|
||||
switch (_counterCondition) {
|
||||
case CounterCondition::BELOW:
|
||||
return macro->RunCount() < _count;
|
||||
@@ -140,6 +156,8 @@ bool MacroConditionMacro::CheckCondition()
|
||||
case Type::ACTION_DISABLED:
|
||||
case Type::ACTION_ENABLED:
|
||||
return CheckActionStateCondition();
|
||||
case Type::PAUSED:
|
||||
return CheckPauseState();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -193,7 +211,7 @@ bool MacroConditionMacro::Load(obs_data_t *obj)
|
||||
|
||||
bool MacroConditionMacro::PostLoad()
|
||||
{
|
||||
return MacroRefCondition::PostLoad() &&
|
||||
return MacroCondition::PostLoad() && MacroRefCondition::PostLoad() &&
|
||||
MultiMacroRefCondtition::PostLoad();
|
||||
}
|
||||
|
||||
@@ -202,6 +220,45 @@ std::string MacroConditionMacro::GetShortDesc() const
|
||||
return _macro.Name();
|
||||
}
|
||||
|
||||
void MacroConditionMacro::SetType(Type type)
|
||||
{
|
||||
_type = type;
|
||||
SetupTempVars();
|
||||
}
|
||||
|
||||
void MacroConditionMacro::SetupTempVars()
|
||||
{
|
||||
MacroCondition::SetupTempVars();
|
||||
switch (_type) {
|
||||
case Type::COUNT:
|
||||
AddTempvar(
|
||||
"runCount",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.macro.runCount"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.macro.runCount.description"));
|
||||
break;
|
||||
case Type::STATE:
|
||||
break;
|
||||
case Type::MULTI_STATE:
|
||||
AddTempvar(
|
||||
"matchedCount",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.macro.matchedCount"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.macro.matchedCount.description"));
|
||||
break;
|
||||
case Type::ACTION_DISABLED:
|
||||
break;
|
||||
case Type::ACTION_ENABLED:
|
||||
break;
|
||||
case Type::PAUSED:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void populateTypeSelection(QComboBox *list)
|
||||
{
|
||||
for (auto entry : macroConditionTypes) {
|
||||
@@ -335,7 +392,10 @@ void MacroConditionMacroEdit::ClearLayouts()
|
||||
|
||||
void MacroConditionMacroEdit::SetupWidgets()
|
||||
{
|
||||
switch (_entryData->_type) {
|
||||
SetWidgetVisibility();
|
||||
ClearLayouts();
|
||||
|
||||
switch (_entryData->GetType()) {
|
||||
case MacroConditionMacro::Type::COUNT:
|
||||
SetupCountWidgets();
|
||||
break;
|
||||
@@ -351,6 +411,9 @@ void MacroConditionMacroEdit::SetupWidgets()
|
||||
case MacroConditionMacro::Type::ACTION_ENABLED:
|
||||
SetupActionStateWidgets(true);
|
||||
break;
|
||||
case MacroConditionMacro::Type::PAUSED:
|
||||
SetupPauseWidgets();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -358,38 +421,24 @@ void MacroConditionMacroEdit::SetupWidgets()
|
||||
|
||||
void MacroConditionMacroEdit::SetupStateWidgets()
|
||||
{
|
||||
SetWidgetVisibility();
|
||||
ClearLayouts();
|
||||
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{macros}}", _macros},
|
||||
};
|
||||
PlaceWidgets(
|
||||
obs_module_text("AdvSceneSwitcher.condition.macro.state.entry"),
|
||||
_settingsLine1, widgetPlaceholders);
|
||||
_settingsLine1, {{"{{macros}}", _macros}});
|
||||
}
|
||||
|
||||
void MacroConditionMacroEdit::SetupMultiStateWidgets()
|
||||
{
|
||||
SetWidgetVisibility();
|
||||
ClearLayouts();
|
||||
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{multiStateConditions}}", _multiStateConditions},
|
||||
{"{{multiStateCount}}", _multiStateCount},
|
||||
};
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.condition.macro.multistate.entry"),
|
||||
_settingsLine1, widgetPlaceholders);
|
||||
_settingsLine1,
|
||||
{{"{{multiStateConditions}}", _multiStateConditions},
|
||||
{"{{multiStateCount}}", _multiStateCount}});
|
||||
}
|
||||
|
||||
void MacroConditionMacroEdit::SetupCountWidgets()
|
||||
{
|
||||
SetWidgetVisibility();
|
||||
ClearLayouts();
|
||||
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
const std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{macros}}", _macros},
|
||||
{"{{conditions}}", _counterConditions},
|
||||
{"{{count}}", _count},
|
||||
@@ -408,9 +457,6 @@ void MacroConditionMacroEdit::SetupCountWidgets()
|
||||
|
||||
void MacroConditionMacroEdit::SetupActionStateWidgets(bool enable)
|
||||
{
|
||||
SetWidgetVisibility();
|
||||
ClearLayouts();
|
||||
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
enable ? "AdvSceneSwitcher.condition.macro.actionState.enabled.entry"
|
||||
@@ -419,35 +465,49 @@ void MacroConditionMacroEdit::SetupActionStateWidgets(bool enable)
|
||||
{{"{{macros}}", _macros}, {"{{actionIndex}}", _actionIndex}});
|
||||
}
|
||||
|
||||
void MacroConditionMacroEdit::SetupPauseWidgets()
|
||||
{
|
||||
PlaceWidgets(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.macro.paused.entry"),
|
||||
_settingsLine1, {{"{{macros}}", _macros}});
|
||||
}
|
||||
|
||||
void MacroConditionMacroEdit::SetWidgetVisibility()
|
||||
{
|
||||
_macros->setVisible(
|
||||
_entryData->_type == MacroConditionMacro::Type::COUNT ||
|
||||
_entryData->_type == MacroConditionMacro::Type::STATE ||
|
||||
_entryData->_type ==
|
||||
_entryData->GetType() == MacroConditionMacro::Type::COUNT ||
|
||||
_entryData->GetType() == MacroConditionMacro::Type::STATE ||
|
||||
_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::ACTION_DISABLED ||
|
||||
_entryData->_type == MacroConditionMacro::Type::ACTION_ENABLED);
|
||||
_counterConditions->setVisible(_entryData->_type ==
|
||||
_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::ACTION_ENABLED ||
|
||||
_entryData->GetType() == MacroConditionMacro::Type::PAUSED);
|
||||
_counterConditions->setVisible(_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::COUNT);
|
||||
_count->setVisible(_entryData->_type ==
|
||||
_count->setVisible(_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::COUNT);
|
||||
_currentCount->setVisible(_entryData->_type ==
|
||||
_currentCount->setVisible(_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::COUNT);
|
||||
_resetCount->setVisible(_entryData->_type ==
|
||||
_resetCount->setVisible(_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::COUNT);
|
||||
_macroList->setVisible(_entryData->_type ==
|
||||
_macroList->setVisible(_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::MULTI_STATE);
|
||||
_multiStateConditions->setVisible(
|
||||
_entryData->_type == MacroConditionMacro::Type::MULTI_STATE);
|
||||
_multiStateCount->setVisible(_entryData->_type ==
|
||||
_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::MULTI_STATE);
|
||||
_multiStateCount->setVisible(_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::MULTI_STATE);
|
||||
_actionIndex->setVisible(
|
||||
_entryData->_type ==
|
||||
_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::ACTION_DISABLED ||
|
||||
_entryData->_type == MacroConditionMacro::Type::ACTION_ENABLED);
|
||||
if (_entryData->_type == MacroConditionMacro::Type::MULTI_STATE ||
|
||||
_entryData->_type == MacroConditionMacro::Type::ACTION_DISABLED ||
|
||||
_entryData->_type == MacroConditionMacro::Type::ACTION_ENABLED) {
|
||||
_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::ACTION_ENABLED);
|
||||
if (_entryData->GetType() == MacroConditionMacro::Type::MULTI_STATE ||
|
||||
_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::ACTION_DISABLED ||
|
||||
_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::ACTION_ENABLED ||
|
||||
_entryData->GetType() == MacroConditionMacro::Type::PAUSED) {
|
||||
_pausedWarning->hide();
|
||||
}
|
||||
|
||||
@@ -463,7 +523,7 @@ void MacroConditionMacroEdit::UpdateEntryData()
|
||||
|
||||
SetupWidgets();
|
||||
_macros->SetCurrentMacro(_entryData->_macro);
|
||||
_types->setCurrentIndex(static_cast<int>(_entryData->_type));
|
||||
_types->setCurrentIndex(static_cast<int>(_entryData->GetType()));
|
||||
_counterConditions->setCurrentIndex(
|
||||
static_cast<int>(_entryData->_counterCondition));
|
||||
_count->SetValue(_entryData->_count);
|
||||
@@ -535,7 +595,7 @@ void MacroConditionMacroEdit::TypeChanged(int type)
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_type = static_cast<MacroConditionMacro::Type>(type);
|
||||
_entryData->SetType(static_cast<MacroConditionMacro::Type>(type));
|
||||
SetupWidgets();
|
||||
}
|
||||
|
||||
@@ -571,7 +631,8 @@ void MacroConditionMacroEdit::UpdatePaused()
|
||||
auto macro = _entryData->_macro.GetMacro();
|
||||
_pausedWarning->setVisible(
|
||||
_entryData &&
|
||||
_entryData->_type != MacroConditionMacro::Type::MULTI_STATE &&
|
||||
_entryData->GetType() !=
|
||||
MacroConditionMacro::Type::MULTI_STATE &&
|
||||
macro && macro->Paused());
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
|
||||
@@ -39,8 +39,10 @@ public:
|
||||
MULTI_STATE,
|
||||
ACTION_DISABLED,
|
||||
ACTION_ENABLED,
|
||||
PAUSED,
|
||||
};
|
||||
Type _type = Type::STATE;
|
||||
void SetType(Type);
|
||||
Type GetType() const { return _type; }
|
||||
|
||||
enum class CounterCondition {
|
||||
BELOW,
|
||||
@@ -64,7 +66,11 @@ private:
|
||||
bool CheckStateCondition();
|
||||
bool CheckMultiStateCondition();
|
||||
bool CheckActionStateCondition();
|
||||
bool CheckPauseState();
|
||||
|
||||
void SetupTempVars();
|
||||
|
||||
Type _type = Type::STATE;
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
};
|
||||
@@ -128,6 +134,7 @@ private:
|
||||
void SetupMultiStateWidgets();
|
||||
void SetupCountWidgets();
|
||||
void SetupActionStateWidgets(bool enable);
|
||||
void SetupPauseWidgets();
|
||||
void SetWidgetVisibility();
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "macro-condition-media.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "scene-switch-helpers.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace advss {
|
||||
@@ -148,26 +150,20 @@ bool MacroConditionMedia::CheckMediaMatch()
|
||||
if (!_source.GetSource()) {
|
||||
return false;
|
||||
}
|
||||
bool match = false;
|
||||
bool matched = CheckState() && CheckTime();
|
||||
|
||||
if (matched && !(_onlyMatchOnChagne && _alreadyMatched)) {
|
||||
match = true;
|
||||
}
|
||||
_alreadyMatched = matched;
|
||||
|
||||
// reset for next check
|
||||
_stopped = false;
|
||||
_ended = false;
|
||||
_next = false;
|
||||
|
||||
return match;
|
||||
return matched;
|
||||
}
|
||||
|
||||
void MacroConditionMedia::HandleSceneChange()
|
||||
{
|
||||
UpdateMediaSourcesOfSceneList();
|
||||
_lastConfigureScene = switcher->currentScene;
|
||||
_lastConfigureScene = GetCurrentScene();
|
||||
}
|
||||
|
||||
bool MacroConditionMedia::CheckCondition()
|
||||
@@ -194,7 +190,7 @@ bool MacroConditionMedia::CheckCondition()
|
||||
break;
|
||||
}
|
||||
|
||||
if (_lastConfigureScene != switcher->currentScene) {
|
||||
if (_lastConfigureScene != GetCurrentScene()) {
|
||||
HandleSceneChange();
|
||||
}
|
||||
|
||||
@@ -210,7 +206,6 @@ bool MacroConditionMedia::Save(obs_data_t *obj) const
|
||||
obs_data_set_int(obj, "state", static_cast<int>(_state));
|
||||
obs_data_set_int(obj, "restriction", static_cast<int>(_restriction));
|
||||
_time.Save(obj);
|
||||
obs_data_set_bool(obj, "matchOnChagne", _onlyMatchOnChagne);
|
||||
obs_data_set_int(obj, "version", 0);
|
||||
return true;
|
||||
}
|
||||
@@ -268,7 +263,6 @@ bool MacroConditionMedia::Load(obs_data_t *obj)
|
||||
_restriction = static_cast<MacroConditionMedia::Time>(
|
||||
obs_data_get_int(obj, "restriction"));
|
||||
_time.Load(obj);
|
||||
_onlyMatchOnChagne = obs_data_get_bool(obj, "matchOnChagne");
|
||||
|
||||
if (_sourceType == Type::SOURCE) {
|
||||
obs_source_t *mediasource =
|
||||
@@ -408,9 +402,7 @@ MacroConditionMediaEdit::MacroConditionMediaEdit(
|
||||
_sources(new SourceSelectionWidget(this, QStringList(), true)),
|
||||
_states(new QComboBox()),
|
||||
_timeRestrictions(new QComboBox()),
|
||||
_time(new DurationSelection()),
|
||||
_onChange(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.media.matchOnChange")))
|
||||
_time(new DurationSelection())
|
||||
{
|
||||
_states->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.media.inconsistencyInfo"));
|
||||
@@ -432,14 +424,12 @@ MacroConditionMediaEdit::MacroConditionMediaEdit(
|
||||
this, SLOT(TimeRestrictionChanged(int)));
|
||||
QWidget::connect(_time, SIGNAL(DurationChanged(const Duration &)), this,
|
||||
SLOT(TimeChanged(const Duration &)));
|
||||
QWidget::connect(_onChange, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(OnChangeChanged(int)));
|
||||
|
||||
populateSourceTypes(_sourceTypes);
|
||||
populateMediaStates(_states);
|
||||
populateMediaTimes(_timeRestrictions);
|
||||
|
||||
QHBoxLayout *entryLayout = new QHBoxLayout;
|
||||
auto layout = new QHBoxLayout;
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{sourceTypes}}", _sourceTypes},
|
||||
{"{{mediaSources}}", _sources},
|
||||
@@ -449,11 +439,8 @@ MacroConditionMediaEdit::MacroConditionMediaEdit(
|
||||
{"{{time}}", _time},
|
||||
};
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.condition.media.entry"),
|
||||
entryLayout, widgetPlaceholders);
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(entryLayout);
|
||||
mainLayout->addWidget(_onChange);
|
||||
setLayout(mainLayout);
|
||||
layout, widgetPlaceholders);
|
||||
setLayout(layout);
|
||||
|
||||
_entryData = entryData;
|
||||
UpdateEntryData();
|
||||
@@ -572,28 +559,12 @@ void MacroConditionMediaEdit::TimeChanged(const Duration &dur)
|
||||
}
|
||||
}
|
||||
|
||||
void MacroConditionMediaEdit::OnChangeChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_onlyMatchOnChagne = value;
|
||||
if (_entryData->_sourceType != MacroConditionMedia::Type::SOURCE) {
|
||||
_entryData->UpdateMediaSourcesOfSceneList();
|
||||
}
|
||||
}
|
||||
|
||||
void MacroConditionMediaEdit::SetWidgetVisibility()
|
||||
{
|
||||
_sources->setVisible(_entryData->_sourceType ==
|
||||
MacroConditionMedia::Type::SOURCE);
|
||||
_scenes->setVisible(_entryData->_sourceType !=
|
||||
MacroConditionMedia::Type::SOURCE);
|
||||
if (!_onChange->isChecked()) {
|
||||
_onChange->hide();
|
||||
}
|
||||
}
|
||||
|
||||
static int getIdxFromMediaState(MacroConditionMedia::State state)
|
||||
@@ -625,7 +596,6 @@ void MacroConditionMediaEdit::UpdateEntryData()
|
||||
MacroConditionMedia::Time::TIME_RESTRICTION_NONE) {
|
||||
_time->setDisabled(true);
|
||||
}
|
||||
_onChange->setChecked(_entryData->_onlyMatchOnChagne);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,6 @@ public:
|
||||
OBSWeakSource _rawSource = nullptr;
|
||||
std::vector<MacroConditionMedia> _sourceGroup;
|
||||
Duration _time;
|
||||
bool _onlyMatchOnChagne = false;
|
||||
|
||||
private:
|
||||
bool CheckTime();
|
||||
@@ -84,9 +83,7 @@ private:
|
||||
bool _stopped = false;
|
||||
bool _ended = false;
|
||||
bool _next = false;
|
||||
// TODO: Remove _alreadyMatched as it does not make much sense when
|
||||
// time restrictions for macro conditions are available.
|
||||
bool _alreadyMatched = false;
|
||||
|
||||
// Workaround to enable use of "ended" to specify end of VLC playlist
|
||||
bool _previousStateEnded = false;
|
||||
// Used to keep track of scene changes
|
||||
@@ -119,7 +116,6 @@ private slots:
|
||||
void StateChanged(int index);
|
||||
void TimeRestrictionChanged(int index);
|
||||
void TimeChanged(const Duration &seconds);
|
||||
void OnChangeChanged(int);
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
|
||||
@@ -130,7 +126,6 @@ protected:
|
||||
QComboBox *_states;
|
||||
QComboBox *_timeRestrictions;
|
||||
DurationSelection *_time;
|
||||
QCheckBox *_onChange;
|
||||
std::shared_ptr<MacroConditionMedia> _entryData;
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "macro-condition-plugin-state.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace advss {
|
||||
@@ -33,7 +34,7 @@ const static std::map<MacroConditionPluginState::Condition, std::string>
|
||||
MacroConditionPluginState::~MacroConditionPluginState()
|
||||
{
|
||||
if (_condition == Condition::OBS_SHUTDOWN) {
|
||||
switcher->shutdownConditionCount--;
|
||||
GetShutdownConditionCount()--;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,15 +42,15 @@ bool MacroConditionPluginState::CheckCondition()
|
||||
{
|
||||
switch (_condition) {
|
||||
case Condition::PLUGIN_SCENE_CHANGE:
|
||||
return switcher->macroSceneSwitched;
|
||||
return MacroSwitchedScene();
|
||||
case Condition::PLUGIN_RUNNING:
|
||||
return true;
|
||||
case Condition::OBS_SHUTDOWN:
|
||||
return switcher->obsIsShuttingDown;
|
||||
return OBSIsShuttingDown();
|
||||
case Condition::PLUGIN_START:
|
||||
return switcher->firstInterval;
|
||||
return IsFirstInterval();
|
||||
case Condition::PLUGIN_RESTART:
|
||||
return switcher->firstIntervalAfterStop;
|
||||
return IsFirstIntervalAfterStop();
|
||||
case Condition::SCENE_COLLECTION_CHANGE:
|
||||
if (_firstCheckAfterSceneCollectionChange) {
|
||||
_firstCheckAfterSceneCollectionChange = false;
|
||||
@@ -83,25 +84,33 @@ bool MacroConditionPluginState::Load(obs_data_t *obj)
|
||||
obs_data_get_int(obj, "condition"));
|
||||
switch (oldValue) {
|
||||
case PluginStateCondition::SCENE_SWITCHED:
|
||||
_condition = Condition::PLUGIN_SCENE_CHANGE;
|
||||
SetCondition(Condition::PLUGIN_SCENE_CHANGE);
|
||||
break;
|
||||
case PluginStateCondition::RUNNING:
|
||||
_condition = Condition::PLUGIN_RUNNING;
|
||||
SetCondition(Condition::PLUGIN_RUNNING);
|
||||
break;
|
||||
case PluginStateCondition::SHUTDOWN:
|
||||
_condition = Condition::OBS_SHUTDOWN;
|
||||
SetCondition(Condition::OBS_SHUTDOWN);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
_condition = static_cast<Condition>(
|
||||
obs_data_get_int(obj, "condition"));
|
||||
}
|
||||
if (_condition == Condition::OBS_SHUTDOWN) {
|
||||
switcher->shutdownConditionCount++;
|
||||
SetCondition(static_cast<Condition>(
|
||||
obs_data_get_int(obj, "condition")));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void MacroConditionPluginState::SetCondition(Condition newValue)
|
||||
{
|
||||
if (_condition == Condition::OBS_SHUTDOWN) {
|
||||
GetShutdownConditionCount()--;
|
||||
}
|
||||
if (newValue == Condition::OBS_SHUTDOWN) {
|
||||
GetShutdownConditionCount()++;
|
||||
}
|
||||
_condition = newValue;
|
||||
}
|
||||
|
||||
static inline void populateConditionSelection(QComboBox *list)
|
||||
{
|
||||
for (const auto &[action, name] : pluginStateConditionTypes) {
|
||||
@@ -148,17 +157,9 @@ void MacroConditionPluginStateEdit::ConditionChanged(int idx)
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
if (_entryData->_condition ==
|
||||
MacroConditionPluginState::Condition::OBS_SHUTDOWN) {
|
||||
switcher->shutdownConditionCount--;
|
||||
}
|
||||
_entryData->_condition =
|
||||
_entryData->SetCondition(
|
||||
static_cast<MacroConditionPluginState::Condition>(
|
||||
_condition->itemData(idx).toInt());
|
||||
if (_entryData->_condition ==
|
||||
MacroConditionPluginState::Condition::OBS_SHUTDOWN) {
|
||||
switcher->shutdownConditionCount++;
|
||||
}
|
||||
_condition->itemData(idx).toInt()));
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
@@ -168,15 +169,15 @@ void MacroConditionPluginStateEdit::UpdateEntryData()
|
||||
return;
|
||||
}
|
||||
|
||||
_condition->setCurrentIndex(
|
||||
_condition->findData(static_cast<int>(_entryData->_condition)));
|
||||
_condition->setCurrentIndex(_condition->findData(
|
||||
static_cast<int>(_entryData->GetCondition())));
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroConditionPluginStateEdit::SetWidgetVisibility()
|
||||
{
|
||||
_shutdownLimitation->setVisible(
|
||||
_entryData->_condition ==
|
||||
_entryData->GetCondition() ==
|
||||
MacroConditionPluginState::Condition::OBS_SHUTDOWN);
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
|
||||
@@ -26,10 +26,11 @@ public:
|
||||
SCENE_COLLECTION_CHANGE,
|
||||
PLUGIN_SCENE_CHANGE,
|
||||
};
|
||||
|
||||
Condition _condition = Condition::PLUGIN_SCENE_CHANGE;
|
||||
void SetCondition(Condition);
|
||||
Condition GetCondition() const { return _condition; }
|
||||
|
||||
private:
|
||||
Condition _condition = Condition::PLUGIN_SCENE_CHANGE;
|
||||
bool _firstCheckAfterSceneCollectionChange = true;
|
||||
|
||||
const static uint32_t _version;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "macro-condition-process.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "platform-funcs.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
@@ -19,25 +18,43 @@ bool MacroConditionProcess::CheckCondition()
|
||||
QStringList runningProcesses;
|
||||
QString proc = QString::fromStdString(_process);
|
||||
GetProcessList(runningProcesses);
|
||||
std::string foregroundProcessName;
|
||||
GetForegroundProcessName(foregroundProcessName);
|
||||
|
||||
bool equals = runningProcesses.contains(proc);
|
||||
bool matches = runningProcesses.indexOf(QRegularExpression(proc)) != -1;
|
||||
bool focus = !_focus || IsInFocus(proc);
|
||||
SetVariableValue(foregroundProcessName);
|
||||
|
||||
if (IsReferencedInVars()) {
|
||||
std::string name;
|
||||
GetForegroundProcessName(name);
|
||||
SetVariableValue(name);
|
||||
if (!_regex.Enabled()) {
|
||||
if (runningProcesses.contains(proc) &&
|
||||
(!_checkFocus || IsInFocus(proc))) {
|
||||
SetTempVarValue("name", proc.toStdString());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return (equals || matches) && focus;
|
||||
auto matchIndex = runningProcesses.indexOf(QRegularExpression(proc));
|
||||
if (matchIndex == -1) {
|
||||
return false;
|
||||
}
|
||||
if (!_checkFocus) {
|
||||
SetTempVarValue("name",
|
||||
runningProcesses.at(matchIndex).toStdString());
|
||||
return true;
|
||||
}
|
||||
if (!IsInFocus(proc)) {
|
||||
return false;
|
||||
}
|
||||
SetTempVarValue("name", foregroundProcessName);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacroConditionProcess::Save(obs_data_t *obj) const
|
||||
{
|
||||
MacroCondition::Save(obj);
|
||||
obs_data_set_string(obj, "process", _process.c_str());
|
||||
obs_data_set_bool(obj, "focus", _focus);
|
||||
obs_data_set_bool(obj, "focus", _checkFocus);
|
||||
_regex.Save(obj);
|
||||
obs_data_set_int(obj, "version", 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -45,7 +62,13 @@ bool MacroConditionProcess::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroCondition::Load(obj);
|
||||
_process = obs_data_get_string(obj, "process");
|
||||
_focus = obs_data_get_bool(obj, "focus");
|
||||
_checkFocus = obs_data_get_bool(obj, "focus");
|
||||
// Fall back to partial match regex as default for old version
|
||||
if (!obs_data_has_user_value(obj, "version")) {
|
||||
_regex.SetEnabled(true);
|
||||
} else {
|
||||
_regex.Load(obj);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -54,10 +77,18 @@ std::string MacroConditionProcess::GetShortDesc() const
|
||||
return _process;
|
||||
}
|
||||
|
||||
void MacroConditionProcess::SetupTempVars()
|
||||
{
|
||||
MacroCondition::SetupTempVars();
|
||||
AddTempvar("name",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.process.name"));
|
||||
}
|
||||
|
||||
MacroConditionProcessEdit::MacroConditionProcessEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroConditionProcess> entryData)
|
||||
: QWidget(parent),
|
||||
_processSelection(new QComboBox()),
|
||||
_regex(new RegexConfigWidget(this)),
|
||||
_focused(new QCheckBox()),
|
||||
_focusProcess(new QLabel()),
|
||||
_focusLayout(new QHBoxLayout())
|
||||
@@ -68,6 +99,8 @@ MacroConditionProcessEdit::MacroConditionProcessEdit(
|
||||
QWidget::connect(_processSelection,
|
||||
SIGNAL(currentTextChanged(const QString &)), this,
|
||||
SLOT(ProcessChanged(const QString &)));
|
||||
QWidget::connect(_regex, SIGNAL(RegexConfigChanged(RegexConfig)), this,
|
||||
SLOT(RegexChanged(RegexConfig)));
|
||||
QWidget::connect(_focused, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(FocusChanged(int)));
|
||||
QWidget::connect(&_timer, SIGNAL(timeout()), this,
|
||||
@@ -77,6 +110,7 @@ MacroConditionProcessEdit::MacroConditionProcessEdit(
|
||||
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{processes}}", _processSelection},
|
||||
{"{{regex}}", _regex},
|
||||
{"{{focused}}", _focused},
|
||||
{"{{focusProcess}}", _focusProcess},
|
||||
};
|
||||
@@ -112,6 +146,18 @@ void MacroConditionProcessEdit::ProcessChanged(const QString &text)
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
}
|
||||
|
||||
void MacroConditionProcessEdit::RegexChanged(RegexConfig conf)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_regex = conf;
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void MacroConditionProcessEdit::FocusChanged(int state)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
@@ -119,14 +165,15 @@ void MacroConditionProcessEdit::FocusChanged(int state)
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_focus = state;
|
||||
_entryData->_checkFocus = state;
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroConditionProcessEdit::UpdateFocusProcess()
|
||||
{
|
||||
_focusProcess->setText(
|
||||
QString::fromStdString(switcher->currentForegroundProcess));
|
||||
std::string name;
|
||||
GetForegroundProcessName(name);
|
||||
_focusProcess->setText(QString::fromStdString(name));
|
||||
}
|
||||
|
||||
void MacroConditionProcessEdit::SetWidgetVisibility()
|
||||
@@ -134,7 +181,7 @@ void MacroConditionProcessEdit::SetWidgetVisibility()
|
||||
if (!_entryData) {
|
||||
return;
|
||||
}
|
||||
SetLayoutVisible(_focusLayout, _entryData->_focus);
|
||||
SetLayoutVisible(_focusLayout, _entryData->_checkFocus);
|
||||
adjustSize();
|
||||
}
|
||||
|
||||
@@ -145,7 +192,8 @@ void MacroConditionProcessEdit::UpdateEntryData()
|
||||
}
|
||||
|
||||
_processSelection->setCurrentText(_entryData->_process.c_str());
|
||||
_focused->setChecked(_entryData->_focus);
|
||||
_regex->SetRegexConfig(_entryData->_regex);
|
||||
_focused->setChecked(_entryData->_checkFocus);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "macro-condition-edit.hpp"
|
||||
#include "regex-config.hpp"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QCheckBox>
|
||||
@@ -20,9 +21,12 @@ public:
|
||||
}
|
||||
|
||||
std::string _process;
|
||||
bool _focus = true;
|
||||
bool _checkFocus = true;
|
||||
RegexConfig _regex = RegexConfig::PartialMatchRegexConfig();
|
||||
|
||||
private:
|
||||
void SetupTempVars();
|
||||
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
};
|
||||
@@ -45,22 +49,22 @@ public:
|
||||
|
||||
private slots:
|
||||
void ProcessChanged(const QString &text);
|
||||
void RegexChanged(RegexConfig);
|
||||
void FocusChanged(int state);
|
||||
void UpdateFocusProcess();
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
|
||||
protected:
|
||||
private:
|
||||
void SetWidgetVisibility();
|
||||
|
||||
QComboBox *_processSelection;
|
||||
RegexConfigWidget *_regex;
|
||||
QCheckBox *_focused;
|
||||
QLabel *_focusProcess;
|
||||
QHBoxLayout *_focusLayout;
|
||||
QTimer _timer;
|
||||
std::shared_ptr<MacroConditionProcess> _entryData;
|
||||
|
||||
private:
|
||||
void SetWidgetVisibility();
|
||||
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "macro-condition-recording.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <thread>
|
||||
|
||||
namespace advss {
|
||||
|
||||
const std::string MacroConditionRecord::id = "recording";
|
||||
@@ -10,45 +12,81 @@ bool MacroConditionRecord::_registered = MacroConditionFactory::Register(
|
||||
{MacroConditionRecord::Create, MacroConditionRecordEdit::Create,
|
||||
"AdvSceneSwitcher.condition.record"});
|
||||
|
||||
const static std::map<RecordState, std::string> recordStates = {
|
||||
{RecordState::STOP, "AdvSceneSwitcher.condition.record.state.stop"},
|
||||
{RecordState::PAUSE, "AdvSceneSwitcher.condition.record.state.pause"},
|
||||
{RecordState::START, "AdvSceneSwitcher.condition.record.state.start"},
|
||||
const static std::map<MacroConditionRecord::Condition, std::string>
|
||||
recordStates = {
|
||||
{MacroConditionRecord::Condition::STOP,
|
||||
"AdvSceneSwitcher.condition.record.state.stop"},
|
||||
{MacroConditionRecord::Condition::PAUSE,
|
||||
"AdvSceneSwitcher.condition.record.state.pause"},
|
||||
{MacroConditionRecord::Condition::START,
|
||||
"AdvSceneSwitcher.condition.record.state.start"},
|
||||
{MacroConditionRecord::Condition::DURATION,
|
||||
"AdvSceneSwitcher.condition.record.state.duration"},
|
||||
};
|
||||
|
||||
static bool SetupRecordingTimer();
|
||||
static bool recordingTimerIsSetup = SetupRecordingTimer();
|
||||
static int currentRecordingDurationInSeconds = 0;
|
||||
|
||||
bool MacroConditionRecord::CheckCondition()
|
||||
{
|
||||
bool stateMatch = false;
|
||||
switch (_recordState) {
|
||||
case RecordState::STOP:
|
||||
stateMatch = !obs_frontend_recording_active();
|
||||
break;
|
||||
case RecordState::PAUSE:
|
||||
stateMatch = obs_frontend_recording_paused();
|
||||
break;
|
||||
case RecordState::START:
|
||||
stateMatch = obs_frontend_recording_active();
|
||||
break;
|
||||
switch (_condition) {
|
||||
case Condition::STOP:
|
||||
return !obs_frontend_recording_active();
|
||||
case Condition::PAUSE:
|
||||
return obs_frontend_recording_paused();
|
||||
case Condition::START:
|
||||
return obs_frontend_recording_active();
|
||||
case Condition::DURATION:
|
||||
SetTempVarValue(
|
||||
"durationSeconds",
|
||||
std::to_string(currentRecordingDurationInSeconds));
|
||||
return currentRecordingDurationInSeconds > _duration.Seconds();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return stateMatch;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MacroConditionRecord::Save(obs_data_t *obj) const
|
||||
{
|
||||
MacroCondition::Save(obj);
|
||||
obs_data_set_int(obj, "state", static_cast<int>(_recordState));
|
||||
obs_data_set_int(obj, "state", static_cast<int>(_condition));
|
||||
_duration.Save(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacroConditionRecord::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroCondition::Load(obj);
|
||||
_recordState = static_cast<RecordState>(obs_data_get_int(obj, "state"));
|
||||
_condition = static_cast<Condition>(obs_data_get_int(obj, "state"));
|
||||
_duration.Load(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
void MacroConditionRecord::SetCondition(Condition condition)
|
||||
{
|
||||
_condition = condition;
|
||||
SetupTempVars();
|
||||
}
|
||||
|
||||
void MacroConditionRecord::SetupTempVars()
|
||||
{
|
||||
MacroCondition::SetupTempVars();
|
||||
switch (_condition) {
|
||||
case Condition::DURATION:
|
||||
AddTempvar(
|
||||
"durationSeconds",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.recording.durationSeconds"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.recording.durationSeconds.description"));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void populateStateSelection(QComboBox *list)
|
||||
{
|
||||
for (auto entry : recordStates) {
|
||||
@@ -58,38 +96,39 @@ static inline void populateStateSelection(QComboBox *list)
|
||||
|
||||
MacroConditionRecordEdit::MacroConditionRecordEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroConditionRecord> entryData)
|
||||
: QWidget(parent)
|
||||
: QWidget(parent),
|
||||
_condition(new QComboBox(this)),
|
||||
_duration(new DurationSelection(this))
|
||||
{
|
||||
_recordState = new QComboBox();
|
||||
populateStateSelection(_condition);
|
||||
|
||||
QWidget::connect(_recordState, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(StateChanged(int)));
|
||||
|
||||
populateStateSelection(_recordState);
|
||||
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{recordState}}", _recordState},
|
||||
};
|
||||
QWidget::connect(_condition, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(ConditionChanged(int)));
|
||||
QWidget::connect(_duration, SIGNAL(DurationChanged(const Duration &)),
|
||||
this, SLOT(DurationChanged(const Duration &)));
|
||||
|
||||
auto layout = new QHBoxLayout;
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.condition.record.entry"),
|
||||
mainLayout, widgetPlaceholders);
|
||||
setLayout(mainLayout);
|
||||
layout,
|
||||
{{"{{condition}}", _condition},
|
||||
{"{{duration}}", _duration}});
|
||||
setLayout(layout);
|
||||
|
||||
_entryData = entryData;
|
||||
UpdateEntryData();
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
void MacroConditionRecordEdit::StateChanged(int value)
|
||||
void MacroConditionRecordEdit::ConditionChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_recordState = static_cast<RecordState>(value);
|
||||
_entryData->SetCondition(
|
||||
static_cast<MacroConditionRecord::Condition>(value));
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroConditionRecordEdit::UpdateEntryData()
|
||||
@@ -98,8 +137,67 @@ void MacroConditionRecordEdit::UpdateEntryData()
|
||||
return;
|
||||
}
|
||||
|
||||
_recordState->setCurrentIndex(
|
||||
static_cast<int>(_entryData->_recordState));
|
||||
_condition->setCurrentIndex(
|
||||
static_cast<int>(_entryData->GetCondition()));
|
||||
_duration->SetDuration(_entryData->_duration);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroConditionRecordEdit::DurationChanged(const Duration &duration)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_duration = duration;
|
||||
}
|
||||
|
||||
void MacroConditionRecordEdit::SetWidgetVisibility()
|
||||
{
|
||||
_duration->setVisible(_entryData->GetCondition() ==
|
||||
MacroConditionRecord::Condition::DURATION);
|
||||
}
|
||||
|
||||
bool SetupRecordingTimer()
|
||||
{
|
||||
static std::atomic_bool recordingStopped = {true};
|
||||
static std::atomic_bool recordingPaused = {false};
|
||||
static auto handleRecordingEvents = [](enum obs_frontend_event event,
|
||||
void *) {
|
||||
switch (event) {
|
||||
case OBS_FRONTEND_EVENT_RECORDING_STOPPED:
|
||||
recordingStopped = true;
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_RECORDING_STARTED:
|
||||
recordingStopped = false;
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_RECORDING_PAUSED:
|
||||
recordingPaused = true;
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_RECORDING_UNPAUSED:
|
||||
recordingPaused = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
};
|
||||
obs_frontend_add_event_callback(handleRecordingEvents, nullptr);
|
||||
std::thread thread([]() {
|
||||
while (true) {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
if (recordingStopped) {
|
||||
currentRecordingDurationInSeconds = 0;
|
||||
continue;
|
||||
}
|
||||
if (recordingPaused) {
|
||||
continue;
|
||||
}
|
||||
++currentRecordingDurationInSeconds;
|
||||
}
|
||||
});
|
||||
thread.detach();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -6,12 +6,6 @@
|
||||
|
||||
namespace advss {
|
||||
|
||||
enum class RecordState {
|
||||
STOP,
|
||||
PAUSE,
|
||||
START,
|
||||
};
|
||||
|
||||
class MacroConditionRecord : public MacroCondition {
|
||||
public:
|
||||
MacroConditionRecord(Macro *m) : MacroCondition(m) {}
|
||||
@@ -24,9 +18,21 @@ public:
|
||||
return std::make_shared<MacroConditionRecord>(m);
|
||||
}
|
||||
|
||||
RecordState _recordState = RecordState::STOP;
|
||||
enum class Condition {
|
||||
STOP,
|
||||
PAUSE,
|
||||
START,
|
||||
DURATION,
|
||||
};
|
||||
|
||||
void SetCondition(Condition);
|
||||
Condition GetCondition() const { return _condition; }
|
||||
Duration _duration;
|
||||
|
||||
private:
|
||||
void SetupTempVars();
|
||||
|
||||
Condition _condition = Condition::STOP;
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
};
|
||||
@@ -48,13 +54,15 @@ public:
|
||||
}
|
||||
|
||||
private slots:
|
||||
void StateChanged(int value);
|
||||
|
||||
protected:
|
||||
QComboBox *_recordState;
|
||||
std::shared_ptr<MacroConditionRecord> _entryData;
|
||||
void ConditionChanged(int value);
|
||||
void DurationChanged(const Duration &);
|
||||
|
||||
private:
|
||||
void SetWidgetVisibility();
|
||||
|
||||
QComboBox *_condition;
|
||||
DurationSelection *_duration;
|
||||
std::shared_ptr<MacroConditionRecord> _entryData;
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "macro-condition-replay-buffer.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace advss {
|
||||
@@ -11,35 +10,63 @@ bool MacroConditionReplayBuffer::_registered = MacroConditionFactory::Register(
|
||||
MacroConditionReplayBufferEdit::Create,
|
||||
"AdvSceneSwitcher.condition.replay"});
|
||||
|
||||
const static std::map<ReplayBufferState, std::string> ReplayBufferStates = {
|
||||
{ReplayBufferState::STOP,
|
||||
"AdvSceneSwitcher.condition.replay.state.stopped"},
|
||||
{ReplayBufferState::START,
|
||||
"AdvSceneSwitcher.condition.replay.state.started"},
|
||||
{ReplayBufferState::SAVE,
|
||||
"AdvSceneSwitcher.condition.replay.state.saved"},
|
||||
const static std::map<MacroConditionReplayBuffer::Condition, std::string>
|
||||
conditions = {
|
||||
{MacroConditionReplayBuffer::Condition::STOP,
|
||||
"AdvSceneSwitcher.condition.replay.state.stopped"},
|
||||
{MacroConditionReplayBuffer::Condition::START,
|
||||
"AdvSceneSwitcher.condition.replay.state.started"},
|
||||
{MacroConditionReplayBuffer::Condition::SAVE,
|
||||
"AdvSceneSwitcher.condition.replay.state.saved"},
|
||||
};
|
||||
|
||||
static bool replayBufferSaved = false;
|
||||
|
||||
static std::chrono::high_resolution_clock::time_point replayBufferSaveTime{};
|
||||
static bool setupReplayBufferEventHandler();
|
||||
static bool replayBufferEventHandlerIsSetup = setupReplayBufferEventHandler();
|
||||
|
||||
static bool setupReplayBufferEventHandler()
|
||||
{
|
||||
static auto handleReplayBufferEvent = [](enum obs_frontend_event event,
|
||||
void *) {
|
||||
switch (event) {
|
||||
case OBS_FRONTEND_EVENT_REPLAY_BUFFER_SAVED:
|
||||
replayBufferSaveTime =
|
||||
std::chrono::high_resolution_clock::now();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
};
|
||||
obs_frontend_add_event_callback(handleReplayBufferEvent, nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacroConditionReplayBuffer::ReplayBufferWasSaved()
|
||||
{
|
||||
bool timersAreInitialized =
|
||||
_saveTime.time_since_epoch().count() != 0 &&
|
||||
replayBufferSaveTime.time_since_epoch().count() != 0;
|
||||
bool newSaveOccurred = timersAreInitialized &&
|
||||
_saveTime != replayBufferSaveTime;
|
||||
_saveTime = replayBufferSaveTime;
|
||||
return newSaveOccurred;
|
||||
}
|
||||
|
||||
bool MacroConditionReplayBuffer::CheckCondition()
|
||||
{
|
||||
bool stateMatch = false;
|
||||
switch (_state) {
|
||||
case ReplayBufferState::STOP:
|
||||
stateMatch = !obs_frontend_replay_buffer_active();
|
||||
break;
|
||||
case ReplayBufferState::START:
|
||||
stateMatch = obs_frontend_replay_buffer_active();
|
||||
break;
|
||||
case ReplayBufferState::SAVE:
|
||||
if (switcher->replayBufferSaved) {
|
||||
stateMatch = true;
|
||||
switcher->replayBufferSaved = false;
|
||||
}
|
||||
break;
|
||||
case Condition::STOP:
|
||||
return !obs_frontend_replay_buffer_active();
|
||||
case Condition::START:
|
||||
return obs_frontend_replay_buffer_active();
|
||||
case Condition::SAVE:
|
||||
return ReplayBufferWasSaved();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return stateMatch;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MacroConditionReplayBuffer::Save(obs_data_t *obj) const
|
||||
@@ -52,37 +79,30 @@ bool MacroConditionReplayBuffer::Save(obs_data_t *obj) const
|
||||
bool MacroConditionReplayBuffer::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroCondition::Load(obj);
|
||||
_state = static_cast<ReplayBufferState>(obs_data_get_int(obj, "state"));
|
||||
_state = static_cast<Condition>(obs_data_get_int(obj, "state"));
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void populateStateSelection(QComboBox *list)
|
||||
{
|
||||
for (auto entry : ReplayBufferStates) {
|
||||
for (const auto &entry : conditions) {
|
||||
list->addItem(obs_module_text(entry.second.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
MacroConditionReplayBufferEdit::MacroConditionReplayBufferEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroConditionReplayBuffer> entryData)
|
||||
: QWidget(parent)
|
||||
: QWidget(parent), _state(new QComboBox())
|
||||
{
|
||||
_state = new QComboBox();
|
||||
|
||||
QWidget::connect(_state, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(StateChanged(int)));
|
||||
|
||||
populateStateSelection(_state);
|
||||
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{state}}", _state},
|
||||
};
|
||||
|
||||
auto layout = new QHBoxLayout;
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.condition.replay.entry"),
|
||||
mainLayout, widgetPlaceholders);
|
||||
setLayout(mainLayout);
|
||||
layout, {{"{{state}}", _state}});
|
||||
setLayout(layout);
|
||||
|
||||
_entryData = entryData;
|
||||
UpdateEntryData();
|
||||
@@ -96,7 +116,8 @@ void MacroConditionReplayBufferEdit::StateChanged(int value)
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_state = static_cast<ReplayBufferState>(value);
|
||||
_entryData->_state =
|
||||
static_cast<MacroConditionReplayBuffer::Condition>(value);
|
||||
}
|
||||
|
||||
void MacroConditionReplayBufferEdit::UpdateEntryData()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user