mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-03-22 09:54:54 -05:00
Compare commits
348 Commits
1.28.0-bet
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9301ead060 | ||
|
|
bc29ece526 | ||
|
|
4158c7a363 | ||
|
|
944d1059da | ||
|
|
bf18d8e106 | ||
|
|
bf216e0917 | ||
|
|
2405b6dbbf | ||
|
|
e64f2d195e | ||
|
|
f66bec8caf | ||
|
|
3eb79e3adb | ||
|
|
07e2ac3ca0 | ||
|
|
8e2c466c2d | ||
|
|
cc68e2366c | ||
|
|
7a0e08b0d8 | ||
|
|
be8744f0d0 | ||
|
|
d4425df694 | ||
|
|
70e5f6002d | ||
|
|
ff98ec36d6 | ||
|
|
4966802f14 | ||
|
|
b23a90557f | ||
|
|
d6ea815b85 | ||
|
|
f35ef558ee | ||
|
|
d7ff9088f8 | ||
|
|
7048925d6e | ||
|
|
fcb3ea50d3 | ||
|
|
87c45e2b32 | ||
|
|
eb5046a9d6 | ||
|
|
58c05f3f6e | ||
|
|
0b284da3de | ||
|
|
03fe7016e4 | ||
|
|
2ea89912a3 | ||
|
|
78d2efa083 | ||
|
|
149fce1c2b | ||
|
|
2dd9120265 | ||
|
|
3a9f315b67 | ||
|
|
6ba01dca39 | ||
|
|
ad1f1effeb | ||
|
|
0a53a8649f | ||
|
|
7ea721f9f1 | ||
|
|
718a899a98 | ||
|
|
4c493451f4 | ||
|
|
a8d483f5a7 | ||
|
|
dc786a5313 | ||
|
|
628a4d896c | ||
|
|
74a9681c8e | ||
|
|
faf52c38bb | ||
|
|
bad1a548fb | ||
|
|
f706416df5 | ||
|
|
c344c88acd | ||
|
|
2cd9e61717 | ||
|
|
6314de8f37 | ||
|
|
6bfcabc4af | ||
|
|
69711d973a | ||
|
|
225913b44d | ||
|
|
7c6d657fdd | ||
|
|
12e38274f5 | ||
|
|
5d49e8825b | ||
|
|
21c34356ed | ||
|
|
266e470509 | ||
|
|
de20c93b14 | ||
|
|
b0d877db8c | ||
|
|
caf9e59475 | ||
|
|
5f6982b5bb | ||
|
|
ce399cc647 | ||
|
|
03f67534c7 | ||
|
|
246667e65e | ||
|
|
68fe7716e7 | ||
|
|
98cc710b4a | ||
|
|
c602c30c54 | ||
|
|
cc1b89fe1d | ||
|
|
1de4ef7ec2 | ||
|
|
e29060fdea | ||
|
|
a0e6e6f528 | ||
|
|
e30d5845fa | ||
|
|
d12911cd02 | ||
|
|
b8ecc40e8c | ||
|
|
8ec4849b1d | ||
|
|
e6e9f3a831 | ||
|
|
555f7c1381 | ||
|
|
f0f8b0fd92 | ||
|
|
661e83162f | ||
|
|
4606f80a9d | ||
|
|
9c109742fb | ||
|
|
b8b0682aaf | ||
|
|
f93175db77 | ||
|
|
8f92ba3ffa | ||
|
|
0d56de11d1 | ||
|
|
e1020a1909 | ||
|
|
8b0bd4193b | ||
|
|
d55bb6bc86 | ||
|
|
0583331bfd | ||
|
|
6932de866d | ||
|
|
00db0cf7c4 | ||
|
|
e9baf27ca2 | ||
|
|
b1a5db0c9c | ||
|
|
8f3b868fd9 | ||
|
|
b3bf89840b | ||
|
|
84f7d0d214 | ||
|
|
e1164c4fa3 | ||
|
|
4534b23bad | ||
|
|
5d6a693f36 | ||
|
|
a82662c8f4 | ||
|
|
602675b3b3 | ||
|
|
9551519cb9 | ||
|
|
badce063eb | ||
|
|
10d45c67d6 | ||
|
|
0b77ef5081 | ||
|
|
8f54e71e61 | ||
|
|
16136b8741 | ||
|
|
02d5051974 | ||
|
|
078d62fa18 | ||
|
|
8aa6a7df2c | ||
|
|
1494b1db6c | ||
|
|
b4b3dc5a2b | ||
|
|
ee41a8d58b | ||
|
|
5f2237ac2a | ||
|
|
6fb76e7e07 | ||
|
|
ba094372a9 | ||
|
|
0c886c8679 | ||
|
|
d9f05d3f7b | ||
|
|
c99b5f1feb | ||
|
|
a3b3cf9818 | ||
|
|
ca3bbf5660 | ||
|
|
18524761a6 | ||
|
|
85222aed33 | ||
|
|
84132f7c37 | ||
|
|
ead664763f | ||
|
|
a2fa16f2d7 | ||
|
|
75edcffac9 | ||
|
|
dd5bcf425a | ||
|
|
de32e1b18e | ||
|
|
1d412a818d | ||
|
|
c8e5b561ef | ||
|
|
a1702dc798 | ||
|
|
ae571583fc | ||
|
|
c4f70657d9 | ||
|
|
7901a988af | ||
|
|
d2b70bbc6b | ||
|
|
4d22a539f0 | ||
|
|
4e561320f7 | ||
|
|
0dfa4fe2c0 | ||
|
|
4cac4584f3 | ||
|
|
d20a975c4f | ||
|
|
756d7bbd3c | ||
|
|
395a18fa4c | ||
|
|
2ea00d94c5 | ||
|
|
058e941a46 | ||
|
|
ea4a951554 | ||
|
|
3c355ac6fe | ||
|
|
37606e274c | ||
|
|
3e8d6e103a | ||
|
|
4cae420ade | ||
|
|
b27a11931a | ||
|
|
92616bed6b | ||
|
|
b3f38851b6 | ||
|
|
bf7fe71ae3 | ||
|
|
12a6b26d9a | ||
|
|
373e74c080 | ||
|
|
f3e7eaf212 | ||
|
|
b036736547 | ||
|
|
817de13e9d | ||
|
|
0b774c171d | ||
|
|
be8f7bd70f | ||
|
|
5f963b5b7d | ||
|
|
c6155c9fea | ||
|
|
be809dbfab | ||
|
|
7478c149b3 | ||
|
|
f4eaa9785d | ||
|
|
49c0de3f1b | ||
|
|
101ef4e973 | ||
|
|
82568b23e8 | ||
|
|
0cd7004f6a | ||
|
|
40c62ba700 | ||
|
|
f2c7b532d9 | ||
|
|
456a9c04c7 | ||
|
|
3e1fdbde45 | ||
|
|
874b9b86e2 | ||
|
|
98d1f83acc | ||
|
|
7e91f81957 | ||
|
|
20488afdd1 | ||
|
|
d9d387ad47 | ||
|
|
0736d673e1 | ||
|
|
34151e4bc6 | ||
|
|
1346c19bec | ||
|
|
be6bc48231 | ||
|
|
79a8ad57af | ||
|
|
daeb9275a3 | ||
|
|
73b542a4db | ||
|
|
e3471066e9 | ||
|
|
ec41c06b4d | ||
|
|
201e45d058 | ||
|
|
b17aa30432 | ||
|
|
93703c80bc | ||
|
|
d7951a7179 | ||
|
|
d42a3b584a | ||
|
|
becd1bd02a | ||
|
|
30422aecf3 | ||
|
|
c567e6ef7f | ||
|
|
1ca61f3ed4 | ||
|
|
1affe9dce3 | ||
|
|
406e3c1855 | ||
|
|
c05dd40c4c | ||
|
|
9a86ecac42 | ||
|
|
721a786e79 | ||
|
|
32d29875ed | ||
|
|
0e5f56b562 | ||
|
|
5490fabf92 | ||
|
|
5e3ab19940 | ||
|
|
1c94a1ab44 | ||
|
|
34baa56134 | ||
|
|
5ce4171773 | ||
|
|
c281c6db83 | ||
|
|
c43439ee64 | ||
|
|
a84731b8fe | ||
|
|
61fbff5821 | ||
|
|
1381654fed | ||
|
|
9805601c07 | ||
|
|
fcf57ee031 | ||
|
|
ba3e87a761 | ||
|
|
3dd3f576c3 | ||
|
|
7403a18e96 | ||
|
|
56494480ba | ||
|
|
cdc5d16e95 | ||
|
|
27aed79305 | ||
|
|
7ec95e33eb | ||
|
|
98260b25a1 | ||
|
|
45b37de9f7 | ||
|
|
027a3e9074 | ||
|
|
cab50e0922 | ||
|
|
88514e209d | ||
|
|
4ed7f13b72 | ||
|
|
0fb11ac274 | ||
|
|
942933290a | ||
|
|
f13beaead2 | ||
|
|
13dba6527d | ||
|
|
b78a6510a9 | ||
|
|
6c22f438b6 | ||
|
|
347abe6c84 | ||
|
|
230863adda | ||
|
|
f59478fac7 | ||
|
|
8adac79cd8 | ||
|
|
ea93c44db7 | ||
|
|
9e20b341d8 | ||
|
|
232cbb06f6 | ||
|
|
e9d57a0f4a | ||
|
|
9633a61a65 | ||
|
|
0643b250e1 | ||
|
|
b52738881f | ||
|
|
470d5ba3d7 | ||
|
|
8326e72047 | ||
|
|
12ab4d8cf9 | ||
|
|
295ec9eb81 | ||
|
|
4c5dbd4b7c | ||
|
|
5568f92ad0 | ||
|
|
7c4c0056ce | ||
|
|
d2b4b1cc07 | ||
|
|
a3ca22d238 | ||
|
|
c73542a3cc | ||
|
|
70bbc7cdac | ||
|
|
d892298995 | ||
|
|
0fe31432be | ||
|
|
aaa0113ccb | ||
|
|
b908954b46 | ||
|
|
b0eede8a85 | ||
|
|
aa87911b71 | ||
|
|
1b05019acc | ||
|
|
78a5a2629d | ||
|
|
634270a978 | ||
|
|
78ba22e1e4 | ||
|
|
aba5737a60 | ||
|
|
4315f7f621 | ||
|
|
53c535962f | ||
|
|
1e718b78c7 | ||
|
|
b1d2156228 | ||
|
|
9c3c953c6b | ||
|
|
ae74f68db7 | ||
|
|
213f1bba36 | ||
|
|
5a2cb0bd68 | ||
|
|
23b461828b | ||
|
|
9944a1b03b | ||
|
|
eaad4d1bbd | ||
|
|
17d9b73b9a | ||
|
|
d6185a6099 | ||
|
|
41c06b9edb | ||
|
|
d8807077da | ||
|
|
34e125f82d | ||
|
|
d670b6d07e | ||
|
|
7b0f985f18 | ||
|
|
212be923f6 | ||
|
|
88fcb57e9f | ||
|
|
9b609c118f | ||
|
|
37c398d37a | ||
|
|
a51b7f6b13 | ||
|
|
808fd84b83 | ||
|
|
57bcea15f5 | ||
|
|
4e51b56b9b | ||
|
|
ef5cf41d34 | ||
|
|
911e79ea6a | ||
|
|
d586177de0 | ||
|
|
202c36646c | ||
|
|
ab5102f5ca | ||
|
|
e612fb99f6 | ||
|
|
691e77a69a | ||
|
|
930118c61f | ||
|
|
1e05f2f2ce | ||
|
|
ae25b4d023 | ||
|
|
af055a12a1 | ||
|
|
7de28eedd3 | ||
|
|
8dfe81f522 | ||
|
|
a1d8ae291d | ||
|
|
eb6989527d | ||
|
|
2986a5dd96 | ||
|
|
816ee9b244 | ||
|
|
51b53bf948 | ||
|
|
2c5121ee94 | ||
|
|
6a58684854 | ||
|
|
0b622fdbed | ||
|
|
3bce8e075f | ||
|
|
f598d84ea1 | ||
|
|
d7a244e80e | ||
|
|
408002e96a | ||
|
|
50da3d3210 | ||
|
|
9e13067769 | ||
|
|
821e768e76 | ||
|
|
4d2179448b | ||
|
|
40d9002470 | ||
|
|
7f1e310ca6 | ||
|
|
66d02f4683 | ||
|
|
0aae1b9978 | ||
|
|
db50822b05 | ||
|
|
63a545b293 | ||
|
|
bc0497d2c9 | ||
|
|
37226a3a4c | ||
|
|
9f15fbe47c | ||
|
|
0ee6feb529 | ||
|
|
3b82b55090 | ||
|
|
071c3309c2 | ||
|
|
ee7ee7a846 | ||
|
|
d10300bd4b | ||
|
|
e262672876 | ||
|
|
392e775c7b | ||
|
|
f641c20564 | ||
|
|
39327be88e | ||
|
|
ed0963799c | ||
|
|
f9e73a2b8f | ||
|
|
dfaa704b71 | ||
|
|
d54edddde4 | ||
|
|
37cc289204 |
|
|
@ -6,15 +6,6 @@
|
|||
"autosort": true
|
||||
},
|
||||
"additional_commands": {
|
||||
"find_qt": {
|
||||
"flags": [],
|
||||
"kwargs": {
|
||||
"COMPONENTS": "+",
|
||||
"COMPONENTS_WIN": "+",
|
||||
"COMPONENTS_MACOS": "+",
|
||||
"COMPONENTS_LINUX": "+"
|
||||
}
|
||||
},
|
||||
"set_target_properties_obs": {
|
||||
"pargs": 1,
|
||||
"flags": [],
|
||||
|
|
|
|||
1
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
1
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
|
|
@ -20,6 +20,7 @@ body:
|
|||
- macOS 13
|
||||
- macOS 12
|
||||
- macOS 11
|
||||
- Ubuntu 24.04
|
||||
- Ubuntu 23.10
|
||||
- Ubuntu 22.04
|
||||
- Other
|
||||
|
|
|
|||
2
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
2
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
|
|
@ -2,7 +2,7 @@
|
|||
# https://github.com/obsproject/.github/tree/master/.github/ISSUE_TEMPLATE
|
||||
|
||||
name: Feature request
|
||||
description: Suggest an idea for this projectReport a bug or crash
|
||||
description: Suggest an idea for this project
|
||||
body:
|
||||
- type: markdown
|
||||
id: md_welcome
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ runs:
|
|||
- name: Setup cmake
|
||||
uses: jwlawson/actions-setup-cmake@v1.13
|
||||
with:
|
||||
cmake-version: '3.24.x'
|
||||
cmake-version: '3.x.x'
|
||||
|
||||
- name: Restore cached dependencies
|
||||
id: restore-cache
|
||||
|
|
|
|||
9
.github/scripts/.Aptfile
vendored
9
.github/scripts/.Aptfile
vendored
|
|
@ -9,5 +9,10 @@ package 'libxtst-dev'
|
|||
package 'libxss-dev'
|
||||
package 'libopencv-dev'
|
||||
package 'libtesseract-dev'
|
||||
package 'libprocps-dev'
|
||||
package 'libusb-1.0-0-dev'
|
||||
package 'libproc2-dev'
|
||||
package 'libusb-1.0-0-dev'
|
||||
package 'libpaho-mqttpp-dev'
|
||||
package 'libpaho-mqtt-dev'
|
||||
package 'libpaho-mqtt-dev'
|
||||
package 'libasound2-dev'
|
||||
package 'libpipewire-0.3-dev'
|
||||
|
|
|
|||
74
.github/scripts/.build-deps.zsh
vendored
74
.github/scripts/.build-deps.zsh
vendored
|
|
@ -394,8 +394,11 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
|
|||
|
||||
popd
|
||||
|
||||
pushd ${advss_dep_path}
|
||||
log_info "Prepare openssl ..."
|
||||
rm -rf ${advss_dep_path}/openssl ${advss_dep_path}/openssl_build
|
||||
mkdir ${advss_dep_path}/openssl_build
|
||||
pushd ${advss_dep_path}/openssl_build
|
||||
|
||||
rm -rf openssl
|
||||
git clone https://github.com/openssl/openssl.git --branch openssl-3.1.2 --depth 1
|
||||
mv openssl openssl_x86
|
||||
|
|
@ -403,25 +406,27 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
|
|||
|
||||
log_info "Building openssl x86 ..."
|
||||
export MACOSX_DEPLOYMENT_TARGET=10.9
|
||||
cd openssl_x86
|
||||
./Configure darwin64-x86_64-cc shared
|
||||
make
|
||||
pushd openssl_x86
|
||||
./Configure darwin64-x86_64-cc no-shared no-module no-zlib --prefix=${advss_dep_path}
|
||||
make -j$(nproc)
|
||||
popd
|
||||
|
||||
log_info "Building openssl arm ..."
|
||||
export MACOSX_DEPLOYMENT_TARGET=10.15
|
||||
cd ../openssl_arm
|
||||
./Configure enable-rc5 zlib darwin64-arm64-cc no-asm
|
||||
make
|
||||
pushd openssl_arm
|
||||
./Configure enable-rc5 darwin64-arm64-cc no-shared no-module no-asm no-zlib --prefix=${advss_dep_path}
|
||||
make -j$(nproc)
|
||||
|
||||
log_info "Install openssl ..."
|
||||
make install
|
||||
popd
|
||||
|
||||
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
|
||||
lipo -create openssl_x86/libcrypto.a openssl_arm/libcrypto.a -output ${advss_dep_path}/lib/libcrypto.a
|
||||
lipo -create openssl_x86/libssl.a openssl_arm/libssl.a -output ${advss_dep_path}/lib/libssl.a
|
||||
|
||||
log_info "Clean up openssl dir ..."
|
||||
mv openssl_x86 openssl
|
||||
rm -rf openssl_arm
|
||||
rm -rf openssl_x86 openssl_arm
|
||||
popd
|
||||
|
||||
pushd ${project_root}/deps/libusb
|
||||
|
|
@ -439,14 +444,16 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
|
|||
mkdir ${project_root}/deps/libusb/out_x86
|
||||
./autogen.sh
|
||||
./configure --host=x86_64-apple-darwin --prefix=${advss_dep_path}
|
||||
make && make install
|
||||
make -j$(nproc)
|
||||
make install
|
||||
|
||||
log_info "Configure libusb arm ..."
|
||||
make clean
|
||||
rm -r ${project_root}/deps/libusb/out_x86
|
||||
mkdir ${project_root}/deps/libusb/out_x86
|
||||
./configure --host=aarch64-apple-darwin --prefix=${project_root}/deps/libusb/out_x86
|
||||
make && make install
|
||||
make -j$(nproc)
|
||||
make install
|
||||
|
||||
log_info "Building libusb arm ..."
|
||||
make clean
|
||||
|
|
@ -459,7 +466,8 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
|
|||
export MACOSX_DEPLOYMENT_TARGET=10.15
|
||||
mkdir ${project_root}/deps/libusb/out_arm
|
||||
./configure --host=aarch64-apple-darwin --prefix=${project_root}/deps/libusb/out_arm
|
||||
make && make install
|
||||
make -j$(nproc)
|
||||
make install
|
||||
|
||||
log_info "Combine arm and x86 libusb binaries ..."
|
||||
lipo -create ${project_root}/deps/libusb/out_x86/lib/libusb-1.0.0.dylib \
|
||||
|
|
@ -478,14 +486,36 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
|
|||
unset MACOSX_DEPLOYMENT_TARGET
|
||||
|
||||
popd
|
||||
|
||||
local mqtt_dir="${project_root}/deps/paho.mqtt.cpp"
|
||||
local mqtt_build_dir="${mqtt_dir}/build_${target##*-}"
|
||||
|
||||
local -a mqtt_cmake_args=(
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
-DCMAKE_OSX_ARCHITECTURES=${${target##*-}//universal/x86_64;arm64}
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${DEPLOYMENT_TARGET:-10.15}
|
||||
-DCMAKE_PREFIX_PATH="${advss_dep_path};${_plugin_deps}"
|
||||
-DCMAKE_INSTALL_PREFIX="${advss_dep_path}"
|
||||
-DPAHO_BUILD_SHARED=OFF
|
||||
-DPAHO_BUILD_STATIC=ON
|
||||
-DPAHO_WITH_MQTT_C=ON
|
||||
-DPAHO_WITH_SSL=ON
|
||||
-DOPENSSL_USE_STATIC_LIBS=ON
|
||||
)
|
||||
|
||||
pushd ${mqtt_dir}
|
||||
log_info "Configure paho.mqtt.cpp ..."
|
||||
cmake -S . -B ${mqtt_build_dir} ${mqtt_cmake_args}
|
||||
|
||||
log_info "Building paho.mqtt.cpp ..."
|
||||
cmake --build ${mqtt_build_dir} --config Release
|
||||
|
||||
log_info "Installing paho.mqtt.cpp ..."
|
||||
cmake --install ${mqtt_build_dir} --prefix "${advss_dep_path}" --config Release
|
||||
popd
|
||||
;;
|
||||
linux)
|
||||
# Hacky workaround to support libproc2 with Ubuntu 22 build environment
|
||||
local lsb_version=$(lsb_release -r | cut -f 2 || true)
|
||||
if [[ "${lsb_version}" == '22.04' ]] {
|
||||
sudo apt install ${project_root}/build-aux/CI/linux/ubuntu22/libproc2-0_4.0.2-3_amd64.deb
|
||||
sudo apt install ${project_root}/build-aux/CI/linux/ubuntu22/libproc2-dev_4.0.2-3_amd64.deb
|
||||
}
|
||||
# Nothing to do for now
|
||||
;;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
6
.github/scripts/.build.zsh
vendored
6
.github/scripts/.build.zsh
vendored
|
|
@ -253,12 +253,8 @@ ${_usage_host:-}"
|
|||
macos-*)
|
||||
if (( ${+CI} )) typeset -gx NSUnbufferedIO=YES
|
||||
|
||||
local openssl_lib_dir="${advss_deps_path}/openssl-combined/"
|
||||
local openssl_include_dir="${advss_deps_path}/openssl/include"
|
||||
|
||||
cmake_args+=(
|
||||
-DOPENSSL_INCLUDE_DIR="${openssl_include_dir}"
|
||||
-DOPENSSL_LIBRARIES="${openssl_lib_dir}/libcrypto.a;${openssl_lib_dir}/libssl.a"
|
||||
-DCMAKE_PREFIX_PATH="${advss_deps_path}"
|
||||
--preset ${_preset}
|
||||
)
|
||||
|
||||
|
|
|
|||
3
.github/scripts/.package.zsh
vendored
3
.github/scripts/.package.zsh
vendored
|
|
@ -258,6 +258,9 @@ ${_usage_host:-}"
|
|||
pushd ${project_root}
|
||||
cmake --build build_${target##*-} --config ${config} -t package ${cmake_args}
|
||||
|
||||
# Mark certain deps as optional
|
||||
build-aux/CI/linux/demote-deps.sh ${project_root}/release/*.deb Recommends '(mqtt)|(opencv)|(tesseract)|(usb)|(x11)'
|
||||
|
||||
if [ ! -e ${project_root}/release/${output_name}.deb ]; then
|
||||
mv ${project_root}/release/*.deb ${project_root}/release/${output_name}.deb
|
||||
mv ${project_root}/release/*.ddeb ${project_root}/release/${output_name}.ddeb
|
||||
|
|
|
|||
49
.github/scripts/Build-Deps-Windows.ps1
vendored
49
.github/scripts/Build-Deps-Windows.ps1
vendored
|
|
@ -209,7 +209,9 @@ function Build {
|
|||
$msbuildExe = vswhere -latest -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe | select-object -first 1
|
||||
|
||||
if ($msbuildExe) {
|
||||
$env:CL="/wd5287"
|
||||
Invoke-External $msbuildExe "${LibusbPath}/msvc/libusb.sln" /property:Configuration=Release /property:Platform=x64
|
||||
Remove-Item Env:CL
|
||||
|
||||
$libusbBuildResultDirectory = "${LibusbPath}/build/v143/x64/Release"
|
||||
if (-not (Test-Path -Path $libusbBuildResultDirectory)) {
|
||||
|
|
@ -219,6 +221,53 @@ function Build {
|
|||
} else {
|
||||
Log-Information "Failed to locate msbuild.exe - skipping libusb build"
|
||||
}
|
||||
|
||||
Push-Location -Stack BuildMqttTemp
|
||||
Ensure-Location $ProjectRoot
|
||||
|
||||
$MqttPath = "${ProjectRoot}/deps/paho.mqtt.cpp"
|
||||
$MqttBuildPath = "${MqttPath}/build"
|
||||
|
||||
# Explicitly disable PkgConfig and tiff as it will lead build errors
|
||||
$MqttCmakeArgs = @(
|
||||
"-DCMAKE_BUILD_TYPE=${Configuration}"
|
||||
"-DCMAKE_PREFIX_PATH:PATH=${OBSDepPath}"
|
||||
"-DCMAKE_INSTALL_PREFIX:PATH=${ADVSSDepPath}"
|
||||
"-DPAHO_WITH_MQTT_C=ON"
|
||||
"-DPAHO_WITH_SSL=ON"
|
||||
)
|
||||
|
||||
# Try to find OpenSSL installed via winget
|
||||
$pf64 = Join-Path $Env:ProgramFiles "OpenSSL-Win64"
|
||||
$pf = Join-Path $Env:ProgramFiles "OpenSSL"
|
||||
$possibleDirs = @($pf64, $pf)
|
||||
$opensslDir = $possibleDirs | Where-Object { Test-Path (Join-Path $_ "include\openssl\ssl.h") } | Select-Object -First 1
|
||||
|
||||
if ($opensslDir) {
|
||||
Write-Host "Detected OpenSSL at: $opensslDir"
|
||||
$MqttCmakeArgs += "-DOPENSSL_ROOT_DIR=$opensslDir"
|
||||
$MqttCmakeArgs += "-DOPENSSL_CRYPTO_LIBRARY=$opensslDir\lib\VC\x64\MD\libcrypto.lib"
|
||||
$MqttCmakeArgs += "-DOPENSSL_SSL_LIBRARY=$opensslDir\lib\VC\x64\MD\libssl.lib"
|
||||
} else {
|
||||
Write-Warning "OpenSSL not found - maybe cmake will find it ..."
|
||||
}
|
||||
|
||||
Log-Information "Configuring paho.mqtt.cpp..."
|
||||
Invoke-External cmake -S ${MqttPath} -B ${MqttBuildPath} @MqttCmakeArgs
|
||||
|
||||
$MqttCmakeArgs = @(
|
||||
'--config', "${Configuration}"
|
||||
)
|
||||
|
||||
if ( $VerbosePreference -eq 'Continue' ) {
|
||||
$MqttCmakeArgs += ('--verbose')
|
||||
}
|
||||
|
||||
Log-Information "Building paho.mqtt.cpp..."
|
||||
Invoke-External cmake --build "${MqttBuildPath}" @MqttCmakeArgs
|
||||
|
||||
Log-Information "Install paho.mqtt.cpp..."
|
||||
Invoke-External cmake --install "${MqttBuildPath}" --prefix "${ADVSSDepPath}" @MqttCmakeArgs
|
||||
}
|
||||
|
||||
Build
|
||||
|
|
|
|||
4
.github/scripts/utils.zsh/check_macos
vendored
4
.github/scripts/utils.zsh/check_macos
vendored
|
|
@ -18,5 +18,7 @@ if (( ! ${+commands[brew]} )) {
|
|||
}
|
||||
|
||||
brew bundle --file ${SCRIPT_HOME}/.Brewfile
|
||||
rehash
|
||||
# Workaround to make sure locally built openssl is picked up by cmake
|
||||
brew uninstall --ignore-dependencies openssl@3 || true
|
||||
rehash || true
|
||||
log_group
|
||||
|
|
|
|||
1
.github/scripts/utils.zsh/setup_ccache
vendored
1
.github/scripts/utils.zsh/setup_ccache
vendored
|
|
@ -10,7 +10,6 @@ if (( ${+commands[ccache]} )) {
|
|||
|
||||
typeset -gx CCACHE_CONFIGPATH="${project_root}/.ccache.conf"
|
||||
|
||||
ccache --set-config=run_second_cpp=true
|
||||
ccache --set-config=direct_mode=true
|
||||
ccache --set-config=inode_cache=true
|
||||
ccache --set-config=compiler_check=content
|
||||
|
|
|
|||
1
.github/scripts/utils.zsh/setup_linux
vendored
1
.github/scripts/utils.zsh/setup_linux
vendored
|
|
@ -41,6 +41,7 @@ if (( ! (${skips[(Ie)all]} + ${skips[(Ie)deps]}) )) {
|
|||
sudo apt-get install ${apt_args} \
|
||||
build-essential \
|
||||
libgles2-mesa-dev \
|
||||
libsimde-dev \
|
||||
obs-studio
|
||||
|
||||
local -a _qt_packages=()
|
||||
|
|
|
|||
0
.github/test
vendored
0
.github/test
vendored
2
.github/workflows/build-debian.yml
vendored
2
.github/workflows/build-debian.yml
vendored
|
|
@ -43,7 +43,7 @@ jobs:
|
|||
# devscripts and libobs-dev are needed but they were already installed
|
||||
# from check_libobs_revision and install_frontend_header sections.
|
||||
sudo apt update
|
||||
sudo apt install cmake debhelper libcurl4-openssl-dev libxss-dev libxtst-dev qtbase5-dev libopencv-dev libprocps-dev
|
||||
sudo apt install build-essential cmake debhelper libcurl4-openssl-dev libxss-dev libxtst-dev qt6-base-dev libopencv-dev libproc2-dev
|
||||
- name: build
|
||||
run: |
|
||||
debuild --no-lintian --no-sign
|
||||
|
|
|
|||
21
.github/workflows/build-project.yaml
vendored
21
.github/workflows/build-project.yaml
vendored
|
|
@ -6,11 +6,11 @@ on:
|
|||
description: "Project name detected by parsing build spec file"
|
||||
value: ${{ jobs.check-event.outputs.pluginName }}
|
||||
env:
|
||||
DEP_DIR: .deps/advss-build-dependencies
|
||||
DEP_DIR: .deps/advss-build-dependencies-3
|
||||
jobs:
|
||||
check-event:
|
||||
name: Check GitHub Event Data 🔎
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
|
@ -75,7 +75,7 @@ jobs:
|
|||
|
||||
macos-build:
|
||||
name: Build for macOS 🍏
|
||||
runs-on: macos-14
|
||||
runs-on: macos-15
|
||||
needs: check-event
|
||||
defaults:
|
||||
run:
|
||||
|
|
@ -107,8 +107,8 @@ jobs:
|
|||
print "pluginName=${product_name}" >> $GITHUB_OUTPUT
|
||||
print "pluginVersion=${git_tag}" >> $GITHUB_OUTPUT
|
||||
|
||||
print '::group::Enable Xcode 15.2'
|
||||
sudo xcode-select --switch /Applications/Xcode_15.2.app/Contents/Developer
|
||||
print '::group::Enable Xcode 16.1'
|
||||
sudo xcode-select --switch /Applications/Xcode_16.1.0.app/Contents/Developer
|
||||
print '::endgroup::'
|
||||
|
||||
- uses: actions/cache@v4
|
||||
|
|
@ -177,7 +177,7 @@ jobs:
|
|||
|
||||
ubuntu-build:
|
||||
name: Build for Ubuntu 🐧
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
needs: check-event
|
||||
defaults:
|
||||
run:
|
||||
|
|
@ -210,6 +210,11 @@ jobs:
|
|||
restore-keys: |
|
||||
${{ runner.os }}-ccache-x86_64-
|
||||
|
||||
- name: Set up CMake 🏗️
|
||||
uses: jwlawson/actions-setup-cmake@v1.13
|
||||
with:
|
||||
cmake-version: '3.x.x'
|
||||
|
||||
- name: Set up Homebrew 🍺
|
||||
uses: Homebrew/actions/setup-homebrew@master
|
||||
|
||||
|
|
@ -241,14 +246,14 @@ jobs:
|
|||
- name: Upload Artifacts 📡
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-ubuntu-22.04-x86_64-${{ needs.check-event.outputs.commitHash }}
|
||||
name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-ubuntu-24.04-x86_64-${{ needs.check-event.outputs.commitHash }}
|
||||
path: ${{ github.workspace }}/release/${{ steps.setup.outputs.pluginName }}-*-x86_64*.*
|
||||
|
||||
- name: Upload debug symbol artifacts 🪲
|
||||
uses: actions/upload-artifact@v4
|
||||
if: ${{ fromJSON(needs.check-event.outputs.package) }}
|
||||
with:
|
||||
name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-ubuntu-22.04-x86_64-${{ needs.check-event.outputs.commitHash }}-dbgsym
|
||||
name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-ubuntu-24.04-x86_64-${{ needs.check-event.outputs.commitHash }}-dbgsym
|
||||
path: ${{ github.workspace }}/release/${{ steps.setup.outputs.pluginName }}-*-x86_64*-dbgsym.ddeb
|
||||
|
||||
windows-build:
|
||||
|
|
|
|||
4
.github/workflows/check-format.yaml
vendored
4
.github/workflows/check-format.yaml
vendored
|
|
@ -3,7 +3,7 @@ on:
|
|||
workflow_call:
|
||||
jobs:
|
||||
clang-format:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
|
|
@ -15,7 +15,7 @@ jobs:
|
|||
failCondition: error
|
||||
|
||||
cmake-format:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
|
|
|
|||
4
.github/workflows/push.yaml
vendored
4
.github/workflows/push.yaml
vendored
|
|
@ -31,7 +31,7 @@ jobs:
|
|||
create-release:
|
||||
name: Create Release 🛫
|
||||
if: github.ref_type == 'tag'
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
needs: build-project
|
||||
defaults:
|
||||
run:
|
||||
|
|
@ -77,7 +77,7 @@ jobs:
|
|||
variants=(
|
||||
'windows-x64;zip|exe'
|
||||
'macos-universal;tar.xz|pkg'
|
||||
'ubuntu-22.04-x86_64;tar.xz|deb|ddeb'
|
||||
'ubuntu-24.04-x86_64;tar.xz|deb|ddeb'
|
||||
'sources;tar.xz'
|
||||
)
|
||||
|
||||
|
|
|
|||
9
.gitmodules
vendored
9
.gitmodules
vendored
|
|
@ -28,3 +28,12 @@
|
|||
[submodule "deps/libusb"]
|
||||
path = deps/libusb
|
||||
url = https://github.com/libusb/libusb.git
|
||||
[submodule "deps/date"]
|
||||
path = deps/date
|
||||
url = https://github.com/HowardHinnant/date.git
|
||||
[submodule "deps/jsoncons"]
|
||||
path = deps/jsoncons
|
||||
url = https://github.com/danielaparker/jsoncons.git
|
||||
[submodule "deps/paho.mqtt.cpp"]
|
||||
path = deps/paho.mqtt.cpp
|
||||
url = https://github.com/eclipse-paho/paho.mqtt.cpp.git
|
||||
|
|
|
|||
|
|
@ -6,18 +6,18 @@ You have the option to ...
|
|||
|
||||
Both methods require [CMake](https://cmake.org/download/).
|
||||
|
||||
The plugin can be compiled for OBS 27 and above, although using the latest version of OBS is recommended to support all features.
|
||||
The plugin can be compiled for OBS 31 and above, although using the latest version of OBS is recommended to support all features.
|
||||
|
||||
## Compiling in tree (recommended for development)
|
||||
This section assumes that you have a working [OBS Studio development environment](https://obsproject.com/wiki/Building-OBS-Studio).
|
||||
|
||||
Add the "SceneSwitcher" source directory to your obs-studio source directory under obs-studio/UI/frontend-plugins/:
|
||||
Add the "SceneSwitcher" source directory to your obs-studio source directory under obs-studio/plugins:
|
||||
```
|
||||
cd obs-studio/UI/frontend-plugins/
|
||||
cd obs-studio/plugins
|
||||
git clone --recursive https://github.com/WarmUpTill/SceneSwitcher.git
|
||||
```
|
||||
|
||||
Then modify the obs-studio/UI/frontend-plugins/CMakeLists.txt Example and add an entry for the scene switcher:
|
||||
Then modify the obs-studio/plugins/CMakeLists.txt and add an entry for the scene switcher:
|
||||
```
|
||||
add_subdirectory(SceneSwitcher)
|
||||
```
|
||||
|
|
|
|||
112
CMakeLists.txt
112
CMakeLists.txt
|
|
@ -1,4 +1,4 @@
|
|||
cmake_minimum_required(VERSION 3.16...3.26)
|
||||
cmake_minimum_required(VERSION 3.21...3.26)
|
||||
|
||||
project(advanced-scene-switcher VERSION 1.0.0)
|
||||
|
||||
|
|
@ -20,6 +20,12 @@ if(BUILD_OUT_OF_TREE)
|
|||
include(helpers)
|
||||
endif()
|
||||
|
||||
# OBS 31 no longer defines find_qt so check if we need to include it for in-tree
|
||||
# builds
|
||||
if(NOT COMMAND find_qt)
|
||||
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/common/helpers_common.cmake")
|
||||
endif()
|
||||
|
||||
set(LIB_NAME "${PROJECT_NAME}-lib")
|
||||
add_library(${PROJECT_NAME} MODULE)
|
||||
add_library(${LIB_NAME} SHARED)
|
||||
|
|
@ -27,6 +33,16 @@ add_library(${LIB_NAME} SHARED)
|
|||
include(cmake/common/get_git_revision_description.cmake)
|
||||
get_git_head_revision(GIT_REFSPEC GIT_SHA1)
|
||||
git_describe(GIT_TAG)
|
||||
|
||||
# Helper for OpenSSL
|
||||
if(OS_WINDOWS)
|
||||
include(cmake/windows/wingetssl.cmake)
|
||||
endif()
|
||||
|
||||
if(${GIT_TAG} STREQUAL "GIT-NOTFOUND")
|
||||
set(GIT_TAG ${PROJECT_VERSION})
|
||||
endif()
|
||||
message(STATUS "${PROJECT_NAME} version: ${GIT_TAG}")
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/common/version.cpp.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/lib/version.cpp" @ONLY)
|
||||
|
||||
|
|
@ -92,8 +108,6 @@ target_sources(
|
|||
lib/macro/macro-action-macro.hpp
|
||||
lib/macro/macro-action-queue.cpp
|
||||
lib/macro/macro-action-queue.hpp
|
||||
lib/macro/macro-action-script.cpp
|
||||
lib/macro/macro-action-script.hpp
|
||||
lib/macro/macro-action-variable.cpp
|
||||
lib/macro/macro-action-variable.hpp
|
||||
lib/macro/macro-action.cpp
|
||||
|
|
@ -106,8 +120,6 @@ target_sources(
|
|||
lib/macro/macro-condition-macro.hpp
|
||||
lib/macro/macro-condition-queue.cpp
|
||||
lib/macro/macro-condition-queue.hpp
|
||||
lib/macro/macro-condition-script.cpp
|
||||
lib/macro/macro-condition-script.hpp
|
||||
lib/macro/macro-condition-tempvar.cpp
|
||||
lib/macro/macro-condition-tempvar.hpp
|
||||
lib/macro/macro-condition-variable.cpp
|
||||
|
|
@ -116,6 +128,12 @@ target_sources(
|
|||
lib/macro/macro-condition.hpp
|
||||
lib/macro/macro-dock.cpp
|
||||
lib/macro/macro-dock.hpp
|
||||
lib/macro/macro-dock-settings.hpp
|
||||
lib/macro/macro-dock-settings.cpp
|
||||
lib/macro/macro-dock-window.cpp
|
||||
lib/macro/macro-dock-window.hpp
|
||||
lib/macro/macro-edit.cpp
|
||||
lib/macro/macro-edit.hpp
|
||||
lib/macro/macro-export-import-dialog.cpp
|
||||
lib/macro/macro-export-import-dialog.hpp
|
||||
lib/macro/macro-helpers.cpp
|
||||
|
|
@ -128,25 +146,27 @@ target_sources(
|
|||
lib/macro/macro-ref.hpp
|
||||
lib/macro/macro-run-button.cpp
|
||||
lib/macro/macro-run-button.hpp
|
||||
lib/macro/macro-script-handler.cpp
|
||||
lib/macro/macro-script-handler.hpp
|
||||
lib/macro/macro-search.cpp
|
||||
lib/macro/macro-search.hpp
|
||||
lib/macro/macro-segment-copy-paste.cpp
|
||||
lib/macro/macro-segment-copy-paste.hpp
|
||||
lib/macro/macro-segment-list.cpp
|
||||
lib/macro/macro-segment-list.hpp
|
||||
lib/macro/macro-segment-script.cpp
|
||||
lib/macro/macro-segment-script.hpp
|
||||
lib/macro/macro-segment-selection.cpp
|
||||
lib/macro/macro-segment-selection.hpp
|
||||
lib/macro/macro-segment-unknown.hpp
|
||||
lib/macro/macro-segment.cpp
|
||||
lib/macro/macro-segment.hpp
|
||||
lib/macro/macro-selection.cpp
|
||||
lib/macro/macro-selection.hpp
|
||||
lib/macro/macro-settings.cpp
|
||||
lib/macro/macro-settings.hpp
|
||||
lib/macro/macro-signals.cpp
|
||||
lib/macro/macro-signals.hpp
|
||||
lib/macro/macro-tab.cpp
|
||||
lib/macro/macro-tree.cpp
|
||||
lib/macro/macro-tree.hpp
|
||||
lib/macro/macro-websocket-trigger.cpp
|
||||
lib/macro/macro.cpp
|
||||
lib/macro/macro.hpp)
|
||||
|
||||
|
|
@ -157,10 +177,16 @@ target_sources(
|
|||
lib/queue/action-queue.hpp
|
||||
lib/queue/action-queue-tab.cpp
|
||||
lib/queue/action-queue-tab.hpp
|
||||
lib/utils/auto-update-tooltip-label.cpp
|
||||
lib/utils/auto-update-tooltip-label.hpp
|
||||
lib/utils/backup.cpp
|
||||
lib/utils/backup.hpp
|
||||
lib/utils/canvas-helpers.cpp
|
||||
lib/utils/canvas-helpers.hpp
|
||||
lib/utils/condition-logic.cpp
|
||||
lib/utils/condition-logic.hpp
|
||||
lib/utils/crash-handler.cpp
|
||||
lib/utils/crash-handler.hpp
|
||||
lib/utils/curl-helper.cpp
|
||||
lib/utils/curl-helper.hpp
|
||||
lib/utils/cursor-shape-changer.cpp
|
||||
|
|
@ -178,10 +204,14 @@ target_sources(
|
|||
lib/utils/file-selection.hpp
|
||||
lib/utils/filter-combo-box.cpp
|
||||
lib/utils/filter-combo-box.hpp
|
||||
lib/utils/first-run-wizard.cpp
|
||||
lib/utils/first-run-wizard.hpp
|
||||
lib/utils/help-icon.hpp
|
||||
lib/utils/help-icon.cpp
|
||||
lib/utils/item-selection-helpers.cpp
|
||||
lib/utils/item-selection-helpers.hpp
|
||||
lib/utils/json-helpers.cpp
|
||||
lib/utils/json-helpers.hpp
|
||||
lib/utils/layout-helpers.cpp
|
||||
lib/utils/layout-helpers.hpp
|
||||
lib/utils/list-controls.cpp
|
||||
|
|
@ -208,17 +238,14 @@ target_sources(
|
|||
lib/utils/plugin-state-helpers.hpp
|
||||
lib/utils/priority-helper.cpp
|
||||
lib/utils/priority-helper.hpp
|
||||
lib/utils/properties-view.cpp
|
||||
lib/utils/properties-view.hpp
|
||||
lib/utils/properties-view.moc.hpp
|
||||
lib/utils/regex-config.cpp
|
||||
lib/utils/regex-config.hpp
|
||||
lib/utils/resizable-widget.cpp
|
||||
lib/utils/resizable-widget.hpp
|
||||
lib/utils/resizing-text-edit.cpp
|
||||
lib/utils/resizing-text-edit.hpp
|
||||
lib/utils/resource-table.cpp
|
||||
lib/utils/resource-table.hpp
|
||||
lib/utils/resource-table-hotkey-handler.cpp
|
||||
lib/utils/resource-table-hotkey-handler.hpp
|
||||
lib/utils/scene-selection.cpp
|
||||
lib/utils/scene-selection.hpp
|
||||
lib/utils/scene-switch-helpers.cpp
|
||||
|
|
@ -287,9 +314,16 @@ include(cmake/common/advss_helpers.cmake)
|
|||
setup_obs_lib_dependency(${LIB_NAME})
|
||||
setup_obs_lib_dependency(${PROJECT_NAME})
|
||||
|
||||
find_qt(COMPONENTS Widgets Core)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE Qt::Core Qt::Widgets)
|
||||
target_link_libraries(${LIB_NAME} PRIVATE Qt::Core Qt::Widgets)
|
||||
find_package(Qt6 REQUIRED COMPONENTS Widgets Core)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Core Qt6::Widgets)
|
||||
target_link_libraries(${LIB_NAME} PRIVATE Qt6::Core Qt6::Widgets)
|
||||
|
||||
# Ignore QCheckBox::stateChanged deprecation warning until minimum supported Qt
|
||||
# version is at least Qt 6.7, which introduces QCheckBox::checkStateChanged
|
||||
if(Qt6_VERSION VERSION_GREATER "6.0.0")
|
||||
target_compile_definitions(${LIB_NAME} PRIVATE QT_NO_DEPRECATED_WARNINGS)
|
||||
endif()
|
||||
|
||||
target_compile_options(
|
||||
${PROJECT_NAME}
|
||||
PRIVATE
|
||||
|
|
@ -338,6 +372,21 @@ else()
|
|||
endif()
|
||||
target_link_libraries(${LIB_NAME} PUBLIC nlohmann_json::nlohmann_json)
|
||||
|
||||
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/deps/jsoncons/CMakeLists.txt")
|
||||
# Don't build jsoncons unit tests as they are causing compilation issues and
|
||||
# won't be executed either way
|
||||
if(OS_MACOS)
|
||||
cmake_policy(SET CMP0077 NEW)
|
||||
endif()
|
||||
set(JSONCONS_BUILD_TESTS
|
||||
OFF
|
||||
CACHE BOOL "" FORCE)
|
||||
|
||||
add_subdirectory(deps/jsoncons EXCLUDE_FROM_ALL)
|
||||
target_link_libraries(${LIB_NAME} PRIVATE jsoncons)
|
||||
target_compile_definitions(${LIB_NAME} PRIVATE JSONPATH_SUPPORT=1)
|
||||
endif()
|
||||
|
||||
find_package(CURL QUIET)
|
||||
find_package(Libcurl QUIET)
|
||||
if(CURL_FOUND)
|
||||
|
|
@ -391,6 +440,7 @@ else()
|
|||
set_target_properties(${LIB_NAME} PROPERTIES PREFIX "")
|
||||
set_target_properties(${LIB_NAME} PROPERTIES SOVERSION 1)
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS DBus)
|
||||
find_package(X11 REQUIRED COMPONENTS Xss)
|
||||
target_include_directories(${LIB_NAME} PRIVATE "${X11_INCLUDE_DIR}"
|
||||
"${X11_Xss_INCLUDE_PATH}")
|
||||
|
|
@ -405,10 +455,30 @@ else()
|
|||
set(PROCESS_CONDITION_SUPPORTED 1)
|
||||
endif()
|
||||
if(PROCPS2_INCLUDE_DIR)
|
||||
message(STATUS "${PROJECT_NAME} using libproc2")
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(libproc2 REQUIRED IMPORTED_TARGET libproc2)
|
||||
set(PROC_INCLUDE_DIR "${PROCPS2_INCLUDE_DIR}")
|
||||
target_compile_definitions(${LIB_NAME} PRIVATE PROCPS2_AVAILABLE)
|
||||
set(PROCESS_CONDITION_SUPPORTED 1)
|
||||
|
||||
# Check if PIDS_VAL takes 4 arguments (old API, pre-4.0.5) or 3 (new API)
|
||||
include(CheckCSourceCompiles)
|
||||
set(CMAKE_REQUIRED_INCLUDES "${PROCPS2_INCLUDE_DIR}")
|
||||
set(CMAKE_REQUIRED_LIBRARIES proc2)
|
||||
check_c_source_compiles(
|
||||
"
|
||||
#include <libproc2/pids.h>
|
||||
int main(void) {
|
||||
struct pids_stack *s = 0;
|
||||
struct pids_info *i = 0;
|
||||
(void)PIDS_VAL(0, str, s, i);
|
||||
return 0;
|
||||
}
|
||||
"
|
||||
PROCPS2_PIDS_VAL_TAKES_INFO)
|
||||
if(PROCPS2_PIDS_VAL_TAKES_INFO)
|
||||
target_compile_definitions(${LIB_NAME} PRIVATE PROCPS2_USE_INFO)
|
||||
endif()
|
||||
endif()
|
||||
if(NOT DEFINED PROCESS_CONDITION_SUPPORTED)
|
||||
message(
|
||||
|
|
@ -417,7 +487,11 @@ else()
|
|||
)
|
||||
endif()
|
||||
target_include_directories(${LIB_NAME} PRIVATE "${PROC_INCLUDE_DIR}")
|
||||
target_sources(${LIB_NAME} PRIVATE lib/linux/advanced-scene-switcher-nix.cpp)
|
||||
target_sources(${LIB_NAME} PRIVATE lib/linux/advanced-scene-switcher-nix.cpp
|
||||
lib/linux/kwin-helpers.cpp)
|
||||
|
||||
# Don't include irrelevant folders into sources archive
|
||||
list(APPEND CPACK_SOURCE_IGNORE_FILES "\\.deps/.*")
|
||||
endif()
|
||||
|
||||
if(NOT OS_WINDOWS)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ The **Snap** package manager offers an OBS Studio installation which is bundled
|
|||
sudo snap install obs-studio
|
||||
```
|
||||
|
||||
More information can be found [here](https://github.com/WarmUpTill/SceneSwitcher/wiki/Installation).
|
||||
|
||||
## Contributing
|
||||
|
||||
- If you wish to contribute code to the project, have a look at this [section](BUILDING.md) describing how to compile the plugin.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ Build-Depends: cmake,
|
|||
libcurl4-openssl-dev,
|
||||
libobs-dev,
|
||||
libxtst-dev,
|
||||
qtbase5-dev,
|
||||
qt6-base-dev,
|
||||
libxss-dev,
|
||||
libopencv-dev
|
||||
Standards-Version: 4.6.0
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
||||
|
||||
export QT_SELECT = qt5
|
||||
export QT_SELECT = qt6
|
||||
|
||||
%:
|
||||
dh $@
|
||||
|
|
|
|||
126
build-aux/CI/linux/demote-deps.sh
Executable file
126
build-aux/CI/linux/demote-deps.sh
Executable file
|
|
@ -0,0 +1,126 @@
|
|||
#!/usr/bin/env bash
|
||||
# Usage: demote_deps.sh <in.deb> [Recommends|Suggests] [regex]
|
||||
# Example: demote_deps.sh build/advanced-scene-switcher_1.31.0_amd64.deb Recommends 'opencv'
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -lt 1 ]]; then
|
||||
echo "Usage: $0 <in.deb> [Recommends|Suggests] [regex]" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IN_DEB="$1"
|
||||
DEST_FIELD="${2:-Recommends}" # Recommends or Suggests
|
||||
MATCH_REGEX="${3:-opencv}" # regex to match packages to demote
|
||||
|
||||
echo "Demoting dependencies matching '${MATCH_REGEX}' to ${DEST_FIELD}"
|
||||
|
||||
TMPDIR="$(mktemp -d)"
|
||||
trap 'rm -rf "$TMPDIR"' EXIT
|
||||
|
||||
dpkg-deb -R "$IN_DEB" "$TMPDIR"
|
||||
CONTROL="$TMPDIR/DEBIAN/control"
|
||||
|
||||
# Read a field (single line value), handling continuation lines starting with a space.
|
||||
get_field() {
|
||||
local key="$1"
|
||||
awk -v key="$key" '
|
||||
BEGIN { val=""; collecting=0 }
|
||||
$0 ~ "^" key ":" {
|
||||
collecting=1
|
||||
sub("^" key ":[[:space:]]*", "", $0)
|
||||
val=$0
|
||||
next
|
||||
}
|
||||
collecting==1 {
|
||||
if ($0 ~ "^[[:space:]]") {
|
||||
sub("^[[:space:]]+", "", $0)
|
||||
val = val " " $0
|
||||
next
|
||||
} else {
|
||||
collecting=0
|
||||
}
|
||||
}
|
||||
END { print val }
|
||||
' "$CONTROL"
|
||||
}
|
||||
|
||||
# Split a comma-separated list into lines, trimming whitespace
|
||||
split_csv() {
|
||||
tr ',' '\n' | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//' | sed '/^$/d'
|
||||
}
|
||||
|
||||
# Join with ", "
|
||||
join_csv() {
|
||||
awk 'BEGIN{first=1}{ if(!first) printf(", "); printf("%s",$0); first=0 } END{print ""}'
|
||||
}
|
||||
|
||||
# Deduplicate while preserving order
|
||||
dedup() {
|
||||
awk '!seen[$0]++'
|
||||
}
|
||||
|
||||
DEPENDS_VAL="$(get_field Depends)"
|
||||
EXIST_DEST_VAL="$(get_field "$DEST_FIELD")"
|
||||
|
||||
# Separate opencv-matching vs the rest (preserve tokens exactly)
|
||||
mapfile -t DEPENDS_ARR < <(printf "%s\n" "$DEPENDS_VAL" | split_csv)
|
||||
declare -a MOVED=()
|
||||
declare -a KEPT=()
|
||||
for item in "${DEPENDS_ARR[@]}"; do
|
||||
# Skip empty just in case
|
||||
[[ -z "$item" ]] && continue
|
||||
if [[ "$item" =~ $MATCH_REGEX ]]; then
|
||||
MOVED+=("$item")
|
||||
else
|
||||
KEPT+=("$item")
|
||||
fi
|
||||
done
|
||||
|
||||
# Merge with existing dest field
|
||||
if [[ -n "$EXIST_DEST_VAL" ]]; then
|
||||
mapfile -t EXIST_DEST_ARR < <(printf "%s\n" "$EXIST_DEST_VAL" | split_csv)
|
||||
MOVED+=("${EXIST_DEST_ARR[@]}")
|
||||
fi
|
||||
|
||||
# De-duplicate
|
||||
mapfile -t MOVED < <(printf "%s\n" "${MOVED[@]:-}" | sed '/^$/d' | dedup)
|
||||
mapfile -t KEPT < <(printf "%s\n" "${KEPT[@]:-}" | sed '/^$/d' | dedup)
|
||||
|
||||
# Rebuild values
|
||||
NEW_DEPENDS="$(printf "%s\n" "${KEPT[@]:-}" | join_csv || true)"
|
||||
NEW_DEST="$(printf "%s\n" "${MOVED[@]:-}" | join_csv || true)"
|
||||
|
||||
# Write a cleaned control (remove existing Depends/Recommends/Suggests incl. continuations)
|
||||
awk '
|
||||
BEGIN { skip=0 }
|
||||
{
|
||||
if ($0 ~ "^(Depends|Recommends|Suggests):") { skip=1; next }
|
||||
if (skip==1) {
|
||||
if ($0 ~ "^[[:space:]]") { next } else { skip=0 }
|
||||
}
|
||||
print
|
||||
}
|
||||
' "$CONTROL" > "$CONTROL.clean"
|
||||
|
||||
# Append the rebuilt fields
|
||||
{
|
||||
cat "$CONTROL.clean"
|
||||
if [[ -n "$NEW_DEPENDS" ]]; then
|
||||
echo "Depends: $NEW_DEPENDS"
|
||||
fi
|
||||
if [[ -n "$NEW_DEST" ]]; then
|
||||
echo "$DEST_FIELD: $NEW_DEST"
|
||||
fi
|
||||
} > "$CONTROL.new"
|
||||
|
||||
# Clean up empty lines
|
||||
sed -i '/^[[:space:]]*$/d' "$CONTROL.new"
|
||||
|
||||
mv "$CONTROL.new" "$CONTROL"
|
||||
rm -f "$CONTROL.clean"
|
||||
|
||||
# Repack
|
||||
rm -f "${IN_DEB}"
|
||||
OUT_DEB="${IN_DEB}"
|
||||
dpkg-deb -b "$TMPDIR" "$OUT_DEB" >/dev/null
|
||||
echo "$OUT_DEB"
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -1,33 +1,33 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"obs-studio": {
|
||||
"version": "30.1.2",
|
||||
"version": "31.1.1",
|
||||
"baseUrl": "https://github.com/obsproject/obs-studio/archive/refs/tags",
|
||||
"label": "OBS sources",
|
||||
"hashes": {
|
||||
"macos": "490bae1c392b3b344b0270afd8cb887da4bc50bd92c0c426e96713c1ccb9701a",
|
||||
"windows-x64": "c2dd03fa7fd01fad5beafce8f7156da11f9ed9a588373fd40b44a06f4c03b867"
|
||||
"macos": "39751f067bacc13d44b116c5138491b5f1391f91516d3d590d874edd21292291",
|
||||
"windows-x64": "2c8427c10b55ac6d68008df2e9a3e82f4647aaad18f105e30d4713c2de678ccf"
|
||||
}
|
||||
},
|
||||
"prebuilt": {
|
||||
"version": "2024-03-19",
|
||||
"version": "2025-07-11",
|
||||
"baseUrl": "https://github.com/obsproject/obs-deps/releases/download",
|
||||
"label": "Pre-Built obs-deps",
|
||||
"hashes": {
|
||||
"macos": "2e9bfb55a5e0e4c1086fa1fda4cf268debfead473089df2aaea80e1c7a3ca7ff",
|
||||
"windows-x64": "6e86068371526a967e805f6f9903f9407adb683c21820db5f07da8f30d11e998"
|
||||
"macos": "495687e63383d1a287684b6e2e9bfe246bb8f156fe265926afb1a325af1edd2a",
|
||||
"windows-x64": "c8c642c1070dc31ce9a0f1e4cef5bb992f4bff4882255788b5da12129e85caa7"
|
||||
}
|
||||
},
|
||||
"qt6": {
|
||||
"version": "2024-03-19",
|
||||
"version": "2025-07-11",
|
||||
"baseUrl": "https://github.com/obsproject/obs-deps/releases/download",
|
||||
"label": "Pre-Built Qt6",
|
||||
"hashes": {
|
||||
"macos": "694f1e639c017e3b1f456f735330dc5afae287cbea85757101af1368de3142c8",
|
||||
"windows-x64": "72d1df34a0ef7413a681d5fcc88cae81da60adc03dcd23ef17862ab170bcc0dd"
|
||||
"macos": "d3f5f04b6ea486e032530bdf0187cbda9a54e0a49621a4c8ba984c5023998867",
|
||||
"windows-x64": "0e76bf0555dd5382838850b748d3dcfab44a1e1058441309ab54e1a65b156d0a"
|
||||
},
|
||||
"debugSymbols": {
|
||||
"windows-x64": "fbddd1f659c360f2291911ac5709b67b6f8182e6bca519d24712e4f6fd3cc865"
|
||||
"windows-x64": "11b7be92cf66a273299b8f3515c07a5cfb61614b59a4e67f7fc5ecba5e2bdf21"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -283,8 +283,14 @@ endfunction()
|
|||
|
||||
function(setup_advss_plugin target)
|
||||
setup_obs_lib_dependency(${target})
|
||||
find_qt(COMPONENTS Widgets Core)
|
||||
target_link_libraries(${target} PRIVATE Qt::Core Qt::Widgets)
|
||||
find_package(Qt6 REQUIRED COMPONENTS Widgets Core)
|
||||
target_link_libraries(${target} PRIVATE Qt6::Core Qt6::Widgets)
|
||||
|
||||
# Ignore QCheckBox::stateChanged deprecation warning until minimum supported
|
||||
# Qt version is at least Qt 6.7, which introduces QCheckBox::checkStateChanged
|
||||
if(Qt6_VERSION VERSION_GREATER "6.7.0")
|
||||
target_compile_definitions(${target} PRIVATE QT_NO_DEPRECATED_WARNINGS)
|
||||
endif()
|
||||
|
||||
set_target_properties(
|
||||
${target}
|
||||
|
|
|
|||
|
|
@ -65,17 +65,16 @@ function(_setup_obs_studio)
|
|||
|
||||
if(OS_WINDOWS)
|
||||
set(_cmake_generator "${CMAKE_GENERATOR}")
|
||||
set(_cmake_arch "-A ${arch}")
|
||||
set(_cmake_arch
|
||||
"-A ${arch},version=${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}")
|
||||
set(_cmake_extra
|
||||
"-DCMAKE_SYSTEM_VERSION=${CMAKE_SYSTEM_VERSION} -DCMAKE_ENABLE_SCRIPTING=OFF"
|
||||
)
|
||||
set(_cmake_version "2.0.0")
|
||||
elseif(OS_MACOS)
|
||||
set(_cmake_generator "Xcode")
|
||||
set(_cmake_arch "-DCMAKE_OSX_ARCHITECTURES:STRING='arm64;x86_64'")
|
||||
set(_cmake_extra
|
||||
"-DCMAKE_OSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}")
|
||||
set(_cmake_version "3.0.0")
|
||||
endif()
|
||||
|
||||
message(STATUS "Configure ${label} (${arch})")
|
||||
|
|
@ -83,32 +82,42 @@ function(_setup_obs_studio)
|
|||
COMMAND
|
||||
"${CMAKE_COMMAND}" -S "${dependencies_dir}/${_obs_destination}" -B
|
||||
"${dependencies_dir}/${_obs_destination}/build_${arch}" -G
|
||||
${_cmake_generator} "${_cmake_arch}"
|
||||
-DOBS_CMAKE_VERSION:STRING=${_cmake_version} -DENABLE_PLUGINS:BOOL=OFF
|
||||
-DENABLE_UI:BOOL=OFF -DOBS_VERSION_OVERRIDE:STRING=${_obs_version}
|
||||
${_cmake_generator} "${_cmake_arch}" -DOBS_CMAKE_VERSION:STRING=3.0.0
|
||||
-DENABLE_PLUGINS:BOOL=OFF -DENABLE_FRONTEND:BOOL=OFF
|
||||
-DOBS_VERSION_OVERRIDE:STRING=${_obs_version}
|
||||
"-DCMAKE_PREFIX_PATH='${CMAKE_PREFIX_PATH}'" ${_is_fresh} ${_cmake_extra}
|
||||
RESULT_VARIABLE _process_result COMMAND_ERROR_IS_FATAL ANY
|
||||
OUTPUT_QUIET)
|
||||
message(STATUS "Configure ${label} (${arch}) - done")
|
||||
|
||||
message(STATUS "Build ${label} (${arch})")
|
||||
message(STATUS "Build ${label} (Debug - ${arch})")
|
||||
execute_process(
|
||||
COMMAND "${CMAKE_COMMAND}" --build build_${arch} --target obs-frontend-api
|
||||
--config Debug --parallel
|
||||
WORKING_DIRECTORY "${dependencies_dir}/${_obs_destination}"
|
||||
RESULT_VARIABLE _process_result COMMAND_ERROR_IS_FATAL ANY
|
||||
OUTPUT_QUIET)
|
||||
message(STATUS "Build ${label} (${arch}) - done")
|
||||
message(STATUS "Build ${label} (Debug - ${arch}) - done")
|
||||
|
||||
message(STATUS "Build ${label} (Release - ${arch})")
|
||||
execute_process(
|
||||
COMMAND "${CMAKE_COMMAND}" --build build_${arch} --target obs-frontend-api
|
||||
--config Release --parallel
|
||||
WORKING_DIRECTORY "${dependencies_dir}/${_obs_destination}"
|
||||
RESULT_VARIABLE _process_result COMMAND_ERROR_IS_FATAL ANY
|
||||
OUTPUT_QUIET)
|
||||
message(STATUS "Build ${label} (Reelase - ${arch}) - done")
|
||||
|
||||
message(STATUS "Install ${label} (${arch})")
|
||||
if(OS_WINDOWS)
|
||||
set(_cmake_extra "--component obs_libraries")
|
||||
else()
|
||||
set(_cmake_extra "")
|
||||
endif()
|
||||
execute_process(
|
||||
COMMAND "${CMAKE_COMMAND}" --install build_${arch} --component Development
|
||||
--config Debug --prefix "${dependencies_dir}" ${_cmake_extra}
|
||||
--config Debug --prefix "${dependencies_dir}"
|
||||
WORKING_DIRECTORY "${dependencies_dir}/${_obs_destination}"
|
||||
RESULT_VARIABLE _process_result COMMAND_ERROR_IS_FATAL ANY
|
||||
OUTPUT_QUIET)
|
||||
execute_process(
|
||||
COMMAND "${CMAKE_COMMAND}" --install build_${arch} --component Development
|
||||
--config Release --prefix "${dependencies_dir}"
|
||||
WORKING_DIRECTORY "${dependencies_dir}/${_obs_destination}"
|
||||
RESULT_VARIABLE _process_result COMMAND_ERROR_IS_FATAL ANY
|
||||
OUTPUT_QUIET)
|
||||
|
|
@ -171,24 +180,46 @@ function(_check_dependencies)
|
|||
set(url ${url}/${version}/${file})
|
||||
endif()
|
||||
|
||||
set(MAX_DOWNLOAD_RETRIES 3)
|
||||
set(RETRY_DELAY 60) # seconds
|
||||
|
||||
if(NOT EXISTS "${dependencies_dir}/${file}")
|
||||
message(STATUS "Downloading ${url}")
|
||||
file(
|
||||
DOWNLOAD "${url}" "${dependencies_dir}/${file}"
|
||||
STATUS download_status
|
||||
EXPECTED_HASH SHA256=${hash})
|
||||
|
||||
list(GET download_status 0 error_code)
|
||||
list(GET download_status 1 error_message)
|
||||
if(error_code GREATER 0)
|
||||
message(STATUS "Downloading ${url} - Failure")
|
||||
set(download_success FALSE)
|
||||
|
||||
foreach(i RANGE 1 ${MAX_DOWNLOAD_RETRIES})
|
||||
message(STATUS "Attempt ${i}/${MAX_DOWNLOAD_RETRIES} for ${url}")
|
||||
|
||||
file(
|
||||
DOWNLOAD "${url}" "${dependencies_dir}/${file}"
|
||||
STATUS download_status
|
||||
EXPECTED_HASH SHA256=${hash})
|
||||
|
||||
list(GET download_status 0 error_code)
|
||||
list(GET download_status 1 error_message)
|
||||
|
||||
if(error_code EQUAL 0)
|
||||
message(STATUS "Downloading ${url} - success on attempt ${i}")
|
||||
set(download_success TRUE)
|
||||
break()
|
||||
else()
|
||||
message(WARNING "Download failed (attempt ${i}): ${error_message}")
|
||||
file(REMOVE "${dependencies_dir}/${file}")
|
||||
|
||||
if(NOT i EQUAL MAX_DOWNLOAD_RETRIES)
|
||||
message(STATUS "Retrying in ${RETRY_DELAY} seconds...")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E sleep ${RETRY_DELAY})
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(NOT download_success)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Unable to download ${url}, failed with error: ${error_message}")
|
||||
file(REMOVE "${dependencies_dir}/${file}")
|
||||
else()
|
||||
message(STATUS "Downloading ${url} - done")
|
||||
"Unable to download ${url} after ${MAX_DOWNLOAD_RETRIES} attempts")
|
||||
endif()
|
||||
message(STATUS "Downloading ${url} - done")
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${dependencies_dir}/${destination}")
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ function(_git_find_closest_git_dir _start_dir _git_dir_var)
|
|||
while(NOT EXISTS "${git_dir}")
|
||||
# .git dir not found, search parent directories
|
||||
set(git_previous_parent "${cur_dir}")
|
||||
get_filename_component(cur_dir ${cur_dir} DIRECTORY)
|
||||
get_filename_component(cur_dir "${cur_dir}" DIRECTORY)
|
||||
if(cur_dir STREQUAL git_previous_parent)
|
||||
# We have reached the root directory, we are not in git
|
||||
set(${_git_dir_var}
|
||||
|
|
|
|||
|
|
@ -17,85 +17,6 @@ if(NOT QT_VERSION)
|
|||
set_property(CACHE QT_VERSION PROPERTY STRINGS AUTO 5 6)
|
||||
endif()
|
||||
|
||||
# find_qt: Macro to find best possible Qt version for use with the project:
|
||||
macro(find_qt)
|
||||
set(multiValueArgs COMPONENTS COMPONENTS_WIN COMPONENTS_MAC COMPONENTS_LINUX)
|
||||
cmake_parse_arguments(find_qt "" "${oneValueArgs}" "${multiValueArgs}"
|
||||
${ARGN})
|
||||
|
||||
# Do not use versionless targets in the first step to avoid Qt::Core being
|
||||
# clobbered by later opportunistic find_package runs
|
||||
set(QT_NO_CREATE_VERSIONLESS_TARGETS TRUE)
|
||||
|
||||
message(DEBUG "Start Qt version discovery...")
|
||||
# Loop until _QT_VERSION is set or FATAL_ERROR aborts script execution early
|
||||
while(NOT _QT_VERSION)
|
||||
message(DEBUG "QT_VERSION set to ${QT_VERSION}")
|
||||
if(QT_VERSION STREQUAL AUTO AND NOT qt_test_version)
|
||||
set(qt_test_version 6)
|
||||
elseif(NOT QT_VERSION STREQUAL AUTO)
|
||||
set(qt_test_version ${QT_VERSION})
|
||||
endif()
|
||||
message(DEBUG "Attempting to find Qt${qt_test_version}")
|
||||
|
||||
find_package(
|
||||
Qt${qt_test_version}
|
||||
COMPONENTS Core
|
||||
QUIET)
|
||||
|
||||
if(TARGET Qt${qt_test_version}::Core)
|
||||
set(_QT_VERSION
|
||||
${qt_test_version}
|
||||
CACHE INTERNAL "")
|
||||
message(STATUS "Qt version found: ${_QT_VERSION}")
|
||||
unset(qt_test_version)
|
||||
break()
|
||||
elseif(QT_VERSION STREQUAL AUTO)
|
||||
if(qt_test_version EQUAL 6)
|
||||
message(WARNING "Qt6 was not found, falling back to Qt5")
|
||||
set(qt_test_version 5)
|
||||
continue()
|
||||
endif()
|
||||
endif()
|
||||
message(FATAL_ERROR "Neither Qt6 nor Qt5 found.")
|
||||
endwhile()
|
||||
|
||||
# Enable versionless targets for the remaining Qt components
|
||||
set(QT_NO_CREATE_VERSIONLESS_TARGETS FALSE)
|
||||
|
||||
set(qt_components ${find_qt_COMPONENTS})
|
||||
if(OS_WINDOWS)
|
||||
list(APPEND qt_components ${find_qt_COMPONENTS_WIN})
|
||||
elseif(OS_MACOS)
|
||||
list(APPEND qt_components ${find_qt_COMPONENTS_MAC})
|
||||
else()
|
||||
list(APPEND qt_components ${find_qt_COMPONENTS_LINUX})
|
||||
endif()
|
||||
message(DEBUG "Trying to find Qt components ${qt_components}...")
|
||||
|
||||
find_package(Qt${_QT_VERSION} REQUIRED ${qt_components})
|
||||
|
||||
list(APPEND qt_components Core)
|
||||
|
||||
if("Gui" IN_LIST find_qt_COMPONENTS_LINUX)
|
||||
list(APPEND qt_components "GuiPrivate")
|
||||
endif()
|
||||
|
||||
# Check for versionless targets of each requested component and create if
|
||||
# necessary
|
||||
foreach(component IN LISTS qt_components)
|
||||
message(DEBUG "Checking for target Qt::${component}")
|
||||
if(NOT TARGET Qt::${component} AND TARGET Qt${_QT_VERSION}::${component})
|
||||
add_library(Qt::${component} INTERFACE IMPORTED)
|
||||
set_target_properties(
|
||||
Qt::${component} PROPERTIES INTERFACE_LINK_LIBRARIES
|
||||
Qt${_QT_VERSION}::${component})
|
||||
endif()
|
||||
set_property(TARGET Qt::${component} PROPERTY INTERFACE_COMPILE_FEATURES "")
|
||||
endforeach()
|
||||
|
||||
endmacro()
|
||||
|
||||
# check_uuid: Helper function to check for valid UUID
|
||||
function(check_uuid uuid_string return_value)
|
||||
set(valid_uuid TRUE)
|
||||
|
|
|
|||
|
|
@ -80,6 +80,8 @@ function(set_target_properties_plugin target)
|
|||
|
||||
configure_file(cmake/windows/resources/installer-Windows.iss.in
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/installer-Windows.generated.iss")
|
||||
configure_file(data/res/images/logo.ico
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/installer.ico" COPYONLY)
|
||||
|
||||
configure_file(cmake/windows/resources/resource.rc.in
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.rc")
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@ OutputBaseFilename={#MyAppName}-{#MyAppVersion}-Windows-Installer
|
|||
Compression=lzma
|
||||
SolidCompression=yes
|
||||
DirExistsWarning=no
|
||||
SetupIconFile=installer.ico
|
||||
UninstallDisplayIcon={app}\data\obs-plugins\advanced-scene-switcher\res\images\logo.ico
|
||||
DisableDirPage=no
|
||||
|
||||
[Languages]
|
||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||
|
|
|
|||
78
cmake/windows/wingetssl.cmake
Normal file
78
cmake/windows/wingetssl.cmake
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
# ---------------------------------------------------------------------------
|
||||
# Detects OpenSSL installed via winget or other common Windows locations,
|
||||
# without requiring the user to manually set OPENSSL_ROOT_DIR.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
if(WIN32 AND (NOT OpenSSL_FOUND))
|
||||
|
||||
set(_openssl_roots
|
||||
"$ENV{ProgramFiles}/OpenSSL-Win64" "$ENV{ProgramFiles}/OpenSSL"
|
||||
"$ENV{ProgramW6432}/OpenSSL-Win64")
|
||||
|
||||
set(_openssl_lib_suffixes "lib/VC/x64/MD" "lib/VC/x64/MDd" "lib/VC/x64/MT"
|
||||
"lib/VC/x64/MTd" "lib")
|
||||
|
||||
# Determine which configuration we're building
|
||||
if(CMAKE_BUILD_TYPE MATCHES "Debug")
|
||||
set(_is_debug TRUE)
|
||||
else()
|
||||
set(_is_debug FALSE)
|
||||
endif()
|
||||
|
||||
# Determine which runtime we use Default to /MD (shared CRT)
|
||||
set(_crt_kind "MD")
|
||||
if(MSVC)
|
||||
if(CMAKE_MSVC_RUNTIME_LIBRARY MATCHES "MultiThreaded")
|
||||
if(CMAKE_MSVC_RUNTIME_LIBRARY MATCHES "Debug")
|
||||
set(_crt_kind "MTd")
|
||||
else()
|
||||
set(_crt_kind "MT")
|
||||
endif()
|
||||
else()
|
||||
if(_is_debug)
|
||||
set(_crt_kind "MDd")
|
||||
else()
|
||||
set(_crt_kind "MD")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message(STATUS "Looking for OpenSSL built with CRT variant: ${_crt_kind}")
|
||||
|
||||
# Try to find the root and corresponding lib path
|
||||
foreach(_root ${_openssl_roots})
|
||||
if(EXISTS "${_root}/include/openssl/ssl.h")
|
||||
foreach(_suffix ${_openssl_lib_suffixes})
|
||||
if(_suffix MATCHES "${_crt_kind}$"
|
||||
AND EXISTS "${_root}/${_suffix}/libcrypto.lib")
|
||||
set(OPENSSL_ROOT_DIR
|
||||
"${_root}"
|
||||
CACHE PATH "Path to OpenSSL root")
|
||||
set(OPENSSL_CRYPTO_LIBRARY
|
||||
"${_root}/${_suffix}/libcrypto.lib"
|
||||
CACHE FILEPATH "OpenSSL crypto lib")
|
||||
set(OPENSSL_SSL_LIBRARY
|
||||
"${_root}/${_suffix}/libssl.lib"
|
||||
CACHE FILEPATH "OpenSSL ssl lib")
|
||||
set(OPENSSL_INCLUDE_DIR
|
||||
"${_root}/include"
|
||||
CACHE PATH "OpenSSL include dir")
|
||||
set(OpenSSL_FOUND
|
||||
TRUE
|
||||
CACHE BOOL "Whether OpenSSL was found")
|
||||
message(STATUS "Found OpenSSL at: ${_root}/${_suffix}")
|
||||
return()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
if(OpenSSL_FOUND)
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(NOT OpenSSL_FOUND)
|
||||
message(WARNING "Could not auto-detect OpenSSL under Program Files. "
|
||||
"Might have to set OPENSSL_ROOT_DIR manually.")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
|
@ -12,7 +12,7 @@ AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Aktiviere den Szenenwe
|
|||
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Aktiviere den Szenenwechsler nicht"
|
||||
AdvSceneSwitcher.generalTab.status.start="Start"
|
||||
AdvSceneSwitcher.generalTab.status.stop="Stop"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart="Starte auotmatischen den Szenenwechsler beim:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.startup="Starte auotmatischen den Szenenwechsler beim:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.never="Niemals"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.recording="Aufnehmen"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Streamen"
|
||||
|
|
@ -26,7 +26,6 @@ AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchToRandom="Wechsle zu
|
|||
AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchTo="Wechsle zu:"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.cooldown="Nach Ausführen von Aktionen überspringe das Ausführen von Aktionen für"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint="In diesem Zeitraum werden potentielle erfüllte Bedingungen ignoriert!"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Ausführliches Logging"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="Fensterposition und -größe speichern"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="Benachrichtigungen im System-Tray anzeigen"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="Deaktiviere UI Tipps"
|
||||
|
|
@ -41,7 +40,7 @@ AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="Exportieren"
|
|||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Importieren"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Exportiere Erweiterter Automatischer Szenenwechsler Einstellungen zu Datei ..."
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Exportiere Erweiterter Automatischer Szenenwechsler Einstellungen von Datei ..."
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Text Dateien (*.txt)"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Text Dateien (*.txt *.json)"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="Importieren der Einstellungen ist fehlgeschlagen"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Einstellungen wurden erfolgreich importiert"
|
||||
AdvSceneSwitcher.generalTab.priority.fileContent="Datei Inhalt"
|
||||
|
|
@ -77,7 +76,6 @@ AdvSceneSwitcher.macroTab.name="Name:"
|
|||
AdvSceneSwitcher.macroTab.run="Makro ausführen"
|
||||
AdvSceneSwitcher.macroTab.runFail="Ausführen von \"%1\" fehlgeschlagen!\nEntweder ist eine der Aktionen fehlgeschlagen oder das Makro wird bereits ausgeführt.\nSoll die aktuelle Ausführung gestoppt werden?"
|
||||
AdvSceneSwitcher.macroTab.runInParallel="Parallel zu anderen Makros ausführen"
|
||||
AdvSceneSwitcher.macroTab.onChange="Nur bei Änderung ausführen"
|
||||
AdvSceneSwitcher.macroTab.defaultname="Makro %1"
|
||||
AdvSceneSwitcher.macroTab.defaultGroupName="Gruppe %1"
|
||||
AdvSceneSwitcher.macroTab.removeGroupPopup.text="Sicher, dass \"%1\" und alle zugehörigen Elemente gelöscht werden?"
|
||||
|
|
@ -195,12 +193,12 @@ AdvSceneSwitcher.condition.video.modelLoadFail="Modelldaten konnten nicht gelade
|
|||
AdvSceneSwitcher.condition.video.type.main="OBS's Haupt-Ausgabe"
|
||||
AdvSceneSwitcher.condition.video.type.source="Quelle"
|
||||
AdvSceneSwitcher.condition.video.type.scene="Szene"
|
||||
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
|
||||
AdvSceneSwitcher.condition.video.entry.modelPath="Modelldaten (Haar-Kaskaden-Klassifikator): {{modelDataPath}}"
|
||||
AdvSceneSwitcher.condition.video.entry.minNeighbor="Minimale Anzahl von Nachbarn: {{minNeighbors}}"
|
||||
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}Reduzieren Sie die CPU-Belastung, indem Sie die Prüfung nur alle {{throttleCount}} Millisekunden"
|
||||
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="Kontrolle nur im Bereich durchführen"
|
||||
AdvSceneSwitcher.condition.video.entry.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
|
||||
AdvSceneSwitcher.condition.video.layout="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
|
||||
AdvSceneSwitcher.condition.video.layout.modelPath="Modelldaten (Haar-Kaskaden-Klassifikator): {{modelDataPath}}"
|
||||
AdvSceneSwitcher.condition.video.layout.minNeighbor="Minimale Anzahl von Nachbarn: {{minNeighbors}}"
|
||||
AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}Reduzieren Sie die CPU-Belastung, indem Sie die Prüfung nur alle {{throttleCount}} Millisekunden"
|
||||
AdvSceneSwitcher.condition.video.layout.checkAreaEnable="Kontrolle nur im Bereich durchführen"
|
||||
AdvSceneSwitcher.condition.video.layout.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
|
||||
AdvSceneSwitcher.condition.video.minSize="Minimale Größe:"
|
||||
AdvSceneSwitcher.condition.video.maxSize="Maximale Größe:"
|
||||
AdvSceneSwitcher.condition.video.selectArea="Bereich auswählen"
|
||||
|
|
@ -212,7 +210,6 @@ AdvSceneSwitcher.condition.stream.state.start="Stream läuft"
|
|||
AdvSceneSwitcher.condition.stream.state.stop="Stream gestoppt"
|
||||
AdvSceneSwitcher.condition.stream.state.starting="Stream wird gestartet"
|
||||
AdvSceneSwitcher.condition.stream.state.stopping="Stream wird gestoppt"
|
||||
AdvSceneSwitcher.condition.stream.entry="{{streamState}}{{keyFrameInterval}}"
|
||||
AdvSceneSwitcher.condition.record="Aufnahme"
|
||||
AdvSceneSwitcher.condition.record.state.start="Aufnahme läuft"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Aufnahme pausiert"
|
||||
|
|
@ -293,14 +290,14 @@ AdvSceneSwitcher.condition.replay.state.started="Replay Buffer gestartet"
|
|||
AdvSceneSwitcher.condition.replay.state.saved="Replay Buffer gespeichert"
|
||||
AdvSceneSwitcher.condition.replay.entry="{{state}}"
|
||||
AdvSceneSwitcher.condition.date="Datum"
|
||||
AdvSceneSwitcher.condition.date.anyDay="Beliebiger Tag"
|
||||
AdvSceneSwitcher.condition.date.monday="Montag"
|
||||
AdvSceneSwitcher.condition.date.tuesday="Dienstag"
|
||||
AdvSceneSwitcher.condition.date.wednesday="Mittwoch"
|
||||
AdvSceneSwitcher.condition.date.thursday="Donnerstag"
|
||||
AdvSceneSwitcher.condition.date.friday="Freitag"
|
||||
AdvSceneSwitcher.condition.date.saturday="Samstag"
|
||||
AdvSceneSwitcher.condition.date.sunday="Sonntag"
|
||||
AdvSceneSwitcher.day.any="Beliebiger Tag"
|
||||
AdvSceneSwitcher.day.monday="Montag"
|
||||
AdvSceneSwitcher.day.tuesday="Dienstag"
|
||||
AdvSceneSwitcher.day.wednesday="Mittwoch"
|
||||
AdvSceneSwitcher.day.thursday="Donnerstag"
|
||||
AdvSceneSwitcher.day.friday="Freitag"
|
||||
AdvSceneSwitcher.day.saturday="Samstag"
|
||||
AdvSceneSwitcher.day.sunday="Sonntag"
|
||||
AdvSceneSwitcher.condition.date.state.at="Am"
|
||||
AdvSceneSwitcher.condition.date.state.after="Nach"
|
||||
AdvSceneSwitcher.condition.date.state.before="Vor"
|
||||
|
|
@ -311,12 +308,13 @@ AdvSceneSwitcher.condition.date.ignoreDate="Wenn diese Option nicht aktiviert is
|
|||
AdvSceneSwitcher.condition.date.ignoreTime="Wenn diese Option nicht aktiviert ist, wird die Zeitkomponente ignoriert"
|
||||
AdvSceneSwitcher.condition.date.showAdvancedSettings="Erweiterte Einstellungen anzeigen"
|
||||
AdvSceneSwitcher.condition.date.showSimpleSettings="Einfache Einstellungen anzeigen"
|
||||
AdvSceneSwitcher.condition.date.entry.simple="Am {{dayOfWeek}} {{weekCondition}} {{ignoreWeekTime}}{{weekTime}}"
|
||||
AdvSceneSwitcher.condition.date.entry.advanced="{{condition}} {{ignoreDate}}{{date}} {{ignoreTime}}{{time}} {{separator}} {{date2}} {{time2}}"
|
||||
AdvSceneSwitcher.condition.date.entry.repeat="{{repeat}} Wiederholen alle {{duration}} bei Datumsübereinstimmung"
|
||||
AdvSceneSwitcher.condition.date.entry.pattern="Aktuelles Datum \"{{currentDate}}\" entspricht dem Muster {{pattern}}"
|
||||
AdvSceneSwitcher.condition.date.entry.nextMatchDate="Nächster Treffer bei: %1"
|
||||
AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}} Bei Wiederholung ausgewähltes Datum auf Wiederholungsdatum aktualisieren"
|
||||
AdvSceneSwitcher.condition.date.layout.simple.day="Am{{dayOfWeek}}"
|
||||
AdvSceneSwitcher.condition.date.layout.simple.time="{{ignoreWeekTime}}{{weekCondition}}{{weekTime}}"
|
||||
AdvSceneSwitcher.condition.date.layout.advanced="{{condition}} {{ignoreDate}}{{date}} {{ignoreTime}}{{time}} {{separator}} {{date2}} {{time2}}"
|
||||
AdvSceneSwitcher.condition.date.layout.repeat="{{repeat}} Wiederholen alle {{duration}} bei Datumsübereinstimmung"
|
||||
AdvSceneSwitcher.condition.date.layout.pattern="Aktuelles Datum \"{{currentDate}}\" entspricht dem Muster {{pattern}}"
|
||||
AdvSceneSwitcher.condition.date.layout.nextMatchDate="Nächster Treffer bei: %1"
|
||||
AdvSceneSwitcher.condition.date.layout.updateOnRepeat="{{updateOnRepeat}} Bei Wiederholung ausgewähltes Datum auf Wiederholungsdatum aktualisieren"
|
||||
AdvSceneSwitcher.condition.sceneTransform="Szenenelement transformieren"
|
||||
AdvSceneSwitcher.condition.sceneTransform.getTransform="Transformation erhalten"
|
||||
AdvSceneSwitcher.condition.sceneTransform.condition.match="entspricht Transformation"
|
||||
|
|
@ -385,8 +383,6 @@ AdvSceneSwitcher.condition.variable.type.greaterThanVariable="ist größer als d
|
|||
|
||||
; Macro Actions
|
||||
AdvSceneSwitcher.action.scene="Szene wechseln"
|
||||
AdvSceneSwitcher.action.scene.entry="Wechsle{{sceneTypes}}Szene zu{{scenes}}mittels{{transitions}}mit einer Dauer von{{duration}}Sekunden"
|
||||
AdvSceneSwitcher.action.scene.entry.noDuration="Wechsle{{sceneTypes}}Szene zu{{scenes}}mittels{{transitions}}"
|
||||
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Warten, bis der Übergang zur Zielszene abgeschlossen ist"
|
||||
AdvSceneSwitcher.action.wait="Warten"
|
||||
AdvSceneSwitcher.action.wait.type.fixed="fixe"
|
||||
|
|
@ -433,7 +429,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.hide="Verstecken"
|
|||
AdvSceneSwitcher.action.sceneVisibility.type.toggle="Umschalten"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.source="Quelle"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Beliebig"
|
||||
AdvSceneSwitcher.action.sceneVisibility.entry="Auf{{scenes}}{{actions}}{{sources}}"
|
||||
AdvSceneSwitcher.action.sceneVisibility.layout="Auf{{scenes}}{{actions}}{{sources}}"
|
||||
AdvSceneSwitcher.action.filter="Filter"
|
||||
AdvSceneSwitcher.action.filter.type.enable="Aktivieren"
|
||||
AdvSceneSwitcher.action.filter.type.disable="Deaktivieren"
|
||||
|
|
@ -468,7 +464,7 @@ AdvSceneSwitcher.action.pluginState.type.stop="Erweiterten Automatischen Szenenw
|
|||
AdvSceneSwitcher.action.pluginState.type.noMatch="Ändern des Nichtübereinstimmungsverhaltens:"
|
||||
AdvSceneSwitcher.action.pluginState.type.import="Einstellungen importieren aus"
|
||||
AdvSceneSwitcher.action.pluginState.importWarning="Hinweis: Die Aktion wird ignoriert, solange das Einstellungsfenster geöffnet ist."
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}"
|
||||
AdvSceneSwitcher.action.virtualCamera="Virtuelle Kamera"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.stop="Virtuelle Kamera stoppen"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.start="Virtuelle Kamera starten"
|
||||
|
|
@ -490,7 +486,7 @@ AdvSceneSwitcher.action.sceneOrder.type.moveDown="Nach unten verschieben"
|
|||
AdvSceneSwitcher.action.sceneOrder.type.moveTop="An erste Stelle verschieben"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveBottom="An letzte Stelle verschieben"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.movePosition="An Position verschieben"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="Auf{{scenes}}{{actions}}{{sources}}{{position}}"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="Auf{{scenes}}{{actions}}{{sources}}{{sources2}}{{position}}"
|
||||
AdvSceneSwitcher.action.sceneTransform="Szenenelement transformieren"
|
||||
AdvSceneSwitcher.action.sceneTransform.getTransform="Transformation erhalten"
|
||||
AdvSceneSwitcher.action.sceneTransform.entry="Auf{{scenes}}{{action}}{{rotation}}{{sources}}{{settingSelection}}{{singleSettingValue}}"
|
||||
|
|
@ -527,7 +523,6 @@ AdvSceneSwitcher.action.screenshot.save.default="Standard"
|
|||
AdvSceneSwitcher.action.screenshot.save.custom="Benutzerdefiniert"
|
||||
AdvSceneSwitcher.action.screenshot.type.source="Quelle"
|
||||
AdvSceneSwitcher.action.screenshot.type.scene="Szene"
|
||||
AdvSceneSwitcher.action.screenshot.mainOutput="OBS's Haupt-Ausgabe"
|
||||
AdvSceneSwitcher.action.screenshot.blackscreenNote="Quellen oder Szenen, die nicht immer gerendert werden, können dazu führen, dass einige Teile der Screenshots leer bleiben."
|
||||
AdvSceneSwitcher.action.screenshot.entry="Screenshot{{targetType}}{{sources}}{{scenes}}und speichere in{{saveType}}{{variables}}Pfad"
|
||||
AdvSceneSwitcher.action.profile="Profil"
|
||||
|
|
@ -755,9 +750,9 @@ AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Starte/Stoppe den Erweite
|
|||
AdvSceneSwitcher.hotkey.macro.pause="Pausiere Makro %1"
|
||||
AdvSceneSwitcher.hotkey.macro.unpause="Makro %1 nicht mehr pausieren"
|
||||
AdvSceneSwitcher.hotkey.macro.togglePause="Pause von Makro %1 togglen"
|
||||
AdvSceneSwitcher.hotkey.upMacroSegmentHotkey="Makro-Segmentauswahl nach oben verschieben"
|
||||
AdvSceneSwitcher.hotkey.downMacroSegmentHotkey="Makro-Segmentauswahl nach unten verschieben"
|
||||
AdvSceneSwitcher.hotkey.removeMacroSegmentHotkey="Ausgewähltes Makro-Segment entfernen"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.up="Makro-Segmentauswahl nach oben verschieben"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.down="Makro-Segmentauswahl nach unten verschieben"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.remove="Ausgewähltes Makro-Segment entfernen"
|
||||
|
||||
AdvSceneSwitcher.askBackup="Neue Version des Erweiterten Automatischen Szenenwechslers wurde erkannt.\nSoll ein Backup der alten Einstellungen angelegt werden?"
|
||||
AdvSceneSwitcher.askForMacro="Makro auswählen {{macroSelection}}"
|
||||
|
|
@ -839,8 +834,6 @@ AdvSceneSwitcher.status.inactive="Inaktiv"
|
|||
AdvSceneSwitcher.running="Plugin läuft"
|
||||
AdvSceneSwitcher.stopped="Plugin gestoppt"
|
||||
|
||||
AdvSceneSwitcher.firstBootMessage="<html><head/><body><p>Dies scheint das erste Mal zu sein, dass der Erweiterte Szenenwechsler gestartet wurde.<br>Bitte schaue ins <a href=\"https://github.com/WarmUpTill/SceneSwitcher/wiki\"><span style=\" text-decoration: underline; color:#268bd2;\">Wiki</span></a> für eine Liste von Anleitungen und Beispielen.<br>Nicht zögern und Fragen im <a href=\"https://obsproject.com/forum/threads/advanced-scene-switcher.48264\"><span style=\" text-decoration: underline; color:#268bd2;\">Thread</span></a> des Plugins im OBS-Forum stellen!!</p></body></html>"
|
||||
|
||||
AdvSceneSwitcher.deprecatedTabWarning="Die Entwicklung für dieses Tab wurde gestoppt!\nBitte stattdessen zur Verwendung des Makros-Tab übergehen.\nDieser Hinweis kann im Allgemein-Tab deaktiviert werden."
|
||||
|
||||
AdvSceneSwitcher.unit.milliseconds="Millisekunden"
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -12,7 +12,7 @@ AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Siempre iniciar el sel
|
|||
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="No iniciar el selector de escenas"
|
||||
AdvSceneSwitcher.generalTab.status.start="Iniciar"
|
||||
AdvSceneSwitcher.generalTab.status.stop="Detener"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart="Iniciar automáticamente el selector de escenas cuando:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.startup="Iniciar automáticamente el selector de escenas cuando:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.never="Nunca"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.recording="Grabando"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Emitiendo"
|
||||
|
|
@ -25,7 +25,6 @@ AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.dontSwitch="No cambiar"
|
|||
AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchToRandom="Cambiar a una escena aleatoria"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchTo="Cambiar a:"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint="¡Durante este tiempo, se ignorarán las posibles coincidencias!"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Habilitar el registro detallado"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="Guardar la posición y el tamaño de la ventana"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="Mostrar notificaciones del sistema"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="Deshabilitar sugerencias de interfaz de usuario"
|
||||
|
|
@ -39,7 +38,7 @@ AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="Exportar"
|
|||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Importar"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Exportar los ajustes para Advanced Scene Switcher ..."
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Importar los ajustes para Advanced Scene Switcher ..."
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Archivos de texto (*.txt)"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Archivos de texto (*.txt *.json)"
|
||||
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"
|
||||
|
|
@ -73,7 +72,6 @@ AdvSceneSwitcher.macroTab.add="Agregar nueva macro"
|
|||
AdvSceneSwitcher.macroTab.name="Nombre:"
|
||||
AdvSceneSwitcher.macroTab.run="Ejecutar macro"
|
||||
AdvSceneSwitcher.macroTab.runInParallel="Ejecutar macro en paralelo a otras macros"
|
||||
AdvSceneSwitcher.macroTab.onChange="Realizar acciones solo en el cambio de condición"
|
||||
AdvSceneSwitcher.macroTab.defaultname="Macro %1"
|
||||
AdvSceneSwitcher.macroTab.copy="Crear copia"
|
||||
AdvSceneSwitcher.macroTab.expandAll="Expandir todo"
|
||||
|
|
@ -155,12 +153,12 @@ AdvSceneSwitcher.condition.video.patternMatchSuccess="El patrón está resaltado
|
|||
AdvSceneSwitcher.condition.video.objectMatchFail="¡No se encontró el objeto!"
|
||||
AdvSceneSwitcher.condition.video.objectMatchSuccess="El objeto está resaltado en rojo"
|
||||
AdvSceneSwitcher.condition.video.modelLoadFail="¡No se pudieron cargar los datos del modelo!"
|
||||
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
|
||||
AdvSceneSwitcher.condition.video.entry.modelPath="Datos del modelo (haar cascade classifier): {{modelDataPath}}"
|
||||
AdvSceneSwitcher.condition.video.entry.minNeighbor="Mínimo de vecinos: {{minNeighbors}}"
|
||||
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}Reduzca la carga de la CPU realizando una comprobación solo cada {{throttleCount}} milisegundos"
|
||||
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="Realizar comprobación solo en el área"
|
||||
AdvSceneSwitcher.condition.video.entry.checkArea="{{checkAreaEnable}}Realizar comprobación solo en el área {{checkArea}} {{selectArea}}"
|
||||
AdvSceneSwitcher.condition.video.layout="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
|
||||
AdvSceneSwitcher.condition.video.layout.modelPath="Datos del modelo (haar cascade classifier): {{modelDataPath}}"
|
||||
AdvSceneSwitcher.condition.video.layout.minNeighbor="Mínimo de vecinos: {{minNeighbors}}"
|
||||
AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}Reduzca la carga de la CPU realizando una comprobación solo cada {{throttleCount}} milisegundos"
|
||||
AdvSceneSwitcher.condition.video.layout.checkAreaEnable="Realizar comprobación solo en el área"
|
||||
AdvSceneSwitcher.condition.video.layout.checkArea="{{checkAreaEnable}}Realizar comprobación solo en el área {{checkArea}} {{selectArea}}"
|
||||
AdvSceneSwitcher.condition.video.minSize="Tamaño mínimo:"
|
||||
AdvSceneSwitcher.condition.video.maxSize="Tamaño máximo:"
|
||||
AdvSceneSwitcher.condition.video.selectArea="Seleccionar área"
|
||||
|
|
@ -172,7 +170,6 @@ AdvSceneSwitcher.condition.stream.state.start="Transmisión en ejecución"
|
|||
AdvSceneSwitcher.condition.stream.state.stop="Transmisión detenida"
|
||||
AdvSceneSwitcher.condition.stream.state.starting="Inicio de transmisión"
|
||||
AdvSceneSwitcher.condition.stream.state.stopping="Detener transmisión"
|
||||
AdvSceneSwitcher.condition.stream.entry="{{streamState}}{{keyFrameInterval}}"
|
||||
AdvSceneSwitcher.condition.record="Grabación"
|
||||
AdvSceneSwitcher.condition.record.state.start="Grabación en ejecución"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Grabación en pausa"
|
||||
|
|
@ -243,14 +240,14 @@ AdvSceneSwitcher.condition.replay.state.started="Búfer de reproducción iniciad
|
|||
AdvSceneSwitcher.condition.replay.state.saved="Búfer de reproducción guardado"
|
||||
AdvSceneSwitcher.condition.replay.entry="{{state}}"
|
||||
AdvSceneSwitcher.condition.date="Fecha"
|
||||
AdvSceneSwitcher.condition.date.anyDay="Cualquier día"
|
||||
AdvSceneSwitcher.condition.date.monday="Lunes"
|
||||
AdvSceneSwitcher.condition.date.tuesday="Martes"
|
||||
AdvSceneSwitcher.condition.date.wednesday="Miércoles"
|
||||
AdvSceneSwitcher.condition.date.thursday="Jueves"
|
||||
AdvSceneSwitcher.condition.date.friday="Viernes"
|
||||
AdvSceneSwitcher.condition.date.saturday="Sábado"
|
||||
AdvSceneSwitcher.condition.date.sunday="Domingo"
|
||||
AdvSceneSwitcher.day.any="Cualquier día"
|
||||
AdvSceneSwitcher.day.monday="Lunes"
|
||||
AdvSceneSwitcher.day.tuesday="Martes"
|
||||
AdvSceneSwitcher.day.wednesday="Miércoles"
|
||||
AdvSceneSwitcher.day.thursday="Jueves"
|
||||
AdvSceneSwitcher.day.friday="Viernes"
|
||||
AdvSceneSwitcher.day.saturday="Sábado"
|
||||
AdvSceneSwitcher.day.sunday="Domingo"
|
||||
AdvSceneSwitcher.condition.date.state.at="A las"
|
||||
AdvSceneSwitcher.condition.date.state.after="Después"
|
||||
AdvSceneSwitcher.condition.date.state.before="Antes"
|
||||
|
|
@ -260,11 +257,12 @@ AdvSceneSwitcher.condition.date.ignoreDate="Si no se marca, se ignorará el comp
|
|||
AdvSceneSwitcher.condition.date.ignoreTime="Si no se marca, se ignorará el componente de tiempo"
|
||||
AdvSceneSwitcher.condition.date.showAdvancedSettings="Mostrar configuración avanzada"
|
||||
AdvSceneSwitcher.condition.date.showSimpleSettings="Mostrar configuración simple"
|
||||
AdvSceneSwitcher.condition.date.entry.simple="El {{dayOfWeek}} {{weekCondition}} {{ignoreWeekTime}}{{weekTime}}"
|
||||
AdvSceneSwitcher.condition.date.entry.advanced="{{condition}} {{ignoreDate}}{{date}} {{ignoreTime}}{{time}} {{separator}} {{date2}} {{time2}}"
|
||||
AdvSceneSwitcher.condition.date.entry.repeat="{{repeat}} Repetir cada {{duration}} en la coincidencia de fechas"
|
||||
AdvSceneSwitcher.condition.date.entry.nextMatchDate="Próxima coincidencia en: %1"
|
||||
AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}} Al repetir actualizar la fecha seleccionada para repetir la fecha"
|
||||
AdvSceneSwitcher.condition.date.layout.simple.day="El{{dayOfWeek}}"
|
||||
AdvSceneSwitcher.condition.date.layout.simple.time="{{ignoreWeekTime}}{{weekCondition}}{{weekTime}}"
|
||||
AdvSceneSwitcher.condition.date.layout.advanced="{{condition}} {{ignoreDate}}{{date}} {{ignoreTime}}{{time}} {{separator}} {{date2}} {{time2}}"
|
||||
AdvSceneSwitcher.condition.date.layout.repeat="{{repeat}} Repetir cada {{duration}} en la coincidencia de fechas"
|
||||
AdvSceneSwitcher.condition.date.layout.nextMatchDate="Próxima coincidencia en: %1"
|
||||
AdvSceneSwitcher.condition.date.layout.updateOnRepeat="{{updateOnRepeat}} Al repetir actualizar la fecha seleccionada para repetir la fecha"
|
||||
AdvSceneSwitcher.condition.sceneTransform="Transformar elemento de escena"
|
||||
AdvSceneSwitcher.condition.sceneTransform.getTransform="Obtener transformación"
|
||||
AdvSceneSwitcher.condition.sceneTransform.condition.match="coincide con la transformación"
|
||||
|
|
@ -313,7 +311,6 @@ AdvSceneSwitcher.condition.stats.entry="{{stats}} esta {{condition}} {{value}}"
|
|||
|
||||
; Macro Actions
|
||||
AdvSceneSwitcher.action.scene="Cambiar escena"
|
||||
AdvSceneSwitcher.action.scene.entry="Cambiar a la{{sceneTypes}}escena{{scenes}}usando{{transitions}}con una duración de{{duration}} segundos"
|
||||
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Espere hasta que se complete la transición a la escena de destino"
|
||||
AdvSceneSwitcher.action.wait="Esperar"
|
||||
AdvSceneSwitcher.action.wait.type.fixed="fijo"
|
||||
|
|
@ -353,7 +350,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.show="Mostrar"
|
|||
AdvSceneSwitcher.action.sceneVisibility.type.hide="Ocultar"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.source="Fuente"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Cualquiera"
|
||||
AdvSceneSwitcher.action.sceneVisibility.entry="En{{scenes}}{{actions}}{{sources}}"
|
||||
AdvSceneSwitcher.action.sceneVisibility.layout="En{{scenes}}{{actions}}{{sources}}"
|
||||
AdvSceneSwitcher.action.filter="Filtro"
|
||||
AdvSceneSwitcher.action.filter.type.enable="Habilitar"
|
||||
AdvSceneSwitcher.action.filter.type.disable="Deshabilitar"
|
||||
|
|
@ -385,7 +382,7 @@ AdvSceneSwitcher.action.pluginState.type.stop="Detener el complemento Advanced S
|
|||
AdvSceneSwitcher.action.pluginState.type.noMatch="Cambiar el comportamiento de no coincidencia:"
|
||||
AdvSceneSwitcher.action.pluginState.type.import="Importar configuración desde"
|
||||
AdvSceneSwitcher.action.pluginState.importWarning="Nota: la acción se ignorará mientras se abra la ventana de configuración."
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}"
|
||||
AdvSceneSwitcher.action.virtualCamera="Cámara virtual"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.stop="Detener cámara virtual"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.start="Iniciar cámara virtual"
|
||||
|
|
@ -407,7 +404,7 @@ AdvSceneSwitcher.action.sceneOrder.type.moveDown="Mover hacia abajo"
|
|||
AdvSceneSwitcher.action.sceneOrder.type.moveTop="Mover al principio"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveBottom="Mover al final"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.movePosition="Mover a la posición"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="En{{scenes}}{{actions}}{{sources}}{{position}}"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="En{{scenes}}{{actions}}{{sources}}{{sources2}}{{position}}"
|
||||
AdvSceneSwitcher.action.sceneTransform="Transformar elemento de escena"
|
||||
AdvSceneSwitcher.action.sceneTransform.getTransform="Obtener transformación"
|
||||
AdvSceneSwitcher.action.sceneTransform.entry="En{{scenes}}{{action}}{{rotation}}{{sources}}{{settingSelection}}{{singleSettingValue}}"
|
||||
|
|
@ -439,7 +436,6 @@ AdvSceneSwitcher.action.random="Aleatorio"
|
|||
AdvSceneSwitcher.action.random.entry="Ejecute aleatoriamente cualquiera de las siguientes macros (las macros en pausa se ignoran)"
|
||||
AdvSceneSwitcher.action.systray="Notificación de la bandeja del sistema"
|
||||
AdvSceneSwitcher.action.screenshot="Captura de pantalla"
|
||||
AdvSceneSwitcher.action.screenshot.mainOutput="Salida principal de OBS"
|
||||
AdvSceneSwitcher.action.profile="Perfil"
|
||||
AdvSceneSwitcher.action.profile.entry="Cambiar perfil activo a {{profiles}}"
|
||||
AdvSceneSwitcher.action.sceneCollection="Colección de escenas"
|
||||
|
|
@ -643,9 +639,9 @@ AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Alternar inicio / detenci
|
|||
AdvSceneSwitcher.hotkey.macro.pause="Pausar macro %1"
|
||||
AdvSceneSwitcher.hotkey.macro.unpause="Despausar macro %1"
|
||||
AdvSceneSwitcher.hotkey.macro.togglePause="Alternar pausa de macro %1"
|
||||
AdvSceneSwitcher.hotkey.upMacroSegmentHotkey="Mover selección de segmento de macro hacia arriba"
|
||||
AdvSceneSwitcher.hotkey.downMacroSegmentHotkey="Mover selección de segmento de macro hacia abajo"
|
||||
AdvSceneSwitcher.hotkey.removeMacroSegmentHotkey="Eliminar segmento de macro seleccionado"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.up="Mover selección de segmento de macro hacia arriba"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.down="Mover selección de segmento de macro hacia abajo"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.remove="Eliminar segmento de macro seleccionado"
|
||||
|
||||
AdvSceneSwitcher.askBackup="Se detectó una nueva versión de Advanced Scene Switcher.\n¿Crear una copia de seguridad de la configuración anterior?"
|
||||
AdvSceneSwitcher.askForMacro="Select macro {{macroSelection}}"
|
||||
|
|
@ -684,8 +680,6 @@ AdvSceneSwitcher.status.inactive="Inactivo"
|
|||
AdvSceneSwitcher.running="Iniciar complemento"
|
||||
AdvSceneSwitcher.stopped="Complemento de detención"
|
||||
|
||||
AdvSceneSwitcher.firstBootMessage="<html><head/><body><p>Esta parece ser la primera vez que se inicia el conmutador de escena avanzado.<br>Por favor, eche un vistazo a <a href=\"https:/ /github.com/WarmUpTill/SceneSwitcher/wiki\"><span style=\" text-decoration: underline; color:#268bd2;\">Wiki</span></a> para obtener una lista de guías y ejemplos.<br>No dude en hacer preguntas en el complemento <a href=\"https://obsproject.com /forum/threads/advanced-scene-switcher.48264\"><span style=\" text-decoration: underline; color:#268bd2;\">hilo</span></a> en los foros de OBS!</p></body></html>"
|
||||
|
||||
AdvSceneSwitcher.deprecatedTabWarning="¡Se detuvo el desarrollo de esta pestaña!\nConsidere cambiar a macros en su lugar.\nEsta sugerencia se puede desactivar en la pestaña General".
|
||||
|
||||
AdvSceneSwitcher.unit.milliseconds="milisegundos"
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Toujours démarrer le
|
|||
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Ne pas démarrer le sélecteur de scène"
|
||||
AdvSceneSwitcher.generalTab.status.start="Démarrer"
|
||||
AdvSceneSwitcher.generalTab.status.stop="Arrêter"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart="Démarrer automatiquement le sélecteur de scène lorsque :"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.startup="Démarrer automatiquement le sélecteur de scène lorsque :"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.never="Jamais"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.recording="Enregistrement"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Diffusion en continu"
|
||||
|
|
@ -26,7 +26,6 @@ AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchToRandom="Basculer v
|
|||
AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchTo="Basculer vers :"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.cooldown="Après avoir effectué des actions, sauter l'exécution d'actions pendant"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint="Pendant cette période, les correspondances potentielles seront ignorées !"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Activer les journaux détaillés"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="Enregistrer la position et la taille de la fenêtre"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="Afficher les notifications dans la zone de notification système"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="Désactiver les indications de l'interface utilisateur"
|
||||
|
|
@ -44,7 +43,7 @@ AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="Exporter"
|
|||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Importer"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Exporter les paramètres d'Advanced Scene Switcher vers un fichier ..."
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Importer les paramètres d'Advanced Scene Switcher depuis un fichier ..."
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Fichiers texte (*.txt)"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Fichiers texte (*.txt *.json)"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="L'importation des paramètres d'Advanced Scene Switcher a échoué"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Les paramètres d'Advanced Scene Switcher ont été importés avec succès"
|
||||
AdvSceneSwitcher.generalTab.priority.fileContent="Contenu du fichier"
|
||||
|
|
@ -79,7 +78,6 @@ AdvSceneSwitcher.macroTab.add="Ajouter une nouvelle macro"
|
|||
AdvSceneSwitcher.macroTab.name="Nom :"
|
||||
AdvSceneSwitcher.macroTab.run="Exécuter la macro"
|
||||
AdvSceneSwitcher.macroTab.runInParallel="Exécuter la macro en parallèle avec d'autres macros"
|
||||
AdvSceneSwitcher.macroTab.onChange="Exécuter des actions uniquement en cas de changement de condition"
|
||||
AdvSceneSwitcher.macroTab.defaultname="Macro %1"
|
||||
AdvSceneSwitcher.macroTab.defaultGroupName="Groupe %1"
|
||||
AdvSceneSwitcher.macroTab.removeSingleMacroPopup.text="Êtes-vous sûr de vouloir supprimer \"%1\" ?"
|
||||
|
|
@ -258,14 +256,14 @@ AdvSceneSwitcher.condition.video.colorDeviationThresholdDescription="À quel poi
|
|||
AdvSceneSwitcher.condition.video.type.main="Sortie principale d'OBS"
|
||||
AdvSceneSwitcher.condition.video.type.source="Source"
|
||||
AdvSceneSwitcher.condition.video.type.scene="Scène"
|
||||
AdvSceneSwitcher.condition.video.entry.modelPath="Données du modèle (classificateur de cascade de Haar) :{{modelDataPath}}"
|
||||
AdvSceneSwitcher.condition.video.entry.minNeighbor="Nombre minimum de voisins :{{minNeighbors}}"
|
||||
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}Réduire la charge CPU en effectuant la vérification uniquement toutes les{{throttleCount}}millisecondes"
|
||||
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="Effectuer la vérification uniquement dans la zone"
|
||||
AdvSceneSwitcher.condition.video.entry.orcColorPick="Vérifier la couleur du texte :{{textColor}}{{selectColor}}"
|
||||
AdvSceneSwitcher.condition.video.entry.orcTextType="Vérifier le type de texte :{{textType}}"
|
||||
AdvSceneSwitcher.condition.video.entry.orcLanguage="Vérifier la langue :{{languageCode}}"
|
||||
AdvSceneSwitcher.condition.video.entry.color="Vérifier la couleur :{{color}}{{selectColor}}"
|
||||
AdvSceneSwitcher.condition.video.layout.modelPath="Données du modèle (classificateur de cascade de Haar) :{{modelDataPath}}"
|
||||
AdvSceneSwitcher.condition.video.layout.minNeighbor="Nombre minimum de voisins :{{minNeighbors}}"
|
||||
AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}Réduire la charge CPU en effectuant la vérification uniquement toutes les{{throttleCount}}millisecondes"
|
||||
AdvSceneSwitcher.condition.video.layout.checkAreaEnable="Effectuer la vérification uniquement dans la zone"
|
||||
AdvSceneSwitcher.condition.video.layout.ocrColorPick="Vérifier la couleur du texte :{{textColor}}{{selectColor}}"
|
||||
AdvSceneSwitcher.condition.video.layout.ocrTextType="Vérifier le type de texte :{{textType}}"
|
||||
AdvSceneSwitcher.condition.video.layout.ocrLanguage="Vérifier la langue :{{languageCode}}"
|
||||
AdvSceneSwitcher.condition.video.layout.color="Vérifier la couleur :{{color}}{{selectColor}}"
|
||||
AdvSceneSwitcher.condition.video.minSize="Taille minimale :"
|
||||
AdvSceneSwitcher.condition.video.maxSize="Taille maximale :"
|
||||
AdvSceneSwitcher.condition.video.selectArea="Sélectionner la zone"
|
||||
|
|
@ -357,14 +355,14 @@ AdvSceneSwitcher.condition.replay.state.stopped="Tampon de répétition arrêté
|
|||
AdvSceneSwitcher.condition.replay.state.started="Tampon de répétition démarré"
|
||||
AdvSceneSwitcher.condition.replay.state.saved="Tampon de répétition enregistré"
|
||||
AdvSceneSwitcher.condition.date="Date"
|
||||
AdvSceneSwitcher.condition.date.anyDay="N'importe quel jour"
|
||||
AdvSceneSwitcher.condition.date.monday="Lundi"
|
||||
AdvSceneSwitcher.condition.date.tuesday="Mardi"
|
||||
AdvSceneSwitcher.condition.date.wednesday="Mercredi"
|
||||
AdvSceneSwitcher.condition.date.thursday="Jeudi"
|
||||
AdvSceneSwitcher.condition.date.friday="Vendredi"
|
||||
AdvSceneSwitcher.condition.date.saturday="Samedi"
|
||||
AdvSceneSwitcher.condition.date.sunday="Dimanche"
|
||||
AdvSceneSwitcher.day.any="N'importe quel jour"
|
||||
AdvSceneSwitcher.day.monday="Lundi"
|
||||
AdvSceneSwitcher.day.tuesday="Mardi"
|
||||
AdvSceneSwitcher.day.wednesday="Mercredi"
|
||||
AdvSceneSwitcher.day.thursday="Jeudi"
|
||||
AdvSceneSwitcher.day.friday="Vendredi"
|
||||
AdvSceneSwitcher.day.saturday="Samedi"
|
||||
AdvSceneSwitcher.day.sunday="Dimanche"
|
||||
AdvSceneSwitcher.condition.date.state.at="À"
|
||||
AdvSceneSwitcher.condition.date.state.after="Après"
|
||||
AdvSceneSwitcher.condition.date.state.before="Avant"
|
||||
|
|
@ -375,11 +373,12 @@ AdvSceneSwitcher.condition.date.ignoreDate="Si non cochée, la composante date s
|
|||
AdvSceneSwitcher.condition.date.ignoreTime="Si non cochée, la composante heure sera ignorée"
|
||||
AdvSceneSwitcher.condition.date.showAdvancedSettings="Afficher les paramètres avancés"
|
||||
AdvSceneSwitcher.condition.date.showSimpleSettings="Afficher les paramètres simples"
|
||||
AdvSceneSwitcher.condition.date.entry.simple="Le{{dayOfWeek}}{{weekCondition}}{{ignoreWeekTime}}{{weekTime}}"
|
||||
AdvSceneSwitcher.condition.date.entry.repeat="{{repeat}}Répéter toutes les{{duration}}lorsque la date correspond"
|
||||
AdvSceneSwitcher.condition.date.entry.pattern="La date actuelle \"{{currentDate}}\" correspond au motif{{pattern}}"
|
||||
AdvSceneSwitcher.condition.date.entry.nextMatchDate="Prochaine correspondance à : %1"
|
||||
AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}}À la répétition, mettre à jour la date sélectionnée pour la date de répétition"
|
||||
AdvSceneSwitcher.condition.date.layout.simple.day="Le{{dayOfWeek}}"
|
||||
AdvSceneSwitcher.condition.date.layout.simple.time="{{ignoreWeekTime}}{{weekCondition}}{{weekTime}}"
|
||||
AdvSceneSwitcher.condition.date.layout.repeat="{{repeat}}Répéter toutes les{{duration}}lorsque la date correspond"
|
||||
AdvSceneSwitcher.condition.date.layout.pattern="La date actuelle \"{{currentDate}}\" correspond au motif{{pattern}}"
|
||||
AdvSceneSwitcher.condition.date.layout.nextMatchDate="Prochaine correspondance à : %1"
|
||||
AdvSceneSwitcher.condition.date.layout.updateOnRepeat="{{updateOnRepeat}}À la répétition, mettre à jour la date sélectionnée pour la date de répétition"
|
||||
AdvSceneSwitcher.condition.sceneTransform="Transformation de l'élément de la scène"
|
||||
AdvSceneSwitcher.condition.sceneTransform.getTransform="Obtenir la transformation"
|
||||
AdvSceneSwitcher.condition.sceneTransform.condition.match="correspond à la transformation"
|
||||
|
|
@ -460,8 +459,6 @@ AdvSceneSwitcher.condition.slideshow.updateInterval.tooltip="Les informations su
|
|||
AdvSceneSwitcher.action.scene="Changer de scène"
|
||||
AdvSceneSwitcher.action.scene.type.program="Programme"
|
||||
AdvSceneSwitcher.action.scene.type.preview="Aperçu"
|
||||
AdvSceneSwitcher.action.scene.entry="Changer la scène{{sceneTypes}}{{scenes}}en utilisant{{transitions}}avec une durée de{{duration}}secondes"
|
||||
AdvSceneSwitcher.action.scene.entry.noDuration="Changer la scène{{sceneTypes}}{{scenes}}en utilisant{{transitions}}"
|
||||
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Attendre que la transition vers la scène cible soit terminée"
|
||||
AdvSceneSwitcher.action.wait="Attendre"
|
||||
AdvSceneSwitcher.action.wait.type.fixed="fixe"
|
||||
|
|
@ -513,7 +510,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.hide="Masquer"
|
|||
AdvSceneSwitcher.action.sceneVisibility.type.toggle="Basculer"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.source="Source"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="N'importe"
|
||||
AdvSceneSwitcher.action.sceneVisibility.entry="Sur{{scenes}}{{actions}}{{sources}}"
|
||||
AdvSceneSwitcher.action.sceneVisibility.layout="Sur{{scenes}}{{actions}}{{sources}}"
|
||||
AdvSceneSwitcher.action.filter="Filtre"
|
||||
AdvSceneSwitcher.action.filter.type.enable="Activer"
|
||||
AdvSceneSwitcher.action.filter.type.disable="Désactiver"
|
||||
|
|
@ -597,7 +594,7 @@ AdvSceneSwitcher.action.sceneOrder.type.moveDown="Déplacer vers le bas"
|
|||
AdvSceneSwitcher.action.sceneOrder.type.moveTop="Déplacer en haut"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveBottom="Déplacer en bas"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.movePosition="Déplacer à la position"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="Sur{{scenes}}{{actions}}{{sources}}{{position}}"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="Sur{{scenes}}{{actions}}{{sources}}{{sources2}}{{position}}"
|
||||
AdvSceneSwitcher.action.sceneTransform="Transformation de l'élément de la scène"
|
||||
AdvSceneSwitcher.action.sceneTransform.type.manual="Transform"
|
||||
AdvSceneSwitcher.action.sceneTransform.type.reset="Réinitialiser la transformation"
|
||||
|
|
@ -647,7 +644,6 @@ AdvSceneSwitcher.action.screenshot.save.default="Par défaut"
|
|||
AdvSceneSwitcher.action.screenshot.save.custom="Personnalisé"
|
||||
AdvSceneSwitcher.action.screenshot.type.source="Source"
|
||||
AdvSceneSwitcher.action.screenshot.type.scene="Scène"
|
||||
AdvSceneSwitcher.action.screenshot.mainOutput="Sortie principale d'OBS"
|
||||
AdvSceneSwitcher.action.screenshot.blackscreenNote="Les sources ou les scènes qui ne sont pas toujours rendues peuvent entraîner des parties de captures d'écran vides."
|
||||
AdvSceneSwitcher.action.screenshot.entry="Capturer{{targetType}}{{sources}}{{scenes}}et enregistrer à l'emplacement{{saveType}}{{variables}}"
|
||||
AdvSceneSwitcher.action.profile="Profil"
|
||||
|
|
@ -705,10 +701,10 @@ AdvSceneSwitcher.action.variable.invalidSelection="Sélection invalide !"
|
|||
AdvSceneSwitcher.action.variable.actionNoVariableSupport="La récupération de valeurs de variables à partir d'actions %1 n'est pas prise en charge !"
|
||||
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="La récupération de valeurs de variables à partir de conditions %1 n'est pas prise en charge !"
|
||||
AdvSceneSwitcher.action.variable.currentSegmentValue="Valeur actuelle :"
|
||||
AdvSceneSwitcher.action.variable.entry.substringIndex="Début de la sous-chaîne :{{subStringStart}}Taille de la sous-chaîne :{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.entry.substringRegex="Attribuer la valeur du match{{regexMatchIdx}}en utilisant une expression régulière :"
|
||||
AdvSceneSwitcher.action.variable.entry.userInput.customPrompt="{{useCustomPrompt}}Utiliser un message personnalisé{{inputPrompt}}"
|
||||
AdvSceneSwitcher.action.variable.entry.userInput.placeholder="{{useInputPlaceholder}}Remplir avec un indicateur de position{{inputPlaceholder}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringIndex="Début de la sous-chaîne :{{subStringStart}}Taille de la sous-chaîne :{{subStringSize}}{{subStringRegex}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringRegex="Attribuer la valeur du match{{regexMatchIdx}}en utilisant une expression régulière:{{subStringRegex}}"
|
||||
AdvSceneSwitcher.action.variable.layout.userInput.customPrompt="{{useCustomPrompt}}Utiliser un message personnalisé{{inputPrompt}}"
|
||||
AdvSceneSwitcher.action.variable.layout.userInput.placeholder="{{useInputPlaceholder}}Remplir avec un indicateur de position{{inputPlaceholder}}"
|
||||
AdvSceneSwitcher.action.projector="Projecteur"
|
||||
AdvSceneSwitcher.action.projector.type.source="Source"
|
||||
AdvSceneSwitcher.action.projector.type.scene="Scène"
|
||||
|
|
@ -718,8 +714,6 @@ AdvSceneSwitcher.action.projector.type.multiview="Multivue"
|
|||
AdvSceneSwitcher.action.projector.display="Affichage"
|
||||
AdvSceneSwitcher.action.projector.windowed="Fenêtré"
|
||||
AdvSceneSwitcher.action.projector.fullscreen="Plein écran"
|
||||
AdvSceneSwitcher.action.projector.entry="Ouvrir le projecteur{{windowTypes}}de{{types}}{{scenes}}{{sources}}"
|
||||
AdvSceneSwitcher.action.projector.entry.monitor="sur{{monitors}}"
|
||||
AdvSceneSwitcher.action.midi="MIDI"
|
||||
AdvSceneSwitcher.action.midi.entry="Envoyer un message à{{device}}:"
|
||||
AdvSceneSwitcher.action.midi.entry.listen="Définir la sélection de messages MIDI sur les messages entrants de{{listenDevices}}:{{listenButton}}"
|
||||
|
|
@ -924,9 +918,9 @@ AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Basculer le démarrage/ar
|
|||
AdvSceneSwitcher.hotkey.macro.pause="Mettre en pause la macro %1"
|
||||
AdvSceneSwitcher.hotkey.macro.unpause="Reprendre la macro %1"
|
||||
AdvSceneSwitcher.hotkey.macro.togglePause="Basculer la pause de la macro %1"
|
||||
AdvSceneSwitcher.hotkey.upMacroSegmentHotkey="Déplacer la sélection du segment de macro vers le haut"
|
||||
AdvSceneSwitcher.hotkey.downMacroSegmentHotkey="Déplacer la sélection du segment de macro vers le bas"
|
||||
AdvSceneSwitcher.hotkey.removeMacroSegmentHotkey="Supprimer le segment de macro sélectionné"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.up="Déplacer la sélection du segment de macro vers le haut"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.down="Déplacer la sélection du segment de macro vers le bas"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.remove="Supprimer le segment de macro sélectionné"
|
||||
|
||||
AdvSceneSwitcher.askBackup="Une nouvelle version du commutateur de scènes avancé a été détectée.\nSouhaitez-vous créer une sauvegarde des anciens paramètres ?"
|
||||
AdvSceneSwitcher.askForMacro="Sélectionnez la macro{{macroSelection}}"
|
||||
|
|
@ -1111,15 +1105,15 @@ AdvSceneSwitcher.sceneItemSelection.configure="Configurer le type de sélection
|
|||
AdvSceneSwitcher.sceneItemSelection.type.sourceName="Nom de la source"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable="Nom de la variable"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern="Le nom de la source correspond au motif"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.entry="{{nameConflictIndex}}correspondant à{{pattern}}{{regex}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.layout="{{nameConflictIndex}}correspondant à{{pattern}}{{regex}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType="Sources de type"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType.entry="{{nameConflictIndex}}Type de source{{sourceTypes}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType.layout="{{nameConflictIndex}}Type de source{{sourceTypes}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index="Source avec index"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index.entry="{{index}}source"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index.layout="{{index}}source"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange="Sources dans la plage d'index"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange.entry="Sources de{{index}}à{{indexEnd}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange.layout="Sources de{{index}}à{{indexEnd}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all="Toutes les sources"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all.entry="Toutes les sources"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all.layout="Toutes les sources"
|
||||
AdvSceneSwitcher.sceneItemSelection.all="Tout"
|
||||
AdvSceneSwitcher.sceneItemSelection.any="N'importe lequel"
|
||||
|
||||
|
|
@ -1128,8 +1122,6 @@ AdvSceneSwitcher.status.inactive="Inactif"
|
|||
AdvSceneSwitcher.running="Plugin en cours d'exécution"
|
||||
AdvSceneSwitcher.stopped="Plugin arrêté"
|
||||
|
||||
AdvSceneSwitcher.firstBootMessage="<html><head/><body><p>Il semble que ce soit la première fois que l'Advanced Scene Switcher est démarré.<br>Veuillez consulter le <a href=\"https://github.com/WarmUpTill/SceneSwitcher/wiki\"><span style=\" text-decoration: underline; color:#268bd2;\">Wiki</span></a> pour obtenir une liste de guides et d'exemples.<br>N'hésitez pas à poser des questions dans le <a href=\"https://obsproject.com/forum/threads/advanced-scene-switcher.48264\"><span style=\" text-decoration: underline; color:#268bd2;\">fil de discussion</span></a> du plugin sur les forums OBS !</p></body></html>"
|
||||
|
||||
AdvSceneSwitcher.deprecatedTabWarning="Le développement de cet onglet est terminé !\nVeuillez envisager de passer à l'utilisation des Macros à la place.\nCette astuce peut être désactivée dans l'onglet Général."
|
||||
|
||||
AdvSceneSwitcher.unit.milliseconds="millisecondes"
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -12,7 +12,7 @@ AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Sempre iniciar o switc
|
|||
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Não iniciar o switcher de cenas"
|
||||
AdvSceneSwitcher.generalTab.status.start="Iniciar"
|
||||
AdvSceneSwitcher.generalTab.status.stop="Parar"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart="Iniciar automaticamente o switcher de cenas quando:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.startup="Iniciar automaticamente o switcher de cenas quando:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.never="Nunca"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.recording="Gravando"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Transmitindo"
|
||||
|
|
@ -30,7 +30,6 @@ AdvSceneSwitcher.generalTab.generalBehavior.logLevel="Nível de log:"
|
|||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.default="Padrão"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.logAction="Registrar ações executadas"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.verbose="Registro detalhado"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Ativar registro detalhado"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="Salvar posição e tamanho da janela"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="Mostrar notificações na área de notificação"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="Desativar dicas de interface"
|
||||
|
|
@ -49,7 +48,7 @@ AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="Exportar"
|
|||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Importar"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Exportar configurações do Advanced Scene Switcher para arquivo ..."
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Importar configurações do Advanced Scene Switcher de arquivo ..."
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Arquivos de texto (*.txt)"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Arquivos de texto (*.txt *.json)"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="O Advanced Scene Switcher falhou ao importar configurações"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Configurações do Advanced Scene Switcher importadas com sucesso"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportSensitiveDataWarning="Aviso:\nOs dados exportados podem conter informações sensíveis!"
|
||||
|
|
@ -148,7 +147,6 @@ AdvSceneSwitcher.macroTab.run.tooltip="Execute todas as ações da macro indepen
|
|||
AdvSceneSwitcher.macroTab.runElse="Executar macro (alternativa)"
|
||||
AdvSceneSwitcher.macroTab.runFail="Falha ao executar \"%1\"!\nUma das ações falhou ou a macro já está em execução.\nDeseja interrompê-la?"
|
||||
AdvSceneSwitcher.macroTab.runInParallel="Executar macro em paralelo com outras macros"
|
||||
AdvSceneSwitcher.macroTab.onChange="Executar ações apenas quando houver mudança na condição"
|
||||
AdvSceneSwitcher.macroTab.defaultname="Macro %1"
|
||||
AdvSceneSwitcher.macroTab.defaultGroupName="Grupo %1"
|
||||
AdvSceneSwitcher.macroTab.macroNameExists="O nome \"%1\" já está em uso por uma macro."
|
||||
|
|
@ -373,16 +371,16 @@ AdvSceneSwitcher.condition.video.colorDeviationThresholdDescription="Quão semel
|
|||
AdvSceneSwitcher.condition.video.type.main="Saída principal do OBS"
|
||||
AdvSceneSwitcher.condition.video.type.source="Fonte"
|
||||
AdvSceneSwitcher.condition.video.type.scene="Cena"
|
||||
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
|
||||
AdvSceneSwitcher.condition.video.entry.modelPath="Dados do modelo (classificador em cascata haar):{{modelDataPath}}"
|
||||
AdvSceneSwitcher.condition.video.entry.minNeighbor="Vizinhos mínimos:{{minNeighbors}}"
|
||||
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}Reduzir carga de CPU realizando a verificação apenas a cada {{throttleCount}} milissegundos"
|
||||
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="Realizar verificação apenas na área"
|
||||
AdvSceneSwitcher.condition.video.entry.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
|
||||
AdvSceneSwitcher.condition.video.entry.orcColorPick="Verificar cor do texto:{{textColor}}{{selectColor}}"
|
||||
AdvSceneSwitcher.condition.video.entry.orcTextType="Verificar tipo de texto:{{textType}}"
|
||||
AdvSceneSwitcher.condition.video.entry.orcLanguage="Verificar idioma:{{languageCode}}"
|
||||
AdvSceneSwitcher.condition.video.entry.color="Verificar cor:{{color}}{{selectColor}}"
|
||||
AdvSceneSwitcher.condition.video.layout="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
|
||||
AdvSceneSwitcher.condition.video.layout.modelPath="Dados do modelo (classificador em cascata haar):{{modelDataPath}}"
|
||||
AdvSceneSwitcher.condition.video.layout.minNeighbor="Vizinhos mínimos:{{minNeighbors}}"
|
||||
AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}Reduzir carga de CPU realizando a verificação apenas a cada {{throttleCount}} milissegundos"
|
||||
AdvSceneSwitcher.condition.video.layout.checkAreaEnable="Realizar verificação apenas na área"
|
||||
AdvSceneSwitcher.condition.video.layout.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
|
||||
AdvSceneSwitcher.condition.video.layout.ocrColorPick="Verificar cor do texto:{{textColor}}{{selectColor}}"
|
||||
AdvSceneSwitcher.condition.video.layout.ocrTextType="Verificar tipo de texto:{{textType}}"
|
||||
AdvSceneSwitcher.condition.video.layout.ocrLanguage="Verificar idioma:{{languageCode}}"
|
||||
AdvSceneSwitcher.condition.video.layout.color="Verificar cor:{{color}}{{selectColor}}"
|
||||
AdvSceneSwitcher.condition.video.minSize="Tamanho mínimo:"
|
||||
AdvSceneSwitcher.condition.video.maxSize="Tamanho máximo:"
|
||||
AdvSceneSwitcher.condition.video.selectArea="Selecionar área"
|
||||
|
|
@ -395,7 +393,6 @@ AdvSceneSwitcher.condition.stream.state.stop="Streaming parado"
|
|||
AdvSceneSwitcher.condition.stream.state.starting="Iniciando o streaming"
|
||||
AdvSceneSwitcher.condition.stream.state.stopping="Parando o streaming"
|
||||
AdvSceneSwitcher.condition.stream.state.keyFrameInterval="Intervalo de keyframe igual a"
|
||||
AdvSceneSwitcher.condition.stream.entry="{{streamState}}{{keyFrameInterval}}"
|
||||
AdvSceneSwitcher.condition.record="Gravação"
|
||||
AdvSceneSwitcher.condition.record.state.start="Gravação em execução"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Gravação pausada"
|
||||
|
|
@ -504,14 +501,14 @@ AdvSceneSwitcher.condition.replay.state.started="Buffer de replay iniciado"
|
|||
AdvSceneSwitcher.condition.replay.state.saved="Buffer de replay salvo"
|
||||
AdvSceneSwitcher.condition.replay.entry="{{state}}"
|
||||
AdvSceneSwitcher.condition.date="Data"
|
||||
AdvSceneSwitcher.condition.date.anyDay="Qualquer dia"
|
||||
AdvSceneSwitcher.condition.date.monday="Segunda-feira"
|
||||
AdvSceneSwitcher.condition.date.tuesday="Terça-feira"
|
||||
AdvSceneSwitcher.condition.date.wednesday="Quarta-feira"
|
||||
AdvSceneSwitcher.condition.date.thursday="Quinta-feira"
|
||||
AdvSceneSwitcher.condition.date.friday="Sexta-feira"
|
||||
AdvSceneSwitcher.condition.date.saturday="Sábado"
|
||||
AdvSceneSwitcher.condition.date.sunday="Domingo"
|
||||
AdvSceneSwitcher.day.any="Qualquer dia"
|
||||
AdvSceneSwitcher.day.monday="Segunda-feira"
|
||||
AdvSceneSwitcher.day.tuesday="Terça-feira"
|
||||
AdvSceneSwitcher.day.wednesday="Quarta-feira"
|
||||
AdvSceneSwitcher.day.thursday="Quinta-feira"
|
||||
AdvSceneSwitcher.day.friday="Sexta-feira"
|
||||
AdvSceneSwitcher.day.saturday="Sábado"
|
||||
AdvSceneSwitcher.day.sunday="Domingo"
|
||||
AdvSceneSwitcher.condition.date.state.at="Às"
|
||||
AdvSceneSwitcher.condition.date.state.after="Após"
|
||||
AdvSceneSwitcher.condition.date.state.before="Antes"
|
||||
|
|
@ -522,12 +519,13 @@ AdvSceneSwitcher.condition.date.ignoreDate="Se desmarcado, o componente de data
|
|||
AdvSceneSwitcher.condition.date.ignoreTime="Se desmarcado, o componente de tempo será ignorado"
|
||||
AdvSceneSwitcher.condition.date.showAdvancedSettings="Mostrar configurações avançadas"
|
||||
AdvSceneSwitcher.condition.date.showSimpleSettings="Mostrar configurações simples"
|
||||
AdvSceneSwitcher.condition.date.entry.simple="Em{{dayOfWeek}}{{weekCondition}}{{ignoreWeekTime}}{{weekTime}}"
|
||||
AdvSceneSwitcher.condition.date.entry.advanced="{{condition}}{{ignoreDate}}{{date}}{{ignoreTime}}{{time}}{{separator}}{{date2}}{{time2}}"
|
||||
AdvSceneSwitcher.condition.date.entry.repeat="{{repeat}}Repetir a cada{{duration}}em correspondência de data"
|
||||
AdvSceneSwitcher.condition.date.entry.pattern="Data atual \"{{currentDate}}\" corresponde ao padrão{{pattern}}"
|
||||
AdvSceneSwitcher.condition.date.entry.nextMatchDate="Próxima correspondência em: %1"
|
||||
AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}}Ao repetir, atualize a data selecionada para a data de repetição"
|
||||
AdvSceneSwitcher.condition.date.layout.simple.day="Em{{dayOfWeek}}"
|
||||
AdvSceneSwitcher.condition.date.layout.simple.time="{{ignoreWeekTime}}{{weekCondition}}{{weekTime}}"
|
||||
AdvSceneSwitcher.condition.date.layout.advanced="{{condition}}{{ignoreDate}}{{date}}{{ignoreTime}}{{time}}{{separator}}{{date2}}{{time2}}"
|
||||
AdvSceneSwitcher.condition.date.layout.repeat="{{repeat}}Repetir a cada{{duration}}em correspondência de data"
|
||||
AdvSceneSwitcher.condition.date.layout.pattern="Data atual \"{{currentDate}}\" corresponde ao padrão{{pattern}}"
|
||||
AdvSceneSwitcher.condition.date.layout.nextMatchDate="Próxima correspondência em: %1"
|
||||
AdvSceneSwitcher.condition.date.layout.updateOnRepeat="{{updateOnRepeat}}Ao repetir, atualize a data selecionada para a data de repetição"
|
||||
AdvSceneSwitcher.condition.sceneTransform="Transformação do item de cena"
|
||||
AdvSceneSwitcher.condition.sceneTransform.getTransform="Obter transformação"
|
||||
AdvSceneSwitcher.condition.sceneTransform.getCurrentValue="Obter valor atual"
|
||||
|
|
@ -722,9 +720,6 @@ AdvSceneSwitcher.condition.noDevicesFoundWarning="Nenhum dispositivo USB detecta
|
|||
AdvSceneSwitcher.action.scene="Trocar cena"
|
||||
AdvSceneSwitcher.action.scene.type.program="Programa"
|
||||
AdvSceneSwitcher.action.scene.type.preview="Pré-visualização"
|
||||
AdvSceneSwitcher.action.scene.entry="Trocar{{sceneTypes}}cena para{{scenes}}usando{{transitions}}com duração de{{duration}}segundos"
|
||||
AdvSceneSwitcher.action.scene.entry.noDuration="Trocar{{sceneTypes}}cena para{{scenes}}usando{{transitions}}"
|
||||
AdvSceneSwitcher.action.scene.entry.preview="Trocar{{sceneTypes}}cena para{{scenes}}"
|
||||
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Aguardar até que a transição para a cena de destino seja concluída"
|
||||
AdvSceneSwitcher.action.wait="Aguardar"
|
||||
AdvSceneSwitcher.action.wait.type.fixed="fixo"
|
||||
|
|
@ -786,7 +781,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.hide="Ocultar"
|
|||
AdvSceneSwitcher.action.sceneVisibility.type.toggle="Alternar"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.source="Fonte"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Qualquer"
|
||||
AdvSceneSwitcher.action.sceneVisibility.entry="Em{{scenes}}{{actions}}{{sources}}"
|
||||
AdvSceneSwitcher.action.sceneVisibility.layout="Em{{scenes}}{{actions}}{{sources}}"
|
||||
AdvSceneSwitcher.action.filter="Filtro"
|
||||
AdvSceneSwitcher.action.filter.type.enable="Habilitar"
|
||||
AdvSceneSwitcher.action.filter.type.disable="Desabilitar"
|
||||
|
|
@ -866,9 +861,9 @@ AdvSceneSwitcher.action.macro.type.stop="Parar ações"
|
|||
AdvSceneSwitcher.action.macro.type.disableAction="Desabilitar ação"
|
||||
AdvSceneSwitcher.action.macro.type.enableAction="Habilitar ação"
|
||||
AdvSceneSwitcher.action.macro.type.toggleAction="Alternar ação"
|
||||
AdvSceneSwitcher.action.macro.entry.run="{{actions}}{{actionTypes}}de{{macros}}"
|
||||
AdvSceneSwitcher.action.macro.entry.run.condition="{{conditionBehaviors}}de{{conditionMacros}}"
|
||||
AdvSceneSwitcher.action.macro.entry.other="{{actions}}{{actionIndex}}{{macros}}"
|
||||
AdvSceneSwitcher.action.macro.layout.run="{{actions}}{{actionSections}}de{{macros}}"
|
||||
AdvSceneSwitcher.action.macro.layout.run.condition="{{conditionBehaviors}}de{{conditionMacros}}"
|
||||
AdvSceneSwitcher.action.macro.layout.other="{{actions}}{{macros}}"
|
||||
AdvSceneSwitcher.action.pluginState="Estado do plugin"
|
||||
AdvSceneSwitcher.action.pluginState.type.stop="Parar o plugin Advanced Scene Switcher"
|
||||
AdvSceneSwitcher.action.pluginState.type.noMatch="Alterar o comportamento em caso de não correspondência:"
|
||||
|
|
@ -876,7 +871,7 @@ AdvSceneSwitcher.action.pluginState.type.import="Importar configurações de"
|
|||
AdvSceneSwitcher.action.pluginState.importWarning="Nota: Ação será ignorada enquanto a janela de configurações estiver aberta."
|
||||
AdvSceneSwitcher.action.pluginState.type.terminate="Desligar OBS"
|
||||
AdvSceneSwitcher.action.pluginState.terminateConfirm="O OBS será desligado automaticamente em 10 segundos!\nDeseja continuar com o desligamento do OBS?"
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}"
|
||||
AdvSceneSwitcher.action.virtualCamera="Câmera virtual"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.stop="Parar câmera virtual"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.start="Iniciar câmera virtual"
|
||||
|
|
@ -907,7 +902,7 @@ AdvSceneSwitcher.action.sceneOrder.type.moveDown="Mover para baixo"
|
|||
AdvSceneSwitcher.action.sceneOrder.type.moveTop="Mover para o topo"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveBottom="Mover para o fundo"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.movePosition="Mover para posição"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="Em{{scenes}}{{actions}}{{sources}}{{position}}"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="Em{{scenes}}{{actions}}{{sources}}{{sources2}}{{position}}"
|
||||
AdvSceneSwitcher.action.sceneTransform="Transformação de item de cena"
|
||||
AdvSceneSwitcher.action.sceneTransform.type.manual="Definir string de transformação"
|
||||
AdvSceneSwitcher.action.sceneTransform.type.setSingleSetting="Definir configuração de transformação"
|
||||
|
|
@ -961,7 +956,6 @@ AdvSceneSwitcher.action.screenshot.save.default="Padrão"
|
|||
AdvSceneSwitcher.action.screenshot.save.custom="Personalizado"
|
||||
AdvSceneSwitcher.action.screenshot.type.source="Fonte"
|
||||
AdvSceneSwitcher.action.screenshot.type.scene="Cena"
|
||||
AdvSceneSwitcher.action.screenshot.mainOutput="Saída principal do OBS"
|
||||
AdvSceneSwitcher.action.screenshot.blackscreenNote="Fontes ou cenas, que nem sempre são renderizadas, podem resultar em algumas partes das capturas de tela permanecendo em branco."
|
||||
AdvSceneSwitcher.action.screenshot.entry="Captura de tela{{targetType}}{{sources}}{{scenes}}e salvar em{{saveType}}{{variables}}localização"
|
||||
AdvSceneSwitcher.action.profile="Perfil"
|
||||
|
|
@ -1014,7 +1008,7 @@ AdvSceneSwitcher.action.variable.type.askForValue="Obter entrada do usuário"
|
|||
AdvSceneSwitcher.action.variable.type.environmentVariable="Definir valor da variável de ambiente"
|
||||
AdvSceneSwitcher.action.variable.type.sceneItemCount="Definir para contagem de itens de cena"
|
||||
AdvSceneSwitcher.action.variable.type.stringLength="Definir comprimento da string"
|
||||
AdvSceneSwitcher.action.variable.type.extractJson="Extrair campo json com nome"
|
||||
AdvSceneSwitcher.action.variable.type.extractJsonField="Extrair campo json com nome"
|
||||
AdvSceneSwitcher.action.variable.type.setToTempvar="Definir para propriedade da macro"
|
||||
AdvSceneSwitcher.action.variable.type.setToTempvar.help="Este tipo de ação permite extrair valores de segmentos da macro atual e atribuir esses valores à variável selecionada.\nPor exemplo, você pode obter o nome da cena atual de uma condição de cena e atribuir esse nome a uma variável."
|
||||
AdvSceneSwitcher.action.variable.type.sceneItemName="Definir para nome do item de cena no índice"
|
||||
|
|
@ -1034,13 +1028,13 @@ AdvSceneSwitcher.action.variable.invalidSelection="Seleção inválida!"
|
|||
AdvSceneSwitcher.action.variable.actionNoVariableSupport="Obter valores de variáveis das ações %1 não é suportado!"
|
||||
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="Obter valores de variáveis das condições %1 não é suportado!"
|
||||
AdvSceneSwitcher.action.variable.currentSegmentValue="Valor atual:"
|
||||
AdvSceneSwitcher.action.variable.entry.pad="{{actions}}de{{variables}}para comprimento{{stringLength}}adicionando{{paddingCharSelection}}ao{{direction}}"
|
||||
AdvSceneSwitcher.action.variable.entry.truncate="{{actions}}de{{variables}}para comprimento{{stringLength}}removendo caracteres da{{direction}}"
|
||||
AdvSceneSwitcher.action.variable.entry.substringIndex="Início da substring:{{subStringStart}}Tamanho da substring:{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.entry.substringRegex="Atribuir valor do{{regexMatchIdx}}correspondência usando expressão regular:"
|
||||
AdvSceneSwitcher.action.variable.entry.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
|
||||
AdvSceneSwitcher.action.variable.entry.userInput.customPrompt="{{useCustomPrompt}}Usar prompt personalizado{{inputPrompt}}"
|
||||
AdvSceneSwitcher.action.variable.entry.userInput.placeholder="{{useInputPlaceholder}}Preencher com placeholder{{inputPlaceholder}}"
|
||||
AdvSceneSwitcher.action.variable.layout.pad="{{actions}}de{{variables}}para comprimento{{stringLength}}adicionando{{paddingCharSelection}}ao{{direction}}"
|
||||
AdvSceneSwitcher.action.variable.layout.truncate="{{actions}}de{{variables}}para comprimento{{stringLength}}removendo caracteres da{{direction}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringIndex="Início da substring:{{subStringStart}}Tamanho da substring:{{subStringSize}}{{subStringRegex}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringRegex="Atribuir valor do{{regexMatchIdx}}correspondência usando expressão regular:{{subStringRegex}}"
|
||||
AdvSceneSwitcher.action.variable.layout.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
|
||||
AdvSceneSwitcher.action.variable.layout.userInput.customPrompt="{{useCustomPrompt}}Usar prompt personalizado{{inputPrompt}}"
|
||||
AdvSceneSwitcher.action.variable.layout.userInput.placeholder="{{useInputPlaceholder}}Preencher com placeholder{{inputPlaceholder}}"
|
||||
AdvSceneSwitcher.action.projector="Projetor"
|
||||
AdvSceneSwitcher.action.projector.type.source="Fonte"
|
||||
AdvSceneSwitcher.action.projector.type.scene="Cena"
|
||||
|
|
@ -1050,8 +1044,6 @@ AdvSceneSwitcher.action.projector.type.multiview="Multivisão"
|
|||
AdvSceneSwitcher.action.projector.display="Exibição"
|
||||
AdvSceneSwitcher.action.projector.windowed="Janela"
|
||||
AdvSceneSwitcher.action.projector.fullscreen="Tela cheia"
|
||||
AdvSceneSwitcher.action.projector.entry="Abrir{{windowTypes}}projetor de{{types}}{{scenes}}{{sources}}"
|
||||
AdvSceneSwitcher.action.projector.entry.monitor="em{{monitors}}"
|
||||
AdvSceneSwitcher.action.midi="MIDI"
|
||||
AdvSceneSwitcher.action.midi.entry="Enviar mensagem para{{device}}:"
|
||||
AdvSceneSwitcher.action.midi.entry.listen="Definir seleção de mensagem MIDI para mensagens recebidas em{{listenDevices}}:{{listenButton}}"
|
||||
|
|
@ -1071,10 +1063,10 @@ AdvSceneSwitcher.action.twitch.type.clip.create="Criar clipe da transmissão"
|
|||
AdvSceneSwitcher.action.twitch.type.chat.announcement.send="Enviar anúncio de chat"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.enable="Habilitar modo apenas emotes no chat"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.disable="Desabilitar modo apenas emotes no chat"
|
||||
AdvSceneSwitcher.action.twitch.type.sendChatMessage="Enviar mensagem de chat"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.sendMessage="Enviar mensagem de chat"
|
||||
AdvSceneSwitcher.action.twitch.categorySelectionDisabled="Não é possível selecionar categoria sem selecionar uma conta Twitch primeiro!"
|
||||
AdvSceneSwitcher.action.twitch.entry.default="Em{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}"
|
||||
AdvSceneSwitcher.action.twitch.entry.chat="Usando conta{{account}}{{actions}}em{{channel}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}"
|
||||
AdvSceneSwitcher.action.twitch.layout.default="Em{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}{{pointsReward}}{{nonModDelayDuration}}"
|
||||
AdvSceneSwitcher.action.twitch.layout.chat="Usando conta{{account}}{{actions}}em{{channel}}"
|
||||
AdvSceneSwitcher.action.twitch.title.title="Digite o título"
|
||||
AdvSceneSwitcher.action.twitch.marker.description="Descreva o marcador"
|
||||
AdvSceneSwitcher.action.twitch.clip.hasDelay="Adicionar um leve atraso antes de capturar o clipe"
|
||||
|
|
@ -1116,9 +1108,9 @@ AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Alternar Iniciar/Parar pa
|
|||
AdvSceneSwitcher.hotkey.macro.pause="Pausar macro %1"
|
||||
AdvSceneSwitcher.hotkey.macro.unpause="Retomar macro %1"
|
||||
AdvSceneSwitcher.hotkey.macro.togglePause="Alternar pausa da macro %1"
|
||||
AdvSceneSwitcher.hotkey.upMacroSegmentHotkey="Mover seleção de segmento de macro para cima"
|
||||
AdvSceneSwitcher.hotkey.downMacroSegmentHotkey="Mover seleção de segmento de macro para baixo"
|
||||
AdvSceneSwitcher.hotkey.removeMacroSegmentHotkey="Remover segmento de macro selecionado"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.up="Mover seleção de segmento de macro para cima"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.down="Mover seleção de segmento de macro para baixo"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.remove="Remover segmento de macro selecionado"
|
||||
|
||||
AdvSceneSwitcher.askBackup="Detectada uma nova versão do Advanced Scene Switcher.\nDeve ser criado um backup das configurações antigas?"
|
||||
AdvSceneSwitcher.askForMacro="Selecionar macro{{macroSelection}}"
|
||||
|
|
@ -1856,19 +1848,19 @@ AdvSceneSwitcher.setting.transform.width="Largura"
|
|||
|
||||
AdvSceneSwitcher.sceneItemSelection.configure="Configurar tipo de seleção de item de cena"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName="Nome da fonte"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName.entry="{{nameConflictIndex}}{{sourceName}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName.layout="{{nameConflictIndex}}{{sourceName}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable="Nome da variável"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable.entry="{{nameConflictIndex}}{{variable}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable.layout="{{nameConflictIndex}}{{variable}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern="Nome da fonte corresponde ao padrão"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.entry="{{nameConflictIndex}}correspondendo{{pattern}}{{regex}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.layout="{{nameConflictIndex}}correspondendo{{pattern}}{{regex}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType="Fontes do tipo"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType.entry="Tipo de fonte{{nameConflictIndex}}{{sourceTypes}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType.layout="Tipo de fonte{{nameConflictIndex}}{{sourceTypes}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index="Fonte com índice"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index.entry="{{index}}fonte"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index.layout="{{index}}fonte"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange="Fontes no intervalo de índices"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange.entry="Fontes de{{index}}para{{indexEnd}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange.layout="Fontes de{{index}}para{{indexEnd}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all="Todas as fontes"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all.entry="Todas as fontes"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all.layout="Todas as fontes"
|
||||
AdvSceneSwitcher.sceneItemSelection.all="Todas"
|
||||
AdvSceneSwitcher.sceneItemSelection.any="Qualquer"
|
||||
|
||||
|
|
@ -1879,8 +1871,6 @@ AdvSceneSwitcher.status.inactive="Inativo"
|
|||
AdvSceneSwitcher.running="Plugin em execução"
|
||||
AdvSceneSwitcher.stopped="Plugin parado"
|
||||
|
||||
AdvSceneSwitcher.firstBootMessage="<html><head/><body><p>Parece que esta é a primeira vez que o Advanced Scene Switcher está sendo iniciado.<br>Por favor, consulte o <a href=\"https://github.com/WarmUpTill/SceneSwitcher/wiki\"><span style=\" text-decoration: underline; color:#268bd2;\">Wiki</span></a> para uma lista de guias e exemplos.<br>Não hesite em fazer perguntas no <a href=\"https://obsproject.com/forum/threads/advanced-scene-switcher.48264\"><span style=\" text-decoration: underline; color:#268bd2;\">tópico</span></a> do plugin nos fóruns do OBS!</p></body></html>"
|
||||
|
||||
AdvSceneSwitcher.deprecatedTabWarning="Desenvolvimento para esta aba interrompido!\nPor favor, considere a transição para o uso de Macros em vez disso.\nEsta dica pode ser desativada na aba Geral."
|
||||
|
||||
AdvSceneSwitcher.unit.milliseconds="milissegundos"
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Всегда запу
|
|||
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Не запускать переключатель сцен"
|
||||
AdvSceneSwitcher.generalTab.status.start="Старт"
|
||||
AdvSceneSwitcher.generalTab.status.stop="Стоп"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart="Автоматически запускать переключатель сцен, когда:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.startup="Автоматически запускать переключатель сцен, когда:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.never="Никогда"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.recording="Запись"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Вещание"
|
||||
|
|
@ -25,7 +25,6 @@ AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.dontSwitch="Не пере
|
|||
AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchToRandom="Переключиться на любую сцену на вкладке Random"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchTo="Переключиться на:"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint="В течение этого времени потенциальные совпадения будут игнорироваться!"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Включить ведение подробного журнала"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="Сохранять положение и размер окна"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="Отключить подсказки пользовательского интерфейса"
|
||||
AdvSceneSwitcher.generalTab.priority="Приоритет"
|
||||
|
|
@ -37,7 +36,7 @@ AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="Экспорт"
|
|||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Импорт"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Экспортировать настройки расширенного переключателя сцен в файл ..."
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Импортировать настройки Advanced Scene Switcher из файла ..."
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Текстовые файлы (*.txt)"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Текстовые файлы (*.txt *.json)"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="Advanced Scene Switcher не удалось импортировать настройки"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Настройки Advanced Scene Switcher импортированы успешно"
|
||||
AdvSceneSwitcher.generalTab.priority.fileContent="Содержание файла"
|
||||
|
|
@ -115,7 +114,6 @@ AdvSceneSwitcher.condition.pluginState.entry="{{condition}}"
|
|||
|
||||
; Macro Actions
|
||||
AdvSceneSwitcher.action.scene="Переключить сцену"
|
||||
AdvSceneSwitcher.action.scene.entry="Перейти к сцене{{sceneTypes}}{{scenes}}используя{{transitions}}с продолжительностью{{duration}}секунд"
|
||||
AdvSceneSwitcher.action.wait="Подождать"
|
||||
AdvSceneSwitcher.action.wait.type.fixed="фиксированный"
|
||||
AdvSceneSwitcher.action.wait.type.random="случайный"
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Her zaman sahne deği
|
|||
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Sahne değiştiriciyi başlatma"
|
||||
AdvSceneSwitcher.generalTab.status.start="Başlat"
|
||||
AdvSceneSwitcher.generalTab.status.stop="Durdur"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart="Aşağıdaki durumlarda sahne değiştiriciyi otomatik olarak başlatın:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.startup="Aşağıdaki durumlarda sahne değiştiriciyi otomatik olarak başlatın:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.never="Asla"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.recording="Kayıt"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Yayın"
|
||||
|
|
@ -26,7 +26,6 @@ AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchToRandom="Rastgele s
|
|||
AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchTo="Değiştirmek:"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.cooldown="Bir eşleşmeden sonra aşağıdakiler için işlem yapmayın:"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint="Bu süre zarfında olası eşleşmeler göz ardı edilecektir!"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Ayrıntılı günlük kaydını etkinleştir"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="Pencere konumunu ve boyutunu kaydet"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="Sistem tepsisi bildirimlerini göster"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="UI ipuçlarını devre dışı bırak"
|
||||
|
|
@ -39,7 +38,7 @@ AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="Dışa Aktar"
|
|||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="İçe Aktar"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Gelişmiş Sahne Değiştirici ayarlarını dosyaya aktar ..."
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Gelişmiş Sahne Değiştirici ayarlarını dosyadan içe aktar ..."
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Text dosyası (*.txt)"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Text dosyası (*.txt *.json)"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="Gelişmiş Sahne Değiştirici ayarları dosyadan içe aktarmakta başarısız oldu"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Gelişmiş Sahne Değiştirici ayarları başarılı bir şekilde dosyadan içe aktarıldı"
|
||||
AdvSceneSwitcher.generalTab.priority.fileContent="Dosya İçeriği"
|
||||
|
|
@ -73,7 +72,6 @@ AdvSceneSwitcher.macroTab.add="Yeni Makro ekle"
|
|||
AdvSceneSwitcher.macroTab.name="İsim:"
|
||||
AdvSceneSwitcher.macroTab.run="Makro Çalıştırma"
|
||||
AdvSceneSwitcher.macroTab.runInParallel="Makroyu diğer makrolara paralel olarak çalıştırın"
|
||||
AdvSceneSwitcher.macroTab.onChange="Eylemleri yalnızca koşul değişikliğinde gerçekleştirin"
|
||||
AdvSceneSwitcher.macroTab.defaultname="Makro %1"
|
||||
AdvSceneSwitcher.macroTab.copy="Kopya oluştur"
|
||||
AdvSceneSwitcher.macroTab.expandAll="Hepsini Genişlet"
|
||||
|
|
@ -140,16 +138,15 @@ AdvSceneSwitcher.condition.video.screenshotFail="Kaynağın ekran görüntüsü
|
|||
AdvSceneSwitcher.condition.video.patternMatchFail="Desen bulunamadı!"
|
||||
AdvSceneSwitcher.condition.video.objectMatchFail="Nesne bulunamadı!"
|
||||
AdvSceneSwitcher.condition.video.modelLoadFail="Model verileri yüklenemedi!"
|
||||
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
|
||||
AdvSceneSwitcher.condition.video.entry.modelPath="Model verileri (haar kademeli sınıflandırıcı):{{modelDataPath}}"
|
||||
AdvSceneSwitcher.condition.video.entry.minNeighbor="Minimum komşular: {{minNeighbors}}"
|
||||
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}} Yalnızca her seferinde kontrol gerçekleştirerek CPU yükünü azaltın {{throttleCount}} millisaniyeler"
|
||||
AdvSceneSwitcher.condition.video.layout="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
|
||||
AdvSceneSwitcher.condition.video.layout.modelPath="Model verileri (haar kademeli sınıflandırıcı):{{modelDataPath}}"
|
||||
AdvSceneSwitcher.condition.video.layout.minNeighbor="Minimum komşular: {{minNeighbors}}"
|
||||
AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}} Yalnızca her seferinde kontrol gerçekleştirerek CPU yükünü azaltın {{throttleCount}} millisaniyeler"
|
||||
AdvSceneSwitcher.condition.stream="Yayınlama"
|
||||
AdvSceneSwitcher.condition.stream.state.start="Yayın çalışıyor"
|
||||
AdvSceneSwitcher.condition.stream.state.stop="Yayın durdu"
|
||||
AdvSceneSwitcher.condition.stream.state.starting="Yayın başlıyor"
|
||||
AdvSceneSwitcher.condition.stream.state.stopping="Yayın duruyor"
|
||||
AdvSceneSwitcher.condition.stream.entry="{{streamState}}{{keyFrameInterval}}"
|
||||
AdvSceneSwitcher.condition.record="Kayıt"
|
||||
AdvSceneSwitcher.condition.record.state.start="Kayıt Çalışıyor"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Kayıt durakladı"
|
||||
|
|
@ -251,7 +248,6 @@ AdvSceneSwitcher.condition.openvr.entry.line3="HMD mevcut {{xPos}} x {{yPos}} x
|
|||
|
||||
; Macro Actions
|
||||
AdvSceneSwitcher.action.scene="Sahne Degistirici"
|
||||
AdvSceneSwitcher.action.scene.entry="Sahneyi{{sceneTypes}}{{scenes}}kullanarak{{transitions}}süresi olan{{duration}}saniye"
|
||||
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Hedef sahneye geçiş tamamlanana kadar bekleyin"
|
||||
AdvSceneSwitcher.action.wait="Bekle"
|
||||
AdvSceneSwitcher.action.wait.type.fixed="sabit"
|
||||
|
|
@ -284,7 +280,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.show="Göster"
|
|||
AdvSceneSwitcher.action.sceneVisibility.type.hide="Gizle"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.source="Kayıt"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Herhangi"
|
||||
AdvSceneSwitcher.action.sceneVisibility.entry="Açık{{scenes}}{{actions}}{{sources}}"
|
||||
AdvSceneSwitcher.action.sceneVisibility.layout="Açık{{scenes}}{{actions}}{{sources}}"
|
||||
AdvSceneSwitcher.action.filter="Filtrele"
|
||||
AdvSceneSwitcher.action.filter.type.enable="Etkin"
|
||||
AdvSceneSwitcher.action.filter.type.disable="Etkisiz"
|
||||
|
|
@ -314,7 +310,7 @@ AdvSceneSwitcher.action.pluginState.type.stop="Advanced Scene Switcher eklentisi
|
|||
AdvSceneSwitcher.action.pluginState.type.noMatch="Eşleşmeme davranışını değiştirin:"
|
||||
AdvSceneSwitcher.action.pluginState.type.import="Ayarları şuradan içe aktar:"
|
||||
AdvSceneSwitcher.action.pluginState.importWarning="Not: Ayarlar penceresi açılırken eylem göz ardı edilecektir."
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}"
|
||||
AdvSceneSwitcher.action.virtualCamera="Sanal Kamera"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.stop="Sanal Kamerayı Durdur"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.start="Sanal Kamerayı Başlat"
|
||||
|
|
@ -336,7 +332,7 @@ AdvSceneSwitcher.action.sceneOrder.type.moveDown="Aşağı indir"
|
|||
AdvSceneSwitcher.action.sceneOrder.type.moveTop="En üste taşı"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveBottom="Aşağıya taşı"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.movePosition="Konuma taşı"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="Açık{{scenes}}{{actions}}{{sources}}{{position}}"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="Açık{{scenes}}{{actions}}{{sources}}{{sources2}}{{position}}"
|
||||
AdvSceneSwitcher.action.sceneTransform="Sahne öğesi dönüşümü"
|
||||
AdvSceneSwitcher.action.sceneTransform.getTransform="Dönüşümü al"
|
||||
AdvSceneSwitcher.action.sceneTransform.entry="Açık{{scenes}}{{action}}{{rotation}}{{sources}}{{settingSelection}}{{singleSettingValue}}"
|
||||
|
|
@ -357,7 +353,6 @@ AdvSceneSwitcher.action.random="Rastgele"
|
|||
AdvSceneSwitcher.action.random.entry="Aşağıdaki makrolardan herhangi birini rastgele çalıştırın (duraklatılmış makrolar yoksayılır)"
|
||||
AdvSceneSwitcher.action.systray="Sistem tepsisi bildirimi"
|
||||
AdvSceneSwitcher.action.screenshot="Ekran görüntüsü"
|
||||
AdvSceneSwitcher.action.screenshot.mainOutput="OBS'nin ana çıkışı"
|
||||
AdvSceneSwitcher.action.profile="Profil"
|
||||
AdvSceneSwitcher.action.profile.entry="Aktif profili şununla değiştir: {{profiles}}"
|
||||
AdvSceneSwitcher.action.sceneCollection="Sahne koleksiyonu"
|
||||
|
|
@ -591,8 +586,6 @@ AdvSceneSwitcher.status.inactive="İnaktif"
|
|||
AdvSceneSwitcher.running="Eklenti çalışıyor"
|
||||
AdvSceneSwitcher.stopped="Eklenti durdu"
|
||||
|
||||
AdvSceneSwitcher.firstBootMessage="<html><head/><body><p>Gelişmiş Sahne Değiştirici ilk kez başlatılıyor gibi görünüyor.<br>Lütfen <a href=\"https://github.com/ adresine bir göz atın. WarmUpTill/SceneSwitcher/wiki\"><span style=\" text-decoration: underline; color:#268bd2;\">Wiki</span></a> için kılavuzlar ve örnekler listesi.<br>Yapmayın. eklentinin <a href=\"https://obsproject.com/forum/threads/advanced-scene-switcher.48264\"><span style=\" text-decoration: underline; color:# sayfasında soru sormaktan çekinmeyin OBS forumlarında 268bd2;\">konu</span></a>!</p></body></html>"
|
||||
|
||||
AdvSceneSwitcher.unit.milliseconds="millisaniye"
|
||||
AdvSceneSwitcher.unit.seconds="saniye"
|
||||
AdvSceneSwitcher.unit.minutes="dakika"
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
BIN
data/res/images/logo.ico
Normal file
BIN
data/res/images/logo.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
1
deps/date
vendored
Submodule
1
deps/date
vendored
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 5bdb7e6f31fac909c090a46dbd9fea27b6e609a4
|
||||
13156
deps/exprtk/exprtk.hpp
vendored
13156
deps/exprtk/exprtk.hpp
vendored
File diff suppressed because it is too large
Load Diff
2
deps/json
vendored
2
deps/json
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit bc889afb4c5bf1c0d8ee29ef35eaaf4c8bef8a5d
|
||||
Subproject commit 55f93686c01528224f448c19128836e7df245f72
|
||||
1
deps/jsoncons
vendored
Submodule
1
deps/jsoncons
vendored
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 64b9da1e9f15eeff4ec9d6bc856538db542118f2
|
||||
2
deps/libremidi
vendored
2
deps/libremidi
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit d6d6557b5bd138a56b7ea68dfcb92a0f9ff70a5b
|
||||
Subproject commit 73e6ea40de1a1ee35f16022e70fecfb45ae4061d
|
||||
2
deps/libusb
vendored
2
deps/libusb
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit d52e355daa09f17ce64819122cb067b8a2ee0d4b
|
||||
Subproject commit 15a7ebb4d426c5ce196684347d2b7cafad862626
|
||||
1
deps/paho.mqtt.cpp
vendored
Submodule
1
deps/paho.mqtt.cpp
vendored
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 165476b1dc248b3f4480f05646086326e1d7d82e
|
||||
File diff suppressed because it is too large
Load Diff
388
forms/macro-edit.ui
Normal file
388
forms/macro-edit.ui
Normal file
|
|
@ -0,0 +1,388 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MacroEdit</class>
|
||||
<widget class="QWidget" name="MacroEdit">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QSplitter" name="macroActionConditionSplitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<widget class="QWidget" name="macroConditions" native="true">
|
||||
<layout class="QVBoxLayout" name="macroConditionsLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="advss::MacroSegmentList" name="conditionsList">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>1</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="conditionControlsLayout">
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QToolButton" name="conditionAdd">
|
||||
<property name="toolTip">
|
||||
<string>AdvSceneSwitcher.macroTab.tooltip.conditionAddButton</string>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">addIconSmall</string>
|
||||
</property>
|
||||
<property name="class" stdset="0">
|
||||
<string notr="true">icon-plus</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="conditionRemove">
|
||||
<property name="toolTip">
|
||||
<string>AdvSceneSwitcher.macroTab.tooltip.conditionRemoveButton</string>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">removeIconSmall</string>
|
||||
</property>
|
||||
<property name="class" stdset="0">
|
||||
<string notr="true">icon-trash</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="conditionTop">
|
||||
<property name="toolTip">
|
||||
<string>AdvSceneSwitcher.macroTab.tooltip.conditionTopButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="conditionUp">
|
||||
<property name="toolTip">
|
||||
<string>AdvSceneSwitcher.macroTab.tooltip.conditionUpButton</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">upArrowIconSmall</string>
|
||||
</property>
|
||||
<property name="class" stdset="0">
|
||||
<string notr="true">icon-up</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="conditionDown">
|
||||
<property name="toolTip">
|
||||
<string>AdvSceneSwitcher.macroTab.tooltip.conditionDownButton</string>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">downArrowIconSmall</string>
|
||||
</property>
|
||||
<property name="class" stdset="0">
|
||||
<string notr="true">icon-down</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="conditionBottom">
|
||||
<property name="toolTip">
|
||||
<string>AdvSceneSwitcher.macroTab.tooltip.conditionBottomButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QSplitter" name="macroElseActionSplitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<widget class="QWidget" name="macroActions" native="true">
|
||||
<layout class="QVBoxLayout" name="macroActionsLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="advss::MacroSegmentList" name="actionsList">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>1</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="actionControlsLayout">
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QToolButton" name="actionAdd">
|
||||
<property name="toolTip">
|
||||
<string>AdvSceneSwitcher.macroTab.tooltip.actionAddButton</string>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">addIconSmall</string>
|
||||
</property>
|
||||
<property name="class" stdset="0">
|
||||
<string notr="true">icon-plus</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="actionRemove">
|
||||
<property name="toolTip">
|
||||
<string>AdvSceneSwitcher.macroTab.tooltip.actionRemoveButton</string>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">removeIconSmall</string>
|
||||
</property>
|
||||
<property name="class" stdset="0">
|
||||
<string notr="true">icon-trash</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="actionTop">
|
||||
<property name="toolTip">
|
||||
<string>AdvSceneSwitcher.macroTab.tooltip.actionTopButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="actionUp">
|
||||
<property name="toolTip">
|
||||
<string>AdvSceneSwitcher.macroTab.tooltip.actionUpButton</string>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">upArrowIconSmall</string>
|
||||
</property>
|
||||
<property name="class" stdset="0">
|
||||
<string notr="true">icon-up</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="actionDown">
|
||||
<property name="toolTip">
|
||||
<string>AdvSceneSwitcher.macroTab.tooltip.actionDownButton</string>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">downArrowIconSmall</string>
|
||||
</property>
|
||||
<property name="class" stdset="0">
|
||||
<string notr="true">icon-down</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="actionBottom">
|
||||
<property name="toolTip">
|
||||
<string>AdvSceneSwitcher.macroTab.tooltip.actionBottomButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_14">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="toggleElseActions">
|
||||
<property name="toolTip">
|
||||
<string>AdvSceneSwitcher.macroTab.tooltip.toggleShowElseSection</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="macroElseActions" native="true">
|
||||
<layout class="QVBoxLayout" name="macroElseActionsLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="advss::MacroSegmentList" name="elseActionsList">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>1</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="elseActionControlsLayout">
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QToolButton" name="elseActionAdd">
|
||||
<property name="toolTip">
|
||||
<string>AdvSceneSwitcher.macroTab.tooltip.elseActionAddButton</string>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">addIconSmall</string>
|
||||
</property>
|
||||
<property name="class" stdset="0">
|
||||
<string notr="true">icon-plus</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="elseActionRemove">
|
||||
<property name="toolTip">
|
||||
<string>AdvSceneSwitcher.macroTab.tooltip.elseActionRemoveButton</string>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">removeIconSmall</string>
|
||||
</property>
|
||||
<property name="class" stdset="0">
|
||||
<string notr="true">icon-trash</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="elseActionTop">
|
||||
<property name="toolTip">
|
||||
<string>AdvSceneSwitcher.macroTab.tooltip.elseActionTopButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="elseActionUp">
|
||||
<property name="toolTip">
|
||||
<string>AdvSceneSwitcher.macroTab.tooltip.elseActionUpButton</string>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">upArrowIconSmall</string>
|
||||
</property>
|
||||
<property name="class" stdset="0">
|
||||
<string notr="true">icon-up</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="elseActionDown">
|
||||
<property name="toolTip">
|
||||
<string>AdvSceneSwitcher.macroTab.tooltip.elseActionDownButton</string>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">downArrowIconSmall</string>
|
||||
</property>
|
||||
<property name="class" stdset="0">
|
||||
<string notr="true">icon-down</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="elseActionBottom">
|
||||
<property name="toolTip">
|
||||
<string>AdvSceneSwitcher.macroTab.tooltip.elseActionBottomButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>advss::MacroSegmentList</class>
|
||||
<extends>QScrollArea</extends>
|
||||
<header>macro-segment-list.hpp</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>conditionsList</tabstop>
|
||||
<tabstop>conditionAdd</tabstop>
|
||||
<tabstop>conditionRemove</tabstop>
|
||||
<tabstop>conditionTop</tabstop>
|
||||
<tabstop>conditionUp</tabstop>
|
||||
<tabstop>conditionDown</tabstop>
|
||||
<tabstop>conditionBottom</tabstop>
|
||||
<tabstop>actionsList</tabstop>
|
||||
<tabstop>actionAdd</tabstop>
|
||||
<tabstop>actionRemove</tabstop>
|
||||
<tabstop>actionTop</tabstop>
|
||||
<tabstop>actionUp</tabstop>
|
||||
<tabstop>actionDown</tabstop>
|
||||
<tabstop>actionBottom</tabstop>
|
||||
<tabstop>toggleElseActions</tabstop>
|
||||
<tabstop>elseActionsList</tabstop>
|
||||
<tabstop>elseActionAdd</tabstop>
|
||||
<tabstop>elseActionRemove</tabstop>
|
||||
<tabstop>elseActionTop</tabstop>
|
||||
<tabstop>elseActionUp</tabstop>
|
||||
<tabstop>elseActionDown</tabstop>
|
||||
<tabstop>elseActionBottom</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#include "advanced-scene-switcher.hpp"
|
||||
#include "backup.hpp"
|
||||
#include "curl-helper.hpp"
|
||||
#include "crash-handler.hpp"
|
||||
#include "log-helper.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "obs-module-helper.hpp"
|
||||
|
|
@ -19,10 +19,15 @@
|
|||
#include <obs-frontend-api.h>
|
||||
#include <QAction>
|
||||
#include <QDirIterator>
|
||||
#include <QLibrary>
|
||||
#include <QMainWindow>
|
||||
#include <QTextStream>
|
||||
#include <regex>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
namespace advss {
|
||||
|
||||
AdvSceneSwitcher *AdvSceneSwitcher::window = nullptr;
|
||||
|
|
@ -142,16 +147,7 @@ void AdvSceneSwitcher::LoadUI()
|
|||
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();
|
||||
} else if (eventType == QEvent::KeyPress) {
|
||||
if (eventType == QEvent::KeyPress) {
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
|
||||
auto pressedKey = keyEvent->key();
|
||||
|
||||
|
|
@ -196,25 +192,21 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
|||
|
||||
switcher->m.lock();
|
||||
if (switcher->VersionChanged(data, g_GIT_SHA1)) {
|
||||
auto json = obs_data_get_json(data);
|
||||
static QString jsonQString = json ? json : "";
|
||||
std::thread t([]() {
|
||||
obs_queue_task(
|
||||
OBS_TASK_UI,
|
||||
[](void *) {
|
||||
AskForBackup(jsonQString);
|
||||
},
|
||||
nullptr, false);
|
||||
});
|
||||
t.detach();
|
||||
AskForBackup(data);
|
||||
}
|
||||
|
||||
switcher->LoadSettings(data);
|
||||
switcher->m.unlock();
|
||||
|
||||
if (!switcher->stop) {
|
||||
switcher->Start();
|
||||
if (switcher->stop) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ShouldSkipPluginStartOnUncleanShutdown()) {
|
||||
return;
|
||||
}
|
||||
|
||||
switcher->Start();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -307,7 +299,7 @@ void SwitcherData::Thread()
|
|||
}
|
||||
}
|
||||
|
||||
ResetForNextInterval();
|
||||
RunIntervalResetSteps();
|
||||
|
||||
if (match) {
|
||||
if (macroMatch) {
|
||||
|
|
@ -357,14 +349,6 @@ void SwitcherData::SetPreconditions()
|
|||
InvalidateMacroTempVarValues();
|
||||
}
|
||||
|
||||
void SwitcherData::ResetForNextInterval()
|
||||
{
|
||||
// Plugin reset functions
|
||||
for (const auto &func : resetIntervalSteps) {
|
||||
func();
|
||||
}
|
||||
}
|
||||
|
||||
bool SwitcherData::CheckForMatch(OBSWeakSource &scene,
|
||||
OBSWeakSource &transition, int &linger,
|
||||
bool &setPrevSceneAfterLinger,
|
||||
|
|
@ -434,7 +418,7 @@ bool SwitcherData::CheckForMatch(OBSWeakSource &scene,
|
|||
|
||||
static void ResetMacros()
|
||||
{
|
||||
for (auto &m : GetMacros()) {
|
||||
for (auto &m : GetTopLevelMacros()) {
|
||||
ResetMacroRunCount(m.get());
|
||||
ResetMacroConditionTimers(m.get());
|
||||
}
|
||||
|
|
@ -445,7 +429,7 @@ void AutoStartActionQueues();
|
|||
void SwitcherData::Start()
|
||||
{
|
||||
if (!(th && th->isRunning())) {
|
||||
ResetForNextInterval();
|
||||
RunIntervalResetSteps();
|
||||
ResetMacros();
|
||||
AutoStartActionQueues();
|
||||
|
||||
|
|
@ -453,10 +437,7 @@ void SwitcherData::Start()
|
|||
th = new SwitcherThread();
|
||||
th->start((QThread::Priority)threadPriority);
|
||||
|
||||
// Will be overwritten quickly but might be useful
|
||||
writeToStatusFile("Advanced Scene Switcher running");
|
||||
SendWebsocketVendorEvent("AdvancedSceneSwitcherStarted",
|
||||
nullptr);
|
||||
RunStartSteps();
|
||||
}
|
||||
|
||||
if (showSystemTrayNotifications) {
|
||||
|
|
@ -483,11 +464,7 @@ void SwitcherData::Stop()
|
|||
th->wait();
|
||||
delete th;
|
||||
th = nullptr;
|
||||
writeToStatusFile("Advanced Scene Switcher stopped");
|
||||
if (!obsIsShuttingDown) {
|
||||
SendWebsocketVendorEvent("AdvancedSceneSwitcherStopped",
|
||||
nullptr);
|
||||
}
|
||||
RunStopSteps();
|
||||
}
|
||||
|
||||
if (showSystemTrayNotifications) {
|
||||
|
|
@ -558,6 +535,7 @@ static void handleSceneChange()
|
|||
}
|
||||
|
||||
switcher->checkDefaultSceneTransitions();
|
||||
switcher->CheckAutoStart();
|
||||
}
|
||||
|
||||
static void setLiveTime()
|
||||
|
|
@ -572,18 +550,28 @@ static void resetLiveTime()
|
|||
|
||||
static void checkAutoStartRecording()
|
||||
{
|
||||
if (switcher->obsIsShuttingDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (switcher->autoStartEvent == SwitcherData::AutoStart::RECORDING ||
|
||||
switcher->autoStartEvent ==
|
||||
SwitcherData::AutoStart::RECORINDG_OR_STREAMING)
|
||||
SwitcherData::AutoStart::RECORINDG_OR_STREAMING) {
|
||||
switcher->Start();
|
||||
}
|
||||
}
|
||||
|
||||
static void checkAutoStartStreaming()
|
||||
{
|
||||
if (switcher->obsIsShuttingDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (switcher->autoStartEvent == SwitcherData::AutoStart::STREAMING ||
|
||||
switcher->autoStartEvent ==
|
||||
SwitcherData::AutoStart::RECORINDG_OR_STREAMING)
|
||||
SwitcherData::AutoStart::RECORINDG_OR_STREAMING) {
|
||||
switcher->Start();
|
||||
}
|
||||
}
|
||||
|
||||
static void handleTransitionEnd()
|
||||
|
|
@ -619,7 +607,7 @@ static void handleSceneCollectionChanging()
|
|||
AdvSceneSwitcher::window->close();
|
||||
}
|
||||
if (!switcher->stop) {
|
||||
switcher->sceneColletionStop = true;
|
||||
switcher->sceneCollectionStop = true;
|
||||
switcher->Stop();
|
||||
}
|
||||
}
|
||||
|
|
@ -735,7 +723,7 @@ void OpenSettingsWindow()
|
|||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::HighligthMacroSettingsButton(bool enable)
|
||||
void AdvSceneSwitcher::HighlightMacroSettingsButton(bool enable)
|
||||
{
|
||||
static QObject *highlight = nullptr;
|
||||
if ((highlight && enable) || (!highlight && !enable)) {
|
||||
|
|
@ -755,13 +743,28 @@ void AdvSceneSwitcher::HighligthMacroSettingsButton(bool enable)
|
|||
highlight = HighlightWidget(ui->macroSettings, Qt::green);
|
||||
}
|
||||
|
||||
void HighligthMacroSettingsButton(bool enable)
|
||||
void AdvSceneSwitcher::HighlightAction(int idx, QColor color) const
|
||||
{
|
||||
ui->macroEdit->HighlightAction(idx, color);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::HighlightElseAction(int idx, QColor color) const
|
||||
{
|
||||
ui->macroEdit->HighlightElseAction(idx, color);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::HighlightCondition(int idx, QColor color) const
|
||||
{
|
||||
ui->macroEdit->HighlightCondition(idx, color);
|
||||
}
|
||||
|
||||
void HighlightMacroSettingsButton(bool enable)
|
||||
{
|
||||
auto window = GetSettingsWindow();
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
static_cast<AdvSceneSwitcher *>(window)->HighligthMacroSettingsButton(
|
||||
static_cast<AdvSceneSwitcher *>(window)->HighlightMacroSettingsButton(
|
||||
enable);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ namespace advss {
|
|||
|
||||
class MacroActionEdit;
|
||||
class MacroConditionEdit;
|
||||
class MacroSegment;
|
||||
class Duration;
|
||||
class SequenceWidget;
|
||||
struct SceneGroup;
|
||||
|
|
@ -44,7 +45,6 @@ protected:
|
|||
/* --- Begin of general tab section --- */
|
||||
public:
|
||||
void SetupGeneralTab();
|
||||
void UpdateNonMatchingScene(const QString &name);
|
||||
void SetDeprecationWarnings();
|
||||
|
||||
public slots:
|
||||
|
|
@ -57,7 +57,6 @@ public slots:
|
|||
void on_startupBehavior_currentIndexChanged(int index);
|
||||
void on_logLevel_currentIndexChanged(int index);
|
||||
void on_autoStartEvent_currentIndexChanged(int index);
|
||||
void on_noMatchSwitchScene_currentTextChanged(const QString &text);
|
||||
void on_checkInterval_valueChanged(int value);
|
||||
void on_tabWidget_currentChanged(int index);
|
||||
void on_exportSettings_clicked();
|
||||
|
|
@ -71,142 +70,56 @@ public slots:
|
|||
void on_priorityUp_clicked();
|
||||
void on_priorityDown_clicked();
|
||||
void on_threadPriority_currentTextChanged(const QString &text);
|
||||
void on_openSetupWizard_clicked();
|
||||
|
||||
/* --- End of legacy tab section --- */
|
||||
|
||||
/* --- Begin of macro tab section --- */
|
||||
public:
|
||||
void SetupMacroTab();
|
||||
bool MacroTabIsInFocus();
|
||||
bool AddNewMacro(std::shared_ptr<Macro> &res, std::string &name,
|
||||
std::string format = "");
|
||||
void RemoveMacro(std::shared_ptr<Macro> &);
|
||||
void RemoveSelectedMacros();
|
||||
void RenameMacro(std::shared_ptr<Macro> &, const QString &name);
|
||||
std::shared_ptr<Macro> GetSelectedMacro();
|
||||
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));
|
||||
std::shared_ptr<Macro> GetSelectedMacro() const;
|
||||
std::vector<std::shared_ptr<Macro>> GetSelectedMacros() const;
|
||||
void SetMacroEditAreaDisabled(bool) const;
|
||||
void HighlightAction(int idx, QColor color = QColor(Qt::green)) const;
|
||||
void HighlightElseAction(int idx,
|
||||
QColor color = QColor(Qt::green)) const;
|
||||
void HighlightCondition(int idx,
|
||||
QColor color = QColor(Qt::green)) const;
|
||||
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 SetActionData(Macro &m) const;
|
||||
void SetElseActionData(Macro &m) const;
|
||||
void SetConditionData(Macro &m) const;
|
||||
void SwapActions(Macro *m, int pos1, int pos2);
|
||||
void SwapConditions(Macro *m, int pos1, int pos2);
|
||||
void HighligthMacroSettingsButton(bool enable = true);
|
||||
void HighlightMacroSettingsButton(bool enable = true);
|
||||
|
||||
public slots:
|
||||
void on_macroAdd_clicked();
|
||||
void on_macroRemove_clicked();
|
||||
void on_macroUp_clicked();
|
||||
void on_macroDown_clicked();
|
||||
void on_macroUp_clicked() const;
|
||||
void on_macroDown_clicked() const;
|
||||
void on_macroName_editingFinished();
|
||||
void on_runMacroInParallel_stateChanged(int value);
|
||||
void on_runMacroOnChange_stateChanged(int value);
|
||||
void on_conditionAdd_clicked();
|
||||
void on_conditionRemove_clicked();
|
||||
void on_conditionTop_clicked();
|
||||
void on_conditionUp_clicked();
|
||||
void on_conditionDown_clicked();
|
||||
void on_conditionBottom_clicked();
|
||||
void on_actionAdd_clicked();
|
||||
void on_actionRemove_clicked();
|
||||
void on_actionTop_clicked();
|
||||
void on_actionUp_clicked();
|
||||
void on_actionDown_clicked();
|
||||
void on_actionBottom_clicked();
|
||||
void on_toggleElseActions_clicked();
|
||||
void on_elseActionAdd_clicked();
|
||||
void on_elseActionRemove_clicked();
|
||||
void on_elseActionTop_clicked();
|
||||
void on_elseActionUp_clicked();
|
||||
void on_elseActionDown_clicked();
|
||||
void on_elseActionBottom_clicked();
|
||||
void MacroSelectionAboutToChange();
|
||||
void on_runMacroInParallel_stateChanged(int value) const;
|
||||
void on_actionTriggerMode_currentIndexChanged(int index) const;
|
||||
void MacroSelectionChanged();
|
||||
void UpMacroSegementHotkey();
|
||||
void DownMacroSegementHotkey();
|
||||
void DeleteMacroSegementHotkey();
|
||||
void ShowMacroContextMenu(const QPoint &);
|
||||
void ShowMacroActionsContextMenu(const QPoint &);
|
||||
void ShowMacroElseActionsContextMenu(const QPoint &);
|
||||
void ShowMacroConditionsContextMenu(const QPoint &);
|
||||
void CopyMacro();
|
||||
void RenameSelectedMacro();
|
||||
void ExportMacros();
|
||||
void ExportMacros() const;
|
||||
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(Macro *macro, int idx, const std::string &id,
|
||||
obs_data_t *data);
|
||||
void AddMacroAction(int idx);
|
||||
void RemoveMacroAction(int idx);
|
||||
void MoveMacroActionUp(int idx);
|
||||
void MoveMacroActionDown(int idx);
|
||||
void MacroElseActionSelectionChanged(int idx);
|
||||
void MacroElseActionReorder(int to, int target);
|
||||
void AddMacroElseAction(Macro *macro, int idx, const std::string &id,
|
||||
obs_data_t *data);
|
||||
void AddMacroElseAction(int idx);
|
||||
void RemoveMacroElseAction(int idx);
|
||||
void SwapElseActions(Macro *m, int pos1, int pos2);
|
||||
void MoveMacroElseActionUp(int idx);
|
||||
void MoveMacroElseActionDown(int idx);
|
||||
void MacroConditionSelectionChanged(int idx);
|
||||
void MacroConditionReorder(int to, int target);
|
||||
void AddMacroCondition(int idx);
|
||||
void AddMacroCondition(Macro *macro, int idx, const std::string &id,
|
||||
obs_data_t *data, Logic::Type logic);
|
||||
void RemoveMacroCondition(int idx);
|
||||
void MoveMacroConditionUp(int idx);
|
||||
void MoveMacroConditionDown(int idx);
|
||||
void HighlightControls();
|
||||
void HighlightOnChange();
|
||||
void HighlightOnChange() const;
|
||||
void on_macroSettings_clicked();
|
||||
void CopyMacroSegment();
|
||||
void PasteMacroSegment();
|
||||
|
||||
signals:
|
||||
void MacroAdded(const QString &name);
|
||||
void MacroRemoved(const QString &name);
|
||||
void MacroRenamed(const QString &oldName, const QString &newName);
|
||||
void MacroSegmentOrderChanged();
|
||||
void SegmentTempVarsChanged();
|
||||
void HighlightMacrosChanged(bool value);
|
||||
|
||||
void ConnectionAdded(const QString &);
|
||||
void ConnectionRenamed(const QString &oldName, const QString &newName);
|
||||
void ConnectionRemoved(const QString &);
|
||||
|
||||
private:
|
||||
enum class MacroSection { CONDITIONS, ACTIONS, ELSE_ACTIONS };
|
||||
|
||||
void SetupMacroSegmentSelection(MacroSection type, int idx);
|
||||
bool ResolveMacroImportNameConflict(std::shared_ptr<Macro> &);
|
||||
bool MacroTabIsInFocus();
|
||||
|
||||
MacroSection lastInteracted = MacroSection::CONDITIONS;
|
||||
int currentConditionIdx = -1;
|
||||
int currentActionIdx = -1;
|
||||
int currentElseActionIdx = -1;
|
||||
|
||||
/* --- End of macro tab section --- */
|
||||
|
||||
|
|
@ -386,6 +299,6 @@ private:
|
|||
};
|
||||
|
||||
void OpenSettingsWindow();
|
||||
void HighligthMacroSettingsButton(bool enable);
|
||||
void HighlightMacroSettingsButton(bool enable);
|
||||
|
||||
} // namespace advss
|
||||
|
|
|
|||
291
lib/general.cpp
291
lib/general.cpp
|
|
@ -1,17 +1,18 @@
|
|||
#include "advanced-scene-switcher.hpp"
|
||||
#include "file-selection.hpp"
|
||||
#include "filter-combo-box.hpp"
|
||||
#include "first-run-wizard.hpp"
|
||||
#include "layout-helpers.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "macro-search.hpp"
|
||||
#include "macro-settings.hpp"
|
||||
#include "path-helpers.hpp"
|
||||
#include "selection-helpers.hpp"
|
||||
#include "source-helpers.hpp"
|
||||
#include "splitter-helpers.hpp"
|
||||
#include "status-control.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "tab-helpers.hpp"
|
||||
#include "ui-helpers.hpp"
|
||||
#include "utility.hpp"
|
||||
#include "variable.hpp"
|
||||
#include "version.h"
|
||||
|
||||
|
|
@ -25,15 +26,6 @@ void AdvSceneSwitcher::reject()
|
|||
close();
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::UpdateNonMatchingScene(const QString &name)
|
||||
{
|
||||
OBSSourceAutoRelease scene =
|
||||
obs_get_source_by_name(name.toUtf8().constData());
|
||||
OBSWeakSourceAutoRelease ws = obs_source_get_weak_source(scene);
|
||||
|
||||
switcher->nonMatchingScene = ws;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_noMatchDontSwitch_clicked()
|
||||
{
|
||||
if (loading) {
|
||||
|
|
@ -55,7 +47,6 @@ void AdvSceneSwitcher::on_noMatchSwitch_clicked()
|
|||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->switchIfNotMatching = NoMatchBehavior::SWITCH;
|
||||
ui->noMatchSwitchScene->setEnabled(true);
|
||||
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
|
||||
ui->randomDisabledWarning->setVisible(true);
|
||||
}
|
||||
|
||||
|
|
@ -113,12 +104,12 @@ void AdvSceneSwitcher::on_startupBehavior_currentIndexChanged(int index)
|
|||
static_cast<SwitcherData::StartupBehavior>(index);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_logLevel_currentIndexChanged(int value)
|
||||
void AdvSceneSwitcher::on_logLevel_currentIndexChanged(int idx)
|
||||
{
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
switcher->logLevel = static_cast<SwitcherData::LogLevel>(value);
|
||||
SetLogLevel(static_cast<LogLevel>(ui->logLevel->itemData(idx).toInt()));
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_autoStartEvent_currentIndexChanged(int index)
|
||||
|
|
@ -131,17 +122,6 @@ void AdvSceneSwitcher::on_autoStartEvent_currentIndexChanged(int index)
|
|||
switcher->autoStartEvent = static_cast<SwitcherData::AutoStart>(index);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_noMatchSwitchScene_currentTextChanged(
|
||||
const QString &text)
|
||||
{
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
UpdateNonMatchingScene(text);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_checkInterval_valueChanged(int value)
|
||||
{
|
||||
if (loading) {
|
||||
|
|
@ -163,7 +143,7 @@ void AdvSceneSwitcher::closeEvent(QCloseEvent *)
|
|||
switcher->windowSize = this->size();
|
||||
switcher->macroListMacroEditSplitterPosition =
|
||||
ui->macroListMacroEditSplitter->sizes();
|
||||
MacroSelectionAboutToChange(); // Trigger saving of splitter states
|
||||
ui->macroEdit->SetMacro(nullptr); // Trigger saving of splitter states
|
||||
|
||||
obs_frontend_save();
|
||||
}
|
||||
|
|
@ -275,12 +255,15 @@ static bool containsSensitiveData(obs_data_t *data)
|
|||
obs_data_get_array(data, "twitchConnections");
|
||||
OBSDataArrayAutoRelease websocketConnections =
|
||||
obs_data_get_array(data, "websocketConnections");
|
||||
OBSDataArrayAutoRelease mqttConnections =
|
||||
obs_data_get_array(data, "mqttConnections");
|
||||
|
||||
auto isNotEmpty = [](obs_data_array *array) {
|
||||
return obs_data_array_count(array) > 0;
|
||||
};
|
||||
|
||||
return isNotEmpty(twitchTokens) || isNotEmpty(websocketConnections);
|
||||
return isNotEmpty(twitchTokens) || isNotEmpty(websocketConnections) ||
|
||||
isNotEmpty(mqttConnections);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_exportSettings_clicked()
|
||||
|
|
@ -344,6 +327,10 @@ void AdvSceneSwitcher::on_importSettings_clicked()
|
|||
return;
|
||||
}
|
||||
|
||||
// We have to make sure to that no macro is currently being edited while
|
||||
// the new settings are loaded
|
||||
ui->macros->clearSelection();
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->LoadSettings(obj);
|
||||
switcher->lastImportPath = path.toStdString();
|
||||
|
|
@ -373,13 +360,46 @@ void AdvSceneSwitcher::RestoreWindowGeo()
|
|||
}
|
||||
}
|
||||
|
||||
static void renameMacroIfNecessary(const std::shared_ptr<Macro> ¯o)
|
||||
{
|
||||
if (!GetMacroByName(macro->Name().c_str())) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto name = macro->Name();
|
||||
int i = 2;
|
||||
while (GetMacroByName((name + " " + std::to_string(i)).c_str())) {
|
||||
i++;
|
||||
}
|
||||
|
||||
macro->SetName(name + " " + std::to_string(i));
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::CheckFirstTimeSetup()
|
||||
{
|
||||
if (switcher->firstBoot && !switcher->disableHints) {
|
||||
switcher->firstBoot = false;
|
||||
DisplayMessage(
|
||||
obs_module_text("AdvSceneSwitcher.firstBootMessage"));
|
||||
if (!IsFirstRun() || !GetTopLevelMacros().empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto macro = FirstRunWizard::ShowWizard(this);
|
||||
if (macro) {
|
||||
renameMacroIfNecessary(macro);
|
||||
QTimer::singleShot(0, this,
|
||||
[this, macro]() { ui->macros->Add(macro); });
|
||||
}
|
||||
switcher->Start();
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_openSetupWizard_clicked()
|
||||
{
|
||||
auto macro = FirstRunWizard::ShowWizard(this);
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
renameMacroIfNecessary(macro);
|
||||
ui->macros->Add(macro);
|
||||
ui->tabWidget->setCurrentWidget(ui->macroTab);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_tabWidget_currentChanged(int)
|
||||
|
|
@ -433,16 +453,14 @@ void SwitcherData::LoadSettings(obs_data_t *obj)
|
|||
}
|
||||
|
||||
// New post load steps to be declared during load
|
||||
postLoadSteps.clear();
|
||||
ClearPostLoadSteps();
|
||||
|
||||
// Needs to be loaded before any entries which might rely on scene group
|
||||
// selections to be available.
|
||||
loadSceneGroups(obj);
|
||||
LoadVariables(obj);
|
||||
|
||||
for (const auto &func : loadSteps) {
|
||||
func(obj);
|
||||
}
|
||||
RunLoadSteps(obj);
|
||||
|
||||
LoadMacros(obj);
|
||||
LoadGlobalMacroSettings(obj);
|
||||
|
|
@ -463,7 +481,7 @@ void SwitcherData::LoadSettings(obs_data_t *obj)
|
|||
LoadHotkeys(obj);
|
||||
LoadUISettings(obj);
|
||||
|
||||
RunPostLoadSteps();
|
||||
RunAndClearPostLoadSteps();
|
||||
|
||||
// Reset on startup and scene collection change
|
||||
ResetLastOpenedTab();
|
||||
|
|
@ -498,18 +516,16 @@ void SwitcherData::SaveSettings(obs_data_t *obj)
|
|||
SaveUISettings(obj);
|
||||
SaveVersion(obj, g_GIT_SHA1);
|
||||
|
||||
for (const auto &func : saveSteps) {
|
||||
func(obj);
|
||||
}
|
||||
RunSaveSteps(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());
|
||||
OBSDataAutoRelease noMatchScene = obs_data_create();
|
||||
nonMatchingScene.Save(noMatchScene);
|
||||
obs_data_set_obj(obj, "noMatchScene", noMatchScene);
|
||||
obs_data_set_int(obj, "switch_if_not_matching",
|
||||
static_cast<int>(switchIfNotMatching));
|
||||
noMatchDelay.Save(obj, "noMatchDelay");
|
||||
|
|
@ -517,16 +533,21 @@ void SwitcherData::SaveGeneralSettings(obs_data_t *obj)
|
|||
cooldown.Save(obj, "cooldown");
|
||||
obs_data_set_bool(obj, "enableCooldown", enableCooldown);
|
||||
|
||||
obs_data_set_bool(obj, "active", sceneColletionStop ? true : !stop);
|
||||
sceneColletionStop = false;
|
||||
obs_data_set_bool(obj, "active", sceneCollectionStop ? true : !stop);
|
||||
sceneCollectionStop = false;
|
||||
obs_data_set_int(obj, "startup_behavior",
|
||||
static_cast<int>(startupBehavior));
|
||||
|
||||
obs_data_set_int(obj, "autoStartEvent",
|
||||
static_cast<int>(autoStartEvent));
|
||||
OBSDataAutoRelease autoStart = obs_data_create();
|
||||
obs_data_set_int(autoStart, "event", static_cast<int>(autoStartEvent));
|
||||
obs_data_set_bool(autoStart, "useAutoStartScene", useAutoStartScene);
|
||||
autoStartScene.Save(autoStart);
|
||||
autoStartSceneName.Save(autoStart, "name");
|
||||
autoStartSceneRegex.Save(autoStart);
|
||||
obs_data_set_obj(obj, "autoStart", autoStart);
|
||||
|
||||
SaveLogLevel(obj);
|
||||
|
||||
obs_data_set_int(obj, "logLevel", static_cast<int>(logLevel));
|
||||
obs_data_set_int(obj, "logLevelVersion", 1);
|
||||
obs_data_set_bool(obj, "showSystemTrayNotifications",
|
||||
showSystemTrayNotifications);
|
||||
obs_data_set_bool(obj, "disableHints", disableHints);
|
||||
|
|
@ -556,9 +577,14 @@ void SwitcherData::LoadGeneralSettings(obs_data_t *obj)
|
|||
static_cast<int>(NoMatchBehavior::NO_SWITCH));
|
||||
switchIfNotMatching = static_cast<NoMatchBehavior>(
|
||||
obs_data_get_int(obj, "switch_if_not_matching"));
|
||||
std::string nonMatchingSceneName =
|
||||
obs_data_get_string(obj, "non_matching_scene");
|
||||
nonMatchingScene = GetWeakSourceByName(nonMatchingSceneName.c_str());
|
||||
|
||||
if (obs_data_has_user_value(obj, "noMatchScene")) {
|
||||
OBSDataAutoRelease noMatchScene =
|
||||
obs_data_get_obj(obj, "noMatchScene");
|
||||
nonMatchingScene.Load(noMatchScene);
|
||||
} else {
|
||||
nonMatchingScene.Load(obj, "non_matching_scene");
|
||||
}
|
||||
noMatchDelay.Load(obj, "noMatchDelay");
|
||||
|
||||
cooldown.Load(obj, "cooldown");
|
||||
|
|
@ -579,28 +605,17 @@ void SwitcherData::LoadGeneralSettings(obs_data_t *obj)
|
|||
stop = true;
|
||||
}
|
||||
|
||||
autoStartEvent =
|
||||
static_cast<AutoStart>(obs_data_get_int(obj, "autoStartEvent"));
|
||||
OBSDataAutoRelease autoStart = obs_data_get_obj(obj, "autoStart");
|
||||
autoStartEvent = static_cast<AutoStart>(
|
||||
obs_data_has_user_value(obj, "autoStart")
|
||||
? obs_data_get_int(autoStart, "event")
|
||||
: obs_data_get_int(obj, "autoStartEvent"));
|
||||
useAutoStartScene = obs_data_get_bool(autoStart, "useAutoStartScene");
|
||||
autoStartScene.Load(autoStart);
|
||||
autoStartSceneName.Load(autoStart, "name");
|
||||
autoStartSceneRegex.Load(autoStart);
|
||||
|
||||
logLevel = static_cast<LogLevel>(obs_data_get_int(obj, "logLevel"));
|
||||
if (obs_data_get_int(obj, "logLevelVersion") < 1) {
|
||||
enum OldLogLevel { DEFAULT, LOG_ACTION, VERBOSE };
|
||||
OldLogLevel oldLogLevel = static_cast<OldLogLevel>(
|
||||
obs_data_get_int(obj, "logLevel"));
|
||||
switch (oldLogLevel) {
|
||||
case DEFAULT:
|
||||
logLevel = LogLevel::DEFAULT;
|
||||
break;
|
||||
case LOG_ACTION:
|
||||
logLevel = LogLevel::LOG_ACTION;
|
||||
break;
|
||||
case VERBOSE:
|
||||
logLevel = LogLevel::VERBOSE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
LoadLogLevel(obj);
|
||||
|
||||
showSystemTrayNotifications =
|
||||
obs_data_get_bool(obj, "showSystemTrayNotifications");
|
||||
|
|
@ -676,10 +691,10 @@ void SwitcherData::CheckNoMatchSwitch(bool &match, OBSWeakSource &scene,
|
|||
return;
|
||||
}
|
||||
|
||||
if (switchIfNotMatching == NoMatchBehavior::SWITCH &&
|
||||
nonMatchingScene) {
|
||||
auto noMatchScene = nonMatchingScene.GetScene(false);
|
||||
if (switchIfNotMatching == NoMatchBehavior::SWITCH && noMatchScene) {
|
||||
match = true;
|
||||
scene = nonMatchingScene;
|
||||
scene = noMatchScene;
|
||||
transition = nullptr;
|
||||
}
|
||||
if (switchIfNotMatching == NoMatchBehavior::RANDOM_SWITCH) {
|
||||
|
|
@ -687,6 +702,27 @@ void SwitcherData::CheckNoMatchSwitch(bool &match, OBSWeakSource &scene,
|
|||
}
|
||||
}
|
||||
|
||||
void SwitcherData::CheckAutoStart()
|
||||
{
|
||||
if (!useAutoStartScene) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool shouldStartPlugin = false;
|
||||
if (autoStartSceneRegex.Enabled()) {
|
||||
const auto currentSceneName = GetWeakSourceName(currentScene);
|
||||
shouldStartPlugin = autoStartSceneRegex.Matches(
|
||||
currentSceneName, autoStartSceneName);
|
||||
} else {
|
||||
shouldStartPlugin = autoStartScene.GetScene(false) ==
|
||||
currentScene;
|
||||
}
|
||||
|
||||
if (shouldStartPlugin) {
|
||||
Start();
|
||||
}
|
||||
}
|
||||
|
||||
void SwitcherData::checkSwitchCooldown(bool &match)
|
||||
{
|
||||
if (!match || !enableCooldown) {
|
||||
|
|
@ -829,7 +865,7 @@ static void setupGeneralTabInactiveWarning(QTabWidget *tabs)
|
|||
inactiveTimer->start();
|
||||
}
|
||||
|
||||
void advss::AdvSceneSwitcher::SetCheckIntervalTooLowVisibility() const
|
||||
void AdvSceneSwitcher::SetCheckIntervalTooLowVisibility() const
|
||||
{
|
||||
auto macro = GetMacroWithInvalidConditionInterval();
|
||||
if (!macro) {
|
||||
|
|
@ -853,8 +889,6 @@ void advss::AdvSceneSwitcher::SetCheckIntervalTooLowVisibility() const
|
|||
|
||||
void AdvSceneSwitcher::SetupGeneralTab()
|
||||
{
|
||||
PopulateSceneSelection(ui->noMatchSwitchScene, false);
|
||||
|
||||
if (switcher->switchIfNotMatching == NoMatchBehavior::SWITCH) {
|
||||
ui->noMatchSwitch->setChecked(true);
|
||||
ui->noMatchSwitchScene->setEnabled(true);
|
||||
|
|
@ -866,8 +900,17 @@ void AdvSceneSwitcher::SetupGeneralTab()
|
|||
ui->noMatchRandomSwitch->setChecked(true);
|
||||
ui->noMatchSwitchScene->setEnabled(false);
|
||||
}
|
||||
ui->noMatchSwitchScene->setCurrentText(
|
||||
GetWeakSourceName(switcher->nonMatchingScene).c_str());
|
||||
ui->noMatchSwitchScene->SetScene(switcher->nonMatchingScene);
|
||||
ui->noMatchSwitchScene->LockToMainCanvas();
|
||||
|
||||
connect(ui->noMatchSwitchScene, &SceneSelectionWidget::SceneChanged,
|
||||
this, [this](const SceneSelection &scene) {
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->nonMatchingScene = scene;
|
||||
});
|
||||
|
||||
DurationSelection *noMatchDelay = new DurationSelection();
|
||||
noMatchDelay->SetDuration(switcher->noMatchDelay);
|
||||
|
|
@ -890,7 +933,9 @@ void AdvSceneSwitcher::SetupGeneralTab()
|
|||
SIGNAL(DurationChanged(const Duration &)), this,
|
||||
SLOT(CooldownDurationChanged(const Duration &)));
|
||||
|
||||
ui->logLevel->setCurrentIndex(static_cast<int>(switcher->logLevel));
|
||||
PopulateLogLevelSelection(ui->logLevel);
|
||||
ui->logLevel->setCurrentIndex(
|
||||
ui->logLevel->findData(static_cast<int>(GetLogLevel())));
|
||||
|
||||
ui->saveWindowGeo->setChecked(switcher->saveWindowGeo);
|
||||
ui->showTrayNotifications->setChecked(
|
||||
|
|
@ -913,6 +958,88 @@ void AdvSceneSwitcher::SetupGeneralTab()
|
|||
populateAutoStartEventSelection(ui->autoStartEvent);
|
||||
ui->autoStartEvent->setCurrentIndex(
|
||||
static_cast<int>(switcher->autoStartEvent));
|
||||
ui->autoStartSceneEnable->setChecked(switcher->useAutoStartScene);
|
||||
ui->autoStartScene->SetScene(switcher->autoStartScene);
|
||||
ui->autoStartScene->LockToMainCanvas();
|
||||
ui->autoStartSceneName->setText(switcher->autoStartSceneName);
|
||||
ui->autoStartSceneNameRegex->SetRegexConfig(
|
||||
switcher->autoStartSceneRegex);
|
||||
|
||||
const auto setupAutoStartSceneLayoutVisibility = [this](bool useRegex) {
|
||||
ui->autoStartSceneName->setVisible(useRegex);
|
||||
ui->autoStartScene->setVisible(!useRegex);
|
||||
if (useRegex) {
|
||||
RemoveStretchIfPresent(ui->autoStartSceneLayout);
|
||||
} else {
|
||||
AddStretchIfNecessary(ui->autoStartSceneLayout);
|
||||
}
|
||||
};
|
||||
setupAutoStartSceneLayoutVisibility(
|
||||
switcher->autoStartSceneRegex.Enabled());
|
||||
|
||||
const auto setupAutoStartSceneWidgetState =
|
||||
[this](bool useAutoStartScene) {
|
||||
ui->autoStartScene->setEnabled(useAutoStartScene);
|
||||
ui->autoStartSceneName->setEnabled(useAutoStartScene);
|
||||
ui->autoStartSceneNameRegex->setEnabled(
|
||||
useAutoStartScene);
|
||||
};
|
||||
setupAutoStartSceneWidgetState(switcher->useAutoStartScene);
|
||||
|
||||
connect(ui->autoStartSceneEnable, &QCheckBox::stateChanged, this,
|
||||
[this, setupAutoStartSceneWidgetState](int enabled) {
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->useAutoStartScene = enabled;
|
||||
setupAutoStartSceneWidgetState(enabled);
|
||||
});
|
||||
|
||||
connect(ui->autoStartScene, &SceneSelectionWidget::SceneChanged, this,
|
||||
[this](const SceneSelection &scene) {
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->autoStartScene = scene;
|
||||
switcher->CheckAutoStart();
|
||||
});
|
||||
connect(ui->autoStartSceneName, &VariableLineEdit::editingFinished,
|
||||
this, [this]() {
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->autoStartSceneName =
|
||||
ui->autoStartSceneName->text().toStdString();
|
||||
switcher->CheckAutoStart();
|
||||
});
|
||||
connect(ui->autoStartSceneNameRegex,
|
||||
&RegexConfigWidget::RegexConfigChanged, this,
|
||||
[this, setupAutoStartSceneLayoutVisibility](
|
||||
const RegexConfig ®ex) {
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->autoStartSceneRegex = regex;
|
||||
setupAutoStartSceneLayoutVisibility(regex.Enabled());
|
||||
switcher->CheckAutoStart();
|
||||
});
|
||||
|
||||
ui->alwaysShowMacroSearch->setChecked(
|
||||
GetMacroSearchSettings().showAlways);
|
||||
|
||||
connect(ui->alwaysShowMacroSearch, &QCheckBox::stateChanged, this,
|
||||
[this](int enabled) {
|
||||
GetMacroSearchSettings().showAlways = enabled;
|
||||
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
CheckMacroSearchVisibility();
|
||||
});
|
||||
|
||||
// Set up status control
|
||||
auto statusControl = new StatusControl(this, true);
|
||||
|
|
@ -933,6 +1060,8 @@ void AdvSceneSwitcher::SetupGeneralTab()
|
|||
setTabOrder(ui->importSettings, ui->cooldownTime);
|
||||
setTabOrder(ui->cooldownTime, ui->noMatchDontSwitch);
|
||||
|
||||
SetupShowAllTabsCheckBox(ui->alwaysShowFeatureTabs, ui->tabWidget);
|
||||
|
||||
MinimizeSizeOfColumn(ui->statusLayout, 0);
|
||||
setWindowTitle(windowTitle() + " - " + g_GIT_TAG);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -259,7 +259,8 @@ void AudioSwitch::setVolumeLevel(void *data, const float *,
|
|||
}
|
||||
}
|
||||
|
||||
obs_volmeter_t *AddVolmeterToSource(AudioSwitch *entry, obs_weak_source *source)
|
||||
static obs_volmeter_t *addVolmeterToSource(AudioSwitch *entry,
|
||||
obs_weak_source *source)
|
||||
{
|
||||
obs_volmeter_t *volmeter = obs_volmeter_create(OBS_FADER_LOG);
|
||||
obs_volmeter_add_callback(volmeter, AudioSwitch::setVolumeLevel, entry);
|
||||
|
|
@ -279,7 +280,7 @@ void AudioSwitch::resetVolmeter()
|
|||
obs_volmeter_remove_callback(volmeter, setVolumeLevel, this);
|
||||
obs_volmeter_destroy(volmeter);
|
||||
|
||||
volmeter = AddVolmeterToSource(this, audioSource);
|
||||
volmeter = addVolmeterToSource(this, audioSource);
|
||||
}
|
||||
|
||||
bool AudioSwitch::initialized()
|
||||
|
|
@ -318,7 +319,7 @@ void AudioSwitch::load(obs_data_t *obj)
|
|||
duration.Load(obj, "duration");
|
||||
ignoreInactiveSource = obs_data_get_bool(obj, "ignoreInactiveSource");
|
||||
|
||||
volmeter = AddVolmeterToSource(this, audioSource);
|
||||
volmeter = addVolmeterToSource(this, audioSource);
|
||||
}
|
||||
|
||||
void AudioSwitchFallback::save(obs_data_t *obj)
|
||||
|
|
@ -349,7 +350,7 @@ AudioSwitch::AudioSwitch(const AudioSwitch &other)
|
|||
condition(other.condition),
|
||||
duration(other.duration)
|
||||
{
|
||||
volmeter = AddVolmeterToSource(this, other.audioSource);
|
||||
volmeter = addVolmeterToSource(this, other.audioSource);
|
||||
}
|
||||
|
||||
AudioSwitch::AudioSwitch(AudioSwitch &&other) noexcept
|
||||
|
|
|
|||
|
|
@ -21,6 +21,29 @@ bool FileSwitch::pause = false;
|
|||
static QObject *addPulse = nullptr;
|
||||
static std::hash<std::string> strHash;
|
||||
|
||||
static void writeToStatusFile(const QString &msg)
|
||||
{
|
||||
if (!GetSwitcher() || !GetSwitcher()->fileIO.writeEnabled ||
|
||||
GetSwitcher()->fileIO.writePath.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QFile file(QString::fromStdString(GetSwitcher()->fileIO.writePath));
|
||||
if (file.open(QIODevice::ReadWrite)) {
|
||||
QTextStream stream(&file);
|
||||
stream << msg << Qt::endl;
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
static bool _ = []() {
|
||||
AddStartStep(
|
||||
[]() { writeToStatusFile("Advanced Scene Switcher running"); });
|
||||
AddStopStep(
|
||||
[]() { writeToStatusFile("Advanced Scene Switcher stopped"); });
|
||||
return true;
|
||||
}();
|
||||
|
||||
void AdvSceneSwitcher::on_browseButton_clicked()
|
||||
{
|
||||
QString path = QFileDialog::getOpenFileName(
|
||||
|
|
@ -113,24 +136,6 @@ void SwitcherData::writeSceneInfoToFile()
|
|||
}
|
||||
}
|
||||
|
||||
void SwitcherData::writeToStatusFile(const QString &msg)
|
||||
{
|
||||
if (!fileIO.writeEnabled || fileIO.writePath.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QFile file(QString::fromStdString(fileIO.writePath));
|
||||
if (file.open(QIODevice::ReadWrite)) {
|
||||
QTextStream stream(&file);
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
stream << msg << "\n";
|
||||
#else
|
||||
stream << msg << Qt::endl;
|
||||
#endif
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
bool SwitcherData::checkSwitchInfoFromFile(OBSWeakSource &scene,
|
||||
OBSWeakSource &transition)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#endif
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include "kwin-helpers.h"
|
||||
|
||||
namespace advss {
|
||||
|
||||
|
|
@ -44,6 +45,10 @@ static XScreenSaverAllocInfoFunc allocSSFunc = nullptr;
|
|||
static XScreenSaverQueryInfoFunc querySSFunc = nullptr;
|
||||
bool canGetIdleTime = false;
|
||||
|
||||
static bool KWin = false;
|
||||
static FocusNotifier notifier;
|
||||
static QString KWinScriptObjectPath;
|
||||
|
||||
static QLibrary *libprocps = nullptr;
|
||||
#ifdef PROCPS_AVAILABLE
|
||||
typedef PROCTAB *(*openproc_func)(int flags);
|
||||
|
|
@ -275,6 +280,11 @@ int getActiveWindow(Window *&window)
|
|||
|
||||
void GetCurrentWindowTitle(std::string &title)
|
||||
{
|
||||
if (KWin) {
|
||||
title = FocusNotifier::getActiveWindowTitle();
|
||||
return;
|
||||
}
|
||||
|
||||
Window *data = 0;
|
||||
if (getActiveWindow(data) != Success || !data) {
|
||||
return;
|
||||
|
|
@ -286,6 +296,7 @@ void GetCurrentWindowTitle(std::string &title)
|
|||
|
||||
auto name = getWindowName(data[0]);
|
||||
XFree(data);
|
||||
|
||||
if (name.empty()) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -384,7 +395,11 @@ static void getProcessListProcps2(QStringList &processes)
|
|||
return;
|
||||
}
|
||||
while ((stack = procps_pids_get_(info, PIDS_FETCH_TASKS_ONLY))) {
|
||||
#ifdef PROCPS2_USE_INFO
|
||||
auto cmd = PIDS_VAL(0, str, stack, info);
|
||||
#else
|
||||
auto cmd = PIDS_VAL(0, str, stack);
|
||||
#endif
|
||||
QString procName(cmd);
|
||||
if (!procName.isEmpty() && !processes.contains(procName)) {
|
||||
processes << procName;
|
||||
|
|
@ -408,6 +423,10 @@ void GetProcessList(QStringList &processes)
|
|||
|
||||
long getForegroundProcessPid()
|
||||
{
|
||||
if (KWin) {
|
||||
return FocusNotifier::getActiveWindowPID();
|
||||
}
|
||||
|
||||
Window *window;
|
||||
if (getActiveWindow(window) != Success || !window || !*window) {
|
||||
return -1;
|
||||
|
|
@ -433,6 +452,7 @@ long getForegroundProcessPid()
|
|||
|
||||
pid = *((long *)prop);
|
||||
XFree(prop);
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
|
|
@ -546,6 +566,11 @@ static void initProc2()
|
|||
#endif
|
||||
}
|
||||
|
||||
int ignoreXerror(Display *d, XErrorEvent *e)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PlatformInit()
|
||||
{
|
||||
auto display = disp();
|
||||
|
|
@ -553,9 +578,21 @@ void PlatformInit()
|
|||
return;
|
||||
}
|
||||
|
||||
KWin = isKWinAvailable();
|
||||
if (!(KWin && startKWinScript(KWinScriptObjectPath) &&
|
||||
registerKWinDBusListener(¬ifier))) {
|
||||
// something bad happened while trying to initialize
|
||||
// the KWin script/dbus so disable it
|
||||
KWin = false;
|
||||
blog(LOG_INFO, "not using KWin compat");
|
||||
} else {
|
||||
blog(LOG_INFO, "using KWin compat");
|
||||
}
|
||||
|
||||
initXss();
|
||||
initProcps();
|
||||
initProc2();
|
||||
XSetErrorHandler(ignoreXerror);
|
||||
}
|
||||
|
||||
static void cleanupHelper(QLibrary *lib)
|
||||
|
|
@ -572,6 +609,9 @@ void PlatformCleanup()
|
|||
cleanupHelper(libprocps);
|
||||
cleanupHelper(libproc2);
|
||||
cleanupDisplay();
|
||||
XSetErrorHandler(NULL);
|
||||
if (KWin && !KWinScriptObjectPath.isEmpty())
|
||||
stopKWinScript(KWinScriptObjectPath);
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
|
|
|||
166
lib/linux/kwin-helpers.cpp
Normal file
166
lib/linux/kwin-helpers.cpp
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
#include "kwin-helpers.h"
|
||||
|
||||
#include "log-helper.hpp"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileDevice>
|
||||
#include <QTextStream>
|
||||
#include <QtDBus/QDBusConnectionInterface>
|
||||
#include <QtDBus/QDBusInterface>
|
||||
#include <QtDBus/QDBusReply>
|
||||
|
||||
namespace advss {
|
||||
|
||||
int FocusNotifier::activePID = -1;
|
||||
std::string FocusNotifier::activeTitle = {};
|
||||
|
||||
int FocusNotifier::getActiveWindowPID()
|
||||
{
|
||||
return activePID;
|
||||
}
|
||||
|
||||
std::string FocusNotifier::getActiveWindowTitle()
|
||||
{
|
||||
return activeTitle;
|
||||
}
|
||||
|
||||
void FocusNotifier::focusChanged(const int pid)
|
||||
{
|
||||
activePID = pid;
|
||||
}
|
||||
|
||||
void FocusNotifier::focusTitle(const QString &title)
|
||||
{
|
||||
activeTitle = title.toStdString();
|
||||
}
|
||||
|
||||
bool isKWinAvailable()
|
||||
{
|
||||
const QDBusConnectionInterface *interface =
|
||||
QDBusConnection::sessionBus().interface();
|
||||
if (!interface)
|
||||
return false;
|
||||
|
||||
const QStringList services =
|
||||
interface->registeredServiceNames().value();
|
||||
return services.contains("org.kde.KWin");
|
||||
}
|
||||
|
||||
bool startKWinScript(QString &scriptObjectPath)
|
||||
{
|
||||
const QString scriptPath =
|
||||
"/tmp/AdvancedSceneSwitcher/KWinFocusNotifier.js";
|
||||
|
||||
const QString script =
|
||||
R"(workspace.windowActivated.connect(function(client) {
|
||||
if (!client) return;
|
||||
if (!client.pid) return;
|
||||
if (!client.caption) return;
|
||||
|
||||
callDBus(
|
||||
"com.github.AdvancedSceneSwitcher",
|
||||
"/com/github/AdvancedSceneSwitcher",
|
||||
"com.github.AdvancedSceneSwitcher",
|
||||
"focusChanged",
|
||||
client.pid
|
||||
);
|
||||
callDBus(
|
||||
"com.github.AdvancedSceneSwitcher",
|
||||
"/com/github/AdvancedSceneSwitcher",
|
||||
"com.github.AdvancedSceneSwitcher",
|
||||
"focusTitle",
|
||||
client.caption
|
||||
);
|
||||
}))";
|
||||
|
||||
if (const QDir dir; !dir.mkpath(QFileInfo(scriptPath).absolutePath())) {
|
||||
blog(LOG_ERROR, "error creating /tmp/AdvancedSceneSwitcher");
|
||||
return false;
|
||||
}
|
||||
|
||||
QFile scriptFile(scriptPath);
|
||||
if (!scriptFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
blog(LOG_ERROR,
|
||||
"error opening KWinFocusNotifier.js for writing");
|
||||
return false;
|
||||
}
|
||||
|
||||
scriptFile.setPermissions(QFileDevice::ReadOwner |
|
||||
QFileDevice::WriteOwner);
|
||||
QTextStream outputStream(&scriptFile);
|
||||
outputStream << script;
|
||||
scriptFile.close();
|
||||
|
||||
const QDBusConnection bus = QDBusConnection::sessionBus();
|
||||
|
||||
QDBusInterface scriptingIface("org.kde.KWin", "/Scripting",
|
||||
"org.kde.kwin.Scripting", bus);
|
||||
if (!scriptingIface.isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const QDBusReply<bool> scriptRunningReply =
|
||||
scriptingIface.call("isScriptLoaded", scriptPath);
|
||||
if (scriptRunningReply.isValid() && scriptRunningReply.value()) {
|
||||
// script already registered and running, don't do it again
|
||||
// this will leave the script running since we do not have
|
||||
// a valid script id anymore, but at the very least this prevents
|
||||
// it from running multiple times
|
||||
return true;
|
||||
}
|
||||
|
||||
const QDBusReply<int> scriptIdReply =
|
||||
scriptingIface.call("loadScript", scriptPath);
|
||||
if (!scriptIdReply.isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int scriptId = scriptIdReply.value();
|
||||
scriptObjectPath =
|
||||
QString("/Scripting/Script%1").arg(QString::number(scriptId));
|
||||
|
||||
QDBusInterface scriptRunner("org.kde.KWin", scriptObjectPath,
|
||||
"org.kde.kwin.Script", bus);
|
||||
if (!scriptRunner.isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const QDBusReply<void> runReply = scriptRunner.call("run");
|
||||
return runReply.isValid();
|
||||
}
|
||||
|
||||
bool stopKWinScript(const QString &scriptObjectPath)
|
||||
{
|
||||
QDBusInterface scriptRunner("org.kde.KWin", scriptObjectPath,
|
||||
"org.kde.kwin.Script",
|
||||
QDBusConnection::sessionBus());
|
||||
if (!scriptRunner.isValid()) {
|
||||
return false;
|
||||
}
|
||||
const QDBusReply<void> stopReply = scriptRunner.call("stop");
|
||||
return stopReply.isValid();
|
||||
}
|
||||
|
||||
bool registerKWinDBusListener(FocusNotifier *notifier)
|
||||
{
|
||||
static const QString serviceName = "com.github.AdvancedSceneSwitcher";
|
||||
static const QString objectPath = "/com/github/AdvancedSceneSwitcher";
|
||||
auto bus = QDBusConnection::sessionBus();
|
||||
|
||||
if (bus.objectRegisteredAt(objectPath)) {
|
||||
// already registered?
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!bus.registerService(serviceName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bus.registerObject(objectPath, notifier,
|
||||
QDBusConnection::ExportAllSlots)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace advss
|
||||
33
lib/linux/kwin-helpers.h
Normal file
33
lib/linux/kwin-helpers.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <string>
|
||||
|
||||
namespace advss {
|
||||
|
||||
class FocusNotifier final : public QObject {
|
||||
Q_OBJECT
|
||||
Q_CLASSINFO("D-Bus Interface", "com.github.AdvancedSceneSwitcher")
|
||||
|
||||
static int activePID;
|
||||
static std::string activeTitle;
|
||||
|
||||
public:
|
||||
using QObject::QObject;
|
||||
|
||||
static int getActiveWindowPID();
|
||||
static std::string getActiveWindowTitle();
|
||||
|
||||
public slots:
|
||||
void focusChanged(const int pid);
|
||||
void focusTitle(const QString &title);
|
||||
};
|
||||
|
||||
bool isKWinAvailable();
|
||||
bool startKWinScript(QString &scriptObjectPath);
|
||||
bool stopKWinScript(const QString &scriptObjectPath);
|
||||
bool registerKWinDBusListener(FocusNotifier *notifier);
|
||||
void printDBusError();
|
||||
|
||||
} // namespace advss
|
||||
|
|
@ -7,8 +7,6 @@
|
|||
#include "section.hpp"
|
||||
#include "switch-button.hpp"
|
||||
|
||||
#include <QGraphicsOpacityEffect>
|
||||
|
||||
namespace advss {
|
||||
|
||||
static inline void populateActionSelection(QComboBox *list)
|
||||
|
|
@ -17,6 +15,9 @@ static inline void populateActionSelection(QComboBox *list)
|
|||
QString entry(obs_module_text(action._name.c_str()));
|
||||
if (list->findText(entry) == -1) {
|
||||
list->addItem(entry);
|
||||
qobject_cast<QListView *>(list->view())
|
||||
->setRowHidden(list->count() - 1,
|
||||
action._hidden);
|
||||
} else {
|
||||
blog(LOG_WARNING,
|
||||
"did not insert duplicate action entry with name \"%s\"",
|
||||
|
|
@ -27,19 +28,20 @@ static inline void populateActionSelection(QComboBox *list)
|
|||
}
|
||||
|
||||
MacroActionEdit::MacroActionEdit(QWidget *parent,
|
||||
std::shared_ptr<MacroAction> *entryData,
|
||||
const std::string &id)
|
||||
std::shared_ptr<MacroAction> *entryData)
|
||||
: MacroSegmentEdit(parent),
|
||||
_actionSelection(new FilterComboBox()),
|
||||
_enable(new SwitchButton()),
|
||||
_entryData(entryData)
|
||||
{
|
||||
auto actionStateTimer = new QTimer(this);
|
||||
|
||||
QWidget::connect(_actionSelection,
|
||||
SIGNAL(currentTextChanged(const QString &)), this,
|
||||
SLOT(ActionSelectionChanged(const QString &)));
|
||||
QWidget::connect(_enable, SIGNAL(checked(bool)), this,
|
||||
SLOT(ActionEnableChanged(bool)));
|
||||
QWidget::connect(&_actionStateTimer, SIGNAL(timeout()), this,
|
||||
QWidget::connect(actionStateTimer, SIGNAL(timeout()), this,
|
||||
SLOT(UpdateActionState()));
|
||||
|
||||
populateActionSelection(_actionSelection);
|
||||
|
|
@ -60,12 +62,40 @@ MacroActionEdit::MacroActionEdit(QWidget *parent,
|
|||
setLayout(mainLayout);
|
||||
|
||||
_entryData = entryData;
|
||||
UpdateEntryData(id);
|
||||
SetupWidgets(true);
|
||||
|
||||
_actionStateTimer.start(300);
|
||||
actionStateTimer->start(300);
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
void MacroActionEdit::SetupWidgets(bool basicSetup)
|
||||
{
|
||||
if (_allWidgetsAreSetup) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto id = (*_entryData)->GetId();
|
||||
_actionSelection->setCurrentText(
|
||||
obs_module_text(MacroActionFactory::GetActionName(id).c_str()));
|
||||
const bool enabled = (*_entryData)->Enabled();
|
||||
_enable->setChecked(enabled);
|
||||
SetDisableEffect(!enabled);
|
||||
HeaderInfoChanged(
|
||||
QString::fromStdString((*_entryData)->GetShortDesc()));
|
||||
|
||||
if (basicSetup) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
|
||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||
this, SLOT(HeaderInfoChanged(const QString &)));
|
||||
_section->SetContent(widget, (*_entryData)->GetCollapsed());
|
||||
SetFocusPolicyOfWidgets();
|
||||
|
||||
_allWidgetsAreSetup = true;
|
||||
}
|
||||
|
||||
void MacroActionEdit::ActionSelectionChanged(const QString &text)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
|
|
@ -86,7 +116,7 @@ void MacroActionEdit::ActionSelectionChanged(const QString &text)
|
|||
*_entryData = MacroActionFactory::Create(id, macro);
|
||||
(*_entryData)->SetIndex(idx);
|
||||
(*_entryData)->PostLoad();
|
||||
RunPostLoadSteps();
|
||||
RunAndClearPostLoadSteps();
|
||||
}
|
||||
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
|
||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||
|
|
@ -95,38 +125,11 @@ void MacroActionEdit::ActionSelectionChanged(const QString &text)
|
|||
SetFocusPolicyOfWidgets();
|
||||
}
|
||||
|
||||
void MacroActionEdit::UpdateEntryData(const std::string &id)
|
||||
{
|
||||
_actionSelection->setCurrentText(
|
||||
obs_module_text(MacroActionFactory::GetActionName(id).c_str()));
|
||||
const bool enabled = (*_entryData)->Enabled();
|
||||
_enable->setChecked(enabled);
|
||||
SetDisableEffect(!enabled);
|
||||
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
|
||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||
this, SLOT(HeaderInfoChanged(const QString &)));
|
||||
HeaderInfoChanged(
|
||||
QString::fromStdString((*_entryData)->GetShortDesc()));
|
||||
_section->SetContent(widget, (*_entryData)->GetCollapsed());
|
||||
SetFocusPolicyOfWidgets();
|
||||
}
|
||||
|
||||
void MacroActionEdit::SetEntryData(std::shared_ptr<MacroAction> *data)
|
||||
{
|
||||
_entryData = data;
|
||||
}
|
||||
|
||||
void MacroActionEdit::SetDisableEffect(bool value)
|
||||
{
|
||||
if (value) {
|
||||
auto effect = new QGraphicsOpacityEffect(this);
|
||||
effect->setOpacity(0.5);
|
||||
_section->setGraphicsEffect(effect);
|
||||
} else {
|
||||
_section->setGraphicsEffect(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroActionEdit::ActionEnableChanged(bool value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
|
|
@ -144,13 +147,9 @@ void MacroActionEdit::UpdateActionState()
|
|||
return;
|
||||
}
|
||||
|
||||
SetEnableAppearance((*_entryData)->Enabled());
|
||||
}
|
||||
|
||||
void MacroActionEdit::SetEnableAppearance(bool value)
|
||||
{
|
||||
_enable->setChecked(value);
|
||||
SetDisableEffect(!value);
|
||||
const bool enabled = (*_entryData)->Enabled();
|
||||
SetEnableAppearance(enabled);
|
||||
_enable->setChecked(enabled);
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroSegment> MacroActionEdit::Data() const
|
||||
|
|
@ -158,473 +157,4 @@ std::shared_ptr<MacroSegment> MacroActionEdit::Data() const
|
|||
return *_entryData;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::AddMacroAction(Macro *macro, int idx,
|
||||
const std::string &id, obs_data_t *data)
|
||||
{
|
||||
if (idx < 0 || idx > (int)macro->Actions().size()) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
auto lock = LockContext();
|
||||
macro->Actions().emplace(macro->Actions().begin() + idx,
|
||||
MacroActionFactory::Create(id, macro));
|
||||
if (data) {
|
||||
macro->Actions().at(idx)->Load(data);
|
||||
}
|
||||
macro->Actions().at(idx)->PostLoad();
|
||||
RunPostLoadSteps();
|
||||
macro->UpdateActionIndices();
|
||||
ui->actionsList->Insert(
|
||||
idx,
|
||||
new MacroActionEdit(this, ¯o->Actions()[idx], id));
|
||||
SetActionData(*macro);
|
||||
}
|
||||
HighlightAction(idx);
|
||||
ui->actionsList->SetHelpMsgVisible(false);
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::AddMacroAction(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 0 || idx > (int)macro->Actions().size()) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string id;
|
||||
if (idx - 1 >= 0) {
|
||||
id = macro->Actions().at(idx - 1)->GetId();
|
||||
} else {
|
||||
id = MacroAction::GetDefaultID();
|
||||
}
|
||||
|
||||
OBSDataAutoRelease data;
|
||||
if (idx - 1 >= 0) {
|
||||
data = obs_data_create();
|
||||
macro->Actions().at(idx - 1)->Save(data);
|
||||
}
|
||||
AddMacroAction(macro.get(), idx, id, data);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_actionAdd_clicked()
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentActionIdx == -1) {
|
||||
AddMacroAction((int)macro->Actions().size());
|
||||
} else {
|
||||
AddMacroAction(currentActionIdx + 1);
|
||||
}
|
||||
if (currentActionIdx != -1) {
|
||||
MacroActionSelectionChanged(currentActionIdx + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::RemoveMacroAction(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 0 || idx >= (int)macro->Actions().size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
auto lock = LockContext();
|
||||
ui->actionsList->Remove(idx);
|
||||
macro->Actions().erase(macro->Actions().begin() + idx);
|
||||
SetMacroAbortWait(true);
|
||||
GetMacroWaitCV().notify_all();
|
||||
macro->UpdateActionIndices();
|
||||
SetActionData(*macro);
|
||||
}
|
||||
MacroActionSelectionChanged(-1);
|
||||
lastInteracted = MacroSection::ACTIONS;
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_actionRemove_clicked()
|
||||
{
|
||||
if (currentActionIdx == -1) {
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
RemoveMacroAction((int)macro->Actions().size() - 1);
|
||||
} else {
|
||||
RemoveMacroAction(currentActionIdx);
|
||||
}
|
||||
MacroActionSelectionChanged(-1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_actionTop_clicked()
|
||||
{
|
||||
if (currentActionIdx == -1) {
|
||||
return;
|
||||
}
|
||||
MacroActionReorder(0, currentActionIdx);
|
||||
MacroActionSelectionChanged(0);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_actionUp_clicked()
|
||||
{
|
||||
if (currentActionIdx == -1 || currentActionIdx == 0) {
|
||||
return;
|
||||
}
|
||||
MoveMacroActionUp(currentActionIdx);
|
||||
MacroActionSelectionChanged(currentActionIdx - 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_actionDown_clicked()
|
||||
{
|
||||
if (currentActionIdx == -1 ||
|
||||
currentActionIdx == ui->actionsList->ContentLayout()->count() - 1) {
|
||||
return;
|
||||
}
|
||||
MoveMacroActionDown(currentActionIdx);
|
||||
MacroActionSelectionChanged(currentActionIdx + 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_actionBottom_clicked()
|
||||
{
|
||||
if (currentActionIdx == -1) {
|
||||
return;
|
||||
}
|
||||
const int newIdx = ui->actionsList->ContentLayout()->count() - 1;
|
||||
MacroActionReorder(newIdx, currentActionIdx);
|
||||
MacroActionSelectionChanged(newIdx);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_elseActionAdd_clicked()
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentElseActionIdx == -1) {
|
||||
AddMacroElseAction((int)macro->ElseActions().size());
|
||||
} else {
|
||||
AddMacroElseAction(currentElseActionIdx + 1);
|
||||
}
|
||||
if (currentElseActionIdx != -1) {
|
||||
MacroElseActionSelectionChanged(currentElseActionIdx + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_elseActionRemove_clicked()
|
||||
{
|
||||
if (currentElseActionIdx == -1) {
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
RemoveMacroElseAction((int)macro->ElseActions().size() - 1);
|
||||
} else {
|
||||
RemoveMacroElseAction(currentElseActionIdx);
|
||||
}
|
||||
MacroElseActionSelectionChanged(-1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_elseActionTop_clicked()
|
||||
{
|
||||
if (currentElseActionIdx == -1) {
|
||||
return;
|
||||
}
|
||||
MacroElseActionReorder(0, currentElseActionIdx);
|
||||
MacroElseActionSelectionChanged(0);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_elseActionUp_clicked()
|
||||
{
|
||||
if (currentElseActionIdx == -1 || currentElseActionIdx == 0) {
|
||||
return;
|
||||
}
|
||||
MoveMacroElseActionUp(currentElseActionIdx);
|
||||
MacroElseActionSelectionChanged(currentElseActionIdx - 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_elseActionDown_clicked()
|
||||
{
|
||||
if (currentElseActionIdx == -1 ||
|
||||
currentElseActionIdx ==
|
||||
ui->elseActionsList->ContentLayout()->count() - 1) {
|
||||
return;
|
||||
}
|
||||
MoveMacroElseActionDown(currentElseActionIdx);
|
||||
MacroElseActionSelectionChanged(currentElseActionIdx + 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_elseActionBottom_clicked()
|
||||
{
|
||||
if (currentElseActionIdx == -1) {
|
||||
return;
|
||||
}
|
||||
const int newIdx = ui->elseActionsList->ContentLayout()->count() - 1;
|
||||
MacroElseActionReorder(newIdx, currentElseActionIdx);
|
||||
MacroElseActionSelectionChanged(newIdx);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::SwapActions(Macro *m, int pos1, int pos2)
|
||||
{
|
||||
if (pos1 == pos2) {
|
||||
return;
|
||||
}
|
||||
if (pos1 > pos2) {
|
||||
std::swap(pos1, pos2);
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
iter_swap(m->Actions().begin() + pos1, m->Actions().begin() + pos2);
|
||||
m->UpdateActionIndices();
|
||||
auto widget1 = static_cast<MacroActionEdit *>(
|
||||
ui->actionsList->ContentLayout()->takeAt(pos1)->widget());
|
||||
auto widget2 = static_cast<MacroActionEdit *>(
|
||||
ui->actionsList->ContentLayout()->takeAt(pos2 - 1)->widget());
|
||||
ui->actionsList->Insert(pos1, widget2);
|
||||
ui->actionsList->Insert(pos2, widget1);
|
||||
SetActionData(*m);
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MoveMacroActionUp(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 1 || idx >= (int)macro->Actions().size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SwapActions(macro.get(), idx, idx - 1);
|
||||
HighlightAction(idx - 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MoveMacroActionDown(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 0 || idx >= (int)macro->Actions().size() - 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
SwapActions(macro.get(), idx, idx + 1);
|
||||
HighlightAction(idx + 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MacroElseActionSelectionChanged(int idx)
|
||||
{
|
||||
SetupMacroSegmentSelection(MacroSection::ELSE_ACTIONS, idx);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MacroElseActionReorder(int to, int from)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (to == from || from < 0 || from > (int)macro->ElseActions().size() ||
|
||||
to < 0 || to > (int)macro->ElseActions().size()) {
|
||||
return;
|
||||
}
|
||||
{
|
||||
auto lock = LockContext();
|
||||
auto action = macro->ElseActions().at(from);
|
||||
macro->ElseActions().erase(macro->ElseActions().begin() + from);
|
||||
macro->ElseActions().insert(macro->ElseActions().begin() + to,
|
||||
action);
|
||||
macro->UpdateElseActionIndices();
|
||||
ui->elseActionsList->ContentLayout()->insertItem(
|
||||
to, ui->elseActionsList->ContentLayout()->takeAt(from));
|
||||
SetElseActionData(*macro);
|
||||
}
|
||||
HighlightElseAction(to);
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::AddMacroElseAction(Macro *macro, int idx,
|
||||
const std::string &id,
|
||||
obs_data_t *data)
|
||||
{
|
||||
if (idx < 0 || idx > (int)macro->ElseActions().size()) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
auto lock = LockContext();
|
||||
macro->ElseActions().emplace(macro->ElseActions().begin() + idx,
|
||||
MacroActionFactory::Create(id,
|
||||
macro));
|
||||
if (data) {
|
||||
macro->ElseActions().at(idx)->Load(data);
|
||||
}
|
||||
macro->ElseActions().at(idx)->PostLoad();
|
||||
RunPostLoadSteps();
|
||||
macro->UpdateElseActionIndices();
|
||||
ui->elseActionsList->Insert(
|
||||
idx, new MacroActionEdit(
|
||||
this, ¯o->ElseActions()[idx], id));
|
||||
SetElseActionData(*macro);
|
||||
}
|
||||
HighlightElseAction(idx);
|
||||
ui->elseActionsList->SetHelpMsgVisible(false);
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::AddMacroElseAction(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 0 || idx > (int)macro->ElseActions().size()) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string id;
|
||||
if (idx - 1 >= 0) {
|
||||
id = macro->ElseActions().at(idx - 1)->GetId();
|
||||
} else {
|
||||
id = MacroAction::GetDefaultID();
|
||||
}
|
||||
|
||||
OBSDataAutoRelease data;
|
||||
if (idx - 1 >= 0) {
|
||||
data = obs_data_create();
|
||||
macro->ElseActions().at(idx - 1)->Save(data);
|
||||
}
|
||||
AddMacroElseAction(macro.get(), idx, id, data);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::RemoveMacroElseAction(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 0 || idx >= (int)macro->ElseActions().size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
auto lock = LockContext();
|
||||
ui->elseActionsList->Remove(idx);
|
||||
macro->ElseActions().erase(macro->ElseActions().begin() + idx);
|
||||
SetMacroAbortWait(true);
|
||||
GetMacroWaitCV().notify_all();
|
||||
macro->UpdateElseActionIndices();
|
||||
SetElseActionData(*macro);
|
||||
}
|
||||
MacroElseActionSelectionChanged(-1);
|
||||
lastInteracted = MacroSection::ELSE_ACTIONS;
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::SwapElseActions(Macro *m, int pos1, int pos2)
|
||||
{
|
||||
if (pos1 == pos2) {
|
||||
return;
|
||||
}
|
||||
if (pos1 > pos2) {
|
||||
std::swap(pos1, pos2);
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
iter_swap(m->ElseActions().begin() + pos1,
|
||||
m->ElseActions().begin() + pos2);
|
||||
m->UpdateElseActionIndices();
|
||||
auto widget1 = static_cast<MacroActionEdit *>(
|
||||
ui->elseActionsList->ContentLayout()->takeAt(pos1)->widget());
|
||||
auto widget2 = static_cast<MacroActionEdit *>(
|
||||
ui->elseActionsList->ContentLayout()
|
||||
->takeAt(pos2 - 1)
|
||||
->widget());
|
||||
ui->elseActionsList->Insert(pos1, widget2);
|
||||
ui->elseActionsList->Insert(pos2, widget1);
|
||||
SetElseActionData(*m);
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MoveMacroElseActionUp(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 1 || idx >= (int)macro->ElseActions().size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SwapElseActions(macro.get(), idx, idx - 1);
|
||||
HighlightElseAction(idx - 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MoveMacroElseActionDown(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 0 || idx >= (int)macro->ElseActions().size() - 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
SwapElseActions(macro.get(), idx, idx + 1);
|
||||
HighlightElseAction(idx + 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MacroActionSelectionChanged(int idx)
|
||||
{
|
||||
SetupMacroSegmentSelection(MacroSection::ACTIONS, idx);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MacroActionReorder(int to, int from)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (to == from || from < 0 || from > (int)macro->Actions().size() ||
|
||||
to < 0 || to > (int)macro->Actions().size()) {
|
||||
return;
|
||||
}
|
||||
{
|
||||
auto lock = LockContext();
|
||||
auto action = macro->Actions().at(from);
|
||||
macro->Actions().erase(macro->Actions().begin() + from);
|
||||
macro->Actions().insert(macro->Actions().begin() + to, action);
|
||||
macro->UpdateActionIndices();
|
||||
ui->actionsList->ContentLayout()->insertItem(
|
||||
to, ui->actionsList->ContentLayout()->takeAt(from));
|
||||
SetActionData(*macro);
|
||||
}
|
||||
HighlightAction(to);
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
|
|
|||
|
|
@ -13,11 +13,9 @@ class MacroActionEdit : public MacroSegmentEdit {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MacroActionEdit(
|
||||
QWidget *parent = nullptr,
|
||||
std::shared_ptr<MacroAction> * = nullptr,
|
||||
const std::string &id = MacroAction::GetDefaultID().data());
|
||||
void UpdateEntryData(const std::string &id);
|
||||
MacroActionEdit(QWidget *parent = nullptr,
|
||||
std::shared_ptr<MacroAction> * = nullptr);
|
||||
void SetupWidgets(bool basicSetup = false);
|
||||
void SetEntryData(std::shared_ptr<MacroAction> *);
|
||||
|
||||
private slots:
|
||||
|
|
@ -27,14 +25,11 @@ private slots:
|
|||
|
||||
private:
|
||||
std::shared_ptr<MacroSegment> Data() const;
|
||||
void SetDisableEffect(bool);
|
||||
void SetEnableAppearance(bool);
|
||||
|
||||
FilterComboBox *_actionSelection;
|
||||
SwitchButton *_enable;
|
||||
|
||||
std::shared_ptr<MacroAction> *_entryData;
|
||||
QTimer _actionStateTimer;
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,25 +1,11 @@
|
|||
#include "macro-action-factory.hpp"
|
||||
#include "macro-segment-unknown.hpp"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
namespace advss {
|
||||
|
||||
namespace {
|
||||
|
||||
class MacroActionUnknown : public MacroAction {
|
||||
public:
|
||||
MacroActionUnknown(Macro *m) : MacroAction(m) {}
|
||||
std::shared_ptr<MacroAction> Copy() const
|
||||
{
|
||||
return std::make_shared<MacroActionUnknown>(GetMacro());
|
||||
}
|
||||
bool PerformAction() { return true; };
|
||||
bool Save(obs_data_t *obj) const { return MacroAction::Save(obj); };
|
||||
bool Load(obs_data_t *obj) { return MacroAction::Load(obj); };
|
||||
std::string GetId() const { return "unknown"; }
|
||||
};
|
||||
|
||||
} // namespace
|
||||
using MacroActionUnknown = MacroSegmentUnknown<MacroAction>;
|
||||
|
||||
static std::recursive_mutex mutex;
|
||||
|
||||
|
|
@ -49,9 +35,10 @@ bool MacroActionFactory::Deregister(const std::string &id)
|
|||
return true;
|
||||
}
|
||||
|
||||
static std::shared_ptr<MacroAction> createUnknownAction(Macro *m)
|
||||
static std::shared_ptr<MacroAction> createUnknownAction(Macro *m,
|
||||
const std::string &id)
|
||||
{
|
||||
return std::make_shared<MacroActionUnknown>(m);
|
||||
return std::make_shared<MacroActionUnknown>(m, id);
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroAction> MacroActionFactory::Create(const std::string &id,
|
||||
|
|
@ -62,12 +49,7 @@ std::shared_ptr<MacroAction> MacroActionFactory::Create(const std::string &id,
|
|||
return it->second._create(m);
|
||||
}
|
||||
|
||||
return createUnknownAction(m);
|
||||
}
|
||||
|
||||
static QWidget *createUnknownActionWidget()
|
||||
{
|
||||
return new QLabel(obs_module_text("AdvSceneSwitcher.action.unknown"));
|
||||
return createUnknownAction(m, id);
|
||||
}
|
||||
|
||||
QWidget *MacroActionFactory::CreateWidget(const std::string &id,
|
||||
|
|
@ -79,7 +61,7 @@ QWidget *MacroActionFactory::CreateWidget(const std::string &id,
|
|||
return it->second._createWidget(parent, action);
|
||||
}
|
||||
|
||||
return createUnknownActionWidget();
|
||||
return CreateUnknownSegmentWidget(true);
|
||||
}
|
||||
|
||||
std::string MacroActionFactory::GetActionName(const std::string &id)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ struct MacroActionInfo {
|
|||
std::function<std::shared_ptr<MacroAction>(Macro *m)> _create = nullptr;
|
||||
CreateActionWidget _createWidget = nullptr;
|
||||
std::string _name;
|
||||
bool _hidden = false;
|
||||
};
|
||||
|
||||
class MacroActionFactory {
|
||||
|
|
@ -19,7 +20,7 @@ public:
|
|||
MacroActionFactory() = delete;
|
||||
|
||||
EXPORT static bool Register(const std::string &id, MacroActionInfo);
|
||||
static bool Deregister(const std::string &id);
|
||||
EXPORT static bool Deregister(const std::string &id);
|
||||
static std::shared_ptr<MacroAction> Create(const std::string &id,
|
||||
Macro *m);
|
||||
static QWidget *CreateWidget(const std::string &id, QWidget *parent,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include "help-icon.hpp"
|
||||
#include "layout-helpers.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "macro-action-factory.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
|
|
@ -12,70 +13,126 @@ bool MacroActionMacro::_registered = MacroActionFactory::Register(
|
|||
{MacroActionMacro::Create, MacroActionMacroEdit::Create,
|
||||
"AdvSceneSwitcher.action.macro"});
|
||||
|
||||
const static std::map<MacroActionMacro::Action, std::string> actionTypes = {
|
||||
{MacroActionMacro::Action::PAUSE,
|
||||
"AdvSceneSwitcher.action.macro.type.pause"},
|
||||
{MacroActionMacro::Action::UNPAUSE,
|
||||
"AdvSceneSwitcher.action.macro.type.unpause"},
|
||||
{MacroActionMacro::Action::RESET_COUNTER,
|
||||
"AdvSceneSwitcher.action.macro.type.resetCounter"},
|
||||
{MacroActionMacro::Action::RUN,
|
||||
"AdvSceneSwitcher.action.macro.type.run"},
|
||||
{MacroActionMacro::Action::STOP,
|
||||
"AdvSceneSwitcher.action.macro.type.stop"},
|
||||
{MacroActionMacro::Action::DISABLE_ACTION,
|
||||
"AdvSceneSwitcher.action.macro.type.disableAction"},
|
||||
{MacroActionMacro::Action::ENABLE_ACTION,
|
||||
"AdvSceneSwitcher.action.macro.type.enableAction"},
|
||||
{MacroActionMacro::Action::TOGGLE_ACTION,
|
||||
"AdvSceneSwitcher.action.macro.type.toggleAction"},
|
||||
};
|
||||
|
||||
bool MacroActionMacro::PerformAction()
|
||||
void MacroActionMacro::AdjustActionState(Macro *macro) const
|
||||
{
|
||||
auto macro = _macro.GetMacro();
|
||||
if (!macro) {
|
||||
return true;
|
||||
}
|
||||
const auto ¯oActions = _useElseSection ? macro->ElseActions()
|
||||
: macro->Actions();
|
||||
|
||||
switch (_action) {
|
||||
case Action::PAUSE:
|
||||
macro->SetPaused();
|
||||
break;
|
||||
case Action::UNPAUSE:
|
||||
macro->SetPaused(false);
|
||||
break;
|
||||
case Action::RESET_COUNTER:
|
||||
macro->ResetRunCount();
|
||||
break;
|
||||
case Action::RUN:
|
||||
RunActions(macro.get());
|
||||
break;
|
||||
case Action::STOP:
|
||||
macro->Stop();
|
||||
break;
|
||||
case Action::DISABLE_ACTION:
|
||||
if (IsValidMacroSegmentIndex(macro.get(), _actionIndex - 1,
|
||||
false)) {
|
||||
macro->Actions().at(_actionIndex - 1)->SetEnabled(false);
|
||||
std::vector<std::shared_ptr<MacroAction>> actionsToModify;
|
||||
switch (_actionSelectionType) {
|
||||
case SelectionType::INDEX: {
|
||||
const bool isValidAction =
|
||||
(_useElseSection &&
|
||||
IsValidElseActionIndex(macro, _actionIndex - 1)) ||
|
||||
(!_useElseSection &&
|
||||
IsValidActionIndex(macro, _actionIndex - 1));
|
||||
|
||||
if (isValidAction) {
|
||||
actionsToModify.emplace_back(
|
||||
macroActions.at(_actionIndex - 1));
|
||||
}
|
||||
break;
|
||||
case Action::ENABLE_ACTION:
|
||||
if (IsValidMacroSegmentIndex(macro.get(), _actionIndex - 1,
|
||||
false)) {
|
||||
macro->Actions().at(_actionIndex - 1)->SetEnabled(true);
|
||||
}
|
||||
case SelectionType::LABEL:
|
||||
for (const auto &action : macroActions) {
|
||||
if (!action->GetUseCustomLabel()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto label = action->GetCustomLabel();
|
||||
|
||||
if (_regex.Enabled()) {
|
||||
if (_regex.Matches(label, _label)) {
|
||||
actionsToModify.emplace_back(action);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (label == std::string(_label)) {
|
||||
actionsToModify.emplace_back(action);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Action::TOGGLE_ACTION:
|
||||
if (IsValidMacroSegmentIndex(macro.get(), _actionIndex - 1,
|
||||
false)) {
|
||||
auto action = macro->Actions().at(_actionIndex - 1);
|
||||
action->SetEnabled(!action->Enabled());
|
||||
case SelectionType::ID:
|
||||
for (const auto &action : macroActions) {
|
||||
if (action->GetId() == _actionId) {
|
||||
actionsToModify.emplace_back(action);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (const auto &action : actionsToModify) {
|
||||
switch (_action) {
|
||||
case Action::DISABLE_ACTION:
|
||||
action->SetEnabled(false);
|
||||
break;
|
||||
case Action::ENABLE_ACTION:
|
||||
action->SetEnabled(true);
|
||||
break;
|
||||
case Action::TOGGLE_ACTION:
|
||||
action->SetEnabled(!action->Enabled());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool MacroActionMacro::PerformAction()
|
||||
{
|
||||
if (_action == Action::NESTED_MACRO) {
|
||||
const bool conditionsMatched = _nestedMacro->CheckConditions();
|
||||
return _nestedMacro->PerformActions(conditionsMatched);
|
||||
}
|
||||
|
||||
auto macro = _macro.GetMacro();
|
||||
if (!macro) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto performActionForMacro = [this](Macro *macro) {
|
||||
switch (_action) {
|
||||
case Action::PAUSE:
|
||||
macro->SetPaused();
|
||||
break;
|
||||
case Action::UNPAUSE:
|
||||
macro->SetPaused(false);
|
||||
break;
|
||||
case Action::TOGGLE_PAUSE:
|
||||
macro->SetPaused(!macro->Paused());
|
||||
break;
|
||||
case Action::RESET_COUNTER:
|
||||
macro->ResetRunCount();
|
||||
break;
|
||||
case Action::RUN_ACTIONS:
|
||||
RunActions(macro);
|
||||
break;
|
||||
case Action::STOP:
|
||||
macro->Stop();
|
||||
break;
|
||||
case Action::DISABLE_ACTION:
|
||||
case Action::ENABLE_ACTION:
|
||||
case Action::TOGGLE_ACTION:
|
||||
AdjustActionState(macro);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
if (!IsGroupMacro(macro.get())) {
|
||||
performActionForMacro(macro.get());
|
||||
return true;
|
||||
}
|
||||
|
||||
auto macros = GetGroupMacroEntries(macro.get());
|
||||
for (const auto ¯o : macros) {
|
||||
performActionForMacro(macro.get());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -96,7 +153,7 @@ void MacroActionMacro::LogAction() const
|
|||
ablog(LOG_INFO, "reset counter for \"%s\"",
|
||||
macro->Name().c_str());
|
||||
break;
|
||||
case Action::RUN:
|
||||
case Action::RUN_ACTIONS:
|
||||
ablog(LOG_INFO, "run nested macro \"%s\"",
|
||||
macro->Name().c_str());
|
||||
break;
|
||||
|
|
@ -115,6 +172,9 @@ void MacroActionMacro::LogAction() const
|
|||
ablog(LOG_INFO, "toggled action %d of macro \"%s\"",
|
||||
_actionIndex.GetValue(), macro->Name().c_str());
|
||||
break;
|
||||
case Action::NESTED_MACRO:
|
||||
ablog(LOG_INFO, "run nested macro");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -123,21 +183,44 @@ void MacroActionMacro::LogAction() const
|
|||
bool MacroActionMacro::Save(obs_data_t *obj) const
|
||||
{
|
||||
MacroAction::Save(obj);
|
||||
_macro.Save(obj);
|
||||
_actionIndex.Save(obj, "actionIndex");
|
||||
obs_data_set_int(obj, "action", static_cast<int>(_action));
|
||||
_macro.Save(obj);
|
||||
obs_data_set_int(obj, "actionSelectionType",
|
||||
static_cast<int>(_actionSelectionType));
|
||||
_actionIndex.Save(obj, "actionIndex");
|
||||
_label.Save(obj, "label");
|
||||
obs_data_set_string(obj, "actionId", _actionId.c_str());
|
||||
_regex.Save(obj);
|
||||
_runOptions.Save(obj);
|
||||
OBSDataAutoRelease nestedMacroData = obs_data_create();
|
||||
_nestedMacro->Save(nestedMacroData);
|
||||
obs_data_set_obj(obj, "nestedMacro", nestedMacroData);
|
||||
obs_data_set_int(obj, "customWidgetHeight", _customWidgetHeight);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacroActionMacro::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroAction::Load(obj);
|
||||
_macro.Load(obj);
|
||||
_actionIndex.Load(obj, "actionIndex");
|
||||
_action = static_cast<MacroActionMacro::Action>(
|
||||
obs_data_get_int(obj, "action"));
|
||||
_macro.Load(obj);
|
||||
_actionSelectionType = static_cast<SelectionType>(
|
||||
obs_data_get_int(obj, "actionSelectionType"));
|
||||
_actionIndex.Load(obj, "actionIndex");
|
||||
_label.Load(obj, "label");
|
||||
_actionId = obs_data_get_string(obj, "actionId");
|
||||
_regex.Load(obj);
|
||||
_runOptions.Load(obj);
|
||||
|
||||
if (obs_data_has_user_value(obj, "nestedMacro")) {
|
||||
OBSDataAutoRelease nestedMacroData =
|
||||
obs_data_get_obj(obj, "nestedMacro");
|
||||
_nestedMacro->Load(nestedMacroData);
|
||||
}
|
||||
|
||||
_customWidgetHeight = obs_data_get_int(obj, "customWidgetHeight");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -146,6 +229,7 @@ bool MacroActionMacro::PostLoad()
|
|||
MacroRefAction::PostLoad();
|
||||
MacroAction::PostLoad();
|
||||
_runOptions.macro.PostLoad();
|
||||
_nestedMacro->PostLoad();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -161,12 +245,23 @@ std::shared_ptr<MacroAction> MacroActionMacro::Create(Macro *m)
|
|||
|
||||
std::shared_ptr<MacroAction> MacroActionMacro::Copy() const
|
||||
{
|
||||
return std::make_shared<MacroActionMacro>(*this);
|
||||
auto copy = std::make_shared<MacroActionMacro>(*this);
|
||||
|
||||
// Create a new nested macro
|
||||
OBSDataAutoRelease data = obs_data_create();
|
||||
_nestedMacro->Save(data);
|
||||
|
||||
copy->_nestedMacro = std::make_shared<Macro>();
|
||||
copy->_nestedMacro->Load(data);
|
||||
copy->_nestedMacro->PostLoad();
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
void MacroActionMacro::ResolveVariablesToFixedValues()
|
||||
{
|
||||
_actionIndex.ResolveVariables();
|
||||
_label.ResolveVariables();
|
||||
}
|
||||
|
||||
static void runActionsHelper(Macro *macro, bool runElseActions, bool setInputs,
|
||||
|
|
@ -210,8 +305,33 @@ void MacroActionMacro::RunActions(Macro *actionMacro) const
|
|||
|
||||
static void populateActionSelection(QComboBox *list)
|
||||
{
|
||||
for (const auto &[_, name] : actionTypes) {
|
||||
list->addItem(obs_module_text(name.c_str()));
|
||||
static const std::vector<std::pair<MacroActionMacro::Action, std::string>>
|
||||
actions = {
|
||||
{MacroActionMacro::Action::PAUSE,
|
||||
"AdvSceneSwitcher.action.macro.type.pause"},
|
||||
{MacroActionMacro::Action::UNPAUSE,
|
||||
"AdvSceneSwitcher.action.macro.type.unpause"},
|
||||
{MacroActionMacro::Action::TOGGLE_PAUSE,
|
||||
"AdvSceneSwitcher.action.macro.type.togglePause"},
|
||||
{MacroActionMacro::Action::RESET_COUNTER,
|
||||
"AdvSceneSwitcher.action.macro.type.resetCounter"},
|
||||
{MacroActionMacro::Action::NESTED_MACRO,
|
||||
"AdvSceneSwitcher.action.macro.type.nestedMacro"},
|
||||
{MacroActionMacro::Action::RUN_ACTIONS,
|
||||
"AdvSceneSwitcher.action.macro.type.run"},
|
||||
{MacroActionMacro::Action::STOP,
|
||||
"AdvSceneSwitcher.action.macro.type.stop"},
|
||||
{MacroActionMacro::Action::DISABLE_ACTION,
|
||||
"AdvSceneSwitcher.action.macro.type.disableAction"},
|
||||
{MacroActionMacro::Action::ENABLE_ACTION,
|
||||
"AdvSceneSwitcher.action.macro.type.enableAction"},
|
||||
{MacroActionMacro::Action::TOGGLE_ACTION,
|
||||
"AdvSceneSwitcher.action.macro.type.toggleAction"},
|
||||
};
|
||||
|
||||
for (const auto &[value, name] : actions) {
|
||||
list->addItem(obs_module_text(name.c_str()),
|
||||
static_cast<int>(value));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -225,7 +345,7 @@ static void populateConditionBehaviorSelection(QComboBox *list)
|
|||
"AdvSceneSwitcher.action.macro.type.run.conditions.false"));
|
||||
}
|
||||
|
||||
static void populateActionTypeSelection(QComboBox *list)
|
||||
static void populateActionSectionSelection(QComboBox *list)
|
||||
{
|
||||
list->addItem(obs_module_text(
|
||||
"AdvSceneSwitcher.action.macro.type.run.actionType.regular"));
|
||||
|
|
@ -233,19 +353,47 @@ static void populateActionTypeSelection(QComboBox *list)
|
|||
"AdvSceneSwitcher.action.macro.type.run.actionType.else"));
|
||||
}
|
||||
|
||||
static void populateActionTypes(QComboBox *list)
|
||||
{
|
||||
for (const auto &[id, info] : MacroActionFactory::GetActionTypes()) {
|
||||
list->addItem(obs_module_text(info._name.c_str()),
|
||||
QString::fromStdString(id));
|
||||
}
|
||||
}
|
||||
|
||||
static void populateActionSelectionTypes(QComboBox *list)
|
||||
{
|
||||
list->addItem(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.macro.actionSelectionType.index"),
|
||||
static_cast<int>(MacroActionMacro::SelectionType::INDEX));
|
||||
list->addItem(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.macro.actionSelectionType.label"),
|
||||
static_cast<int>(MacroActionMacro::SelectionType::LABEL));
|
||||
list->addItem(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.macro.actionSelectionType.id"),
|
||||
static_cast<int>(MacroActionMacro::SelectionType::ID));
|
||||
}
|
||||
|
||||
MacroActionMacroEdit::MacroActionMacroEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroActionMacro> entryData)
|
||||
: QWidget(parent),
|
||||
: ResizableWidget(parent),
|
||||
_actions(new QComboBox()),
|
||||
_macros(new MacroSelection(parent)),
|
||||
_actionSelectionType(new QComboBox(this)),
|
||||
_actionIndex(new MacroSegmentSelection(
|
||||
this, MacroSegmentSelection::Type::ACTION)),
|
||||
_actions(new QComboBox()),
|
||||
_label(new VariableLineEdit(this)),
|
||||
_actionTypes(new FilterComboBox(this)),
|
||||
_regex(new RegexConfigWidget(this)),
|
||||
_conditionMacros(new MacroSelection(parent)),
|
||||
_conditionBehaviors(new QComboBox()),
|
||||
_reevaluateConditionState(new QCheckBox(
|
||||
obs_module_text("AdvSceneSwitcher.action.macro.type.run."
|
||||
"updateConditionMatchState"))),
|
||||
_actionTypes(new QComboBox()),
|
||||
_actionSections(new QComboBox(this)),
|
||||
_skipWhenPaused(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.action.macro.type.run.skipWhenPaused"))),
|
||||
_setInputs(new QCheckBox(obs_module_text(
|
||||
|
|
@ -254,28 +402,46 @@ MacroActionMacroEdit::MacroActionMacroEdit(
|
|||
_entryLayout(new QHBoxLayout()),
|
||||
_conditionLayout(new QHBoxLayout()),
|
||||
_reevaluateConditionStateLayout(new QHBoxLayout()),
|
||||
_setInputsLayout(new QHBoxLayout())
|
||||
_setInputsLayout(new QHBoxLayout()),
|
||||
_nestedMacro(new MacroEdit(
|
||||
this,
|
||||
QStringList()
|
||||
<< "AdvSceneSwitcher.action.macro.type.nestedMacro.conditionHelp"
|
||||
<< "AdvSceneSwitcher.action.macro.type.nestedMacro.actionHelp"
|
||||
<< "AdvSceneSwitcher.action.macro.type.nestedMacro.elseActionHelp"))
|
||||
{
|
||||
populateActionSelection(_actions);
|
||||
populateConditionBehaviorSelection(_conditionBehaviors);
|
||||
populateActionTypeSelection(_actionTypes);
|
||||
populateActionSectionSelection(_actionSections);
|
||||
populateActionSelectionTypes(_actionSelectionType);
|
||||
populateActionTypes(_actionTypes);
|
||||
|
||||
_conditionMacros->HideSelectedMacro();
|
||||
_conditionMacros->HideGroups();
|
||||
|
||||
QWidget::connect(_macros, SIGNAL(currentTextChanged(const QString &)),
|
||||
this, SLOT(MacroChanged(const QString &)));
|
||||
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(ActionChanged(int)));
|
||||
QWidget::connect(_actionSelectionType, SIGNAL(currentIndexChanged(int)),
|
||||
this, SLOT(ActionSelectionTypeChanged(int)));
|
||||
QWidget::connect(_actionIndex,
|
||||
SIGNAL(SelectionChanged(const IntVariable &)), this,
|
||||
SLOT(ActionIndexChanged(const IntVariable &)));
|
||||
QWidget::connect(_label, SIGNAL(editingFinished()), this,
|
||||
SLOT(LabelChanged()));
|
||||
QWidget::connect(_actionTypes, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(ActionTypeChanged(int)));
|
||||
QWidget::connect(_regex,
|
||||
SIGNAL(RegexConfigChanged(const RegexConfig &)), this,
|
||||
SLOT(RegexChanged(const RegexConfig &)));
|
||||
QWidget::connect(_conditionMacros,
|
||||
SIGNAL(currentTextChanged(const QString &)), this,
|
||||
SLOT(ConditionMacroChanged(const QString &)));
|
||||
QWidget::connect(_conditionBehaviors, SIGNAL(currentIndexChanged(int)),
|
||||
this, SLOT(ConditionBehaviorChanged(int)));
|
||||
QWidget::connect(_actionTypes, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(ActionTypeChanged(int)));
|
||||
QWidget::connect(_actionSections, SIGNAL(currentIndexChanged(int)),
|
||||
this, SLOT(ActionSectionChanged(int)));
|
||||
QWidget::connect(_skipWhenPaused, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(SkipWhenPausedChanged(int)));
|
||||
QWidget::connect(_setInputs, SIGNAL(stateChanged(int)), this,
|
||||
|
|
@ -303,17 +469,24 @@ MacroActionMacroEdit::MacroActionMacroEdit(
|
|||
layout->addLayout(_setInputsLayout);
|
||||
layout->addWidget(_inputs);
|
||||
layout->addWidget(_skipWhenPaused);
|
||||
layout->addWidget(_nestedMacro);
|
||||
setLayout(layout);
|
||||
_entryData = entryData;
|
||||
UpdateEntryData();
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
void HighligthMacroSettingsButton(bool enable);
|
||||
void HighlightMacroSettingsButton(bool enable);
|
||||
|
||||
MacroActionMacroEdit::~MacroActionMacroEdit()
|
||||
{
|
||||
HighligthMacroSettingsButton(false);
|
||||
HighlightMacroSettingsButton(false);
|
||||
|
||||
if (!_entryData) {
|
||||
return;
|
||||
}
|
||||
_entryData->_customWidgetHeight = GetCustomHeight();
|
||||
_nestedMacro->SetMacro({}); // Save splitter states
|
||||
}
|
||||
|
||||
void MacroActionMacroEdit::UpdateEntryData()
|
||||
|
|
@ -321,23 +494,42 @@ void MacroActionMacroEdit::UpdateEntryData()
|
|||
if (!_entryData) {
|
||||
return;
|
||||
}
|
||||
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
|
||||
|
||||
_actions->setCurrentIndex(
|
||||
_actions->findData(static_cast<int>(_entryData->_action)));
|
||||
_actionSelectionType->setCurrentIndex(_actionSelectionType->findData(
|
||||
static_cast<int>(_entryData->_actionSelectionType)));
|
||||
_actionIndex->SetValue(_entryData->_actionIndex);
|
||||
_actionIndex->SetMacro(_entryData->_macro.GetMacro());
|
||||
_label->setText(_entryData->_label);
|
||||
_actionTypes->setCurrentIndex(_actionTypes->findData(
|
||||
QString::fromStdString(_entryData->_actionId)));
|
||||
_regex->SetRegexConfig(_entryData->_regex);
|
||||
_macros->SetCurrentMacro(_entryData->_macro);
|
||||
_conditionMacros->SetCurrentMacro(_entryData->_runOptions.macro);
|
||||
_conditionBehaviors->setCurrentIndex(
|
||||
static_cast<int>(_entryData->_runOptions.logic));
|
||||
_reevaluateConditionState->setChecked(
|
||||
_entryData->_runOptions.reevaluateConditionState);
|
||||
_actionTypes->setCurrentIndex(
|
||||
_actionSections->setCurrentIndex(
|
||||
_entryData->_runOptions.runElseActions ? 1 : 0);
|
||||
_skipWhenPaused->setChecked(_entryData->_runOptions.skipWhenPaused);
|
||||
_setInputs->setChecked(_entryData->_runOptions.setInputs);
|
||||
SetupMacroInput(_entryData->_macro.GetMacro().get());
|
||||
|
||||
const auto ¯o = _entryData->_nestedMacro;
|
||||
_nestedMacro->SetMacro(macro);
|
||||
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
QWidget *MacroActionMacroEdit::Create(QWidget *parent,
|
||||
std::shared_ptr<MacroAction> action)
|
||||
{
|
||||
return new MacroActionMacroEdit(
|
||||
parent, std::dynamic_pointer_cast<MacroActionMacro>(action));
|
||||
}
|
||||
|
||||
void MacroActionMacroEdit::MacroChanged(const QString &text)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
|
|
@ -350,10 +542,20 @@ void MacroActionMacroEdit::MacroChanged(const QString &text)
|
|||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionMacroEdit::ActionChanged(int value)
|
||||
void MacroActionMacroEdit::ActionChanged(int idx)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_action = static_cast<MacroActionMacro::Action>(value);
|
||||
_entryData->_action = static_cast<MacroActionMacro::Action>(
|
||||
_actions->itemData(idx).toInt());
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionMacroEdit::ActionSelectionTypeChanged(int idx)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_actionSelectionType =
|
||||
static_cast<MacroActionMacro::SelectionType>(
|
||||
_actionSelectionType->itemData(idx).toInt());
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
|
|
@ -363,6 +565,25 @@ void MacroActionMacroEdit::ActionIndexChanged(const IntVariable &value)
|
|||
_entryData->_actionIndex = value;
|
||||
}
|
||||
|
||||
void MacroActionMacroEdit::LabelChanged()
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_label = _label->text().toStdString();
|
||||
}
|
||||
|
||||
void MacroActionMacroEdit::ActionTypeChanged(int idx)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_actionId =
|
||||
_actionTypes->itemData(idx).toString().toStdString();
|
||||
}
|
||||
|
||||
void MacroActionMacroEdit::RegexChanged(const RegexConfig ®ex)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_regex = regex;
|
||||
}
|
||||
|
||||
void MacroActionMacroEdit::ConditionMacroChanged(const QString &text)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
|
|
@ -384,10 +605,13 @@ void MacroActionMacroEdit::ReevaluateConditionStateChanged(int value)
|
|||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionMacroEdit::ActionTypeChanged(int value)
|
||||
void MacroActionMacroEdit::ActionSectionChanged(int useElse)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_runOptions.runElseActions = value;
|
||||
_entryData->_runOptions.runElseActions = useElse;
|
||||
_entryData->_useElseSection = useElse;
|
||||
_actionIndex->SetType(useElse ? MacroSegmentSelection::Type::ELSE_ACTION
|
||||
: MacroSegmentSelection::Type::ACTION);
|
||||
}
|
||||
|
||||
void MacroActionMacroEdit::SkipWhenPausedChanged(int value)
|
||||
|
|
@ -416,7 +640,11 @@ void MacroActionMacroEdit::SetWidgetVisibility()
|
|||
_entryLayout->removeWidget(_actions);
|
||||
_entryLayout->removeWidget(_actionIndex);
|
||||
_entryLayout->removeWidget(_macros);
|
||||
_entryLayout->removeWidget(_actionSections);
|
||||
_entryLayout->removeWidget(_label);
|
||||
_entryLayout->removeWidget(_regex);
|
||||
_entryLayout->removeWidget(_actionTypes);
|
||||
_entryLayout->removeWidget(_actionSelectionType);
|
||||
_conditionLayout->removeWidget(_conditionBehaviors);
|
||||
_conditionLayout->removeWidget(_conditionMacros);
|
||||
|
||||
|
|
@ -427,18 +655,40 @@ void MacroActionMacroEdit::SetWidgetVisibility()
|
|||
{"{{actions}}", _actions},
|
||||
{"{{actionIndex}}", _actionIndex},
|
||||
{"{{macros}}", _macros},
|
||||
{"{{actionTypes}}", _actionTypes},
|
||||
{"{{actionSections}}", _actionSections},
|
||||
{"{{conditionBehaviors}}", _conditionBehaviors},
|
||||
{"{{conditionMacros}}", _conditionMacros},
|
||||
{"{{actionSelectionType}}", _actionSelectionType},
|
||||
{"{{label}}", _label},
|
||||
{"{{regex}}", _regex},
|
||||
{"{{actionTypes}}", _actionTypes},
|
||||
|
||||
};
|
||||
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
_entryData->_action == MacroActionMacro::Action::RUN
|
||||
? "AdvSceneSwitcher.action.macro.entry.run"
|
||||
: "AdvSceneSwitcher.action.macro.entry.other"),
|
||||
_entryLayout, placeholders);
|
||||
const auto action = _entryData->_action;
|
||||
const char *layoutText = "";
|
||||
switch (action) {
|
||||
case MacroActionMacro::Action::PAUSE:
|
||||
case MacroActionMacro::Action::UNPAUSE:
|
||||
case MacroActionMacro::Action::TOGGLE_PAUSE:
|
||||
case MacroActionMacro::Action::RESET_COUNTER:
|
||||
case MacroActionMacro::Action::STOP:
|
||||
case MacroActionMacro::Action::NESTED_MACRO:
|
||||
layoutText = "AdvSceneSwitcher.action.macro.layout.other";
|
||||
break;
|
||||
case MacroActionMacro::Action::RUN_ACTIONS:
|
||||
layoutText = "AdvSceneSwitcher.action.macro.layout.run";
|
||||
break;
|
||||
case MacroActionMacro::Action::DISABLE_ACTION:
|
||||
case MacroActionMacro::Action::ENABLE_ACTION:
|
||||
case MacroActionMacro::Action::TOGGLE_ACTION:
|
||||
layoutText = "AdvSceneSwitcher.action.macro.layout.actionState";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
PlaceWidgets(obs_module_text(layoutText), _entryLayout, placeholders);
|
||||
|
||||
if (_entryData->_runOptions.logic ==
|
||||
MacroActionMacro::RunOptions::Logic::IGNORE_CONDITIONS) {
|
||||
|
|
@ -447,47 +697,70 @@ void MacroActionMacroEdit::SetWidgetVisibility()
|
|||
} else {
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.macro.entry.run.condition"),
|
||||
"AdvSceneSwitcher.action.macro.layout.run.condition"),
|
||||
_conditionLayout, placeholders);
|
||||
}
|
||||
|
||||
if (_entryData->_action == MacroActionMacro::Action::RUN ||
|
||||
_entryData->_action == MacroActionMacro::Action::STOP) {
|
||||
if (action == MacroActionMacro::Action::RUN_ACTIONS ||
|
||||
action == MacroActionMacro::Action::STOP) {
|
||||
_macros->HideSelectedMacro();
|
||||
} else {
|
||||
_macros->ShowAllMacros();
|
||||
}
|
||||
|
||||
const auto actionSelectionType = _entryData->_actionSelectionType;
|
||||
const bool isModifyingActionState =
|
||||
_entryData->_action ==
|
||||
MacroActionMacro::Action::DISABLE_ACTION ||
|
||||
_entryData->_action ==
|
||||
MacroActionMacro::Action::ENABLE_ACTION ||
|
||||
_entryData->_action == MacroActionMacro::Action::TOGGLE_ACTION;
|
||||
_actionIndex->setVisible(isModifyingActionState);
|
||||
action == MacroActionMacro::Action::DISABLE_ACTION ||
|
||||
action == MacroActionMacro::Action::ENABLE_ACTION ||
|
||||
action == MacroActionMacro::Action::TOGGLE_ACTION;
|
||||
_actionSelectionType->setVisible(isModifyingActionState);
|
||||
_actionIndex->setVisible(
|
||||
isModifyingActionState &&
|
||||
actionSelectionType == MacroActionMacro::SelectionType::INDEX);
|
||||
_label->setVisible(isModifyingActionState &&
|
||||
actionSelectionType ==
|
||||
MacroActionMacro::SelectionType::LABEL);
|
||||
_regex->setVisible(isModifyingActionState &&
|
||||
actionSelectionType ==
|
||||
MacroActionMacro::SelectionType::LABEL);
|
||||
_actionTypes->setVisible(isModifyingActionState &&
|
||||
actionSelectionType ==
|
||||
MacroActionMacro::SelectionType::ID);
|
||||
|
||||
SetLayoutVisible(_conditionLayout,
|
||||
_entryData->_action == MacroActionMacro::Action::RUN);
|
||||
action == MacroActionMacro::Action::RUN_ACTIONS);
|
||||
const bool needsAdditionalConditionWidgets =
|
||||
_entryData->_action == MacroActionMacro::Action::RUN &&
|
||||
action == MacroActionMacro::Action::RUN_ACTIONS &&
|
||||
_entryData->_runOptions.logic !=
|
||||
MacroActionMacro::RunOptions::Logic::IGNORE_CONDITIONS;
|
||||
_conditionMacros->setVisible(needsAdditionalConditionWidgets);
|
||||
SetLayoutVisible(_reevaluateConditionStateLayout,
|
||||
needsAdditionalConditionWidgets);
|
||||
SetLayoutVisible(_setInputsLayout,
|
||||
_entryData->_action == MacroActionMacro::Action::RUN);
|
||||
_inputs->setVisible(_entryData->_action ==
|
||||
MacroActionMacro::Action::RUN &&
|
||||
action == MacroActionMacro::Action::RUN_ACTIONS);
|
||||
_inputs->setVisible(action == MacroActionMacro::Action::RUN_ACTIONS &&
|
||||
_entryData->_runOptions.setInputs);
|
||||
HighligthMacroSettingsButton(_entryData->_action ==
|
||||
MacroActionMacro::Action::RUN &&
|
||||
_entryData->_runOptions.setInputs &&
|
||||
!_inputs->HasInputsToSet());
|
||||
_actionTypes->setVisible(_entryData->_action ==
|
||||
MacroActionMacro::Action::RUN);
|
||||
_skipWhenPaused->setVisible(_entryData->_action ==
|
||||
MacroActionMacro::Action::RUN);
|
||||
HighlightMacroSettingsButton(
|
||||
action == MacroActionMacro::Action::RUN_ACTIONS &&
|
||||
_entryData->_runOptions.setInputs &&
|
||||
!_inputs->HasInputsToSet());
|
||||
_actionSections->setVisible(
|
||||
action == MacroActionMacro::Action::RUN_ACTIONS ||
|
||||
isModifyingActionState);
|
||||
_skipWhenPaused->setVisible(action ==
|
||||
MacroActionMacro::Action::RUN_ACTIONS);
|
||||
|
||||
_nestedMacro->setVisible(action ==
|
||||
MacroActionMacro::Action::NESTED_MACRO);
|
||||
_macros->setVisible(action != MacroActionMacro::Action::NESTED_MACRO);
|
||||
SetResizingEnabled(action == MacroActionMacro::Action::NESTED_MACRO);
|
||||
|
||||
if (_nestedMacro->IsEmpty()) {
|
||||
_nestedMacro->ShowAllMacroSections();
|
||||
// TODO: find a better solution than setting a fixed height
|
||||
_entryData->_customWidgetHeight = 600;
|
||||
}
|
||||
SetCustomHeight(_entryData->_customWidgetHeight);
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
|
|
|
|||
|
|
@ -1,8 +1,13 @@
|
|||
#pragma once
|
||||
#include "macro-action-edit.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "macro-edit.hpp"
|
||||
#include "macro-input.hpp"
|
||||
#include "macro-selection.hpp"
|
||||
#include "macro-segment-selection.hpp"
|
||||
#include "regex-config.hpp"
|
||||
#include "resizable-widget.hpp"
|
||||
#include "variable-line-edit.hpp"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QHBoxLayout>
|
||||
|
|
@ -44,24 +49,37 @@ public:
|
|||
PAUSE,
|
||||
UNPAUSE,
|
||||
RESET_COUNTER,
|
||||
RUN,
|
||||
RUN_ACTIONS,
|
||||
STOP,
|
||||
DISABLE_ACTION,
|
||||
ENABLE_ACTION,
|
||||
TOGGLE_ACTION,
|
||||
TOGGLE_PAUSE,
|
||||
NESTED_MACRO,
|
||||
};
|
||||
Action _action = Action::RUN;
|
||||
|
||||
enum class SelectionType { INDEX, LABEL, ID };
|
||||
|
||||
Action _action = Action::NESTED_MACRO;
|
||||
SelectionType _actionSelectionType = SelectionType::INDEX;
|
||||
bool _useElseSection = false;
|
||||
IntVariable _actionIndex = 1;
|
||||
StringVariable _label = "Custom label";
|
||||
std::string _actionId;
|
||||
RegexConfig _regex;
|
||||
RunOptions _runOptions = {};
|
||||
std::shared_ptr<Macro> _nestedMacro = std::make_shared<Macro>();
|
||||
int _customWidgetHeight = 0;
|
||||
|
||||
private:
|
||||
void RunActions(Macro *actionMacro) const;
|
||||
void AdjustActionState(Macro *) const;
|
||||
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
class MacroActionMacroEdit final : public QWidget {
|
||||
class MacroActionMacroEdit final : public ResizableWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
|
@ -70,22 +88,20 @@ public:
|
|||
std::shared_ptr<MacroActionMacro> entryData = nullptr);
|
||||
~MacroActionMacroEdit();
|
||||
void UpdateEntryData();
|
||||
static QWidget *Create(QWidget *parent,
|
||||
std::shared_ptr<MacroAction> action)
|
||||
{
|
||||
return new MacroActionMacroEdit(
|
||||
parent,
|
||||
std::dynamic_pointer_cast<MacroActionMacro>(action));
|
||||
}
|
||||
static QWidget *Create(QWidget *, std::shared_ptr<MacroAction>);
|
||||
|
||||
private slots:
|
||||
void MacroChanged(const QString &text);
|
||||
void ActionChanged(int value);
|
||||
void ActionSelectionTypeChanged(int value);
|
||||
void ActionIndexChanged(const IntVariable &value);
|
||||
void LabelChanged();
|
||||
void ActionTypeChanged(int value);
|
||||
void RegexChanged(const RegexConfig &);
|
||||
void ConditionMacroChanged(const QString &text);
|
||||
void ConditionBehaviorChanged(int value);
|
||||
void ReevaluateConditionStateChanged(int value);
|
||||
void ActionTypeChanged(int value);
|
||||
void ActionSectionChanged(int value);
|
||||
void SkipWhenPausedChanged(int value);
|
||||
void SetInputsChanged(int value);
|
||||
void InputsChanged(const StringList &);
|
||||
|
|
@ -97,13 +113,17 @@ private:
|
|||
void SetWidgetVisibility();
|
||||
void SetupMacroInput(Macro *) const;
|
||||
|
||||
MacroSelection *_macros;
|
||||
MacroSegmentSelection *_actionIndex;
|
||||
QComboBox *_actions;
|
||||
MacroSelection *_macros;
|
||||
QComboBox *_actionSelectionType;
|
||||
MacroSegmentSelection *_actionIndex;
|
||||
VariableLineEdit *_label;
|
||||
FilterComboBox *_actionTypes;
|
||||
RegexConfigWidget *_regex;
|
||||
MacroSelection *_conditionMacros;
|
||||
QComboBox *_conditionBehaviors;
|
||||
QCheckBox *_reevaluateConditionState;
|
||||
QComboBox *_actionTypes;
|
||||
QComboBox *_actionSections;
|
||||
QCheckBox *_skipWhenPaused;
|
||||
QCheckBox *_setInputs;
|
||||
MacroInputEdit *_inputs;
|
||||
|
|
@ -111,6 +131,7 @@ private:
|
|||
QHBoxLayout *_conditionLayout;
|
||||
QHBoxLayout *_reevaluateConditionStateLayout;
|
||||
QHBoxLayout *_setInputsLayout;
|
||||
MacroEdit *_nestedMacro;
|
||||
|
||||
std::shared_ptr<MacroActionMacro> _entryData;
|
||||
bool _loading = true;
|
||||
|
|
|
|||
|
|
@ -170,11 +170,7 @@ void MacroActionQueueEdit::UpdateEntryData()
|
|||
|
||||
void MacroActionQueueEdit::MacroChanged(const QString &text)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_macro = text;
|
||||
emit HeaderInfoChanged(
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
|
|
@ -182,11 +178,7 @@ void MacroActionQueueEdit::MacroChanged(const QString &text)
|
|||
|
||||
void MacroActionQueueEdit::QueueChanged(const QString &text)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_queue = GetWeakActionQueueByQString(text);
|
||||
emit HeaderInfoChanged(
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
|
|
@ -194,11 +186,7 @@ void MacroActionQueueEdit::QueueChanged(const QString &text)
|
|||
|
||||
void MacroActionQueueEdit::ActionChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_action = static_cast<MacroActionQueue::Action>(value);
|
||||
SetWidgetVisibility();
|
||||
emit HeaderInfoChanged(
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -6,6 +6,7 @@
|
|||
#include "resizing-text-edit.hpp"
|
||||
#include "scene-selection.hpp"
|
||||
#include "single-char-selection.hpp"
|
||||
#include "string-list.hpp"
|
||||
#include "variable-line-edit.hpp"
|
||||
#include "variable-text-edit.hpp"
|
||||
#include "variable-spinbox.hpp"
|
||||
|
|
@ -28,8 +29,8 @@ public:
|
|||
int GetSegmentIndexValue() const;
|
||||
void ResolveVariablesToFixedValues();
|
||||
|
||||
enum class Type {
|
||||
SET_FIXED_VALUE,
|
||||
enum class Action {
|
||||
SET_VALUE,
|
||||
APPEND,
|
||||
APPEND_VAR,
|
||||
INCREMENT,
|
||||
|
|
@ -52,18 +53,23 @@ public:
|
|||
SWAP_VALUES,
|
||||
TRIM,
|
||||
CHANGE_CASE,
|
||||
RANDOM_NUMBER,
|
||||
QUERY_JSON,
|
||||
ARRAY_JSON,
|
||||
COPY_VAR,
|
||||
RANDOM_LIST_VALUE,
|
||||
};
|
||||
|
||||
Type _type = Type::SET_FIXED_VALUE;
|
||||
Action _action = Action::SET_VALUE;
|
||||
std::weak_ptr<Variable> _variable;
|
||||
std::weak_ptr<Variable> _variable2;
|
||||
StringVariable _strValue = "";
|
||||
double _numValue = 0;
|
||||
int _subStringStart = 0;
|
||||
int _subStringSize = 0;
|
||||
DoubleVariable _numValue = 0;
|
||||
IntVariable _subStringStart = 0;
|
||||
IntVariable _subStringSize = 0;
|
||||
RegexConfig _subStringRegex = RegexConfig::PartialMatchRegexConfig();
|
||||
std::string _regexPattern = ".*";
|
||||
int _regexMatchIdx = 0;
|
||||
IntVariable _regexMatchIdx = 0;
|
||||
RegexConfig _findRegex;
|
||||
StringVariable _findStr = obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.findAndReplace.find");
|
||||
|
|
@ -99,6 +105,16 @@ public:
|
|||
};
|
||||
|
||||
CaseType _caseType = CaseType::LOWER_CASE;
|
||||
DoubleVariable _randomNumberStart = 0;
|
||||
DoubleVariable _randomNumberEnd = 100;
|
||||
bool _generateInteger = true;
|
||||
|
||||
StringList _randomValues = {"value1", "value2", "value3"};
|
||||
bool _allowRepeatValues = true;
|
||||
std::optional<std::string> _lastRandomValue;
|
||||
|
||||
StringVariable _jsonQuery = "$.some.nested.value";
|
||||
IntVariable _jsonIndex = 0;
|
||||
|
||||
private:
|
||||
void DecrementCurrentSegmentVariableRef();
|
||||
|
|
@ -108,6 +124,8 @@ private:
|
|||
void HandleMathExpression(Variable *);
|
||||
void HandleCaseChange(Variable *);
|
||||
void SetToSceneItemName(Variable *);
|
||||
void GenerateRandomNumber(Variable *);
|
||||
void PickRandomValue(Variable *);
|
||||
|
||||
std::weak_ptr<MacroSegment> _macroSegment;
|
||||
int _segmentIdxLoadValue = -1;
|
||||
|
|
@ -136,15 +154,15 @@ private slots:
|
|||
void Variable2Changed(const QString &);
|
||||
void ActionChanged(int);
|
||||
void StrValueChanged();
|
||||
void NumValueChanged(double);
|
||||
void NumValueChanged(const NumberVariable<double> &value);
|
||||
void SegmentIndexChanged(const IntVariable &);
|
||||
void UpdateSegmentVariableValue();
|
||||
void MacroSegmentOrderChanged();
|
||||
void SubStringStartChanged(int val);
|
||||
void SubStringSizeChanged(int val);
|
||||
void SubStringStartChanged(const NumberVariable<int> &start);
|
||||
void SubStringSizeChanged(const NumberVariable<int> &size);
|
||||
void SubStringRegexChanged(const RegexConfig &conf);
|
||||
void RegexPatternChanged();
|
||||
void RegexMatchIdxChanged(int val);
|
||||
void RegexMatchIdxChanged(const NumberVariable<int> &index);
|
||||
void FindStrValueChanged();
|
||||
void FindRegexChanged(const RegexConfig &conf);
|
||||
void ReplaceStrValueChanged();
|
||||
|
|
@ -161,6 +179,13 @@ private slots:
|
|||
void StringLengthChanged(const NumberVariable<int> &);
|
||||
void CharSelectionChanged(const QString &);
|
||||
void CaseTypeChanged(int index);
|
||||
void RandomNumberStartChanged(const NumberVariable<double> &);
|
||||
void RandomNumberEndChanged(const NumberVariable<double> &);
|
||||
void GenerateIntegerChanged(int);
|
||||
void RandomValueListChanged(const StringList &);
|
||||
void AllowRepeatValuesChanged(int);
|
||||
void JsonQueryChanged();
|
||||
void JsonIndexChanged(const NumberVariable<int> &);
|
||||
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
|
|
@ -173,18 +198,17 @@ private:
|
|||
VariableSelection *_variables2;
|
||||
FilterComboBox *_actions;
|
||||
VariableTextEdit *_strValue;
|
||||
QDoubleSpinBox *_numValue;
|
||||
VariableDoubleSpinBox *_numValue;
|
||||
MacroSegmentSelection *_segmentIdx;
|
||||
QLabel *_segmentValueStatus;
|
||||
ResizingPlainTextEdit *_segmentValue;
|
||||
QVBoxLayout *_substringLayout;
|
||||
QHBoxLayout *_subStringIndexEntryLayout;
|
||||
QHBoxLayout *_subStringRegexEntryLayout;
|
||||
QSpinBox *_subStringStart;
|
||||
QSpinBox *_subStringSize;
|
||||
RegexConfigWidget *_substringRegex;
|
||||
QHBoxLayout *_subStringControlsLayout;
|
||||
VariableSpinBox *_subStringStart;
|
||||
VariableSpinBox *_subStringSize;
|
||||
RegexConfigWidget *_subStringRegex;
|
||||
ResizingPlainTextEdit *_regexPattern;
|
||||
QSpinBox *_regexMatchIdx;
|
||||
VariableSpinBox *_regexMatchIdx;
|
||||
QHBoxLayout *_findReplaceLayout;
|
||||
RegexConfigWidget *_findRegex;
|
||||
VariableTextEdit *_findStr;
|
||||
|
|
@ -206,6 +230,16 @@ private:
|
|||
VariableSpinBox *_stringLength;
|
||||
SingleCharSelection *_paddingCharSelection;
|
||||
FilterComboBox *_caseType;
|
||||
VariableDoubleSpinBox *_randomNumberStart;
|
||||
VariableDoubleSpinBox *_randomNumberEnd;
|
||||
QCheckBox *_generateInteger;
|
||||
QVBoxLayout *_randomNumberLayout;
|
||||
StringListEdit *_randomValues;
|
||||
QCheckBox *_allowRepeatValues;
|
||||
QVBoxLayout *_randomValueLayout;
|
||||
VariableLineEdit *_jsonQuery;
|
||||
QLabel *_jsonQueryHelp;
|
||||
VariableSpinBox *_jsonIndex;
|
||||
QHBoxLayout *_entryLayout;
|
||||
|
||||
std::shared_ptr<MacroActionVariable> _entryData;
|
||||
|
|
|
|||
|
|
@ -11,15 +11,12 @@ bool MacroAction::Save(obs_data_t *obj) const
|
|||
{
|
||||
MacroSegment::Save(obj);
|
||||
obs_data_set_string(obj, "id", GetId().c_str());
|
||||
obs_data_set_bool(obj, "enabled", _enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacroAction::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroSegment::Load(obj);
|
||||
obs_data_set_default_bool(obj, "enabled", true);
|
||||
_enabled = obs_data_get_bool(obj, "enabled");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -28,16 +25,6 @@ void MacroAction::LogAction() const
|
|||
ablog(LOG_INFO, "performed action %s", GetId().c_str());
|
||||
}
|
||||
|
||||
void MacroAction::SetEnabled(bool value)
|
||||
{
|
||||
_enabled = value;
|
||||
}
|
||||
|
||||
bool MacroAction::Enabled() const
|
||||
{
|
||||
return _enabled;
|
||||
}
|
||||
|
||||
void MacroAction::ResolveVariablesToFixedValues() {}
|
||||
|
||||
std::string_view MacroAction::GetDefaultID()
|
||||
|
|
|
|||
|
|
@ -19,13 +19,9 @@ public:
|
|||
// Used to resolve variables before actions are added to action queues
|
||||
virtual void ResolveVariablesToFixedValues();
|
||||
|
||||
void SetEnabled(bool);
|
||||
bool Enabled() const;
|
||||
|
||||
static std::string_view GetDefaultID();
|
||||
|
||||
private:
|
||||
bool _enabled = true;
|
||||
};
|
||||
|
||||
class EXPORT MacroRefAction : virtual public MacroAction {
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ void DurationModifierEdit::Collapse(bool collapse)
|
|||
|
||||
MacroConditionEdit::MacroConditionEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroCondition> *entryData,
|
||||
const std::string &id, bool isRootCondition)
|
||||
bool isRootCondition)
|
||||
: MacroSegmentEdit(parent),
|
||||
_logicSelection(new QComboBox()),
|
||||
_conditionSelection(new FilterComboBox()),
|
||||
|
|
@ -138,7 +138,7 @@ MacroConditionEdit::MacroConditionEdit(
|
|||
mainLayout->addWidget(_frame);
|
||||
setLayout(mainLayout);
|
||||
|
||||
UpdateEntryData(id);
|
||||
SetupWidgets(true);
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
|
|
@ -152,9 +152,11 @@ void MacroConditionEdit::LogicSelectionChanged(int idx)
|
|||
const auto logic = static_cast<Logic::Type>(
|
||||
_logicSelection->itemData(idx).toInt());
|
||||
(*_entryData)->SetLogicType(logic);
|
||||
|
||||
SetEnableAppearance(logic != Logic::Type::NONE);
|
||||
}
|
||||
|
||||
bool MacroConditionEdit::IsRootNode()
|
||||
bool MacroConditionEdit::IsRootNode() const
|
||||
{
|
||||
return _isRoot;
|
||||
}
|
||||
|
|
@ -164,6 +166,7 @@ void MacroConditionEdit::SetLogicSelection()
|
|||
const auto logic = (*_entryData)->GetLogicType();
|
||||
_logicSelection->setCurrentIndex(
|
||||
_logicSelection->findData(static_cast<int>(logic)));
|
||||
SetEnableAppearance(logic != Logic::Type::NONE);
|
||||
}
|
||||
|
||||
void MacroConditionEdit::SetRootNode(bool root)
|
||||
|
|
@ -175,23 +178,36 @@ void MacroConditionEdit::SetRootNode(bool root)
|
|||
SetLogicSelection();
|
||||
}
|
||||
|
||||
void MacroConditionEdit::UpdateEntryData(const std::string &id)
|
||||
void MacroConditionEdit::SetupWidgets(bool basicSetup)
|
||||
{
|
||||
if (_allWidgetsAreSetup) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto id = (*_entryData)->GetId();
|
||||
_conditionSelection->setCurrentText(obs_module_text(
|
||||
MacroConditionFactory::GetConditionName(id).c_str()));
|
||||
auto widget =
|
||||
MacroConditionFactory::CreateWidget(id, this, *_entryData);
|
||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||
this, SLOT(HeaderInfoChanged(const QString &)));
|
||||
|
||||
HeaderInfoChanged(
|
||||
QString::fromStdString((*_entryData)->GetShortDesc()));
|
||||
SetLogicSelection();
|
||||
_section->SetContent(widget, (*_entryData)->GetCollapsed());
|
||||
|
||||
_dur->setVisible(MacroConditionFactory::UsesDurationModifier(id));
|
||||
auto modifier = (*_entryData)->GetDurationModifier();
|
||||
_dur->SetValue(modifier);
|
||||
|
||||
if (basicSetup) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto widget =
|
||||
MacroConditionFactory::CreateWidget(id, this, *_entryData);
|
||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||
this, SLOT(HeaderInfoChanged(const QString &)));
|
||||
_section->SetContent(widget, (*_entryData)->GetCollapsed());
|
||||
SetFocusPolicyOfWidgets();
|
||||
|
||||
_allWidgetsAreSetup = true;
|
||||
}
|
||||
|
||||
void MacroConditionEdit::SetEntryData(std::shared_ptr<MacroCondition> *data)
|
||||
|
|
@ -223,7 +239,7 @@ void MacroConditionEdit::ConditionSelectionChanged(const QString &text)
|
|||
(*_entryData)->SetIndex(idx);
|
||||
(*_entryData)->SetLogicType(logic);
|
||||
(*_entryData)->PostLoad();
|
||||
RunPostLoadSteps();
|
||||
RunAndClearPostLoadSteps();
|
||||
}
|
||||
auto widget =
|
||||
MacroConditionFactory::CreateWidget(id, this, *_entryData);
|
||||
|
|
@ -259,289 +275,4 @@ std::shared_ptr<MacroSegment> MacroConditionEdit::Data() const
|
|||
return *_entryData;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::AddMacroCondition(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 0 || idx > (int)macro->Conditions().size()) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string id;
|
||||
Logic::Type logic;
|
||||
if (idx >= 1) {
|
||||
id = macro->Conditions().at(idx - 1)->GetId();
|
||||
if (idx == 1) {
|
||||
logic = Logic::Type::OR;
|
||||
} else {
|
||||
logic = macro->Conditions().at(idx - 1)->GetLogicType();
|
||||
}
|
||||
} else {
|
||||
id = MacroCondition::GetDefaultID();
|
||||
logic = Logic::Type::ROOT_NONE;
|
||||
}
|
||||
|
||||
OBSDataAutoRelease data;
|
||||
if (idx - 1 >= 0) {
|
||||
data = obs_data_create();
|
||||
macro->Conditions().at(idx - 1)->Save(data);
|
||||
}
|
||||
AddMacroCondition(macro.get(), idx, id, data.Get(), logic);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::AddMacroCondition(Macro *macro, int idx,
|
||||
const std::string &id,
|
||||
obs_data_t *data, Logic::Type logic)
|
||||
{
|
||||
if (idx < 0 || idx > (int)macro->Conditions().size()) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
auto lock = LockContext();
|
||||
auto cond = macro->Conditions().emplace(
|
||||
macro->Conditions().begin() + idx,
|
||||
MacroConditionFactory::Create(id, macro));
|
||||
if (data) {
|
||||
macro->Conditions().at(idx)->Load(data);
|
||||
}
|
||||
macro->Conditions().at(idx)->PostLoad();
|
||||
RunPostLoadSteps();
|
||||
(*cond)->SetLogicType(logic);
|
||||
macro->UpdateConditionIndices();
|
||||
ui->conditionsList->Insert(
|
||||
idx,
|
||||
new MacroConditionEdit(this, ¯o->Conditions()[idx],
|
||||
id, idx == 0));
|
||||
SetConditionData(*macro);
|
||||
}
|
||||
HighlightCondition(idx);
|
||||
ui->conditionsList->SetHelpMsgVisible(false);
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_conditionAdd_clicked()
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentConditionIdx == -1) {
|
||||
AddMacroCondition((int)macro->Conditions().size());
|
||||
} else {
|
||||
AddMacroCondition(currentConditionIdx + 1);
|
||||
}
|
||||
if (currentConditionIdx != -1) {
|
||||
MacroConditionSelectionChanged(currentConditionIdx + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::RemoveMacroCondition(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 0 || idx >= (int)macro->Conditions().size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
auto lock = LockContext();
|
||||
ui->conditionsList->Remove(idx);
|
||||
macro->Conditions().erase(macro->Conditions().begin() + idx);
|
||||
macro->UpdateConditionIndices();
|
||||
if (idx == 0 && macro->Conditions().size() > 0) {
|
||||
auto newRoot = macro->Conditions().at(0);
|
||||
newRoot->SetLogicType(Logic::Type::ROOT_NONE);
|
||||
static_cast<MacroConditionEdit *>(
|
||||
ui->conditionsList->WidgetAt(0))
|
||||
->SetRootNode(true);
|
||||
}
|
||||
SetConditionData(*macro);
|
||||
}
|
||||
MacroConditionSelectionChanged(-1);
|
||||
lastInteracted = MacroSection::CONDITIONS;
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_conditionRemove_clicked()
|
||||
{
|
||||
if (currentConditionIdx == -1) {
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
RemoveMacroCondition((int)macro->Conditions().size() - 1);
|
||||
} else {
|
||||
RemoveMacroCondition(currentConditionIdx);
|
||||
}
|
||||
MacroConditionSelectionChanged(-1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_conditionTop_clicked()
|
||||
{
|
||||
if (currentConditionIdx == -1) {
|
||||
return;
|
||||
}
|
||||
MacroConditionReorder(0, currentConditionIdx);
|
||||
MacroConditionSelectionChanged(0);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_conditionUp_clicked()
|
||||
{
|
||||
if (currentConditionIdx == -1 || currentConditionIdx == 0) {
|
||||
return;
|
||||
}
|
||||
MoveMacroConditionUp(currentConditionIdx);
|
||||
MacroConditionSelectionChanged(currentConditionIdx - 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_conditionDown_clicked()
|
||||
{
|
||||
if (currentConditionIdx == -1 ||
|
||||
currentConditionIdx ==
|
||||
ui->conditionsList->ContentLayout()->count() - 1) {
|
||||
return;
|
||||
}
|
||||
MoveMacroConditionDown(currentConditionIdx);
|
||||
MacroConditionSelectionChanged(currentConditionIdx + 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_conditionBottom_clicked()
|
||||
{
|
||||
if (currentConditionIdx == -1) {
|
||||
return;
|
||||
}
|
||||
const int newIdx = ui->conditionsList->ContentLayout()->count() - 1;
|
||||
MacroConditionReorder(newIdx, currentConditionIdx);
|
||||
MacroConditionSelectionChanged(newIdx);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::SwapConditions(Macro *m, int pos1, int pos2)
|
||||
{
|
||||
if (pos1 == pos2) {
|
||||
return;
|
||||
}
|
||||
if (pos1 > pos2) {
|
||||
std::swap(pos1, pos2);
|
||||
}
|
||||
|
||||
bool root = pos1 == 0;
|
||||
auto lock = LockContext();
|
||||
iter_swap(m->Conditions().begin() + pos1,
|
||||
m->Conditions().begin() + pos2);
|
||||
m->UpdateConditionIndices();
|
||||
|
||||
auto c1 = m->Conditions().begin() + pos1;
|
||||
auto c2 = m->Conditions().begin() + pos2;
|
||||
if (root) {
|
||||
auto logic1 = (*c1)->GetLogicType();
|
||||
auto logic2 = (*c2)->GetLogicType();
|
||||
(*c1)->SetLogicType(logic2);
|
||||
(*c2)->SetLogicType(logic1);
|
||||
}
|
||||
|
||||
auto widget1 = static_cast<MacroConditionEdit *>(
|
||||
ui->conditionsList->ContentLayout()->takeAt(pos1)->widget());
|
||||
auto widget2 = static_cast<MacroConditionEdit *>(
|
||||
ui->conditionsList->ContentLayout()->takeAt(pos2 - 1)->widget());
|
||||
ui->conditionsList->Insert(pos1, widget2);
|
||||
ui->conditionsList->Insert(pos2, widget1);
|
||||
SetConditionData(*m);
|
||||
widget2->SetRootNode(root);
|
||||
widget1->SetRootNode(false);
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MoveMacroConditionUp(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 1 || idx >= (int)macro->Conditions().size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SwapConditions(macro.get(), idx, idx - 1);
|
||||
HighlightCondition(idx - 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MoveMacroConditionDown(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 0 || idx >= (int)macro->Conditions().size() - 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
SwapConditions(macro.get(), idx, idx + 1);
|
||||
HighlightCondition(idx + 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MacroConditionSelectionChanged(int idx)
|
||||
{
|
||||
SetupMacroSegmentSelection(MacroSection::CONDITIONS, idx);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MacroConditionReorder(int to, int from)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (to == from || from < 0 || from > (int)macro->Conditions().size() ||
|
||||
to < 0 || to > (int)macro->Conditions().size()) {
|
||||
return;
|
||||
}
|
||||
{
|
||||
auto lock = LockContext();
|
||||
auto condition = macro->Conditions().at(from);
|
||||
if (to == 0) {
|
||||
condition->SetLogicType(Logic::Type::ROOT_NONE);
|
||||
static_cast<MacroConditionEdit *>(
|
||||
ui->conditionsList->WidgetAt(from))
|
||||
->SetRootNode(true);
|
||||
macro->Conditions().at(0)->SetLogicType(
|
||||
Logic::Type::AND);
|
||||
static_cast<MacroConditionEdit *>(
|
||||
ui->conditionsList->WidgetAt(0))
|
||||
->SetRootNode(false);
|
||||
}
|
||||
if (from == 0) {
|
||||
condition->SetLogicType(Logic::Type::AND);
|
||||
static_cast<MacroConditionEdit *>(
|
||||
ui->conditionsList->WidgetAt(from))
|
||||
->SetRootNode(false);
|
||||
macro->Conditions().at(1)->SetLogicType(
|
||||
Logic::Type::ROOT_NONE);
|
||||
static_cast<MacroConditionEdit *>(
|
||||
ui->conditionsList->WidgetAt(1))
|
||||
->SetRootNode(true);
|
||||
}
|
||||
macro->Conditions().erase(macro->Conditions().begin() + from);
|
||||
macro->Conditions().insert(macro->Conditions().begin() + to,
|
||||
condition);
|
||||
macro->UpdateConditionIndices();
|
||||
ui->conditionsList->ContentLayout()->insertItem(
|
||||
to, ui->conditionsList->ContentLayout()->takeAt(from));
|
||||
SetConditionData(*macro);
|
||||
}
|
||||
HighlightCondition(to);
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
|
|
|||
|
|
@ -34,14 +34,12 @@ class MacroConditionEdit : public MacroSegmentEdit {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MacroConditionEdit(
|
||||
QWidget *parent = nullptr,
|
||||
std::shared_ptr<MacroCondition> * = nullptr,
|
||||
const std::string &id = MacroCondition::GetDefaultID().data(),
|
||||
bool root = true);
|
||||
bool IsRootNode();
|
||||
MacroConditionEdit(QWidget *parent = nullptr,
|
||||
std::shared_ptr<MacroCondition> * = nullptr,
|
||||
bool root = true);
|
||||
bool IsRootNode() const;
|
||||
void SetRootNode(bool);
|
||||
void UpdateEntryData(const std::string &id);
|
||||
void SetupWidgets(bool basicSetup = false);
|
||||
void SetEntryData(std::shared_ptr<MacroCondition> *);
|
||||
|
||||
private slots:
|
||||
|
|
|
|||
|
|
@ -1,21 +1,11 @@
|
|||
#include "macro-condition-factory.hpp"
|
||||
#include "macro-segment-unknown.hpp"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
namespace advss {
|
||||
|
||||
namespace {
|
||||
|
||||
class MacroConditionUnknown : public MacroCondition {
|
||||
public:
|
||||
MacroConditionUnknown(Macro *m) : MacroCondition(m) {}
|
||||
bool CheckCondition() { return false; }
|
||||
bool Save(obs_data_t *obj) const { return MacroCondition::Save(obj); };
|
||||
bool Load(obs_data_t *obj) { return MacroCondition::Load(obj); };
|
||||
std::string GetId() const { return "unknown"; }
|
||||
};
|
||||
|
||||
} // namespace
|
||||
using MacroConditionUnknown = MacroSegmentUnknown<MacroCondition>;
|
||||
|
||||
static std::recursive_mutex mutex;
|
||||
|
||||
|
|
@ -46,9 +36,10 @@ bool MacroConditionFactory::Deregister(const std::string &id)
|
|||
return true;
|
||||
}
|
||||
|
||||
static std::shared_ptr<MacroCondition> createUnknownCondition(Macro *m)
|
||||
static std::shared_ptr<MacroCondition>
|
||||
createUnknownCondition(Macro *m, const std::string &id)
|
||||
{
|
||||
return std::make_shared<MacroConditionUnknown>(m);
|
||||
return std::make_shared<MacroConditionUnknown>(m, id);
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroCondition>
|
||||
|
|
@ -58,13 +49,7 @@ MacroConditionFactory::Create(const std::string &id, Macro *m)
|
|||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||
return it->second._create(m);
|
||||
}
|
||||
return createUnknownCondition(m);
|
||||
}
|
||||
|
||||
static QWidget *createUnknownConditionWidget()
|
||||
{
|
||||
return new QLabel(
|
||||
obs_module_text("AdvSceneSwitcher.condition.unknown"));
|
||||
return createUnknownCondition(m, id);
|
||||
}
|
||||
|
||||
QWidget *
|
||||
|
|
@ -75,7 +60,7 @@ MacroConditionFactory::CreateWidget(const std::string &id, QWidget *parent,
|
|||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||
return it->second._createWidget(parent, cond);
|
||||
}
|
||||
return createUnknownConditionWidget();
|
||||
return CreateUnknownSegmentWidget(false);
|
||||
}
|
||||
|
||||
std::string MacroConditionFactory::GetConditionName(const std::string &id)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class MacroConditionFactory {
|
|||
public:
|
||||
MacroConditionFactory() = delete;
|
||||
EXPORT static bool Register(const std::string &, MacroConditionInfo);
|
||||
static bool Deregister(const std::string &);
|
||||
EXPORT static bool Deregister(const std::string &);
|
||||
static std::shared_ptr<MacroCondition> Create(const std::string &,
|
||||
Macro *m);
|
||||
static QWidget *CreateWidget(const std::string &id, QWidget *parent,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "macro-condition-macro.hpp"
|
||||
#include "layout-helpers.hpp"
|
||||
#include "macro-action-edit.hpp"
|
||||
#include "macro-signals.hpp"
|
||||
#include "macro.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
|
@ -26,6 +27,8 @@ const static std::map<MacroConditionMacro::Type, std::string>
|
|||
"AdvSceneSwitcher.condition.macro.type.actionEnabled"},
|
||||
{MacroConditionMacro::Type::PAUSED,
|
||||
"AdvSceneSwitcher.condition.macro.type.paused"},
|
||||
{MacroConditionMacro::Type::ACTIONS_PERFORMED,
|
||||
"AdvSceneSwitcher.condition.macro.type.actionsPerformed"},
|
||||
};
|
||||
|
||||
const static std::map<MacroConditionMacro::CounterCondition, std::string>
|
||||
|
|
@ -99,7 +102,7 @@ bool MacroConditionMacro::CheckActionStateCondition()
|
|||
if (!macro) {
|
||||
return false;
|
||||
}
|
||||
if (!IsValidMacroSegmentIndex(macro.get(), _actionIndex - 1, false)) {
|
||||
if (!IsValidActionIndex(macro.get(), _actionIndex - 1)) {
|
||||
return false;
|
||||
}
|
||||
if (_type == Type::ACTION_DISABLED) {
|
||||
|
|
@ -121,6 +124,16 @@ bool MacroConditionMacro::CheckPauseState()
|
|||
return macro->Paused();
|
||||
}
|
||||
|
||||
bool MacroConditionMacro::CheckActionsPerformed()
|
||||
{
|
||||
auto macro = _macro.GetMacro();
|
||||
if (!macro) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return macro->WasExecutedSince(macro->LastConditionCheckTime());
|
||||
}
|
||||
|
||||
bool MacroConditionMacro::CheckCountCondition()
|
||||
{
|
||||
auto macro = _macro.GetMacro();
|
||||
|
|
@ -158,6 +171,8 @@ bool MacroConditionMacro::CheckCondition()
|
|||
return CheckActionStateCondition();
|
||||
case Type::PAUSED:
|
||||
return CheckPauseState();
|
||||
case Type::ACTIONS_PERFORMED:
|
||||
return CheckActionsPerformed();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -300,6 +315,7 @@ MacroConditionMacroEdit::MacroConditionMacroEdit(
|
|||
_actionIndex(new MacroSegmentSelection(
|
||||
this, MacroSegmentSelection::Type::ACTION))
|
||||
{
|
||||
_macros->HideGroups();
|
||||
_count->setMaximum(10000000);
|
||||
populateTypeSelection(_types);
|
||||
populateCounterConditionSelection(_counterConditions);
|
||||
|
|
@ -307,7 +323,8 @@ MacroConditionMacroEdit::MacroConditionMacroEdit(
|
|||
|
||||
QWidget::connect(_macros, SIGNAL(currentTextChanged(const QString &)),
|
||||
this, SLOT(MacroChanged(const QString &)));
|
||||
QWidget::connect(parent, SIGNAL(MacroRemoved(const QString &)), this,
|
||||
QWidget::connect(MacroSignalManager::Instance(),
|
||||
SIGNAL(Remove(const QString &)), this,
|
||||
SLOT(MacroRemove(const QString &)));
|
||||
QWidget::connect(_types, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(TypeChanged(int)));
|
||||
|
|
@ -414,6 +431,9 @@ void MacroConditionMacroEdit::SetupWidgets()
|
|||
case MacroConditionMacro::Type::PAUSED:
|
||||
SetupPauseWidgets();
|
||||
break;
|
||||
case MacroConditionMacro::Type::ACTIONS_PERFORMED:
|
||||
SetupActionsPerformedWidgets();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -472,6 +492,14 @@ void MacroConditionMacroEdit::SetupPauseWidgets()
|
|||
_settingsLine1, {{"{{macros}}", _macros}});
|
||||
}
|
||||
|
||||
void MacroConditionMacroEdit::SetupActionsPerformedWidgets()
|
||||
{
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.condition.macro.actionsPerformed.entry"),
|
||||
_settingsLine1, {{"{{macros}}", _macros}});
|
||||
}
|
||||
|
||||
void MacroConditionMacroEdit::SetWidgetVisibility()
|
||||
{
|
||||
_macros->setVisible(
|
||||
|
|
@ -481,7 +509,9 @@ void MacroConditionMacroEdit::SetWidgetVisibility()
|
|||
MacroConditionMacro::Type::ACTION_DISABLED ||
|
||||
_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::ACTION_ENABLED ||
|
||||
_entryData->GetType() == MacroConditionMacro::Type::PAUSED);
|
||||
_entryData->GetType() == MacroConditionMacro::Type::PAUSED ||
|
||||
_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::ACTIONS_PERFORMED);
|
||||
_counterConditions->setVisible(_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::COUNT);
|
||||
_count->setVisible(_entryData->GetType() ==
|
||||
|
|
@ -538,11 +568,7 @@ void MacroConditionMacroEdit::UpdateEntryData()
|
|||
|
||||
void MacroConditionMacroEdit::MacroChanged(const QString &text)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_macro = text;
|
||||
_actionIndex->SetMacro(_entryData->_macro.GetMacro());
|
||||
emit HeaderInfoChanged(
|
||||
|
|
@ -551,21 +577,13 @@ void MacroConditionMacroEdit::MacroChanged(const QString &text)
|
|||
|
||||
void MacroConditionMacroEdit::CountChanged(const NumberVariable<int> &value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_count = value;
|
||||
}
|
||||
|
||||
void MacroConditionMacroEdit::CountConditionChanged(int cond)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_counterCondition =
|
||||
static_cast<MacroConditionMacro::CounterCondition>(cond);
|
||||
}
|
||||
|
|
@ -590,11 +608,7 @@ void MacroConditionMacroEdit::MacroRemove(const QString &)
|
|||
|
||||
void MacroConditionMacroEdit::TypeChanged(int type)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->SetType(static_cast<MacroConditionMacro::Type>(type));
|
||||
SetupWidgets();
|
||||
}
|
||||
|
|
@ -640,11 +654,7 @@ void MacroConditionMacroEdit::UpdatePaused()
|
|||
|
||||
void MacroConditionMacroEdit::MultiStateConditionChanged(int cond)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_multiSateCondition =
|
||||
static_cast<MacroConditionMacro::MultiStateCondition>(cond);
|
||||
}
|
||||
|
|
@ -652,21 +662,13 @@ void MacroConditionMacroEdit::MultiStateConditionChanged(int cond)
|
|||
void MacroConditionMacroEdit::MultiStateCountChanged(
|
||||
const NumberVariable<int> &value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_multiSateCount = value;
|
||||
}
|
||||
|
||||
void MacroConditionMacroEdit::Add(const std::string &name)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
MacroRef macro(name);
|
||||
_entryData->_macros.push_back(macro);
|
||||
adjustSize();
|
||||
|
|
@ -675,11 +677,7 @@ void MacroConditionMacroEdit::Add(const std::string &name)
|
|||
|
||||
void MacroConditionMacroEdit::Remove(int idx)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_macros.erase(std::next(_entryData->_macros.begin(), idx));
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
|
|
@ -687,12 +685,8 @@ void MacroConditionMacroEdit::Remove(int idx)
|
|||
|
||||
void MacroConditionMacroEdit::Replace(int idx, const std::string &name)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
MacroRef macro(name);
|
||||
auto lock = LockContext();
|
||||
_entryData->_macros[idx] = macro;
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
|
|
@ -700,11 +694,7 @@ void MacroConditionMacroEdit::Replace(int idx, const std::string &name)
|
|||
|
||||
void MacroConditionMacroEdit::ActionIndexChanged(const IntVariable &value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_actionIndex = value;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
#include <QPushButton>
|
||||
#include <QHBoxLayout>
|
||||
#include <QTimer>
|
||||
#include <QListWidget>
|
||||
|
||||
namespace advss {
|
||||
|
||||
|
|
@ -40,6 +39,7 @@ public:
|
|||
ACTION_DISABLED,
|
||||
ACTION_ENABLED,
|
||||
PAUSED,
|
||||
ACTIONS_PERFORMED,
|
||||
};
|
||||
void SetType(Type);
|
||||
Type GetType() const { return _type; }
|
||||
|
|
@ -67,6 +67,7 @@ private:
|
|||
bool CheckMultiStateCondition();
|
||||
bool CheckActionStateCondition();
|
||||
bool CheckPauseState();
|
||||
bool CheckActionsPerformed();
|
||||
|
||||
void SetupTempVars();
|
||||
|
||||
|
|
@ -135,6 +136,7 @@ private:
|
|||
void SetupCountWidgets();
|
||||
void SetupActionStateWidgets(bool enable);
|
||||
void SetupPauseWidgets();
|
||||
void SetupActionsPerformedWidgets();
|
||||
void SetWidgetVisibility();
|
||||
bool _loading = true;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ bool MacroConditionQueue::CheckCondition()
|
|||
return false;
|
||||
}
|
||||
|
||||
SetTempVarValue("size", std::to_string(queue->Size()));
|
||||
SetTempVarValue("running", queue->IsRunning());
|
||||
|
||||
switch (_condition) {
|
||||
case Condition::STARTED:
|
||||
return queue->IsRunning();
|
||||
|
|
@ -63,6 +66,18 @@ std::string MacroConditionQueue::GetShortDesc() const
|
|||
return GetActionQueueName(_queue);
|
||||
}
|
||||
|
||||
void MacroConditionQueue::SetupTempVars()
|
||||
{
|
||||
MacroCondition::SetupTempVars();
|
||||
AddTempvar("size",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.queue.size"));
|
||||
AddTempvar(
|
||||
"running",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.queue.running"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.queue.running.description"));
|
||||
}
|
||||
|
||||
static inline void populateQueueTypeSelection(QComboBox *list)
|
||||
{
|
||||
for (const auto &[_, name] : conditionTypes) {
|
||||
|
|
@ -100,11 +115,7 @@ MacroConditionQueueEdit::MacroConditionQueueEdit(
|
|||
|
||||
void MacroConditionQueueEdit::ConditionChanged(int condition)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_condition =
|
||||
static_cast<MacroConditionQueue::Condition>(condition);
|
||||
emit HeaderInfoChanged(
|
||||
|
|
@ -114,11 +125,7 @@ void MacroConditionQueueEdit::ConditionChanged(int condition)
|
|||
|
||||
void MacroConditionQueueEdit::QueueChanged(const QString &text)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_queue = GetWeakActionQueueByQString(text);
|
||||
emit HeaderInfoChanged(
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
|
|
@ -126,11 +133,7 @@ void MacroConditionQueueEdit::QueueChanged(const QString &text)
|
|||
|
||||
void MacroConditionQueueEdit::SizeChanged(const NumberVariable<int> &value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_size = value;
|
||||
}
|
||||
|
||||
|
|
@ -141,6 +144,7 @@ void MacroConditionQueueEdit::UpdateEntryData()
|
|||
}
|
||||
_conditions->setCurrentIndex(static_cast<int>(_entryData->_condition));
|
||||
_queues->SetActionQueue(_entryData->_queue);
|
||||
_size->SetValue(_entryData->_size);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ public:
|
|||
IntVariable _size = 1;
|
||||
|
||||
private:
|
||||
void SetupTempVars();
|
||||
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ bool MacroConditionTempVar::CheckCondition()
|
|||
bool MacroConditionTempVar::Save(obs_data_t *obj) const
|
||||
{
|
||||
MacroCondition::Save(obj);
|
||||
_tempVar.Save(obj);
|
||||
_tempVar.Save(obj, GetMacro());
|
||||
obs_data_set_string(obj, "variableName",
|
||||
GetWeakVariableName(_variable2).c_str());
|
||||
_strValue.Save(obj, "strValue");
|
||||
|
|
@ -264,32 +264,19 @@ void MacroConditionTempVarEdit::UpdateEntryData()
|
|||
|
||||
void MacroConditionTempVarEdit::VariableChanged(const TempVariableRef &var)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_tempVar = var;
|
||||
}
|
||||
|
||||
void MacroConditionTempVarEdit::Variable2Changed(const QString &text)
|
||||
{
|
||||
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_variable2 = GetWeakVariableByQString(text);
|
||||
}
|
||||
|
||||
void MacroConditionTempVarEdit::ConditionChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_type =
|
||||
static_cast<MacroConditionTempVar::Condition>(value);
|
||||
SetWidgetVisibility();
|
||||
|
|
@ -297,11 +284,7 @@ void MacroConditionTempVarEdit::ConditionChanged(int value)
|
|||
|
||||
void MacroConditionTempVarEdit::StrValueChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_strValue = _strValue->toPlainText().toStdString();
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
|
|
@ -309,21 +292,13 @@ void MacroConditionTempVarEdit::StrValueChanged()
|
|||
|
||||
void MacroConditionTempVarEdit::NumValueChanged(double val)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_numValue = val;
|
||||
}
|
||||
|
||||
void MacroConditionTempVarEdit::RegexChanged(const RegexConfig &conf)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_regex = conf;
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
|
|
|
|||
|
|
@ -236,11 +236,7 @@ void MacroConditionVariableEdit::UpdateEntryData()
|
|||
|
||||
void MacroConditionVariableEdit::VariableChanged(const QString &text)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_variable = GetWeakVariableByQString(text);
|
||||
emit HeaderInfoChanged(
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
|
|
@ -248,22 +244,13 @@ void MacroConditionVariableEdit::VariableChanged(const QString &text)
|
|||
|
||||
void MacroConditionVariableEdit::Variable2Changed(const QString &text)
|
||||
{
|
||||
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_variable2 = GetWeakVariableByQString(text);
|
||||
}
|
||||
|
||||
void MacroConditionVariableEdit::ConditionChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_type =
|
||||
static_cast<MacroConditionVariable::Condition>(value);
|
||||
SetWidgetVisibility();
|
||||
|
|
@ -271,11 +258,7 @@ void MacroConditionVariableEdit::ConditionChanged(int value)
|
|||
|
||||
void MacroConditionVariableEdit::StrValueChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_strValue = _strValue->toPlainText().toStdString();
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
|
|
@ -283,21 +266,13 @@ void MacroConditionVariableEdit::StrValueChanged()
|
|||
|
||||
void MacroConditionVariableEdit::NumValueChanged(double val)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_numValue = val;
|
||||
}
|
||||
|
||||
void MacroConditionVariableEdit::RegexChanged(const RegexConfig &conf)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_regex = conf;
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
|
|
|
|||
|
|
@ -7,6 +7,17 @@ MacroCondition::MacroCondition(Macro *m, bool supportsVariableValue)
|
|||
{
|
||||
}
|
||||
|
||||
bool MacroCondition::EvaluateCondition()
|
||||
{
|
||||
bool newValue = CheckCondition();
|
||||
_changed = _previousValue.has_value() && (*_previousValue != newValue);
|
||||
const bool negate = _logic.IsNegationType(GetLogicType());
|
||||
_risingEdge = _changed &&
|
||||
((!negate && newValue) || (negate && !newValue));
|
||||
_previousValue = newValue;
|
||||
return newValue;
|
||||
}
|
||||
|
||||
bool MacroCondition::Save(obs_data_t *obj) const
|
||||
{
|
||||
MacroSegment::Save(obj);
|
||||
|
|
|
|||
|
|
@ -4,13 +4,19 @@
|
|||
#include "duration-modifier.hpp"
|
||||
#include "macro-ref.hpp"
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace advss {
|
||||
|
||||
class EXPORT MacroCondition : public MacroSegment {
|
||||
public:
|
||||
MacroCondition(Macro *m, bool supportsVariableValue = false);
|
||||
virtual ~MacroCondition() = default;
|
||||
virtual bool CheckCondition() = 0;
|
||||
|
||||
bool EvaluateCondition();
|
||||
bool HasChanged() const { return _changed; }
|
||||
bool IsRisingEdge() const { return _risingEdge; }
|
||||
|
||||
virtual bool Save(obs_data_t *obj) const = 0;
|
||||
virtual bool Load(obs_data_t *obj) = 0;
|
||||
|
||||
|
|
@ -28,9 +34,15 @@ public:
|
|||
|
||||
static std::string_view GetDefaultID();
|
||||
|
||||
protected:
|
||||
virtual bool CheckCondition() = 0;
|
||||
|
||||
private:
|
||||
Logic _logic = Logic(Logic::Type::ROOT_NONE);
|
||||
DurationModifier _durationModifier;
|
||||
std::optional<bool> _previousValue;
|
||||
bool _changed = false;
|
||||
bool _risingEdge = false;
|
||||
};
|
||||
|
||||
class EXPORT MacroRefCondition : virtual public MacroCondition {
|
||||
|
|
|
|||
394
lib/macro/macro-dock-settings.cpp
Normal file
394
lib/macro/macro-dock-settings.cpp
Normal file
|
|
@ -0,0 +1,394 @@
|
|||
#include "macro-dock-settings.hpp"
|
||||
#include "macro-dock.hpp"
|
||||
#include "macro-dock-window.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
|
||||
#include <obs-frontend-api.h>
|
||||
#include <util/platform.h>
|
||||
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(30, 0, 0)
|
||||
#include <QDockWidget>
|
||||
|
||||
namespace {
|
||||
|
||||
struct DockMapEntry {
|
||||
QAction *action = nullptr;
|
||||
QWidget *dock = nullptr;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
static std::unordered_map<const char *, DockMapEntry> dockIds;
|
||||
static std::mutex dockMutex;
|
||||
|
||||
static bool obs_frontend_add_dock_by_id(const char *id, const char *title,
|
||||
QWidget *widget)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(dockMutex);
|
||||
if (dockIds.count(id) > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
widget->setObjectName(id);
|
||||
|
||||
auto dock = new QDockWidget();
|
||||
dock->setWindowTitle(title);
|
||||
dock->setWidget(widget);
|
||||
dock->setFloating(true);
|
||||
dock->setVisible(false);
|
||||
dock->setFeatures(QDockWidget::DockWidgetClosable |
|
||||
QDockWidget::DockWidgetMovable |
|
||||
QDockWidget::DockWidgetFloatable);
|
||||
|
||||
auto action = static_cast<QAction *>(obs_frontend_add_dock(dock));
|
||||
if (!action) {
|
||||
return false;
|
||||
}
|
||||
dockIds[id] = {action, dock};
|
||||
return true;
|
||||
}
|
||||
|
||||
static void obs_frontend_remove_dock(const char *id)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(dockMutex);
|
||||
auto it = dockIds.find(id);
|
||||
if (it == dockIds.end()) {
|
||||
return;
|
||||
}
|
||||
it->second.action->deleteLater();
|
||||
it->second.dock->deleteLater();
|
||||
dockIds.erase(it);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
namespace advss {
|
||||
|
||||
MacroDockSettings::MacroDockSettings(Macro *macro) : _macro(macro) {}
|
||||
|
||||
MacroDockSettings::~MacroDockSettings()
|
||||
{
|
||||
// Keep the dock widgets in case of shutdown so they can be restored by
|
||||
// OBS on startup
|
||||
if (!OBSIsShuttingDown()) {
|
||||
RemoveDock();
|
||||
}
|
||||
}
|
||||
|
||||
void MacroDockSettings::Save(obs_data_t *obj, bool saveForCopy) const
|
||||
{
|
||||
OBSDataAutoRelease dockSettings = obs_data_create();
|
||||
obs_data_set_bool(dockSettings, "register", _registerDock);
|
||||
obs_data_set_bool(dockSettings, "standaloneDock", _standaloneDock);
|
||||
obs_data_set_string(dockSettings, "dockWindow", _dockWindow.c_str());
|
||||
obs_data_set_bool(dockSettings, "hasRunButton", _hasRunButton);
|
||||
obs_data_set_bool(dockSettings, "hasPauseButton", _hasPauseButton);
|
||||
obs_data_set_bool(dockSettings, "hasStatusLabel", _hasStatusLabel);
|
||||
obs_data_set_bool(dockSettings, "highlightIfConditionsTrue",
|
||||
_highlight);
|
||||
_runButtonText.Save(dockSettings, "runButtonText");
|
||||
_pauseButtonText.Save(dockSettings, "pauseButtonText");
|
||||
_unpauseButtonText.Save(dockSettings, "unpauseButtonText");
|
||||
_conditionsTrueStatusText.Save(dockSettings,
|
||||
"conditionsTrueStatusText");
|
||||
_conditionsFalseStatusText.Save(dockSettings,
|
||||
"conditionsFalseStatusText");
|
||||
if (saveForCopy) {
|
||||
auto uuid = GenerateId();
|
||||
obs_data_set_string(dockSettings, "dockId", uuid.c_str());
|
||||
|
||||
} else {
|
||||
obs_data_set_string(dockSettings, "dockId", _id.c_str());
|
||||
}
|
||||
obs_data_set_int(dockSettings, "version", 1);
|
||||
obs_data_set_obj(obj, "dockSettings", dockSettings);
|
||||
}
|
||||
|
||||
void MacroDockSettings::Load(obs_data_t *obj)
|
||||
{
|
||||
OBSDataAutoRelease dockSettings = obs_data_get_obj(obj, "dockSettings");
|
||||
if (!dockSettings) {
|
||||
// TODO: Remove this fallback
|
||||
_hasRunButton = obs_data_get_bool(obj, "dockHasRunButton");
|
||||
_hasPauseButton = obs_data_get_bool(obj, "dockHasPauseButton");
|
||||
_registerDock = obs_data_get_bool(obj, "registerDock");
|
||||
ResetDockIfEnabled();
|
||||
return;
|
||||
}
|
||||
|
||||
_macroName = _macro->Name();
|
||||
if (!obs_data_has_user_value(dockSettings, "version")) {
|
||||
assert(_macro);
|
||||
_id = std::string("ADVSS-") + _macroName;
|
||||
} else {
|
||||
_id = obs_data_get_string(dockSettings, "dockId");
|
||||
}
|
||||
|
||||
_registerDock = obs_data_get_bool(dockSettings, "register");
|
||||
|
||||
// TODO: remove these default settings in a future version
|
||||
obs_data_set_default_bool(dockSettings, "standaloneDock", true);
|
||||
obs_data_set_default_string(dockSettings, "dockWindow", "Dock");
|
||||
obs_data_set_default_string(
|
||||
dockSettings, "runButtonText",
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.run"));
|
||||
obs_data_set_default_string(
|
||||
dockSettings, "pauseButtonText",
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.pause"));
|
||||
obs_data_set_default_string(
|
||||
dockSettings, "unpauseButtonText",
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.unpause"));
|
||||
_standaloneDock = obs_data_get_bool(dockSettings, "standaloneDock");
|
||||
_dockWindow = obs_data_get_string(dockSettings, "dockWindow");
|
||||
_runButtonText.Load(dockSettings, "runButtonText");
|
||||
_pauseButtonText.Load(dockSettings, "pauseButtonText");
|
||||
_unpauseButtonText.Load(dockSettings, "unpauseButtonText");
|
||||
_conditionsTrueStatusText.Load(dockSettings,
|
||||
"conditionsTrueStatusText");
|
||||
_conditionsFalseStatusText.Load(dockSettings,
|
||||
"conditionsFalseStatusText");
|
||||
if (_registerDock) {
|
||||
_hasRunButton = obs_data_get_bool(dockSettings, "hasRunButton");
|
||||
_hasPauseButton =
|
||||
obs_data_get_bool(dockSettings, "hasPauseButton");
|
||||
_hasStatusLabel =
|
||||
obs_data_get_bool(dockSettings, "hasStatusLabel");
|
||||
_highlight = obs_data_get_bool(dockSettings,
|
||||
"highlightIfConditionsTrue");
|
||||
}
|
||||
|
||||
ResetDockIfEnabled();
|
||||
}
|
||||
|
||||
void MacroDockSettings::EnableDock(bool enable)
|
||||
{
|
||||
// Only apply "on change" to avoid recreation of the dock widget
|
||||
if (_registerDock == enable) {
|
||||
return;
|
||||
}
|
||||
|
||||
RemoveDock();
|
||||
|
||||
if (!enable) {
|
||||
_registerDock = enable;
|
||||
return;
|
||||
}
|
||||
|
||||
assert(_macro);
|
||||
_macroName = _macro->Name();
|
||||
_dock = new MacroDock(GetWeakMacroByName(_macroName.c_str()),
|
||||
_runButtonText, _pauseButtonText,
|
||||
_unpauseButtonText, _conditionsTrueStatusText,
|
||||
_conditionsFalseStatusText, _highlight);
|
||||
|
||||
if (!_standaloneDock) {
|
||||
auto window = GetDockWindowByName(_dockWindow);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
window->AddMacroDock(_dock, QString::fromStdString(_macroName));
|
||||
_registerDock = enable;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!obs_frontend_add_dock_by_id(_id.c_str(), _macroName.c_str(),
|
||||
_dock)) {
|
||||
blog(LOG_INFO, "failed to add macro dock for macro %s",
|
||||
_macroName.c_str());
|
||||
_dock->deleteLater();
|
||||
_dock = nullptr;
|
||||
_registerDock = false;
|
||||
return;
|
||||
}
|
||||
|
||||
_registerDock = enable;
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetIsStandaloneDock(bool value)
|
||||
{
|
||||
if (_standaloneDock == value) {
|
||||
return;
|
||||
}
|
||||
|
||||
RemoveDock();
|
||||
_standaloneDock = value;
|
||||
ResetDockIfEnabled();
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetDockWindowName(const std::string &name)
|
||||
{
|
||||
if (_dockWindow == name) {
|
||||
return;
|
||||
}
|
||||
|
||||
RemoveDock();
|
||||
_dockWindow = name;
|
||||
ResetDockIfEnabled();
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetHasRunButton(bool value)
|
||||
{
|
||||
_hasRunButton = value;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dock->ShowRunButton(value);
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetHasPauseButton(bool value)
|
||||
{
|
||||
_hasPauseButton = value;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dock->ShowPauseButton(value);
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetHasStatusLabel(bool value)
|
||||
{
|
||||
_hasStatusLabel = value;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dock->ShowStatusLabel(value);
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetHighlightEnable(bool value)
|
||||
{
|
||||
_highlight = value;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dock->EnableHighlight(value);
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetRunButtonText(const std::string &text)
|
||||
{
|
||||
_runButtonText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dock->SetRunButtonText(text);
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetPauseButtonText(const std::string &text)
|
||||
{
|
||||
_pauseButtonText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dock->SetPauseButtonText(text);
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetUnpauseButtonText(const std::string &text)
|
||||
{
|
||||
_unpauseButtonText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dock->SetUnpauseButtonText(text);
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetConditionsTrueStatusText(const std::string &text)
|
||||
{
|
||||
_conditionsTrueStatusText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dock->SetConditionsTrueText(text);
|
||||
}
|
||||
|
||||
StringVariable MacroDockSettings::ConditionsTrueStatusText() const
|
||||
{
|
||||
return _conditionsTrueStatusText;
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetConditionsFalseStatusText(const std::string &text)
|
||||
{
|
||||
_conditionsFalseStatusText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dock->SetConditionsFalseText(text);
|
||||
}
|
||||
|
||||
StringVariable MacroDockSettings::ConditionsFalseStatusText() const
|
||||
{
|
||||
return _conditionsFalseStatusText;
|
||||
}
|
||||
|
||||
void MacroDockSettings::HandleMacroNameChange()
|
||||
{
|
||||
const auto newName = _macro->Name();
|
||||
|
||||
if (!_standaloneDock) {
|
||||
auto window = GetDockWindowByName(_dockWindow);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
|
||||
window->RenameMacro(_macroName, newName);
|
||||
_macroName = newName;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_macroName != newName) {
|
||||
RemoveDock();
|
||||
_id = GenerateId();
|
||||
_macroName = newName;
|
||||
}
|
||||
|
||||
ResetDockIfEnabled();
|
||||
}
|
||||
|
||||
void MacroDockSettings::ResetDockIfEnabled()
|
||||
{
|
||||
if (_registerDock) {
|
||||
_registerDock = false;
|
||||
EnableDock(true);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroDockSettings::RemoveDock()
|
||||
{
|
||||
if (_standaloneDock) {
|
||||
obs_frontend_remove_dock(_id.c_str());
|
||||
_dock = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
auto window = GetDockWindowByName(_dockWindow);
|
||||
if (window) {
|
||||
window->RemoveMacroDock(_dock);
|
||||
}
|
||||
|
||||
if (_dock) {
|
||||
_dock = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::string MacroDockSettings::GenerateId()
|
||||
{
|
||||
#if LIBOBS_API_VER > MAKE_SEMANTIC_VERSION(30, 0, 0)
|
||||
auto uuid = os_generate_uuid();
|
||||
auto id = std::string("advss-macro-dock-") + std::string(uuid);
|
||||
bfree(uuid);
|
||||
return id;
|
||||
|
||||
#else
|
||||
static std::atomic_int16_t idCounter = 0;
|
||||
return std::to_string(++idCounter);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
76
lib/macro/macro-dock-settings.hpp
Normal file
76
lib/macro/macro-dock-settings.hpp
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
#pragma once
|
||||
#include "obs-module-helper.hpp"
|
||||
#include "variable-string.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
class Macro;
|
||||
class MacroDock;
|
||||
|
||||
class MacroDockSettings {
|
||||
public:
|
||||
MacroDockSettings(Macro *macro);
|
||||
~MacroDockSettings();
|
||||
|
||||
void Save(obs_data_t *obj, bool saveForCopy) const;
|
||||
void Load(obs_data_t *obj);
|
||||
|
||||
void EnableDock(bool);
|
||||
bool DockEnabled() const { return _registerDock; }
|
||||
|
||||
bool IsStandaloneDock() const { return _standaloneDock; }
|
||||
void SetIsStandaloneDock(bool value);
|
||||
std::string DockWindowName() const { return _dockWindow; }
|
||||
void SetDockWindowName(const std::string &name);
|
||||
|
||||
void SetHasRunButton(bool value);
|
||||
bool HasRunButton() const { return _hasRunButton; }
|
||||
void SetHasPauseButton(bool value);
|
||||
bool HasPauseButton() const { return _hasPauseButton; }
|
||||
void SetHasStatusLabel(bool value);
|
||||
bool HasStatusLabel() const { return _hasStatusLabel; }
|
||||
void SetHighlightEnable(bool value);
|
||||
bool HighlightEnabled() const { return _highlight; }
|
||||
StringVariable RunButtonText() const { return _runButtonText; }
|
||||
void SetRunButtonText(const std::string &text);
|
||||
StringVariable PauseButtonText() const { return _pauseButtonText; }
|
||||
void SetPauseButtonText(const std::string &text);
|
||||
StringVariable UnpauseButtonText() const { return _unpauseButtonText; }
|
||||
void SetUnpauseButtonText(const std::string &text);
|
||||
void SetConditionsTrueStatusText(const std::string &text);
|
||||
StringVariable ConditionsTrueStatusText() const;
|
||||
void SetConditionsFalseStatusText(const std::string &text);
|
||||
StringVariable ConditionsFalseStatusText() const;
|
||||
|
||||
void HandleMacroNameChange();
|
||||
|
||||
private:
|
||||
void ResetDockIfEnabled();
|
||||
void RemoveDock();
|
||||
static std::string GenerateId();
|
||||
|
||||
bool _registerDock = false;
|
||||
bool _standaloneDock = true;
|
||||
std::string _dockWindow = "Dock";
|
||||
bool _hasRunButton = true;
|
||||
bool _hasPauseButton = true;
|
||||
bool _hasStatusLabel = false;
|
||||
bool _highlight = false;
|
||||
StringVariable _runButtonText =
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.run");
|
||||
StringVariable _pauseButtonText =
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.pause");
|
||||
StringVariable _unpauseButtonText =
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.unpause");
|
||||
StringVariable _conditionsTrueStatusText =
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.statusLabel.true");
|
||||
StringVariable _conditionsFalseStatusText =
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.statusLabel.false");
|
||||
std::string _id = GenerateId();
|
||||
std::string _macroName = "";
|
||||
|
||||
Macro *_macro = nullptr;
|
||||
MacroDock *_dock = nullptr;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
170
lib/macro/macro-dock-window.cpp
Normal file
170
lib/macro/macro-dock-window.cpp
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
#include "macro-dock-window.hpp"
|
||||
#include "log-helper.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
|
||||
#include <obs-frontend-api.h>
|
||||
|
||||
#include <QDockWidget>
|
||||
#include <QLayout>
|
||||
#include <mutex>
|
||||
|
||||
namespace advss {
|
||||
|
||||
static std::unordered_map<std::string, MacroDockWindow *> windows;
|
||||
static std::unordered_map<std::string, QByteArray> windowGeometries;
|
||||
static std::mutex mutex;
|
||||
|
||||
static void saveDocks(obs_data_t *obj)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
OBSDataAutoRelease data = obs_data_create();
|
||||
OBSDataArrayAutoRelease array = obs_data_array_create();
|
||||
for (const auto &[name, window] : windows) {
|
||||
OBSDataAutoRelease dockData = obs_data_create();
|
||||
obs_data_set_string(dockData, "name", name.c_str());
|
||||
obs_data_set_string(dockData, "geometry",
|
||||
window->GetWindow()
|
||||
->saveState()
|
||||
.toBase64()
|
||||
.toStdString()
|
||||
.c_str());
|
||||
obs_data_array_push_back(array, dockData);
|
||||
}
|
||||
obs_data_set_array(data, "docks", array);
|
||||
obs_data_set_obj(obj, "dockWindows", data);
|
||||
}
|
||||
|
||||
static void restoreDockGeometry()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
for (const auto &[name, dock] : windows) {
|
||||
const auto it = windowGeometries.find(name);
|
||||
if (it == windowGeometries.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dock->GetWindow()->restoreState(it->second);
|
||||
}
|
||||
}
|
||||
|
||||
static void loadDocks(obs_data_t *obj)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
windowGeometries.clear();
|
||||
OBSDataAutoRelease data = obs_data_get_obj(obj, "dockWindows");
|
||||
OBSDataArrayAutoRelease array = obs_data_get_array(data, "docks");
|
||||
auto size = obs_data_array_count(array);
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
OBSDataAutoRelease dockData = obs_data_array_item(array, i);
|
||||
const auto name = obs_data_get_string(dockData, "name");
|
||||
const auto geometry = QByteArray::fromBase64(
|
||||
obs_data_get_string(dockData, "geometry"));
|
||||
windowGeometries[name] = geometry;
|
||||
}
|
||||
AddPostLoadStep(restoreDockGeometry);
|
||||
}
|
||||
|
||||
[[maybe_unused]] static bool _ = []() {
|
||||
AddPluginInitStep([]() {
|
||||
AddSaveStep(saveDocks);
|
||||
AddLoadStep(loadDocks);
|
||||
});
|
||||
return true;
|
||||
}();
|
||||
|
||||
MacroDockWindow::MacroDockWindow(const std::string &name)
|
||||
: QFrame(),
|
||||
_name(name),
|
||||
_window(new QMainWindow())
|
||||
{
|
||||
setFrameShape(QFrame::StyledPanel);
|
||||
setFrameShadow(QFrame::Sunken);
|
||||
_window->setDockNestingEnabled(true);
|
||||
auto layout = new QVBoxLayout;
|
||||
layout->addWidget(_window);
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
QWidget *MacroDockWindow::AddMacroDock(QWidget *widget, const QString &title)
|
||||
{
|
||||
auto dock = new QDockWidget();
|
||||
dock->setWindowTitle(title);
|
||||
dock->setWidget(widget);
|
||||
dock->setVisible(true);
|
||||
dock->setFeatures(QDockWidget::DockWidgetMovable);
|
||||
dock->setObjectName(title);
|
||||
_window->addDockWidget(Qt::RightDockWidgetArea, dock);
|
||||
return dock;
|
||||
}
|
||||
|
||||
void MacroDockWindow::RenameMacro(const std::string &oldName,
|
||||
const std::string &newName)
|
||||
{
|
||||
auto docks = _window->findChildren<QDockWidget *>();
|
||||
for (const auto dock : docks) {
|
||||
if (dock->windowTitle() == QString::fromStdString(oldName)) {
|
||||
dock->setWindowTitle(QString::fromStdString(newName));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MacroDockWindow::RemoveMacroDock(QWidget *widget)
|
||||
{
|
||||
bool removedDock = false;
|
||||
auto docks = _window->findChildren<QDockWidget *>();
|
||||
for (const auto dock : docks) {
|
||||
if (dock->widget() == widget) {
|
||||
_window->removeDockWidget(dock);
|
||||
dock->deleteLater();
|
||||
removedDock = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (OBSIsShuttingDown()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool shouldRemoveDockWindow = docks.isEmpty() ||
|
||||
(removedDock && docks.count() == 1);
|
||||
if (!shouldRemoveDockWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
auto it = windows.find(_name);
|
||||
if (it != windows.end()) {
|
||||
windows.erase(it);
|
||||
}
|
||||
|
||||
const auto id = "advss-dock-window-" + _name;
|
||||
obs_frontend_remove_dock(id.c_str());
|
||||
}
|
||||
|
||||
QMainWindow *MacroDockWindow::GetWindow() const
|
||||
{
|
||||
return _window;
|
||||
}
|
||||
|
||||
MacroDockWindow *GetDockWindowByName(const std::string &name)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
auto it = windows.find(name);
|
||||
if (it != windows.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
auto window = new MacroDockWindow(name);
|
||||
const auto id = "advss-dock-window-" + name;
|
||||
if (!obs_frontend_add_dock_by_id(id.c_str(), name.c_str(), window)) {
|
||||
blog(LOG_INFO, "failed to add macro dock window '%s'",
|
||||
id.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
windows[name] = window;
|
||||
return window;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
29
lib/macro/macro-dock-window.hpp
Normal file
29
lib/macro/macro-dock-window.hpp
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
#include <QFrame>
|
||||
#include <QMainWindow>
|
||||
#include <QWidget>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace advss {
|
||||
|
||||
class MacroDockWindow : public QFrame {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MacroDockWindow(const std::string &name);
|
||||
QWidget *AddMacroDock(QWidget *, const QString &title);
|
||||
void RenameMacro(const std::string &oldName,
|
||||
const std::string &newName);
|
||||
void RemoveMacroDock(QWidget *);
|
||||
QMainWindow *GetWindow() const;
|
||||
|
||||
private:
|
||||
std::string _name;
|
||||
QMainWindow *_window;
|
||||
};
|
||||
|
||||
MacroDockWindow *GetDockWindowByName(const std::string &name);
|
||||
|
||||
} // namespace advss
|
||||
|
|
@ -30,9 +30,10 @@ MacroDock::MacroDock(std::weak_ptr<Macro> m,
|
|||
|
||||
auto macro = _macro.lock();
|
||||
if (macro) {
|
||||
_run->setVisible(macro->DockHasRunButton());
|
||||
_pauseToggle->setVisible(macro->DockHasPauseButton());
|
||||
_statusText->setVisible(macro->DockHasStatusLabel());
|
||||
const auto &settings = macro->GetDockSettings();
|
||||
_run->setVisible(settings.HasRunButton());
|
||||
_pauseToggle->setVisible(settings.HasPauseButton());
|
||||
_statusText->setVisible(settings.HasStatusLabel());
|
||||
}
|
||||
|
||||
QWidget::connect(_run, SIGNAL(clicked()), this, SLOT(RunClicked()));
|
||||
|
|
@ -109,7 +110,7 @@ void MacroDock::RunClicked()
|
|||
return;
|
||||
}
|
||||
|
||||
auto ret = macro->PerformActions(true);
|
||||
auto ret = macro->PerformActions(true, true, true);
|
||||
if (!ret) {
|
||||
QString err =
|
||||
obs_module_text("AdvSceneSwitcher.macroTab.runFail");
|
||||
|
|
|
|||
1853
lib/macro/macro-edit.cpp
Normal file
1853
lib/macro/macro-edit.cpp
Normal file
File diff suppressed because it is too large
Load Diff
141
lib/macro/macro-edit.hpp
Normal file
141
lib/macro/macro-edit.hpp
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
#pragma once
|
||||
#include "condition-logic.hpp"
|
||||
|
||||
#include <ui_macro-edit.h>
|
||||
|
||||
namespace advss {
|
||||
|
||||
class Macro;
|
||||
class MacroSegment;
|
||||
|
||||
class MacroEdit : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MacroEdit(QWidget *parent, QStringList helpMsg = {});
|
||||
void SetMacro(const std::shared_ptr<Macro> &);
|
||||
std::shared_ptr<Macro> GetMacro() const;
|
||||
void ClearSegmentWidgetCacheFor(Macro *) const;
|
||||
void SetControlsDisabled(bool disable) const;
|
||||
void HighlightAction(int idx, QColor color = QColor(Qt::green)) const;
|
||||
void HighlightElseAction(int idx,
|
||||
QColor color = QColor(Qt::green)) const;
|
||||
void HighlightCondition(int idx,
|
||||
QColor color = QColor(Qt::green)) const;
|
||||
void ResetConditionHighlights();
|
||||
void ResetActionHighlights();
|
||||
void SetActionData(Macro &m) const;
|
||||
void SetElseActionData(Macro &m) const;
|
||||
void SetConditionData(Macro &m) const;
|
||||
void SwapActions(Macro *m, int pos1, int pos2);
|
||||
void SwapElseActions(Macro *m, int pos1, int pos2);
|
||||
void SwapConditions(Macro *m, int pos1, int pos2);
|
||||
void CopyMacroSegment();
|
||||
void PasteMacroSegment();
|
||||
bool IsEmpty() const;
|
||||
void ShowAllMacroSections();
|
||||
|
||||
private slots:
|
||||
void on_conditionAdd_clicked();
|
||||
void on_conditionRemove_clicked();
|
||||
void on_conditionTop_clicked();
|
||||
void on_conditionUp_clicked();
|
||||
void on_conditionDown_clicked();
|
||||
void on_conditionBottom_clicked();
|
||||
void on_actionAdd_clicked();
|
||||
void on_actionRemove_clicked();
|
||||
void on_actionTop_clicked();
|
||||
void on_actionUp_clicked();
|
||||
void on_actionDown_clicked();
|
||||
void on_actionBottom_clicked();
|
||||
void on_toggleElseActions_clicked() const;
|
||||
void on_elseActionAdd_clicked();
|
||||
void on_elseActionRemove_clicked();
|
||||
void on_elseActionTop_clicked();
|
||||
void on_elseActionUp_clicked();
|
||||
void on_elseActionDown_clicked();
|
||||
void on_elseActionBottom_clicked();
|
||||
void UpMacroSegmentHotkey();
|
||||
void DownMacroSegmentHotkey();
|
||||
void DeleteMacroSegmentHotkey();
|
||||
void ShowMacroActionsContextMenu(const QPoint &);
|
||||
void ShowMacroElseActionsContextMenu(const QPoint &);
|
||||
void ShowMacroConditionsContextMenu(const QPoint &);
|
||||
void ExpandAllActions() const;
|
||||
void ExpandAllElseActions() const;
|
||||
void ExpandAllConditions() const;
|
||||
void CollapseAllActions() const;
|
||||
void CollapseAllElseActions() const;
|
||||
void CollapseAllConditions() const;
|
||||
void MinimizeActions() const;
|
||||
void MaximizeActions() const;
|
||||
void MinimizeElseActions() const;
|
||||
void MaximizeElseActions() const;
|
||||
void MinimizeConditions() const;
|
||||
void MaximizeConditions() const;
|
||||
void SetElseActionsStateToHidden() const;
|
||||
void SetElseActionsStateToVisible() const;
|
||||
void MacroActionSelectionChanged(int idx);
|
||||
void MacroActionReorder(int to, int target);
|
||||
void AddMacroAction(Macro *macro, int idx, const std::string &id,
|
||||
obs_data_t *data);
|
||||
void AddMacroAction(int idx);
|
||||
void RemoveMacroAction(int idx);
|
||||
void MoveMacroActionUp(int idx);
|
||||
void MoveMacroActionDown(int idx);
|
||||
void MacroElseActionSelectionChanged(int idx);
|
||||
void MacroElseActionReorder(int to, int target);
|
||||
void AddMacroElseAction(Macro *macro, int idx, const std::string &id,
|
||||
obs_data_t *data);
|
||||
void AddMacroElseAction(int idx);
|
||||
void RemoveMacroElseAction(int idx);
|
||||
void MoveMacroElseActionUp(int idx);
|
||||
void MoveMacroElseActionDown(int idx);
|
||||
void MacroConditionSelectionChanged(int idx);
|
||||
void MacroConditionReorder(int to, int target);
|
||||
void AddMacroCondition(int idx);
|
||||
void AddMacroCondition(Macro *macro, int idx, const std::string &id,
|
||||
obs_data_t *data, Logic::Type logic);
|
||||
void RemoveMacroCondition(int idx);
|
||||
void MoveMacroConditionUp(int idx);
|
||||
void MoveMacroConditionDown(int idx);
|
||||
void HighlightControls() const;
|
||||
|
||||
signals:
|
||||
void MacroAdded(const QString &name);
|
||||
void MacroRemoved(const QString &name);
|
||||
void MacroRenamed(const QString &oldName, const QString &newName);
|
||||
void MacroSegmentOrderChanged();
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
|
||||
private:
|
||||
enum class MacroSection { CONDITIONS, ACTIONS, ELSE_ACTIONS };
|
||||
|
||||
void PopulateMacroActions(Macro &m, uint32_t afterIdx = 0);
|
||||
void PopulateMacroElseActions(Macro &m, uint32_t afterIdx = 0);
|
||||
void PopulateMacroConditions(Macro &m, uint32_t afterIdx = 0);
|
||||
void SetupMacroSegmentSelection(MacroSection type, int idx);
|
||||
void
|
||||
SetupContextMenu(const QPoint &pos,
|
||||
const std::function<void(MacroEdit *, int)> &remove,
|
||||
const std::function<void(MacroEdit *)> &expand,
|
||||
const std::function<void(MacroEdit *)> &collapse,
|
||||
const std::function<void(MacroEdit *)> &maximize,
|
||||
const std::function<void(MacroEdit *)> &minimize,
|
||||
MacroSegmentList *list);
|
||||
void RunSegmentHighlightChecks();
|
||||
bool ElseSectionIsVisible() const;
|
||||
|
||||
MacroSection lastInteracted = MacroSection::CONDITIONS;
|
||||
int currentConditionIdx = -1;
|
||||
int currentActionIdx = -1;
|
||||
int currentElseActionIdx = -1;
|
||||
|
||||
std::shared_ptr<Macro> _currentMacro;
|
||||
|
||||
std::unique_ptr<Ui_MacroEdit> ui;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
#include "macro-helpers.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "macro-action-macro.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
|
@ -8,6 +9,87 @@ static std::atomic_bool abortMacroWait = {false};
|
|||
static std::atomic_bool macroSceneSwitched = {false};
|
||||
static std::atomic_int shutdownConditionCount = {0};
|
||||
|
||||
static void appendNestedMacros(std::deque<std::shared_ptr<Macro>> ¯os,
|
||||
Macro *macro)
|
||||
{
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto iterate = [¯os](const std::deque<
|
||||
std::shared_ptr<MacroAction>> &actions) {
|
||||
for (const auto &action : actions) {
|
||||
const auto nestedMacroAction =
|
||||
dynamic_cast<MacroActionMacro *>(action.get());
|
||||
if (!nestedMacroAction) {
|
||||
continue;
|
||||
}
|
||||
|
||||
macros.push_back(nestedMacroAction->_nestedMacro);
|
||||
appendNestedMacros(
|
||||
macros, nestedMacroAction->_nestedMacro.get());
|
||||
}
|
||||
};
|
||||
|
||||
iterate(macro->Actions());
|
||||
iterate(macro->ElseActions());
|
||||
}
|
||||
|
||||
std::deque<std::shared_ptr<Macro>> &GetTopLevelMacros()
|
||||
{
|
||||
static std::deque<std::shared_ptr<Macro>> macros;
|
||||
return macros;
|
||||
}
|
||||
|
||||
std::deque<std::shared_ptr<Macro>> &GetTemporaryMacros()
|
||||
{
|
||||
static std::deque<std::shared_ptr<Macro>> tempMacros;
|
||||
return tempMacros;
|
||||
}
|
||||
|
||||
std::deque<std::shared_ptr<Macro>> GetAllMacros()
|
||||
{
|
||||
auto macros = GetTopLevelMacros();
|
||||
for (const auto &topLevelMacro : macros) {
|
||||
appendNestedMacros(macros, topLevelMacro.get());
|
||||
}
|
||||
|
||||
const auto &tempMacros = GetTemporaryMacros();
|
||||
macros.insert(macros.end(), tempMacros.begin(), tempMacros.end());
|
||||
for (const auto &tempMacro : tempMacros) {
|
||||
appendNestedMacros(macros, tempMacro.get());
|
||||
}
|
||||
|
||||
return macros;
|
||||
}
|
||||
|
||||
Macro *GetMacroByName(const char *name)
|
||||
{
|
||||
for (const auto &m : GetTopLevelMacros()) {
|
||||
if (m->Name() == name) {
|
||||
return m.get();
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Macro *GetMacroByQString(const QString &name)
|
||||
{
|
||||
return GetMacroByName(name.toUtf8().constData());
|
||||
}
|
||||
|
||||
std::weak_ptr<Macro> GetWeakMacroByName(const char *name)
|
||||
{
|
||||
for (const auto &m : GetTopLevelMacros()) {
|
||||
if (m->Name() == name) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<std::deque<std::shared_ptr<MacroAction>>>
|
||||
GetMacroActions(Macro *macro)
|
||||
{
|
||||
|
|
@ -17,6 +99,15 @@ GetMacroActions(Macro *macro)
|
|||
return macro->Actions();
|
||||
}
|
||||
|
||||
std::optional<std::deque<std::shared_ptr<MacroAction>>>
|
||||
GetMacroElseActions(Macro *macro)
|
||||
{
|
||||
if (!macro) {
|
||||
return {};
|
||||
}
|
||||
return macro->ElseActions();
|
||||
}
|
||||
|
||||
std::optional<std::deque<std::shared_ptr<MacroCondition>>>
|
||||
GetMacroConditions(Macro *macro)
|
||||
{
|
||||
|
|
@ -26,9 +117,32 @@ GetMacroConditions(Macro *macro)
|
|||
return macro->Conditions();
|
||||
}
|
||||
|
||||
std::string_view GetSceneSwitchActionId()
|
||||
bool IsGroupMacro(Macro *macro)
|
||||
{
|
||||
return MacroAction::GetDefaultID();
|
||||
return macro && macro->IsGroup();
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<Macro>> GetGroupMacroEntries(Macro *macro)
|
||||
{
|
||||
if (!macro || !macro->IsGroup()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<Macro>> entries;
|
||||
entries.reserve(macro->GroupSize());
|
||||
|
||||
const auto ¯os = GetTopLevelMacros();
|
||||
for (auto it = macros.begin(); it < macros.end(); it++) {
|
||||
if ((*it)->Name() != macro->Name()) {
|
||||
continue;
|
||||
}
|
||||
for (uint32_t i = 1; i <= macro->GroupSize(); i++) {
|
||||
entries.emplace_back(*std::next(it, i));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
std::condition_variable &GetMacroWaitCV()
|
||||
|
|
@ -67,9 +181,7 @@ void SetMacroSwitchedScene(bool value)
|
|||
{
|
||||
static bool setupDone = false;
|
||||
if (!setupDone) {
|
||||
// Will always be called with switcher lock already held
|
||||
AddIntervalResetStep([]() { macroSceneSwitched = false; },
|
||||
false);
|
||||
AddIntervalResetStep([]() { macroSceneSwitched = false; });
|
||||
setupDone = true;
|
||||
}
|
||||
macroSceneSwitched = value;
|
||||
|
|
@ -80,35 +192,43 @@ bool MacroSwitchedScene()
|
|||
return macroSceneSwitched;
|
||||
}
|
||||
|
||||
std::string GetMacroName(Macro *macro)
|
||||
std::string GetMacroName(const Macro *macro)
|
||||
{
|
||||
return macro ? macro->Name() : "";
|
||||
}
|
||||
|
||||
std::chrono::high_resolution_clock::time_point
|
||||
LastMacroConditionCheckTime(Macro *macro)
|
||||
LastMacroConditionCheckTime(const Macro *macro)
|
||||
{
|
||||
return macro ? macro->LastConditionCheckTime()
|
||||
: std::chrono::high_resolution_clock::time_point{};
|
||||
}
|
||||
|
||||
bool MacroIsStopped(Macro *macro)
|
||||
bool MacroIsStopped(const Macro *macro)
|
||||
{
|
||||
return macro ? macro->GetStop() : true;
|
||||
}
|
||||
|
||||
bool MacroIsPaused(Macro *macro)
|
||||
bool MacroIsPaused(const Macro *macro)
|
||||
{
|
||||
return macro ? macro->Paused() : true;
|
||||
}
|
||||
|
||||
bool MacroWasPausedSince(
|
||||
Macro *macro,
|
||||
const Macro *macro,
|
||||
const std::chrono::high_resolution_clock::time_point &time)
|
||||
{
|
||||
return macro ? macro->WasPausedSince(time) : false;
|
||||
}
|
||||
|
||||
bool MacroWasCheckedSinceLastStart(const Macro *macro)
|
||||
{
|
||||
if (!macro) {
|
||||
return false;
|
||||
}
|
||||
return macro->LastConditionCheckTime().time_since_epoch().count() != 0;
|
||||
}
|
||||
|
||||
void AddMacroHelperThread(Macro *macro, std::thread &&newThread)
|
||||
{
|
||||
if (!macro) {
|
||||
|
|
@ -122,6 +242,11 @@ bool RunMacroActions(Macro *macro)
|
|||
return macro && macro->PerformActions(true);
|
||||
}
|
||||
|
||||
bool RunMacroElseActions(Macro *macro)
|
||||
{
|
||||
return macro && macro->PerformActions(false);
|
||||
}
|
||||
|
||||
void ResetMacroConditionTimers(Macro *macro)
|
||||
{
|
||||
if (!macro) {
|
||||
|
|
@ -138,20 +263,42 @@ void ResetMacroRunCount(Macro *macro)
|
|||
macro->ResetRunCount();
|
||||
}
|
||||
|
||||
bool IsValidMacroSegmentIndex(Macro *m, const int idx, bool isCondition)
|
||||
bool IsValidActionIndex(const Macro *m, const int idx)
|
||||
{
|
||||
if (!m || idx < 0) {
|
||||
return false;
|
||||
}
|
||||
if (isCondition) {
|
||||
if (idx >= (int)m->Conditions().size()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (idx >= (int)m->Actions().size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (idx >= (int)m->Actions().size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsValidElseActionIndex(const Macro *m, const int idx)
|
||||
{
|
||||
if (!m || idx < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (idx >= (int)m->ElseActions().size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsValidConditionIndex(const Macro *m, const int idx)
|
||||
{
|
||||
if (!m || idx < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (idx >= (int)m->Conditions().size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
#pragma once
|
||||
#include "export-symbol-helper.hpp"
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <deque>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
|
||||
struct obs_data;
|
||||
|
|
@ -18,16 +19,25 @@ class Macro;
|
|||
class MacroAction;
|
||||
class MacroCondition;
|
||||
|
||||
EXPORT std::deque<std::shared_ptr<Macro>> &GetMacros();
|
||||
static const int macro_func = 10;
|
||||
|
||||
EXPORT std::deque<std::shared_ptr<Macro>> &GetTopLevelMacros();
|
||||
std::deque<std::shared_ptr<Macro>> &GetTemporaryMacros();
|
||||
EXPORT std::deque<std::shared_ptr<Macro>> GetAllMacros();
|
||||
|
||||
Macro *GetMacroByName(const char *name);
|
||||
Macro *GetMacroByQString(const QString &name);
|
||||
std::weak_ptr<Macro> GetWeakMacroByName(const char *name);
|
||||
|
||||
EXPORT std::optional<std::deque<std::shared_ptr<MacroAction>>>
|
||||
GetMacroActions(Macro *);
|
||||
EXPORT std::optional<std::deque<std::shared_ptr<MacroAction>>>
|
||||
GetMacroElseActions(Macro *);
|
||||
EXPORT std::optional<std::deque<std::shared_ptr<MacroCondition>>>
|
||||
GetMacroConditions(Macro *);
|
||||
|
||||
std::string_view GetSceneSwitchActionId();
|
||||
|
||||
constexpr auto macro_func = 10;
|
||||
EXPORT bool IsGroupMacro(Macro *);
|
||||
EXPORT std::vector<std::shared_ptr<Macro>> GetGroupMacroEntries(Macro *);
|
||||
|
||||
EXPORT std::condition_variable &GetMacroWaitCV();
|
||||
EXPORT std::condition_variable &GetMacroTransitionCV();
|
||||
|
|
@ -41,22 +51,24 @@ EXPORT std::atomic_int &GetShutdownConditionCount();
|
|||
EXPORT void SetMacroSwitchedScene(bool value);
|
||||
EXPORT bool MacroSwitchedScene();
|
||||
|
||||
EXPORT std::string GetMacroName(Macro *);
|
||||
EXPORT std::string GetMacroName(const Macro *);
|
||||
|
||||
EXPORT std::chrono::high_resolution_clock::time_point
|
||||
LastMacroConditionCheckTime(Macro *);
|
||||
LastMacroConditionCheckTime(const Macro *);
|
||||
|
||||
EXPORT bool MacroIsStopped(Macro *);
|
||||
EXPORT bool MacroIsPaused(Macro *);
|
||||
EXPORT bool MacroIsStopped(const Macro *);
|
||||
EXPORT bool MacroIsPaused(const Macro *);
|
||||
EXPORT bool
|
||||
MacroWasPausedSince(Macro *,
|
||||
MacroWasPausedSince(const Macro *,
|
||||
const std::chrono::high_resolution_clock::time_point &);
|
||||
EXPORT bool MacroWasCheckedSinceLastStart(const Macro *);
|
||||
|
||||
EXPORT void AddMacroHelperThread(Macro *, std::thread &&);
|
||||
|
||||
EXPORT bool CheckMacros();
|
||||
|
||||
EXPORT bool RunMacroActions(Macro *);
|
||||
bool RunMacroElseActions(Macro *);
|
||||
EXPORT bool RunMacros();
|
||||
void StopAllMacros();
|
||||
|
||||
|
|
@ -67,6 +79,8 @@ EXPORT void InvalidateMacroTempVarValues();
|
|||
EXPORT void ResetMacroConditionTimers(Macro *);
|
||||
EXPORT void ResetMacroRunCount(Macro *);
|
||||
|
||||
bool IsValidMacroSegmentIndex(Macro *m, const int idx, bool isCondition);
|
||||
bool IsValidActionIndex(const Macro *m, const int idx);
|
||||
bool IsValidElseActionIndex(const Macro *m, const int idx);
|
||||
bool IsValidConditionIndex(const Macro *m, const int idx);
|
||||
|
||||
} // namespace advss
|
||||
|
|
|
|||
|
|
@ -181,15 +181,7 @@ void MacroInputEdit::SetInputVariablesAndValues(
|
|||
_variables = inputs;
|
||||
_values = values;
|
||||
if ((size_t)_values.size() < _variables._inputVariables.size()) {
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
for (int i = 0;
|
||||
_variables._inputVariables.size() - (size_t)_values.size();
|
||||
i++) {
|
||||
_values.push_back({});
|
||||
}
|
||||
#else
|
||||
_values.resize(_variables._inputVariables.size());
|
||||
#endif
|
||||
}
|
||||
SetupWidgets();
|
||||
}
|
||||
|
|
@ -199,7 +191,7 @@ bool MacroInputEdit::HasInputsToSet() const
|
|||
return !_variables._inputVariables.empty();
|
||||
}
|
||||
|
||||
void HighligthMacroSettingsButton(bool enable);
|
||||
void HighlightMacroSettingsButton(bool enable);
|
||||
|
||||
void MacroInputEdit::SetupWidgets()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "macro-list.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "macro-selection.hpp"
|
||||
#include "macro-signals.hpp"
|
||||
#include "obs-module-helper.hpp"
|
||||
#include "ui-helpers.hpp"
|
||||
|
||||
|
|
@ -10,11 +11,11 @@ MacroList::MacroList(QWidget *parent, bool allowDuplicates, bool reorder)
|
|||
: ListEditor(parent, reorder),
|
||||
_allowDuplicates(allowDuplicates)
|
||||
{
|
||||
QWidget::connect(window(),
|
||||
SIGNAL(MacroRenamed(const QString &, const QString &)),
|
||||
this,
|
||||
QWidget::connect(MacroSignalManager::Instance(),
|
||||
SIGNAL(Rename(const QString &, const QString &)), this,
|
||||
SLOT(MacroRename(const QString &, const QString &)));
|
||||
QWidget::connect(window(), SIGNAL(MacroRemoved(const QString &)), this,
|
||||
QWidget::connect(MacroSignalManager::Instance(),
|
||||
SIGNAL(Remove(const QString &)), this,
|
||||
SLOT(MacroRemove(const QString &)));
|
||||
UpdateListSize();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,10 +11,14 @@ namespace advss {
|
|||
MacroRunButton::MacroRunButton(QWidget *parent) : QPushButton(parent)
|
||||
{
|
||||
installEventFilter(this);
|
||||
auto parentWindow = window();
|
||||
if (parentWindow) {
|
||||
parentWindow->installEventFilter(this);
|
||||
}
|
||||
|
||||
// GetSettingsWindow() might still return null while this constructor is called
|
||||
QTimer::singleShot(0, this, [this]() {
|
||||
auto parentWindow = GetSettingsWindow();
|
||||
if (parentWindow) {
|
||||
parentWindow->installEventFilter(this);
|
||||
}
|
||||
});
|
||||
|
||||
setToolTip(obs_module_text("AdvSceneSwitcher.macroTab.run.tooltip"));
|
||||
|
||||
|
|
|
|||
323
lib/macro/macro-search.cpp
Normal file
323
lib/macro/macro-search.cpp
Normal file
|
|
@ -0,0 +1,323 @@
|
|||
#include "macro-search.hpp"
|
||||
#include "layout-helpers.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "macro-action-factory.hpp"
|
||||
#include "macro-condition-factory.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "macro-signals.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "ui-helpers.hpp"
|
||||
|
||||
#include <obs.hpp>
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QLayout>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
|
||||
namespace advss {
|
||||
|
||||
static bool searchEnabled = false;
|
||||
static bool setup();
|
||||
static bool setupDone = setup();
|
||||
|
||||
static QLayout *searchLayout = nullptr;
|
||||
static QComboBox *searchType = nullptr;
|
||||
static RegexConfigWidget *searchRegex = nullptr;
|
||||
static QPushButton *showSettings = nullptr;
|
||||
static std::function<void()> refreshFilter;
|
||||
|
||||
static void save(obs_data_t *data)
|
||||
{
|
||||
GetMacroSearchSettings().Save(data, "macroSearchSettings");
|
||||
}
|
||||
|
||||
static void load(obs_data_t *data)
|
||||
{
|
||||
GetMacroSearchSettings().Load(data, "macroSearchSettings");
|
||||
}
|
||||
|
||||
static bool setup()
|
||||
{
|
||||
AddSaveStep(save);
|
||||
AddLoadStep(load);
|
||||
return true;
|
||||
}
|
||||
|
||||
void MacroSearchSettings::Save(obs_data_t *data, const char *name)
|
||||
{
|
||||
OBSDataAutoRelease settings = obs_data_create();
|
||||
obs_data_set_bool(settings, "showAlways", showAlways);
|
||||
obs_data_set_int(settings, "searchType", static_cast<int>(searchType));
|
||||
obs_data_set_string(settings, "searchString", searchString.c_str());
|
||||
regex.Save(settings);
|
||||
obs_data_set_obj(data, name, settings);
|
||||
}
|
||||
|
||||
void MacroSearchSettings::Load(obs_data_t *data, const char *name)
|
||||
{
|
||||
OBSDataAutoRelease settings = obs_data_get_obj(data, name);
|
||||
showAlways = obs_data_get_bool(settings, "showAlways");
|
||||
searchType = static_cast<SearchType>(
|
||||
obs_data_get_int(settings, "searchType"));
|
||||
searchString = obs_data_get_string(settings, "searchString");
|
||||
regex.Load(settings);
|
||||
}
|
||||
|
||||
static void showAdvancedSearchSettings(bool show)
|
||||
{
|
||||
assert(searchType);
|
||||
assert(searchRegex);
|
||||
|
||||
searchType->setVisible(show);
|
||||
searchRegex->setVisible(show);
|
||||
}
|
||||
|
||||
static bool shouldShowSearch()
|
||||
{
|
||||
static const int showSearchThreshold = 10;
|
||||
return GetMacroSearchSettings().showAlways ||
|
||||
GetTopLevelMacros().size() >= showSearchThreshold;
|
||||
}
|
||||
|
||||
void CheckMacroSearchVisibility()
|
||||
{
|
||||
assert(searchLayout);
|
||||
assert(searchType);
|
||||
assert(searchRegex);
|
||||
assert(showSettings);
|
||||
|
||||
searchEnabled = shouldShowSearch();
|
||||
SetLayoutVisible(searchLayout, searchEnabled);
|
||||
showAdvancedSearchSettings(false);
|
||||
showSettings->setChecked(false);
|
||||
refreshFilter();
|
||||
}
|
||||
|
||||
void SetupMacroSearchWidgets(QLayout *searchLayoutArg, QLineEdit *searchText,
|
||||
QPushButton *searchClear, QComboBox *searchTypeArg,
|
||||
RegexConfigWidget *searchRegexArg,
|
||||
QPushButton *showSettingsArg,
|
||||
const std::function<void()> &refreshArg)
|
||||
{
|
||||
searchLayout = searchLayoutArg;
|
||||
searchType = searchTypeArg;
|
||||
searchRegex = searchRegexArg;
|
||||
refreshFilter = refreshArg;
|
||||
showSettings = showSettingsArg;
|
||||
|
||||
searchClear->setMaximumWidth(22);
|
||||
SetButtonIcon(searchClear, GetThemeTypeName() == "Light"
|
||||
? "theme:Light/close.svg"
|
||||
: "theme:Dark/close.svg");
|
||||
searchClear->setDisabled(GetMacroSearchSettings().searchString.empty());
|
||||
|
||||
QWidget::connect(searchClear, &QPushButton::clicked, searchClear,
|
||||
[=]() {
|
||||
searchText->setText("");
|
||||
searchClear->setDisabled(true);
|
||||
});
|
||||
|
||||
const auto ph = searchText->placeholderText();
|
||||
const QFontMetrics fm(searchText->font());
|
||||
const int width = fm.horizontalAdvance(ph);
|
||||
// Add a little padding so the text isn't cramped
|
||||
searchText->setMinimumWidth(width + 10);
|
||||
|
||||
searchText->setText(
|
||||
QString::fromStdString(GetMacroSearchSettings().searchString));
|
||||
QWidget::connect(searchText, &QLineEdit::textChanged, searchText,
|
||||
[searchClear](const QString &text) {
|
||||
GetMacroSearchSettings().searchString =
|
||||
text.toStdString();
|
||||
searchClear->setDisabled(text.isEmpty());
|
||||
refreshFilter();
|
||||
});
|
||||
|
||||
searchType->addItem(
|
||||
obs_module_text("AdvSceneSwitcher.macroTab.search.name"),
|
||||
static_cast<int>(MacroSearchSettings::SearchType::NAME));
|
||||
searchType->addItem(
|
||||
obs_module_text("AdvSceneSwitcher.macroTab.search.allSegments"),
|
||||
static_cast<int>(
|
||||
MacroSearchSettings::SearchType::ALL_SEGMENTS));
|
||||
searchType->addItem(
|
||||
obs_module_text("AdvSceneSwitcher.macroTab.search.conditions"),
|
||||
static_cast<int>(MacroSearchSettings::SearchType::CONDITIONS));
|
||||
searchType->addItem(
|
||||
obs_module_text("AdvSceneSwitcher.macroTab.search.actions"),
|
||||
static_cast<int>(MacroSearchSettings::SearchType::ACTIONS));
|
||||
searchType->addItem(
|
||||
obs_module_text("AdvSceneSwitcher.macroTab.search.label"),
|
||||
static_cast<int>(MacroSearchSettings::SearchType::LABEL));
|
||||
searchType->setCurrentIndex(searchType->findData(
|
||||
static_cast<int>(GetMacroSearchSettings().searchType)));
|
||||
QWidget::connect(
|
||||
searchType, &QComboBox::currentIndexChanged, searchType, []() {
|
||||
GetMacroSearchSettings().searchType =
|
||||
static_cast<MacroSearchSettings::SearchType>(
|
||||
searchType->currentData().toInt());
|
||||
refreshFilter();
|
||||
});
|
||||
|
||||
searchRegex->SetRegexConfig(GetMacroSearchSettings().regex);
|
||||
QWidget::connect(searchRegex, &RegexConfigWidget::RegexConfigChanged,
|
||||
searchRegex, [](const RegexConfig ®ex) {
|
||||
GetMacroSearchSettings().regex = regex;
|
||||
refreshFilter();
|
||||
});
|
||||
|
||||
showSettings->setCheckable(true);
|
||||
showSettings->setMaximumWidth(11);
|
||||
SetButtonIcon(showSettings, GetThemeTypeName() == "Light"
|
||||
? ":/res/images/dots-vert.svg"
|
||||
: "theme:Dark/dots-vert.svg");
|
||||
QWidget::connect(showSettings, &QPushButton::toggled, showSettings,
|
||||
showAdvancedSearchSettings);
|
||||
|
||||
QWidget::connect(MacroSignalManager::Instance(),
|
||||
&MacroSignalManager::Rename, searchText,
|
||||
[]() { refreshFilter(); });
|
||||
|
||||
CheckMacroSearchVisibility();
|
||||
}
|
||||
|
||||
MacroSearchSettings &GetMacroSearchSettings()
|
||||
{
|
||||
static MacroSearchSettings settings;
|
||||
return settings;
|
||||
}
|
||||
|
||||
static bool stringMatches(const std::string &text)
|
||||
{
|
||||
const auto &settings = GetMacroSearchSettings();
|
||||
const auto ®ex = settings.regex;
|
||||
const auto &searchString = settings.searchString;
|
||||
|
||||
if (regex.Enabled()) {
|
||||
return regex.Matches(text, searchString);
|
||||
}
|
||||
|
||||
return QString::fromStdString(text).contains(
|
||||
QString::fromStdString(searchString), Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
static bool segmentTypeMatches(MacroSegment *segment, bool isCondition)
|
||||
{
|
||||
if (!segment) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto getNameFromId =
|
||||
isCondition ? MacroConditionFactory::GetConditionName
|
||||
: MacroActionFactory::GetActionName;
|
||||
const auto name = getNameFromId(segment->GetId());
|
||||
return stringMatches(obs_module_text(name.c_str()));
|
||||
}
|
||||
|
||||
static bool segmentLabelMatches(MacroSegment *segment)
|
||||
{
|
||||
if (!segment) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!segment->GetUseCustomLabel()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto label = segment->GetCustomLabel();
|
||||
return stringMatches(label);
|
||||
}
|
||||
|
||||
bool MacroMatchesSearchFilter(Macro *macro)
|
||||
{
|
||||
assert(macro);
|
||||
|
||||
if (!searchEnabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto &settings = GetMacroSearchSettings();
|
||||
|
||||
if (settings.searchString.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (macro->IsGroup()) {
|
||||
const auto groupEntries = GetGroupMacroEntries(macro);
|
||||
for (const auto &entry : groupEntries) {
|
||||
if (MacroMatchesSearchFilter(entry.get())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (settings.searchType) {
|
||||
case MacroSearchSettings::SearchType::NAME: {
|
||||
const auto name = macro->Name();
|
||||
return stringMatches(name);
|
||||
}
|
||||
case MacroSearchSettings::SearchType::ALL_SEGMENTS:
|
||||
for (const auto &condition : macro->Conditions()) {
|
||||
if (segmentTypeMatches(condition.get(), true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (const auto &action : macro->Actions()) {
|
||||
if (segmentTypeMatches(action.get(), false)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (const auto &action : macro->ElseActions()) {
|
||||
if (segmentTypeMatches(action.get(), false)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
case MacroSearchSettings::SearchType::CONDITIONS:
|
||||
for (const auto &condition : macro->Conditions()) {
|
||||
if (segmentTypeMatches(condition.get(), true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
case MacroSearchSettings::SearchType::ACTIONS:
|
||||
for (const auto &action : macro->Actions()) {
|
||||
if (segmentTypeMatches(action.get(), false)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (const auto &action : macro->ElseActions()) {
|
||||
if (segmentTypeMatches(action.get(), false)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
case MacroSearchSettings::SearchType::LABEL:
|
||||
for (const auto &condition : macro->Conditions()) {
|
||||
if (segmentLabelMatches(condition.get())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (const auto &action : macro->Actions()) {
|
||||
if (segmentLabelMatches(action.get())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (const auto &action : macro->ElseActions()) {
|
||||
if (segmentLabelMatches(action.get())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Unhandled search type
|
||||
assert(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
43
lib/macro/macro-search.hpp
Normal file
43
lib/macro/macro-search.hpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
#include "regex-config.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
class QComboBox;
|
||||
class QLayout;
|
||||
class QLineEdit;
|
||||
class QPushButton;
|
||||
|
||||
namespace advss {
|
||||
|
||||
class Macro;
|
||||
|
||||
struct MacroSearchSettings {
|
||||
void Save(obs_data_t *data, const char *name);
|
||||
void Load(obs_data_t *data, const char *name);
|
||||
|
||||
enum class SearchType {
|
||||
NAME = 0,
|
||||
ALL_SEGMENTS = 10,
|
||||
CONDITIONS = 20,
|
||||
ACTIONS = 30,
|
||||
LABEL = 40,
|
||||
};
|
||||
|
||||
SearchType searchType = SearchType::NAME;
|
||||
std::string searchString;
|
||||
RegexConfig regex;
|
||||
bool showAlways = false;
|
||||
};
|
||||
|
||||
void CheckMacroSearchVisibility();
|
||||
void SetupMacroSearchWidgets(QLayout *searchLayout, QLineEdit *searchText,
|
||||
QPushButton *searchClear, QComboBox *searchType,
|
||||
RegexConfigWidget *searchRegex,
|
||||
QPushButton *showSettings,
|
||||
const std::function<void()> &refresh);
|
||||
MacroSearchSettings &GetMacroSearchSettings();
|
||||
bool MacroMatchesSearchFilter(Macro *macro);
|
||||
|
||||
} // namespace advss
|
||||
|
|
@ -13,7 +13,7 @@ struct MacroSegmentCopyInfo {
|
|||
};
|
||||
static MacroSegmentCopyInfo copyInfo;
|
||||
|
||||
void AdvSceneSwitcher::CopyMacroSegment()
|
||||
void MacroEdit::CopyMacroSegment()
|
||||
{
|
||||
copyInfo.segment.reset();
|
||||
copyInfo.type = MacroSegmentCopyInfo::Type::NONE;
|
||||
|
|
@ -23,7 +23,7 @@ void AdvSceneSwitcher::CopyMacroSegment()
|
|||
return;
|
||||
}
|
||||
|
||||
auto macro = GetSelectedMacro();
|
||||
auto macro = _currentMacro;
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -43,13 +43,13 @@ void AdvSceneSwitcher::CopyMacroSegment()
|
|||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::PasteMacroSegment()
|
||||
void MacroEdit::PasteMacroSegment()
|
||||
{
|
||||
if (copyInfo.type == MacroSegmentCopyInfo::Type::NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto macro = GetSelectedMacro();
|
||||
auto macro = _currentMacro;
|
||||
if (!macro || !copyInfo.segment) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -113,14 +113,14 @@ void SetCopySegmentTargetActionType(bool setToElseAction)
|
|||
}
|
||||
}
|
||||
|
||||
void SetupSegmentCopyPasteShortcutHandlers(AdvSceneSwitcher *window)
|
||||
void SetupSegmentCopyPasteShortcutHandlers(MacroEdit *edit)
|
||||
{
|
||||
auto copyShortcut = new QShortcut(QKeySequence("Ctrl+C"), window);
|
||||
QWidget::connect(copyShortcut, &QShortcut::activated, window,
|
||||
&AdvSceneSwitcher::CopyMacroSegment);
|
||||
auto pasteShortcut = new QShortcut(QKeySequence("Ctrl+V"), window);
|
||||
QWidget::connect(pasteShortcut, &QShortcut::activated, window,
|
||||
&AdvSceneSwitcher::PasteMacroSegment);
|
||||
auto copyShortcut = new QShortcut(QKeySequence("Ctrl+C"), edit);
|
||||
QWidget::connect(copyShortcut, &QShortcut::activated, edit,
|
||||
&MacroEdit::CopyMacroSegment);
|
||||
auto pasteShortcut = new QShortcut(QKeySequence("Ctrl+V"), edit);
|
||||
QWidget::connect(pasteShortcut, &QShortcut::activated, edit,
|
||||
&MacroEdit::PasteMacroSegment);
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
namespace advss {
|
||||
|
||||
class AdvSceneSwitcher;
|
||||
class MacroEdit;
|
||||
|
||||
bool MacroSegmentIsInClipboard();
|
||||
bool MacroActionIsInClipboard();
|
||||
void SetCopySegmentTargetActionType(bool setToElseAction);
|
||||
void SetupSegmentCopyPasteShortcutHandlers(AdvSceneSwitcher *window);
|
||||
void SetupSegmentCopyPasteShortcutHandlers(MacroEdit *edit);
|
||||
|
||||
} // namespace advss
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user