Compare commits
334 Commits
1.21.0-bet
...
hotkey
| 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 | ||
|
|
68c6492c3f | ||
|
|
0ba7ba77d8 | ||
|
|
04b2b3474d | ||
|
|
ecbb5ebbd7 | ||
|
|
b62757b65d | ||
|
|
b1a3ab5493 | ||
|
|
abc3357180 | ||
|
|
29f9cba236 | ||
|
|
9a62522140 | ||
|
|
666c52556e | ||
|
|
1c0734d1cb | ||
|
|
1304ac7336 | ||
|
|
884fb1b637 | ||
|
|
a82bce947f | ||
|
|
d5241f0700 | ||
|
|
f24f258c9c | ||
|
|
eddd9fa8ab | ||
|
|
6cc224aeec | ||
|
|
4b0a631987 | ||
|
|
dcae0e8e8b | ||
|
|
29f810a2a0 | ||
|
|
719dfa7b72 | ||
|
|
259aac8fcd | ||
|
|
5be2cd278f | ||
|
|
211eac5313 | ||
|
|
f92ed3139d | ||
|
|
bdff84c605 | ||
|
|
08e430396a | ||
|
|
df7fc7ec01 | ||
|
|
9eef581161 | ||
|
|
52811e44f4 | ||
|
|
7b1c56877e | ||
|
|
78d73af589 | ||
|
|
d9c1ef4c22 | ||
|
|
93f96ee660 | ||
|
|
d25a8d4efb | ||
|
|
1f22278496 | ||
|
|
70b705e0fd | ||
|
|
9e1dfdc3f0 | ||
|
|
47d6d4ac06 | ||
|
|
fe3586b6f4 | ||
|
|
650881204f | ||
|
|
8c0ba112e2 | ||
|
|
a17d8f7e09 | ||
|
|
371b4ae05d | ||
|
|
1d7ce510f7 | ||
|
|
d759ded64d | ||
|
|
0b2e1b88cc | ||
|
|
72a11eedfc | ||
|
|
1f02226620 | ||
|
|
ad8c29997c | ||
|
|
2c7c40c3f0 | ||
|
|
c9c0e4db2e | ||
|
|
dd880b13c0 | ||
|
|
76c759c8f4 | ||
|
|
284c8020b2 | ||
|
|
f506600b8c | ||
|
|
339418b5f3 | ||
|
|
2eca2cc2e9 | ||
|
|
4315d309f2 | ||
|
|
8d18bb363a | ||
|
|
592f31f059 | ||
|
|
300ad15ad0 | ||
|
|
91f93169eb | ||
|
|
5d95069291 | ||
|
|
e5bb9162ef | ||
|
|
6869cc8a01 | ||
|
|
55c7ac8a32 | ||
|
|
101a85b063 | ||
|
|
e7c6afbc6a | ||
|
|
18e19fb6c8 | ||
|
|
a7ccfc3282 | ||
|
|
85eb2a4235 | ||
|
|
3e3805b542 | ||
|
|
c59acd836a | ||
|
|
1e81181312 | ||
|
|
8a796efdb3 | ||
|
|
1a07a93552 | ||
|
|
bd74629420 | ||
|
|
dabb293cc0 | ||
|
|
b6031bd29a | ||
|
|
05fa3af2ac | ||
|
|
c52166bfec | ||
|
|
6d3964fa5d | ||
|
|
65545d85ba | ||
|
|
dea4ff47cd | ||
|
|
258a5f6ab7 | ||
|
|
2048ca2816 | ||
|
|
eb9e2e8062 | ||
|
|
3229bf0150 | ||
|
|
dfa12f9807 | ||
|
|
e0917a35fd | ||
|
|
686b00ffd1 | ||
|
|
78402f6546 | ||
|
|
a1b5fbb1fe | ||
|
|
b71f633fac | ||
|
|
dbb674aa8e | ||
|
|
018daf7f09 | ||
|
|
a07a84a8b1 | ||
|
|
0f36f34a4f | ||
|
|
cf2cebd0fc | ||
|
|
90dd59abe6 | ||
|
|
5332ed6bef | ||
|
|
d45d4ded99 | ||
|
|
25b5590d2c | ||
|
|
d2b2ced5bf | ||
|
|
c551953283 | ||
|
|
5ae1f38ea8 | ||
|
|
372f12de95 | ||
|
|
9cfa88dd8c | ||
|
|
7b355ebc49 | ||
|
|
43a56c8ec8 | ||
|
|
3da90bfa97 | ||
|
|
dd572a7456 | ||
|
|
8cd818b80e | ||
|
|
530bbc07c5 | ||
|
|
a992f7a0e8 | ||
|
|
ca3718594d | ||
|
|
17a66853d5 | ||
|
|
8c317c1396 | ||
|
|
20f888b991 | ||
|
|
cd0d3862c7 | ||
|
|
443ffb7906 | ||
|
|
5967c83b03 | ||
|
|
66498a03ce | ||
|
|
9ec772f723 | ||
|
|
20eb56db2d | ||
|
|
e4d064aaa3 | ||
|
|
5602dfa09a | ||
|
|
0138b412b4 | ||
|
|
20a934c9ab | ||
|
|
09d2b397dc | ||
|
|
482a99cf15 | ||
|
|
81ac45a1d4 | ||
|
|
0b8078f3bf | ||
|
|
8b6ace902c | ||
|
|
1dead9fca5 | ||
|
|
524c4b71d7 | ||
|
|
e51318768d | ||
|
|
c821bb20d0 | ||
|
|
c6b693b4ac | ||
|
|
2c5caabab0 | ||
|
|
b7479e8342 | ||
|
|
ffca124762 | ||
|
|
9bedbf6fb8 | ||
|
|
853150e458 | ||
|
|
1ddd48e008 | ||
|
|
17d24d642e | ||
|
|
87a46684cd | ||
|
|
e4c5193945 | ||
|
|
2e969bf6dd | ||
|
|
6db26d9f7b | ||
|
|
4f02c9ec36 | ||
|
|
2fdd39fba5 | ||
|
|
fe1ddc3a94 | ||
|
|
cff2d805db | ||
|
|
34425d3e47 |
1
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -22,6 +22,7 @@ A clear and concise description of what you expected to happen.
|
||||
|
||||
**Logs**
|
||||
Please provide a log of your issue with verbose logging enabled (See General tab of the plugin).
|
||||
In case of a crash, please also include the corresponding crash log.
|
||||
See [here](https://obsproject.com/forum/threads/please-post-a-log-with-your-issue-heres-how.23074/) for a description where to find the log files and how to share them.
|
||||
Please share the currently used plugin settings by exporting them them to a file (See General tab of the plugin).
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
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
@@ -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
|
||||
|
||||
1
.github/actions/run-tests/action.yml
vendored
@@ -16,6 +16,7 @@ runs:
|
||||
shell: zsh {0}
|
||||
run: |
|
||||
if [[ '${{ inputs.target }}' != 'x86_64' ]]; then
|
||||
echo tests skipped!
|
||||
exit 0
|
||||
fi
|
||||
${{ inputs.workingDirectory }}/build_x86_64/tests/advanced-scene-switcher-tests
|
||||
|
||||
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,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
@@ -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 ${@}
|
||||
122
.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,109 +174,34 @@ 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)"
|
||||
|
||||
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}'"
|
||||
}
|
||||
|
||||
case ${host_os} {
|
||||
macos)
|
||||
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'' \
|
||||
@@ -289,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)
|
||||
@@ -306,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"
|
||||
)
|
||||
|
||||
;;
|
||||
|
||||
9
.github/scripts/.package.zsh
vendored
@@ -128,9 +128,18 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
|
||||
|
||||
local product_name
|
||||
local product_version
|
||||
local git_tag="$(git describe --tags)"
|
||||
|
||||
read -r product_name product_version <<< \
|
||||
"$(jq -r '. | {name, version} | join(" ")' ${project_root}/buildspec.json)"
|
||||
|
||||
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 [[ ${host_os} == 'macos' ]] {
|
||||
autoload -Uz check_packages read_codesign read_codesign_installer read_codesign_pass
|
||||
|
||||
|
||||
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
@@ -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=Release"
|
||||
"-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', "Release"
|
||||
)
|
||||
|
||||
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=Release"
|
||||
"-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', "Release"
|
||||
)
|
||||
|
||||
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
@@ -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
@@ -0,0 +1 @@
|
||||
.build-deps.zsh
|
||||
1
.github/scripts/build-deps-macos.zsh
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
.build-deps.zsh
|
||||
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
@@ -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 )) {
|
||||
|
||||
32
.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:
|
||||
@@ -425,10 +442,11 @@ jobs:
|
||||
for file in ${{ github.workspace }}/**/@(*.pkg|*.exe|*.deb|*.zip); do
|
||||
echo " ${file##*/}: $(sha256sum "${file}" | cut -d " " -f 1)" >> ${{ github.workspace }}/CHECKSUMS.txt
|
||||
done
|
||||
cat ${{ github.workspace }}/CHECKSUMS.txt
|
||||
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: softprops/action-gh-release@1e07f4398721186383de40550babbdf2b84acfc5
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
draft: true
|
||||
prerelease: true
|
||||
|
||||
1
.gitignore
vendored
@@ -91,6 +91,7 @@ Thumbs.db
|
||||
.settings
|
||||
.idea
|
||||
.metadata
|
||||
.vscode
|
||||
*.iml
|
||||
*.ipr
|
||||
*.sublime*
|
||||
|
||||
9
.gitmodules
vendored
@@ -16,3 +16,12 @@
|
||||
[submodule "deps/tesseract"]
|
||||
path = deps/tesseract
|
||||
url = https://github.com/tesseract-ocr/tesseract.git
|
||||
[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
|
||||
|
||||
107
CMakeLists.txt
@@ -42,21 +42,20 @@ target_sources(
|
||||
src/general.cpp
|
||||
src/hotkey.cpp
|
||||
src/hotkey.hpp
|
||||
src/hotkey.hpp
|
||||
src/platform-funcs.hpp
|
||||
src/scene-group.cpp
|
||||
src/scene-group.hpp
|
||||
src/status-control.cpp
|
||||
src/status-control.hpp
|
||||
src/switcher-data-structs.cpp
|
||||
src/switcher-data-structs.hpp
|
||||
src/switcher-data.cpp
|
||||
src/switcher-data.hpp
|
||||
src/version.cpp
|
||||
src/version.h)
|
||||
|
||||
# Legacy function sources
|
||||
target_sources(
|
||||
${LIB_NAME}
|
||||
PRIVATE src/legacy/scene-trigger.cpp
|
||||
PRIVATE src/legacy/scene-group.cpp
|
||||
src/legacy/scene-group.hpp
|
||||
src/legacy/scene-trigger.cpp
|
||||
src/legacy/scene-trigger.hpp
|
||||
src/legacy/switch-audio.cpp
|
||||
src/legacy/switch-audio.hpp
|
||||
@@ -74,7 +73,6 @@ target_sources(
|
||||
src/legacy/switch-network.hpp
|
||||
src/legacy/switch-pause.cpp
|
||||
src/legacy/switch-pause.hpp
|
||||
src/legacy/switch-priority.cpp
|
||||
src/legacy/switch-random.cpp
|
||||
src/legacy/switch-random.hpp
|
||||
src/legacy/switch-screen-region.cpp
|
||||
@@ -95,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
|
||||
@@ -109,6 +111,8 @@ target_sources(
|
||||
src/macro-core/macro-action-macro.hpp
|
||||
src/macro-core/macro-action-media.cpp
|
||||
src/macro-core/macro-action-media.hpp
|
||||
src/macro-core/macro-action-osc.cpp
|
||||
src/macro-core/macro-action-osc.hpp
|
||||
src/macro-core/macro-action-plugin-state.cpp
|
||||
src/macro-core/macro-action-plugin-state.hpp
|
||||
src/macro-core/macro-action-profile.cpp
|
||||
@@ -125,6 +129,8 @@ target_sources(
|
||||
src/macro-core/macro-action-run.hpp
|
||||
src/macro-core/macro-action-scene-collection.cpp
|
||||
src/macro-core/macro-action-scene-collection.hpp
|
||||
src/macro-core/macro-action-scene-lock.cpp
|
||||
src/macro-core/macro-action-scene-lock.hpp
|
||||
src/macro-core/macro-action-scene-order.cpp
|
||||
src/macro-core/macro-action-scene-order.hpp
|
||||
src/macro-core/macro-action-scene-switch.cpp
|
||||
@@ -165,8 +171,12 @@ target_sources(
|
||||
src/macro-core/macro-condition-cursor.hpp
|
||||
src/macro-core/macro-condition-date.cpp
|
||||
src/macro-core/macro-condition-date.hpp
|
||||
src/macro-core/macro-condition-display.cpp
|
||||
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
|
||||
@@ -199,6 +209,8 @@ target_sources(
|
||||
src/macro-core/macro-condition-scene-transform.hpp
|
||||
src/macro-core/macro-condition-scene-visibility.cpp
|
||||
src/macro-core/macro-condition-scene-visibility.hpp
|
||||
src/macro-core/macro-condition-slideshow.cpp
|
||||
src/macro-core/macro-condition-slideshow.hpp
|
||||
src/macro-core/macro-condition-scene.cpp
|
||||
src/macro-core/macro-condition-scene.hpp
|
||||
src/macro-core/macro-condition-source.cpp
|
||||
@@ -207,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
|
||||
@@ -223,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
|
||||
@@ -246,21 +262,45 @@ 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
|
||||
src/utils/file-selection.cpp
|
||||
src/utils/file-selection.hpp
|
||||
src/utils/filter-combo-box.cpp
|
||||
src/utils/filter-combo-box.hpp
|
||||
src/utils/filter-selection.cpp
|
||||
src/utils/filter-selection.hpp
|
||||
src/utils/macro-export-import-dialog.cpp
|
||||
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
|
||||
src/utils/math-helpers.hpp
|
||||
src/utils/mouse-wheel-guard.cpp
|
||||
src/utils/mouse-wheel-guard.hpp
|
||||
src/utils/name-dialog.cpp
|
||||
src/utils/name-dialog.hpp
|
||||
src/utils/non-modal-dialog.cpp
|
||||
src/utils/non-modal-dialog.hpp
|
||||
src/utils/obs-dock.hpp
|
||||
src/utils/obs-module-helper.cpp
|
||||
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
|
||||
src/utils/process-config.hpp
|
||||
src/utils/regex-config.cpp
|
||||
@@ -271,6 +311,8 @@ target_sources(
|
||||
src/utils/scene-item-selection.hpp
|
||||
src/utils/scene-selection.cpp
|
||||
src/utils/scene-selection.hpp
|
||||
src/utils/scene-switch-helpers.cpp
|
||||
src/utils/scene-switch-helpers.hpp
|
||||
src/utils/screenshot-helper.cpp
|
||||
src/utils/screenshot-helper.hpp
|
||||
src/utils/section.cpp
|
||||
@@ -279,10 +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-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
|
||||
@@ -343,7 +393,16 @@ target_include_directories(
|
||||
${LIB_NAME}
|
||||
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/deps/asio/asio/include"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/deps/websocketpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/deps/obs-websocket/lib")
|
||||
"${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 ---
|
||||
|
||||
@@ -354,7 +413,8 @@ if(OS_WINDOWS)
|
||||
|
||||
target_compile_definitions(${LIB_NAME} PRIVATE UNICODE _UNICODE)
|
||||
if(MSVC)
|
||||
target_compile_options(${LIB_NAME} PUBLIC /MP /d2FH4- /wd4267 /wd4267)
|
||||
target_compile_options(${LIB_NAME} PUBLIC /MP /d2FH4- /wd4267 /wd4267
|
||||
/bigobj)
|
||||
endif()
|
||||
target_sources(${LIB_NAME} PRIVATE src/win/advanced-scene-switcher-win.cpp)
|
||||
add_definitions(-D_WEBSOCKETPP_CPP11_STL_)
|
||||
@@ -410,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"
|
||||
@@ -219,14 +215,13 @@ AdvSceneSwitcher.condition.stream.state.start="Stream läuft"
|
||||
AdvSceneSwitcher.condition.stream.state.stop="Stream gestoppt"
|
||||
AdvSceneSwitcher.condition.stream.state.starting="Stream wird gestartet"
|
||||
AdvSceneSwitcher.condition.stream.state.stopping="Stream wird gestoppt"
|
||||
AdvSceneSwitcher.condition.stream.entry="{{streamState}}"
|
||||
AdvSceneSwitcher.condition.stream.entry="{{streamState}}{{keyFrameInterval}}"
|
||||
AdvSceneSwitcher.condition.record="Aufnahme"
|
||||
AdvSceneSwitcher.condition.record.state.start="Aufnahme läuft"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Aufnahme pausiert"
|
||||
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"
|
||||
@@ -428,7 +424,7 @@ AdvSceneSwitcher.action.recording.type.unpause="Aufnahme nicht mehr pausieren"
|
||||
AdvSceneSwitcher.action.recording.type.split="Aufnahme-Datei teilen"
|
||||
AdvSceneSwitcher.action.recording.pause.hint="Bitte beachten, dass je nach Aufnahmeeinstellung die Aufnahme möglicherweise nicht unterbrochen werden kann"
|
||||
AdvSceneSwitcher.action.recording.split.hint="Vergewissern, dass die automatische Dateiaufteilung in den OBS-Einstellungen aktiviert ist!"
|
||||
AdvSceneSwitcher.action.recording.entry="{{actions}}{{pauseHint}}{{splitHint}}"
|
||||
AdvSceneSwitcher.action.recording.entry="{{actions}}{{recordFolder}}{{recordFileFormat}}{{pauseHint}}{{splitHint}}"
|
||||
AdvSceneSwitcher.action.replay="Replay Buffer"
|
||||
AdvSceneSwitcher.action.replay.saveWarn="Warnung: Ein zu häufiges Speichern kann dazu führen, dass der Replay Buffer nicht gespeichert wird!"
|
||||
AdvSceneSwitcher.action.replay.type.stop="Replay Buffer stoppen"
|
||||
@@ -438,20 +434,15 @@ AdvSceneSwitcher.action.replay.entry="{{actions}}"
|
||||
AdvSceneSwitcher.action.streaming="Stream"
|
||||
AdvSceneSwitcher.action.streaming.type.stop="Stream stoppen"
|
||||
AdvSceneSwitcher.action.streaming.type.start="Stream starten"
|
||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}"
|
||||
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"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.toggle="Umschalten"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.source="Quelle"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Beliebig"
|
||||
AdvSceneSwitcher.action.sceneVisibility.entry="Auf{{scenes}}{{actions}}{{sourceTypes}}{{sources}}{{sourceGroups}}"
|
||||
AdvSceneSwitcher.action.sceneVisibility.entry="Auf{{scenes}}{{actions}}{{sources}}"
|
||||
AdvSceneSwitcher.action.filter="Filter"
|
||||
AdvSceneSwitcher.action.filter.type.enable="Aktivieren"
|
||||
AdvSceneSwitcher.action.filter.type.disable="Deaktivieren"
|
||||
@@ -466,7 +457,7 @@ AdvSceneSwitcher.action.source.type.refreshSettings="Aktualisieren der Quellenei
|
||||
AdvSceneSwitcher.action.source.type.pressSettingsButton="Drücken der Einstellungstaste"
|
||||
AdvSceneSwitcher.action.source.type.refreshSettings.tooltip="Kann verwendet werden, um Browser-, Medien- usw. Quellen zu aktualisieren"
|
||||
AdvSceneSwitcher.action.source.noSettingsButtons="Keine Buttons gefunden!"
|
||||
AdvSceneSwitcher.action.source.entry="{{actions}}{{sources}}{{settingsButtons}}"
|
||||
AdvSceneSwitcher.action.source.entry="{{actions}}{{sources}}{{settingsButtons}}{{deinterlaceMode}}{{deinterlaceOrder}}"
|
||||
AdvSceneSwitcher.action.source.warning="Warnung: Das globale Aktivieren und Deaktivieren von Quellen kann nicht über die OBS-Benutzeroberfläche gesteuert werden"
|
||||
AdvSceneSwitcher.action.source.getSettings="Aktuelle Einstellungen abfragen"
|
||||
AdvSceneSwitcher.action.media="Medien"
|
||||
@@ -476,15 +467,14 @@ 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"
|
||||
AdvSceneSwitcher.action.macro.type.resetCounter="Zähler zurücksetzen"
|
||||
AdvSceneSwitcher.action.macro.type.run="Aktionen ausführen"
|
||||
AdvSceneSwitcher.action.macro.type.stop="Aktionen stoppen"
|
||||
AdvSceneSwitcher.action.macro.entry="{{actions}} {{macros}}"
|
||||
AdvSceneSwitcher.action.macro.entry="{{actions}}{{actionIndex}}{{macros}}"
|
||||
AdvSceneSwitcher.action.pluginState="Plugin-Status"
|
||||
AdvSceneSwitcher.action.pluginState.type.stop="Erweiterten Automatischen Szenenwechsler stoppen"
|
||||
AdvSceneSwitcher.action.pluginState.type.noMatch="Ändern des Nichtübereinstimmungsverhaltens:"
|
||||
@@ -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"
|
||||
@@ -516,7 +505,7 @@ AdvSceneSwitcher.action.sceneOrder.type.movePosition="An Position verschieben"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="Auf{{scenes}}{{actions}}{{sources}}{{position}}"
|
||||
AdvSceneSwitcher.action.sceneTransform="Szenenelement transformieren"
|
||||
AdvSceneSwitcher.action.sceneTransform.getTransform="Transformation erhalten"
|
||||
AdvSceneSwitcher.action.sceneTransform.entry="Auf{{scenes}}transformieren{{sources}}"
|
||||
AdvSceneSwitcher.action.sceneTransform.entry="Auf{{scenes}}{{action}}{{rotation}}{{sources}}"
|
||||
AdvSceneSwitcher.action.file="Datei"
|
||||
AdvSceneSwitcher.action.file.type.write="Schreiben"
|
||||
AdvSceneSwitcher.action.file.type.append="Anhängen"
|
||||
@@ -545,7 +534,6 @@ AdvSceneSwitcher.action.random="Zufall"
|
||||
AdvSceneSwitcher.action.random.allowRepeat="Aufeinanderfolgende Ausführung desselben Makros zulassen"
|
||||
AdvSceneSwitcher.action.random.entry="Zufällige Ausführung eines der folgenden Makros (pausierte Makros werden ignoriert)"
|
||||
AdvSceneSwitcher.action.systray="Benachrichtigung im System-Tray"
|
||||
AdvSceneSwitcher.action.systray.entry="Benachrichtigung anzeigen: {{message}}"
|
||||
AdvSceneSwitcher.action.screenshot="Screenshot"
|
||||
AdvSceneSwitcher.action.screenshot.save.default="Standard"
|
||||
AdvSceneSwitcher.action.screenshot.save.custom="Benutzerdefiniert"
|
||||
@@ -568,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"
|
||||
@@ -587,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
|
||||
@@ -647,7 +632,7 @@ AdvSceneSwitcher.mediaTab.states.none="Keine Auswahl"
|
||||
AdvSceneSwitcher.mediaTab.states.playing="Abspielen"
|
||||
AdvSceneSwitcher.mediaTab.states.opening="Öffnen"
|
||||
AdvSceneSwitcher.mediaTab.states.buffering="Buffern"
|
||||
AdvSceneSwitcher.mediaTab.states.Paused="Pausiert"
|
||||
AdvSceneSwitcher.mediaTab.states.paused="Pausiert"
|
||||
AdvSceneSwitcher.mediaTab.states.stopped="Gestoppt"
|
||||
AdvSceneSwitcher.mediaTab.states.ended="Beendet"
|
||||
AdvSceneSwitcher.mediaTab.states.error="Fehler"
|
||||
@@ -725,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}}"
|
||||
|
||||
@@ -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"
|
||||
@@ -179,14 +176,13 @@ AdvSceneSwitcher.condition.stream.state.start="Transmisión en ejecución"
|
||||
AdvSceneSwitcher.condition.stream.state.stop="Transmisión detenida"
|
||||
AdvSceneSwitcher.condition.stream.state.starting="Inicio de transmisión"
|
||||
AdvSceneSwitcher.condition.stream.state.stopping="Detener transmisión"
|
||||
AdvSceneSwitcher.condition.stream.entry="{{streamState}}"
|
||||
AdvSceneSwitcher.condition.stream.entry="{{streamState}}{{keyFrameInterval}}"
|
||||
AdvSceneSwitcher.condition.record="Grabación"
|
||||
AdvSceneSwitcher.condition.record.state.start="Grabación en ejecución"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Grabación en pausa"
|
||||
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"
|
||||
@@ -350,7 +347,7 @@ AdvSceneSwitcher.action.recording.type.start="Iniciar grabación"
|
||||
AdvSceneSwitcher.action.recording.type.pause="Pausar grabación"
|
||||
AdvSceneSwitcher.action.recording.type.unpause="Reanudar grabación"
|
||||
AdvSceneSwitcher.action.recording.pause.hint="Tenga en cuenta que, dependiendo de la configuración de grabación, es posible que no pueda pausar la grabación"
|
||||
AdvSceneSwitcher.action.recording.entry="{{actions}}{{pauseHint}}{{splitHint}}"
|
||||
AdvSceneSwitcher.action.recording.entry="{{actions}}{{recordFolder}}{{recordFileFormat}}{{pauseHint}}{{splitHint}}"
|
||||
AdvSceneSwitcher.action.replay="Búfer de reproducción"
|
||||
AdvSceneSwitcher.action.replay.saveWarn="Advertencia: ¡Guardar con demasiada frecuencia puede hacer que el búfer de reproducción no se guarde realmente!"
|
||||
AdvSceneSwitcher.action.replay.type.stop="Detener el búfer de reproducción"
|
||||
@@ -360,18 +357,14 @@ AdvSceneSwitcher.action.replay.entry="{{actions}}"
|
||||
AdvSceneSwitcher.action.streaming="Transmisión"
|
||||
AdvSceneSwitcher.action.streaming.type.stop="Detener transmisión"
|
||||
AdvSceneSwitcher.action.streaming.type.start="Iniciar transmisión"
|
||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}"
|
||||
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"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.source="Fuente"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Cualquiera"
|
||||
AdvSceneSwitcher.action.sceneVisibility.entry="En{{scenes}}{{actions}}{{sourceTypes}}{{sources}}{{sourceGroups}}"
|
||||
AdvSceneSwitcher.action.sceneVisibility.entry="En{{scenes}}{{actions}}{{sources}}"
|
||||
AdvSceneSwitcher.action.filter="Filtro"
|
||||
AdvSceneSwitcher.action.filter.type.enable="Habilitar"
|
||||
AdvSceneSwitcher.action.filter.type.disable="Deshabilitar"
|
||||
@@ -382,7 +375,7 @@ AdvSceneSwitcher.action.source="Fuente"
|
||||
AdvSceneSwitcher.action.source.type.enable="Habilitar"
|
||||
AdvSceneSwitcher.action.source.type.disable="Deshabilitar"
|
||||
AdvSceneSwitcher.action.source.type.settings="Establecer configuración"
|
||||
AdvSceneSwitcher.action.source.entry="{{actions}}{{sources}}{{settingsButtons}}"
|
||||
AdvSceneSwitcher.action.source.entry="{{actions}}{{sources}}{{settingsButtons}}{{deinterlaceMode}}{{deinterlaceOrder}}"
|
||||
AdvSceneSwitcher.action.source.warning="Advertencia: la IU de OBS no puede controlar la habilitación y deshabilitación global de fuentes"
|
||||
AdvSceneSwitcher.action.source.getSettings="Obtener la configuración actual"
|
||||
AdvSceneSwitcher.action.media="Medios"
|
||||
@@ -392,15 +385,14 @@ 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"
|
||||
AdvSceneSwitcher.action.macro.type.resetCounter="Reiniciar contador"
|
||||
AdvSceneSwitcher.action.macro.type.run="Ejecutar"
|
||||
AdvSceneSwitcher.action.macro.type.stop="Detener"
|
||||
AdvSceneSwitcher.action.macro.entry="{{actions}} {{macros}}"
|
||||
AdvSceneSwitcher.action.macro.entry="{{actions}}{{actionIndex}}{{macros}}"
|
||||
AdvSceneSwitcher.action.pluginState="Estado del complemento"
|
||||
AdvSceneSwitcher.action.pluginState.type.stop="Detener el complemento Advanced Scene Switcher"
|
||||
AdvSceneSwitcher.action.pluginState.type.noMatch="Cambiar el comportamiento de no coincidencia:"
|
||||
@@ -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"
|
||||
@@ -432,7 +423,7 @@ AdvSceneSwitcher.action.sceneOrder.type.movePosition="Mover a la posición"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="En{{scenes}}{{actions}}{{sources}}{{position}}"
|
||||
AdvSceneSwitcher.action.sceneTransform="Transformar elemento de escena"
|
||||
AdvSceneSwitcher.action.sceneTransform.getTransform="Obtener transformación"
|
||||
AdvSceneSwitcher.action.sceneTransform.entry="En{{scenes}}transformar{{sources}}"
|
||||
AdvSceneSwitcher.action.sceneTransform.entry="En{{scenes}}{{action}}{{rotation}}{{sources}}"
|
||||
AdvSceneSwitcher.action.file="Archivo"
|
||||
AdvSceneSwitcher.action.file.type.write="Escribir"
|
||||
AdvSceneSwitcher.action.file.type.append="Agregar"
|
||||
@@ -460,7 +451,6 @@ AdvSceneSwitcher.action.timer.entry="{{timerAction}} temporizadores en {{macros}
|
||||
AdvSceneSwitcher.action.random="Aleatorio"
|
||||
AdvSceneSwitcher.action.random.entry="Ejecute aleatoriamente cualquiera de las siguientes macros (las macros en pausa se ignoran)"
|
||||
AdvSceneSwitcher.action.systray="Notificación de la bandeja del sistema"
|
||||
AdvSceneSwitcher.action.systray.entry="Mostrar notificación: {{message}}"
|
||||
AdvSceneSwitcher.action.screenshot="Captura de pantalla"
|
||||
AdvSceneSwitcher.action.screenshot.mainOutput="Salida principal de OBS"
|
||||
AdvSceneSwitcher.action.profile="Perfil"
|
||||
@@ -532,7 +522,7 @@ AdvSceneSwitcher.mediaTab.states.none="Ninguno"
|
||||
AdvSceneSwitcher.mediaTab.states.playing="Reproduciéndose"
|
||||
AdvSceneSwitcher.mediaTab.states.opening="Abriendo"
|
||||
AdvSceneSwitcher.mediaTab.states.buffering="Almacenando en búfer"
|
||||
AdvSceneSwitcher.mediaTab.states.Paused="Pausado"
|
||||
AdvSceneSwitcher.mediaTab.states.paused="Pausado"
|
||||
AdvSceneSwitcher.mediaTab.states.stopped="Detenido"
|
||||
AdvSceneSwitcher.mediaTab.states.ended="Finalizado"
|
||||
AdvSceneSwitcher.mediaTab.states.error="Error"
|
||||
@@ -574,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
@@ -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="случайный"
|
||||
@@ -135,7 +134,7 @@ AdvSceneSwitcher.action.recording.type.start="Начать запись"
|
||||
AdvSceneSwitcher.action.recording.type.pause="Пауза записи"
|
||||
AdvSceneSwitcher.action.recording.type.unpause="Снять запись с паузы"
|
||||
AdvSceneSwitcher.action.recording.pause.hint="Обратите внимание, что в зависимости от настроек записи вы можете не иметь возможности приостановить запись"
|
||||
AdvSceneSwitcher.action.recording.entry="{{actions}}{{pauseHint}}{{splitHint}}"
|
||||
AdvSceneSwitcher.action.recording.entry="{{actions}}{{recordFolder}}{{recordFileFormat}}{{pauseHint}}{{splitHint}}"
|
||||
AdvSceneSwitcher.action.replay="Буфер воспроизведения"
|
||||
AdvSceneSwitcher.action.replay.type.stop="Остановить буфер воспроизведения"
|
||||
AdvSceneSwitcher.action.replay.type.start="Начать воспроизведение буфера"
|
||||
@@ -144,7 +143,7 @@ AdvSceneSwitcher.action.replay.entry="{{actions}}"
|
||||
AdvSceneSwitcher.action.streaming="Потоковое вещание"
|
||||
AdvSceneSwitcher.action.streaming.type.stop="Остановить потоковое вещание"
|
||||
AdvSceneSwitcher.action.streaming.type.start="Начать потоковое вещание"
|
||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}"
|
||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
|
||||
AdvSceneSwitcher.action.run="Запустить"
|
||||
|
||||
|
||||
@@ -205,7 +204,7 @@ AdvSceneSwitcher.mediaTab.states.none="Нет"
|
||||
AdvSceneSwitcher.mediaTab.states.playing="Играет"
|
||||
AdvSceneSwitcher.mediaTab.states.opening="Открытие"
|
||||
AdvSceneSwitcher.mediaTab.states.buffering="Буферизация"
|
||||
AdvSceneSwitcher.mediaTab.states.Paused="Приостановлено"
|
||||
AdvSceneSwitcher.mediaTab.states.paused="Приостановлено"
|
||||
AdvSceneSwitcher.mediaTab.states.stopped="Остановлено"
|
||||
AdvSceneSwitcher.mediaTab.states.ended="Закончилось"
|
||||
AdvSceneSwitcher.mediaTab.states.error="Ошибка"
|
||||
|
||||
@@ -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"
|
||||
@@ -156,14 +153,13 @@ AdvSceneSwitcher.condition.stream.state.start="Yayın çalışıyor"
|
||||
AdvSceneSwitcher.condition.stream.state.stop="Yayın durdu"
|
||||
AdvSceneSwitcher.condition.stream.state.starting="Yayın başlıyor"
|
||||
AdvSceneSwitcher.condition.stream.state.stopping="Yayın duruyor"
|
||||
AdvSceneSwitcher.condition.stream.entry="{{streamState}}"
|
||||
AdvSceneSwitcher.condition.stream.entry="{{streamState}}{{keyFrameInterval}}"
|
||||
AdvSceneSwitcher.condition.record="Kayıt"
|
||||
AdvSceneSwitcher.condition.record.state.start="Kayıt Çalışıyor"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Kayıt durakladı"
|
||||
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"
|
||||
@@ -281,7 +278,7 @@ AdvSceneSwitcher.action.recording.type.start="Kayıt Başlat"
|
||||
AdvSceneSwitcher.action.recording.type.pause="Kayıt Duraklat"
|
||||
AdvSceneSwitcher.action.recording.type.unpause="Kayıt Duraklatma"
|
||||
AdvSceneSwitcher.action.recording.pause.hint="Kayıt ayarlarınıza bağlı olarak kaydı duraklatamayabileceğinizi unutmayın."
|
||||
AdvSceneSwitcher.action.recording.entry="{{actions}}{{pauseHint}}{{splitHint}}"
|
||||
AdvSceneSwitcher.action.recording.entry="{{actions}}{{recordFolder}}{{recordFileFormat}}{{pauseHint}}{{splitHint}}"
|
||||
AdvSceneSwitcher.action.replay="Tekrar arabelleği"
|
||||
AdvSceneSwitcher.action.replay.type.stop="Tekrar arabelleğini durdur"
|
||||
AdvSceneSwitcher.action.replay.type.start="Tekrar arabelleğini başlat"
|
||||
@@ -290,18 +287,14 @@ AdvSceneSwitcher.action.replay.entry="{{actions}}"
|
||||
AdvSceneSwitcher.action.streaming="Yayın"
|
||||
AdvSceneSwitcher.action.streaming.type.stop="Yayın durdur"
|
||||
AdvSceneSwitcher.action.streaming.type.start="Yayın başlat"
|
||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}"
|
||||
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"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.source="Kayıt"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Herhangi"
|
||||
AdvSceneSwitcher.action.sceneVisibility.entry="Açık{{scenes}}{{actions}}{{sourceTypes}}{{sources}}{{sourceGroups}}"
|
||||
AdvSceneSwitcher.action.sceneVisibility.entry="Açık{{scenes}}{{actions}}{{sources}}"
|
||||
AdvSceneSwitcher.action.filter="Filtrele"
|
||||
AdvSceneSwitcher.action.filter.type.enable="Etkin"
|
||||
AdvSceneSwitcher.action.filter.type.disable="Etkisiz"
|
||||
@@ -312,7 +305,7 @@ AdvSceneSwitcher.action.source="Kaynak"
|
||||
AdvSceneSwitcher.action.source.type.enable="Etkin"
|
||||
AdvSceneSwitcher.action.source.type.disable="Etkisiz"
|
||||
AdvSceneSwitcher.action.source.type.settings="Ayarları yap"
|
||||
AdvSceneSwitcher.action.source.entry="{{actions}}{{sources}}{{settingsButtons}}"
|
||||
AdvSceneSwitcher.action.source.entry="{{actions}}{{sources}}{{settingsButtons}}{{deinterlaceMode}}{{deinterlaceOrder}}"
|
||||
AdvSceneSwitcher.action.source.warning="Uyarı: Kaynakların global olarak etkinleştirilmesi ve devre dışı bırakılması, OBS UI tarafından kontrol edilemez"
|
||||
AdvSceneSwitcher.action.source.getSettings="Mevcut Ayarları yap"
|
||||
AdvSceneSwitcher.action.media="Medya"
|
||||
@@ -322,13 +315,12 @@ 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"
|
||||
AdvSceneSwitcher.action.macro.type.resetCounter="Sayacı sıfırla"
|
||||
AdvSceneSwitcher.action.macro.type.run="Çalıştır"
|
||||
AdvSceneSwitcher.action.macro.entry="{{actions}} {{macros}}"
|
||||
AdvSceneSwitcher.action.macro.entry="{{actions}}{{actionIndex}}{{macros}}"
|
||||
AdvSceneSwitcher.action.pluginState="Eklenti durumu"
|
||||
AdvSceneSwitcher.action.pluginState.type.stop="Advanced Scene Switcher eklentisini durdurun"
|
||||
AdvSceneSwitcher.action.pluginState.type.noMatch="Eşleşmeme davranışını değiştirin:"
|
||||
@@ -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"
|
||||
@@ -360,7 +351,7 @@ AdvSceneSwitcher.action.sceneOrder.type.movePosition="Konuma taşı"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="Açık{{scenes}}{{actions}}{{sources}}{{position}}"
|
||||
AdvSceneSwitcher.action.sceneTransform="Sahne öğesi dönüşümü"
|
||||
AdvSceneSwitcher.action.sceneTransform.getTransform="Dönüşümü al"
|
||||
AdvSceneSwitcher.action.sceneTransform.entry="Açık{{scenes}}transform{{sources}}"
|
||||
AdvSceneSwitcher.action.sceneTransform.entry="Açık{{scenes}}{{action}}{{rotation}}{{sources}}"
|
||||
AdvSceneSwitcher.action.file="Dosya"
|
||||
AdvSceneSwitcher.action.file.type.write="Yaz"
|
||||
AdvSceneSwitcher.action.file.type.append="Ekle"
|
||||
@@ -377,7 +368,6 @@ AdvSceneSwitcher.action.timer.entry="{{timerAction}} zamanlayıcılar açık {{m
|
||||
AdvSceneSwitcher.action.random="Rastgele"
|
||||
AdvSceneSwitcher.action.random.entry="Aşağıdaki makrolardan herhangi birini rastgele çalıştırın (duraklatılmış makrolar yoksayılır)"
|
||||
AdvSceneSwitcher.action.systray="Sistem tepsisi bildirimi"
|
||||
AdvSceneSwitcher.action.systray.entry="Bildirimleri göster: {{message}}"
|
||||
AdvSceneSwitcher.action.screenshot="Ekran görüntüsü"
|
||||
AdvSceneSwitcher.action.screenshot.mainOutput="OBS'nin ana çıkışı"
|
||||
AdvSceneSwitcher.action.profile="Profil"
|
||||
@@ -443,7 +433,7 @@ AdvSceneSwitcher.mediaTab.states.none="Yok"
|
||||
AdvSceneSwitcher.mediaTab.states.playing="Oynamak"
|
||||
AdvSceneSwitcher.mediaTab.states.opening="Açmak"
|
||||
AdvSceneSwitcher.mediaTab.states.buffering="Arabelleğe alma"
|
||||
AdvSceneSwitcher.mediaTab.states.Paused="Duraklatıldı"
|
||||
AdvSceneSwitcher.mediaTab.states.paused="Duraklatıldı"
|
||||
AdvSceneSwitcher.mediaTab.states.stopped="Durduruldu"
|
||||
AdvSceneSwitcher.mediaTab.states.ended="Bitti"
|
||||
AdvSceneSwitcher.mediaTab.states.error="Hata"
|
||||
|
||||
@@ -4,7 +4,7 @@ AdvSceneSwitcher.windowTitle="高级场景切换器"
|
||||
; General Tab
|
||||
AdvSceneSwitcher.generalTab.title="通用"
|
||||
AdvSceneSwitcher.generalTab.status="状态"
|
||||
AdvSceneSwitcher.generalTab.status.hotkeytips="快捷键可在OBS设置中设置"
|
||||
AdvSceneSwitcher.generalTab.status.hotkeytips="快捷键可在OBS设置中设置<br><br>汉化作者:[ 从不咕咕的阿坤 ] - 全平台统一名 - 如对你有所帮助,劳烦点个关注!"
|
||||
AdvSceneSwitcher.generalTab.status.currentStatus="当前状态:"
|
||||
AdvSceneSwitcher.generalTab.status.onStartup="在OBS启动时"
|
||||
AdvSceneSwitcher.generalTab.status.onStartup.asLastRun="按照最后运行时的状态"
|
||||
@@ -24,11 +24,14 @@ AdvSceneSwitcher.generalTab.generalBehavior.onNoMetDelayTooltip="时间精度最
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.dontSwitch="不切换"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchToRandom="切换到随机场景列表中任意随机场景"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchTo="切换到"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.cooldown="执行完操作后,跳过执行操作,为"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint="在此期间,可能的匹配项将被忽略!"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="详细日志输出"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="保存窗口位置和大小"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="显示系统托盘通知"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="禁用UI提示"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.warnPluginLoadFailure="如果无法加载插件显示警告"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.warnPluginLoadFailureMessage="<html><body>加载以下插件库失败,这可能导致某些高级场景切换器功能不可用:%1 查看 OBS 日志了解详细信息.<br>可以在“常规”选项卡上禁用此消息.</body></html>"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.hideLegacyTabs="隐藏可通过宏操作的分组栏"
|
||||
AdvSceneSwitcher.generalTab.matchBehavior="场景匹配设置"
|
||||
AdvSceneSwitcher.generalTab.priority="优先级"
|
||||
@@ -78,17 +81,39 @@ AdvSceneSwitcher.macroTab.runFail="运行 \"%1\" 失败!\n其中一个操作失
|
||||
AdvSceneSwitcher.macroTab.runInParallel="与其他宏同时运行宏"
|
||||
AdvSceneSwitcher.macroTab.onChange="仅在条件更改时执行操作"
|
||||
AdvSceneSwitcher.macroTab.defaultname="宏 %1"
|
||||
AdvSceneSwitcher.macroTab.defaultGroupName="组 %1"
|
||||
AdvSceneSwitcher.macroTab.exists="宏名称已存在"
|
||||
AdvSceneSwitcher.macroTab.groupDeleteConfirm="您确定要删除 \"%1\"及其所有元素吗?"
|
||||
AdvSceneSwitcher.macroTab.deleteMultipleMacrosConfirmation="您确定要删除 %1 宏吗?"
|
||||
AdvSceneSwitcher.macroTab.deleteSingleMacroConfirmation="你确定你要删除 \"%1\"?"
|
||||
AdvSceneSwitcher.macroTab.contextMenuAdd="增加"
|
||||
AdvSceneSwitcher.macroTab.copy="创建副本"
|
||||
AdvSceneSwitcher.macroTab.group="对选定的宏进行分组"
|
||||
AdvSceneSwitcher.macroTab.ungroup="解除选定的组的分组"
|
||||
AdvSceneSwitcher.macroTab.rename="重命名"
|
||||
AdvSceneSwitcher.macroTab.remove="删除"
|
||||
AdvSceneSwitcher.macroTab.expandAll="全部展开"
|
||||
AdvSceneSwitcher.macroTab.collapseAll="全部收回"
|
||||
AdvSceneSwitcher.macroTab.maximize="最大化"
|
||||
AdvSceneSwitcher.macroTab.minimize="最小化"
|
||||
AdvSceneSwitcher.macroTab.highlightSettings="显示 设置"
|
||||
AdvSceneSwitcher.macroTab.hotkeySettings="热键 设置"
|
||||
AdvSceneSwitcher.macroTab.dockSettings="停靠 设置"
|
||||
AdvSceneSwitcher.macroTab.highlightExecutedMacros="突出显示最近执行的宏"
|
||||
AdvSceneSwitcher.macroTab.highlightTrueConditions="突出显示最近运算为 真 的当前选定宏的条件"
|
||||
AdvSceneSwitcher.macroTab.highlightPerformedActions="突出显示当前选定宏的最近执行的操作"
|
||||
AdvSceneSwitcher.macroTab.newMacroRegisterHotkey="使用快捷键控制新增宏的暂停状态"
|
||||
AdvSceneSwitcher.macroTab.currentDisableHotkeys="使用快捷键控制所选宏的暂停状态"
|
||||
AdvSceneSwitcher.macroTab.currentRegisterDock="注册停靠小部件以控制所选宏的暂停状态或手动运行它"
|
||||
AdvSceneSwitcher.macroTab.currentDockAddRunButton="添加按钮以运行宏"
|
||||
AdvSceneSwitcher.macroTab.currentDockAddPauseButton="添加按钮以暂停或取消暂停宏"
|
||||
AdvSceneSwitcher.macroTab.currentDockButtonText.run="运行按钮文本:"
|
||||
AdvSceneSwitcher.macroTab.currentDockButtonText.pause="暂停按钮文本:"
|
||||
AdvSceneSwitcher.macroTab.currentDockButtonText.unpause="取消暂停按钮文本:"
|
||||
|
||||
AdvSceneSwitcher.macroDock.pause="暂停"
|
||||
AdvSceneSwitcher.macroDock.unpause="取消暂停"
|
||||
AdvSceneSwitcher.macroDock.run="运行"
|
||||
|
||||
; Macro List
|
||||
AdvSceneSwitcher.macroList.deleted="删除"
|
||||
@@ -112,10 +137,17 @@ AdvSceneSwitcher.condition.audio.state.mute="静音"
|
||||
AdvSceneSwitcher.condition.audio.state.unmute="取消静音"
|
||||
AdvSceneSwitcher.condition.audio.type.output="输出音频"
|
||||
AdvSceneSwitcher.condition.audio.type.volume="配置音量级别"
|
||||
AdvSceneSwitcher.condition.audio.type.syncOffset="同步偏移"
|
||||
AdvSceneSwitcher.condition.audio.type.monitor="音频监控"
|
||||
AdvSceneSwitcher.condition.audio.type.balance="音频平衡"
|
||||
AdvSceneSwitcher.condition.audio.entry="{{checkType}} 的 {{audioSources}} 是 {{condition}}{{volume}}{{syncOffset}}{{monitorTypes}}"
|
||||
AdvSceneSwitcher.condition.cursor="屏幕区域"
|
||||
AdvSceneSwitcher.condition.cursor.type.region="当前位置"
|
||||
AdvSceneSwitcher.condition.cursor.type.moving="正在移动"
|
||||
AdvSceneSwitcher.condition.cursor.type.click="点击"
|
||||
AdvSceneSwitcher.condition.cursor.button.left="鼠标左键"
|
||||
AdvSceneSwitcher.condition.cursor.button.middle="鼠标中键"
|
||||
AdvSceneSwitcher.condition.cursor.button.right="鼠标右键"
|
||||
AdvSceneSwitcher.condition.cursor.showFrame="显示帧率"
|
||||
AdvSceneSwitcher.condition.cursor.hideFrame="隐藏帧率"
|
||||
AdvSceneSwitcher.condition.cursor.entry.line1="鼠标 处于{{conditions}}{{buttons}}{{minX}}{{minY}}{{maxX}}{{maxY}}{{toggleFrameButton}}"
|
||||
@@ -125,36 +157,46 @@ AdvSceneSwitcher.condition.scene.type.current="当前场景是"
|
||||
AdvSceneSwitcher.condition.scene.type.previous="上一个场景是"
|
||||
AdvSceneSwitcher.condition.scene.type.changed="场景改变了"
|
||||
AdvSceneSwitcher.condition.scene.type.notChanged="场景没有改变"
|
||||
AdvSceneSwitcher.condition.scene.type.currentPattern="当前场景匹配"
|
||||
AdvSceneSwitcher.condition.scene.type.previousPattern="上一个场景匹配"
|
||||
AdvSceneSwitcher.condition.scene.currentSceneTransitionBehaviour="在转场过程中检查转场源场景"
|
||||
AdvSceneSwitcher.condition.scene.previousSceneTransitionBehaviour="在转场过程中检查转场源场景"
|
||||
AdvSceneSwitcher.condition.scene.entry.line1="{{sceneType}}{{scenes}}{{pattern}}"
|
||||
AdvSceneSwitcher.condition.scene.entry.line2="{{useTransitionTargetScene}}"
|
||||
AdvSceneSwitcher.condition.window="窗口"
|
||||
AdvSceneSwitcher.condition.window.entry.line1="{{windows}} 存在..."
|
||||
AdvSceneSwitcher.condition.window.entry.line2="... 并且是 {{fullscreen}} 全屏 {{maximized}} 最大化 {{focused}} 获得焦点 {{windowFocusChanged}} 焦点窗口已更改"
|
||||
AdvSceneSwitcher.condition.window.entry.line3="当前焦点窗口: {{focusWindow}}"
|
||||
AdvSceneSwitcher.condition.window.entry.window="{{checkTitle}}窗口标题匹配{{windowRegex}}{{windows}}"
|
||||
AdvSceneSwitcher.condition.window.entry.fullscreen="{{fullscreen}}窗口为全屏"
|
||||
AdvSceneSwitcher.condition.window.entry.maximized="{{maximized}}窗口为最大化"
|
||||
AdvSceneSwitcher.condition.window.entry.focused="{{focused}}窗口为焦点"
|
||||
AdvSceneSwitcher.condition.window.entry.focusedChange="{{windowFocusChanged}}焦点窗口被改变"
|
||||
AdvSceneSwitcher.condition.window.entry.text="{{checkText}}窗口包含文本{{textRegex}}{{windowText}}"
|
||||
AdvSceneSwitcher.condition.window.entry.text.note="此选项可能不会对窗口中显示的每个文本起作用。\n如果是这种情况,您可以考虑使用视频条件OCR检查来代替。"
|
||||
AdvSceneSwitcher.condition.window.entry.currentFocus="当前焦点窗口:{{focusWindow}}"
|
||||
AdvSceneSwitcher.condition.file="文件"
|
||||
AdvSceneSwitcher.condition.file.type.match="内容完全匹配"
|
||||
AdvSceneSwitcher.condition.file.type.contentChange="内容已更改"
|
||||
AdvSceneSwitcher.condition.file.type.dateChange="修改日期已更改"
|
||||
AdvSceneSwitcher.condition.file.entry.line1="文件内容来自{{fileType}}{{filePath}}{{conditions}}"
|
||||
AdvSceneSwitcher.condition.file.remote="远程文件"
|
||||
AdvSceneSwitcher.condition.file.local="本地文件"
|
||||
AdvSceneSwitcher.condition.file.entry.line1="{{fileType}}{{filePath}}{{conditions}}{{useRegex}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line3="{{useRegex}} {{checkModificationDate}} {{checkFileContent}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFileContent}}"
|
||||
AdvSceneSwitcher.condition.media="媒体"
|
||||
AdvSceneSwitcher.condition.media.anyOnScene="任何媒体来源"
|
||||
AdvSceneSwitcher.condition.media.allOnScene="所有媒体来源"
|
||||
AdvSceneSwitcher.condition.media.matchOnChange="仅在更改时匹配(注意:此选项将在未来版本中删除-请改用时间限制)"
|
||||
AdvSceneSwitcher.condition.media.source="源"
|
||||
AdvSceneSwitcher.condition.media.anyOnScene="任何媒体源"
|
||||
AdvSceneSwitcher.condition.media.allOnScene="所有媒体源"
|
||||
AdvSceneSwitcher.condition.media.inconsistencyInfo="不幸的是,并非所有媒体源类型的行为都相同(例如,媒体源与VLC视频源“停止”状态)。\n所以,请尝试适合您的设置!"
|
||||
AdvSceneSwitcher.condition.media.entry="{{sourceTypes}}{{mediaSources}}{{scenes}}的状态是{{states}}和{{timeRestrictions}}{{time}}"
|
||||
AdvSceneSwitcher.condition.media.entry="{{sourceTypes}}{{mediaSources}}{{scenes}} 的状态是 {{states}} 和 {{timeRestrictions}}{{time}}"
|
||||
AdvSceneSwitcher.condition.video="视频"
|
||||
AdvSceneSwitcher.condition.video.condition.match="完全匹配"
|
||||
AdvSceneSwitcher.condition.video.condition.differ="不匹配"
|
||||
AdvSceneSwitcher.condition.video.condition.hasChanged="改变了"
|
||||
AdvSceneSwitcher.condition.video.condition.hasNotChanged="没有改变"
|
||||
AdvSceneSwitcher.condition.video.condition.hasChanged="已改变"
|
||||
AdvSceneSwitcher.condition.video.condition.hasNotChanged="未改变"
|
||||
AdvSceneSwitcher.condition.video.condition.noImage="没有输出"
|
||||
AdvSceneSwitcher.condition.video.condition.pattern="匹配模式"
|
||||
AdvSceneSwitcher.condition.video.condition.object="包含对象"
|
||||
AdvSceneSwitcher.condition.video.condition.brightness="亮度"
|
||||
AdvSceneSwitcher.condition.video.condition.ocr="包含文本"
|
||||
AdvSceneSwitcher.condition.video.askFileAction="是否要使用现有文件或创建当前选定源的屏幕截图?"
|
||||
AdvSceneSwitcher.condition.video.askFileAction.file="使用现有文件"
|
||||
AdvSceneSwitcher.condition.video.askFileAction.screenshot="创建屏幕截图"
|
||||
@@ -164,28 +206,49 @@ AdvSceneSwitcher.condition.video.usePatternForChangedCheck="使用模式匹配"
|
||||
AdvSceneSwitcher.condition.video.usePatternForChangedCheck.tooltip="这将允许您控制图像必须更改多少才能使条件为真."
|
||||
AdvSceneSwitcher.condition.video.patternThreshold="阈值: "
|
||||
AdvSceneSwitcher.condition.video.patternThresholdDescription="较高的阈值意味着模式需要更紧密地匹配视频源."
|
||||
AdvSceneSwitcher.condition.video.patternThresholdUseAlphaAsMask="使用alpha通道作为图案的遮罩."
|
||||
AdvSceneSwitcher.condition.video.patternThresholdUseAlphaAsMask="使用alpha通道作为模式的遮罩."
|
||||
AdvSceneSwitcher.condition.video.patternMatchMode="使用模式匹配方式 {{patternMatchingModes}}"
|
||||
AdvSceneSwitcher.condition.video.patternMatchMode.crossCorrelation="交叉相关"
|
||||
AdvSceneSwitcher.condition.video.patternMatchMode.correlationCoefficient="相关系数"
|
||||
AdvSceneSwitcher.condition.video.patternMatchMode.squaredDifference="平方差"
|
||||
AdvSceneSwitcher.condition.video.patternMatchMode.tip="使用的最佳方法取决于具体问题和所涉及图像的特性。\n在实践中,通常需要使用不同的方法和参数进行实验,以找到对特定用例的最佳匹配。"
|
||||
AdvSceneSwitcher.condition.video.brightnessThreshold="平均亮度:"
|
||||
AdvSceneSwitcher.condition.video.brightnessThresholdDescription="较高的值表示图像较亮,较低的值表示图像较暗。"
|
||||
AdvSceneSwitcher.condition.video.brightnessThresholdDescription="高的值表示明亮的图像,低的值表示较暗的图像。"
|
||||
AdvSceneSwitcher.condition.video.currentBrightness="当前平均亮度: %1"
|
||||
AdvSceneSwitcher.condition.video.objectScaleThreshold="模型比例: "
|
||||
AdvSceneSwitcher.condition.video.objectScaleThresholdDescription="较低的模比例将导致更多的匹配,但会导致更高的CPU负载."
|
||||
AdvSceneSwitcher.condition.video.objectScaleThresholdDescription="较低的模型比例会产生更多的匹配,但将导致CPU负载更高."
|
||||
AdvSceneSwitcher.condition.video.minNeighborDescription="较高的“最小区域”值将导致较少但质量较高的匹配."
|
||||
AdvSceneSwitcher.condition.video.showMatch="显示模式"
|
||||
AdvSceneSwitcher.condition.video.showMatch.loading="Checking for match"
|
||||
AdvSceneSwitcher.condition.video.showMatch.loading="检查是否匹配"
|
||||
AdvSceneSwitcher.condition.video.screenshotFail="无法获取源的屏幕截图!"
|
||||
AdvSceneSwitcher.condition.video.screenshotEmpty="Screenshot is empty - Is the source visible?"
|
||||
AdvSceneSwitcher.condition.video.screenshotEmpty="屏幕截图为空 - 源是否可见?"
|
||||
AdvSceneSwitcher.condition.video.patternMatchFail="没有找到模式!"
|
||||
AdvSceneSwitcher.condition.video.patternMatchSuccess="Pattern is highlighted in red"
|
||||
AdvSceneSwitcher.condition.video.patternMatchSuccess="模式以红色突出显示"
|
||||
AdvSceneSwitcher.condition.video.objectMatchFail="找不到对象!"
|
||||
AdvSceneSwitcher.condition.video.objectMatchSuccess="Object is highlighted in red"
|
||||
AdvSceneSwitcher.condition.video.objectMatchSuccess="对象以红色突出显示"
|
||||
AdvSceneSwitcher.condition.video.ocrMatchSuccess="检测到的文本:\n\n%1"
|
||||
AdvSceneSwitcher.condition.video.modelLoadFail="无法加载模型数据!"
|
||||
AdvSceneSwitcher.condition.video.selectColor="选择颜色"
|
||||
AdvSceneSwitcher.condition.video.ocrMode.singleColumn="单列可变大小的文本"
|
||||
AdvSceneSwitcher.condition.video.ocrMode.singleBlockVertText="垂直对齐的单个统一文本块"
|
||||
AdvSceneSwitcher.condition.video.ocrMode.singleBlock="单个统一的文本块"
|
||||
AdvSceneSwitcher.condition.video.ocrMode.singleLine="单个文本行"
|
||||
AdvSceneSwitcher.condition.video.ocrMode.singleWord="单词"
|
||||
AdvSceneSwitcher.condition.video.ocrMode.circleWord="圆圈中的单个单词"
|
||||
AdvSceneSwitcher.condition.video.ocrMode.singleChar="单个字符"
|
||||
AdvSceneSwitcher.condition.video.ocrMode.sparseText="不按特定顺序查找文本"
|
||||
AdvSceneSwitcher.condition.video.ocrMode.sparseTextOSD="不按特定顺序查找文本(OSD)"
|
||||
AdvSceneSwitcher.condition.video.type.main="OBS的主输出"
|
||||
AdvSceneSwitcher.condition.video.type.source="源"
|
||||
AdvSceneSwitcher.condition.video.type.scene="场景"
|
||||
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
|
||||
AdvSceneSwitcher.condition.video.entry.modelPath="模型数据 (haar级联分类器): {{modelDataPath}}"
|
||||
AdvSceneSwitcher.condition.video.entry.minNeighbor="最小区域: {{minNeighbors}}"
|
||||
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}通过只执行每一次检查来减少CPU负载 {{throttleCount}} 毫秒"
|
||||
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}每隔一段时间检查一次,来减少CPU负载 {{throttleCount}} 毫秒"
|
||||
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="仅在区域内执行检查"
|
||||
AdvSceneSwitcher.condition.video.entry.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
|
||||
AdvSceneSwitcher.condition.video.entry.orcColorPick="检查文本颜色:{{textColor}}{{selectColor}}"
|
||||
AdvSceneSwitcher.condition.video.entry.orcTextType="检查文本类型:{{textType}}"
|
||||
AdvSceneSwitcher.condition.video.minSize="最小尺寸:"
|
||||
AdvSceneSwitcher.condition.video.maxSize="最大尺寸:"
|
||||
AdvSceneSwitcher.condition.video.selectArea="选择区域"
|
||||
@@ -197,21 +260,24 @@ AdvSceneSwitcher.condition.stream.state.start="推流启动"
|
||||
AdvSceneSwitcher.condition.stream.state.stop="推流停止"
|
||||
AdvSceneSwitcher.condition.stream.state.starting="推流启动中"
|
||||
AdvSceneSwitcher.condition.stream.state.stopping="推流停止中"
|
||||
AdvSceneSwitcher.condition.stream.entry="{{streamState}}"
|
||||
AdvSceneSwitcher.condition.stream.state.keyFrameInterval="关键帧间隔等于"
|
||||
AdvSceneSwitcher.condition.stream.entry="{{streamState}}{{keyFrameInterval}}"
|
||||
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}}"
|
||||
AdvSceneSwitcher.condition.pluginState="插件状态"
|
||||
AdvSceneSwitcher.condition.pluginState.state.sceneSwitched="在此时间间隔内触发了自动场景更改"
|
||||
AdvSceneSwitcher.condition.pluginState.state.running="高级场景切换程序正在运行"
|
||||
AdvSceneSwitcher.condition.pluginState.state.start="插件已启动"
|
||||
AdvSceneSwitcher.condition.pluginState.state.restart="插件已重新启动"
|
||||
AdvSceneSwitcher.condition.pluginState.state.running="插件正在运行"
|
||||
AdvSceneSwitcher.condition.pluginState.state.shutdown="OBS正在关闭"
|
||||
AdvSceneSwitcher.condition.pluginState.state.sceneCollection="场景集合已加载"
|
||||
AdvSceneSwitcher.condition.pluginState.state.sceneSwitched="场景被上一个宏改变"
|
||||
AdvSceneSwitcher.condition.pluginState.entry="{{condition}}"
|
||||
AdvSceneSwitcher.condition.timer="计时器"
|
||||
AdvSceneSwitcher.condition.timer.type.fixed="固定"
|
||||
@@ -236,11 +302,11 @@ AdvSceneSwitcher.condition.macro.state.type.above="大于"
|
||||
AdvSceneSwitcher.condition.macro.state.type.equal="等于"
|
||||
AdvSceneSwitcher.condition.macro.count.reset="重置"
|
||||
AdvSceneSwitcher.condition.macro.pausedWarning="所选宏当前已暂停!"
|
||||
AdvSceneSwitcher.condition.macro.state.entry="条件 {{macros}} 运行结果为真"
|
||||
AdvSceneSwitcher.condition.macro.multistate.entry="条件 {{multiStateConditions}}{{multiStateCount}} 以下宏运行结果为真:"
|
||||
AdvSceneSwitcher.condition.macro.count.entry.line1="{{macros}} 运行 {{conditions}} {{count}} 次(相对于下面计数匹配)"
|
||||
AdvSceneSwitcher.condition.macro.state.entry="{{macros}} 的条件为真"
|
||||
AdvSceneSwitcher.condition.macro.multistate.entry=" 以下宏的 {{multiStateConditions}}{{multiStateCount}} 的条件为真:"
|
||||
AdvSceneSwitcher.condition.macro.count.entry.line1="{{macros}} 执行 {{conditions}} {{count}} 次(相对于下面计数匹配)"
|
||||
AdvSceneSwitcher.condition.macro.count.entry.line2="当前计数: {{currentCount}} {{resetCount}}"
|
||||
AdvSceneSwitcher.condition.source="来源"
|
||||
AdvSceneSwitcher.condition.source="源"
|
||||
AdvSceneSwitcher.condition.source.type.active="是激活状态"
|
||||
AdvSceneSwitcher.condition.source.type.showing="是显示状态"
|
||||
AdvSceneSwitcher.condition.source.type.settings="设置完全匹配"
|
||||
@@ -257,7 +323,7 @@ AdvSceneSwitcher.condition.filter.type.active="已启用"
|
||||
AdvSceneSwitcher.condition.filter.type.showing="已关闭"
|
||||
AdvSceneSwitcher.condition.filter.type.settings="设置完全匹配"
|
||||
AdvSceneSwitcher.condition.filter.getSettings="获取当前设置"
|
||||
AdvSceneSwitcher.condition.filter.entry.line1="在 {{sources}} {{filters}} {{conditions}}"
|
||||
AdvSceneSwitcher.condition.filter.entry.line1="在 {{sources}} 的 {{filters}} 是 {{conditions}}"
|
||||
AdvSceneSwitcher.condition.filter.entry.line2="{{settings}}"
|
||||
AdvSceneSwitcher.condition.filter.entry.line3="{{regex}} {{getSettings}}"
|
||||
AdvSceneSwitcher.condition.sceneOrder="场景项目顺序"
|
||||
@@ -289,7 +355,8 @@ AdvSceneSwitcher.condition.date.state.at="现在"
|
||||
AdvSceneSwitcher.condition.date.state.after="之后"
|
||||
AdvSceneSwitcher.condition.date.state.before="之前"
|
||||
AdvSceneSwitcher.condition.date.state.between="之间"
|
||||
AdvSceneSwitcher.condition.date.separator="和"
|
||||
AdvSceneSwitcher.condition.date.state.pattern="模式"
|
||||
AdvSceneSwitcher.condition.date.separator="到"
|
||||
AdvSceneSwitcher.condition.date.ignoreDate="如果未选中,日期组件将被忽略"
|
||||
AdvSceneSwitcher.condition.date.ignoreTime="如果未选中,时间组件将被忽略"
|
||||
AdvSceneSwitcher.condition.date.showAdvancedSettings="显示高级设置"
|
||||
@@ -297,11 +364,13 @@ AdvSceneSwitcher.condition.date.showSimpleSettings="显示简单设置"
|
||||
AdvSceneSwitcher.condition.date.entry.simple="在 {{dayOfWeek}} {{weekCondition}} {{ignoreWeekTime}}{{weekTime}}"
|
||||
AdvSceneSwitcher.condition.date.entry.advanced="{{condition}} {{ignoreDate}}{{date}} {{ignoreTime}}{{time}} {{separator}} {{date2}} {{time2}}"
|
||||
AdvSceneSwitcher.condition.date.entry.repeat="{{repeat}} 在匹配到日期时间后,每隔 {{duration}} 重复一次"
|
||||
AdvSceneSwitcher.condition.date.entry.nextMatchDate="Next match at: %1"
|
||||
AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}} On repeat update selected date to repeat date"
|
||||
AdvSceneSwitcher.condition.date.entry.pattern="当前日期 \"{{currentDate}}\" 匹配模式 {{pattern}}"
|
||||
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="转场"
|
||||
@@ -316,6 +385,7 @@ AdvSceneSwitcher.condition.transition.entry="{{conditions}}{{transitions}}{{scen
|
||||
AdvSceneSwitcher.condition.sceneVisibility="场景项目可见"
|
||||
AdvSceneSwitcher.condition.sceneVisibility.type.shown="显示的"
|
||||
AdvSceneSwitcher.condition.sceneVisibility.type.hidden="隐藏的"
|
||||
AdvSceneSwitcher.condition.sceneVisibility.type.changed="可见性已更改"
|
||||
AdvSceneSwitcher.condition.sceneVisibility.entry="在 {{scenes}} {{sources}} 是 {{conditions}} "
|
||||
AdvSceneSwitcher.condition.studioMode="工作室模式"
|
||||
AdvSceneSwitcher.condition.studioMode.state.active="工作室模式处于活动状态"
|
||||
@@ -345,7 +415,7 @@ AdvSceneSwitcher.condition.stats.condition.above="大于"
|
||||
AdvSceneSwitcher.condition.stats.condition.equals="等于"
|
||||
AdvSceneSwitcher.condition.stats.condition.below="少于"
|
||||
AdvSceneSwitcher.condition.stats.dockHint="你可以打开“统计”窗口查看当前状态"
|
||||
AdvSceneSwitcher.condition.stats.entry="{{stats}} is {{condition}} {{value}}"
|
||||
AdvSceneSwitcher.condition.stats.entry="{{stats}} 是 {{condition}} {{value}}"
|
||||
AdvSceneSwitcher.condition.profile="配置文件"
|
||||
AdvSceneSwitcher.condition.profile.entry="当前活动的配置文件为 {{profiles}}"
|
||||
AdvSceneSwitcher.condition.websocket="websocket"
|
||||
@@ -361,12 +431,24 @@ AdvSceneSwitcher.condition.variable.type.number="是一个数字"
|
||||
AdvSceneSwitcher.condition.variable.type.lessThan="小于"
|
||||
AdvSceneSwitcher.condition.variable.type.greaterThan="大于"
|
||||
AdvSceneSwitcher.condition.variable.type.valueChanged="值已更改"
|
||||
AdvSceneSwitcher.condition.variable.entry="{{variables}}{{conditions}}{{strValue}}{{numValue}}{{variables2}}"
|
||||
AdvSceneSwitcher.condition.variable.type.equalsVariable="等于变量"
|
||||
AdvSceneSwitcher.condition.variable.type.lessThanVariable="小于变量"
|
||||
AdvSceneSwitcher.condition.variable.type.greaterThanVariable="大于变量"
|
||||
AdvSceneSwitcher.condition.run="运行"
|
||||
AdvSceneSwitcher.condition.run.entry="进程在超时 {{timeout}} 秒之前退出"
|
||||
AdvSceneSwitcher.condition.run.entry.exit="{{checkExitCode}}检查退出代码{{exitCode}}"
|
||||
AdvSceneSwitcher.condition.midi="MIDI"
|
||||
AdvSceneSwitcher.condition.midi.entry="从{{device}} 收到的信息,符合:(从不咕咕的阿坤:这个好像是声卡工作是录音相关的功能,英文太抽象了,我就硬译过来了,如有相关设备,音乐好的,可以根据英文翻译好发给我!)"
|
||||
AdvSceneSwitcher.condition.midi.entry.listen="将MIDI信息选择设置为从选定设备上接收的信息: {{listenButton}}"
|
||||
AdvSceneSwitcher.condition.display="显示器"
|
||||
AdvSceneSwitcher.condition.display.type.displayName="连接的显示器的名称匹配"
|
||||
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="固定数值"
|
||||
@@ -378,6 +460,10 @@ AdvSceneSwitcher.action.audio.type.mute="静音"
|
||||
AdvSceneSwitcher.action.audio.type.unmute="取消静音"
|
||||
AdvSceneSwitcher.action.audio.type.sourceVolume="来源音量"
|
||||
AdvSceneSwitcher.action.audio.type.masterVolume="主音量"
|
||||
AdvSceneSwitcher.action.audio.type.syncOffset="设置同步偏移"
|
||||
AdvSceneSwitcher.action.audio.type.monitor="设置音频监听"
|
||||
AdvSceneSwitcher.action.audio.type.balance="设置平衡"
|
||||
AdvSceneSwitcher.action.audio.balance.description="选择的音频源将滑块方向移动(从不咕咕的阿坤的理解:左/右声道偏侧向)"
|
||||
AdvSceneSwitcher.action.audio.fade.type.duration="持续时间"
|
||||
AdvSceneSwitcher.action.audio.fade.type.rate="百分比"
|
||||
AdvSceneSwitcher.action.audio.fade.duration="{{fade}}淡出 {{fadeTypes}} {{duration}} 秒."
|
||||
@@ -391,43 +477,45 @@ AdvSceneSwitcher.action.recording.type.start="开始录制"
|
||||
AdvSceneSwitcher.action.recording.type.pause="暂停录制"
|
||||
AdvSceneSwitcher.action.recording.type.unpause="取消录制暂停"
|
||||
AdvSceneSwitcher.action.recording.type.split="分割录制文件"
|
||||
AdvSceneSwitcher.action.recording.type.changeOutputFolder="更改输出文件夹"
|
||||
AdvSceneSwitcher.action.recording.type.changeOutputFileFormat="改变文件名的格式"
|
||||
AdvSceneSwitcher.action.recording.pause.hint="请注意,根据您的录制设置,您可能无法暂停录制"
|
||||
AdvSceneSwitcher.action.recording.split.hint="确保先在OBS设置中启用自动分割文件!"
|
||||
AdvSceneSwitcher.action.recording.entry="{{actions}}{{pauseHint}}{{splitHint}}"
|
||||
AdvSceneSwitcher.action.replay="回放缓冲区"
|
||||
AdvSceneSwitcher.action.replay.saveWarn="警告:保存过于频繁可能会导致重播缓冲区实际上未保存!"
|
||||
AdvSceneSwitcher.action.replay.type.stop="停止回放缓冲区"
|
||||
AdvSceneSwitcher.action.replay.type.start="启动回放缓冲区"
|
||||
AdvSceneSwitcher.action.replay.type.save="保存回放缓冲区"
|
||||
AdvSceneSwitcher.action.recording.entry="{{actions}}{{recordFolder}}{{recordFileFormat}}{{pauseHint}}{{splitHint}}"
|
||||
AdvSceneSwitcher.action.replay="回放缓存"
|
||||
AdvSceneSwitcher.action.replay.saveWarn="警告:保存过于频繁可能会导致回放缓存实际上未保存!"
|
||||
AdvSceneSwitcher.action.replay.type.stop="停止回放缓存"
|
||||
AdvSceneSwitcher.action.replay.type.start="启动回放缓存"
|
||||
AdvSceneSwitcher.action.replay.type.save="保存回放缓存"
|
||||
AdvSceneSwitcher.action.replay.entry="{{actions}}"
|
||||
AdvSceneSwitcher.action.streaming="推流"
|
||||
AdvSceneSwitcher.action.streaming.type.stop="停止推流"
|
||||
AdvSceneSwitcher.action.streaming.type.start="开始推流"
|
||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}"
|
||||
AdvSceneSwitcher.action.streaming.type.keyFrameInterval="设置关键帧间隔"
|
||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
|
||||
AdvSceneSwitcher.action.run="运行"
|
||||
AdvSceneSwitcher.action.run.arguments="参数:"
|
||||
AdvSceneSwitcher.action.run.addArgument="添加参数"
|
||||
AdvSceneSwitcher.action.run.addArgumentDescription="添加新参数:"
|
||||
AdvSceneSwitcher.action.run.entry="运行 {{filePath}}"
|
||||
AdvSceneSwitcher.action.sceneVisibility="场景项目可见性"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.show="显示"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.hide="隐藏"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.toggle="切换"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.source="来源"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="全部"
|
||||
AdvSceneSwitcher.action.sceneVisibility.entry="设置{{scenes}}{{actions}}{{sourceTypes}}{{sources}}{{sourceGroups}}"
|
||||
AdvSceneSwitcher.action.sceneVisibility.entry="置{{scenes}}{{actions}}{{sources}}"
|
||||
AdvSceneSwitcher.action.filter="滤镜"
|
||||
AdvSceneSwitcher.action.filter.type.enable="开启"
|
||||
AdvSceneSwitcher.action.filter.type.disable="关闭"
|
||||
AdvSceneSwitcher.action.filter.type.settings="参数设置"
|
||||
AdvSceneSwitcher.action.filter.entry="在 {{sources}} {{actions}} {{filters}}"
|
||||
AdvSceneSwitcher.action.filter.entry="置 {{sources}} {{actions}} {{filters}}"
|
||||
AdvSceneSwitcher.action.filter.getSettings="获取当前设置"
|
||||
AdvSceneSwitcher.action.source="来源"
|
||||
AdvSceneSwitcher.action.source="源"
|
||||
AdvSceneSwitcher.action.source.type.enable="启用"
|
||||
AdvSceneSwitcher.action.source.type.disable="停用"
|
||||
AdvSceneSwitcher.action.source.type.settings="配置设置"
|
||||
AdvSceneSwitcher.action.source.type.refreshSettings="刷新源设置"
|
||||
AdvSceneSwitcher.action.source.type.refreshSettings.tooltip="可用于刷新浏览器、媒体等源"
|
||||
AdvSceneSwitcher.action.source.entry="{{actions}}{{sources}}{{settingsButtons}}"
|
||||
AdvSceneSwitcher.action.source.type.pressSettingsButton="按下设置按钮"
|
||||
AdvSceneSwitcher.action.source.type.refreshSettings.tooltip="可用于刷新浏览器、媒体、源、etc"
|
||||
AdvSceneSwitcher.action.source.noSettingsButtons="未找到按钮!"
|
||||
AdvSceneSwitcher.action.source.entry="{{actions}}{{sources}}{{settingsButtons}}{{deinterlaceMode}}{{deinterlaceOrder}}"
|
||||
AdvSceneSwitcher.action.source.warning="警告:OBS UI无法控制全局启用和禁用源,注意,通过这个设置禁用,我测试,你必须通过这个在启用才行,不然点击小眼睛你无法显示!"
|
||||
AdvSceneSwitcher.action.source.getSettings="获取当前设置"
|
||||
AdvSceneSwitcher.action.media="媒体"
|
||||
@@ -437,20 +525,21 @@ 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="取消暂停"
|
||||
AdvSceneSwitcher.action.macro.type.resetCounter="复位计数器"
|
||||
AdvSceneSwitcher.action.macro.type.run="运行"
|
||||
AdvSceneSwitcher.action.macro.type.stop="停止"
|
||||
AdvSceneSwitcher.action.macro.entry="{{actions}} {{macros}}"
|
||||
AdvSceneSwitcher.action.macro.type.run="运行操作"
|
||||
AdvSceneSwitcher.action.macro.type.stop="停止操作"
|
||||
AdvSceneSwitcher.action.macro.entry="{{actions}}{{actionIndex}}{{macros}}"
|
||||
AdvSceneSwitcher.action.pluginState="插件状态"
|
||||
AdvSceneSwitcher.action.pluginState.type.stop="停止高级场景切换插件"
|
||||
AdvSceneSwitcher.action.pluginState.type.noMatch="没有匹配项:"
|
||||
AdvSceneSwitcher.action.pluginState.type.noMatch="没有匹配项时:"
|
||||
AdvSceneSwitcher.action.pluginState.type.import="从设置导入"
|
||||
AdvSceneSwitcher.action.pluginState.importWarning="注意:当“设置”窗口打开时,操作将被忽略。"
|
||||
AdvSceneSwitcher.action.pluginState.type.terminate="关闭 OBS"
|
||||
AdvSceneSwitcher.action.pluginState.terminateConfirm="OBS将在10秒后自动关闭!/n你想继续关闭OBS吗?"
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
|
||||
AdvSceneSwitcher.action.virtualCamera="虚拟摄像机"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.stop="停止虚拟摄像机"
|
||||
@@ -467,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}} for {{duration}}"
|
||||
AdvSceneSwitcher.action.sceneOrder="场景项目顺序"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveUp="上移"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveDown="下移"
|
||||
@@ -475,9 +563,9 @@ AdvSceneSwitcher.action.sceneOrder.type.moveTop="顶部"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveBottom="底部"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.movePosition="移动到数值位置"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="在 {{scenes}} {{actions}} {{sources}} {{position}}"
|
||||
AdvSceneSwitcher.action.sceneTransform="场景项目变换"
|
||||
AdvSceneSwitcher.action.sceneTransform.getTransform="得到变换"
|
||||
AdvSceneSwitcher.action.sceneTransform.entry="在 {{scenes}} 变换 {{sources}}"
|
||||
AdvSceneSwitcher.action.sceneTransform="场景项目转换"
|
||||
AdvSceneSwitcher.action.sceneTransform.getTransform="获得转换"
|
||||
AdvSceneSwitcher.action.sceneTransform.entry="在 {{scenes}}{{action}}{{rotation}}{{sources}}"
|
||||
AdvSceneSwitcher.action.file="文件"
|
||||
AdvSceneSwitcher.action.file.type.write="写入"
|
||||
AdvSceneSwitcher.action.file.type.append="追加写入"
|
||||
@@ -503,9 +591,13 @@ AdvSceneSwitcher.action.timer.type.reset="重置"
|
||||
AdvSceneSwitcher.action.timer.type.setTimeRemaining="设置剩余时间"
|
||||
AdvSceneSwitcher.action.timer.entry="{{timerAction}} 定时在 {{macros}} {{duration}}"
|
||||
AdvSceneSwitcher.action.random="随机"
|
||||
AdvSceneSwitcher.action.random.allowRepeat="允许连续执行同一宏"
|
||||
AdvSceneSwitcher.action.random.entry="随机运行以下任何宏(忽略暂停的宏)"
|
||||
AdvSceneSwitcher.action.systray="系统托盘通知"
|
||||
AdvSceneSwitcher.action.systray.entry="显示通知: {{message}}"
|
||||
AdvSceneSwitcher.action.systray.title="标题:"
|
||||
AdvSceneSwitcher.action.systray.message="信息:"
|
||||
AdvSceneSwitcher.action.systray.icon="图标:"
|
||||
AdvSceneSwitcher.action.systray.iconHint="留空以使用默认图标"
|
||||
AdvSceneSwitcher.action.screenshot="截图"
|
||||
AdvSceneSwitcher.action.screenshot.save.default="默认"
|
||||
AdvSceneSwitcher.action.screenshot.save.custom="其他"
|
||||
@@ -528,21 +620,53 @@ 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="发送场景切换器 {{type}}{{connection}}"
|
||||
AdvSceneSwitcher.action.websocket.entry.event="发送场景切换器 {{type}} 到连接的客户端"
|
||||
AdvSceneSwitcher.action.http="Http"
|
||||
AdvSceneSwitcher.action.http.type.get="GET"
|
||||
AdvSceneSwitcher.action.http.type.post="POST"
|
||||
AdvSceneSwitcher.action.http.setHeaders="设置头信息(SET headers)"
|
||||
AdvSceneSwitcher.action.http.headers="头信息(headers):"
|
||||
AdvSceneSwitcher.action.http.addHeader="增加头信息(ADD headers)"
|
||||
AdvSceneSwitcher.action.http.type.get="获取(GET)"
|
||||
AdvSceneSwitcher.action.http.type.post="发送(POST)"
|
||||
AdvSceneSwitcher.action.http.entry.line1="发送 {{method}} 到 {{url}}"
|
||||
AdvSceneSwitcher.action.http.entry.line2="超时: {{timeout}} 秒"
|
||||
AdvSceneSwitcher.action.variable="变量"
|
||||
AdvSceneSwitcher.action.variable.type.set="设置"
|
||||
AdvSceneSwitcher.action.variable.type.set="设置为固定值"
|
||||
AdvSceneSwitcher.action.variable.type.append="追加"
|
||||
AdvSceneSwitcher.action.variable.type.appendVar="追加变量"
|
||||
AdvSceneSwitcher.action.variable.type.increment="增加"
|
||||
AdvSceneSwitcher.action.variable.type.decrement="减少"
|
||||
AdvSceneSwitcher.action.variable.entry="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}"
|
||||
|
||||
AdvSceneSwitcher.action.variable.type.setActionValue="设置为操作值"
|
||||
AdvSceneSwitcher.action.variable.type.setConditionValue="设置为条件值"
|
||||
AdvSceneSwitcher.action.variable.type.roundToInt="取整到最近的整数"
|
||||
AdvSceneSwitcher.action.variable.type.subString="设置为当前值的子字符串"
|
||||
AdvSceneSwitcher.action.variable.type.findAndReplace="在当前值中查找并替换"
|
||||
AdvSceneSwitcher.action.variable.type.mathExpression="数学表达式"
|
||||
AdvSceneSwitcher.action.variable.mathExpression.example="( 1 + 2 * 3 ) / 4"
|
||||
AdvSceneSwitcher.action.variable.findAndReplace.find="要查找的文本"
|
||||
AdvSceneSwitcher.action.variable.findAndReplace.replace="要替换为的文本"
|
||||
AdvSceneSwitcher.action.variable.subString.begin="开始"
|
||||
AdvSceneSwitcher.action.variable.subString.all="全部"
|
||||
AdvSceneSwitcher.action.variable.invalidSelection="无效选择!"
|
||||
AdvSceneSwitcher.action.variable.actionNoVariableSupport="不支持从 %1 个操作获取变量值!"
|
||||
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="不支持从 %1 条件中获取变量值!"
|
||||
AdvSceneSwitcher.action.variable.currentSegmentValue="当前值:"
|
||||
AdvSceneSwitcher.action.variable.entry.substringIndex="子字符串开始:{{subStringStart}} 子字符串大小:{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.entry.substringRegex="使用正则表达式为 {{regexMatchIdx}} 匹配的值:"
|
||||
AdvSceneSwitcher.action.variable.entry.findAndReplace="{{findStr}}{{replaceStr}}"
|
||||
AdvSceneSwitcher.action.projector="投影仪"
|
||||
AdvSceneSwitcher.action.projector.type.source="源"
|
||||
AdvSceneSwitcher.action.projector.type.scene="场景"
|
||||
AdvSceneSwitcher.action.projector.type.preview="预览"
|
||||
AdvSceneSwitcher.action.projector.type.program="程序"
|
||||
AdvSceneSwitcher.action.projector.type.multiview="多视图"
|
||||
AdvSceneSwitcher.action.projector.display="显示"
|
||||
AdvSceneSwitcher.action.projector.windowed="窗口"
|
||||
AdvSceneSwitcher.action.projector.fullscreen="全屏"
|
||||
AdvSceneSwitcher.action.projector.entry="打开为{{windowTypes}} 的 {{types}}{{scenes}}{{sources}}投影"
|
||||
AdvSceneSwitcher.action.projector.entry.monitor="在 {{monitors}} 上 (从不咕咕的阿坤说:谨慎开启!)"
|
||||
AdvSceneSwitcher.action.midi="MIDI"
|
||||
AdvSceneSwitcher.action.midi.entry="发送消息到 {{device}}:"
|
||||
AdvSceneSwitcher.action.midi.entry.listen="将MIDI消息选择设置为 {{listenDevices}} 上传入的消息: {{listenButton}}"
|
||||
AdvSceneSwitcher.action.osc="打开声音控制"
|
||||
|
||||
; Transition Tab
|
||||
AdvSceneSwitcher.transitionTab.title="转场特效"
|
||||
@@ -601,7 +725,7 @@ AdvSceneSwitcher.mediaTab.states.none="无"
|
||||
AdvSceneSwitcher.mediaTab.states.playing="播放中"
|
||||
AdvSceneSwitcher.mediaTab.states.opening="打开中"
|
||||
AdvSceneSwitcher.mediaTab.states.buffering="缓冲中"
|
||||
AdvSceneSwitcher.mediaTab.states.Paused="暂停"
|
||||
AdvSceneSwitcher.mediaTab.states.paused="暂停"
|
||||
AdvSceneSwitcher.mediaTab.states.stopped="停止"
|
||||
AdvSceneSwitcher.mediaTab.states.ended="结束"
|
||||
AdvSceneSwitcher.mediaTab.states.error="错误"
|
||||
@@ -822,6 +946,7 @@ AdvSceneSwitcher.connection.password="密码:"
|
||||
AdvSceneSwitcher.connection.reconnect="自动重新连接:"
|
||||
AdvSceneSwitcher.connection.reconnectDelay="自动重新连接延迟:"
|
||||
AdvSceneSwitcher.connection.connectOnStart="启动时自动连接:"
|
||||
AdvSceneSwitcher.connection.useOBSWebsocketProtocol="<html><head/><body><p>如何使用 obs-websocket <a href=\"https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md\"><span style=\" text-decoration: underline; color:#268bd2;\">protocol</span></a></p></body></html>"
|
||||
AdvSceneSwitcher.connection.test="测试连接"
|
||||
AdvSceneSwitcher.connection.status.disconnected="断开"
|
||||
AdvSceneSwitcher.connection.status.connecting="连接"
|
||||
@@ -835,6 +960,68 @@ AdvSceneSwitcher.regex.dotMatchNewline=". 匹配换行符"
|
||||
AdvSceneSwitcher.regex.multiLine="^ 和 $ 是匹配行的开始/结束"
|
||||
AdvSceneSwitcher.regex.extendedPattern="启用Qt的扩展模式语法"
|
||||
|
||||
AdvSceneSwitcher.process.showAdvanced="显示高级设置"
|
||||
AdvSceneSwitcher.process.arguments="参数:"
|
||||
AdvSceneSwitcher.process.addArgument="增加参数"
|
||||
AdvSceneSwitcher.process.addArgumentDescription="添加新参数:"
|
||||
AdvSceneSwitcher.process.entry="运行{{filePath}}{{advancedSettings}}"
|
||||
AdvSceneSwitcher.process.entry.workingDirectory="工作目录:{{workingDirectory}}"
|
||||
|
||||
AdvSceneSwitcher.math.expressionFail="计算表达式失败"
|
||||
|
||||
AdvSceneSwitcher.midi.deviceNamePattern="[端口 #%1] %2"
|
||||
AdvSceneSwitcher.midi.message.type="类型:"
|
||||
AdvSceneSwitcher.midi.message.type.optional="任意"
|
||||
AdvSceneSwitcher.midi.message.type.invalid="无效"
|
||||
AdvSceneSwitcher.midi.message.type.noteOff="关闭音符"
|
||||
AdvSceneSwitcher.midi.message.type.noteOn="打开音符"
|
||||
AdvSceneSwitcher.midi.message.type.polyphonicPressure="合成音压力"
|
||||
AdvSceneSwitcher.midi.message.type.controlChange="控制更改"
|
||||
AdvSceneSwitcher.midi.message.type.programChange="程序更改"
|
||||
AdvSceneSwitcher.midi.message.type.channelAftertouch="频道余音"
|
||||
AdvSceneSwitcher.midi.message.type.pitchBend="音高弯曲"
|
||||
AdvSceneSwitcher.midi.message.type.systemExclusive="系统独占"
|
||||
AdvSceneSwitcher.midi.message.type.timeCode="时间码"
|
||||
AdvSceneSwitcher.midi.message.type.songPositionPointer="歌曲位置指针"
|
||||
AdvSceneSwitcher.midi.message.type.songSelect="歌曲选择"
|
||||
AdvSceneSwitcher.midi.message.type.reserved1="保留 (1)"
|
||||
AdvSceneSwitcher.midi.message.type.reserved2="保留 (2)"
|
||||
AdvSceneSwitcher.midi.message.type.tuneRequest="调音请求"
|
||||
AdvSceneSwitcher.midi.message.type.endOfSystemExclusive="系统独占结束"
|
||||
AdvSceneSwitcher.midi.message.type.timeClock="时间时钟"
|
||||
AdvSceneSwitcher.midi.message.type.reserved3="保留 (3)"
|
||||
AdvSceneSwitcher.midi.message.type.startFile="开始文件"
|
||||
AdvSceneSwitcher.midi.message.type.continueFile="继续文件"
|
||||
AdvSceneSwitcher.midi.message.type.stopFile="停止文件"
|
||||
AdvSceneSwitcher.midi.message.type.reserved4="保留 (4)"
|
||||
AdvSceneSwitcher.midi.message.type.activeSensing="主动感应"
|
||||
AdvSceneSwitcher.midi.message.type.systemReset="系统充值"
|
||||
AdvSceneSwitcher.midi.message.type.unknown="未知"
|
||||
AdvSceneSwitcher.midi.message.channel="频道 :"
|
||||
AdvSceneSwitcher.midi.message.note="音符 / 值(1):"
|
||||
AdvSceneSwitcher.midi.message.value="值(2):"
|
||||
AdvSceneSwitcher.midi.message.placeholder="任意"
|
||||
AdvSceneSwitcher.midi.resetDevices="重新连接所有 MIDI 设备"
|
||||
AdvSceneSwitcher.midi.startListen="开始监听"
|
||||
AdvSceneSwitcher.midi.stopListen="停止监听"
|
||||
AdvSceneSwitcher.midi.startListenFail="设备正忙!\n其他设备已经在监听!"
|
||||
AdvSceneSwitcher.midi.deviceOpenFail="初始化 MIDI 设备失败!"
|
||||
|
||||
AdvSceneSwitcher.osc.network="网络"
|
||||
AdvSceneSwitcher.osc.network.protocol="协议:"
|
||||
AdvSceneSwitcher.osc.network.address="地址:"
|
||||
AdvSceneSwitcher.osc.network.port="端口:"
|
||||
AdvSceneSwitcher.osc.message="信息"
|
||||
AdvSceneSwitcher.osc.message.type.none="无"
|
||||
AdvSceneSwitcher.osc.message.type.float="浮点数哦"
|
||||
AdvSceneSwitcher.osc.message.type.int="整数"
|
||||
AdvSceneSwitcher.osc.message.type.string="字符串"
|
||||
AdvSceneSwitcher.osc.message.type.binaryBlob="二进制"
|
||||
AdvSceneSwitcher.osc.message.type.true="真"
|
||||
AdvSceneSwitcher.osc.message.type.false="假"
|
||||
AdvSceneSwitcher.osc.message.type.infinity="无限"
|
||||
AdvSceneSwitcher.osc.message.type.null="无"
|
||||
|
||||
AdvSceneSwitcher.selectScene="--选择场景--"
|
||||
AdvSceneSwitcher.selectPreviousScene="上个场景"
|
||||
AdvSceneSwitcher.selectCurrentScene="当前场景"
|
||||
@@ -844,7 +1031,7 @@ AdvSceneSwitcher.currentTransition="当前转场特效"
|
||||
AdvSceneSwitcher.anyTransition="任何转场特效"
|
||||
AdvSceneSwitcher.selectTransition="--选择转场特效--"
|
||||
AdvSceneSwitcher.selectWindow="--选择窗口--"
|
||||
AdvSceneSwitcher.selectSource="--选择来源--"
|
||||
AdvSceneSwitcher.selectSource="--选择源--"
|
||||
AdvSceneSwitcher.selectAudioSource="--选择音频源--"
|
||||
AdvSceneSwitcher.selectVideoSource="--选择视频源--"
|
||||
AdvSceneSwitcher.OBSVideoOutput="OBS的主要输出"
|
||||
@@ -865,8 +1052,8 @@ AdvSceneSwitcher.sceneItemSelection.any="任何"
|
||||
|
||||
AdvSceneSwitcher.status.active="运行中"
|
||||
AdvSceneSwitcher.status.inactive="已停止"
|
||||
AdvSceneSwitcher.running="插件运行"
|
||||
AdvSceneSwitcher.stopped="插件停止"
|
||||
AdvSceneSwitcher.running="插件正在运行"
|
||||
AdvSceneSwitcher.stopped="插件已停止"
|
||||
|
||||
AdvSceneSwitcher.firstBootMessage="<html><head/><body><p>这似乎是第一次启动高级场景切换程序.<br>请看一下 <a href=\"https://github.com/WarmUpTill/SceneSwitcher/wiki\"><span style=\" text-decoration: underline; color:#268bd2;\">Wiki</span></a> 查看指南和示例列表.<br>如果有问题,在在OBS论坛插件帖子内提问 <a href=\"https://obsproject.com/forum/threads/advanced-scene-switcher.48264\"><span style=\" text-decoration: underline; color:#268bd2;\">thread</span></a></p></body></html>"
|
||||
|
||||
@@ -880,4 +1067,8 @@ AdvSceneSwitcher.duration.condition.none="没有时间限制"
|
||||
AdvSceneSwitcher.duration.condition.more="时间少于"
|
||||
AdvSceneSwitcher.duration.condition.equal="时间等于"
|
||||
AdvSceneSwitcher.duration.condition.less="时间大于"
|
||||
AdvSceneSwitcher.duration.condition.within="保留结果后余存"
|
||||
AdvSceneSwitcher.duration.condition.within="在最后"
|
||||
|
||||
AdvSceneSwitcher.audio.monitor.none="关闭监听"
|
||||
AdvSceneSwitcher.audio.monitor.monitorOnly="仅监听(输出静音)"
|
||||
AdvSceneSwitcher.audio.monitor.both="监听并输出"
|
||||
|
||||
9
data/res/images/DarkDoubleDown.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0"?>
|
||||
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<g class="layer">
|
||||
<title>Layer 1</title>
|
||||
<path d="m1,2c0,-0.27 0.11,-0.52 0.29,-0.71c0.39,-0.39 1.03,-0.39 1.42,0l5.29,5.3l5.29,-5.3c0.39,-0.39 1.03,-0.39 1.42,0c0.18,0.19 0.29,0.44 0.29,0.71s-0.11,0.52 -0.29,0.71l-6,6c-0.39,0.39 -1.03,0.39 -1.42,0l-6,-6c-0.18,-0.19 -0.29,-0.44 -0.29,-0.71zm0,0" fill="#fefefe" id="svg_1" transform="matrix(1, 0, 0, 1, 0, 0)"/>
|
||||
<path d="m1,8c0,-0.27 0.09,-0.52 0.28,-0.71c0.38,-0.39 1.03,-0.39 1.41,0l5.31,5.3l5.28,-5.3c0.38,-0.39 1.03,-0.39 1.41,0c0.19,0.19 0.31,0.44 0.31,0.71s-0.13,0.52 -0.31,0.71l-6,6c-0.38,0.39 -1.03,0.39 -1.41,0l-6,-6c-0.19,-0.19 -0.28,-0.44 -0.28,-0.71zm0,0" fill="#fefefe" id="svg_2"/>
|
||||
</g>
|
||||
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 791 B |
9
data/res/images/DarkDoubleUp.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0"?>
|
||||
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
|
||||
|
||||
<g class="layer">
|
||||
<title>Layer 1</title>
|
||||
<path d="m1,8c0,-0.27 0.11,-0.52 0.29,-0.71l6,-6c0.39,-0.39 1.03,-0.39 1.42,0l6,6c0.18,0.19 0.29,0.44 0.29,0.71s-0.11,0.52 -0.29,0.71c-0.39,0.39 -1.03,0.39 -1.42,0l-5.29,-5.3l-5.29,5.3c-0.39,0.39 -1.03,0.39 -1.42,0c-0.18,-0.19 -0.29,-0.44 -0.29,-0.71zm0,0" fill="#fefefe" id="svg_1"/>
|
||||
<path d="m1,14c0,-0.27 0.11,-0.52 0.28,-0.71l6,-6c0.39,-0.39 1.03,-0.39 1.42,0l6,6c0.19,0.19 0.3,0.44 0.3,0.71s-0.11,0.52 -0.3,0.71c-0.39,0.39 -1.03,0.39 -1.42,0l-5.28,-5.3l-5.3,5.3c-0.39,0.39 -1.03,0.39 -1.42,0c-0.17,-0.19 -0.28,-0.44 -0.28,-0.71zm0,0" fill="#fefefe" id="svg_2"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 753 B |
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 |
24
data/res/images/DarkNote.svg
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0"?>
|
||||
<svg width="640" height="640" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid meet" version="1.1">
|
||||
<defs>
|
||||
<path d="m599.62,325.49c0,151.77 -123.21,274.98 -274.98,274.98c-151.76,0 -274.97,-123.21 -274.97,-274.98c0,-151.76 123.21,-274.97 274.97,-274.97c151.77,0 274.98,123.21 274.98,274.97z" id="c3Wyq0kfYS"/>
|
||||
<mask height="689.95" id="maskanTyyngos" maskUnits="userSpaceOnUse" width="689.95" x="-20.33" y="-19.48">
|
||||
<rect fill="white" height="689.95" id="svg_1" width="689.95" x="-20.33" y="-19.48"/>
|
||||
<use fill="black" id="svg_2" xlink:href="#c3Wyq0kfYS"/>
|
||||
</mask>
|
||||
<path d="m334.97,96.07c4.54,0 8.23,3.68 8.23,8.23c0,46.94 0,179.54 0,226.48c0,4.54 -3.69,8.22 -8.23,8.22c-5.77,0 -14.88,0 -20.66,0c-4.54,0 -8.22,-3.68 -8.22,-8.22c0,-46.94 0,-179.54 0,-226.48c0,-4.55 3.68,-8.23 8.22,-8.23c5.78,0 14.89,0 20.66,0z" id="fxMeu932c"/>
|
||||
<path d="m471.96,338.21c0.01,3.1 -2.5,5.62 -5.59,5.63c-32.02,0.09 -122.45,0.37 -154.46,0.47c-3.1,0.01 -5.61,-2.49 -5.62,-5.59c-0.02,-6.3 -0.06,-19.59 -0.08,-25.89c-0.01,-3.1 2.49,-5.62 5.59,-5.63c32.01,-0.09 122.44,-0.37 154.45,-0.47c3.1,-0.01 5.62,2.5 5.63,5.59c0.02,6.3 0.06,19.59 0.08,25.89z" id="h65nGmP2BL"/>
|
||||
</defs>
|
||||
<g class="layer">
|
||||
<title>Layer 1</title>
|
||||
<path fill="none" fill-opacity="null" id="svg_11" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02"/>
|
||||
<ellipse cx="103.84" cy="562.04" fill="#fefefe" id="svg_3" rx="80" ry="45" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" transform="rotate(-18.699, 103.843, 562.038)"/>
|
||||
<ellipse cx="506" cy="554" fill="#fefefe" id="svg_4" rx="77" ry="45" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" transform="rotate(-18.699, 506, 554)"/>
|
||||
<rect fill="#fefefe" height="359" id="svg_7" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" stroke-width="0" width="58" x="122" y="185"/>
|
||||
<rect fill="#fefefe" height="453" id="svg_8" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" width="58" x="522" y="84.5"/>
|
||||
<rect fill="#fefefe" height="37" id="svg_9" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" transform="rotate(-14.1985, 351.556, 146.245)" width="463.07" x="120.02" y="127.74"/>
|
||||
<rect fill="none" fill-opacity="null" height="0" id="svg_10" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" width="0" x="538.25" y="107.12"/>
|
||||
<path d="m537.42,112.06l0,-67.88l17.58,67.88z" fill="#fefefe" id="svg_16" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" transform="rotate(-90, 546.203, 78.1248)"/>
|
||||
<rect fill="#fefefe" height="0" id="svg_18" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" width="0" x="82.12" y="287.56"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
10
data/res/images/DarkRegex.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<?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>
|
||||
<text fill="#fefefe" font-family="Serif" font-size="24" id="svg_1" stroke="#fefefe" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="0" text-anchor="middle" transform="matrix(1.0974, 0, 0, 1.0974, -4.98544, 4.97639)" x="14" xml:space="preserve" y="13">*</text>
|
||||
<rect fill="#fefefe" height="3.3" id="svg_2" stroke="#fefefe" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" transform="matrix(1, 0, 0, 1, 0, 0)" width="5" x="1" y="12"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 815 B |
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 |
9
data/res/images/LightDoubleDown.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0"?>
|
||||
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<g class="layer">
|
||||
<title>Layer 1</title>
|
||||
<path d="m1,2c0,-0.27 0.11,-0.52 0.29,-0.71c0.39,-0.39 1.03,-0.39 1.42,0l5.29,5.3l5.29,-5.3c0.39,-0.39 1.03,-0.39 1.42,0c0.18,0.19 0.29,0.44 0.29,0.71s-0.11,0.52 -0.29,0.71l-6,6c-0.39,0.39 -1.03,0.39 -1.42,0l-6,-6c-0.18,-0.19 -0.29,-0.44 -0.29,-0.71zm0,0" fill="#202020" id="svg_1"/>
|
||||
<path d="m1,8c0,-0.27 0.11,-0.52 0.29,-0.71c0.39,-0.39 1.03,-0.39 1.42,0l5.29,5.3l5.29,-5.3c0.39,-0.39 1.03,-0.39 1.42,0c0.18,0.19 0.29,0.44 0.29,0.71s-0.11,0.52 -0.29,0.71l-6,6c-0.39,0.39 -1.03,0.39 -1.42,0l-6,-6c-0.18,-0.19 -0.29,-0.44 -0.29,-0.71zm0,0" fill="#202020" id="svg_4" transform="matrix(1, 0, 0, 1, 0, 0)"/>
|
||||
</g>
|
||||
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 791 B |
9
data/res/images/LightDoubleUp.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0"?>
|
||||
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
|
||||
|
||||
<g class="layer">
|
||||
<title>Layer 1</title>
|
||||
<path d="m1,8c0,-0.27 0.11,-0.52 0.29,-0.71l6,-6c0.39,-0.39 1.03,-0.39 1.42,0l6,6c0.18,0.19 0.29,0.44 0.29,0.71s-0.11,0.52 -0.29,0.71c-0.39,0.39 -1.03,0.39 -1.42,0l-5.29,-5.3l-5.29,5.3c-0.39,0.39 -1.03,0.39 -1.42,0c-0.18,-0.19 -0.29,-0.44 -0.29,-0.71zm0,0" fill="#202020" id="svg_1"/>
|
||||
<path d="m1,14c0,-0.27 0.11,-0.52 0.29,-0.71l6,-6c0.39,-0.39 1.03,-0.39 1.42,0l6,6c0.18,0.19 0.29,0.44 0.29,0.71s-0.11,0.52 -0.29,0.71c-0.39,0.39 -1.03,0.39 -1.42,0l-5.29,-5.3l-5.29,5.3c-0.39,0.39 -1.03,0.39 -1.42,0c-0.18,-0.19 -0.29,-0.44 -0.29,-0.71zm0,0" fill="#202020" id="svg_2"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 757 B |
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 |
24
data/res/images/LightNote.svg
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0"?>
|
||||
<svg width="640" height="640" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid meet" version="1.1">
|
||||
<defs>
|
||||
<path d="m599.62,325.49c0,151.77 -123.21,274.98 -274.98,274.98c-151.76,0 -274.97,-123.21 -274.97,-274.98c0,-151.76 123.21,-274.97 274.97,-274.97c151.77,0 274.98,123.21 274.98,274.97z" id="c3Wyq0kfYS"/>
|
||||
<mask height="689.95" id="maskanTyyngos" maskUnits="userSpaceOnUse" width="689.95" x="-20.33" y="-19.48">
|
||||
<rect fill="white" height="689.95" id="svg_1" width="689.95" x="-20.33" y="-19.48"/>
|
||||
<use fill="black" id="svg_2" xlink:href="#c3Wyq0kfYS"/>
|
||||
</mask>
|
||||
<path d="m334.97,96.07c4.54,0 8.23,3.68 8.23,8.23c0,46.94 0,179.54 0,226.48c0,4.54 -3.69,8.22 -8.23,8.22c-5.77,0 -14.88,0 -20.66,0c-4.54,0 -8.22,-3.68 -8.22,-8.22c0,-46.94 0,-179.54 0,-226.48c0,-4.55 3.68,-8.23 8.22,-8.23c5.78,0 14.89,0 20.66,0z" id="fxMeu932c"/>
|
||||
<path d="m471.96,338.21c0.01,3.1 -2.5,5.62 -5.59,5.63c-32.02,0.09 -122.45,0.37 -154.46,0.47c-3.1,0.01 -5.61,-2.49 -5.62,-5.59c-0.02,-6.3 -0.06,-19.59 -0.08,-25.89c-0.01,-3.1 2.49,-5.62 5.59,-5.63c32.01,-0.09 122.44,-0.37 154.45,-0.47c3.1,-0.01 5.62,2.5 5.63,5.59c0.02,6.3 0.06,19.59 0.08,25.89z" id="h65nGmP2BL"/>
|
||||
</defs>
|
||||
<g class="layer">
|
||||
<title>Layer 1</title>
|
||||
<path fill="none" fill-opacity="null" id="svg_11" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02"/>
|
||||
<ellipse cx="103.84" cy="562.04" fill="#202020" id="svg_3" rx="80" ry="45" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" transform="rotate(-18.699, 103.843, 562.038)"/>
|
||||
<ellipse cx="506" cy="554" fill="#202020" id="svg_4" rx="77" ry="45" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" transform="rotate(-18.699, 506, 554)"/>
|
||||
<rect fill="#202020" height="359" id="svg_7" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" stroke-width="0" width="58" x="122" y="185"/>
|
||||
<rect fill="#202020" height="453" id="svg_8" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" width="58" x="522" y="84.5"/>
|
||||
<rect fill="#202020" height="37" id="svg_9" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" transform="rotate(-14.1985, 351.556, 146.245)" width="463.07" x="120.02" y="127.74"/>
|
||||
<rect fill="none" fill-opacity="null" height="0" id="svg_10" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" width="0" x="538.25" y="107.12"/>
|
||||
<path d="m537.42,112.06l0,-67.88l17.58,67.88z" fill="#202020" id="svg_16" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" transform="rotate(-90, 546.203, 78.1248)"/>
|
||||
<rect fill="#202020" height="0" id="svg_18" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" width="0" x="82.12" y="287.56"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
10
data/res/images/LightRegex.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<?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>
|
||||
<text fill="#202020" font-family="Serif" font-size="24" id="svg_1" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="0" text-anchor="middle" transform="matrix(1.0974, 0, 0, 1.0974, -4.98544, 4.97639)" x="14" xml:space="preserve" y="13">*</text>
|
||||
<rect fill="#202020" height="3.3" id="svg_2" stroke="#202020" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" transform="matrix(1, 0, 0, 1, 0, 0)" width="5" x="1" y="12"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 815 B |
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
1
deps/cpp-httplib
vendored
Submodule
41032
deps/exprtk/exprtk.hpp
vendored
Normal file
1
deps/json
vendored
Submodule
1
deps/libremidi
vendored
Submodule
2
deps/websocketpp
vendored
@@ -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,54 @@
|
||||
</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>
|
||||
<widget class="QCheckBox" name="warnPluginLoadFailure">
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.generalTab.generalBehavior.warnPluginLoadFailure</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_19">
|
||||
<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_24">
|
||||
<item>
|
||||
@@ -634,7 +682,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="MacroTree" name="macros">
|
||||
<widget class="advss::MacroTree" name="macros">
|
||||
<property name="showDropIndicator" stdset="0">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
@@ -781,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>
|
||||
@@ -795,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>
|
||||
@@ -888,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">
|
||||
@@ -964,6 +1022,19 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="conditionTop">
|
||||
<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="conditionUp">
|
||||
<property name="maximumSize">
|
||||
@@ -999,6 +1070,19 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="conditionBottom">
|
||||
<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_15">
|
||||
<property name="orientation">
|
||||
@@ -1016,144 +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="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>
|
||||
<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>
|
||||
@@ -4539,10 +4855,21 @@
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>MacroTree</class>
|
||||
<class>advss::MacroTree</class>
|
||||
<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,37 +1,24 @@
|
||||
#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"
|
||||
#include "platform-funcs.hpp"
|
||||
#include "utility.hpp"
|
||||
#include "version.h"
|
||||
|
||||
const char *obs_module_text(const char *text)
|
||||
{
|
||||
if (!switcher) {
|
||||
return "";
|
||||
}
|
||||
return switcher->translate(text);
|
||||
}
|
||||
#include <QMainWindow>
|
||||
#include <QAction>
|
||||
#include <QFileDialog>
|
||||
#include <QTextStream>
|
||||
#include <QDirIterator>
|
||||
#include <regex>
|
||||
#include <filesystem>
|
||||
#include <obs-module.h>
|
||||
#include <obs-frontend-api.h>
|
||||
|
||||
obs_module_t *obs_current_module()
|
||||
{
|
||||
return switcher->modulePtr;
|
||||
}
|
||||
|
||||
SwitcherData *switcher = nullptr;
|
||||
SwitcherData *GetSwitcher()
|
||||
{
|
||||
return switcher;
|
||||
}
|
||||
namespace advss {
|
||||
|
||||
AdvSceneSwitcher *AdvSceneSwitcher::window = nullptr;
|
||||
|
||||
@@ -43,11 +30,9 @@ AdvSceneSwitcher::AdvSceneSwitcher(QWidget *parent)
|
||||
{
|
||||
switcher->settingsWindowOpened = true;
|
||||
ui->setupUi(this);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
switcher->Prune();
|
||||
loadUI();
|
||||
LoadUI();
|
||||
}
|
||||
|
||||
AdvSceneSwitcher::~AdvSceneSwitcher()
|
||||
@@ -58,65 +43,113 @@ AdvSceneSwitcher::~AdvSceneSwitcher()
|
||||
}
|
||||
}
|
||||
|
||||
bool translationAvailable()
|
||||
static bool translationAvailable()
|
||||
{
|
||||
return !!strcmp(obs_module_text("AdvSceneSwitcher.pluginName"),
|
||||
"AdvSceneSwitcher.pluginName");
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::loadUI()
|
||||
static void DisplayMissingDependencyWarning()
|
||||
{
|
||||
if (!translationAvailable()) {
|
||||
QString msg = "Failed to find plug-in's 'data' directory.\n"
|
||||
"Please check installation instructions!\n\n"
|
||||
"Data most likely expected at:\n\n";
|
||||
#ifdef _WIN32
|
||||
msg += QString::fromStdString(
|
||||
(std::filesystem::current_path().string()));
|
||||
msg += "/";
|
||||
#endif
|
||||
msg += obs_get_module_data_path(obs_current_module());
|
||||
(void)DisplayMessage(msg);
|
||||
if (!switcher->warnPluginLoadFailure ||
|
||||
switcher->loadFailureLibs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
setupGeneralTab();
|
||||
setupTitleTab();
|
||||
setupExecutableTab();
|
||||
setupRegionTab();
|
||||
setupPauseTab();
|
||||
setupSequenceTab();
|
||||
setupTransitionsTab();
|
||||
setupIdleTab();
|
||||
setupRandomTab();
|
||||
setupMediaTab();
|
||||
setupFileTab();
|
||||
setupTimeTab();
|
||||
setupAudioTab();
|
||||
setupVideoTab();
|
||||
setupNetworkTab();
|
||||
setupSceneGroupTab();
|
||||
setupTriggerTab();
|
||||
setupMacroTab();
|
||||
QString failedLibsString = "<ul>";
|
||||
for (const auto &lib : switcher->loadFailureLibs) {
|
||||
failedLibsString += "<li>" + lib + "</li>";
|
||||
}
|
||||
failedLibsString += "</ul>";
|
||||
QString warning(obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.warnPluginLoadFailureMessage"));
|
||||
DisplayMessage(warning.arg(failedLibsString));
|
||||
}
|
||||
|
||||
setDeprecationWarnings();
|
||||
setTabOrder();
|
||||
setCurrentTab();
|
||||
restoreWindowGeo();
|
||||
checkFirstTimeSetup();
|
||||
static void DisplayMissingDataDirWarning()
|
||||
{
|
||||
if (translationAvailable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString msg = "Failed to find plug-in's 'data' directory.\n"
|
||||
"Please check installation instructions!\n\n"
|
||||
"Data most likely expected at:\n\n";
|
||||
#ifdef _WIN32
|
||||
msg += QString::fromStdString(
|
||||
(std::filesystem::current_path().string()));
|
||||
msg += "/";
|
||||
#endif
|
||||
msg += obs_get_module_data_path(obs_current_module());
|
||||
DisplayMessage(msg);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::LoadUI()
|
||||
{
|
||||
DisplayMissingDataDirWarning();
|
||||
DisplayMissingDependencyWarning();
|
||||
|
||||
SetupGeneralTab();
|
||||
SetupTitleTab();
|
||||
SetupExecutableTab();
|
||||
SetupRegionTab();
|
||||
SetupPauseTab();
|
||||
SetupSequenceTab();
|
||||
SetupTransitionsTab();
|
||||
SetupIdleTab();
|
||||
SetupRandomTab();
|
||||
SetupMediaTab();
|
||||
SetupFileTab();
|
||||
SetupTimeTab();
|
||||
SetupAudioTab();
|
||||
SetupVideoTab();
|
||||
SetupNetworkTab();
|
||||
SetupSceneGroupTab();
|
||||
SetupTriggerTab();
|
||||
SetupMacroTab();
|
||||
|
||||
SetDeprecationWarnings();
|
||||
SetTabOrder();
|
||||
SetCurrentTab();
|
||||
RestoreWindowGeo();
|
||||
CheckFirstTimeSetup();
|
||||
|
||||
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(const QString &json);
|
||||
|
||||
static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
||||
{
|
||||
if (!switcher) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (saving) {
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->Prune();
|
||||
obs_data_t *obj = obs_data_create();
|
||||
switcher->saveSettings(obj);
|
||||
switcher->SaveSettings(obj);
|
||||
obs_data_set_obj(save_data, "advanced-scene-switcher", obj);
|
||||
obs_data_release(obj);
|
||||
} else {
|
||||
@@ -125,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);
|
||||
if (switcher->VersionChanged(obj, g_GIT_SHA1)) {
|
||||
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->LoadSettings(obj);
|
||||
switcher->m.unlock();
|
||||
|
||||
if (!switcher->stop) {
|
||||
@@ -143,6 +185,34 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
||||
}
|
||||
}
|
||||
|
||||
static void AskForBackup(const QString &json)
|
||||
{
|
||||
const bool backupWasConfirmed = DisplayMessage(
|
||||
obs_module_text("AdvSceneSwitcher.askBackup"), true, false);
|
||||
|
||||
if (!backupWasConfirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString path = QFileDialog::getSaveFileName(
|
||||
nullptr,
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle"),
|
||||
GetDefaultSettingsSaveLocation(),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType"));
|
||||
if (path.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QFile file(path);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
return;
|
||||
}
|
||||
auto out = QTextStream(&file);
|
||||
out << json;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Main switcher thread
|
||||
******************************************************************************/
|
||||
@@ -167,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>(
|
||||
@@ -186,7 +255,7 @@ void SwitcherData::Thread()
|
||||
}
|
||||
|
||||
vblog(LOG_INFO, "try to sleep for %ld", duration.count());
|
||||
setWaitScene();
|
||||
SetWaitScene();
|
||||
cv.wait_for(lock, duration);
|
||||
|
||||
startTime = std::chrono::high_resolution_clock::now();
|
||||
@@ -200,13 +269,13 @@ void SwitcherData::Thread()
|
||||
if (checkPause()) {
|
||||
continue;
|
||||
}
|
||||
setPreconditions();
|
||||
match = checkForMatch(scene, transition, linger,
|
||||
SetPreconditions();
|
||||
match = CheckForMatch(scene, transition, linger,
|
||||
setPrevSceneAfterLinger, macroMatch);
|
||||
if (stop) {
|
||||
break;
|
||||
}
|
||||
checkNoMatchSwitch(match, scene, transition, sleep);
|
||||
CheckNoMatchSwitch(match, scene, transition, sleep);
|
||||
checkSwitchCooldown(match);
|
||||
|
||||
if (linger) {
|
||||
@@ -214,14 +283,14 @@ void SwitcherData::Thread()
|
||||
vblog(LOG_INFO, "sleep for %ld before switching scene",
|
||||
duration.count());
|
||||
|
||||
setWaitScene();
|
||||
SetWaitScene();
|
||||
cv.wait_for(lock, duration);
|
||||
|
||||
if (stop) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (sceneChangedDuringWait()) {
|
||||
if (SceneChangedDuringWait()) {
|
||||
vblog(LOG_INFO,
|
||||
"scene was changed manually - ignoring match");
|
||||
|
||||
@@ -232,13 +301,13 @@ void SwitcherData::Thread()
|
||||
}
|
||||
}
|
||||
|
||||
ClearWebsocketMessages();
|
||||
ResetForNextInterval();
|
||||
|
||||
if (match) {
|
||||
if (macroMatch) {
|
||||
runMacros();
|
||||
RunMacros();
|
||||
} else {
|
||||
switchScene({scene, transition, 0});
|
||||
SwitchScene({scene, transition, 0});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,7 +320,7 @@ void SwitcherData::Thread()
|
||||
blog(LOG_INFO, "stopped");
|
||||
}
|
||||
|
||||
void SwitcherData::setPreconditions()
|
||||
void SwitcherData::SetPreconditions()
|
||||
{
|
||||
// Window title
|
||||
lastTitle = currentTitle;
|
||||
@@ -278,14 +347,19 @@ 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();
|
||||
}
|
||||
|
||||
bool SwitcherData::checkForMatch(OBSWeakSource &scene,
|
||||
void SwitcherData::ResetForNextInterval()
|
||||
{
|
||||
// Plugin reset functions
|
||||
for (const auto &func : resetIntervalSteps) {
|
||||
func();
|
||||
}
|
||||
}
|
||||
|
||||
bool SwitcherData::CheckForMatch(OBSWeakSource &scene,
|
||||
OBSWeakSource &transition, int &linger,
|
||||
bool &setPrevSceneAfterLinger,
|
||||
bool ¯oMatch)
|
||||
@@ -335,7 +409,7 @@ bool SwitcherData::checkForMatch(OBSWeakSource &scene,
|
||||
match = checkVideoSwitch(scene, transition);
|
||||
break;
|
||||
case macro_func:
|
||||
if (checkMacros()) {
|
||||
if (CheckMacros()) {
|
||||
match = true;
|
||||
macroMatch = true;
|
||||
}
|
||||
@@ -352,48 +426,20 @@ bool SwitcherData::checkForMatch(OBSWeakSource &scene,
|
||||
return match;
|
||||
}
|
||||
|
||||
void switchScene(const sceneSwitchInfo &sceneSwitch, bool force)
|
||||
static void ResetMacros()
|
||||
{
|
||||
if (!sceneSwitch.scene && switcher->verbose) {
|
||||
blog(LOG_INFO, "nothing to switch to");
|
||||
return;
|
||||
for (auto &m : GetMacros()) {
|
||||
m->ResetRunCount();
|
||||
m->ResetTimers();
|
||||
}
|
||||
|
||||
obs_source_t *source = obs_weak_source_get_source(sceneSwitch.scene);
|
||||
obs_source_t *currentSource = obs_frontend_get_current_scene();
|
||||
|
||||
if (source && (source != currentSource || force)) {
|
||||
transitionData currentTransitionData;
|
||||
setNextTransition(sceneSwitch, currentSource,
|
||||
currentTransitionData);
|
||||
obs_frontend_set_current_scene(source);
|
||||
if (switcher->transitionOverrideOverride) {
|
||||
restoreTransitionOverride(source,
|
||||
currentTransitionData);
|
||||
}
|
||||
|
||||
if (switcher->verbose) {
|
||||
blog(LOG_INFO, "switched scene");
|
||||
}
|
||||
|
||||
if (switcher->networkConfig.ShouldSendSceneChange()) {
|
||||
switcher->server.sendMessage(sceneSwitch);
|
||||
}
|
||||
}
|
||||
obs_source_release(currentSource);
|
||||
obs_source_release(source);
|
||||
}
|
||||
|
||||
void switchPreviewScene(const OBSWeakSource &ws)
|
||||
{
|
||||
auto source = obs_weak_source_get_source(ws);
|
||||
obs_frontend_set_current_preview_scene(source);
|
||||
obs_source_release(source);
|
||||
}
|
||||
|
||||
void SwitcherData::Start()
|
||||
{
|
||||
if (!(th && th->isRunning())) {
|
||||
ResetForNextInterval();
|
||||
ResetMacros();
|
||||
|
||||
stop = false;
|
||||
th = new SwitcherThread();
|
||||
th->start((QThread::Priority)threadPriority);
|
||||
@@ -418,28 +464,34 @@ void SwitcherData::Start()
|
||||
}
|
||||
}
|
||||
|
||||
void ResetMacros()
|
||||
{
|
||||
for (auto &m : switcher->macros) {
|
||||
m->ResetRunCount();
|
||||
m->ResetTimers();
|
||||
}
|
||||
}
|
||||
bool CloseAllInputDialogs();
|
||||
|
||||
void SwitcherData::Stop()
|
||||
{
|
||||
if (th && th->isRunning()) {
|
||||
stop = true;
|
||||
cv.notify_all();
|
||||
abortMacroWait = true;
|
||||
macroWaitCv.notify_all();
|
||||
macroTransitionCv.notify_all();
|
||||
th->wait();
|
||||
delete th;
|
||||
th = nullptr;
|
||||
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()
|
||||
// is called.
|
||||
//
|
||||
// The QEventLoop handling the dialog would not exit until Stop()
|
||||
// would return, which itself would wait for the switcher thread
|
||||
// to complete, which itself is blocked by the variable input
|
||||
// dialog.
|
||||
//
|
||||
// Must be reworked in the future, as this will not go well when
|
||||
// OBS is shutting down and a dialog is still opened.
|
||||
if (!CloseAllInputDialogs()) {
|
||||
th->wait();
|
||||
delete th;
|
||||
th = nullptr;
|
||||
}
|
||||
writeToStatusFile("Advanced Scene Switcher stopped");
|
||||
ResetMacros();
|
||||
}
|
||||
|
||||
server.stop();
|
||||
@@ -452,13 +504,13 @@ void SwitcherData::Stop()
|
||||
}
|
||||
}
|
||||
|
||||
void SwitcherData::setWaitScene()
|
||||
void SwitcherData::SetWaitScene()
|
||||
{
|
||||
waitScene = obs_frontend_get_current_scene();
|
||||
obs_source_release(waitScene);
|
||||
}
|
||||
|
||||
bool SwitcherData::sceneChangedDuringWait()
|
||||
bool SwitcherData::SceneChangedDuringWait()
|
||||
{
|
||||
obs_source_t *currentSource = obs_frontend_get_current_scene();
|
||||
if (!currentSource) {
|
||||
@@ -471,7 +523,7 @@ bool SwitcherData::sceneChangedDuringWait()
|
||||
// Relies on the fact that switcher->currentScene will only be updated on event
|
||||
// OBS_FRONTEND_EVENT_SCENE_CHANGED but obs_frontend_get_current_scene() will
|
||||
// already return the scene to be transitioned to.
|
||||
bool SwitcherData::anySceneTransitionStarted()
|
||||
bool SwitcherData::AnySceneTransitionStarted()
|
||||
{
|
||||
auto currentSceneSrouce = obs_frontend_get_current_scene();
|
||||
auto currentScene = obs_source_get_weak_source(currentSceneSrouce);
|
||||
@@ -492,13 +544,10 @@ extern "C" void FreeSceneSwitcher()
|
||||
switcher = nullptr;
|
||||
}
|
||||
|
||||
void handleSceneChange()
|
||||
static void handleSceneChange()
|
||||
{
|
||||
switcher->lastSceneChangeTime =
|
||||
std::chrono::high_resolution_clock::now();
|
||||
|
||||
// Stop waiting if scene was changed
|
||||
if (switcher->sceneChangedDuringWait()) {
|
||||
if (switcher->SceneChangedDuringWait()) {
|
||||
switcher->cv.notify_one();
|
||||
}
|
||||
|
||||
@@ -526,31 +575,33 @@ void handleSceneChange()
|
||||
}
|
||||
}
|
||||
|
||||
void setLiveTime()
|
||||
static void setLiveTime()
|
||||
{
|
||||
switcher->liveTime = QDateTime::currentDateTime();
|
||||
}
|
||||
|
||||
void resetLiveTime()
|
||||
static void resetLiveTime()
|
||||
{
|
||||
switcher->liveTime = QDateTime();
|
||||
}
|
||||
|
||||
void checkAutoStartRecording()
|
||||
static void checkAutoStartRecording()
|
||||
{
|
||||
if (switcher->autoStartEvent == AutoStartEvent::RECORDING ||
|
||||
switcher->autoStartEvent == AutoStartEvent::RECORINDG_OR_STREAMING)
|
||||
if (switcher->autoStartEvent == SwitcherData::AutoStart::RECORDING ||
|
||||
switcher->autoStartEvent ==
|
||||
SwitcherData::AutoStart::RECORINDG_OR_STREAMING)
|
||||
switcher->Start();
|
||||
}
|
||||
|
||||
void checkAutoStartStreaming()
|
||||
static void checkAutoStartStreaming()
|
||||
{
|
||||
if (switcher->autoStartEvent == AutoStartEvent::STREAMING ||
|
||||
switcher->autoStartEvent == AutoStartEvent::RECORINDG_OR_STREAMING)
|
||||
if (switcher->autoStartEvent == SwitcherData::AutoStart::STREAMING ||
|
||||
switcher->autoStartEvent ==
|
||||
SwitcherData::AutoStart::RECORINDG_OR_STREAMING)
|
||||
switcher->Start();
|
||||
}
|
||||
|
||||
void handlePeviewSceneChange()
|
||||
static void handlePeviewSceneChange()
|
||||
{
|
||||
if (switcher->networkConfig.ShouldSendPrviewSceneChange()) {
|
||||
auto source = obs_frontend_get_current_preview_scene();
|
||||
@@ -561,43 +612,32 @@ void handlePeviewSceneChange()
|
||||
}
|
||||
}
|
||||
|
||||
void setReplayBufferSaved()
|
||||
static void handleTransitionEnd()
|
||||
{
|
||||
switcher->replayBufferSaved = true;
|
||||
GetMacroTransitionCV().notify_all();
|
||||
}
|
||||
|
||||
void setTranstionEnd()
|
||||
static void handleShutdown()
|
||||
{
|
||||
switcher->lastTransitionEndTime =
|
||||
std::chrono::high_resolution_clock::now();
|
||||
switcher->macroTransitionCv.notify_all();
|
||||
}
|
||||
|
||||
void setStreamStarting()
|
||||
{
|
||||
switcher->lastStreamStartingTime =
|
||||
std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
void setStreamStopping()
|
||||
{
|
||||
switcher->lastStreamStoppingTime =
|
||||
std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
void handleExit()
|
||||
{
|
||||
switcher->obsIsShuttingDown = true;
|
||||
if (switcher && switcher->obsIsShuttingDown &&
|
||||
switcher->shutdownConditionCount) {
|
||||
switcher->Stop();
|
||||
switcher->checkMacros();
|
||||
switcher->runMacros();
|
||||
if (!switcher) {
|
||||
return;
|
||||
}
|
||||
switcher->obsIsShuttingDown = true;
|
||||
if (ShutdownCheckIsNecessary()) {
|
||||
switcher->Stop();
|
||||
CheckMacros();
|
||||
RunMacros();
|
||||
|
||||
// Unfortunately this will not work as OBS will now allow saving
|
||||
// the scene collection data at this point, So any OBS specific
|
||||
// changes done during shutdown will be lost
|
||||
//
|
||||
// TODO: Look for a way to possibly resolve this
|
||||
obs_frontend_save();
|
||||
}
|
||||
FreeSceneSwitcher();
|
||||
}
|
||||
|
||||
void handleSceneCollectionChanging()
|
||||
static void handleSceneCollectionChanging()
|
||||
{
|
||||
if (switcher->settingsWindowOpened) {
|
||||
AdvSceneSwitcher::window->close();
|
||||
@@ -618,8 +658,12 @@ static void OBSEvent(enum obs_frontend_event event, void *switcher)
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
case OBS_FRONTEND_EVENT_EXIT:
|
||||
handleExit();
|
||||
case OBS_FRONTEND_EVENT_SCRIPTING_SHUTDOWN:
|
||||
// Note: We are intentionally not listening for
|
||||
// OBS_FRONTEND_EVENT_EXIT here as at that point all scene
|
||||
// collection data will already have been cleared and thus all
|
||||
// macros will have already been cleared
|
||||
handleShutdown();
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_SCENE_CHANGED:
|
||||
handleSceneChange();
|
||||
@@ -639,31 +683,23 @@ 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:
|
||||
handleSceneCollectionChanging();
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_SCENE_COLLECTION_CLEANUP:
|
||||
SaveSceneSwitcher(nullptr, false, nullptr);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void LoadPlugins()
|
||||
static void LoadPlugins()
|
||||
{
|
||||
QFileInfo libPath(
|
||||
QString(obs_get_module_binary_path(obs_current_module())));
|
||||
@@ -687,6 +723,7 @@ void LoadPlugins()
|
||||
blog(LOG_WARNING, "failed to load \"%s\": %s",
|
||||
file.toStdString().c_str(),
|
||||
lib->errorString().toStdString().c_str());
|
||||
switcher->loadFailureLibs << file;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -706,18 +743,21 @@ void OpenSettingsWindow()
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void InitSceneSwitcher(obs_module_t *m, translateFunc t)
|
||||
void SetupConnectionManager();
|
||||
void SetupWebsocketHelpers();
|
||||
|
||||
extern "C" void InitSceneSwitcher(obs_module_t *module, translateFunc translate)
|
||||
{
|
||||
blog(LOG_INFO, "version: %s", g_GIT_TAG);
|
||||
blog(LOG_INFO, "version: %s", g_GIT_SHA1);
|
||||
|
||||
switcher = new SwitcherData;
|
||||
switcher->modulePtr = m;
|
||||
switcher->translate = t;
|
||||
switcher = new SwitcherData(module, translate);
|
||||
|
||||
PlatformInit();
|
||||
LoadPlugins();
|
||||
SetupDock();
|
||||
SetupConnectionManager();
|
||||
SetupWebsocketHelpers();
|
||||
|
||||
obs_frontend_add_save_callback(SaveSceneSwitcher, nullptr);
|
||||
obs_frontend_add_event_callback(OBSEvent, switcher);
|
||||
@@ -726,3 +766,5 @@ extern "C" void InitSceneSwitcher(obs_module_t *m, translateFunc t)
|
||||
obs_module_text("AdvSceneSwitcher.pluginName"));
|
||||
action->connect(action, &QAction::triggered, OpenSettingsWindow);
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
#pragma once
|
||||
#include "switcher-data-structs.hpp"
|
||||
#include "platform-funcs.hpp"
|
||||
#include "macro-segment-list.hpp"
|
||||
#include "log-helper.hpp"
|
||||
|
||||
#include <macro-segment-list.hpp>
|
||||
#include <ui_advanced-scene-switcher.h>
|
||||
|
||||
#define blog(level, msg, ...) blog(level, "[adv-ss] " msg, ##__VA_ARGS__)
|
||||
#define vblog(level, msg, ...) \
|
||||
if (switcher->verbose) { \
|
||||
blog(level, msg, ##__VA_ARGS__); \
|
||||
}
|
||||
|
||||
class QCloseEvent;
|
||||
|
||||
namespace advss {
|
||||
|
||||
class MacroActionEdit;
|
||||
class MacroConditionEdit;
|
||||
class Duration;
|
||||
class SequenceWidget;
|
||||
struct SceneGroup;
|
||||
|
||||
/*******************************************************************************
|
||||
* Advanced Scene Switcher window
|
||||
@@ -33,82 +32,23 @@ public:
|
||||
void reject() override;
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
|
||||
void SetShowFrames();
|
||||
void SetHideFrames();
|
||||
void clearFrames(QListWidget *list);
|
||||
void LoadUI();
|
||||
|
||||
int IgnoreWindowsFindByData(const QString &window);
|
||||
int IgnoreIdleWindowsFindByData(const QString &window);
|
||||
void SetTabOrder();
|
||||
void SetCurrentTab();
|
||||
void RestoreWindowGeo();
|
||||
void CheckFirstTimeSetup();
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
|
||||
/* --- Begin of general tab section --- */
|
||||
public:
|
||||
void SetupGeneralTab();
|
||||
void UpdateNonMatchingScene(const QString &name);
|
||||
void OpenSequenceExtendEdit(SequenceWidget *sw);
|
||||
void SetEditSceneGroup(SceneGroup &sg);
|
||||
|
||||
bool addNewMacro(std::shared_ptr<Macro> &res, std::string &name,
|
||||
std::string format = "");
|
||||
void RemoveMacro(std::shared_ptr<Macro> &);
|
||||
void RenameMacro(std::shared_ptr<Macro> &, const QString &name);
|
||||
std::shared_ptr<Macro> getSelectedMacro();
|
||||
std::vector<std::shared_ptr<Macro>> getSelectedMacros();
|
||||
void SetEditMacro(Macro &m);
|
||||
void SetMacroEditAreaDisabled(bool);
|
||||
void HighlightAction(int idx, QColor color = QColor(Qt::green));
|
||||
void HighlightCondition(int idx, QColor color = QColor(Qt::green));
|
||||
void PopulateMacroActions(Macro &m, uint32_t afterIdx = 0);
|
||||
void PopulateMacroConditions(Macro &m, uint32_t afterIdx = 0);
|
||||
void SetActionData(Macro &m);
|
||||
void SetConditionData(Macro &m);
|
||||
void SwapActions(Macro *m, int pos1, int pos2);
|
||||
void SwapConditions(Macro *m, int pos1, int pos2);
|
||||
|
||||
void loadUI();
|
||||
void setupGeneralTab();
|
||||
void setupTitleTab();
|
||||
void setupExecutableTab();
|
||||
void setupRegionTab();
|
||||
void setupPauseTab();
|
||||
void setupSequenceTab();
|
||||
void setupTransitionsTab();
|
||||
void setupIdleTab();
|
||||
void setupRandomTab();
|
||||
void setupMediaTab();
|
||||
void setupFileTab();
|
||||
void setupTimeTab();
|
||||
void setupAudioTab();
|
||||
void setupSceneGroupTab();
|
||||
void setupTriggerTab();
|
||||
void setupVideoTab();
|
||||
void setupNetworkTab();
|
||||
void setupMacroTab();
|
||||
void setDeprecationWarnings();
|
||||
void setTabOrder();
|
||||
void setCurrentTab();
|
||||
void restoreWindowGeo();
|
||||
void checkFirstTimeSetup();
|
||||
|
||||
signals:
|
||||
void MacroAdded(const QString &name);
|
||||
void MacroRemoved(const QString &name);
|
||||
void MacroRenamed(const QString &oldName, const QString &newName);
|
||||
void MacroSegmentOrderChanged();
|
||||
void HighlightMacrosChanged(bool value);
|
||||
void HighlightActionsChanged(bool value);
|
||||
void HighlightConditionsChanged(bool value);
|
||||
void SceneGroupAdded(const QString &name);
|
||||
void SceneGroupRemoved(const QString &name);
|
||||
void SceneGroupRenamed(const QString &oldName, const QString newName);
|
||||
void ConnectionAdded(const QString &);
|
||||
void ConnectionRenamed(const QString &oldName, const QString &newName);
|
||||
void ConnectionRemoved(const QString &);
|
||||
void VariableAdded(const QString &);
|
||||
void VariableRenamed(const QString &oldName, const QString &newName);
|
||||
void VariableRemoved(const QString &);
|
||||
void SetDeprecationWarnings();
|
||||
|
||||
public slots:
|
||||
void on_windowUp_clicked();
|
||||
void on_windowDown_clicked();
|
||||
void on_windowAdd_clicked();
|
||||
void on_windowRemove_clicked();
|
||||
void on_noMatchDontSwitch_clicked();
|
||||
void on_noMatchSwitch_clicked();
|
||||
void on_noMatchRandomSwitch_clicked();
|
||||
@@ -120,45 +60,111 @@ public slots:
|
||||
void on_checkInterval_valueChanged(int value);
|
||||
void on_tabMoved(int from, int to);
|
||||
void on_tabWidget_currentChanged(int index);
|
||||
void on_exportSettings_clicked();
|
||||
void on_importSettings_clicked();
|
||||
void on_verboseLogging_stateChanged(int state);
|
||||
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();
|
||||
void on_priorityDown_clicked();
|
||||
void on_threadPriority_currentTextChanged(const QString &text);
|
||||
|
||||
/* --- End of legacy tab section --- */
|
||||
|
||||
/* --- Begin of macro tab section --- */
|
||||
public:
|
||||
void SetupMacroTab();
|
||||
bool AddNewMacro(std::shared_ptr<Macro> &res, std::string &name,
|
||||
std::string format = "");
|
||||
void RemoveMacro(std::shared_ptr<Macro> &);
|
||||
void RenameMacro(std::shared_ptr<Macro> &, const QString &name);
|
||||
std::shared_ptr<Macro> GetSelectedMacro();
|
||||
std::vector<std::shared_ptr<Macro>> GetSelectedMacros();
|
||||
void SetEditMacro(Macro &m);
|
||||
void SetMacroEditAreaDisabled(bool);
|
||||
void HighlightAction(int idx, QColor color = QColor(Qt::green));
|
||||
void HighlightElseAction(int idx, QColor color = QColor(Qt::green));
|
||||
void HighlightCondition(int idx, QColor color = QColor(Qt::green));
|
||||
void PopulateMacroActions(Macro &m, uint32_t afterIdx = 0);
|
||||
void PopulateMacroElseActions(Macro &m, uint32_t afterIdx = 0);
|
||||
void PopulateMacroConditions(Macro &m, uint32_t afterIdx = 0);
|
||||
void SetActionData(Macro &m);
|
||||
void SetElseActionData(Macro &m);
|
||||
void SetConditionData(Macro &m);
|
||||
void SwapActions(Macro *m, int pos1, int pos2);
|
||||
void SwapConditions(Macro *m, int pos1, int pos2);
|
||||
|
||||
public slots:
|
||||
void on_macroAdd_clicked();
|
||||
void on_macroRemove_clicked();
|
||||
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();
|
||||
void on_conditionRemove_clicked();
|
||||
void on_conditionTop_clicked();
|
||||
void on_conditionUp_clicked();
|
||||
void on_conditionDown_clicked();
|
||||
void on_conditionBottom_clicked();
|
||||
void on_actionAdd_clicked();
|
||||
void on_actionRemove_clicked();
|
||||
void on_actionTop_clicked();
|
||||
void on_actionUp_clicked();
|
||||
void on_actionDown_clicked();
|
||||
void MacroSelectionChanged(const QItemSelection &,
|
||||
const QItemSelection &);
|
||||
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);
|
||||
@@ -173,22 +179,84 @@ public slots:
|
||||
void HighlightOnChange();
|
||||
void on_macroProperties_clicked();
|
||||
|
||||
signals:
|
||||
void MacroAdded(const QString &name);
|
||||
void MacroRemoved(const QString &name);
|
||||
void MacroRenamed(const QString &oldName, const QString &newName);
|
||||
void MacroSegmentOrderChanged();
|
||||
void SegmentTempVarsChanged();
|
||||
void HighlightMacrosChanged(bool value);
|
||||
void HighlightActionsChanged(bool value);
|
||||
void HighlightElseActionsChanged(bool value);
|
||||
void HighlightConditionsChanged(bool value);
|
||||
|
||||
void ConnectionAdded(const QString &);
|
||||
void ConnectionRenamed(const QString &oldName, const QString &newName);
|
||||
void ConnectionRemoved(const QString &);
|
||||
void VariableAdded(const QString &);
|
||||
void VariableRenamed(const QString &oldName, const QString &newName);
|
||||
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();
|
||||
|
||||
MacroSection lastInteracted = MacroSection::CONDITIONS;
|
||||
int currentConditionIdx = -1;
|
||||
int currentActionIdx = -1;
|
||||
int currentElseActionIdx = -1;
|
||||
|
||||
/* --- End of macro tab section --- */
|
||||
|
||||
/* --- Begin of legacy tab section --- */
|
||||
public:
|
||||
void ClearFrames(QListWidget *list);
|
||||
int IgnoreWindowsFindByData(const QString &window);
|
||||
int IgnoreIdleWindowsFindByData(const QString &window);
|
||||
void OpenSequenceExtendEdit(SequenceWidget *sw);
|
||||
|
||||
// Window tab
|
||||
public:
|
||||
void SetupTitleTab();
|
||||
public slots:
|
||||
void on_windowUp_clicked();
|
||||
void on_windowDown_clicked();
|
||||
void on_windowAdd_clicked();
|
||||
void on_windowRemove_clicked();
|
||||
void on_ignoreWindows_currentRowChanged(int idx);
|
||||
void on_ignoreWindowsAdd_clicked();
|
||||
void on_ignoreWindowsRemove_clicked();
|
||||
|
||||
// Screen region tab
|
||||
public:
|
||||
void SetupRegionTab();
|
||||
public slots:
|
||||
void SetShowFrames();
|
||||
void SetHideFrames();
|
||||
void on_screenRegionSwitches_currentRowChanged(int idx);
|
||||
void on_showFrame_clicked();
|
||||
void on_screenRegionAdd_clicked();
|
||||
void on_screenRegionRemove_clicked();
|
||||
void on_screenRegionUp_clicked();
|
||||
void on_screenRegionDown_clicked();
|
||||
void updateScreenRegionCursorPos();
|
||||
|
||||
// Pause tab
|
||||
public:
|
||||
void SetupPauseTab();
|
||||
public slots:
|
||||
void on_pauseUp_clicked();
|
||||
void on_pauseDown_clicked();
|
||||
void on_pauseAdd_clicked();
|
||||
void on_pauseRemove_clicked();
|
||||
|
||||
void on_ignoreWindows_currentRowChanged(int idx);
|
||||
void on_ignoreWindowsAdd_clicked();
|
||||
void on_ignoreWindowsRemove_clicked();
|
||||
|
||||
// Sequence tab
|
||||
public:
|
||||
void SetupSequenceTab();
|
||||
public slots:
|
||||
void on_sceneSequenceAdd_clicked();
|
||||
void on_sceneSequenceRemove_clicked();
|
||||
void on_sceneSequenceUp_clicked();
|
||||
@@ -198,15 +266,10 @@ public slots:
|
||||
void on_sequenceEdit_clicked();
|
||||
void on_sceneSequenceSwitches_itemDoubleClicked(QListWidgetItem *item);
|
||||
|
||||
void on_verboseLogging_stateChanged(int state);
|
||||
void on_saveWindowGeo_stateChanged(int state);
|
||||
void on_showTrayNotifications_stateChanged(int state);
|
||||
void on_uiHintsDisable_stateChanged(int state);
|
||||
void on_hideLegacyTabs_stateChanged(int state);
|
||||
|
||||
void on_exportSettings_clicked();
|
||||
void on_importSettings_clicked();
|
||||
|
||||
// Transition tab
|
||||
public:
|
||||
void SetupTransitionsTab();
|
||||
public slots:
|
||||
void on_transitionsAdd_clicked();
|
||||
void on_transitionsRemove_clicked();
|
||||
void on_transitionsUp_clicked();
|
||||
@@ -217,60 +280,95 @@ public slots:
|
||||
void on_defaultTransitionsDown_clicked();
|
||||
void on_transitionOverridecheckBox_stateChanged(int state);
|
||||
void on_adjustActiveTransitionType_stateChanged(int state);
|
||||
void defTransitionDelayValueChanged(int value);
|
||||
void DefTransitionDelayValueChanged(int value);
|
||||
|
||||
// Executable tab
|
||||
public:
|
||||
void SetupExecutableTab();
|
||||
public slots:
|
||||
void on_executableUp_clicked();
|
||||
void on_executableDown_clicked();
|
||||
void on_executableAdd_clicked();
|
||||
void on_executableRemove_clicked();
|
||||
|
||||
// Idle tab
|
||||
public:
|
||||
void SetupIdleTab();
|
||||
public slots:
|
||||
void on_idleCheckBox_stateChanged(int state);
|
||||
void on_ignoreIdleWindows_currentRowChanged(int idx);
|
||||
void on_ignoreIdleAdd_clicked();
|
||||
void on_ignoreIdleRemove_clicked();
|
||||
|
||||
// Random tab
|
||||
public:
|
||||
void SetupRandomTab();
|
||||
public slots:
|
||||
void on_randomAdd_clicked();
|
||||
void on_randomRemove_clicked();
|
||||
|
||||
// File tab
|
||||
public:
|
||||
void SetupFileTab();
|
||||
public slots:
|
||||
void on_fileAdd_clicked();
|
||||
void on_fileRemove_clicked();
|
||||
void on_fileSwitches_currentRowChanged(int idx);
|
||||
void on_fileUp_clicked();
|
||||
void on_fileDown_clicked();
|
||||
void on_browseButton_clicked();
|
||||
void on_readFileCheckBox_stateChanged(int state);
|
||||
void on_readPathLineEdit_textChanged(const QString &text);
|
||||
void on_writePathLineEdit_textChanged(const QString &text);
|
||||
void on_browseButton_2_clicked();
|
||||
|
||||
void on_executableUp_clicked();
|
||||
void on_executableDown_clicked();
|
||||
void on_executableAdd_clicked();
|
||||
void on_executableRemove_clicked();
|
||||
|
||||
void on_idleCheckBox_stateChanged(int state);
|
||||
void on_ignoreIdleWindows_currentRowChanged(int idx);
|
||||
void on_ignoreIdleAdd_clicked();
|
||||
void on_ignoreIdleRemove_clicked();
|
||||
|
||||
void on_randomAdd_clicked();
|
||||
void on_randomRemove_clicked();
|
||||
|
||||
void on_fileAdd_clicked();
|
||||
void on_fileRemove_clicked();
|
||||
void on_fileSwitches_currentRowChanged(int idx);
|
||||
void on_fileUp_clicked();
|
||||
void on_fileDown_clicked();
|
||||
|
||||
// Media tab
|
||||
public:
|
||||
void SetupMediaTab();
|
||||
public slots:
|
||||
void on_mediaAdd_clicked();
|
||||
void on_mediaRemove_clicked();
|
||||
void on_mediaUp_clicked();
|
||||
void on_mediaDown_clicked();
|
||||
|
||||
// Time tab
|
||||
public:
|
||||
void SetupTimeTab();
|
||||
public slots:
|
||||
void on_timeAdd_clicked();
|
||||
void on_timeRemove_clicked();
|
||||
void on_timeUp_clicked();
|
||||
void on_timeDown_clicked();
|
||||
|
||||
// Audio tab
|
||||
public:
|
||||
void SetupAudioTab();
|
||||
public slots:
|
||||
void on_audioAdd_clicked();
|
||||
void on_audioRemove_clicked();
|
||||
void on_audioUp_clicked();
|
||||
void on_audioDown_clicked();
|
||||
void on_audioFallback_toggled(bool on);
|
||||
|
||||
// Video tab
|
||||
public:
|
||||
void SetupVideoTab();
|
||||
public slots:
|
||||
void on_videoAdd_clicked();
|
||||
void on_videoRemove_clicked();
|
||||
void on_videoUp_clicked();
|
||||
void on_videoDown_clicked();
|
||||
void on_getScreenshot_clicked();
|
||||
|
||||
// Scene group tab
|
||||
public:
|
||||
void SetupNetworkTab();
|
||||
public slots:
|
||||
void on_serverSettings_toggled(bool on);
|
||||
void on_serverPort_valueChanged(int value);
|
||||
void on_lockToIPv4_stateChanged(int state);
|
||||
void on_serverRestart_clicked();
|
||||
void updateServerStatus();
|
||||
void UpdateServerStatus();
|
||||
void on_clientSettings_toggled(bool on);
|
||||
void on_clientHostname_textChanged(const QString &text);
|
||||
void on_clientPort_valueChanged(int value);
|
||||
@@ -278,67 +376,41 @@ public slots:
|
||||
void on_restrictSend_stateChanged(int state);
|
||||
void on_sendPreview_stateChanged(int state);
|
||||
void on_clientReconnect_clicked();
|
||||
void updateClientStatus();
|
||||
void UpdateClientStatus();
|
||||
|
||||
// Scene group tab
|
||||
public:
|
||||
void SetupSceneGroupTab();
|
||||
void SetEditSceneGroup(SceneGroup &sg);
|
||||
public slots:
|
||||
void on_sceneGroupAdd_clicked();
|
||||
void on_sceneGroupRemove_clicked();
|
||||
void on_sceneGroupUp_clicked();
|
||||
void on_sceneGroupDown_clicked();
|
||||
void on_sceneGroupName_editingFinished();
|
||||
void on_sceneGroups_currentRowChanged(int idx);
|
||||
|
||||
void on_sceneGroupSceneAdd_clicked();
|
||||
void on_sceneGroupSceneRemove_clicked();
|
||||
void on_sceneGroupSceneUp_clicked();
|
||||
void on_sceneGroupSceneDown_clicked();
|
||||
|
||||
signals:
|
||||
void SceneGroupAdded(const QString &name);
|
||||
void SceneGroupRemoved(const QString &name);
|
||||
void SceneGroupRenamed(const QString &oldName, const QString newName);
|
||||
|
||||
// Trigger tab
|
||||
public:
|
||||
void SetupTriggerTab();
|
||||
public slots:
|
||||
void on_triggerAdd_clicked();
|
||||
void on_triggerRemove_clicked();
|
||||
void on_triggerUp_clicked();
|
||||
void on_triggerDown_clicked();
|
||||
|
||||
void on_priorityUp_clicked();
|
||||
void on_priorityDown_clicked();
|
||||
void on_threadPriority_currentTextChanged(const QString &text);
|
||||
|
||||
void updateScreenRegionCursorPos();
|
||||
|
||||
private:
|
||||
bool MacroTabIsInFocus();
|
||||
|
||||
MacroSegmentList *conditionsList = nullptr;
|
||||
MacroSegmentList *actionsList = nullptr;
|
||||
|
||||
enum class MacroSection {
|
||||
CONDITIONS,
|
||||
ACTIONS,
|
||||
};
|
||||
MacroSection lastInteracted = MacroSection::CONDITIONS;
|
||||
int currentConditionIdx = -1;
|
||||
int currentActionIdx = -1;
|
||||
/* --- End of legacy tab section --- */
|
||||
};
|
||||
|
||||
void OpenSettingsWindow();
|
||||
|
||||
/******************************************************************************
|
||||
* Sceneswitch helper
|
||||
******************************************************************************/
|
||||
void setNextTransition(const sceneSwitchInfo &ssi, obs_source_t *currentSource,
|
||||
transitionData &td);
|
||||
void overwriteTransitionOverride(const sceneSwitchInfo &ssi,
|
||||
transitionData &td);
|
||||
void restoreTransitionOverride(obs_source_t *scene, const transitionData &td);
|
||||
void switchScene(const sceneSwitchInfo &ssi, bool force = false);
|
||||
void switchPreviewScene(const OBSWeakSource &ws);
|
||||
|
||||
/******************************************************************************
|
||||
* Settings helper
|
||||
******************************************************************************/
|
||||
void AskForBackup(obs_data_t *obj);
|
||||
|
||||
/******************************************************************************
|
||||
* Main SwitcherData
|
||||
******************************************************************************/
|
||||
struct SwitcherData;
|
||||
extern SwitcherData *switcher;
|
||||
SwitcherData *GetSwitcher();
|
||||
} // namespace advss
|
||||
|
||||
475
src/general.cpp
@@ -1,11 +1,15 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#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"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QStandardPaths>
|
||||
|
||||
namespace advss {
|
||||
|
||||
void AdvSceneSwitcher::reject()
|
||||
{
|
||||
@@ -30,7 +34,7 @@ void AdvSceneSwitcher::on_noMatchDontSwitch_clicked()
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->switchIfNotMatching = NO_SWITCH;
|
||||
switcher->switchIfNotMatching = NoMatchBehavior::NO_SWITCH;
|
||||
ui->noMatchSwitchScene->setEnabled(false);
|
||||
ui->randomDisabledWarning->setVisible(true);
|
||||
}
|
||||
@@ -42,7 +46,7 @@ void AdvSceneSwitcher::on_noMatchSwitch_clicked()
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->switchIfNotMatching = SWITCH;
|
||||
switcher->switchIfNotMatching = NoMatchBehavior::SWITCH;
|
||||
ui->noMatchSwitchScene->setEnabled(true);
|
||||
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
|
||||
ui->randomDisabledWarning->setVisible(true);
|
||||
@@ -55,7 +59,7 @@ void AdvSceneSwitcher::on_noMatchRandomSwitch_clicked()
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->switchIfNotMatching = RANDOM_SWITCH;
|
||||
switcher->switchIfNotMatching = NoMatchBehavior::RANDOM_SWITCH;
|
||||
ui->noMatchSwitchScene->setEnabled(false);
|
||||
ui->randomDisabledWarning->setVisible(false);
|
||||
}
|
||||
@@ -87,7 +91,8 @@ void AdvSceneSwitcher::on_startupBehavior_currentIndexChanged(int index)
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->startupBehavior = (StartupBehavior)index;
|
||||
switcher->startupBehavior =
|
||||
static_cast<SwitcherData::StartupBehavior>(index);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_autoStartEvent_currentIndexChanged(int index)
|
||||
@@ -97,7 +102,7 @@ void AdvSceneSwitcher::on_autoStartEvent_currentIndexChanged(int index)
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->autoStartEvent = static_cast<AutoStartEvent>(index);
|
||||
switcher->autoStartEvent = static_cast<SwitcherData::AutoStart>(index);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_noMatchSwitchScene_currentTextChanged(
|
||||
@@ -128,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();
|
||||
}
|
||||
@@ -172,7 +176,26 @@ void AdvSceneSwitcher::on_uiHintsDisable_stateChanged(int state)
|
||||
switcher->disableHints = state;
|
||||
}
|
||||
|
||||
bool isLegacyTab(const QString &name)
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
|
||||
switcher->warnPluginLoadFailure = state;
|
||||
}
|
||||
|
||||
static bool isLegacyTab(const QString &name)
|
||||
{
|
||||
return name == obs_module_text(
|
||||
"AdvSceneSwitcher.sceneGroupTab.title") ||
|
||||
@@ -217,7 +240,7 @@ void AdvSceneSwitcher::on_hideLegacyTabs_stateChanged(int state)
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setDeprecationWarnings()
|
||||
void AdvSceneSwitcher::SetDeprecationWarnings()
|
||||
{
|
||||
QString toolTip =
|
||||
switcher->disableHints
|
||||
@@ -231,70 +254,13 @@ void AdvSceneSwitcher::setDeprecationWarnings()
|
||||
}
|
||||
}
|
||||
|
||||
QString getDefaultSaveLocation()
|
||||
{
|
||||
QString desktopPath = QStandardPaths::writableLocation(
|
||||
QStandardPaths::DesktopLocation);
|
||||
|
||||
auto scName = obs_frontend_get_current_scene_collection();
|
||||
QString sceneCollectionName(scName);
|
||||
bfree(scName);
|
||||
|
||||
auto timestamp = QDateTime::currentDateTime();
|
||||
auto path = desktopPath + "/adv-ss-" + sceneCollectionName + "-" +
|
||||
timestamp.toString("yyyy.MM.dd.hh.mm.ss");
|
||||
|
||||
// Check if scene collection name contains invalid path characters
|
||||
QFile file(path);
|
||||
if (file.exists()) {
|
||||
return path;
|
||||
}
|
||||
|
||||
bool validPath = file.open(QIODevice::WriteOnly);
|
||||
if (validPath) {
|
||||
file.remove();
|
||||
return path;
|
||||
}
|
||||
|
||||
return desktopPath + "/adv-ss-" +
|
||||
timestamp.toString("yyyy.MM.dd.hh.mm.ss");
|
||||
}
|
||||
|
||||
void AskForBackup(obs_data_t *obj)
|
||||
{
|
||||
bool backupSettings = DisplayMessage(
|
||||
obs_module_text("AdvSceneSwitcher.askBackup"), true);
|
||||
|
||||
if (!backupSettings) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString path = QFileDialog::getSaveFileName(
|
||||
nullptr,
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle"),
|
||||
getDefaultSaveLocation(),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType"));
|
||||
if (path.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QFile file(path);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
return;
|
||||
}
|
||||
|
||||
obs_data_save_json(obj, file.fileName().toUtf8().constData());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_exportSettings_clicked()
|
||||
{
|
||||
QString directory = QFileDialog::getSaveFileName(
|
||||
this,
|
||||
tr(obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle")),
|
||||
getDefaultSaveLocation(),
|
||||
GetDefaultSettingsSaveLocation(),
|
||||
tr(obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType")));
|
||||
if (directory.isEmpty()) {
|
||||
@@ -307,7 +273,7 @@ void AdvSceneSwitcher::on_exportSettings_clicked()
|
||||
}
|
||||
|
||||
obs_data_t *obj = obs_data_create();
|
||||
switcher->saveSettings(obj);
|
||||
switcher->SaveSettings(obj);
|
||||
obs_data_save_json(obj, file.fileName().toUtf8().constData());
|
||||
obs_data_release(obj);
|
||||
}
|
||||
@@ -347,7 +313,7 @@ void AdvSceneSwitcher::on_importSettings_clicked()
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->loadSettings(obj);
|
||||
switcher->LoadSettings(obj);
|
||||
obs_data_release(obj);
|
||||
switcher->lastImportPath = path.toStdString();
|
||||
|
||||
@@ -363,7 +329,7 @@ void AdvSceneSwitcher::on_importSettings_clicked()
|
||||
}
|
||||
}
|
||||
|
||||
int findTabIndex(QTabWidget *tabWidget, int pos)
|
||||
static int findTabIndex(QTabWidget *tabWidget, int pos)
|
||||
{
|
||||
int at = -1;
|
||||
|
||||
@@ -437,10 +403,10 @@ int findTabIndex(QTabWidget *tabWidget, int pos)
|
||||
return at;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setTabOrder()
|
||||
void AdvSceneSwitcher::SetTabOrder()
|
||||
{
|
||||
if (!switcher->tabOrderValid()) {
|
||||
switcher->resetTabOrder();
|
||||
if (!switcher->TabOrderValid()) {
|
||||
switcher->ResetTabOrder();
|
||||
}
|
||||
|
||||
QTabBar *bar = ui->tabWidget->tabBar();
|
||||
@@ -455,22 +421,22 @@ void AdvSceneSwitcher::setTabOrder()
|
||||
connect(bar, &QTabBar::tabMoved, this, &AdvSceneSwitcher::on_tabMoved);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setCurrentTab()
|
||||
void AdvSceneSwitcher::SetCurrentTab()
|
||||
{
|
||||
if (switcher->lastOpenedTab >= 0) {
|
||||
ui->tabWidget->setCurrentIndex(switcher->lastOpenedTab);
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::restoreWindowGeo()
|
||||
void AdvSceneSwitcher::RestoreWindowGeo()
|
||||
{
|
||||
if (switcher->saveWindowGeo && windowPosValid(switcher->windowPos)) {
|
||||
if (switcher->saveWindowGeo && WindowPosValid(switcher->windowPos)) {
|
||||
this->resize(switcher->windowSize);
|
||||
this->move(switcher->windowPos);
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::checkFirstTimeSetup()
|
||||
void AdvSceneSwitcher::CheckFirstTimeSetup()
|
||||
{
|
||||
if (switcher->firstBoot && !switcher->disableHints) {
|
||||
switcher->firstBoot = false;
|
||||
@@ -491,7 +457,7 @@ void AdvSceneSwitcher::on_tabMoved(int from, int to)
|
||||
void AdvSceneSwitcher::on_tabWidget_currentChanged(int)
|
||||
{
|
||||
switcher->showFrame = false;
|
||||
clearFrames(ui->screenRegionSwitches);
|
||||
ClearFrames(ui->screenRegionSwitches);
|
||||
SetShowFrames();
|
||||
}
|
||||
|
||||
@@ -528,18 +494,26 @@ void AdvSceneSwitcher::on_adjustActiveTransitionType_stateChanged(int state)
|
||||
switcher->adjustActiveTransitionType = state;
|
||||
}
|
||||
|
||||
void SwitcherData::loadSettings(obs_data_t *obj)
|
||||
void SwitcherData::LoadSettings(obs_data_t *obj)
|
||||
{
|
||||
if (!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);
|
||||
loadMacros(obj);
|
||||
loadConnections(obj);
|
||||
LoadVariables(obj);
|
||||
|
||||
for (const auto &func : loadSteps) {
|
||||
func(obj);
|
||||
}
|
||||
|
||||
LoadMacros(obj);
|
||||
LoadGlobalMacroProperties(obj);
|
||||
loadWindowTitleSwitches(obj);
|
||||
loadScreenRegionSwitches(obj);
|
||||
loadPauseSwitches(obj);
|
||||
@@ -555,24 +529,29 @@ void SwitcherData::loadSettings(obs_data_t *obj)
|
||||
loadVideoSwitches(obj);
|
||||
loadNetworkSettings(obj);
|
||||
loadSceneTriggers(obj);
|
||||
loadGeneralSettings(obj);
|
||||
loadHotkeys(obj);
|
||||
loadUISettings(obj);
|
||||
LoadGeneralSettings(obj);
|
||||
LoadHotkeys(obj);
|
||||
LoadUISettings(obj);
|
||||
|
||||
for (const auto &func : postLoadSteps) {
|
||||
func();
|
||||
}
|
||||
|
||||
// Reset on startup and scene collection change
|
||||
switcher->lastOpenedTab = -1;
|
||||
startupLoadDone = true;
|
||||
}
|
||||
|
||||
void SwitcherData::saveSettings(obs_data_t *obj)
|
||||
void SwitcherData::SaveSettings(obs_data_t *obj)
|
||||
{
|
||||
if (!obj) {
|
||||
return;
|
||||
}
|
||||
|
||||
saveSceneGroups(obj);
|
||||
saveMacros(obj);
|
||||
saveConnections(obj);
|
||||
saveVariables(obj);
|
||||
SaveMacros(obj);
|
||||
SaveGlobalMacroProperties(obj);
|
||||
SaveVariables(obj);
|
||||
saveWindowTitleSwitches(obj);
|
||||
saveScreenRegionSwitches(obj);
|
||||
savePauseSwitches(obj);
|
||||
@@ -588,27 +567,33 @@ void SwitcherData::saveSettings(obs_data_t *obj)
|
||||
saveVideoSwitches(obj);
|
||||
saveNetworkSwitches(obj);
|
||||
saveSceneTriggers(obj);
|
||||
saveGeneralSettings(obj);
|
||||
saveHotkeys(obj);
|
||||
saveUISettings(obj);
|
||||
saveVersion(obj, g_GIT_SHA1);
|
||||
SaveGeneralSettings(obj);
|
||||
SaveHotkeys(obj);
|
||||
SaveUISettings(obj);
|
||||
SaveVersion(obj, g_GIT_SHA1);
|
||||
|
||||
for (const auto &func : saveSteps) {
|
||||
func(obj);
|
||||
}
|
||||
}
|
||||
|
||||
void SwitcherData::saveGeneralSettings(obs_data_t *obj)
|
||||
void SwitcherData::SaveGeneralSettings(obs_data_t *obj)
|
||||
{
|
||||
obs_data_set_int(obj, "interval", interval);
|
||||
|
||||
std::string nonMatchingSceneName = GetWeakSourceName(nonMatchingScene);
|
||||
obs_data_set_string(obj, "non_matching_scene",
|
||||
nonMatchingSceneName.c_str());
|
||||
obs_data_set_int(obj, "switch_if_not_matching", switchIfNotMatching);
|
||||
obs_data_set_int(obj, "switch_if_not_matching",
|
||||
static_cast<int>(switchIfNotMatching));
|
||||
noMatchDelay.Save(obj, "noMatchDelay");
|
||||
|
||||
cooldown.Save(obj, "cooldown");
|
||||
|
||||
obs_data_set_bool(obj, "active", sceneColletionStop ? true : !stop);
|
||||
sceneColletionStop = false;
|
||||
obs_data_set_int(obj, "startup_behavior", startupBehavior);
|
||||
obs_data_set_int(obj, "startup_behavior",
|
||||
static_cast<int>(startupBehavior));
|
||||
|
||||
obs_data_set_int(obj, "autoStartEvent",
|
||||
static_cast<int>(autoStartEvent));
|
||||
@@ -617,19 +602,12 @@ 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);
|
||||
|
||||
obs_data_set_int(obj, "priority0", functionNamesByPriority[0]);
|
||||
obs_data_set_int(obj, "priority1", functionNamesByPriority[1]);
|
||||
obs_data_set_int(obj, "priority2", functionNamesByPriority[2]);
|
||||
obs_data_set_int(obj, "priority3", functionNamesByPriority[3]);
|
||||
obs_data_set_int(obj, "priority4", functionNamesByPriority[4]);
|
||||
obs_data_set_int(obj, "priority5", functionNamesByPriority[5]);
|
||||
obs_data_set_int(obj, "priority6", functionNamesByPriority[6]);
|
||||
obs_data_set_int(obj, "priority7", functionNamesByPriority[7]);
|
||||
obs_data_set_int(obj, "priority8", functionNamesByPriority[8]);
|
||||
obs_data_set_int(obj, "priority9", functionNamesByPriority[9]);
|
||||
obs_data_set_int(obj, "priority10", functionNamesByPriority[10]);
|
||||
SaveFunctionPriorities(obj, functionNamesByPriority);
|
||||
|
||||
obs_data_set_int(obj, "threadPriority", threadPriority);
|
||||
|
||||
@@ -641,14 +619,15 @@ void SwitcherData::saveGeneralSettings(obs_data_t *obj)
|
||||
obs_data_set_string(obj, "lastImportPath", lastImportPath.c_str());
|
||||
}
|
||||
|
||||
void SwitcherData::loadGeneralSettings(obs_data_t *obj)
|
||||
void SwitcherData::LoadGeneralSettings(obs_data_t *obj)
|
||||
{
|
||||
obs_data_set_default_int(obj, "interval", default_interval);
|
||||
interval = obs_data_get_int(obj, "interval");
|
||||
|
||||
obs_data_set_default_int(obj, "switch_if_not_matching", NO_SWITCH);
|
||||
switchIfNotMatching =
|
||||
(NoMatch)obs_data_get_int(obj, "switch_if_not_matching");
|
||||
obs_data_set_default_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());
|
||||
@@ -659,70 +638,39 @@ void SwitcherData::loadGeneralSettings(obs_data_t *obj)
|
||||
stop = !obs_data_get_bool(obj, "active");
|
||||
startupBehavior =
|
||||
(StartupBehavior)obs_data_get_int(obj, "startup_behavior");
|
||||
if (startupBehavior == START) {
|
||||
if (startupBehavior == StartupBehavior::START) {
|
||||
stop = false;
|
||||
}
|
||||
if (startupBehavior == STOP) {
|
||||
if (startupBehavior == StartupBehavior::STOP) {
|
||||
stop = true;
|
||||
}
|
||||
|
||||
autoStartEvent = static_cast<AutoStartEvent>(
|
||||
obs_data_get_int(obj, "autoStartEvent"));
|
||||
autoStartEvent =
|
||||
static_cast<AutoStart>(obs_data_get_int(obj, "autoStartEvent"));
|
||||
|
||||
verbose = obs_data_get_bool(obj, "verbose");
|
||||
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);
|
||||
hideLegacyTabs = obs_data_get_bool(obj, "hideLegacyTabs");
|
||||
|
||||
obs_data_set_default_int(obj, "priority0", default_priority_0);
|
||||
obs_data_set_default_int(obj, "priority1", default_priority_1);
|
||||
obs_data_set_default_int(obj, "priority2", default_priority_2);
|
||||
obs_data_set_default_int(obj, "priority3", default_priority_3);
|
||||
obs_data_set_default_int(obj, "priority4", default_priority_4);
|
||||
obs_data_set_default_int(obj, "priority5", default_priority_5);
|
||||
obs_data_set_default_int(obj, "priority6", default_priority_6);
|
||||
obs_data_set_default_int(obj, "priority7", default_priority_7);
|
||||
obs_data_set_default_int(obj, "priority8", default_priority_8);
|
||||
|
||||
functionNamesByPriority[0] = (obs_data_get_int(obj, "priority0"));
|
||||
functionNamesByPriority[1] = (obs_data_get_int(obj, "priority1"));
|
||||
functionNamesByPriority[2] = (obs_data_get_int(obj, "priority2"));
|
||||
functionNamesByPriority[3] = (obs_data_get_int(obj, "priority3"));
|
||||
functionNamesByPriority[4] = (obs_data_get_int(obj, "priority4"));
|
||||
functionNamesByPriority[5] = (obs_data_get_int(obj, "priority5"));
|
||||
functionNamesByPriority[6] = (obs_data_get_int(obj, "priority6"));
|
||||
functionNamesByPriority[7] = (obs_data_get_int(obj, "priority7"));
|
||||
functionNamesByPriority[8] = (obs_data_get_int(obj, "priority8"));
|
||||
functionNamesByPriority[9] = (obs_data_get_int(obj, "priority9"));
|
||||
functionNamesByPriority[10] = (obs_data_get_int(obj, "priority10"));
|
||||
if (!prioFuncsValid()) {
|
||||
functionNamesByPriority[0] = (default_priority_0);
|
||||
functionNamesByPriority[1] = (default_priority_1);
|
||||
functionNamesByPriority[2] = (default_priority_2);
|
||||
functionNamesByPriority[3] = (default_priority_3);
|
||||
functionNamesByPriority[4] = (default_priority_4);
|
||||
functionNamesByPriority[5] = (default_priority_5);
|
||||
functionNamesByPriority[6] = (default_priority_6);
|
||||
functionNamesByPriority[7] = (default_priority_7);
|
||||
functionNamesByPriority[8] = (default_priority_8);
|
||||
functionNamesByPriority[9] = (default_priority_9);
|
||||
functionNamesByPriority[10] = (default_priority_10);
|
||||
SetDefaultFunctionPriorities(obj);
|
||||
LoadFunctionPriorities(obj, functionNamesByPriority);
|
||||
if (!PrioFuncsValid()) {
|
||||
functionNamesByPriority = GetDefaultFunctionPriorityList();
|
||||
}
|
||||
|
||||
obs_data_set_default_int(obj, "threadPriority",
|
||||
QThread::NormalPriority);
|
||||
threadPriority = obs_data_get_int(obj, "threadPriority");
|
||||
|
||||
// TODO: Remove this fallback in future version
|
||||
if (obs_data_has_user_value(obj, "tansitionOverrideOverride")) {
|
||||
transitionOverrideOverride =
|
||||
obs_data_get_bool(obj, "tansitionOverrideOverride");
|
||||
} else {
|
||||
transitionOverrideOverride =
|
||||
obs_data_get_bool(obj, "transitionOverrideOverride");
|
||||
}
|
||||
transitionOverrideOverride =
|
||||
obs_data_get_bool(obj, "transitionOverrideOverride");
|
||||
adjustActiveTransitionType =
|
||||
obs_data_get_bool(obj, "adjustActiveTransitionType");
|
||||
|
||||
@@ -735,33 +683,7 @@ void SwitcherData::loadGeneralSettings(obs_data_t *obj)
|
||||
lastImportPath = obs_data_get_string(obj, "lastImportPath");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
void SwitcherData::SaveUISettings(obs_data_t *obj)
|
||||
{
|
||||
obs_data_set_int(obj, "generalTabPos", tabOrder[0]);
|
||||
obs_data_set_int(obj, "macroTabPos", tabOrder[1]);
|
||||
@@ -788,13 +710,11 @@ 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");
|
||||
}
|
||||
|
||||
void SwitcherData::loadUISettings(obs_data_t *obj)
|
||||
void SwitcherData::LoadUISettings(obs_data_t *obj)
|
||||
{
|
||||
obs_data_set_default_int(obj, "generalTabPos", 0);
|
||||
obs_data_set_default_int(obj, "macroTabPos", 1);
|
||||
@@ -835,8 +755,8 @@ void SwitcherData::loadUISettings(obs_data_t *obj)
|
||||
tabOrder.emplace_back((int)(obs_data_get_int(obj, "sceneGroupTabPos")));
|
||||
tabOrder.emplace_back((int)(obs_data_get_int(obj, "triggerTabPos")));
|
||||
|
||||
if (!tabOrderValid()) {
|
||||
resetTabOrder();
|
||||
if (!TabOrderValid()) {
|
||||
ResetTabOrder();
|
||||
}
|
||||
|
||||
saveWindowGeo = obs_data_get_bool(obj, "saveWindowGeo");
|
||||
@@ -844,13 +764,12 @@ 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");
|
||||
}
|
||||
|
||||
bool SwitcherData::tabOrderValid()
|
||||
bool SwitcherData::TabOrderValid()
|
||||
{
|
||||
auto tmp = std::vector<int>(tab_count);
|
||||
std::iota(tmp.begin(), tmp.end(), 0);
|
||||
@@ -864,13 +783,13 @@ bool SwitcherData::tabOrderValid()
|
||||
return true;
|
||||
}
|
||||
|
||||
void SwitcherData::resetTabOrder()
|
||||
void SwitcherData::ResetTabOrder()
|
||||
{
|
||||
tabOrder = std::vector<int>(tab_count);
|
||||
std::iota(tabOrder.begin(), tabOrder.end(), 0);
|
||||
}
|
||||
|
||||
void SwitcherData::checkNoMatchSwitch(bool &match, OBSWeakSource &scene,
|
||||
void SwitcherData::CheckNoMatchSwitch(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition, int &sleep)
|
||||
{
|
||||
if (match) {
|
||||
@@ -882,12 +801,13 @@ void SwitcherData::checkNoMatchSwitch(bool &match, OBSWeakSource &scene,
|
||||
return;
|
||||
}
|
||||
|
||||
if (switchIfNotMatching == SWITCH && nonMatchingScene) {
|
||||
if (switchIfNotMatching == NoMatchBehavior::SWITCH &&
|
||||
nonMatchingScene) {
|
||||
match = true;
|
||||
scene = nonMatchingScene;
|
||||
transition = nullptr;
|
||||
}
|
||||
if (switchIfNotMatching == RANDOM_SWITCH) {
|
||||
if (switchIfNotMatching == NoMatchBehavior::RANDOM_SWITCH) {
|
||||
match = checkRandom(scene, transition, sleep);
|
||||
}
|
||||
}
|
||||
@@ -906,7 +826,7 @@ void SwitcherData::checkSwitchCooldown(bool &match)
|
||||
}
|
||||
}
|
||||
|
||||
void populateStartupBehavior(QComboBox *cb)
|
||||
static void populateStartupBehavior(QComboBox *cb)
|
||||
{
|
||||
cb->addItem(obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.status.onStartup.asLastRun"));
|
||||
@@ -916,7 +836,7 @@ void populateStartupBehavior(QComboBox *cb)
|
||||
"AdvSceneSwitcher.generalTab.status.onStartup.doNotStart"));
|
||||
}
|
||||
|
||||
void populateAutoStartEventSelection(QComboBox *cb)
|
||||
static void populateAutoStartEventSelection(QComboBox *cb)
|
||||
{
|
||||
cb->addItem(obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.status.autoStart.never"));
|
||||
@@ -928,51 +848,8 @@ void populateAutoStartEventSelection(QComboBox *cb)
|
||||
"AdvSceneSwitcher.generalTab.status.autoStart.recordingAndStreaming"));
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupGeneralTab()
|
||||
static void populatePriorityFunctionList(QListWidget *list)
|
||||
{
|
||||
populateSceneSelection(ui->noMatchSwitchScene, false);
|
||||
|
||||
if (switcher->switchIfNotMatching == SWITCH) {
|
||||
ui->noMatchSwitch->setChecked(true);
|
||||
ui->noMatchSwitchScene->setEnabled(true);
|
||||
} else if (switcher->switchIfNotMatching == NO_SWITCH) {
|
||||
ui->noMatchDontSwitch->setChecked(true);
|
||||
ui->noMatchSwitchScene->setEnabled(false);
|
||||
} else {
|
||||
ui->noMatchRandomSwitch->setChecked(true);
|
||||
ui->noMatchSwitchScene->setEnabled(false);
|
||||
}
|
||||
ui->noMatchSwitchScene->setCurrentText(
|
||||
GetWeakSourceName(switcher->nonMatchingScene).c_str());
|
||||
|
||||
DurationSelection *noMatchDelay = new DurationSelection();
|
||||
noMatchDelay->SetDuration(switcher->noMatchDelay);
|
||||
noMatchDelay->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.onNoMetDelayTooltip"));
|
||||
ui->noMatchLayout->addWidget(noMatchDelay);
|
||||
QWidget::connect(noMatchDelay,
|
||||
SIGNAL(DurationChanged(const Duration &)), this,
|
||||
SLOT(NoMatchDelayDurationChanged(const Duration &)));
|
||||
|
||||
ui->checkInterval->setValue(switcher->interval);
|
||||
|
||||
DurationSelection *cooldownTime = new DurationSelection();
|
||||
cooldownTime->SetDuration(switcher->cooldown);
|
||||
cooldownTime->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint"));
|
||||
ui->cooldownLayout->addWidget(cooldownTime);
|
||||
ui->cooldownLayout->addStretch();
|
||||
QWidget::connect(cooldownTime,
|
||||
SIGNAL(DurationChanged(const Duration &)), this,
|
||||
SLOT(CooldownDurationChanged(const Duration &)));
|
||||
|
||||
ui->verboseLogging->setChecked(switcher->verbose);
|
||||
ui->saveWindowGeo->setChecked(switcher->saveWindowGeo);
|
||||
ui->showTrayNotifications->setChecked(
|
||||
switcher->showSystemTrayNotifications);
|
||||
ui->uiHintsDisable->setChecked(switcher->disableHints);
|
||||
ui->hideLegacyTabs->setChecked(switcher->hideLegacyTabs);
|
||||
|
||||
for (int p : switcher->functionNamesByPriority) {
|
||||
std::string s = "";
|
||||
switch (p) {
|
||||
@@ -1022,26 +899,118 @@ void AdvSceneSwitcher::setupGeneralTab()
|
||||
break;
|
||||
}
|
||||
QString text(s.c_str());
|
||||
QListWidgetItem *item =
|
||||
new QListWidgetItem(text, ui->priorityList);
|
||||
QListWidgetItem *item = new QListWidgetItem(text, list);
|
||||
item->setData(Qt::UserRole, text);
|
||||
}
|
||||
}
|
||||
|
||||
static void populateThreadPriorityList(QComboBox *list)
|
||||
{
|
||||
for (int i = 0; i < (int)switcher->threadPriorities.size(); ++i) {
|
||||
ui->threadPriority->addItem(
|
||||
switcher->threadPriorities[i].name.c_str());
|
||||
ui->threadPriority->setItemData(
|
||||
list->addItem(switcher->threadPriorities[i].name.c_str());
|
||||
list->setItemData(
|
||||
i, switcher->threadPriorities[i].description.c_str(),
|
||||
Qt::ToolTipRole);
|
||||
if (switcher->threadPriority ==
|
||||
switcher->threadPriorities[i].value) {
|
||||
ui->threadPriority->setCurrentText(
|
||||
list->setCurrentText(
|
||||
switcher->threadPriorities[i].name.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool isGeneralTab(const QString &name)
|
||||
{
|
||||
return name == obs_module_text("AdvSceneSwitcher.generalTab.title");
|
||||
}
|
||||
|
||||
static int getGeneralTabIdx(QTabWidget *tabWidget)
|
||||
{
|
||||
for (int idx = 0; idx < tabWidget->count(); idx++) {
|
||||
if (isGeneralTab(tabWidget->tabText(idx))) {
|
||||
return idx;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void setupGeneralTabInactiveWarning(QTabWidget *tabs)
|
||||
{
|
||||
auto callback = [tabs]() {
|
||||
const bool isRunning = switcher && switcher->th &&
|
||||
switcher->th->isRunning();
|
||||
auto idx = getGeneralTabIdx(tabs);
|
||||
tabs->setTabIcon(
|
||||
idx,
|
||||
isRunning ? QIcon()
|
||||
: QIcon::fromTheme(
|
||||
"obs",
|
||||
QIcon(":/res/images/warning.svg")));
|
||||
};
|
||||
|
||||
auto inactiveTimer = new QTimer(tabs);
|
||||
inactiveTimer->setInterval(1000);
|
||||
QObject::connect(inactiveTimer, &QTimer::timeout, callback);
|
||||
inactiveTimer->start();
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::SetupGeneralTab()
|
||||
{
|
||||
PopulateSceneSelection(ui->noMatchSwitchScene, false);
|
||||
|
||||
if (switcher->switchIfNotMatching == NoMatchBehavior::SWITCH) {
|
||||
ui->noMatchSwitch->setChecked(true);
|
||||
ui->noMatchSwitchScene->setEnabled(true);
|
||||
} else if (switcher->switchIfNotMatching ==
|
||||
NoMatchBehavior::NO_SWITCH) {
|
||||
ui->noMatchDontSwitch->setChecked(true);
|
||||
ui->noMatchSwitchScene->setEnabled(false);
|
||||
} else {
|
||||
ui->noMatchRandomSwitch->setChecked(true);
|
||||
ui->noMatchSwitchScene->setEnabled(false);
|
||||
}
|
||||
ui->noMatchSwitchScene->setCurrentText(
|
||||
GetWeakSourceName(switcher->nonMatchingScene).c_str());
|
||||
|
||||
DurationSelection *noMatchDelay = new DurationSelection();
|
||||
noMatchDelay->SetDuration(switcher->noMatchDelay);
|
||||
noMatchDelay->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.onNoMetDelayTooltip"));
|
||||
ui->noMatchLayout->addWidget(noMatchDelay);
|
||||
QWidget::connect(noMatchDelay,
|
||||
SIGNAL(DurationChanged(const Duration &)), this,
|
||||
SLOT(NoMatchDelayDurationChanged(const Duration &)));
|
||||
|
||||
ui->checkInterval->setValue(switcher->interval);
|
||||
|
||||
DurationSelection *cooldownTime = new DurationSelection();
|
||||
cooldownTime->SetDuration(switcher->cooldown);
|
||||
cooldownTime->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint"));
|
||||
ui->cooldownLayout->addWidget(cooldownTime);
|
||||
ui->cooldownLayout->addStretch();
|
||||
QWidget::connect(cooldownTime,
|
||||
SIGNAL(DurationChanged(const Duration &)), this,
|
||||
SLOT(CooldownDurationChanged(const Duration &)));
|
||||
|
||||
ui->verboseLogging->setChecked(switcher->verbose);
|
||||
ui->saveWindowGeo->setChecked(switcher->saveWindowGeo);
|
||||
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);
|
||||
|
||||
populatePriorityFunctionList(ui->priorityList);
|
||||
populateThreadPriorityList(ui->threadPriority);
|
||||
|
||||
populateStartupBehavior(ui->startupBehavior);
|
||||
ui->startupBehavior->setCurrentIndex(switcher->startupBehavior);
|
||||
ui->startupBehavior->setCurrentIndex(
|
||||
static_cast<int>(switcher->startupBehavior));
|
||||
|
||||
populateAutoStartEventSelection(ui->autoStartEvent);
|
||||
ui->autoStartEvent->setCurrentIndex(
|
||||
@@ -1058,6 +1027,10 @@ void AdvSceneSwitcher::setupGeneralTab()
|
||||
// Hide the now empty invisible shell of the statusControl widget
|
||||
// as otherwise it could block user input
|
||||
statusControl->hide();
|
||||
setupGeneralTabInactiveWarning(ui->tabWidget);
|
||||
|
||||
MinimizeSizeOfColumn(ui->statusLayout, 0);
|
||||
setWindowTitle(windowTitle() + " - " + g_GIT_TAG);
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
#include "hotkey.hpp"
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include <obs-module.h>
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
|
||||
namespace advss {
|
||||
|
||||
std::vector<std::weak_ptr<Hotkey>> Hotkey::_registeredHotkeys = {};
|
||||
uint32_t Hotkey::_hotkeyCounter = 1;
|
||||
|
||||
@@ -117,7 +120,7 @@ void Hotkey::ClearAllHotkeys()
|
||||
_registeredHotkeys.clear();
|
||||
}
|
||||
|
||||
void startHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *, bool pressed)
|
||||
static void startHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *, bool pressed)
|
||||
{
|
||||
if (pressed) {
|
||||
if (!(switcher->th && switcher->th->isRunning())) {
|
||||
@@ -126,7 +129,7 @@ void startHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *, bool pressed)
|
||||
}
|
||||
}
|
||||
|
||||
void stopHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *, bool pressed)
|
||||
static void stopHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *, bool pressed)
|
||||
{
|
||||
if (pressed) {
|
||||
if (switcher->th && switcher->th->isRunning()) {
|
||||
@@ -135,8 +138,8 @@ void stopHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *, bool pressed)
|
||||
}
|
||||
}
|
||||
|
||||
void startStopToggleHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
|
||||
bool pressed)
|
||||
static void startStopToggleHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
|
||||
bool pressed)
|
||||
{
|
||||
if (pressed) {
|
||||
if (switcher->th && switcher->th->isRunning()) {
|
||||
@@ -147,8 +150,8 @@ void startStopToggleHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
|
||||
}
|
||||
}
|
||||
|
||||
void upMacroSegmentHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
|
||||
bool pressed)
|
||||
static void upMacroSegmentHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
|
||||
bool pressed)
|
||||
{
|
||||
if (pressed && switcher->settingsWindowOpened &&
|
||||
AdvSceneSwitcher::window) {
|
||||
@@ -158,8 +161,8 @@ void upMacroSegmentHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
|
||||
}
|
||||
}
|
||||
|
||||
void downMacroSegmentHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
|
||||
bool pressed)
|
||||
static void downMacroSegmentHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
|
||||
bool pressed)
|
||||
{
|
||||
if (pressed && switcher->settingsWindowOpened &&
|
||||
AdvSceneSwitcher::window) {
|
||||
@@ -169,8 +172,8 @@ void downMacroSegmentHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
|
||||
}
|
||||
}
|
||||
|
||||
void removeMacroSegmentHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
|
||||
bool pressed)
|
||||
static void removeMacroSegmentHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
|
||||
bool pressed)
|
||||
{
|
||||
if (pressed && switcher->settingsWindowOpened &&
|
||||
AdvSceneSwitcher::window) {
|
||||
@@ -180,7 +183,7 @@ void removeMacroSegmentHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
|
||||
}
|
||||
}
|
||||
|
||||
void registerHotkeys()
|
||||
static void registerHotkeys()
|
||||
{
|
||||
switcher->startHotkey = obs_hotkey_register_frontend(
|
||||
"startSwitcherHotkey",
|
||||
@@ -213,14 +216,14 @@ void registerHotkeys()
|
||||
switcher->hotkeysRegistered = true;
|
||||
}
|
||||
|
||||
void saveHotkey(obs_data_t *obj, obs_hotkey_id id, const char *name)
|
||||
static void saveHotkey(obs_data_t *obj, obs_hotkey_id id, const char *name)
|
||||
{
|
||||
obs_data_array_t *a = obs_hotkey_save(id);
|
||||
obs_data_set_array(obj, name, a);
|
||||
obs_data_array_release(a);
|
||||
}
|
||||
|
||||
void SwitcherData::saveHotkeys(obs_data_t *obj)
|
||||
void SwitcherData::SaveHotkeys(obs_data_t *obj)
|
||||
{
|
||||
saveHotkey(obj, startHotkey, "startHotkey");
|
||||
saveHotkey(obj, stopHotkey, "stopHotkey");
|
||||
@@ -230,14 +233,14 @@ void SwitcherData::saveHotkeys(obs_data_t *obj)
|
||||
saveHotkey(obj, removeMacroSegment, "removeMacroSegmentHotkey");
|
||||
}
|
||||
|
||||
void loadHotkey(obs_data_t *obj, obs_hotkey_id id, const char *name)
|
||||
static void loadHotkey(obs_data_t *obj, obs_hotkey_id id, const char *name)
|
||||
{
|
||||
obs_data_array_t *a = obs_data_get_array(obj, name);
|
||||
obs_hotkey_load(id, a);
|
||||
obs_data_array_release(a);
|
||||
}
|
||||
|
||||
void SwitcherData::loadHotkeys(obs_data_t *obj)
|
||||
void SwitcherData::LoadHotkeys(obs_data_t *obj)
|
||||
{
|
||||
if (!hotkeysRegistered) {
|
||||
registerHotkeys();
|
||||
@@ -249,3 +252,5 @@ void SwitcherData::loadHotkeys(obs_data_t *obj)
|
||||
loadHotkey(obj, downMacroSegment, "downMacroSegmentHotkey");
|
||||
loadHotkey(obj, removeMacroSegment, "removeMacroSegmentHotkey");
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
|
||||
namespace advss {
|
||||
|
||||
extern bool canSimulateKeyPresses;
|
||||
|
||||
class Hotkey {
|
||||
@@ -158,7 +160,9 @@ enum class HotkeyType {
|
||||
Key_NumpadMultiply,
|
||||
Key_NumpadDivide,
|
||||
Key_NumpadDecimal,
|
||||
Key_NumpadEnter
|
||||
Key_NumpadEnter,
|
||||
|
||||
Key_Tilde,
|
||||
};
|
||||
|
||||
void registerHotkeys();
|
||||
} // namespace advss
|
||||
|
||||
@@ -3,12 +3,20 @@
|
||||
#include <random>
|
||||
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "name-dialog.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
static QMetaObject::Connection addPulse;
|
||||
SceneGroupEditWidget *typeEdit = nullptr;
|
||||
|
||||
std::deque<SceneGroup> &GetSceneGroups()
|
||||
{
|
||||
return switcher->sceneGroups;
|
||||
}
|
||||
|
||||
void SceneGroup::advanceIdx()
|
||||
{
|
||||
currentIdx++;
|
||||
@@ -487,9 +495,9 @@ void SwitcherData::loadSceneGroups(obs_data_t *obj)
|
||||
obs_data_array_release(sceneGroupArray);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupSceneGroupTab()
|
||||
void AdvSceneSwitcher::SetupSceneGroupTab()
|
||||
{
|
||||
populateSceneSelection(ui->sceneGroupSceneSelection);
|
||||
PopulateSceneSelection(ui->sceneGroupSceneSelection);
|
||||
|
||||
for (auto &sg : switcher->sceneGroups) {
|
||||
QString text = QString::fromStdString(sg.name);
|
||||
@@ -538,7 +546,7 @@ SceneGroupEditWidget::SceneGroupEditWidget()
|
||||
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{type}}", type}};
|
||||
placeWidgets(
|
||||
PlaceWidgets(
|
||||
obs_module_text("AdvSceneSwitcher.sceneGroupTab.edit.type"),
|
||||
typeLayout, widgetPlaceholders);
|
||||
|
||||
@@ -555,7 +563,7 @@ SceneGroupEditWidget::SceneGroupEditWidget()
|
||||
countLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
widgetPlaceholders = {{"{{count}}", count}};
|
||||
placeWidgets(
|
||||
PlaceWidgets(
|
||||
obs_module_text("AdvSceneSwitcher.sceneGroupTab.edit.count"),
|
||||
countLayout, widgetPlaceholders);
|
||||
|
||||
@@ -573,7 +581,7 @@ SceneGroupEditWidget::SceneGroupEditWidget()
|
||||
timeLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
widgetPlaceholders = {{"{{time}}", time}};
|
||||
placeWidgets(
|
||||
PlaceWidgets(
|
||||
obs_module_text("AdvSceneSwitcher.sceneGroupTab.edit.time"),
|
||||
timeLayout, widgetPlaceholders);
|
||||
|
||||
@@ -705,3 +713,5 @@ SceneGroup *GetSceneGroupByQString(const QString &name)
|
||||
{
|
||||
return GetSceneGroupByName(name.toUtf8().constData());
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
#include <QDialog>
|
||||
#include <QLabel>
|
||||
@@ -10,6 +10,8 @@
|
||||
#include <QCheckBox>
|
||||
#include <obs.hpp>
|
||||
|
||||
namespace advss {
|
||||
|
||||
auto constexpr invalid_scene_group_name = "invalid-scene-group";
|
||||
|
||||
enum class AdvanceCondition {
|
||||
@@ -85,3 +87,6 @@ private:
|
||||
|
||||
SceneGroup *GetSceneGroupByName(const char *name);
|
||||
SceneGroup *GetSceneGroupByQString(const QString &name);
|
||||
std::deque<SceneGroup> &GetSceneGroups();
|
||||
|
||||
} // namespace advss
|
||||
@@ -1,7 +1,10 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "utility.hpp"
|
||||
namespace advss {
|
||||
|
||||
bool SceneTrigger::pause = false;
|
||||
static QMetaObject::Connection addPulse;
|
||||
@@ -349,7 +352,7 @@ void SwitcherData::loadSceneTriggers(obs_data_t *obj)
|
||||
obs_data_array_release(triggerArray);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupTriggerTab()
|
||||
void AdvSceneSwitcher::SetupTriggerTab()
|
||||
{
|
||||
for (auto &s : switcher->sceneTriggers) {
|
||||
QListWidgetItem *item;
|
||||
@@ -398,7 +401,7 @@ void SceneTrigger::load(obs_data_t *obj)
|
||||
|
||||
static inline void populateTriggers(QComboBox *list)
|
||||
{
|
||||
addSelectionEntry(
|
||||
AddSelectionEntry(
|
||||
list,
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.none"));
|
||||
@@ -413,7 +416,7 @@ static inline void populateTriggers(QComboBox *list)
|
||||
|
||||
inline void populateActions(QComboBox *list)
|
||||
{
|
||||
addSelectionEntry(
|
||||
AddSelectionEntry(
|
||||
list,
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.none"));
|
||||
@@ -468,7 +471,7 @@ SceneTriggerWidget::SceneTriggerWidget(QWidget *parent, SceneTrigger *s)
|
||||
|
||||
populateTriggers(triggers);
|
||||
populateActions(actions);
|
||||
populateAudioSelection(audioSources);
|
||||
PopulateAudioSelection(audioSources);
|
||||
|
||||
if (s) {
|
||||
triggers->setCurrentIndex(static_cast<int>(s->triggerType));
|
||||
@@ -492,7 +495,7 @@ SceneTriggerWidget::SceneTriggerWidget(QWidget *parent, SceneTrigger *s)
|
||||
{"{{audioSources}}", audioSources},
|
||||
{"{{duration}}", duration},
|
||||
{"{{scenes}}", scenes}};
|
||||
placeWidgets(obs_module_text("AdvSceneSwitcher.sceneTriggerTab.entry"),
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.sceneTriggerTab.entry"),
|
||||
mainLayout, widgetPlaceholders);
|
||||
setLayout(mainLayout);
|
||||
|
||||
@@ -569,3 +572,5 @@ void SceneTriggerWidget::AudioSourceChanged(const QString &text)
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->audioSource = GetWeakSourceByQString(text);
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include "switch-generic.hpp"
|
||||
#include "duration-control.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
enum class sceneTriggerType {
|
||||
NONE = 0,
|
||||
SCENE_ACTIVE = 1,
|
||||
@@ -82,3 +84,5 @@ private:
|
||||
|
||||
SceneTrigger *switchData;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
#include <float.h>
|
||||
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "volume-control.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <float.h>
|
||||
|
||||
namespace advss {
|
||||
|
||||
bool AudioSwitch::pause = false;
|
||||
static QMetaObject::Connection addPulse;
|
||||
|
||||
@@ -212,7 +215,7 @@ void SwitcherData::loadAudioSwitches(obs_data_t *obj)
|
||||
audioFallback.load(obj);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupAudioTab()
|
||||
void AdvSceneSwitcher::SetupAudioTab()
|
||||
{
|
||||
for (auto &s : switcher->audioSwitches) {
|
||||
QListWidgetItem *item;
|
||||
@@ -446,7 +449,7 @@ AudioSwitchWidget::AudioSwitchWidget(QWidget *parent, AudioSwitch *s)
|
||||
QWidget::connect(ignoreInactiveSource, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(IgnoreInactiveChanged(int)));
|
||||
|
||||
populateAudioSelection(audioSources);
|
||||
PopulateAudioSelection(audioSources);
|
||||
populateConditionSelection(condition);
|
||||
|
||||
if (s) {
|
||||
@@ -467,7 +470,7 @@ AudioSwitchWidget::AudioSwitchWidget(QWidget *parent, AudioSwitch *s)
|
||||
{"{{ignoreInactiveSource}}", ignoreInactiveSource},
|
||||
{"{{scenes}}", scenes},
|
||||
{"{{transitions}}", transitions}};
|
||||
placeWidgets(obs_module_text("AdvSceneSwitcher.audioTab.entry"),
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.audioTab.entry"),
|
||||
switchLayout, widgetPlaceholders);
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
@@ -592,7 +595,7 @@ AudioSwitchFallbackWidget::AudioSwitchFallbackWidget(QWidget *parent,
|
||||
{"{{scenes}}", scenes},
|
||||
{"{{duration}}", duration},
|
||||
{"{{transitions}}", transitions}};
|
||||
placeWidgets(
|
||||
PlaceWidgets(
|
||||
obs_module_text("AdvSceneSwitcher.audioTab.multiMatchfallback"),
|
||||
mainLayout, widgetPlaceholders);
|
||||
setLayout(mainLayout);
|
||||
@@ -611,3 +614,5 @@ void AudioSwitchFallbackWidget::DurationChanged(const Duration &dur)
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->duration = dur;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#include "duration-control.hpp"
|
||||
#include "volume-control.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
constexpr auto audio_func = 8;
|
||||
|
||||
typedef enum {
|
||||
@@ -103,3 +105,5 @@ private:
|
||||
|
||||
AudioSwitchFallback *switchData;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "platform-funcs.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
bool ExecutableSwitch::pause = false;
|
||||
static QMetaObject::Connection addPulse;
|
||||
|
||||
@@ -99,7 +103,7 @@ bool SwitcherData::checkExeSwitch(OBSWeakSource &scene,
|
||||
bool equals = runningProcesses.contains(s.exe);
|
||||
bool matches = (runningProcesses.indexOf(
|
||||
QRegularExpression(s.exe)) != -1);
|
||||
bool focus = (!s.inFocus || isInFocus(s.exe));
|
||||
bool focus = (!s.inFocus || IsInFocus(s.exe));
|
||||
|
||||
// True if current window is ignored AND switch equals OR matches last window
|
||||
bool ignore =
|
||||
@@ -156,7 +160,7 @@ void SwitcherData::loadExecutableSwitches(obs_data_t *obj)
|
||||
obs_data_array_release(executableArray);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupExecutableTab()
|
||||
void AdvSceneSwitcher::SetupExecutableTab()
|
||||
{
|
||||
for (auto &s : switcher->executableSwitches) {
|
||||
QListWidgetItem *item;
|
||||
@@ -208,7 +212,7 @@ ExecutableSwitchWidget::ExecutableSwitchWidget(QWidget *parent,
|
||||
QWidget::connect(requiresFocus, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(FocusChanged(int)));
|
||||
|
||||
populateProcessSelection(processes);
|
||||
PopulateProcessSelection(processes);
|
||||
|
||||
processes->setEditable(true);
|
||||
processes->setMaxVisibleItems(20);
|
||||
@@ -224,7 +228,7 @@ ExecutableSwitchWidget::ExecutableSwitchWidget(QWidget *parent,
|
||||
{"{{requiresFocus}}", requiresFocus},
|
||||
{"{{scenes}}", scenes},
|
||||
{"{{transitions}}", transitions}};
|
||||
placeWidgets(obs_module_text("AdvSceneSwitcher.executableTab.entry"),
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.executableTab.entry"),
|
||||
mainLayout, widgetPlaceholders);
|
||||
setLayout(mainLayout);
|
||||
|
||||
@@ -272,3 +276,5 @@ void ExecutableSwitchWidget::FocusChanged(int state)
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->inFocus = state;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include <QCheckBox>
|
||||
#include "switch-generic.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
constexpr auto exe_func = 3;
|
||||
|
||||
struct ExecutableSwitch : SceneSwitcherEntry {
|
||||
@@ -42,3 +44,5 @@ private:
|
||||
|
||||
ExecutableSwitch *switchData;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "curl-helper.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QFileDialog>
|
||||
#include <QTextStream>
|
||||
@@ -6,9 +11,7 @@
|
||||
#include <regex>
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "curl-helper.hpp"
|
||||
#include "utility.hpp"
|
||||
namespace advss {
|
||||
|
||||
bool FileSwitch::pause = false;
|
||||
static QMetaObject::Connection addPulse;
|
||||
@@ -116,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
|
||||
@@ -174,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;
|
||||
}
|
||||
@@ -209,7 +212,7 @@ bool matchFileContent(QString &filedata, FileSwitch &s)
|
||||
}
|
||||
|
||||
QString text = QString::fromStdString(s.text);
|
||||
return compareIgnoringLineEnding(text, filedata);
|
||||
return CompareIgnoringLineEnding(text, filedata);
|
||||
}
|
||||
|
||||
bool checkRemoteFileContent(FileSwitch &s)
|
||||
@@ -411,7 +414,7 @@ void SwitcherData::loadFileSwitches(obs_data_t *obj)
|
||||
fileIO.writePath = obs_data_get_string(obj, "writePath");
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupFileTab()
|
||||
void AdvSceneSwitcher::SetupFileTab()
|
||||
{
|
||||
ui->remoteFileWarningLabel->setText(
|
||||
obs_module_text("AdvSceneSwitcher.fileTab.remoteFileWarning1") +
|
||||
@@ -419,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);
|
||||
}
|
||||
|
||||
@@ -542,11 +545,11 @@ FileSwitchWidget::FileSwitchWidget(QWidget *parent, FileSwitch *s)
|
||||
QHBoxLayout *line1Layout = new QHBoxLayout;
|
||||
QHBoxLayout *line2Layout = new QHBoxLayout;
|
||||
QHBoxLayout *line3Layout = new QHBoxLayout;
|
||||
placeWidgets(obs_module_text("AdvSceneSwitcher.fileTab.entry"),
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.fileTab.entry"),
|
||||
line1Layout, widgetPlaceholders);
|
||||
placeWidgets(obs_module_text("AdvSceneSwitcher.fileTab.entry2"),
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.fileTab.entry2"),
|
||||
line2Layout, widgetPlaceholders, false);
|
||||
placeWidgets(obs_module_text("AdvSceneSwitcher.fileTab.entry3"),
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.fileTab.entry3"),
|
||||
line3Layout, widgetPlaceholders);
|
||||
mainLayout->addLayout(line1Layout);
|
||||
mainLayout->addLayout(line2Layout);
|
||||
@@ -665,3 +668,5 @@ void FileSwitchWidget::CheckFileContentChanged(int state)
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->onlyMatchIfChanged = state;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -8,8 +8,11 @@
|
||||
#pragma once
|
||||
#include "switch-generic.hpp"
|
||||
#include <QPlainTextEdit>
|
||||
#include <QDateTime>
|
||||
#include <obs-module.h>
|
||||
|
||||
namespace advss {
|
||||
|
||||
constexpr auto read_file_func = 0;
|
||||
|
||||
typedef enum {
|
||||
@@ -77,3 +80,5 @@ static inline QString MakeFileSwitchName(const QString &scene,
|
||||
const QString &fileName,
|
||||
const QString &text, bool useRegex,
|
||||
bool useTime, bool onlyMatchIfChanged);
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
constexpr auto previous_scene_name = "Previous Scene";
|
||||
constexpr auto current_transition_name = "Current Transition";
|
||||
|
||||
namespace advss {
|
||||
|
||||
static inline bool SceneGroupValid(SceneGroup *group)
|
||||
{
|
||||
if (group) {
|
||||
@@ -208,9 +214,9 @@ SwitchWidget::SwitchWidget(QWidget *parent, SceneSwitcherEntry *s,
|
||||
SIGNAL(SceneGroupRenamed(const QString &, const QString &)),
|
||||
this, SLOT(SceneGroupRename(const QString &, const QString &)));
|
||||
|
||||
populateSceneSelection(scenes, usePreviousScene, false, false,
|
||||
PopulateSceneSelection(scenes, usePreviousScene, false, false,
|
||||
addSceneGroup, &switcher->sceneGroups);
|
||||
populateTransitionSelection(transitions, addCurrentTransition);
|
||||
PopulateTransitionSelection(transitions, addCurrentTransition);
|
||||
|
||||
switchData = s;
|
||||
showSwitchData();
|
||||
@@ -300,3 +306,5 @@ void SwitchWidget::TransitionChanged(const QString &text)
|
||||
switchData->transition = GetWeakTransitionByQString(text);
|
||||
switchData->useCurrentTransition = switchData->transition == nullptr;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include "scene-group.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
enum class SwitchTargetType {
|
||||
Scene,
|
||||
SceneGroup,
|
||||
@@ -95,3 +97,5 @@ protected:
|
||||
|
||||
SceneSwitcherEntry *switchData;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "platform-funcs.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <regex>
|
||||
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "utility.hpp"
|
||||
namespace advss {
|
||||
|
||||
bool IdleData::pause = false;
|
||||
IdleWidget *idleWidget = nullptr;
|
||||
@@ -38,7 +42,7 @@ bool SwitcherData::checkIdleSwitch(OBSWeakSource &scene,
|
||||
}
|
||||
}
|
||||
|
||||
if (!ignoreIdle && secondsSinceLastInput() > idleData.time) {
|
||||
if (!ignoreIdle && SecondsSinceLastInput() > idleData.time) {
|
||||
if (idleData.alreadySwitched) {
|
||||
return false;
|
||||
}
|
||||
@@ -205,9 +209,9 @@ void SwitcherData::loadIdleSwitches(obs_data_t *obj)
|
||||
idleData.load(obj);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupIdleTab()
|
||||
void AdvSceneSwitcher::SetupIdleTab()
|
||||
{
|
||||
populateWindowSelection(ui->ignoreIdleWindowsWindows);
|
||||
PopulateWindowSelection(ui->ignoreIdleWindowsWindows);
|
||||
|
||||
for (auto &window : switcher->ignoreIdleWindows) {
|
||||
QString text = QString::fromStdString(window);
|
||||
@@ -267,7 +271,7 @@ IdleWidget::IdleWidget(QWidget *parent, IdleData *s)
|
||||
{"{{duration}}", duration},
|
||||
{"{{scenes}}", scenes},
|
||||
{"{{transitions}}", transitions}};
|
||||
placeWidgets(obs_module_text("AdvSceneSwitcher.idleTab.idleswitch"),
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.idleTab.idleswitch"),
|
||||
mainLayout, widgetPlaceholders);
|
||||
setLayout(mainLayout);
|
||||
|
||||
@@ -285,3 +289,5 @@ void IdleWidget::DurationChanged(int dur)
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->idleData.time = dur;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#pragma once
|
||||
#include "switch-generic.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
constexpr auto default_idle_time = 60;
|
||||
constexpr auto idle_func = 2;
|
||||
|
||||
@@ -36,3 +38,5 @@ private:
|
||||
|
||||
IdleData *switchData;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
bool MediaSwitch::pause = false;
|
||||
static QMetaObject::Connection addPulse;
|
||||
|
||||
@@ -232,7 +235,7 @@ void SwitcherData::loadMediaSwitches(obs_data_t *obj)
|
||||
obs_data_array_release(mediaArray);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupMediaTab()
|
||||
void AdvSceneSwitcher::SetupMediaTab()
|
||||
{
|
||||
for (auto &s : switcher->mediaSwitches) {
|
||||
QListWidgetItem *item;
|
||||
@@ -460,7 +463,7 @@ MediaSwitchWidget::MediaSwitchWidget(QWidget *parent, MediaSwitch *s)
|
||||
QWidget::connect(time, SIGNAL(valueChanged(int)), this,
|
||||
SLOT(TimeChanged(int)));
|
||||
|
||||
populateMediaSelection(mediaSources);
|
||||
PopulateMediaSelection(mediaSources);
|
||||
populateMediaStates(states);
|
||||
populateTimeRestrictions(timeRestrictions);
|
||||
|
||||
@@ -483,7 +486,7 @@ MediaSwitchWidget::MediaSwitchWidget(QWidget *parent, MediaSwitch *s)
|
||||
{"{{time}}", time},
|
||||
{"{{scenes}}", scenes},
|
||||
{"{{transitions}}", transitions}};
|
||||
placeWidgets(obs_module_text("AdvSceneSwitcher.mediaTab.entry"),
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.mediaTab.entry"),
|
||||
mainLayout, widgetPlaceholders);
|
||||
setLayout(mainLayout);
|
||||
|
||||
@@ -560,3 +563,5 @@ void MediaSwitchWidget::TimeChanged(int time)
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->time = time;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#pragma once
|
||||
#include "switch-generic.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
constexpr auto media_func = 6;
|
||||
|
||||
typedef enum {
|
||||
@@ -83,3 +85,5 @@ private:
|
||||
|
||||
MediaSwitch *switchData;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -7,8 +7,12 @@ Most of this code is based on https://github.com/Palakis/obs-websocket
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "scene-switch-helpers.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
#define PARAM_SERVER_ENABLE "ServerEnabled"
|
||||
#define PARAM_SERVER_PORT "ServerPort"
|
||||
#define PARAM_LOCKTOIPV4 "LockToIPv4"
|
||||
@@ -124,10 +128,9 @@ WSServer::WSServer() : QObject(nullptr), _connections(), _clMutex()
|
||||
_server.set_reuse_addr(true);
|
||||
#endif
|
||||
|
||||
_server.set_open_handler(bind(&WSServer::onOpen, this, ::_1));
|
||||
_server.set_close_handler(bind(&WSServer::onClose, this, ::_1));
|
||||
_server.set_message_handler(
|
||||
bind(&WSServer::onMessage, this, ::_1, ::_2));
|
||||
_server.set_open_handler(bind(&WSServer::onOpen, this, _1));
|
||||
_server.set_close_handler(bind(&WSServer::onClose, this, _1));
|
||||
_server.set_message_handler(bind(&WSServer::onMessage, this, _1, _2));
|
||||
}
|
||||
|
||||
WSServer::~WSServer()
|
||||
@@ -221,7 +224,7 @@ void WSServer::stop()
|
||||
blog(LOG_INFO, "server stopped successfully");
|
||||
}
|
||||
|
||||
void WSServer::sendMessage(sceneSwitchInfo sceneSwitch, bool preview)
|
||||
void WSServer::sendMessage(SceneSwitchInfo sceneSwitch, bool preview)
|
||||
{
|
||||
if (!sceneSwitch.scene) {
|
||||
return;
|
||||
@@ -305,9 +308,9 @@ std::string processMessage(std::string payload)
|
||||
"'";
|
||||
}
|
||||
if (preview) {
|
||||
switchPreviewScene(scene);
|
||||
SwitchPreviewScene(scene);
|
||||
} else {
|
||||
switchScene({scene, transition, duration});
|
||||
SwitchScene({scene, transition, duration});
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -361,11 +364,10 @@ WSClient::WSClient() : QObject(nullptr)
|
||||
_client.set_reuse_addr(true);
|
||||
#endif
|
||||
|
||||
_client.set_open_handler(bind(&WSClient::onOpen, this, ::_1));
|
||||
_client.set_fail_handler(bind(&WSClient::onFail, this, ::_1));
|
||||
_client.set_message_handler(
|
||||
bind(&WSClient::onMessage, this, ::_1, ::_2));
|
||||
_client.set_close_handler(bind(&WSClient::onClose, this, ::_1));
|
||||
_client.set_open_handler(bind(&WSClient::onOpen, this, _1));
|
||||
_client.set_fail_handler(bind(&WSClient::onFail, this, _1));
|
||||
_client.set_message_handler(bind(&WSClient::onMessage, this, _1, _2));
|
||||
_client.set_close_handler(bind(&WSClient::onClose, this, _1));
|
||||
}
|
||||
|
||||
WSClient::~WSClient()
|
||||
@@ -501,7 +503,7 @@ void SwitcherData::saveNetworkSwitches(obs_data_t *obj)
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupNetworkTab()
|
||||
void AdvSceneSwitcher::SetupNetworkTab()
|
||||
{
|
||||
ui->serverSettings->setChecked(switcher->networkConfig.ServerEnabled);
|
||||
ui->serverPort->setValue(switcher->networkConfig.ServerPort);
|
||||
@@ -519,9 +521,9 @@ void AdvSceneSwitcher::setupNetworkTab()
|
||||
|
||||
QTimer *statusTimer = new QTimer(this);
|
||||
connect(statusTimer, SIGNAL(timeout()), this,
|
||||
SLOT(updateClientStatus()));
|
||||
SLOT(UpdateClientStatus()));
|
||||
connect(statusTimer, SIGNAL(timeout()), this,
|
||||
SLOT(updateServerStatus()));
|
||||
SLOT(UpdateServerStatus()));
|
||||
statusTimer->start(500);
|
||||
}
|
||||
|
||||
@@ -572,7 +574,7 @@ void AdvSceneSwitcher::on_serverRestart_clicked()
|
||||
switcher->networkConfig.LockToIPv4);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::updateServerStatus()
|
||||
void AdvSceneSwitcher::UpdateServerStatus()
|
||||
{
|
||||
switch (switcher->serverStatus) {
|
||||
case ServerStatus::NOT_RUNNING:
|
||||
@@ -670,7 +672,7 @@ void AdvSceneSwitcher::on_clientReconnect_clicked()
|
||||
switcher->client.connect(switcher->networkConfig.GetClientUri());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::updateClientStatus()
|
||||
void AdvSceneSwitcher::UpdateClientStatus()
|
||||
{
|
||||
switch (switcher->clientStatus) {
|
||||
case ClientStatus::DISCONNECTED:
|
||||
@@ -709,3 +711,5 @@ Compatability::StdFunctionRunnable::StdFunctionRunnable(
|
||||
: cb(std::move(func))
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -19,11 +19,13 @@ Most of this code is based on https://github.com/Palakis/obs-websocket
|
||||
#include <websocketpp/server.hpp>
|
||||
#include <websocketpp/client.hpp>
|
||||
|
||||
namespace advss {
|
||||
|
||||
using websocketpp::connection_hdl;
|
||||
typedef websocketpp::server<websocketpp::config::asio> server;
|
||||
typedef websocketpp::client<websocketpp::config::asio_client> client;
|
||||
|
||||
struct sceneSwitchInfo;
|
||||
struct SceneSwitchInfo;
|
||||
|
||||
class NetworkConfig {
|
||||
public:
|
||||
@@ -60,7 +62,7 @@ public:
|
||||
virtual ~WSServer();
|
||||
void start(quint16 port, bool lockToIPv4);
|
||||
void stop();
|
||||
void sendMessage(sceneSwitchInfo sceneSwitch, bool preview = false);
|
||||
void sendMessage(SceneSwitchInfo sceneSwitch, bool preview = false);
|
||||
QThreadPool *threadPool() { return &_threadPool; }
|
||||
|
||||
private:
|
||||
@@ -131,3 +133,5 @@ public:
|
||||
|
||||
QRunnable *CreateFunctionRunnable(std::function<void()> func);
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <regex>
|
||||
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "utility.hpp"
|
||||
namespace advss {
|
||||
|
||||
static QMetaObject::Connection addPulse;
|
||||
|
||||
@@ -244,7 +247,7 @@ void SwitcherData::loadPauseSwitches(obs_data_t *obj)
|
||||
obs_data_array_release(pauseArray);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupPauseTab()
|
||||
void AdvSceneSwitcher::SetupPauseTab()
|
||||
{
|
||||
for (auto &s : switcher->pauseEntries) {
|
||||
QListWidgetItem *item;
|
||||
@@ -309,7 +312,7 @@ PauseEntryWidget::PauseEntryWidget(QWidget *parent, PauseEntry *s)
|
||||
|
||||
populatePauseTypes(pauseTypes);
|
||||
populatePauseTargets(pauseTargets);
|
||||
populateWindowSelection(windows);
|
||||
PopulateWindowSelection(windows);
|
||||
|
||||
windows->setEditable(true);
|
||||
windows->setMaxVisibleItems(20);
|
||||
@@ -335,7 +338,7 @@ PauseEntryWidget::PauseEntryWidget(QWidget *parent, PauseEntry *s)
|
||||
{"{{pauseTargets}}", pauseTargets},
|
||||
{"{{windows}}", windows}};
|
||||
|
||||
placeWidgets(obs_module_text("AdvSceneSwitcher.pauseTab.pauseEntry"),
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.pauseTab.pauseEntry"),
|
||||
mainLayout, widgetPlaceholders);
|
||||
setLayout(mainLayout);
|
||||
|
||||
@@ -410,3 +413,5 @@ bool PauseEntry::valid()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#pragma once
|
||||
#include "switch-generic.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
enum class PauseType {
|
||||
Scene,
|
||||
Window,
|
||||
@@ -70,3 +72,5 @@ private:
|
||||
|
||||
PauseEntry *switchData;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
|
||||
void AdvSceneSwitcher::on_threadPriority_currentTextChanged(const QString &text)
|
||||
{
|
||||
if (loading || ui->threadPriority->count() !=
|
||||
(int)switcher->threadPriorities.size())
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
for (auto p : switcher->threadPriorities) {
|
||||
if (p.name == text.toUtf8().constData()) {
|
||||
switcher->threadPriority = p.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_priorityUp_clicked()
|
||||
{
|
||||
int currentIndex = ui->priorityList->currentRow();
|
||||
if (currentIndex != -1 && currentIndex != 0) {
|
||||
ui->priorityList->insertItem(
|
||||
currentIndex - 1,
|
||||
ui->priorityList->takeItem(currentIndex));
|
||||
ui->priorityList->setCurrentRow(currentIndex - 1);
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
iter_swap(switcher->functionNamesByPriority.begin() +
|
||||
currentIndex,
|
||||
switcher->functionNamesByPriority.begin() +
|
||||
currentIndex - 1);
|
||||
}
|
||||
ui->macroPriorityWarning->setVisible(
|
||||
switcher->functionNamesByPriority[0] != macro_func);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_priorityDown_clicked()
|
||||
{
|
||||
int currentIndex = ui->priorityList->currentRow();
|
||||
if (currentIndex != -1 &&
|
||||
currentIndex != ui->priorityList->count() - 1) {
|
||||
ui->priorityList->insertItem(
|
||||
currentIndex + 1,
|
||||
ui->priorityList->takeItem(currentIndex));
|
||||
ui->priorityList->setCurrentRow(currentIndex + 1);
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
|
||||
iter_swap(switcher->functionNamesByPriority.begin() +
|
||||
currentIndex,
|
||||
switcher->functionNamesByPriority.begin() +
|
||||
currentIndex + 1);
|
||||
}
|
||||
ui->macroPriorityWarning->setVisible(
|
||||
switcher->functionNamesByPriority[0] != macro_func);
|
||||
}
|
||||
|
||||
bool SwitcherData::prioFuncsValid()
|
||||
{
|
||||
auto fNBPCopy = functionNamesByPriority;
|
||||
|
||||
std::sort(fNBPCopy.begin(), fNBPCopy.end());
|
||||
auto it = std::unique(fNBPCopy.begin(), fNBPCopy.end());
|
||||
bool wasUnique = (it == fNBPCopy.end());
|
||||
|
||||
if (!wasUnique) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int p : functionNamesByPriority) {
|
||||
if (p < 0 || p > 10) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1,7 +1,10 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <random>
|
||||
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "utility.hpp"
|
||||
namespace advss {
|
||||
|
||||
bool RandomSwitch::pause = false;
|
||||
static QMetaObject::Connection addPulse;
|
||||
@@ -113,7 +116,7 @@ void SwitcherData::loadRandomSwitches(obs_data_t *obj)
|
||||
obs_data_array_release(randomArray);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupRandomTab()
|
||||
void AdvSceneSwitcher::SetupRandomTab()
|
||||
{
|
||||
for (auto &s : switcher->randomSwitches) {
|
||||
QListWidgetItem *item;
|
||||
@@ -140,7 +143,7 @@ void AdvSceneSwitcher::setupRandomTab()
|
||||
border-radius: 7px; \
|
||||
border-color: rgb(0,0,0,0) \
|
||||
}");
|
||||
if (switcher->switchIfNotMatching != RANDOM_SWITCH) {
|
||||
if (switcher->switchIfNotMatching != NoMatchBehavior::RANDOM_SWITCH) {
|
||||
if (!switcher->disableHints) {
|
||||
PulseWidget(ui->randomDisabledWarning, QColor(Qt::red),
|
||||
QColor(0, 0, 0, 0));
|
||||
@@ -182,7 +185,7 @@ RandomSwitchWidget::RandomSwitchWidget(QWidget *parent, RandomSwitch *s)
|
||||
{"{{scenes}}", scenes},
|
||||
{"{{transitions}}", transitions},
|
||||
{"{{delay}}", delay}};
|
||||
placeWidgets(obs_module_text("AdvSceneSwitcher.randomTab.entry"),
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.randomTab.entry"),
|
||||
mainLayout, widgetPlaceholders);
|
||||
setLayout(mainLayout);
|
||||
|
||||
@@ -220,3 +223,5 @@ void RandomSwitchWidget::DelayChanged(double d)
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->delay = d;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#pragma once
|
||||
#include "switch-generic.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
struct RandomSwitch : SceneSwitcherEntry {
|
||||
static bool pause;
|
||||
double delay = 0.0;
|
||||
@@ -36,3 +38,5 @@ private:
|
||||
|
||||
RandomSwitch *switchData;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "utility.hpp"
|
||||
namespace advss {
|
||||
|
||||
bool ScreenRegionSwitch::pause = false;
|
||||
static QMetaObject::Connection addPulse;
|
||||
|
||||
void AdvSceneSwitcher::clearFrames(QListWidget *list)
|
||||
void AdvSceneSwitcher::ClearFrames(QListWidget *list)
|
||||
{
|
||||
for (int i = 0; i < list->count(); ++i) {
|
||||
ScreenRegionWidget *sw =
|
||||
@@ -48,7 +51,7 @@ void AdvSceneSwitcher::on_showFrame_clicked()
|
||||
showCurrentFrame(ui->screenRegionSwitches);
|
||||
} else {
|
||||
SetShowFrames();
|
||||
clearFrames(ui->screenRegionSwitches);
|
||||
ClearFrames(ui->screenRegionSwitches);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +62,7 @@ void AdvSceneSwitcher::on_screenRegionSwitches_currentRowChanged(int idx)
|
||||
}
|
||||
|
||||
if (switcher->showFrame) {
|
||||
clearFrames(ui->screenRegionSwitches);
|
||||
ClearFrames(ui->screenRegionSwitches);
|
||||
showCurrentFrame(ui->screenRegionSwitches);
|
||||
}
|
||||
}
|
||||
@@ -153,7 +156,7 @@ bool SwitcherData::checkScreenRegionSwitch(OBSWeakSource &scene,
|
||||
return false;
|
||||
}
|
||||
|
||||
std::pair<int, int> cursorPos = getCursorPos();
|
||||
std::pair<int, int> cursorPos = GetCursorPos();
|
||||
int minRegionSize = 99999;
|
||||
bool match = false;
|
||||
|
||||
@@ -188,7 +191,7 @@ bool SwitcherData::checkScreenRegionSwitch(OBSWeakSource &scene,
|
||||
|
||||
void AdvSceneSwitcher::updateScreenRegionCursorPos()
|
||||
{
|
||||
std::pair<int, int> position = getCursorPos();
|
||||
std::pair<int, int> position = GetCursorPos();
|
||||
ui->cursorXPosition->setText(QString::number(position.first));
|
||||
ui->cursorYPosition->setText(QString::number(position.second));
|
||||
}
|
||||
@@ -228,7 +231,7 @@ void SwitcherData::loadScreenRegionSwitches(obs_data_t *obj)
|
||||
obs_data_array_release(screenRegionArray);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupRegionTab()
|
||||
void AdvSceneSwitcher::SetupRegionTab()
|
||||
{
|
||||
for (auto &s : switcher->screenRegionSwitches) {
|
||||
QListWidgetItem *item;
|
||||
@@ -318,7 +321,7 @@ ScreenRegionWidget::ScreenRegionWidget(QWidget *parent, ScreenRegionSwitch *s)
|
||||
QWidget::connect(maxY, SIGNAL(valueChanged(int)), this,
|
||||
SLOT(MaxYChanged(int)));
|
||||
|
||||
populateSceneSelection(
|
||||
PopulateSceneSelection(
|
||||
excludeScenes, false, false, false, false, nullptr, true,
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.screenRegionTab.excludeScenes.None"),
|
||||
@@ -342,7 +345,7 @@ ScreenRegionWidget::ScreenRegionWidget(QWidget *parent, ScreenRegionSwitch *s)
|
||||
{"{{scenes}}", scenes},
|
||||
{"{{transitions}}", transitions},
|
||||
{"{{excludeScenes}}", excludeScenes}};
|
||||
placeWidgets(obs_module_text("AdvSceneSwitcher.screenRegionTab.entry"),
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.screenRegionTab.entry"),
|
||||
mainLayout, widgetPlaceholders);
|
||||
setLayout(mainLayout);
|
||||
|
||||
@@ -455,3 +458,5 @@ void ScreenRegionWidget::drawFrame()
|
||||
switchData->maxY - switchData->minY);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include <QSpinBox>
|
||||
#include "switch-generic.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
constexpr auto screen_region_func = 4;
|
||||
|
||||
struct ScreenRegionSwitch : SceneSwitcherEntry {
|
||||
@@ -55,3 +57,5 @@ private:
|
||||
|
||||
void drawFrame();
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QTextStream>
|
||||
#include <QScrollArea>
|
||||
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "utility.hpp"
|
||||
namespace advss {
|
||||
|
||||
constexpr auto max_extend_text_size = 150;
|
||||
|
||||
@@ -278,7 +281,7 @@ void SwitcherData::loadSceneSequenceSwitches(obs_data_t *obj)
|
||||
obs_data_array_release(sceneSequenceArray);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupSequenceTab()
|
||||
void AdvSceneSwitcher::SetupSequenceTab()
|
||||
{
|
||||
for (auto &s : switcher->sceneSequenceSwitches) {
|
||||
QListWidgetItem *item;
|
||||
@@ -601,7 +604,7 @@ SequenceWidget::SequenceWidget(QWidget *parent, SceneSequenceSwitch *s,
|
||||
QWidget::connect(reduce, SIGNAL(clicked()), this,
|
||||
SLOT(ReduceClicked()));
|
||||
|
||||
populateSceneSelection(startScenes);
|
||||
PopulateSceneSelection(startScenes);
|
||||
interruptible->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.sceneSequenceTab.interruptibleHint"));
|
||||
|
||||
@@ -613,7 +616,7 @@ SequenceWidget::SequenceWidget(QWidget *parent, SceneSequenceSwitch *s,
|
||||
{"{{scenes}}", scenes},
|
||||
{"{{delay}}", delay},
|
||||
{"{{transitions}}", transitions}};
|
||||
placeWidgets(
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.sceneSequenceTab.extendEntry"),
|
||||
mainLayout, widgetPlaceholders);
|
||||
@@ -626,7 +629,7 @@ SequenceWidget::SequenceWidget(QWidget *parent, SceneSequenceSwitch *s,
|
||||
{"{{delay}}", delay},
|
||||
{"{{transitions}}", transitions},
|
||||
{"{{interruptible}}", interruptible}};
|
||||
placeWidgets(obs_module_text(
|
||||
PlaceWidgets(obs_module_text(
|
||||
"AdvSceneSwitcher.sceneSequenceTab.entry"),
|
||||
startSequence, widgetPlaceholders);
|
||||
|
||||
@@ -793,3 +796,5 @@ void SequenceWidget::ReduceClicked()
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#include "switch-generic.hpp"
|
||||
#include "duration-control.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
constexpr auto round_trip_func = 1;
|
||||
|
||||
struct SceneSequenceSwitch : SceneSwitcherEntry {
|
||||
@@ -82,3 +84,5 @@ protected:
|
||||
|
||||
SceneSequenceSwitch *switchData;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
bool TimeSwitch::pause = false;
|
||||
static QMetaObject::Connection addPulse;
|
||||
|
||||
@@ -179,7 +182,7 @@ void SwitcherData::loadTimeSwitches(obs_data_t *obj)
|
||||
obs_data_array_release(timeArray);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupTimeTab()
|
||||
void AdvSceneSwitcher::SetupTimeTab()
|
||||
{
|
||||
for (auto &s : switcher->timeSwitches) {
|
||||
QListWidgetItem *item;
|
||||
@@ -258,7 +261,7 @@ TimeSwitchWidget::TimeSwitchWidget(QWidget *parent, TimeSwitch *s)
|
||||
{"{{time}}", time},
|
||||
{"{{scenes}}", scenes},
|
||||
{"{{transitions}}", transitions}};
|
||||
placeWidgets(obs_module_text("AdvSceneSwitcher.timeTab.entry"),
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.timeTab.entry"),
|
||||
mainLayout, widgetPlaceholders);
|
||||
setLayout(mainLayout);
|
||||
|
||||
@@ -306,3 +309,5 @@ void TimeSwitchWidget::TimeChanged(const QTime &time)
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->time = time;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
#include "switch-generic.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
constexpr auto time_func = 7;
|
||||
|
||||
typedef enum {
|
||||
@@ -54,3 +56,5 @@ private:
|
||||
|
||||
TimeSwitch *switchData;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "utility.hpp"
|
||||
namespace advss {
|
||||
|
||||
constexpr auto default_def_transition_dealy = 300;
|
||||
bool DefaultSceneTransition::pause = false;
|
||||
@@ -169,7 +172,7 @@ void SwitcherData::checkDefaultSceneTransitions()
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::defTransitionDelayValueChanged(int value)
|
||||
void AdvSceneSwitcher::DefTransitionDelayValueChanged(int value)
|
||||
{
|
||||
if (loading) {
|
||||
return;
|
||||
@@ -179,104 +182,6 @@ void AdvSceneSwitcher::defTransitionDelayValueChanged(int value)
|
||||
DefaultSceneTransition::delay = value;
|
||||
}
|
||||
|
||||
std::pair<obs_weak_source_t *, int> getNextTransition(obs_weak_source_t *scene1,
|
||||
obs_weak_source_t *scene2)
|
||||
{
|
||||
obs_weak_source_t *ws = nullptr;
|
||||
int duration = 0;
|
||||
if (scene1 && scene2) {
|
||||
for (SceneTransition &t : switcher->sceneTransitions) {
|
||||
if (!t.initialized()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (t.scene == scene1 && t.scene2 == scene2) {
|
||||
ws = t.transition;
|
||||
duration = t.duration * 1000;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::make_pair(ws, duration);
|
||||
}
|
||||
|
||||
void overwriteTransitionOverride(const sceneSwitchInfo &ssi, transitionData &td)
|
||||
{
|
||||
obs_source_t *scene = obs_weak_source_get_source(ssi.scene);
|
||||
obs_data_t *data = obs_source_get_private_settings(scene);
|
||||
|
||||
td.name = obs_data_get_string(data, "transition");
|
||||
td.duration = obs_data_get_int(data, "transition_duration");
|
||||
|
||||
std::string name = GetWeakSourceName(ssi.transition);
|
||||
|
||||
obs_data_set_string(data, "transition", name.c_str());
|
||||
obs_data_set_int(data, "transition_duration", ssi.duration);
|
||||
|
||||
obs_data_release(data);
|
||||
obs_source_release(scene);
|
||||
}
|
||||
|
||||
void restoreTransitionOverride(obs_source_t *scene, const transitionData &td)
|
||||
{
|
||||
obs_data_t *data = obs_source_get_private_settings(scene);
|
||||
|
||||
obs_data_set_string(data, "transition", td.name.c_str());
|
||||
obs_data_set_int(data, "transition_duration", td.duration);
|
||||
|
||||
obs_data_release(data);
|
||||
}
|
||||
|
||||
void setNextTransition(const sceneSwitchInfo &sceneSwitch,
|
||||
obs_source_t *currentSource, transitionData &td)
|
||||
{
|
||||
// Priority:
|
||||
// 1. Transition tab
|
||||
// 2. Individual switcher entry
|
||||
// 3. Current transition settings
|
||||
|
||||
// Transition Tab
|
||||
obs_weak_source_t *currentScene =
|
||||
obs_source_get_weak_source(currentSource);
|
||||
auto tinfo = getNextTransition(currentScene, sceneSwitch.scene);
|
||||
obs_weak_source_release(currentScene);
|
||||
|
||||
OBSWeakSource nextTransition = tinfo.first;
|
||||
int nextTransitionDuration = tinfo.second;
|
||||
|
||||
// Individual switcher entry
|
||||
if (!nextTransition) {
|
||||
nextTransition = sceneSwitch.transition;
|
||||
}
|
||||
if (!nextTransitionDuration) {
|
||||
nextTransitionDuration = sceneSwitch.duration;
|
||||
}
|
||||
|
||||
// Current transition settings
|
||||
if (!nextTransition) {
|
||||
auto ct = obs_frontend_get_current_transition();
|
||||
nextTransition = obs_source_get_weak_source(ct);
|
||||
obs_weak_source_release(nextTransition);
|
||||
obs_source_release(ct);
|
||||
}
|
||||
if (!nextTransitionDuration) {
|
||||
nextTransitionDuration = obs_frontend_get_transition_duration();
|
||||
}
|
||||
|
||||
if (switcher->adjustActiveTransitionType) {
|
||||
obs_frontend_set_transition_duration(nextTransitionDuration);
|
||||
auto t = obs_weak_source_get_source(nextTransition);
|
||||
obs_frontend_set_current_transition(t);
|
||||
obs_source_release(t);
|
||||
}
|
||||
|
||||
if (switcher->transitionOverrideOverride) {
|
||||
overwriteTransitionOverride({sceneSwitch.scene, nextTransition,
|
||||
nextTransitionDuration},
|
||||
td);
|
||||
}
|
||||
}
|
||||
|
||||
void SwitcherData::saveSceneTransitions(obs_data_t *obj)
|
||||
{
|
||||
obs_data_array_t *sceneTransitionsArray = obs_data_array_create();
|
||||
@@ -349,7 +254,7 @@ void SwitcherData::loadSceneTransitions(obs_data_t *obj)
|
||||
obs_data_get_int(obj, "defTransitionDelay");
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupTransitionsTab()
|
||||
void AdvSceneSwitcher::SetupTransitionsTab()
|
||||
{
|
||||
for (auto &s : switcher->sceneTransitions) {
|
||||
QListWidgetItem *item;
|
||||
@@ -397,11 +302,11 @@ void AdvSceneSwitcher::setupTransitionsTab()
|
||||
"AdvSceneSwitcher.transitionTab.defaultTransition.delay.help"));
|
||||
|
||||
QWidget::connect(defTransitionDelay, SIGNAL(valueChanged(int)), this,
|
||||
SLOT(defTransitionDelayValueChanged(int)));
|
||||
SLOT(DefTransitionDelayValueChanged(int)));
|
||||
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{defTransitionDelay}}", defTransitionDelay}};
|
||||
placeWidgets(
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.transitionTab.defaultTransition.delay"),
|
||||
ui->defTransitionDelayLayout, widgetPlaceholders);
|
||||
@@ -449,7 +354,7 @@ TransitionSwitchWidget::TransitionSwitchWidget(QWidget *parent,
|
||||
QWidget::connect(duration, SIGNAL(valueChanged(double)), this,
|
||||
SLOT(DurationChanged(double)));
|
||||
|
||||
populateSceneSelection(scenes2);
|
||||
PopulateSceneSelection(scenes2);
|
||||
|
||||
if (s) {
|
||||
scenes2->setCurrentText(GetWeakSourceName(s->scene2).c_str());
|
||||
@@ -462,7 +367,7 @@ TransitionSwitchWidget::TransitionSwitchWidget(QWidget *parent,
|
||||
{"{{scenes2}}", scenes2},
|
||||
{"{{duration}}", duration},
|
||||
{"{{transitions}}", transitions}};
|
||||
placeWidgets(obs_module_text("AdvSceneSwitcher.transitionTab.entry"),
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.transitionTab.entry"),
|
||||
mainLayout, widgetPlaceholders);
|
||||
setLayout(mainLayout);
|
||||
|
||||
@@ -518,7 +423,7 @@ DefTransitionSwitchWidget::DefTransitionSwitchWidget(QWidget *parent,
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{scenes}}", scenes}, {"{{transitions}}", transitions}};
|
||||
placeWidgets(
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.transitionTab.defaultTransitionEntry"),
|
||||
mainLayout, widgetPlaceholders);
|
||||
@@ -592,3 +497,5 @@ void DefaultSceneTransition::setTransition()
|
||||
t = std::thread(setTransitionDelayed, transition, delay);
|
||||
t.detach();
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include "switch-generic.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
struct SceneTransition : SceneSwitcherEntry {
|
||||
OBSWeakSource scene2 = nullptr;
|
||||
double duration = 0.3;
|
||||
@@ -77,3 +79,5 @@ public:
|
||||
private:
|
||||
DefaultSceneTransition *switchData;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QBuffer>
|
||||
#include <QToolTip>
|
||||
#include <thread>
|
||||
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "utility.hpp"
|
||||
namespace advss {
|
||||
|
||||
bool VideoSwitch::pause = false;
|
||||
static QMetaObject::Connection addPulse;
|
||||
@@ -182,7 +185,7 @@ void SwitcherData::loadVideoSwitches(obs_data_t *obj)
|
||||
obs_data_array_release(videoArray);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupVideoTab()
|
||||
void AdvSceneSwitcher::SetupVideoTab()
|
||||
{
|
||||
for (auto &s : switcher->videoSwitches) {
|
||||
QListWidgetItem *item;
|
||||
@@ -428,7 +431,7 @@ VideoSwitchWidget::VideoSwitchWidget(QWidget *parent, VideoSwitch *s)
|
||||
{"{{ignoreInactiveSource}}", ignoreInactiveSource},
|
||||
{"{{scenes}}", scenes},
|
||||
{"{{transitions}}", transitions}};
|
||||
placeWidgets(obs_module_text("AdvSceneSwitcher.videoTab.entry"),
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.videoTab.entry"),
|
||||
switchLayout, widgetPlaceholders);
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
@@ -577,3 +580,5 @@ void VideoSwitchWidget::IgnoreInactiveChanged(int state)
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->ignoreInactiveSource = state;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#include "switch-generic.hpp"
|
||||
#include "screenshot-helper.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
constexpr auto video_func = 9;
|
||||
|
||||
enum class videoSwitchType {
|
||||
@@ -80,3 +82,5 @@ private:
|
||||
|
||||
VideoSwitch *switchData;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "platform-funcs.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <regex>
|
||||
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "utility.hpp"
|
||||
namespace advss {
|
||||
|
||||
bool WindowSwitch::pause = false;
|
||||
static QMetaObject::Connection addPulse;
|
||||
@@ -177,8 +181,8 @@ void checkWindowTitleSwitchDirect(WindowSwitch &s,
|
||||
OBSWeakSource &transition)
|
||||
{
|
||||
bool focus = (!s.focus || s.window == currentWindowTitle);
|
||||
bool fullscreen = (!s.fullscreen || isFullscreen(s.window));
|
||||
bool max = (!s.maximized || isMaximized(s.window));
|
||||
bool fullscreen = (!s.fullscreen || IsFullscreen(s.window));
|
||||
bool max = (!s.maximized || IsMaximized(s.window));
|
||||
|
||||
if (focus && fullscreen && max) {
|
||||
match = true;
|
||||
@@ -203,8 +207,8 @@ void checkWindowTitleSwitchRegex(WindowSwitch &s,
|
||||
}
|
||||
|
||||
bool focus = (!s.focus || window == currentWindowTitle);
|
||||
bool fullscreen = (!s.fullscreen || isFullscreen(window));
|
||||
bool max = (!s.maximized || isMaximized(window));
|
||||
bool fullscreen = (!s.fullscreen || IsFullscreen(window));
|
||||
bool max = (!s.maximized || IsMaximized(window));
|
||||
|
||||
if (focus && fullscreen && max) {
|
||||
match = true;
|
||||
@@ -315,7 +319,7 @@ void SwitcherData::loadWindowTitleSwitches(obs_data_t *obj)
|
||||
obs_data_array_release(ignoreWindowsArray);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::setupTitleTab()
|
||||
void AdvSceneSwitcher::SetupTitleTab()
|
||||
{
|
||||
for (auto &s : switcher->windowSwitches) {
|
||||
QListWidgetItem *item;
|
||||
@@ -336,7 +340,7 @@ void AdvSceneSwitcher::setupTitleTab()
|
||||
ui->windowHelp->setVisible(false);
|
||||
}
|
||||
|
||||
populateWindowSelection(ui->ignoreWindowsWindows);
|
||||
PopulateWindowSelection(ui->ignoreWindowsWindows);
|
||||
|
||||
for (auto &window : switcher->ignoreWindowsSwitches) {
|
||||
QString text = QString::fromStdString(window);
|
||||
@@ -394,7 +398,7 @@ WindowSwitchWidget::WindowSwitchWidget(QWidget *parent, WindowSwitch *s)
|
||||
QWidget::connect(focused, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(FocusChanged(int)));
|
||||
|
||||
populateWindowSelection(windows);
|
||||
PopulateWindowSelection(windows);
|
||||
|
||||
windows->setEditable(true);
|
||||
windows->setMaxVisibleItems(20);
|
||||
@@ -414,7 +418,7 @@ WindowSwitchWidget::WindowSwitchWidget(QWidget *parent, WindowSwitch *s)
|
||||
{"{{fullscreen}}", fullscreen},
|
||||
{"{{maximized}}", maximized},
|
||||
{"{{focused}}", focused}};
|
||||
placeWidgets(obs_module_text("AdvSceneSwitcher.windowTitleTab.entry"),
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.windowTitleTab.entry"),
|
||||
mainLayout, widgetPlaceholders);
|
||||
setLayout(mainLayout);
|
||||
|
||||
@@ -482,3 +486,5 @@ void WindowSwitchWidget::FocusChanged(int state)
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switchData->focus = state;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#pragma once
|
||||
#include "switch-generic.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
constexpr auto window_title_func = 5;
|
||||
|
||||
struct WindowSwitch : SceneSwitcherEntry {
|
||||
@@ -47,3 +49,5 @@ private:
|
||||
|
||||
WindowSwitch *switchData;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "platform-funcs.hpp"
|
||||
#include "hotkey.hpp"
|
||||
#include "log-helper.hpp"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
@@ -25,14 +26,17 @@
|
||||
#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>
|
||||
#include <sstream>
|
||||
|
||||
namespace advss {
|
||||
|
||||
static Display *xdisplay = 0;
|
||||
|
||||
static QLibrary *libXtstHandle = nullptr;
|
||||
@@ -51,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) {
|
||||
@@ -315,7 +344,7 @@ bool windowStatesAreSet(const std::string &windowTitle,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isMaximized(const std::string &title)
|
||||
bool IsMaximized(const std::string &title)
|
||||
{
|
||||
std::vector<QString> states;
|
||||
states.emplace_back("_NET_WM_STATE_MAXIMIZED_VERT");
|
||||
@@ -323,53 +352,70 @@ bool isMaximized(const std::string &title)
|
||||
return windowStatesAreSet(title, states);
|
||||
}
|
||||
|
||||
bool isFullscreen(const std::string &title)
|
||||
bool IsFullscreen(const std::string &title)
|
||||
{
|
||||
std::vector<QString> states;
|
||||
states.emplace_back("_NET_WM_STATE_FULLSCREEN");
|
||||
return windowStatesAreSet(title, states);
|
||||
}
|
||||
|
||||
#ifdef USE_PROCPS
|
||||
void GetProcessList(QStringList &processes)
|
||||
std::optional<std::string> GetTextInWindow(const std::string &)
|
||||
{
|
||||
processes.clear();
|
||||
PROCTAB *proc = openproc(PROC_FILLSTAT);
|
||||
// Not implemented
|
||||
return {};
|
||||
}
|
||||
|
||||
static void getProcessListProcps(QStringList &processes)
|
||||
{
|
||||
#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()
|
||||
{
|
||||
@@ -428,7 +474,7 @@ void GetForegroundProcessName(std::string &proc)
|
||||
proc = getProcNameFromPid(pid);
|
||||
}
|
||||
|
||||
bool isInFocus(const QString &executable)
|
||||
bool IsInFocus(const QString &executable)
|
||||
{
|
||||
std::string current;
|
||||
GetForegroundProcessName(current);
|
||||
@@ -442,7 +488,7 @@ bool isInFocus(const QString &executable)
|
||||
return (equals || matches);
|
||||
}
|
||||
|
||||
int secondsSinceLastInput()
|
||||
int SecondsSinceLastInput()
|
||||
{
|
||||
if (!canGetIdleTime) {
|
||||
return 0;
|
||||
@@ -509,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},
|
||||
@@ -625,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();
|
||||
@@ -632,30 +733,27 @@ 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();
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#include "macro-action-audio.hpp"
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
constexpr int64_t nsPerMs = 1000000;
|
||||
const std::string MacroActionAudio::id = "audio";
|
||||
|
||||
@@ -34,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,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;
|
||||
@@ -68,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)
|
||||
@@ -85,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,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;
|
||||
}
|
||||
@@ -285,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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,7 +367,7 @@ MacroActionAudioEdit::MacroActionAudioEdit(
|
||||
sources.sort();
|
||||
_sources->SetSourceNameList(sources);
|
||||
populateFadeTypeSelection(_fadeTypes);
|
||||
populateMonitorTypeSelection(_monitorTypes);
|
||||
PopulateMonitorTypeSelection(_monitorTypes);
|
||||
|
||||
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(ActionChanged(int)));
|
||||
@@ -395,10 +418,10 @@ MacroActionAudioEdit::MacroActionAudioEdit(
|
||||
{"{{fadeTypes}}", _fadeTypes},
|
||||
};
|
||||
QHBoxLayout *entryLayout = new QHBoxLayout;
|
||||
placeWidgets(obs_module_text("AdvSceneSwitcher.action.audio.entry"),
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.audio.entry"),
|
||||
entryLayout, widgetPlaceholders);
|
||||
_fadeTypeLayout = new QHBoxLayout;
|
||||
placeWidgets(
|
||||
PlaceWidgets(
|
||||
obs_module_text("AdvSceneSwitcher.action.audio.fade.duration"),
|
||||
_fadeTypeLayout, widgetPlaceholders);
|
||||
|
||||
@@ -417,7 +440,7 @@ MacroActionAudioEdit::MacroActionAudioEdit(
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
bool hasVolumeControl(MacroActionAudio::Action action)
|
||||
static bool hasVolumeControl(MacroActionAudio::Action action)
|
||||
{
|
||||
return action == MacroActionAudio::Action::SOURCE_VOLUME ||
|
||||
action == MacroActionAudio::Action::MASTER_VOLUME;
|
||||
@@ -435,17 +458,11 @@ void MacroActionAudioEdit::SetWidgetVisibility()
|
||||
_balance->setVisible(_entryData->_action ==
|
||||
MacroActionAudio::Action::BALANCE);
|
||||
|
||||
_fadeTypes->setDisabled(!_entryData->_fade);
|
||||
_wait->setDisabled(!_entryData->_fade);
|
||||
_abortActiveFade->setDisabled(!_entryData->_fade);
|
||||
_duration->setDisabled(!_entryData->_fade);
|
||||
_rate->setDisabled(!_entryData->_fade);
|
||||
|
||||
_fadeTypeLayout->removeWidget(_fade);
|
||||
_fadeTypeLayout->removeWidget(_fadeTypes);
|
||||
_fadeTypeLayout->removeWidget(_duration);
|
||||
_fadeTypeLayout->removeWidget(_rate);
|
||||
clearLayout(_fadeTypeLayout);
|
||||
ClearLayout(_fadeTypeLayout);
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{fade}}", _fade},
|
||||
{"{{duration}}", _duration},
|
||||
@@ -453,12 +470,12 @@ void MacroActionAudioEdit::SetWidgetVisibility()
|
||||
{"{{fadeTypes}}", _fadeTypes},
|
||||
};
|
||||
if (_entryData->_fadeType == MacroActionAudio::FadeType::DURATION) {
|
||||
placeWidgets(
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.audio.fade.duration"),
|
||||
_fadeTypeLayout, widgetPlaceholders);
|
||||
} else {
|
||||
placeWidgets(obs_module_text(
|
||||
PlaceWidgets(obs_module_text(
|
||||
"AdvSceneSwitcher.action.audio.fade.rate"),
|
||||
_fadeTypeLayout, widgetPlaceholders);
|
||||
}
|
||||
@@ -468,10 +485,24 @@ void MacroActionAudioEdit::SetWidgetVisibility()
|
||||
_rate->setVisible(_entryData->_fadeType ==
|
||||
MacroActionAudio::FadeType::RATE);
|
||||
|
||||
setLayoutVisible(_fadeTypeLayout,
|
||||
SetLayoutVisible(_fadeTypeLayout,
|
||||
hasVolumeControl(_entryData->_action));
|
||||
setLayoutVisible(_fadeOptionsLayout,
|
||||
SetLayoutVisible(_fadeOptionsLayout,
|
||||
hasVolumeControl(_entryData->_action));
|
||||
_abortActiveFade->setVisible(hasVolumeControl(_entryData->_action) &&
|
||||
_entryData->_fade);
|
||||
_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();
|
||||
}
|
||||
|
||||
@@ -503,7 +534,7 @@ void MacroActionAudioEdit::SourceChanged(const SourceSelection &source)
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->_audioSource = source;
|
||||
emit HeaderInfoChanged(
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
@@ -515,7 +546,7 @@ void MacroActionAudioEdit::ActionChanged(int idx)
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->_action = static_cast<MacroActionAudio::Action>(
|
||||
_actions->itemData(idx).toInt());
|
||||
SetWidgetVisibility();
|
||||
@@ -527,7 +558,7 @@ void MacroActionAudioEdit::SyncOffsetChanged(const NumberVariable<int> &value)
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->_syncOffset = value;
|
||||
}
|
||||
|
||||
@@ -537,7 +568,7 @@ void MacroActionAudioEdit::MonitorTypeChanged(int value)
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->_monitorType = static_cast<obs_monitoring_type>(value);
|
||||
}
|
||||
|
||||
@@ -547,7 +578,7 @@ void MacroActionAudioEdit::BalanceChanged(const NumberVariable<double> &value)
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->_balance = value;
|
||||
}
|
||||
|
||||
@@ -557,7 +588,7 @@ void MacroActionAudioEdit::VolumeChanged(const NumberVariable<int> &value)
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->_volume = value;
|
||||
}
|
||||
|
||||
@@ -567,7 +598,7 @@ void MacroActionAudioEdit::FadeChanged(int value)
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->_fade = value;
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
@@ -578,7 +609,7 @@ void MacroActionAudioEdit::DurationChanged(const Duration &dur)
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->_duration = dur;
|
||||
}
|
||||
|
||||
@@ -588,7 +619,7 @@ void MacroActionAudioEdit::RateChanged(const NumberVariable<double> &value)
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->_rate = value;
|
||||
}
|
||||
|
||||
@@ -598,7 +629,7 @@ void MacroActionAudioEdit::WaitChanged(int value)
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->_wait = value;
|
||||
}
|
||||
|
||||
@@ -608,7 +639,7 @@ void MacroActionAudioEdit::AbortActiveFadeChanged(int value)
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->_abortActiveFade = value;
|
||||
}
|
||||
|
||||
@@ -618,7 +649,9 @@ void MacroActionAudioEdit::FadeTypeChanged(int value)
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->_fadeType = static_cast<MacroActionAudio::FadeType>(value);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include <QCheckBox>
|
||||
#include <QHBoxLayout>
|
||||
|
||||
namespace advss {
|
||||
|
||||
class MacroActionAudio : public MacroAction {
|
||||
public:
|
||||
MacroActionAudio(Macro *m) : MacroAction(m) {}
|
||||
@@ -119,3 +121,5 @@ private:
|
||||
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
||||
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
@@ -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,64 +1,20 @@
|
||||
#include "advanced-scene-switcher.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"
|
||||
#include "utility.hpp"
|
||||
|
||||
std::map<std::string, MacroActionInfo> &MacroActionFactory::GetMap()
|
||||
{
|
||||
static std::map<std::string, MacroActionInfo> _methods;
|
||||
return _methods;
|
||||
}
|
||||
#include <QGraphicsOpacityEffect>
|
||||
|
||||
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 "";
|
||||
}
|
||||
namespace advss {
|
||||
|
||||
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);
|
||||
@@ -74,27 +30,34 @@ static inline void populateActionSelection(QComboBox *list)
|
||||
MacroActionEdit::MacroActionEdit(QWidget *parent,
|
||||
std::shared_ptr<MacroAction> *entryData,
|
||||
const std::string &id)
|
||||
: MacroSegmentEdit(switcher->macroProperties._highlightActions, parent),
|
||||
_actionSelection(new QComboBox()),
|
||||
: MacroSegmentEdit(GetGlobalMacroProperties()._highlightActions,
|
||||
parent),
|
||||
_actionSelection(new FilterComboBox()),
|
||||
_enable(new SwitchButton()),
|
||||
_entryData(entryData)
|
||||
{
|
||||
QWidget::connect(_actionSelection,
|
||||
SIGNAL(currentTextChanged(const QString &)), this,
|
||||
SLOT(ActionSelectionChanged(const QString &)));
|
||||
QWidget::connect(_enable, SIGNAL(checked(bool)), this,
|
||||
SLOT(ActionEnableChanged(bool)));
|
||||
QWidget::connect(window(), SIGNAL(HighlightActionsChanged(bool)), this,
|
||||
SLOT(EnableHighlight(bool)));
|
||||
QWidget::connect(&_actionStateTimer, SIGNAL(timeout()), this,
|
||||
SLOT(UpdateActionState()));
|
||||
|
||||
populateActionSelection(_actionSelection);
|
||||
|
||||
_section->AddHeaderWidget(_enable);
|
||||
_section->AddHeaderWidget(_actionSelection);
|
||||
_section->AddHeaderWidget(_headerInfo);
|
||||
|
||||
QVBoxLayout *actionLayout = new QVBoxLayout;
|
||||
auto actionLayout = new QVBoxLayout;
|
||||
actionLayout->setContentsMargins({7, 7, 7, 7});
|
||||
actionLayout->addWidget(_section);
|
||||
_contentLayout->addLayout(actionLayout);
|
||||
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||
auto mainLayout = new QHBoxLayout;
|
||||
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||
mainLayout->setSpacing(0);
|
||||
mainLayout->addWidget(_frame);
|
||||
@@ -103,6 +66,7 @@ MacroActionEdit::MacroActionEdit(QWidget *parent,
|
||||
_entryData = entryData;
|
||||
UpdateEntryData(id);
|
||||
|
||||
_actionStateTimer.start(300);
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
@@ -112,15 +76,20 @@ void MacroActionEdit::ActionSelectionChanged(const QString &text)
|
||||
return;
|
||||
}
|
||||
|
||||
std::string id = MacroActionFactory::GetIdByName(text);
|
||||
if (id.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
HeaderInfoChanged("");
|
||||
auto idx = _entryData->get()->GetIndex();
|
||||
auto macro = _entryData->get()->GetMacro();
|
||||
std::string id = MacroActionFactory::GetIdByName(text);
|
||||
HeaderInfoChanged("");
|
||||
{
|
||||
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 &)),
|
||||
@@ -133,6 +102,9 @@ void MacroActionEdit::UpdateEntryData(const std::string &id)
|
||||
{
|
||||
_actionSelection->setCurrentText(
|
||||
obs_module_text(MacroActionFactory::GetActionName(id).c_str()));
|
||||
const bool enabled = (*_entryData)->Enabled();
|
||||
_enable->setChecked(enabled);
|
||||
SetDisableEffect(!enabled);
|
||||
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
|
||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||
this, SLOT(HeaderInfoChanged(const QString &)));
|
||||
@@ -147,14 +119,51 @@ void MacroActionEdit::SetEntryData(std::shared_ptr<MacroAction> *data)
|
||||
_entryData = data;
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroSegment> MacroActionEdit::Data()
|
||||
void MacroActionEdit::SetDisableEffect(bool value)
|
||||
{
|
||||
if (value) {
|
||||
auto effect = new QGraphicsOpacityEffect(this);
|
||||
effect->setOpacity(0.5);
|
||||
_section->setGraphicsEffect(effect);
|
||||
} else {
|
||||
_section->setGraphicsEffect(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroActionEdit::ActionEnableChanged(bool value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
(*_entryData)->SetEnabled(value);
|
||||
SetDisableEffect(!value);
|
||||
}
|
||||
|
||||
void MacroActionEdit::UpdateActionState()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
SetEnableAppearance((*_entryData)->Enabled());
|
||||
}
|
||||
|
||||
void MacroActionEdit::SetEnableAppearance(bool value)
|
||||
{
|
||||
_enable->setChecked(value);
|
||||
SetDisableEffect(!value);
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroSegment> MacroActionEdit::Data() const
|
||||
{
|
||||
return *_entryData;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::AddMacroAction(int idx)
|
||||
{
|
||||
auto macro = getSelectedMacro();
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
@@ -171,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()));
|
||||
@@ -179,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);
|
||||
@@ -193,7 +203,7 @@ void AdvSceneSwitcher::AddMacroAction(int idx)
|
||||
|
||||
void AdvSceneSwitcher::on_actionAdd_clicked()
|
||||
{
|
||||
auto macro = getSelectedMacro();
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
@@ -206,12 +216,12 @@ void AdvSceneSwitcher::on_actionAdd_clicked()
|
||||
if (currentActionIdx != -1) {
|
||||
MacroActionSelectionChanged(currentActionIdx + 1);
|
||||
}
|
||||
actionsList->SetHelpMsgVisible(false);
|
||||
ui->actionsList->SetHelpMsgVisible(false);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::RemoveMacroAction(int idx)
|
||||
{
|
||||
auto macro = getSelectedMacro();
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
@@ -221,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);
|
||||
}
|
||||
@@ -237,7 +247,7 @@ void AdvSceneSwitcher::RemoveMacroAction(int idx)
|
||||
void AdvSceneSwitcher::on_actionRemove_clicked()
|
||||
{
|
||||
if (currentActionIdx == -1) {
|
||||
auto macro = getSelectedMacro();
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
@@ -248,23 +258,115 @@ void AdvSceneSwitcher::on_actionRemove_clicked()
|
||||
MacroActionSelectionChanged(-1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_actionUp_clicked()
|
||||
void AdvSceneSwitcher::on_actionTop_clicked()
|
||||
{
|
||||
if (currentActionIdx == -1) {
|
||||
return;
|
||||
}
|
||||
MacroActionReorder(0, currentActionIdx);
|
||||
MacroActionSelectionChanged(0);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_actionUp_clicked()
|
||||
{
|
||||
if (currentActionIdx == -1 || currentActionIdx == 0) {
|
||||
return;
|
||||
}
|
||||
MoveMacroActionUp(currentActionIdx);
|
||||
MacroActionSelectionChanged(currentActionIdx - 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_actionDown_clicked()
|
||||
{
|
||||
if (currentActionIdx == -1) {
|
||||
if (currentActionIdx == -1 ||
|
||||
currentActionIdx == ui->actionsList->ContentLayout()->count() - 1) {
|
||||
return;
|
||||
}
|
||||
MoveMacroActionDown(currentActionIdx);
|
||||
MacroActionSelectionChanged(currentActionIdx + 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_actionBottom_clicked()
|
||||
{
|
||||
if (currentActionIdx == -1) {
|
||||
return;
|
||||
}
|
||||
const int newIdx = ui->actionsList->ContentLayout()->count() - 1;
|
||||
MacroActionReorder(newIdx, currentActionIdx);
|
||||
MacroActionSelectionChanged(newIdx);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_elseActionAdd_clicked()
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentElseActionIdx == -1) {
|
||||
AddMacroElseAction((int)macro->ElseActions().size());
|
||||
} else {
|
||||
AddMacroElseAction(currentElseActionIdx + 1);
|
||||
}
|
||||
if (currentElseActionIdx != -1) {
|
||||
MacroElseActionSelectionChanged(currentElseActionIdx + 1);
|
||||
}
|
||||
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) {
|
||||
@@ -274,22 +376,22 @@ 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());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MoveMacroActionUp(int idx)
|
||||
{
|
||||
auto macro = getSelectedMacro();
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
@@ -304,7 +406,7 @@ void AdvSceneSwitcher::MoveMacroActionUp(int idx)
|
||||
|
||||
void AdvSceneSwitcher::MoveMacroActionDown(int idx)
|
||||
{
|
||||
auto macro = getSelectedMacro();
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
@@ -317,47 +419,184 @@ void AdvSceneSwitcher::MoveMacroActionDown(int idx)
|
||||
HighlightAction(idx + 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MacroActionSelectionChanged(int idx)
|
||||
void AdvSceneSwitcher::MacroElseActionSelectionChanged(int idx)
|
||||
{
|
||||
auto macro = getSelectedMacro();
|
||||
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)
|
||||
{
|
||||
auto macro = getSelectedMacro();
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (from < 0 || from > (int)macro->Actions().size() || to < 0 ||
|
||||
to > (int)macro->Actions().size()) {
|
||||
if (to == from || from < 0 || from > (int)macro->Actions().size() ||
|
||||
to < 0 || to > (int)macro->Actions().size()) {
|
||||
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);
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,34 +1,13 @@
|
||||
#pragma once
|
||||
#include "macro-action.hpp"
|
||||
#include "macro-action-factory.hpp"
|
||||
#include "filter-combo-box.hpp"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <memory>
|
||||
|
||||
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;
|
||||
};
|
||||
namespace advss {
|
||||
|
||||
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 SwitchButton;
|
||||
|
||||
class MacroActionEdit : public MacroSegmentEdit {
|
||||
Q_OBJECT
|
||||
@@ -42,12 +21,20 @@ public:
|
||||
|
||||
private slots:
|
||||
void ActionSelectionChanged(const QString &text);
|
||||
void ActionEnableChanged(bool);
|
||||
void UpdateActionState();
|
||||
|
||||
private:
|
||||
std::shared_ptr<MacroSegment> Data();
|
||||
std::shared_ptr<MacroSegment> Data() const;
|
||||
void SetDisableEffect(bool);
|
||||
void SetEnableAppearance(bool);
|
||||
|
||||
QComboBox *_actionSelection;
|
||||
FilterComboBox *_actionSelection;
|
||||
SwitchButton *_enable;
|
||||
|
||||
std::shared_ptr<MacroAction> *_entryData;
|
||||
QTimer _actionStateTimer;
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
||||
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
@@ -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
|
||||
@@ -1,11 +1,12 @@
|
||||
#include "macro-action-file.hpp"
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QFileDialog>
|
||||
|
||||
namespace advss {
|
||||
|
||||
const std::string MacroActionFile::id = "file";
|
||||
|
||||
bool MacroActionFile::_registered = MacroActionFactory::Register(
|
||||
@@ -106,7 +107,7 @@ MacroActionFileEdit::MacroActionFileEdit(
|
||||
{"{{matchText}}", _text},
|
||||
{"{{actions}}", _actions},
|
||||
};
|
||||
placeWidgets(obs_module_text("AdvSceneSwitcher.action.file.entry"),
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.file.entry"),
|
||||
entryLayout, widgetPlaceholders);
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
@@ -139,7 +140,7 @@ void MacroActionFileEdit::PathChanged(const QString &text)
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->_file = text.toUtf8().constData();
|
||||
emit HeaderInfoChanged(
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
@@ -151,7 +152,7 @@ void MacroActionFileEdit::TextChanged()
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->_text = _text->toPlainText().toStdString();
|
||||
|
||||
adjustSize();
|
||||
@@ -164,6 +165,8 @@ void MacroActionFileEdit::ActionChanged(int value)
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->_action = static_cast<FileAction>(value);
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
#include <QSpinBox>
|
||||
|
||||
namespace advss {
|
||||
|
||||
enum class FileAction {
|
||||
WRITE,
|
||||
APPEND,
|
||||
@@ -65,3 +67,5 @@ protected:
|
||||
private:
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#include "macro-action-filter.hpp"
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
const std::string MacroActionFilter::id = "filter";
|
||||
|
||||
bool MacroActionFilter::_registered = MacroActionFactory::Register(
|
||||
@@ -14,42 +15,75 @@ const static std::map<MacroActionFilter::Action, std::string> actionTypes = {
|
||||
"AdvSceneSwitcher.action.filter.type.enable"},
|
||||
{MacroActionFilter::Action::DISABLE,
|
||||
"AdvSceneSwitcher.action.filter.type.disable"},
|
||||
{MacroActionFilter::Action::TOGGLE,
|
||||
"AdvSceneSwitcher.action.filter.type.toggle"},
|
||||
{MacroActionFilter::Action::SETTINGS,
|
||||
"AdvSceneSwitcher.action.filter.type.settings"},
|
||||
};
|
||||
|
||||
void MacroActionFilter::ResolveVariables()
|
||||
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)
|
||||
{
|
||||
if (_source.GetType() == SourceSelection::Type::SOURCE) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string name = GetWeakSourceName(_filter);
|
||||
if (!name.empty()) {
|
||||
_filterName = name;
|
||||
}
|
||||
_filter = GetWeakFilterByName(_source.GetSource(), _filterName.c_str());
|
||||
}
|
||||
|
||||
bool MacroActionFilter::PerformAction()
|
||||
{
|
||||
ResolveVariables();
|
||||
|
||||
auto s = obs_weak_source_get_source(_filter);
|
||||
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::SETTINGS:
|
||||
setSourceSettings(s, _settings);
|
||||
case MacroActionFilter::Action::TOGGLE:
|
||||
obs_source_set_enabled(source, !obs_source_enabled(source));
|
||||
break;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -59,7 +93,7 @@ void MacroActionFilter::LogAction() const
|
||||
if (it != actionTypes.end()) {
|
||||
vblog(LOG_INFO,
|
||||
"performed action \"%s\" for filter \"%s\" on source \"%s\"",
|
||||
it->second.c_str(), GetWeakSourceName(_filter).c_str(),
|
||||
it->second.c_str(), _filter.ToString().c_str(),
|
||||
_source.ToString(true).c_str());
|
||||
} else {
|
||||
blog(LOG_WARNING, "ignored unknown filter action %d",
|
||||
@@ -71,9 +105,15 @@ bool MacroActionFilter::Save(obs_data_t *obj) const
|
||||
{
|
||||
MacroAction::Save(obj);
|
||||
_source.Save(obj);
|
||||
obs_data_set_string(obj, "filter", _filterName.c_str());
|
||||
_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;
|
||||
}
|
||||
|
||||
@@ -81,18 +121,36 @@ bool MacroActionFilter::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroAction::Load(obj);
|
||||
_source.Load(obj);
|
||||
_filterName = obs_data_get_string(obj, "filter");
|
||||
_filter = GetWeakFilterByQString(_source.GetSource(),
|
||||
_filterName.c_str());
|
||||
_action = static_cast<Action>(obs_data_get_int(obj, "action"));
|
||||
_settings.Load(obj, "settings");
|
||||
_filter.Load(obj, _source, "filter");
|
||||
// TODO: Remove this fallback in future version
|
||||
if (!obs_data_has_user_value(obj, "version")) {
|
||||
const auto value = obs_data_get_int(obj, "action");
|
||||
if (value == 2) {
|
||||
_action = Action::SETTINGS;
|
||||
} else {
|
||||
_action = static_cast<Action>(value);
|
||||
}
|
||||
} else {
|
||||
_action = static_cast<Action>(obs_data_get_int(obj, "action"));
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
|
||||
std::string MacroActionFilter::GetShortDesc() const
|
||||
{
|
||||
if (_filter && !_source.ToString().empty()) {
|
||||
return _source.ToString() + " - " + GetWeakSourceName(_filter);
|
||||
if (!_filter.ToString().empty() && !_source.ToString().empty()) {
|
||||
return _source.ToString() + " - " + _filter.ToString();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
@@ -104,15 +162,29 @@ 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),
|
||||
_sources(new SourceSelectionWidget(this, QStringList(), true)),
|
||||
_filters(new QComboBox()),
|
||||
_filters(new FilterSelectionWidget(this, _sources, true)),
|
||||
_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,35 +193,60 @@ MacroActionFilterEdit::MacroActionFilterEdit(
|
||||
sources.sort();
|
||||
_sources->SetSourceNameList(sources);
|
||||
|
||||
populateSettingsInputMethods(_settingsInputMethods);
|
||||
|
||||
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(ActionChanged(int)));
|
||||
QWidget::connect(_sources,
|
||||
SIGNAL(SourceChanged(const SourceSelection &)), this,
|
||||
SLOT(SourceChanged(const SourceSelection &)));
|
||||
QWidget::connect(_filters, SIGNAL(currentTextChanged(const QString &)),
|
||||
this, SLOT(FilterChanged(const QString &)));
|
||||
QWidget::connect(_filters,
|
||||
SIGNAL(FilterChanged(const FilterSelection &)), this,
|
||||
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);
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.filter.entry"),
|
||||
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);
|
||||
|
||||
@@ -166,15 +263,17 @@ void MacroActionFilterEdit::UpdateEntryData()
|
||||
|
||||
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
|
||||
_sources->SetSource(_entryData->_source);
|
||||
populateFilterSelection(_filters, _entryData->_source.GetSource());
|
||||
_filters->setCurrentText(
|
||||
GetWeakSourceName(_entryData->_filter).c_str());
|
||||
_settings->setPlainText(_entryData->_settings);
|
||||
SetWidgetVisibility(_entryData->_action ==
|
||||
MacroActionFilter::Action::SETTINGS);
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
_filters->SetFilter(_entryData->_source, _entryData->_filter);
|
||||
_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)
|
||||
@@ -182,25 +281,24 @@ void MacroActionFilterEdit::SourceChanged(const SourceSelection &source)
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
_entryData->_source = source;
|
||||
}
|
||||
_filters->clear();
|
||||
populateFilterSelection(_filters, _entryData->_source.GetSource());
|
||||
_filters->adjustSize();
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_source = source;
|
||||
}
|
||||
|
||||
void MacroActionFilterEdit::FilterChanged(const QString &text)
|
||||
void MacroActionFilterEdit::FilterChanged(const FilterSelection &filter)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
_entryData->_filterName = text.toStdString();
|
||||
_entryData->_filter =
|
||||
GetWeakFilterByQString(_entryData->_source.GetSource(), text);
|
||||
{
|
||||
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()));
|
||||
}
|
||||
@@ -211,39 +309,134 @@ void MacroActionFilterEdit::ActionChanged(int value)
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->_action = static_cast<MacroActionFilter::Action>(value);
|
||||
SetWidgetVisibility(_entryData->_action ==
|
||||
MacroActionFilter::Action::SETTINGS);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionFilterEdit::GetSettingsClicked()
|
||||
{
|
||||
if (_loading || !_entryData || !_entryData->_source.GetSource() ||
|
||||
!_entryData->_filter) {
|
||||
if (_loading || !_entryData ||
|
||||
_entryData->_filter.GetFilters(_entryData->_source).empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
_settings->setPlainText(
|
||||
formatJsonString(getSourceSettings(_entryData->_filter)));
|
||||
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;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
_entryData->_settings = _settings->toPlainText().toStdString();
|
||||
auto lock = LockContext();
|
||||
_entryData->_settingsString =
|
||||
_settingsString->toPlainText().toStdString();
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void MacroActionFilterEdit::SetWidgetVisibility(bool showSettings)
|
||||
void MacroActionFilterEdit::SettingsInputMethodChanged(int idx)
|
||||
{
|
||||
_settings->setVisible(showSettings);
|
||||
_getSettings->setVisible(showSettings);
|
||||
adjustSize();
|
||||
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();
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -2,11 +2,15 @@
|
||||
#include "macro-action-edit.hpp"
|
||||
#include "variable-text-edit.hpp"
|
||||
#include "source-selection.hpp"
|
||||
#include "filter-selection.hpp"
|
||||
#include "source-setting.hpp"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QSpinBox>
|
||||
#include <QPushButton>
|
||||
|
||||
namespace advss {
|
||||
|
||||
class MacroActionFilter : public MacroAction {
|
||||
public:
|
||||
MacroActionFilter(Macro *m) : MacroAction(m) {}
|
||||
@@ -24,22 +28,29 @@ public:
|
||||
enum class Action {
|
||||
ENABLE,
|
||||
DISABLE,
|
||||
TOGGLE,
|
||||
SETTINGS,
|
||||
};
|
||||
|
||||
enum class SettingsInputMethod {
|
||||
INDIVIDUAL_MANUAL,
|
||||
INDIVIDUAL_TEMPVAR,
|
||||
JSON_STRING,
|
||||
};
|
||||
SettingsInputMethod _settingsInputMethod =
|
||||
SettingsInputMethod::INDIVIDUAL_MANUAL;
|
||||
|
||||
SourceSelection _source;
|
||||
OBSWeakSource _filter;
|
||||
FilterSelection _filter;
|
||||
Action _action = Action::ENABLE;
|
||||
StringVariable _settings = "";
|
||||
StringVariable _settingsString = "";
|
||||
TempVariableRef _tempVar;
|
||||
StringVariable _manualSettingValue = "";
|
||||
SourceSetting _setting;
|
||||
|
||||
private:
|
||||
void ResolveVariables();
|
||||
std::string _filterName = "";
|
||||
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
|
||||
friend class MacroActionFilterEdit;
|
||||
};
|
||||
|
||||
class MacroActionFilterEdit : public QWidget {
|
||||
@@ -60,22 +71,34 @@ public:
|
||||
|
||||
private slots:
|
||||
void SourceChanged(const SourceSelection &);
|
||||
void FilterChanged(const QString &);
|
||||
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 &);
|
||||
|
||||
protected:
|
||||
SourceSelectionWidget *_sources;
|
||||
QComboBox *_filters;
|
||||
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;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
#include "macro-action-hotkey.hpp"
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "platform-funcs.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <thread>
|
||||
#include <obs-interaction.h>
|
||||
|
||||
namespace advss {
|
||||
|
||||
const std::string MacroActionHotkey::id = "hotkey";
|
||||
|
||||
bool MacroActionHotkey::_registered = MacroActionFactory::Register(
|
||||
@@ -10,7 +14,27 @@ bool MacroActionHotkey::_registered = MacroActionFactory::Register(
|
||||
{MacroActionHotkey::Create, MacroActionHotkeyEdit::Create,
|
||||
"AdvSceneSwitcher.action.hotkey"});
|
||||
|
||||
static std::unordered_map<HotkeyType, long> keyTable = {
|
||||
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"},
|
||||
};
|
||||
|
||||
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,
|
||||
"AdvSceneSwitcher.action.hotkey.type.obs.type.soruce"},
|
||||
{OBS_HOTKEY_REGISTERER_OUTPUT,
|
||||
"AdvSceneSwitcher.action.hotkey.type.obs.type.output"},
|
||||
{OBS_HOTKEY_REGISTERER_ENCODER,
|
||||
"AdvSceneSwitcher.action.hotkey.type.obs.type.encoder"},
|
||||
{OBS_HOTKEY_REGISTERER_SERVICE,
|
||||
"AdvSceneSwitcher.action.hotkey.type.obs.type.service"},
|
||||
};
|
||||
|
||||
static const std::unordered_map<HotkeyType, long> keyTable = {
|
||||
// Chars
|
||||
{HotkeyType::Key_A, OBS_KEY_A},
|
||||
{HotkeyType::Key_B, OBS_KEY_B},
|
||||
@@ -51,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},
|
||||
@@ -130,7 +157,8 @@ static std::unordered_map<HotkeyType, long> keyTable = {
|
||||
//{HotkeyType::Key_NumpadEnter, ???},
|
||||
};
|
||||
|
||||
obs_key_combination keysToOBSKeycombo(const std::vector<HotkeyType> &keys)
|
||||
static obs_key_combination
|
||||
keysToOBSKeycombo(const std::vector<HotkeyType> &keys)
|
||||
{
|
||||
obs_key_combination combo{};
|
||||
auto it = keyTable.find(keys.back());
|
||||
@@ -178,7 +206,7 @@ obs_key_combination keysToOBSKeycombo(const std::vector<HotkeyType> &keys)
|
||||
return combo;
|
||||
}
|
||||
|
||||
void InjectKeys(const std::vector<HotkeyType> &keys, int duration)
|
||||
static void InjectKeys(const std::vector<HotkeyType> &keys, int duration)
|
||||
{
|
||||
auto combo = keysToOBSKeycombo(keys);
|
||||
if (obs_key_combination_is_empty(combo)) {
|
||||
@@ -192,7 +220,92 @@ void InjectKeys(const std::vector<HotkeyType> &keys, int duration)
|
||||
obs_hotkey_inject_event(combo, false);
|
||||
}
|
||||
|
||||
bool MacroActionHotkey::PerformAction()
|
||||
static void addNamePrefix(std::string &name, obs_hotkey_t *hotkey)
|
||||
{
|
||||
const auto type = obs_hotkey_get_registerer_type(hotkey);
|
||||
std::string prefix;
|
||||
if (type == OBS_HOTKEY_REGISTERER_SOURCE) {
|
||||
auto source = reinterpret_cast<obs_weak_source_t *>(
|
||||
obs_hotkey_get_registerer(hotkey));
|
||||
prefix = "[" + GetWeakSourceName(source) + "] ";
|
||||
} else if (type == OBS_HOTKEY_REGISTERER_OUTPUT) {
|
||||
auto weakOutput = reinterpret_cast<obs_weak_output_t *>(
|
||||
obs_hotkey_get_registerer(hotkey));
|
||||
std::string name;
|
||||
auto output = obs_weak_output_get_output(weakOutput);
|
||||
if (output) {
|
||||
name = obs_output_get_name(output);
|
||||
obs_output_release(output);
|
||||
}
|
||||
prefix = "[" + name + "] ";
|
||||
} else if (type == OBS_HOTKEY_REGISTERER_ENCODER) {
|
||||
auto weakEncoder = reinterpret_cast<obs_weak_encoder_t *>(
|
||||
obs_hotkey_get_registerer(hotkey));
|
||||
std::string name;
|
||||
auto encoder = obs_weak_encoder_get_encoder(weakEncoder);
|
||||
if (encoder) {
|
||||
name = obs_encoder_get_name(encoder);
|
||||
obs_encoder_release(encoder);
|
||||
}
|
||||
prefix = "[" + name + "] ";
|
||||
} else if (type == OBS_HOTKEY_REGISTERER_SERVICE) {
|
||||
auto weakService = reinterpret_cast<obs_weak_service_t *>(
|
||||
obs_hotkey_get_registerer(hotkey));
|
||||
std::string name;
|
||||
auto service = obs_weak_service_get_service(weakService);
|
||||
if (service) {
|
||||
name = obs_service_get_name(service);
|
||||
obs_service_release(service);
|
||||
}
|
||||
prefix = "[" + name + "] ";
|
||||
}
|
||||
name = prefix + name;
|
||||
}
|
||||
|
||||
static obs_hotkey_id getHotkeyIdByName(const std::string &name)
|
||||
{
|
||||
struct Parameters {
|
||||
std::string name;
|
||||
obs_hotkey_id id = OBS_INVALID_HOTKEY_ID;
|
||||
} params;
|
||||
|
||||
auto func = [](void *param, obs_hotkey_id id, obs_hotkey_t *hotkey) {
|
||||
auto params = static_cast<Parameters *>(param);
|
||||
std::string name = obs_hotkey_get_name(hotkey);
|
||||
addNamePrefix(name, hotkey);
|
||||
if (name == params->name) {
|
||||
params->id = id;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
params.name = name;
|
||||
obs_enum_hotkeys(func, ¶ms);
|
||||
return params.id;
|
||||
}
|
||||
|
||||
void MacroActionHotkey::SendOBSHotkey()
|
||||
{
|
||||
auto id = getHotkeyIdByName(_hotkeyName);
|
||||
if (id == OBS_INVALID_HOTKEY_ID) {
|
||||
blog(LOG_WARNING,
|
||||
"failed to get hotkey id for \"%s\" - key will not be pressed",
|
||||
_hotkeyName.c_str());
|
||||
return;
|
||||
}
|
||||
obs_queue_task(
|
||||
OBS_TASK_UI,
|
||||
[](void *param) {
|
||||
auto id = (size_t *)param;
|
||||
obs_hotkey_trigger_routed_callback(*id, false);
|
||||
obs_hotkey_trigger_routed_callback(*id, true);
|
||||
obs_hotkey_trigger_routed_callback(*id, false);
|
||||
},
|
||||
&id, true);
|
||||
}
|
||||
|
||||
void MacroActionHotkey::SendCustomHotkey()
|
||||
{
|
||||
std::vector<HotkeyType> keys;
|
||||
if (_leftShift) {
|
||||
@@ -233,18 +346,35 @@ bool MacroActionHotkey::PerformAction()
|
||||
t.detach();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool MacroActionHotkey::PerformAction()
|
||||
{
|
||||
switch (_action) {
|
||||
case advss::MacroActionHotkey::Action::OBS_HOTKEY:
|
||||
SendOBSHotkey();
|
||||
break;
|
||||
case advss::MacroActionHotkey::Action::CUSTOM:
|
||||
SendCustomHotkey();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MacroActionHotkey::LogAction() const
|
||||
{
|
||||
vblog(LOG_INFO, "sent hotkey");
|
||||
vblog(LOG_INFO, "sent hotkey type %d", static_cast<int>(_action));
|
||||
}
|
||||
|
||||
bool MacroActionHotkey::Save(obs_data_t *obj) const
|
||||
{
|
||||
MacroAction::Save(obj);
|
||||
obs_data_set_int(obj, "action", static_cast<int>(_action));
|
||||
obs_data_set_int(obj, "hotkeyType", _hotkeyType);
|
||||
obs_data_set_string(obj, "hotkeyName", _hotkeyName.c_str());
|
||||
obs_data_set_int(obj, "key", static_cast<int>(_key));
|
||||
obs_data_set_bool(obj, "left_shift", _leftShift);
|
||||
obs_data_set_bool(obj, "right_shift", _rightShift);
|
||||
@@ -256,13 +386,22 @@ bool MacroActionHotkey::Save(obs_data_t *obj) const
|
||||
obs_data_set_bool(obj, "right_meta", _rightMeta);
|
||||
_duration.Save(obj);
|
||||
obs_data_set_bool(obj, "onlyOBS", _onlySendToObs);
|
||||
obs_data_set_int(obj, "version", 1);
|
||||
obs_data_set_int(obj, "version", 2);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacroActionHotkey::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroAction::Load(obj);
|
||||
int version = obs_data_get_int(obj, "version");
|
||||
if (version != 2) {
|
||||
_action = Action::CUSTOM;
|
||||
} else {
|
||||
_action = static_cast<Action>(obs_data_get_int(obj, "action"));
|
||||
}
|
||||
_hotkeyType = static_cast<obs_hotkey_registerer_type>(
|
||||
obs_data_get_int(obj, "hotkeyType"));
|
||||
_hotkeyName = obs_data_get_string(obj, "hotkeyName");
|
||||
_key = static_cast<HotkeyType>(obs_data_get_int(obj, "key"));
|
||||
_leftShift = obs_data_get_bool(obj, "left_shift");
|
||||
_rightShift = obs_data_get_bool(obj, "right_shift");
|
||||
@@ -272,7 +411,7 @@ bool MacroActionHotkey::Load(obs_data_t *obj)
|
||||
_rightAlt = obs_data_get_bool(obj, "right_alt");
|
||||
_leftMeta = obs_data_get_bool(obj, "left_meta");
|
||||
_rightMeta = obs_data_get_bool(obj, "right_meta");
|
||||
if (!obs_data_has_user_value(obj, "version")) {
|
||||
if (version == 0) {
|
||||
_duration = obs_data_get_int(obj, "duration") / 1000.0;
|
||||
} else {
|
||||
_duration.Load(obj);
|
||||
@@ -389,11 +528,68 @@ static inline void populateKeySelection(QComboBox *list)
|
||||
list->addItem("NumpadDivide");
|
||||
list->addItem("NumpadDecimal");
|
||||
list->addItem("NumpadEnter");
|
||||
list->addItem("Tilde");
|
||||
}
|
||||
|
||||
static void populateActionSelection(QComboBox *list)
|
||||
{
|
||||
for (const auto &[_, value] : actionTypes) {
|
||||
list->addItem(obs_module_text(value.c_str()));
|
||||
}
|
||||
}
|
||||
static void populateHotkeyTypeSelection(QComboBox *list)
|
||||
{
|
||||
for (const auto &[_, value] : hotkeyTypes) {
|
||||
list->addItem(obs_module_text(value.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
static void addNamePrefix(QString &name, obs_hotkey_t *hotkey)
|
||||
{
|
||||
auto temp = name.toStdString();
|
||||
addNamePrefix(temp, hotkey);
|
||||
name = QString::fromStdString(temp);
|
||||
}
|
||||
|
||||
static void populateHotkeyNames(QComboBox *list,
|
||||
obs_hotkey_registerer_type type)
|
||||
{
|
||||
struct Parameters {
|
||||
QStringList names;
|
||||
QStringList descriptions;
|
||||
obs_hotkey_registerer_type type;
|
||||
} params;
|
||||
|
||||
auto func = [](void *param, obs_hotkey_id, obs_hotkey_t *hotkey) {
|
||||
auto params = static_cast<Parameters *>(param);
|
||||
if (obs_hotkey_get_registerer_type(hotkey) == params->type) {
|
||||
QString description(obs_hotkey_get_description(hotkey));
|
||||
addNamePrefix(description, hotkey);
|
||||
params->descriptions.append(description);
|
||||
QString name(obs_hotkey_get_name(hotkey));
|
||||
addNamePrefix(name, hotkey);
|
||||
params->names.append(name);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
params.type = type;
|
||||
obs_enum_hotkeys(func, ¶ms);
|
||||
|
||||
list->clear();
|
||||
for (int i = 0; i < params.names.size(); i++) {
|
||||
list->addItem(params.descriptions.at(i), params.names.at(i));
|
||||
}
|
||||
AddSelectionEntry(list,
|
||||
obs_module_text("AdvSceneSwitcher.selectHotkey"));
|
||||
}
|
||||
|
||||
MacroActionHotkeyEdit::MacroActionHotkeyEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroActionHotkey> entryData)
|
||||
: QWidget(parent),
|
||||
_actionType(new QComboBox()),
|
||||
_hotkeyType(new QComboBox()),
|
||||
_obsHotkeys(new QComboBox()),
|
||||
_keys(new QComboBox()),
|
||||
_leftShift(new QCheckBox(
|
||||
obs_module_text("AdvSceneSwitcher.action.hotkey.leftShift"))),
|
||||
@@ -415,10 +611,20 @@ MacroActionHotkeyEdit::MacroActionHotkeyEdit(
|
||||
_onlySendToOBS(new QCheckBox(
|
||||
obs_module_text("AdvSceneSwitcher.action.hotkey.onlyOBS"))),
|
||||
_noKeyPressSimulationWarning(new QLabel(
|
||||
obs_module_text("AdvSceneSwitcher.action.hotkey.disabled")))
|
||||
obs_module_text("AdvSceneSwitcher.action.hotkey.disabled"))),
|
||||
_entryLayout(new QHBoxLayout()),
|
||||
_keyConfigLayout(new QHBoxLayout())
|
||||
{
|
||||
populateKeySelection(_keys);
|
||||
populateActionSelection(_actionType);
|
||||
populateHotkeyTypeSelection(_hotkeyType);
|
||||
|
||||
QWidget::connect(_actionType, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(ActionChanged(int)));
|
||||
QWidget::connect(_hotkeyType, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(HotkeyTypeChanged(int)));
|
||||
QWidget::connect(_obsHotkeys, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(OBSHotkeyChanged(int)));
|
||||
QWidget::connect(_keys, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(KeyChanged(int)));
|
||||
QWidget::connect(_leftShift, SIGNAL(stateChanged(int)), this,
|
||||
@@ -442,28 +648,21 @@ MacroActionHotkeyEdit::MacroActionHotkeyEdit(
|
||||
QWidget::connect(_onlySendToOBS, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(OnlySendToOBSChanged(int)));
|
||||
|
||||
QHBoxLayout *line1Layout = new QHBoxLayout;
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{keys}}", _keys},
|
||||
{"{{duration}}", _duration},
|
||||
};
|
||||
placeWidgets(obs_module_text("AdvSceneSwitcher.action.hotkey.entry"),
|
||||
line1Layout, widgetPlaceholders);
|
||||
_entryLayout->setContentsMargins(0, 0, 0, 0);
|
||||
_keyConfigLayout->setContentsMargins(0, 0, 0, 0);
|
||||
_keyConfigLayout->addWidget(_leftShift);
|
||||
_keyConfigLayout->addWidget(_rightShift);
|
||||
_keyConfigLayout->addWidget(_leftCtrl);
|
||||
_keyConfigLayout->addWidget(_rightCtrl);
|
||||
_keyConfigLayout->addWidget(_leftAlt);
|
||||
_keyConfigLayout->addWidget(_rightAlt);
|
||||
_keyConfigLayout->addWidget(_leftMeta);
|
||||
_keyConfigLayout->addWidget(_rightMeta);
|
||||
_keyConfigLayout->addStretch();
|
||||
|
||||
QHBoxLayout *line2Layout = new QHBoxLayout;
|
||||
line2Layout->addWidget(_leftShift);
|
||||
line2Layout->addWidget(_rightShift);
|
||||
line2Layout->addWidget(_leftCtrl);
|
||||
line2Layout->addWidget(_rightCtrl);
|
||||
line2Layout->addWidget(_leftAlt);
|
||||
line2Layout->addWidget(_rightAlt);
|
||||
line2Layout->addWidget(_leftMeta);
|
||||
line2Layout->addWidget(_rightMeta);
|
||||
line2Layout->addStretch();
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(line1Layout);
|
||||
mainLayout->addLayout(line2Layout);
|
||||
auto mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(_entryLayout);
|
||||
mainLayout->addLayout(_keyConfigLayout);
|
||||
mainLayout->addWidget(_onlySendToOBS);
|
||||
mainLayout->addWidget(_noKeyPressSimulationWarning);
|
||||
setLayout(mainLayout);
|
||||
@@ -475,10 +674,76 @@ MacroActionHotkeyEdit::MacroActionHotkeyEdit(
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
void MacroActionHotkeyEdit::SetWarningVisibility()
|
||||
void MacroActionHotkeyEdit::RepopulateOBSHotkeySelection()
|
||||
{
|
||||
populateHotkeyNames(_obsHotkeys, _entryData->_hotkeyType);
|
||||
}
|
||||
|
||||
void MacroActionHotkeyEdit::SetWidgetVisibility()
|
||||
{
|
||||
_entryLayout->removeWidget(_actionType);
|
||||
_entryLayout->removeWidget(_hotkeyType);
|
||||
_entryLayout->removeWidget(_obsHotkeys);
|
||||
_entryLayout->removeWidget(_keys);
|
||||
_entryLayout->removeWidget(_duration);
|
||||
ClearLayout(_entryLayout);
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
_entryData->_action ==
|
||||
MacroActionHotkey::Action::OBS_HOTKEY
|
||||
? "AdvSceneSwitcher.action.hotkey.entry.obs"
|
||||
: "AdvSceneSwitcher.action.hotkey.entry.custom"),
|
||||
_entryLayout,
|
||||
{
|
||||
{"{{actionType}}", _actionType},
|
||||
{"{{hotkeyType}}", _hotkeyType},
|
||||
{"{{obsHotkeys}}", _obsHotkeys},
|
||||
{"{{keys}}", _keys},
|
||||
{"{{duration}}", _duration},
|
||||
});
|
||||
|
||||
_noKeyPressSimulationWarning->setVisible(!_entryData->_onlySendToObs &&
|
||||
!canSimulateKeyPresses);
|
||||
SetLayoutVisible(_keyConfigLayout,
|
||||
_entryData->_action ==
|
||||
MacroActionHotkey::Action::CUSTOM);
|
||||
_duration->setVisible(_entryData->_action ==
|
||||
MacroActionHotkey::Action::CUSTOM);
|
||||
_keys->setVisible(_entryData->_action ==
|
||||
MacroActionHotkey::Action::CUSTOM);
|
||||
_onlySendToOBS->setVisible(_entryData->_action ==
|
||||
MacroActionHotkey::Action::CUSTOM);
|
||||
_hotkeyType->setVisible(_entryData->_action ==
|
||||
MacroActionHotkey::Action::OBS_HOTKEY);
|
||||
_obsHotkeys->setVisible(_entryData->_action ==
|
||||
MacroActionHotkey::Action::OBS_HOTKEY);
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
static QString getHotkeyDescriptionByName(const std::string &name)
|
||||
{
|
||||
struct Parameters {
|
||||
std::string name;
|
||||
QString description = "";
|
||||
} params;
|
||||
|
||||
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);
|
||||
if (name == params->name) {
|
||||
params->description =
|
||||
obs_hotkey_get_description(hotkey);
|
||||
addNamePrefix(params->description, hotkey);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
params.name = name;
|
||||
obs_enum_hotkeys(func, ¶ms);
|
||||
return params.description;
|
||||
}
|
||||
|
||||
void MacroActionHotkeyEdit::UpdateEntryData()
|
||||
@@ -487,6 +752,11 @@ void MacroActionHotkeyEdit::UpdateEntryData()
|
||||
return;
|
||||
}
|
||||
|
||||
_actionType->setCurrentIndex(static_cast<int>(_entryData->_action));
|
||||
_hotkeyType->setCurrentIndex(static_cast<int>(_entryData->_hotkeyType));
|
||||
RepopulateOBSHotkeySelection();
|
||||
_obsHotkeys->setCurrentText(
|
||||
getHotkeyDescriptionByName(_entryData->_hotkeyName));
|
||||
_keys->setCurrentIndex(static_cast<int>(_entryData->_key));
|
||||
_leftShift->setChecked(_entryData->_leftShift);
|
||||
_rightShift->setChecked(_entryData->_rightShift);
|
||||
@@ -499,7 +769,7 @@ void MacroActionHotkeyEdit::UpdateEntryData()
|
||||
_duration->SetDuration(_entryData->_duration);
|
||||
_onlySendToOBS->setChecked(_entryData->_onlySendToObs ||
|
||||
!canSimulateKeyPresses);
|
||||
SetWarningVisibility();
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionHotkeyEdit::LShiftChanged(int state)
|
||||
@@ -508,7 +778,7 @@ void MacroActionHotkeyEdit::LShiftChanged(int state)
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->_leftShift = state;
|
||||
}
|
||||
|
||||
@@ -518,7 +788,7 @@ void MacroActionHotkeyEdit::RShiftChanged(int state)
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->_rightShift = state;
|
||||
}
|
||||
|
||||
@@ -528,7 +798,7 @@ void MacroActionHotkeyEdit::LCtrlChanged(int state)
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->_leftCtrl = state;
|
||||
}
|
||||
|
||||
@@ -538,7 +808,7 @@ void MacroActionHotkeyEdit::RCtrlChanged(int state)
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->_rightCtrl = state;
|
||||
}
|
||||
|
||||
@@ -548,7 +818,7 @@ void MacroActionHotkeyEdit::LAltChanged(int state)
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->_leftAlt = state;
|
||||
}
|
||||
|
||||
@@ -558,7 +828,7 @@ void MacroActionHotkeyEdit::RAltChanged(int state)
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->_rightAlt = state;
|
||||
}
|
||||
|
||||
@@ -568,7 +838,7 @@ void MacroActionHotkeyEdit::LMetaChanged(int state)
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->_leftMeta = state;
|
||||
}
|
||||
|
||||
@@ -578,7 +848,7 @@ void MacroActionHotkeyEdit::RMetaChanged(int state)
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->_rightMeta = state;
|
||||
}
|
||||
|
||||
@@ -588,7 +858,7 @@ void MacroActionHotkeyEdit::DurationChanged(const Duration &dur)
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->_duration = dur;
|
||||
}
|
||||
|
||||
@@ -598,9 +868,9 @@ void MacroActionHotkeyEdit::OnlySendToOBSChanged(int state)
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->_onlySendToObs = state;
|
||||
SetWarningVisibility();
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionHotkeyEdit::KeyChanged(int key)
|
||||
@@ -609,6 +879,47 @@ void MacroActionHotkeyEdit::KeyChanged(int key)
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->_key = static_cast<HotkeyType>(key);
|
||||
}
|
||||
|
||||
void MacroActionHotkeyEdit::ActionChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_action = static_cast<MacroActionHotkey::Action>(value);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionHotkeyEdit::HotkeyTypeChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
{
|
||||
auto lock = LockContext();
|
||||
_entryData->_hotkeyType =
|
||||
static_cast<obs_hotkey_registerer_type>(value);
|
||||
}
|
||||
RepopulateOBSHotkeySelection();
|
||||
}
|
||||
|
||||
void MacroActionHotkeyEdit::OBSHotkeyChanged(int idx)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
if (idx == -1) {
|
||||
_entryData->_hotkeyName = "";
|
||||
return;
|
||||
}
|
||||
_entryData->_hotkeyName =
|
||||
_obsHotkeys->itemData(idx).toString().toStdString();
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||